authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-01 12:39:47-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-01 12:39:47-07:00
log4c13d020dbecbd7664b99765de33f230e98f3322
treea4e9adc1b9ee5ca6a2db85a1e23f74847f75f878
parent717b0e827511b55375de82258f570709c07cc59d

stage2: proper split of requireRuntimeBlock and requireFunctionBlock

* improve the ZIR generated of variable decls - utilize the same ZIR for the type and init value when possible - init value gets a result location with the variable type. no manual coercion is required. * no longer use return instructions to extract values out of comptime blocks. Instead run the analysis and then look at the corresponding analyzed instruction, relying on the comptime mechanism to report errors when something could not be comptime evaluated.

4 files changed, 98 insertions(+), 89 deletions(-)

src-self-hosted/Module.zig+62-60
......@@ -1308,7 +1308,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
13081308 .return_type = return_type_inst,
13091309 .param_types = param_types,
13101310 }, .{});
1311 _ = try astgen.addZIRUnOp(self, &fn_type_scope.base, fn_src, .@"return", fn_type_inst);
13121311
13131312 // We need the memory for the Type to go into the arena for the Decl
13141313 var decl_arena = std.heap.ArenaAllocator.init(self.gpa);
......@@ -1325,7 +1324,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
13251324 };
13261325 defer block_scope.instructions.deinit(self.gpa);
13271326
1328 const fn_type = try zir_sema.analyzeBodyValueAsType(self, &block_scope, .{
1327 const fn_type = try zir_sema.analyzeBodyValueAsType(self, &block_scope, fn_type_inst, .{
13291328 .instructions = fn_type_scope.instructions.items,
13301329 });
13311330 const new_func = try decl_arena.allocator.create(Fn);
......@@ -1492,35 +1491,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
14921491 return self.failNode(&block_scope.base, sect_expr, "TODO implement function section expression", .{});
14931492 }
14941493
1495 const explicit_type = blk: {
1496 const type_node = var_decl.getTypeNode() orelse
1497 break :blk null;
1498
1499 // Temporary arena for the zir instructions.
1500 var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1501 defer type_scope_arena.deinit();
1502 var type_scope: Scope.GenZIR = .{
1503 .decl = decl,
1504 .arena = &type_scope_arena.allocator,
1505 .parent = decl.scope,
1506 };
1507 defer type_scope.instructions.deinit(self.gpa);
1508
1509 const src = tree.token_locs[type_node.firstToken()].start;
1510 const type_type = try astgen.addZIRInstConst(self, &type_scope.base, src, .{
1511 .ty = Type.initTag(.type),
1512 .val = Value.initTag(.type_type),
1513 });
1514 const var_type = try astgen.expr(self, &type_scope.base, .{ .ty = type_type }, type_node);
1515 _ = try astgen.addZIRUnOp(self, &type_scope.base, src, .@"return", var_type);
1516
1517 break :blk try zir_sema.analyzeBodyValueAsType(self, &block_scope, .{
1518 .instructions = type_scope.instructions.items,
1519 });
1520 };
1521
1522 var var_type: Type = undefined;
1523 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: {
15241495 var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
15251496 defer gen_scope_arena.deinit();
15261497 var gen_scope: Scope.GenZIR = .{
......@@ -1529,10 +1500,19 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
15291500 .parent = decl.scope,
15301501 };
15311502 defer gen_scope.instructions.deinit(self.gpa);
1532 const src = tree.token_locs[init_node.firstToken()].start;
15331503
1534 const init_inst = try astgen.expr(self, &gen_scope.base, .none, init_node);
1535 _ = 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);
15361516
15371517 var inner_block: Scope.Block = .{
15381518 .parent = null,
......@@ -1545,38 +1525,53 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
15451525 defer inner_block.instructions.deinit(self.gpa);
15461526 try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items });
15471527
1548 for (inner_block.instructions.items) |inst| {
1549 if (inst.castTag(.ret)) |ret| {
1550 const coerced = if (explicit_type) |some|
1551 try self.coerce(&inner_block.base, some, ret.operand)
1552 else
1553 ret.operand;
1554 const val = coerced.value() orelse
1555 return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{});
1556
1557 var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena);
1558 break :blk try val.copy(block_scope.arena);
1559 } else {
1560 return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{});
1561 }
1562 }
1563 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 };
15641538 } else if (!is_extern) {
15651539 return self.failTok(&block_scope.base, var_decl.firstToken(), "variables must be initialized", .{});
1566 } else if (explicit_type) |some| blk: {
1567 var_type = some;
1568 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 };
15691564 } else {
15701565 return self.failTok(&block_scope.base, var_decl.firstToken(), "unable to infer variable type", .{});
15711566 };
15721567
1573 if (is_mutable and !var_type.isValidVarType(is_extern)) {
1574 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});
15751570 }
15761571
15771572 var type_changed = true;
15781573 if (decl.typedValueManaged()) |tvm| {
1579 type_changed = !tvm.typed_value.ty.eql(var_type);
1574 type_changed = !tvm.typed_value.ty.eql(var_info.ty);
15801575
15811576 tvm.deinit(self.gpa);
15821577 }
......@@ -1585,7 +1580,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
15851580 const var_payload = try decl_arena.allocator.create(Value.Payload.Variable);
15861581 new_variable.* = .{
15871582 .owner_decl = decl,
1588 .init = value orelse undefined,
1583 .init = var_info.val orelse undefined,
15891584 .is_extern = is_extern,
15901585 .is_mutable = is_mutable,
15911586 .is_threadlocal = is_threadlocal,
......@@ -1596,7 +1591,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
15961591 decl.typed_value = .{
15971592 .most_recent = .{
15981593 .typed_value = .{
1599 .ty = var_type,
1594 .ty = var_info.ty,
16001595 .val = Value.initPayload(&var_payload.base),
16011596 },
16021597 .arena = decl_arena_state,
......@@ -2096,12 +2091,19 @@ pub fn getErrorValue(self: *Module, name: []const u8) !std.StringHashMapUnmanage
20962091 return gop.entry.*;
20972092}
20982093
2099/// TODO split this into `requireRuntimeBlock` and `requireFunctionBlock` and audit callsites.
2100pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
2094pub fn requireFunctionBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
21012095 return scope.cast(Scope.Block) orelse
21022096 return self.fail(scope, src, "instruction illegal outside function body", .{});
21032097}
21042098
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
21052107pub fn resolveConstValue(self: *Module, scope: *Scope, base: *Inst) !Value {
21062108 return (try self.resolveDefinedValue(scope, base)) orelse
21072109 return self.fail(scope, base.src, "unable to resolve comptime value", .{});
src-self-hosted/test.zig+11-11
......@@ -474,15 +474,15 @@ pub const TestContext = struct {
474474 var all_errors = try module.getAllErrorsAlloc();
475475 defer all_errors.deinit(allocator);
476476 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", .{});
478478 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 });
480480 }
481481 if (case.cbe) {
482482 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});
484484 }
485 std.debug.warn("Test failed.\n", .{});
485 std.debug.print("Test failed.\n", .{});
486486 std.process.exit(1);
487487 }
488488 }
......@@ -497,12 +497,12 @@ pub const TestContext = struct {
497497 var out = file.reader().readAllAlloc(arena, 1024 * 1024) catch @panic("Unable to read C output!");
498498
499499 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 });
501501 std.process.exit(1);
502502 }
503503 for (expected_output) |e, i| {
504504 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 });
506506 std.process.exit(1);
507507 }
508508 }
......@@ -526,12 +526,12 @@ pub const TestContext = struct {
526526 defer test_node.end();
527527
528528 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 });
530530 std.process.exit(1);
531531 }
532532 for (expected_output) |e, i| {
533533 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 });
535535 std.process.exit(1);
536536 }
537537 }
......@@ -554,7 +554,7 @@ pub const TestContext = struct {
554554 break;
555555 }
556556 } 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 });
558558 std.process.exit(1);
559559 }
560560 }
......@@ -562,7 +562,7 @@ pub const TestContext = struct {
562562 for (handled_errors) |h, i| {
563563 if (!h) {
564564 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 });
566566 std.process.exit(1);
567567 }
568568 }
......@@ -643,7 +643,7 @@ pub const TestContext = struct {
643643 switch (exec_result.term) {
644644 .Exited => |code| {
645645 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});
647647 return error.BinaryBadExitCode;
648648 }
649649 },
src-self-hosted/zir_sema.zig+10-12
......@@ -150,18 +150,16 @@ pub fn analyzeBody(mod: *Module, scope: *Scope, body: zir.Module.Body) !void {
150150 }
151151}
152152
153/// TODO improve this to use .block_comptime_flat
154pub 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 {
155159 try analyzeBody(mod, &block_scope.base, body);
156 for (block_scope.instructions.items) |inst| {
157 if (inst.castTag(.ret)) |ret| {
158 const val = try mod.resolveConstValue(&block_scope.base, ret.operand);
159 return val.toType(block_scope.base.arena());
160 } else {
161 return mod.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{});
162 }
163 }
164 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());
165163}
166164
167165pub fn analyzeZirDecl(mod: *Module, decl: *Decl, src_decl: *zir.Decl) InnerError!bool {
......@@ -366,7 +364,7 @@ fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!
366364}
367365
368366fn analyzeInstRetType(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
369 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
367 const b = try mod.requireFunctionBlock(scope, inst.base.src);
370368 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
371369 const ret_type = fn_ty.fnReturnType();
372370 return mod.constType(scope, inst.base.src, ret_type);
test/stage2/test.zig+15-6
......@@ -967,10 +967,19 @@ pub fn addCases(ctx: *TestContext) !void {
967967 \\fn entry() void {}
968968 , &[_][]const u8{":2:4: error: redefinition of 'entry'"});
969969
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 }
976985}