| author | |
| committer | |
| log | 4c13d020dbecbd7664b99765de33f230e98f3322 |
| tree | a4e9adc1b9ee5ca6a2db85a1e23f74847f75f878 |
| parent | 717b0e827511b55375de82258f570709c07cc59d |
* 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 { | ... | @@ -1308,7 +1308,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1308 | .return_type = return_type_inst, | 1308 | .return_type = return_type_inst, |
| 1309 | .param_types = param_types, | 1309 | .param_types = param_types, |
| 1310 | }, .{}); | 1310 | }, .{}); |
| 1311 | _ = try astgen.addZIRUnOp(self, &fn_type_scope.base, fn_src, .@"return", fn_type_inst); | ||
| 1312 | 1311 | ||
| 1313 | // We need the memory for the Type to go into the arena for the Decl | 1312 | // We need the memory for the Type to go into the arena for the Decl |
| 1314 | var decl_arena = std.heap.ArenaAllocator.init(self.gpa); | 1313 | var decl_arena = std.heap.ArenaAllocator.init(self.gpa); |
| ... | @@ -1325,7 +1324,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1325,7 +1324,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1325 | }; | 1324 | }; |
| 1326 | defer block_scope.instructions.deinit(self.gpa); | 1325 | defer block_scope.instructions.deinit(self.gpa); |
| 1327 | 1326 | ||
| 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, .{ |
| 1329 | .instructions = fn_type_scope.instructions.items, | 1328 | .instructions = fn_type_scope.instructions.items, |
| 1330 | }); | 1329 | }); |
| 1331 | const new_func = try decl_arena.allocator.create(Fn); | 1330 | const new_func = try decl_arena.allocator.create(Fn); |
| ... | @@ -1492,35 +1491,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1492,35 +1491,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1492 | 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", .{}); |
| 1493 | } | 1492 | } |
| 1494 | 1493 | ||
| 1495 | const explicit_type = blk: { | 1494 | const var_info: struct { ty: Type, val: ?Value } = if (var_decl.getInitNode()) |init_node| vi: { |
| 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: { | ||
| 1524 | var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa); | 1495 | var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa); |
| 1525 | defer gen_scope_arena.deinit(); | 1496 | defer gen_scope_arena.deinit(); |
| 1526 | var gen_scope: Scope.GenZIR = .{ | 1497 | var gen_scope: Scope.GenZIR = .{ |
| ... | @@ -1529,10 +1500,19 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1529,10 +1500,19 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1529 | .parent = decl.scope, | 1500 | .parent = decl.scope, |
| 1530 | }; | 1501 | }; |
| 1531 | defer gen_scope.instructions.deinit(self.gpa); | 1502 | defer gen_scope.instructions.deinit(self.gpa); |
| 1532 | const src = tree.token_locs[init_node.firstToken()].start; | ||
| 1533 | 1503 | ||
| 1534 | const init_inst = try astgen.expr(self, &gen_scope.base, .none, init_node); | 1504 | const init_result_loc: astgen.ResultLoc = if (var_decl.getTypeNode()) |type_node| rl: { |
| 1535 | _ = try astgen.addZIRUnOp(self, &gen_scope.base, src, .@"return", init_inst); | 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); | ||
| 1536 | 1516 | ||
| 1537 | var inner_block: Scope.Block = .{ | 1517 | var inner_block: Scope.Block = .{ |
| 1538 | .parent = null, | 1518 | .parent = null, |
| ... | @@ -1545,38 +1525,53 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1545,38 +1525,53 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1545 | defer inner_block.instructions.deinit(self.gpa); | 1525 | defer inner_block.instructions.deinit(self.gpa); |
| 1546 | 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 }); |
| 1547 | 1527 | ||
| 1548 | for (inner_block.instructions.items) |inst| { | 1528 | // The result location guarantees the type coercion. |
| 1549 | if (inst.castTag(.ret)) |ret| { | 1529 | const analyzed_init_inst = init_inst.analyzed_inst.?; |
| 1550 | const coerced = if (explicit_type) |some| | 1530 | // The is_comptime in the Scope.Block guarantees the result is comptime-known. |
| 1551 | try self.coerce(&inner_block.base, some, ret.operand) | 1531 | const val = analyzed_init_inst.value().?; |
| 1552 | else | 1532 | |
| 1553 | ret.operand; | 1533 | const ty = try analyzed_init_inst.ty.copy(block_scope.arena); |
| 1554 | const val = coerced.value() orelse | 1534 | break :vi .{ |
| 1555 | return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); | 1535 | .ty = ty, |
| 1556 | 1536 | .val = try val.copy(block_scope.arena), | |
| 1557 | var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena); | 1537 | }; |
| 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; | ||
| 1564 | } else if (!is_extern) { | 1538 | } else if (!is_extern) { |
| 1565 | 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", .{}); |
| 1566 | } else if (explicit_type) |some| blk: { | 1540 | } else if (var_decl.getTypeNode()) |type_node| vi: { |
| 1567 | var_type = some; | 1541 | // Temporary arena for the zir instructions. |
| 1568 | 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 | }; | ||
| 1569 | } else { | 1564 | } else { |
| 1570 | 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", .{}); |
| 1571 | }; | 1566 | }; |
| 1572 | 1567 | ||
| 1573 | if (is_mutable and !var_type.isValidVarType(is_extern)) { | 1568 | if (is_mutable and !var_info.ty.isValidVarType(is_extern)) { |
| 1574 | 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}); |
| 1575 | } | 1570 | } |
| 1576 | 1571 | ||
| 1577 | var type_changed = true; | 1572 | var type_changed = true; |
| 1578 | if (decl.typedValueManaged()) |tvm| { | 1573 | 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); |
| 1580 | 1575 | ||
| 1581 | tvm.deinit(self.gpa); | 1576 | tvm.deinit(self.gpa); |
| 1582 | } | 1577 | } |
| ... | @@ -1585,7 +1580,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1585,7 +1580,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1585 | const var_payload = try decl_arena.allocator.create(Value.Payload.Variable); | 1580 | const var_payload = try decl_arena.allocator.create(Value.Payload.Variable); |
| 1586 | new_variable.* = .{ | 1581 | new_variable.* = .{ |
| 1587 | .owner_decl = decl, | 1582 | .owner_decl = decl, |
| 1588 | .init = value orelse undefined, | 1583 | .init = var_info.val orelse undefined, |
| 1589 | .is_extern = is_extern, | 1584 | .is_extern = is_extern, |
| 1590 | .is_mutable = is_mutable, | 1585 | .is_mutable = is_mutable, |
| 1591 | .is_threadlocal = is_threadlocal, | 1586 | .is_threadlocal = is_threadlocal, |
| ... | @@ -1596,7 +1591,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1596,7 +1591,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1596 | decl.typed_value = .{ | 1591 | decl.typed_value = .{ |
| 1597 | .most_recent = .{ | 1592 | .most_recent = .{ |
| 1598 | .typed_value = .{ | 1593 | .typed_value = .{ |
| 1599 | .ty = var_type, | 1594 | .ty = var_info.ty, |
| 1600 | .val = Value.initPayload(&var_payload.base), | 1595 | .val = Value.initPayload(&var_payload.base), |
| 1601 | }, | 1596 | }, |
| 1602 | .arena = decl_arena_state, | 1597 | .arena = decl_arena_state, |
| ... | @@ -2096,12 +2091,19 @@ pub fn getErrorValue(self: *Module, name: []const u8) !std.StringHashMapUnmanage | ... | @@ -2096,12 +2091,19 @@ pub fn getErrorValue(self: *Module, name: []const u8) !std.StringHashMapUnmanage |
| 2096 | return gop.entry.*; | 2091 | return gop.entry.*; |
| 2097 | } | 2092 | } |
| 2098 | 2093 | ||
| 2099 | /// TODO split this into `requireRuntimeBlock` and `requireFunctionBlock` and audit callsites. | 2094 | pub fn requireFunctionBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block { |
| 2100 | pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block { | ||
| 2101 | return scope.cast(Scope.Block) orelse | 2095 | return scope.cast(Scope.Block) orelse |
| 2102 | return self.fail(scope, src, "instruction illegal outside function body", .{}); | 2096 | return self.fail(scope, src, "instruction illegal outside function body", .{}); |
| 2103 | } | 2097 | } |
| 2104 | 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 | |||
| 2105 | pub fn resolveConstValue(self: *Module, scope: *Scope, base: *Inst) !Value { | 2107 | pub fn resolveConstValue(self: *Module, scope: *Scope, base: *Inst) !Value { |
| 2106 | return (try self.resolveDefinedValue(scope, base)) orelse | 2108 | return (try self.resolveDefinedValue(scope, base)) orelse |
| 2107 | return self.fail(scope, base.src, "unable to resolve comptime value", .{}); | 2109 | 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 { | ... | @@ -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!"); |
| 498 | 498 | ||
| 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(); |
| 527 | 527 | ||
| 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_sema.zig+10-12| ... | @@ -150,18 +150,16 @@ pub fn analyzeBody(mod: *Module, scope: *Scope, body: zir.Module.Body) !void { | ... | @@ -150,18 +150,16 @@ pub fn analyzeBody(mod: *Module, scope: *Scope, body: zir.Module.Body) !void { |
| 150 | } | 150 | } |
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | /// TODO improve this to use .block_comptime_flat | 153 | pub fn analyzeBodyValueAsType( |
| 154 | pub fn analyzeBodyValueAsType(mod: *Module, block_scope: *Scope.Block, body: zir.Module.Body) !Type { | 154 | mod: *Module, |
| 155 | block_scope: *Scope.Block, | ||
| 156 | zir_result_inst: *zir.Inst, | ||
| 157 | body: zir.Module.Body, | ||
| 158 | ) !Type { | ||
| 155 | try analyzeBody(mod, &block_scope.base, body); | 159 | try analyzeBody(mod, &block_scope.base, body); |
| 156 | for (block_scope.instructions.items) |inst| { | 160 | const result_inst = zir_result_inst.analyzed_inst.?; |
| 157 | if (inst.castTag(.ret)) |ret| { | 161 | const val = try mod.resolveConstValue(&block_scope.base, result_inst); |
| 158 | const val = try mod.resolveConstValue(&block_scope.base, ret.operand); | 162 | return val.toType(block_scope.base.arena()); |
| 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; | ||
| 165 | } | 163 | } |
| 166 | 164 | ||
| 167 | pub fn analyzeZirDecl(mod: *Module, decl: *Decl, src_decl: *zir.Decl) InnerError!bool { | 165 | pub 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! | ... | @@ -366,7 +364,7 @@ fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError! |
| 366 | } | 364 | } |
| 367 | 365 | ||
| 368 | fn analyzeInstRetType(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | 366 | fn 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); |
| 370 | 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; |
| 371 | const ret_type = fn_ty.fnReturnType(); | 369 | const ret_type = fn_ty.fnReturnType(); |
| 372 | return mod.constType(scope, inst.base.src, ret_type); | 370 | 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 { | ... | @@ -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'"}); |
| 969 | 969 | ||
| 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 | } |