authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-01 15:44:45-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-09-01 15:44:45-04:00
log3f7cb14b267bbd823597ba24fd2e3f6f66abcbaa
tree9d3ce364c8619ac5ca6ce273be0b86164264a9d7
parentbaa734c42a2bdb3f63fd26dd30bc8c9a846831bf
parent4c13d020dbecbd7664b99765de33f230e98f3322
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6225 from ziglang/stage2-comptime

stage2: introduce the ability for Scope.Block to be comptime

7 files changed, 259 insertions(+), 113 deletions(-)

src-self-hosted/Module.zig+70-63
...@@ -725,6 +725,7 @@ pub const Scope = struct {...@@ -725,6 +725,7 @@ pub const Scope = struct {
725 /// Points to the arena allocator of DeclAnalysis725 /// Points to the arena allocator of DeclAnalysis
726 arena: *Allocator,726 arena: *Allocator,
727 label: ?Label = null,727 label: ?Label = null,
728 is_comptime: bool,
728729
729 pub const Label = struct {730 pub const Label = struct {
730 zir_block: *zir.Inst.Block,731 zir_block: *zir.Inst.Block,
...@@ -1307,7 +1308,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1307,7 +1308,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1307 .return_type = return_type_inst,1308 .return_type = return_type_inst,
1308 .param_types = param_types,1309 .param_types = param_types,
1309 }, .{});1310 }, .{});
1310 _ = try astgen.addZIRUnOp(self, &fn_type_scope.base, fn_src, .@"return", fn_type_inst);
13111311
1312 // We need the memory for the Type to go into the arena for the Decl1312 // We need the memory for the Type to go into the arena for the Decl
1313 var decl_arena = std.heap.ArenaAllocator.init(self.gpa);1313 var decl_arena = std.heap.ArenaAllocator.init(self.gpa);
...@@ -1320,10 +1320,11 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1320,10 +1320,11 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1320 .decl = decl,1320 .decl = decl,
1321 .instructions = .{},1321 .instructions = .{},
1322 .arena = &decl_arena.allocator,1322 .arena = &decl_arena.allocator,
1323 .is_comptime = false,
1323 };1324 };
1324 defer block_scope.instructions.deinit(self.gpa);1325 defer block_scope.instructions.deinit(self.gpa);
13251326
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 .instructions = fn_type_scope.instructions.items,1328 .instructions = fn_type_scope.instructions.items,
1328 });1329 });
1329 const new_func = try decl_arena.allocator.create(Fn);1330 const new_func = try decl_arena.allocator.create(Fn);
...@@ -1457,6 +1458,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1457,6 +1458,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1457 .decl = decl,1458 .decl = decl,
1458 .instructions = .{},1459 .instructions = .{},
1459 .arena = &decl_arena.allocator,1460 .arena = &decl_arena.allocator,
1461 .is_comptime = true,
1460 };1462 };
1461 defer block_scope.instructions.deinit(self.gpa);1463 defer block_scope.instructions.deinit(self.gpa);
14621464
...@@ -1489,35 +1491,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1489,35 +1491,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1489 return self.failNode(&block_scope.base, sect_expr, "TODO implement function section expression", .{});1491 return self.failNode(&block_scope.base, sect_expr, "TODO implement function section expression", .{});
1490 }1492 }
14911493
1492 const explicit_type = blk: {1494 const var_info: struct { ty: Type, val: ?Value } = if (var_decl.getInitNode()) |init_node| vi: {
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: {
1521 var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa);1495 var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1522 defer gen_scope_arena.deinit();1496 defer gen_scope_arena.deinit();
1523 var gen_scope: Scope.GenZIR = .{1497 var gen_scope: Scope.GenZIR = .{
...@@ -1526,11 +1500,19 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1526,11 +1500,19 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1526 .parent = decl.scope,1500 .parent = decl.scope,
1527 };1501 };
1528 defer gen_scope.instructions.deinit(self.gpa);1502 defer gen_scope.instructions.deinit(self.gpa);
1529 const src = tree.token_locs[init_node.firstToken()].start;
15301503
1531 // TODO comptime scope here1504 const init_result_loc: astgen.ResultLoc = if (var_decl.getTypeNode()) |type_node| rl: {
1532 const init_inst = try astgen.expr(self, &gen_scope.base, .none, init_node);1505 const src = tree.token_locs[type_node.firstToken()].start;
1533 _ = try astgen.addZIRUnOp(self, &gen_scope.base, src, .@"return", init_inst);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);
15341516
1535 var inner_block: Scope.Block = .{1517 var inner_block: Scope.Block = .{
1536 .parent = null,1518 .parent = null,
...@@ -1538,42 +1520,58 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1538,42 +1520,58 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1538 .decl = decl,1520 .decl = decl,
1539 .instructions = .{},1521 .instructions = .{},
1540 .arena = &gen_scope_arena.allocator,1522 .arena = &gen_scope_arena.allocator,
1523 .is_comptime = true,
1541 };1524 };
1542 defer inner_block.instructions.deinit(self.gpa);1525 defer inner_block.instructions.deinit(self.gpa);
1543 try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items });1526 try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items });
15441527
1545 for (inner_block.instructions.items) |inst| {1528 // The result location guarantees the type coercion.
1546 if (inst.castTag(.ret)) |ret| {1529 const analyzed_init_inst = init_inst.analyzed_inst.?;
1547 const coerced = if (explicit_type) |some|1530 // The is_comptime in the Scope.Block guarantees the result is comptime-known.
1548 try self.coerce(&inner_block.base, some, ret.operand)1531 const val = analyzed_init_inst.value().?;
1549 else1532
1550 ret.operand;1533 const ty = try analyzed_init_inst.ty.copy(block_scope.arena);
1551 const val = coerced.value() orelse1534 break :vi .{
1552 return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{});1535 .ty = ty,
15531536 .val = try val.copy(block_scope.arena),
1554 var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena);1537 };
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;
1561 } else if (!is_extern) {1538 } else if (!is_extern) {
1562 return self.failTok(&block_scope.base, var_decl.firstToken(), "variables must be initialized", .{});1539 return self.failTok(&block_scope.base, var_decl.firstToken(), "variables must be initialized", .{});
1563 } else if (explicit_type) |some| blk: {1540 } else if (var_decl.getTypeNode()) |type_node| vi: {
1564 var_type = some;1541 // Temporary arena for the zir instructions.
1565 break :blk null;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 } else {1564 } else {
1567 return self.failTok(&block_scope.base, var_decl.firstToken(), "unable to infer variable type", .{});1565 return self.failTok(&block_scope.base, var_decl.firstToken(), "unable to infer variable type", .{});
1568 };1566 };
15691567
1570 if (is_mutable and !var_type.isValidVarType(is_extern)) {1568 if (is_mutable and !var_info.ty.isValidVarType(is_extern)) {
1571 return self.failTok(&block_scope.base, var_decl.firstToken(), "variable of type '{}' must be const", .{var_type});1569 return self.failTok(&block_scope.base, var_decl.firstToken(), "variable of type '{}' must be const", .{var_info.ty});
1572 }1570 }
15731571
1574 var type_changed = true;1572 var type_changed = true;
1575 if (decl.typedValueManaged()) |tvm| {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);
15771575
1578 tvm.deinit(self.gpa);1576 tvm.deinit(self.gpa);
1579 }1577 }
...@@ -1582,7 +1580,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1582,7 +1580,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1582 const var_payload = try decl_arena.allocator.create(Value.Payload.Variable);1580 const var_payload = try decl_arena.allocator.create(Value.Payload.Variable);
1583 new_variable.* = .{1581 new_variable.* = .{
1584 .owner_decl = decl,1582 .owner_decl = decl,
1585 .init = value orelse undefined,1583 .init = var_info.val orelse undefined,
1586 .is_extern = is_extern,1584 .is_extern = is_extern,
1587 .is_mutable = is_mutable,1585 .is_mutable = is_mutable,
1588 .is_threadlocal = is_threadlocal,1586 .is_threadlocal = is_threadlocal,
...@@ -1593,7 +1591,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1593,7 +1591,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1593 decl.typed_value = .{1591 decl.typed_value = .{
1594 .most_recent = .{1592 .most_recent = .{
1595 .typed_value = .{1593 .typed_value = .{
1596 .ty = var_type,1594 .ty = var_info.ty,
1597 .val = Value.initPayload(&var_payload.base),1595 .val = Value.initPayload(&var_payload.base),
1598 },1596 },
1599 .arena = decl_arena_state,1597 .arena = decl_arena_state,
...@@ -1628,8 +1626,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1628,8 +1626,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1628 };1626 };
1629 defer gen_scope.instructions.deinit(self.gpa);1627 defer gen_scope.instructions.deinit(self.gpa);
16301628
1631 // TODO comptime scope here1629 _ = try astgen.comptimeExpr(self, &gen_scope.base, .none, comptime_decl.expr);
1632 _ = try astgen.expr(self, &gen_scope.base, .none, comptime_decl.expr);
16331630
1634 var block_scope: Scope.Block = .{1631 var block_scope: Scope.Block = .{
1635 .parent = null,1632 .parent = null,
...@@ -1637,6 +1634,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1637,6 +1634,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1637 .decl = decl,1634 .decl = decl,
1638 .instructions = .{},1635 .instructions = .{},
1639 .arena = &analysis_arena.allocator,1636 .arena = &analysis_arena.allocator,
1637 .is_comptime = true,
1640 };1638 };
1641 defer block_scope.instructions.deinit(self.gpa);1639 defer block_scope.instructions.deinit(self.gpa);
16421640
...@@ -2007,6 +2005,7 @@ fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {...@@ -2007,6 +2005,7 @@ fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {
2007 .decl = decl,2005 .decl = decl,
2008 .instructions = .{},2006 .instructions = .{},
2009 .arena = &arena.allocator,2007 .arena = &arena.allocator,
2008 .is_comptime = false,
2010 };2009 };
2011 defer inner_block.instructions.deinit(self.gpa);2010 defer inner_block.instructions.deinit(self.gpa);
20122011
...@@ -2092,12 +2091,19 @@ pub fn getErrorValue(self: *Module, name: []const u8) !std.StringHashMapUnmanage...@@ -2092,12 +2091,19 @@ pub fn getErrorValue(self: *Module, name: []const u8) !std.StringHashMapUnmanage
2092 return gop.entry.*;2091 return gop.entry.*;
2093}2092}
20942093
2095/// TODO split this into `requireRuntimeBlock` and `requireFunctionBlock` and audit callsites.2094pub fn requireFunctionBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
2096pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
2097 return scope.cast(Scope.Block) orelse2095 return scope.cast(Scope.Block) orelse
2098 return self.fail(scope, src, "instruction illegal outside function body", .{});2096 return self.fail(scope, src, "instruction illegal outside function body", .{});
2099}2097}
21002098
2099pub 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
2101pub fn resolveConstValue(self: *Module, scope: *Scope, base: *Inst) !Value {2107pub fn resolveConstValue(self: *Module, scope: *Scope, base: *Inst) !Value {
2102 return (try self.resolveDefinedValue(scope, base)) orelse2108 return (try self.resolveDefinedValue(scope, base)) orelse
2103 return self.fail(scope, base.src, "unable to resolve comptime value", .{});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,6 +3438,7 @@ pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic
3432 .decl = parent_block.decl,3438 .decl = parent_block.decl,
3433 .instructions = .{},3439 .instructions = .{},
3434 .arena = parent_block.arena,3440 .arena = parent_block.arena,
3441 .is_comptime = parent_block.is_comptime,
3435 };3442 };
3436 defer fail_block.instructions.deinit(mod.gpa);3443 defer fail_block.instructions.deinit(mod.gpa);
34373444
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,7 +258,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
258 .OptionalType => return rlWrap(mod, scope, rl, try optionalType(mod, scope, node.castTag(.OptionalType).?)),258 .OptionalType => return rlWrap(mod, scope, rl, try optionalType(mod, scope, node.castTag(.OptionalType).?)),
259 .UnwrapOptional => return unwrapOptional(mod, scope, rl, node.castTag(.UnwrapOptional).?),259 .UnwrapOptional => return unwrapOptional(mod, scope, rl, node.castTag(.UnwrapOptional).?),
260 .Block => return rlWrapVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)),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 .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)),262 .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)),
263 .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)),263 .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)),
264 .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr),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,6 +276,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
276 .For => return forExpr(mod, scope, rl, node.castTag(.For).?),276 .For => return forExpr(mod, scope, rl, node.castTag(.For).?),
277 .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?),277 .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?),
278 .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?),278 .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?),
279 .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?),
279280
280 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),281 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
281 .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),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,11 +295,46 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
294 .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}),295 .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}),
295 .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}),296 .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}),
296 .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}),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 .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}),298 .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}),
299 }299 }
300}300}
301301
302fn 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
309pub 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
302fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst {338fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst {
303 const tree = parent_scope.tree();339 const tree = parent_scope.tree();
304 const src = tree.token_locs[node.ltoken].start;340 const src = tree.token_locs[node.ltoken].start;
...@@ -360,10 +396,13 @@ fn labeledBlockExpr(...@@ -360,10 +396,13 @@ fn labeledBlockExpr(
360 parent_scope: *Scope,396 parent_scope: *Scope,
361 rl: ResultLoc,397 rl: ResultLoc,
362 block_node: *ast.Node.LabeledBlock,398 block_node: *ast.Node.LabeledBlock,
399 zir_tag: zir.Inst.Tag,
363) InnerError!*zir.Inst {400) InnerError!*zir.Inst {
364 const tracy = trace(@src());401 const tracy = trace(@src());
365 defer tracy.end();402 defer tracy.end();
366403
404 assert(zir_tag == .block or zir_tag == .block_comptime);
405
367 const tree = parent_scope.tree();406 const tree = parent_scope.tree();
368 const src = tree.token_locs[block_node.lbrace].start;407 const src = tree.token_locs[block_node.lbrace].start;
369408
...@@ -373,7 +412,7 @@ fn labeledBlockExpr(...@@ -373,7 +412,7 @@ fn labeledBlockExpr(
373 const block_inst = try gen_zir.arena.create(zir.Inst.Block);412 const block_inst = try gen_zir.arena.create(zir.Inst.Block);
374 block_inst.* = .{413 block_inst.* = .{
375 .base = .{414 .base = .{
376 .tag = .block,415 .tag = zir_tag,
377 .src = src,416 .src = src,
378 },417 },
379 .positionals = .{418 .positionals = .{
...@@ -773,7 +812,7 @@ fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch)...@@ -773,7 +812,7 @@ fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch)
773 .else_body = undefined, // populated below812 .else_body = undefined, // populated below
774 }, .{});813 }, .{});
775814
776 const block = try addZIRInstBlock(mod, scope, src, .{815 const block = try addZIRInstBlock(mod, scope, src, .block, .{
777 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),816 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
778 });817 });
779818
...@@ -946,7 +985,7 @@ fn boolBinOp(...@@ -946,7 +985,7 @@ fn boolBinOp(
946 .else_body = undefined, // populated below985 .else_body = undefined, // populated below
947 }, .{});986 }, .{});
948987
949 const block = try addZIRInstBlock(mod, scope, src, .{988 const block = try addZIRInstBlock(mod, scope, src, .block, .{
950 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),989 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
951 });990 });
952991
...@@ -1095,7 +1134,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn...@@ -1095,7 +1134,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
1095 .else_body = undefined, // populated below1134 .else_body = undefined, // populated below
1096 }, .{});1135 }, .{});
10971136
1098 const block = try addZIRInstBlock(mod, scope, if_src, .{1137 const block = try addZIRInstBlock(mod, scope, if_src, .block, .{
1099 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),1138 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
1100 });1139 });
11011140
...@@ -1218,7 +1257,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W...@@ -1218,7 +1257,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
1218 .then_body = undefined, // populated below1257 .then_body = undefined, // populated below
1219 .else_body = undefined, // populated below1258 .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 .instructions = try loop_scope.arena.dupe(*zir.Inst, continue_scope.instructions.items),1261 .instructions = try loop_scope.arena.dupe(*zir.Inst, continue_scope.instructions.items),
1223 });1262 });
1224 // TODO avoid emitting the continue expr when there1263 // 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,7 +1270,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
1231 const loop = try addZIRInstLoop(mod, &expr_scope.base, while_src, .{1270 const loop = try addZIRInstLoop(mod, &expr_scope.base, while_src, .{
1232 .instructions = try expr_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items),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 .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items),1274 .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items),
1236 });1275 });
12371276
...@@ -1365,7 +1404,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)...@@ -1365,7 +1404,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)
1365 .then_body = undefined, // populated below1404 .then_body = undefined, // populated below
1366 .else_body = undefined, // populated below1405 .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 .instructions = try loop_scope.arena.dupe(*zir.Inst, cond_scope.instructions.items),1408 .instructions = try loop_scope.arena.dupe(*zir.Inst, cond_scope.instructions.items),
1370 });1409 });
13711410
...@@ -1382,7 +1421,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)...@@ -1382,7 +1421,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)
1382 const loop = try addZIRInstLoop(mod, &for_scope.base, for_src, .{1421 const loop = try addZIRInstLoop(mod, &for_scope.base, for_src, .{
1383 .instructions = try for_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items),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 .instructions = try for_scope.arena.dupe(*zir.Inst, for_scope.instructions.items),1425 .instructions = try for_scope.arena.dupe(*zir.Inst, for_scope.instructions.items),
1387 });1426 });
13881427
...@@ -2260,6 +2299,30 @@ pub fn addZIRBinOp(...@@ -2260,6 +2299,30 @@ pub fn addZIRBinOp(
2260 return &inst.base;2299 return &inst.base;
2261}2300}
22622301
2302pub 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
2263pub fn addZIRInst(2326pub fn addZIRInst(
2264 mod: *Module,2327 mod: *Module,
2265 scope: *Scope,2328 scope: *Scope,
...@@ -2278,12 +2341,6 @@ pub fn addZIRInstConst(mod: *Module, scope: *Scope, src: usize, typed_value: Typ...@@ -2278,12 +2341,6 @@ pub fn addZIRInstConst(mod: *Module, scope: *Scope, src: usize, typed_value: Typ
2278 return addZIRInst(mod, scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{});2341 return addZIRInst(mod, scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{});
2279}2342}
22802343
2281/// TODO The existence of this function is a workaround for a bug in stage1.
2282pub 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/// TODO The existence of this function is a workaround for a bug in stage1.2344/// TODO The existence of this function is a workaround for a bug in stage1.
2288pub fn addZIRInstLoop(mod: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Loop {2345pub fn addZIRInstLoop(mod: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Loop {
2289 const P = std.meta.fieldInfo(zir.Inst.Loop, "positionals").field_type;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,7 +189,7 @@ pub const Inst = struct {
189 }189 }
190190
191 pub fn cmpOperator(base: *Inst) ?std.math.CompareOperator {191 pub fn cmpOperator(base: *Inst) ?std.math.CompareOperator {
192 return switch (self.base.tag) {192 return switch (base.tag) {
193 .cmp_lt => .lt,193 .cmp_lt => .lt,
194 .cmp_lte => .lte,194 .cmp_lte => .lte,
195 .cmp_eq => .eq,195 .cmp_eq => .eq,
...@@ -220,6 +220,14 @@ pub const Inst = struct {...@@ -220,6 +220,14 @@ pub const Inst = struct {
220 unreachable;220 unreachable;
221 }221 }
222222
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 pub const NoOp = struct {231 pub const NoOp = struct {
224 base: Inst,232 base: Inst,
225233
src-self-hosted/test.zig+11-11
...@@ -474,15 +474,15 @@ pub const TestContext = struct {...@@ -474,15 +474,15 @@ pub const TestContext = struct {
474 var all_errors = try module.getAllErrorsAlloc();474 var all_errors = try module.getAllErrorsAlloc();
475 defer all_errors.deinit(allocator);475 defer all_errors.deinit(allocator);
476 if (all_errors.list.len != 0) {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 for (all_errors.list) |err| {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 if (case.cbe) {481 if (case.cbe) {
482 const C = module.bin_file.cast(link.File.C).?;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 std.process.exit(1);486 std.process.exit(1);
487 }487 }
488 }488 }
...@@ -497,12 +497,12 @@ pub const TestContext = struct {...@@ -497,12 +497,12 @@ pub const TestContext = struct {
497 var out = file.reader().readAllAlloc(arena, 1024 * 1024) catch @panic("Unable to read C output!");497 var out = file.reader().readAllAlloc(arena, 1024 * 1024) catch @panic("Unable to read C output!");
498498
499 if (expected_output.len != out.len) {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 std.process.exit(1);501 std.process.exit(1);
502 }502 }
503 for (expected_output) |e, i| {503 for (expected_output) |e, i| {
504 if (out[i] != e) {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 std.process.exit(1);506 std.process.exit(1);
507 }507 }
508 }508 }
...@@ -526,12 +526,12 @@ pub const TestContext = struct {...@@ -526,12 +526,12 @@ pub const TestContext = struct {
526 defer test_node.end();526 defer test_node.end();
527527
528 if (expected_output.len != out_zir.items.len) {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 std.process.exit(1);530 std.process.exit(1);
531 }531 }
532 for (expected_output) |e, i| {532 for (expected_output) |e, i| {
533 if (out_zir.items[i] != e) {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 std.process.exit(1);535 std.process.exit(1);
536 }536 }
537 }537 }
...@@ -554,7 +554,7 @@ pub const TestContext = struct {...@@ -554,7 +554,7 @@ pub const TestContext = struct {
554 break;554 break;
555 }555 }
556 } else {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 std.process.exit(1);558 std.process.exit(1);
559 }559 }
560 }560 }
...@@ -562,7 +562,7 @@ pub const TestContext = struct {...@@ -562,7 +562,7 @@ pub const TestContext = struct {
562 for (handled_errors) |h, i| {562 for (handled_errors) |h, i| {
563 if (!h) {563 if (!h) {
564 const er = e[i];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 std.process.exit(1);566 std.process.exit(1);
567 }567 }
568 }568 }
...@@ -643,7 +643,7 @@ pub const TestContext = struct {...@@ -643,7 +643,7 @@ pub const TestContext = struct {
643 switch (exec_result.term) {643 switch (exec_result.term) {
644 .Exited => |code| {644 .Exited => |code| {
645 if (code != 0) {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 return error.BinaryBadExitCode;647 return error.BinaryBadExitCode;
648 }648 }
649 },649 },
src-self-hosted/zir.zig+16-1
...@@ -78,6 +78,13 @@ pub const Inst = struct {...@@ -78,6 +78,13 @@ pub const Inst = struct {
78 bitor,78 bitor,
79 /// A labeled block of code, which can return a value.79 /// A labeled block of code, which can return a value.
80 block,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 /// Boolean NOT. See also `bitnot`.88 /// Boolean NOT. See also `bitnot`.
82 boolnot,89 boolnot,
83 /// Return a value from a `Block`.90 /// Return a value from a `Block`.
...@@ -338,9 +345,14 @@ pub const Inst = struct {...@@ -338,9 +345,14 @@ pub const Inst = struct {
338 .merge_error_sets,345 .merge_error_sets,
339 => BinOp,346 => BinOp,
340347
348 .block,
349 .block_flat,
350 .block_comptime,
351 .block_comptime_flat,
352 => Block,
353
341 .arg => Arg,354 .arg => Arg,
342 .array_type_sentinel => ArrayTypeSentinel,355 .array_type_sentinel => ArrayTypeSentinel,
343 .block => Block,
344 .@"break" => Break,356 .@"break" => Break,
345 .breakvoid => BreakVoid,357 .breakvoid => BreakVoid,
346 .call => Call,358 .call => Call,
...@@ -392,6 +404,9 @@ pub const Inst = struct {...@@ -392,6 +404,9 @@ pub const Inst = struct {
392 .bitcast_result_ptr,404 .bitcast_result_ptr,
393 .bitor,405 .bitor,
394 .block,406 .block,
407 .block_flat,
408 .block_comptime,
409 .block_comptime_flat,
395 .boolnot,410 .boolnot,
396 .breakpoint,411 .breakpoint,
397 .call,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,7 +31,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
31 .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?),31 .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?),
32 .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?),32 .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?),
33 .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?),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 .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?),38 .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?),
36 .breakpoint => return analyzeInstBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?),39 .breakpoint => return analyzeInstBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?),
37 .breakvoid => return analyzeInstBreakVoid(mod, scope, old_inst.castTag(.breakvoid).?),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,17 +150,16 @@ pub fn analyzeBody(mod: *Module, scope: *Scope, body: zir.Module.Body) !void {
147 }150 }
148}151}
149152
150pub fn analyzeBodyValueAsType(mod: *Module, block_scope: *Scope.Block, body: zir.Module.Body) !Type {153pub fn analyzeBodyValueAsType(
154 mod: *Module,
155 block_scope: *Scope.Block,
156 zir_result_inst: *zir.Inst,
157 body: zir.Module.Body,
158) !Type {
151 try analyzeBody(mod, &block_scope.base, body);159 try analyzeBody(mod, &block_scope.base, body);
152 for (block_scope.instructions.items) |inst| {160 const result_inst = zir_result_inst.analyzed_inst.?;
153 if (inst.castTag(.ret)) |ret| {161 const val = try mod.resolveConstValue(&block_scope.base, result_inst);
154 const val = try mod.resolveConstValue(&block_scope.base, ret.operand);162 return val.toType(block_scope.base.arena());
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;
161}163}
162164
163pub fn analyzeZirDecl(mod: *Module, decl: *Decl, src_decl: *zir.Decl) InnerError!bool {165pub 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,7 +364,7 @@ fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!
362}364}
363365
364fn analyzeInstRetType(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {366fn 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 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;368 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
367 const ret_type = fn_ty.fnReturnType();369 const ret_type = fn_ty.fnReturnType();
368 return mod.constType(scope, inst.base.src, ret_type);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,6 +519,7 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError
517 .decl = parent_block.decl,519 .decl = parent_block.decl,
518 .instructions = .{},520 .instructions = .{},
519 .arena = parent_block.arena,521 .arena = parent_block.arena,
522 .is_comptime = parent_block.is_comptime,
520 };523 };
521 defer child_block.instructions.deinit(mod.gpa);524 defer child_block.instructions.deinit(mod.gpa);
522525
...@@ -529,7 +532,29 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError...@@ -529,7 +532,29 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError
529 return &loop_inst.base;532 return &loop_inst.base;
530}533}
531534
532fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst {535fn 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
557fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst {
533 const parent_block = scope.cast(Scope.Block).?;558 const parent_block = scope.cast(Scope.Block).?;
534559
535 // Reserve space for a Block instruction so that generated Break instructions can560 // 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,6 +582,7 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerErr
557 .results = .{},582 .results = .{},
558 .block_inst = block_inst,583 .block_inst = block_inst,
559 }),584 }),
585 .is_comptime = is_comptime or parent_block.is_comptime,
560 };586 };
561 const label = &child_block.label.?;587 const label = &child_block.label.?;
562588
...@@ -569,6 +595,28 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerErr...@@ -569,6 +595,28 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerErr
569 assert(child_block.instructions.items.len != 0);595 assert(child_block.instructions.items.len != 0);
570 assert(child_block.instructions.items[child_block.instructions.items.len - 1].ty.isNoReturn());596 assert(child_block.instructions.items[child_block.instructions.items.len - 1].ty.isNoReturn());
571597
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 // Need to set the type and emit the Block instruction. This allows machine code generation620 // Need to set the type and emit the Block instruction. This allows machine code generation
573 // to emit a jump instruction to after the block when it encounters the break.621 // to emit a jump instruction to after the block when it encounters the break.
574 try parent_block.instructions.append(mod.gpa, &block_inst.base);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,7 +1131,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
1083 const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr);1131 const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr);
1084 const uncasted_index = try resolveInst(mod, scope, inst.positionals.index);1132 const uncasted_index = try resolveInst(mod, scope, inst.positionals.index);
1085 const elem_index = try mod.coerce(scope, Type.initTag(.usize), uncasted_index);1133 const elem_index = try mod.coerce(scope, Type.initTag(.usize), uncasted_index);
1086 1134
1087 const elem_ty = switch (array_ptr.ty.zigTypeTag()) {1135 const elem_ty = switch (array_ptr.ty.zigTypeTag()) {
1088 .Pointer => array_ptr.ty.elemType(),1136 .Pointer => array_ptr.ty.elemType(),
1089 else => return mod.fail(scope, inst.positionals.array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}),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,6 +1424,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE
1376 .decl = parent_block.decl,1424 .decl = parent_block.decl,
1377 .instructions = .{},1425 .instructions = .{},
1378 .arena = parent_block.arena,1426 .arena = parent_block.arena,
1427 .is_comptime = parent_block.is_comptime,
1379 };1428 };
1380 defer true_block.instructions.deinit(mod.gpa);1429 defer true_block.instructions.deinit(mod.gpa);
1381 try analyzeBody(mod, &true_block.base, inst.positionals.then_body);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,6 +1435,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE
1386 .decl = parent_block.decl,1435 .decl = parent_block.decl,
1387 .instructions = .{},1436 .instructions = .{},
1388 .arena = parent_block.arena,1437 .arena = parent_block.arena,
1438 .is_comptime = parent_block.is_comptime,
1389 };1439 };
1390 defer false_block.instructions.deinit(mod.gpa);1440 defer false_block.instructions.deinit(mod.gpa);
1391 try analyzeBody(mod, &false_block.base, inst.positionals.else_body);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,7 +274,7 @@ pub fn addCases(ctx: *TestContext) !void {
274 }274 }
275275
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 case.addCompareOutput(278 case.addCompareOutput(
279 \\export fn _start() noreturn {279 \\export fn _start() noreturn {
280 \\ sub(7, 4);280 \\ sub(7, 4);
...@@ -967,10 +967,19 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -967,10 +967,19 @@ pub fn addCases(ctx: *TestContext) !void {
967 \\fn entry() void {}967 \\fn entry() void {}
968 , &[_][]const u8{":2:4: error: redefinition of 'entry'"});968 , &[_][]const u8{":2:4: error: redefinition of 'entry'"});
969969
970 ctx.compileError("extern variable has no type", linux_x64,970 {
971 \\comptime {971 var case = ctx.obj("extern variable has no type", linux_x64);
972 \\ _ = foo;972 case.addError(
973 \\}973 \\comptime {
974 \\extern var foo;974 \\ _ = foo;
975 , &[_][]const u8{":4:1: error: unable to infer variable type"});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}