| author | |
| committer | |
| log | 3f7cb14b267bbd823597ba24fd2e3f6f66abcbaa |
| tree | 9d3ce364c8619ac5ca6ce273be0b86164264a9d7 |
| parent | baa734c42a2bdb3f63fd26dd30bc8c9a846831bf |
| parent | 4c13d020dbecbd7664b99765de33f230e98f3322 |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
stage2: introduce the ability for Scope.Block to be comptime7 files changed, 259 insertions(+), 113 deletions(-)
src-self-hosted/Module.zig+70-63| ... | ... | @@ -725,6 +725,7 @@ pub const Scope = struct { |
| 725 | 725 | /// Points to the arena allocator of DeclAnalysis |
| 726 | 726 | arena: *Allocator, |
| 727 | 727 | label: ?Label = null, |
| 728 | is_comptime: bool, | |
| 728 | 729 | |
| 729 | 730 | pub const Label = struct { |
| 730 | 731 | zir_block: *zir.Inst.Block, |
| ... | ... | @@ -1307,7 +1308,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1307 | 1308 | .return_type = return_type_inst, |
| 1308 | 1309 | .param_types = param_types, |
| 1309 | 1310 | }, .{}); |
| 1310 | _ = try astgen.addZIRUnOp(self, &fn_type_scope.base, fn_src, .@"return", fn_type_inst); | |
| 1311 | 1311 | |
| 1312 | 1312 | // We need the memory for the Type to go into the arena for the Decl |
| 1313 | 1313 | var decl_arena = std.heap.ArenaAllocator.init(self.gpa); |
| ... | ... | @@ -1320,10 +1320,11 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1320 | 1320 | .decl = decl, |
| 1321 | 1321 | .instructions = .{}, |
| 1322 | 1322 | .arena = &decl_arena.allocator, |
| 1323 | .is_comptime = false, | |
| 1323 | 1324 | }; |
| 1324 | 1325 | defer block_scope.instructions.deinit(self.gpa); |
| 1325 | 1326 | |
| 1326 | const fn_type = try zir_sema.analyzeBodyValueAsType(self, &block_scope, .{ | |
| 1327 | const fn_type = try zir_sema.analyzeBodyValueAsType(self, &block_scope, fn_type_inst, .{ | |
| 1327 | 1328 | .instructions = fn_type_scope.instructions.items, |
| 1328 | 1329 | }); |
| 1329 | 1330 | const new_func = try decl_arena.allocator.create(Fn); |
| ... | ... | @@ -1457,6 +1458,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1457 | 1458 | .decl = decl, |
| 1458 | 1459 | .instructions = .{}, |
| 1459 | 1460 | .arena = &decl_arena.allocator, |
| 1461 | .is_comptime = true, | |
| 1460 | 1462 | }; |
| 1461 | 1463 | defer block_scope.instructions.deinit(self.gpa); |
| 1462 | 1464 | |
| ... | ... | @@ -1489,35 +1491,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1489 | 1491 | return self.failNode(&block_scope.base, sect_expr, "TODO implement function section expression", .{}); |
| 1490 | 1492 | } |
| 1491 | 1493 | |
| 1492 | const explicit_type = blk: { | |
| 1493 | const type_node = var_decl.getTypeNode() orelse | |
| 1494 | break :blk null; | |
| 1495 | ||
| 1496 | // Temporary arena for the zir instructions. | |
| 1497 | var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa); | |
| 1498 | defer type_scope_arena.deinit(); | |
| 1499 | var type_scope: Scope.GenZIR = .{ | |
| 1500 | .decl = decl, | |
| 1501 | .arena = &type_scope_arena.allocator, | |
| 1502 | .parent = decl.scope, | |
| 1503 | }; | |
| 1504 | defer type_scope.instructions.deinit(self.gpa); | |
| 1505 | ||
| 1506 | const src = tree.token_locs[type_node.firstToken()].start; | |
| 1507 | const type_type = try astgen.addZIRInstConst(self, &type_scope.base, src, .{ | |
| 1508 | .ty = Type.initTag(.type), | |
| 1509 | .val = Value.initTag(.type_type), | |
| 1510 | }); | |
| 1511 | const var_type = try astgen.expr(self, &type_scope.base, .{ .ty = type_type }, type_node); | |
| 1512 | _ = try astgen.addZIRUnOp(self, &type_scope.base, src, .@"return", var_type); | |
| 1513 | ||
| 1514 | break :blk try zir_sema.analyzeBodyValueAsType(self, &block_scope, .{ | |
| 1515 | .instructions = type_scope.instructions.items, | |
| 1516 | }); | |
| 1517 | }; | |
| 1518 | ||
| 1519 | var var_type: Type = undefined; | |
| 1520 | const value: ?Value = if (var_decl.getInitNode()) |init_node| blk: { | |
| 1494 | const var_info: struct { ty: Type, val: ?Value } = if (var_decl.getInitNode()) |init_node| vi: { | |
| 1521 | 1495 | var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa); |
| 1522 | 1496 | defer gen_scope_arena.deinit(); |
| 1523 | 1497 | var gen_scope: Scope.GenZIR = .{ |
| ... | ... | @@ -1526,11 +1500,19 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1526 | 1500 | .parent = decl.scope, |
| 1527 | 1501 | }; |
| 1528 | 1502 | defer gen_scope.instructions.deinit(self.gpa); |
| 1529 | const src = tree.token_locs[init_node.firstToken()].start; | |
| 1530 | 1503 | |
| 1531 | // TODO comptime scope here | |
| 1532 | const init_inst = try astgen.expr(self, &gen_scope.base, .none, init_node); | |
| 1533 | _ = try astgen.addZIRUnOp(self, &gen_scope.base, src, .@"return", init_inst); | |
| 1504 | const init_result_loc: astgen.ResultLoc = if (var_decl.getTypeNode()) |type_node| rl: { | |
| 1505 | const src = tree.token_locs[type_node.firstToken()].start; | |
| 1506 | const type_type = try astgen.addZIRInstConst(self, &gen_scope.base, src, .{ | |
| 1507 | .ty = Type.initTag(.type), | |
| 1508 | .val = Value.initTag(.type_type), | |
| 1509 | }); | |
| 1510 | const var_type = try astgen.expr(self, &gen_scope.base, .{ .ty = type_type }, type_node); | |
| 1511 | break :rl .{ .ty = var_type }; | |
| 1512 | } else .none; | |
| 1513 | ||
| 1514 | const src = tree.token_locs[init_node.firstToken()].start; | |
| 1515 | const init_inst = try astgen.expr(self, &gen_scope.base, init_result_loc, init_node); | |
| 1534 | 1516 | |
| 1535 | 1517 | var inner_block: Scope.Block = .{ |
| 1536 | 1518 | .parent = null, |
| ... | ... | @@ -1538,42 +1520,58 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1538 | 1520 | .decl = decl, |
| 1539 | 1521 | .instructions = .{}, |
| 1540 | 1522 | .arena = &gen_scope_arena.allocator, |
| 1523 | .is_comptime = true, | |
| 1541 | 1524 | }; |
| 1542 | 1525 | defer inner_block.instructions.deinit(self.gpa); |
| 1543 | 1526 | try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items }); |
| 1544 | 1527 | |
| 1545 | for (inner_block.instructions.items) |inst| { | |
| 1546 | if (inst.castTag(.ret)) |ret| { | |
| 1547 | const coerced = if (explicit_type) |some| | |
| 1548 | try self.coerce(&inner_block.base, some, ret.operand) | |
| 1549 | else | |
| 1550 | ret.operand; | |
| 1551 | const val = coerced.value() orelse | |
| 1552 | return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); | |
| 1553 | ||
| 1554 | var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena); | |
| 1555 | break :blk try val.copy(block_scope.arena); | |
| 1556 | } else { | |
| 1557 | return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); | |
| 1558 | } | |
| 1559 | } | |
| 1560 | unreachable; | |
| 1528 | // The result location guarantees the type coercion. | |
| 1529 | const analyzed_init_inst = init_inst.analyzed_inst.?; | |
| 1530 | // The is_comptime in the Scope.Block guarantees the result is comptime-known. | |
| 1531 | const val = analyzed_init_inst.value().?; | |
| 1532 | ||
| 1533 | const ty = try analyzed_init_inst.ty.copy(block_scope.arena); | |
| 1534 | break :vi .{ | |
| 1535 | .ty = ty, | |
| 1536 | .val = try val.copy(block_scope.arena), | |
| 1537 | }; | |
| 1561 | 1538 | } else if (!is_extern) { |
| 1562 | 1539 | return self.failTok(&block_scope.base, var_decl.firstToken(), "variables must be initialized", .{}); |
| 1563 | } else if (explicit_type) |some| blk: { | |
| 1564 | var_type = some; | |
| 1565 | break :blk null; | |
| 1540 | } else if (var_decl.getTypeNode()) |type_node| vi: { | |
| 1541 | // Temporary arena for the zir instructions. | |
| 1542 | var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa); | |
| 1543 | defer type_scope_arena.deinit(); | |
| 1544 | var type_scope: Scope.GenZIR = .{ | |
| 1545 | .decl = decl, | |
| 1546 | .arena = &type_scope_arena.allocator, | |
| 1547 | .parent = decl.scope, | |
| 1548 | }; | |
| 1549 | defer type_scope.instructions.deinit(self.gpa); | |
| 1550 | ||
| 1551 | const src = tree.token_locs[type_node.firstToken()].start; | |
| 1552 | const type_type = try astgen.addZIRInstConst(self, &type_scope.base, src, .{ | |
| 1553 | .ty = Type.initTag(.type), | |
| 1554 | .val = Value.initTag(.type_type), | |
| 1555 | }); | |
| 1556 | const var_type = try astgen.expr(self, &type_scope.base, .{ .ty = type_type }, type_node); | |
| 1557 | const ty = try zir_sema.analyzeBodyValueAsType(self, &block_scope, var_type, .{ | |
| 1558 | .instructions = type_scope.instructions.items, | |
| 1559 | }); | |
| 1560 | break :vi .{ | |
| 1561 | .ty = ty, | |
| 1562 | .val = null, | |
| 1563 | }; | |
| 1566 | 1564 | } else { |
| 1567 | 1565 | return self.failTok(&block_scope.base, var_decl.firstToken(), "unable to infer variable type", .{}); |
| 1568 | 1566 | }; |
| 1569 | 1567 | |
| 1570 | if (is_mutable and !var_type.isValidVarType(is_extern)) { | |
| 1571 | return self.failTok(&block_scope.base, var_decl.firstToken(), "variable of type '{}' must be const", .{var_type}); | |
| 1568 | if (is_mutable and !var_info.ty.isValidVarType(is_extern)) { | |
| 1569 | return self.failTok(&block_scope.base, var_decl.firstToken(), "variable of type '{}' must be const", .{var_info.ty}); | |
| 1572 | 1570 | } |
| 1573 | 1571 | |
| 1574 | 1572 | var type_changed = true; |
| 1575 | 1573 | if (decl.typedValueManaged()) |tvm| { |
| 1576 | type_changed = !tvm.typed_value.ty.eql(var_type); | |
| 1574 | type_changed = !tvm.typed_value.ty.eql(var_info.ty); | |
| 1577 | 1575 | |
| 1578 | 1576 | tvm.deinit(self.gpa); |
| 1579 | 1577 | } |
| ... | ... | @@ -1582,7 +1580,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1582 | 1580 | const var_payload = try decl_arena.allocator.create(Value.Payload.Variable); |
| 1583 | 1581 | new_variable.* = .{ |
| 1584 | 1582 | .owner_decl = decl, |
| 1585 | .init = value orelse undefined, | |
| 1583 | .init = var_info.val orelse undefined, | |
| 1586 | 1584 | .is_extern = is_extern, |
| 1587 | 1585 | .is_mutable = is_mutable, |
| 1588 | 1586 | .is_threadlocal = is_threadlocal, |
| ... | ... | @@ -1593,7 +1591,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1593 | 1591 | decl.typed_value = .{ |
| 1594 | 1592 | .most_recent = .{ |
| 1595 | 1593 | .typed_value = .{ |
| 1596 | .ty = var_type, | |
| 1594 | .ty = var_info.ty, | |
| 1597 | 1595 | .val = Value.initPayload(&var_payload.base), |
| 1598 | 1596 | }, |
| 1599 | 1597 | .arena = decl_arena_state, |
| ... | ... | @@ -1628,8 +1626,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1628 | 1626 | }; |
| 1629 | 1627 | defer gen_scope.instructions.deinit(self.gpa); |
| 1630 | 1628 | |
| 1631 | // TODO comptime scope here | |
| 1632 | _ = try astgen.expr(self, &gen_scope.base, .none, comptime_decl.expr); | |
| 1629 | _ = try astgen.comptimeExpr(self, &gen_scope.base, .none, comptime_decl.expr); | |
| 1633 | 1630 | |
| 1634 | 1631 | var block_scope: Scope.Block = .{ |
| 1635 | 1632 | .parent = null, |
| ... | ... | @@ -1637,6 +1634,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1637 | 1634 | .decl = decl, |
| 1638 | 1635 | .instructions = .{}, |
| 1639 | 1636 | .arena = &analysis_arena.allocator, |
| 1637 | .is_comptime = true, | |
| 1640 | 1638 | }; |
| 1641 | 1639 | defer block_scope.instructions.deinit(self.gpa); |
| 1642 | 1640 | |
| ... | ... | @@ -2007,6 +2005,7 @@ fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void { |
| 2007 | 2005 | .decl = decl, |
| 2008 | 2006 | .instructions = .{}, |
| 2009 | 2007 | .arena = &arena.allocator, |
| 2008 | .is_comptime = false, | |
| 2010 | 2009 | }; |
| 2011 | 2010 | defer inner_block.instructions.deinit(self.gpa); |
| 2012 | 2011 | |
| ... | ... | @@ -2092,12 +2091,19 @@ pub fn getErrorValue(self: *Module, name: []const u8) !std.StringHashMapUnmanage |
| 2092 | 2091 | return gop.entry.*; |
| 2093 | 2092 | } |
| 2094 | 2093 | |
| 2095 | /// TODO split this into `requireRuntimeBlock` and `requireFunctionBlock` and audit callsites. | |
| 2096 | pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block { | |
| 2094 | pub fn requireFunctionBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block { | |
| 2097 | 2095 | return scope.cast(Scope.Block) orelse |
| 2098 | 2096 | return self.fail(scope, src, "instruction illegal outside function body", .{}); |
| 2099 | 2097 | } |
| 2100 | 2098 | |
| 2099 | pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block { | |
| 2100 | const block = try self.requireFunctionBlock(scope, src); | |
| 2101 | if (block.is_comptime) { | |
| 2102 | return self.fail(scope, src, "unable to resolve comptime value", .{}); | |
| 2103 | } | |
| 2104 | return block; | |
| 2105 | } | |
| 2106 | ||
| 2101 | 2107 | pub fn resolveConstValue(self: *Module, scope: *Scope, base: *Inst) !Value { |
| 2102 | 2108 | return (try self.resolveDefinedValue(scope, base)) orelse |
| 2103 | 2109 | return self.fail(scope, base.src, "unable to resolve comptime value", .{}); |
| ... | ... | @@ -3432,6 +3438,7 @@ pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic |
| 3432 | 3438 | .decl = parent_block.decl, |
| 3433 | 3439 | .instructions = .{}, |
| 3434 | 3440 | .arena = parent_block.arena, |
| 3441 | .is_comptime = parent_block.is_comptime, | |
| 3435 | 3442 | }; |
| 3436 | 3443 | defer fail_block.instructions.deinit(mod.gpa); |
| 3437 | 3444 |
src-self-hosted/astgen.zig+73-16| ... | ... | @@ -258,7 +258,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 258 | 258 | .OptionalType => return rlWrap(mod, scope, rl, try optionalType(mod, scope, node.castTag(.OptionalType).?)), |
| 259 | 259 | .UnwrapOptional => return unwrapOptional(mod, scope, rl, node.castTag(.UnwrapOptional).?), |
| 260 | 260 | .Block => return rlWrapVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)), |
| 261 | .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?), | |
| 261 | .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?, .block), | |
| 262 | 262 | .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)), |
| 263 | 263 | .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)), |
| 264 | 264 | .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr), |
| ... | ... | @@ -276,6 +276,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 276 | 276 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), |
| 277 | 277 | .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?), |
| 278 | 278 | .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?), |
| 279 | .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?), | |
| 279 | 280 | |
| 280 | 281 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), |
| 281 | 282 | .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}), |
| ... | ... | @@ -294,11 +295,46 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 294 | 295 | .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), |
| 295 | 296 | .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), |
| 296 | 297 | .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}), |
| 297 | .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}), | |
| 298 | 298 | .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}), |
| 299 | 299 | } |
| 300 | 300 | } |
| 301 | 301 | |
| 302 | fn comptimeKeyword(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Comptime) InnerError!*zir.Inst { | |
| 303 | const tracy = trace(@src()); | |
| 304 | defer tracy.end(); | |
| 305 | ||
| 306 | return comptimeExpr(mod, scope, rl, node.expr); | |
| 307 | } | |
| 308 | ||
| 309 | pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { | |
| 310 | const tree = parent_scope.tree(); | |
| 311 | const src = tree.token_locs[node.firstToken()].start; | |
| 312 | ||
| 313 | // Optimization for labeled blocks: don't need to have 2 layers of blocks, we can reuse the existing one. | |
| 314 | if (node.castTag(.LabeledBlock)) |block_node| { | |
| 315 | return labeledBlockExpr(mod, parent_scope, rl, block_node, .block_comptime); | |
| 316 | } | |
| 317 | ||
| 318 | // Make a scope to collect generated instructions in the sub-expression. | |
| 319 | var block_scope: Scope.GenZIR = .{ | |
| 320 | .parent = parent_scope, | |
| 321 | .decl = parent_scope.decl().?, | |
| 322 | .arena = parent_scope.arena(), | |
| 323 | .instructions = .{}, | |
| 324 | }; | |
| 325 | defer block_scope.instructions.deinit(mod.gpa); | |
| 326 | ||
| 327 | // No need to capture the result here because block_comptime_flat implies that the final | |
| 328 | // instruction is the block's result value. | |
| 329 | _ = try expr(mod, &block_scope.base, rl, node); | |
| 330 | ||
| 331 | const block = try addZIRInstBlock(mod, parent_scope, src, .block_comptime_flat, .{ | |
| 332 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | |
| 333 | }); | |
| 334 | ||
| 335 | return &block.base; | |
| 336 | } | |
| 337 | ||
| 302 | 338 | fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { |
| 303 | 339 | const tree = parent_scope.tree(); |
| 304 | 340 | const src = tree.token_locs[node.ltoken].start; |
| ... | ... | @@ -360,10 +396,13 @@ fn labeledBlockExpr( |
| 360 | 396 | parent_scope: *Scope, |
| 361 | 397 | rl: ResultLoc, |
| 362 | 398 | block_node: *ast.Node.LabeledBlock, |
| 399 | zir_tag: zir.Inst.Tag, | |
| 363 | 400 | ) InnerError!*zir.Inst { |
| 364 | 401 | const tracy = trace(@src()); |
| 365 | 402 | defer tracy.end(); |
| 366 | 403 | |
| 404 | assert(zir_tag == .block or zir_tag == .block_comptime); | |
| 405 | ||
| 367 | 406 | const tree = parent_scope.tree(); |
| 368 | 407 | const src = tree.token_locs[block_node.lbrace].start; |
| 369 | 408 | |
| ... | ... | @@ -373,7 +412,7 @@ fn labeledBlockExpr( |
| 373 | 412 | const block_inst = try gen_zir.arena.create(zir.Inst.Block); |
| 374 | 413 | block_inst.* = .{ |
| 375 | 414 | .base = .{ |
| 376 | .tag = .block, | |
| 415 | .tag = zir_tag, | |
| 377 | 416 | .src = src, |
| 378 | 417 | }, |
| 379 | 418 | .positionals = .{ |
| ... | ... | @@ -773,7 +812,7 @@ fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) |
| 773 | 812 | .else_body = undefined, // populated below |
| 774 | 813 | }, .{}); |
| 775 | 814 | |
| 776 | const block = try addZIRInstBlock(mod, scope, src, .{ | |
| 815 | const block = try addZIRInstBlock(mod, scope, src, .block, .{ | |
| 777 | 816 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 778 | 817 | }); |
| 779 | 818 | |
| ... | ... | @@ -946,7 +985,7 @@ fn boolBinOp( |
| 946 | 985 | .else_body = undefined, // populated below |
| 947 | 986 | }, .{}); |
| 948 | 987 | |
| 949 | const block = try addZIRInstBlock(mod, scope, src, .{ | |
| 988 | const block = try addZIRInstBlock(mod, scope, src, .block, .{ | |
| 950 | 989 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 951 | 990 | }); |
| 952 | 991 | |
| ... | ... | @@ -1095,7 +1134,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1095 | 1134 | .else_body = undefined, // populated below |
| 1096 | 1135 | }, .{}); |
| 1097 | 1136 | |
| 1098 | const block = try addZIRInstBlock(mod, scope, if_src, .{ | |
| 1137 | const block = try addZIRInstBlock(mod, scope, if_src, .block, .{ | |
| 1099 | 1138 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 1100 | 1139 | }); |
| 1101 | 1140 | |
| ... | ... | @@ -1218,7 +1257,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1218 | 1257 | .then_body = undefined, // populated below |
| 1219 | 1258 | .else_body = undefined, // populated below |
| 1220 | 1259 | }, .{}); |
| 1221 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .{ | |
| 1260 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .block, .{ | |
| 1222 | 1261 | .instructions = try loop_scope.arena.dupe(*zir.Inst, continue_scope.instructions.items), |
| 1223 | 1262 | }); |
| 1224 | 1263 | // TODO avoid emitting the continue expr when there |
| ... | ... | @@ -1231,7 +1270,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1231 | 1270 | const loop = try addZIRInstLoop(mod, &expr_scope.base, while_src, .{ |
| 1232 | 1271 | .instructions = try expr_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), |
| 1233 | 1272 | }); |
| 1234 | const while_block = try addZIRInstBlock(mod, scope, while_src, .{ | |
| 1273 | const while_block = try addZIRInstBlock(mod, scope, while_src, .block, .{ | |
| 1235 | 1274 | .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items), |
| 1236 | 1275 | }); |
| 1237 | 1276 | |
| ... | ... | @@ -1365,7 +1404,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) |
| 1365 | 1404 | .then_body = undefined, // populated below |
| 1366 | 1405 | .else_body = undefined, // populated below |
| 1367 | 1406 | }, .{}); |
| 1368 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, for_src, .{ | |
| 1407 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, for_src, .block, .{ | |
| 1369 | 1408 | .instructions = try loop_scope.arena.dupe(*zir.Inst, cond_scope.instructions.items), |
| 1370 | 1409 | }); |
| 1371 | 1410 | |
| ... | ... | @@ -1382,7 +1421,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) |
| 1382 | 1421 | const loop = try addZIRInstLoop(mod, &for_scope.base, for_src, .{ |
| 1383 | 1422 | .instructions = try for_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), |
| 1384 | 1423 | }); |
| 1385 | const for_block = try addZIRInstBlock(mod, scope, for_src, .{ | |
| 1424 | const for_block = try addZIRInstBlock(mod, scope, for_src, .block, .{ | |
| 1386 | 1425 | .instructions = try for_scope.arena.dupe(*zir.Inst, for_scope.instructions.items), |
| 1387 | 1426 | }); |
| 1388 | 1427 | |
| ... | ... | @@ -2260,6 +2299,30 @@ pub fn addZIRBinOp( |
| 2260 | 2299 | return &inst.base; |
| 2261 | 2300 | } |
| 2262 | 2301 | |
| 2302 | pub fn addZIRInstBlock( | |
| 2303 | mod: *Module, | |
| 2304 | scope: *Scope, | |
| 2305 | src: usize, | |
| 2306 | tag: zir.Inst.Tag, | |
| 2307 | body: zir.Module.Body, | |
| 2308 | ) !*zir.Inst.Block { | |
| 2309 | const gen_zir = scope.getGenZIR(); | |
| 2310 | try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1); | |
| 2311 | const inst = try gen_zir.arena.create(zir.Inst.Block); | |
| 2312 | inst.* = .{ | |
| 2313 | .base = .{ | |
| 2314 | .tag = tag, | |
| 2315 | .src = src, | |
| 2316 | }, | |
| 2317 | .positionals = .{ | |
| 2318 | .body = body, | |
| 2319 | }, | |
| 2320 | .kw_args = .{}, | |
| 2321 | }; | |
| 2322 | gen_zir.instructions.appendAssumeCapacity(&inst.base); | |
| 2323 | return inst; | |
| 2324 | } | |
| 2325 | ||
| 2263 | 2326 | pub fn addZIRInst( |
| 2264 | 2327 | mod: *Module, |
| 2265 | 2328 | scope: *Scope, |
| ... | ... | @@ -2278,12 +2341,6 @@ pub fn addZIRInstConst(mod: *Module, scope: *Scope, src: usize, typed_value: Typ |
| 2278 | 2341 | return addZIRInst(mod, scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{}); |
| 2279 | 2342 | } |
| 2280 | 2343 | |
| 2281 | /// TODO The existence of this function is a workaround for a bug in stage1. | |
| 2282 | pub fn addZIRInstBlock(mod: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Block { | |
| 2283 | const P = std.meta.fieldInfo(zir.Inst.Block, "positionals").field_type; | |
| 2284 | return addZIRInstSpecial(mod, scope, src, zir.Inst.Block, P{ .body = body }, .{}); | |
| 2285 | } | |
| 2286 | ||
| 2287 | 2344 | /// TODO The existence of this function is a workaround for a bug in stage1. |
| 2288 | 2345 | pub fn addZIRInstLoop(mod: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Loop { |
| 2289 | 2346 | const P = std.meta.fieldInfo(zir.Inst.Loop, "positionals").field_type; |
src-self-hosted/ir.zig+9-1| ... | ... | @@ -189,7 +189,7 @@ pub const Inst = struct { |
| 189 | 189 | } |
| 190 | 190 | |
| 191 | 191 | pub fn cmpOperator(base: *Inst) ?std.math.CompareOperator { |
| 192 | return switch (self.base.tag) { | |
| 192 | return switch (base.tag) { | |
| 193 | 193 | .cmp_lt => .lt, |
| 194 | 194 | .cmp_lte => .lte, |
| 195 | 195 | .cmp_eq => .eq, |
| ... | ... | @@ -220,6 +220,14 @@ pub const Inst = struct { |
| 220 | 220 | unreachable; |
| 221 | 221 | } |
| 222 | 222 | |
| 223 | pub fn breakBlock(base: *Inst) ?*Block { | |
| 224 | return switch (base.tag) { | |
| 225 | .br => base.castTag(.br).?.block, | |
| 226 | .brvoid => base.castTag(.brvoid).?.block, | |
| 227 | else => null, | |
| 228 | }; | |
| 229 | } | |
| 230 | ||
| 223 | 231 | pub const NoOp = struct { |
| 224 | 232 | base: Inst, |
| 225 | 233 |
src-self-hosted/test.zig+11-11| ... | ... | @@ -474,15 +474,15 @@ pub const TestContext = struct { |
| 474 | 474 | var all_errors = try module.getAllErrorsAlloc(); |
| 475 | 475 | defer all_errors.deinit(allocator); |
| 476 | 476 | if (all_errors.list.len != 0) { |
| 477 | std.debug.warn("\nErrors occurred updating the module:\n================\n", .{}); | |
| 477 | std.debug.print("\nErrors occurred updating the module:\n================\n", .{}); | |
| 478 | 478 | for (all_errors.list) |err| { |
| 479 | std.debug.warn(":{}:{}: error: {}\n================\n", .{ err.line + 1, err.column + 1, err.msg }); | |
| 479 | std.debug.print(":{}:{}: error: {}\n================\n", .{ err.line + 1, err.column + 1, err.msg }); | |
| 480 | 480 | } |
| 481 | 481 | if (case.cbe) { |
| 482 | 482 | const C = module.bin_file.cast(link.File.C).?; |
| 483 | std.debug.warn("Generated C: \n===============\n{}\n\n===========\n\n", .{C.main.items}); | |
| 483 | std.debug.print("Generated C: \n===============\n{}\n\n===========\n\n", .{C.main.items}); | |
| 484 | 484 | } |
| 485 | std.debug.warn("Test failed.\n", .{}); | |
| 485 | std.debug.print("Test failed.\n", .{}); | |
| 486 | 486 | std.process.exit(1); |
| 487 | 487 | } |
| 488 | 488 | } |
| ... | ... | @@ -497,12 +497,12 @@ pub const TestContext = struct { |
| 497 | 497 | var out = file.reader().readAllAlloc(arena, 1024 * 1024) catch @panic("Unable to read C output!"); |
| 498 | 498 | |
| 499 | 499 | if (expected_output.len != out.len) { |
| 500 | std.debug.warn("\nTransformed C length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ expected_output, out }); | |
| 500 | std.debug.print("\nTransformed C length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ expected_output, out }); | |
| 501 | 501 | std.process.exit(1); |
| 502 | 502 | } |
| 503 | 503 | for (expected_output) |e, i| { |
| 504 | 504 | if (out[i] != e) { |
| 505 | std.debug.warn("\nTransformed C differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ expected_output, out }); | |
| 505 | std.debug.print("\nTransformed C differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ expected_output, out }); | |
| 506 | 506 | std.process.exit(1); |
| 507 | 507 | } |
| 508 | 508 | } |
| ... | ... | @@ -526,12 +526,12 @@ pub const TestContext = struct { |
| 526 | 526 | defer test_node.end(); |
| 527 | 527 | |
| 528 | 528 | if (expected_output.len != out_zir.items.len) { |
| 529 | std.debug.warn("{}\nTransformed ZIR length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, expected_output, out_zir.items }); | |
| 529 | std.debug.print("{}\nTransformed ZIR length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, expected_output, out_zir.items }); | |
| 530 | 530 | std.process.exit(1); |
| 531 | 531 | } |
| 532 | 532 | for (expected_output) |e, i| { |
| 533 | 533 | if (out_zir.items[i] != e) { |
| 534 | std.debug.warn("{}\nTransformed ZIR differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, expected_output, out_zir.items }); | |
| 534 | std.debug.print("{}\nTransformed ZIR differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, expected_output, out_zir.items }); | |
| 535 | 535 | std.process.exit(1); |
| 536 | 536 | } |
| 537 | 537 | } |
| ... | ... | @@ -554,7 +554,7 @@ pub const TestContext = struct { |
| 554 | 554 | break; |
| 555 | 555 | } |
| 556 | 556 | } else { |
| 557 | std.debug.warn("{}\nUnexpected error:\n================\n:{}:{}: error: {}\n================\nTest failed.\n", .{ case.name, a.line + 1, a.column + 1, a.msg }); | |
| 557 | std.debug.print("{}\nUnexpected error:\n================\n:{}:{}: error: {}\n================\nTest failed.\n", .{ case.name, a.line + 1, a.column + 1, a.msg }); | |
| 558 | 558 | std.process.exit(1); |
| 559 | 559 | } |
| 560 | 560 | } |
| ... | ... | @@ -562,7 +562,7 @@ pub const TestContext = struct { |
| 562 | 562 | for (handled_errors) |h, i| { |
| 563 | 563 | if (!h) { |
| 564 | 564 | const er = e[i]; |
| 565 | std.debug.warn("{}\nDid not receive error:\n================\n{}:{}: {}\n================\nTest failed.\n", .{ case.name, er.line, er.column, er.msg }); | |
| 565 | std.debug.print("{}\nDid not receive error:\n================\n{}:{}: {}\n================\nTest failed.\n", .{ case.name, er.line, er.column, er.msg }); | |
| 566 | 566 | std.process.exit(1); |
| 567 | 567 | } |
| 568 | 568 | } |
| ... | ... | @@ -643,7 +643,7 @@ pub const TestContext = struct { |
| 643 | 643 | switch (exec_result.term) { |
| 644 | 644 | .Exited => |code| { |
| 645 | 645 | if (code != 0) { |
| 646 | std.debug.warn("elf file exited with code {}\n", .{code}); | |
| 646 | std.debug.print("elf file exited with code {}\n", .{code}); | |
| 647 | 647 | return error.BinaryBadExitCode; |
| 648 | 648 | } |
| 649 | 649 | }, |
src-self-hosted/zir.zig+16-1| ... | ... | @@ -78,6 +78,13 @@ pub const Inst = struct { |
| 78 | 78 | bitor, |
| 79 | 79 | /// A labeled block of code, which can return a value. |
| 80 | 80 | block, |
| 81 | /// A block of code, which can return a value. There are no instructions that break out of | |
| 82 | /// this block; it is implied that the final instruction is the result. | |
| 83 | block_flat, | |
| 84 | /// Same as `block` but additionally makes the inner instructions execute at comptime. | |
| 85 | block_comptime, | |
| 86 | /// Same as `block_flat` but additionally makes the inner instructions execute at comptime. | |
| 87 | block_comptime_flat, | |
| 81 | 88 | /// Boolean NOT. See also `bitnot`. |
| 82 | 89 | boolnot, |
| 83 | 90 | /// Return a value from a `Block`. |
| ... | ... | @@ -338,9 +345,14 @@ pub const Inst = struct { |
| 338 | 345 | .merge_error_sets, |
| 339 | 346 | => BinOp, |
| 340 | 347 | |
| 348 | .block, | |
| 349 | .block_flat, | |
| 350 | .block_comptime, | |
| 351 | .block_comptime_flat, | |
| 352 | => Block, | |
| 353 | ||
| 341 | 354 | .arg => Arg, |
| 342 | 355 | .array_type_sentinel => ArrayTypeSentinel, |
| 343 | .block => Block, | |
| 344 | 356 | .@"break" => Break, |
| 345 | 357 | .breakvoid => BreakVoid, |
| 346 | 358 | .call => Call, |
| ... | ... | @@ -392,6 +404,9 @@ pub const Inst = struct { |
| 392 | 404 | .bitcast_result_ptr, |
| 393 | 405 | .bitor, |
| 394 | 406 | .block, |
| 407 | .block_flat, | |
| 408 | .block_comptime, | |
| 409 | .block_comptime_flat, | |
| 395 | 410 | .boolnot, |
| 396 | 411 | .breakpoint, |
| 397 | 412 | .call, |
src-self-hosted/zir_sema.zig+64-14| ... | ... | @@ -31,7 +31,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 31 | 31 | .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?), |
| 32 | 32 | .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?), |
| 33 | 33 | .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?), |
| 34 | .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?), | |
| 34 | .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?, false), | |
| 35 | .block_comptime => return analyzeInstBlock(mod, scope, old_inst.castTag(.block_comptime).?, true), | |
| 36 | .block_flat => return analyzeInstBlockFlat(mod, scope, old_inst.castTag(.block_flat).?, false), | |
| 37 | .block_comptime_flat => return analyzeInstBlockFlat(mod, scope, old_inst.castTag(.block_comptime_flat).?, true), | |
| 35 | 38 | .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?), |
| 36 | 39 | .breakpoint => return analyzeInstBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?), |
| 37 | 40 | .breakvoid => return analyzeInstBreakVoid(mod, scope, old_inst.castTag(.breakvoid).?), |
| ... | ... | @@ -147,17 +150,16 @@ pub fn analyzeBody(mod: *Module, scope: *Scope, body: zir.Module.Body) !void { |
| 147 | 150 | } |
| 148 | 151 | } |
| 149 | 152 | |
| 150 | pub fn analyzeBodyValueAsType(mod: *Module, block_scope: *Scope.Block, body: zir.Module.Body) !Type { | |
| 153 | pub fn analyzeBodyValueAsType( | |
| 154 | mod: *Module, | |
| 155 | block_scope: *Scope.Block, | |
| 156 | zir_result_inst: *zir.Inst, | |
| 157 | body: zir.Module.Body, | |
| 158 | ) !Type { | |
| 151 | 159 | try analyzeBody(mod, &block_scope.base, body); |
| 152 | for (block_scope.instructions.items) |inst| { | |
| 153 | if (inst.castTag(.ret)) |ret| { | |
| 154 | const val = try mod.resolveConstValue(&block_scope.base, ret.operand); | |
| 155 | return val.toType(block_scope.base.arena()); | |
| 156 | } else { | |
| 157 | return mod.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); | |
| 158 | } | |
| 159 | } | |
| 160 | unreachable; | |
| 160 | const result_inst = zir_result_inst.analyzed_inst.?; | |
| 161 | const val = try mod.resolveConstValue(&block_scope.base, result_inst); | |
| 162 | return val.toType(block_scope.base.arena()); | |
| 161 | 163 | } |
| 162 | 164 | |
| 163 | 165 | pub fn analyzeZirDecl(mod: *Module, decl: *Decl, src_decl: *zir.Decl) InnerError!bool { |
| ... | ... | @@ -362,7 +364,7 @@ fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError! |
| 362 | 364 | } |
| 363 | 365 | |
| 364 | 366 | fn analyzeInstRetType(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { |
| 365 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); | |
| 367 | const b = try mod.requireFunctionBlock(scope, inst.base.src); | |
| 366 | 368 | const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty; |
| 367 | 369 | const ret_type = fn_ty.fnReturnType(); |
| 368 | 370 | return mod.constType(scope, inst.base.src, ret_type); |
| ... | ... | @@ -517,6 +519,7 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError |
| 517 | 519 | .decl = parent_block.decl, |
| 518 | 520 | .instructions = .{}, |
| 519 | 521 | .arena = parent_block.arena, |
| 522 | .is_comptime = parent_block.is_comptime, | |
| 520 | 523 | }; |
| 521 | 524 | defer child_block.instructions.deinit(mod.gpa); |
| 522 | 525 | |
| ... | ... | @@ -529,7 +532,29 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError |
| 529 | 532 | return &loop_inst.base; |
| 530 | 533 | } |
| 531 | 534 | |
| 532 | fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst { | |
| 535 | fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst { | |
| 536 | const parent_block = scope.cast(Scope.Block).?; | |
| 537 | ||
| 538 | var child_block: Scope.Block = .{ | |
| 539 | .parent = parent_block, | |
| 540 | .func = parent_block.func, | |
| 541 | .decl = parent_block.decl, | |
| 542 | .instructions = .{}, | |
| 543 | .arena = parent_block.arena, | |
| 544 | .label = null, | |
| 545 | .is_comptime = parent_block.is_comptime or is_comptime, | |
| 546 | }; | |
| 547 | defer child_block.instructions.deinit(mod.gpa); | |
| 548 | ||
| 549 | try analyzeBody(mod, &child_block.base, inst.positionals.body); | |
| 550 | ||
| 551 | const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items); | |
| 552 | try parent_block.instructions.appendSlice(mod.gpa, copied_instructions); | |
| 553 | ||
| 554 | return copied_instructions[copied_instructions.len - 1]; | |
| 555 | } | |
| 556 | ||
| 557 | fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst { | |
| 533 | 558 | const parent_block = scope.cast(Scope.Block).?; |
| 534 | 559 | |
| 535 | 560 | // Reserve space for a Block instruction so that generated Break instructions can |
| ... | ... | @@ -557,6 +582,7 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerErr |
| 557 | 582 | .results = .{}, |
| 558 | 583 | .block_inst = block_inst, |
| 559 | 584 | }), |
| 585 | .is_comptime = is_comptime or parent_block.is_comptime, | |
| 560 | 586 | }; |
| 561 | 587 | const label = &child_block.label.?; |
| 562 | 588 | |
| ... | ... | @@ -569,6 +595,28 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerErr |
| 569 | 595 | assert(child_block.instructions.items.len != 0); |
| 570 | 596 | assert(child_block.instructions.items[child_block.instructions.items.len - 1].ty.isNoReturn()); |
| 571 | 597 | |
| 598 | if (label.results.items.len == 0) { | |
| 599 | // No need for a block instruction. We can put the new instructions directly into the parent block. | |
| 600 | const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items); | |
| 601 | try parent_block.instructions.appendSlice(mod.gpa, copied_instructions); | |
| 602 | return copied_instructions[copied_instructions.len - 1]; | |
| 603 | } | |
| 604 | if (label.results.items.len == 1) { | |
| 605 | const last_inst_index = child_block.instructions.items.len - 1; | |
| 606 | const last_inst = child_block.instructions.items[last_inst_index]; | |
| 607 | if (last_inst.breakBlock()) |br_block| { | |
| 608 | if (br_block == block_inst) { | |
| 609 | // No need for a block instruction. We can put the new instructions directly into the parent block. | |
| 610 | // Here we omit the break instruction. | |
| 611 | const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items[0..last_inst_index]); | |
| 612 | try parent_block.instructions.appendSlice(mod.gpa, copied_instructions); | |
| 613 | return label.results.items[0]; | |
| 614 | } | |
| 615 | } | |
| 616 | } | |
| 617 | // It should be impossible to have the number of results be > 1 in a comptime scope. | |
| 618 | assert(!child_block.is_comptime); // We should have already got a compile error in the condbr condition. | |
| 619 | ||
| 572 | 620 | // Need to set the type and emit the Block instruction. This allows machine code generation |
| 573 | 621 | // to emit a jump instruction to after the block when it encounters the break. |
| 574 | 622 | try parent_block.instructions.append(mod.gpa, &block_inst.base); |
| ... | ... | @@ -1083,7 +1131,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne |
| 1083 | 1131 | const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr); |
| 1084 | 1132 | const uncasted_index = try resolveInst(mod, scope, inst.positionals.index); |
| 1085 | 1133 | const elem_index = try mod.coerce(scope, Type.initTag(.usize), uncasted_index); |
| 1086 | ||
| 1134 | ||
| 1087 | 1135 | const elem_ty = switch (array_ptr.ty.zigTypeTag()) { |
| 1088 | 1136 | .Pointer => array_ptr.ty.elemType(), |
| 1089 | 1137 | else => return mod.fail(scope, inst.positionals.array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}), |
| ... | ... | @@ -1376,6 +1424,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE |
| 1376 | 1424 | .decl = parent_block.decl, |
| 1377 | 1425 | .instructions = .{}, |
| 1378 | 1426 | .arena = parent_block.arena, |
| 1427 | .is_comptime = parent_block.is_comptime, | |
| 1379 | 1428 | }; |
| 1380 | 1429 | defer true_block.instructions.deinit(mod.gpa); |
| 1381 | 1430 | try analyzeBody(mod, &true_block.base, inst.positionals.then_body); |
| ... | ... | @@ -1386,6 +1435,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE |
| 1386 | 1435 | .decl = parent_block.decl, |
| 1387 | 1436 | .instructions = .{}, |
| 1388 | 1437 | .arena = parent_block.arena, |
| 1438 | .is_comptime = parent_block.is_comptime, | |
| 1389 | 1439 | }; |
| 1390 | 1440 | defer false_block.instructions.deinit(mod.gpa); |
| 1391 | 1441 | try analyzeBody(mod, &false_block.base, inst.positionals.else_body); |
test/stage2/test.zig+16-7| ... | ... | @@ -274,7 +274,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 274 | 274 | } |
| 275 | 275 | |
| 276 | 276 | { |
| 277 | var case = ctx.exe("substracting numbers at runtime", linux_x64); | |
| 277 | var case = ctx.exe("subtracting numbers at runtime", linux_x64); | |
| 278 | 278 | case.addCompareOutput( |
| 279 | 279 | \\export fn _start() noreturn { |
| 280 | 280 | \\ sub(7, 4); |
| ... | ... | @@ -967,10 +967,19 @@ pub fn addCases(ctx: *TestContext) !void { |
| 967 | 967 | \\fn entry() void {} |
| 968 | 968 | , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); |
| 969 | 969 | |
| 970 | ctx.compileError("extern variable has no type", linux_x64, | |
| 971 | \\comptime { | |
| 972 | \\ _ = foo; | |
| 973 | \\} | |
| 974 | \\extern var foo; | |
| 975 | , &[_][]const u8{":4:1: error: unable to infer variable type"}); | |
| 970 | { | |
| 971 | var case = ctx.obj("extern variable has no type", linux_x64); | |
| 972 | case.addError( | |
| 973 | \\comptime { | |
| 974 | \\ _ = foo; | |
| 975 | \\} | |
| 976 | \\extern var foo; | |
| 977 | , &[_][]const u8{":2:5: error: unable to resolve comptime value"}); | |
| 978 | case.addError( | |
| 979 | \\export fn entry() void { | |
| 980 | \\ _ = foo; | |
| 981 | \\} | |
| 982 | \\extern var foo; | |
| 983 | , &[_][]const u8{":4:1: error: unable to infer variable type"}); | |
| 984 | } | |
| 976 | 985 | } |