| author | |
| committer | |
| log | 3f7cb14b267bbd823597ba24fd2e3f6f66abcbaa |
| tree | 9d3ce364c8619ac5ca6ce273be0b86164264a9d7 |
| parent | baa734c42a2bdb3f63fd26dd30bc8c9a846831bf |
| parent | 4c13d020dbecbd7664b99765de33f230e98f3322 |
| signature |
stage2: introduce the ability for Scope.Block to be comptime7 files changed, 259 insertions(+), 113 deletions(-)
src-self-hosted/Module.zig+70-63| ... | @@ -725,6 +725,7 @@ pub const Scope = struct { | ... | @@ -725,6 +725,7 @@ pub const Scope = struct { |
| 725 | /// Points to the arena allocator of DeclAnalysis | 725 | /// 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, | ||
| 728 | 729 | ||
| 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); | ||
| 1311 | 1311 | ||
| 1312 | // 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 |
| 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); |
| 1325 | 1326 | ||
| 1326 | const fn_type = try zir_sema.analyzeBodyValueAsType(self, &block_scope, .{ | 1327 | const fn_type = try zir_sema.analyzeBodyValueAsType(self, &block_scope, fn_type_inst, .{ |
| 1327 | .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); |
| 1462 | 1464 | ||
| ... | @@ -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 | } |
| 1491 | 1493 | ||
| 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; | ||
| 1530 | 1503 | ||
| 1531 | // TODO comptime scope here | 1504 | 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); | ||
| 1534 | 1516 | ||
| 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 }); |
| 1544 | 1527 | ||
| 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 | else | 1532 | |
| 1550 | ret.operand; | 1533 | const ty = try analyzed_init_inst.ty.copy(block_scope.arena); |
| 1551 | const val = coerced.value() orelse | 1534 | break :vi .{ |
| 1552 | return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); | 1535 | .ty = ty, |
| 1553 | 1536 | .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 | }; |
| 1569 | 1567 | ||
| 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 | } |
| 1573 | 1571 | ||
| 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); |
| 1577 | 1575 | ||
| 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); |
| 1630 | 1628 | ||
| 1631 | // TODO comptime scope here | 1629 | _ = try astgen.comptimeExpr(self, &gen_scope.base, .none, comptime_decl.expr); |
| 1632 | _ = try astgen.expr(self, &gen_scope.base, .none, comptime_decl.expr); | ||
| 1633 | 1630 | ||
| 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); |
| 1642 | 1640 | ||
| ... | @@ -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); |
| 2012 | 2011 | ||
| ... | @@ -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 | } |
| 2094 | 2093 | ||
| 2095 | /// TODO split this into `requireRuntimeBlock` and `requireFunctionBlock` and audit callsites. | 2094 | pub fn requireFunctionBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block { |
| 2096 | pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block { | ||
| 2097 | return scope.cast(Scope.Block) orelse | 2095 | 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 | } |
| 2100 | 2098 | ||
| 2099 | pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block { | ||
| 2100 | const block = try self.requireFunctionBlock(scope, src); | ||
| 2101 | if (block.is_comptime) { | ||
| 2102 | return self.fail(scope, src, "unable to resolve comptime value", .{}); | ||
| 2103 | } | ||
| 2104 | return block; | ||
| 2105 | } | ||
| 2106 | |||
| 2101 | pub fn resolveConstValue(self: *Module, scope: *Scope, base: *Inst) !Value { | 2107 | pub fn resolveConstValue(self: *Module, scope: *Scope, base: *Inst) !Value { |
| 2102 | return (try self.resolveDefinedValue(scope, base)) orelse | 2108 | 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); |
| 3437 | 3444 |
src-self-hosted/astgen.zig+73-16| ... | @@ -258,7 +258,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -258,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).?), | ||
| 279 | 280 | ||
| 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 | } |
| 301 | 301 | ||
| 302 | fn comptimeKeyword(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Comptime) InnerError!*zir.Inst { | ||
| 303 | const tracy = trace(@src()); | ||
| 304 | defer tracy.end(); | ||
| 305 | |||
| 306 | return comptimeExpr(mod, scope, rl, node.expr); | ||
| 307 | } | ||
| 308 | |||
| 309 | pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { | ||
| 310 | const tree = parent_scope.tree(); | ||
| 311 | const src = tree.token_locs[node.firstToken()].start; | ||
| 312 | |||
| 313 | // Optimization for labeled blocks: don't need to have 2 layers of blocks, we can reuse the existing one. | ||
| 314 | if (node.castTag(.LabeledBlock)) |block_node| { | ||
| 315 | return labeledBlockExpr(mod, parent_scope, rl, block_node, .block_comptime); | ||
| 316 | } | ||
| 317 | |||
| 318 | // Make a scope to collect generated instructions in the sub-expression. | ||
| 319 | var block_scope: Scope.GenZIR = .{ | ||
| 320 | .parent = parent_scope, | ||
| 321 | .decl = parent_scope.decl().?, | ||
| 322 | .arena = parent_scope.arena(), | ||
| 323 | .instructions = .{}, | ||
| 324 | }; | ||
| 325 | defer block_scope.instructions.deinit(mod.gpa); | ||
| 326 | |||
| 327 | // No need to capture the result here because block_comptime_flat implies that the final | ||
| 328 | // instruction is the block's result value. | ||
| 329 | _ = try expr(mod, &block_scope.base, rl, node); | ||
| 330 | |||
| 331 | const block = try addZIRInstBlock(mod, parent_scope, src, .block_comptime_flat, .{ | ||
| 332 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | ||
| 333 | }); | ||
| 334 | |||
| 335 | return &block.base; | ||
| 336 | } | ||
| 337 | |||
| 302 | fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { | 338 | fn 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(); |
| 366 | 403 | ||
| 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; |
| 369 | 408 | ||
| ... | @@ -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 below | 812 | .else_body = undefined, // populated below |
| 774 | }, .{}); | 813 | }, .{}); |
| 775 | 814 | ||
| 776 | const block = try addZIRInstBlock(mod, scope, src, .{ | 815 | const block = try addZIRInstBlock(mod, scope, src, .block, .{ |
| 777 | .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 | }); |
| 779 | 818 | ||
| ... | @@ -946,7 +985,7 @@ fn boolBinOp( | ... | @@ -946,7 +985,7 @@ fn boolBinOp( |
| 946 | .else_body = undefined, // populated below | 985 | .else_body = undefined, // populated below |
| 947 | }, .{}); | 986 | }, .{}); |
| 948 | 987 | ||
| 949 | const block = try addZIRInstBlock(mod, scope, src, .{ | 988 | const block = try addZIRInstBlock(mod, scope, src, .block, .{ |
| 950 | .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 | }); |
| 952 | 991 | ||
| ... | @@ -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 below | 1134 | .else_body = undefined, // populated below |
| 1096 | }, .{}); | 1135 | }, .{}); |
| 1097 | 1136 | ||
| 1098 | const block = try addZIRInstBlock(mod, scope, if_src, .{ | 1137 | const block = try addZIRInstBlock(mod, scope, if_src, .block, .{ |
| 1099 | .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 | }); |
| 1101 | 1140 | ||
| ... | @@ -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 below | 1257 | .then_body = undefined, // populated below |
| 1219 | .else_body = undefined, // populated below | 1258 | .else_body = undefined, // populated below |
| 1220 | }, .{}); | 1259 | }, .{}); |
| 1221 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .{ | 1260 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .block, .{ |
| 1222 | .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 there | 1263 | // TODO avoid emitting the continue expr when there |
| ... | @@ -1231,7 +1270,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1231,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 | }); |
| 1237 | 1276 | ||
| ... | @@ -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 below | 1404 | .then_body = undefined, // populated below |
| 1366 | .else_body = undefined, // populated below | 1405 | .else_body = undefined, // populated below |
| 1367 | }, .{}); | 1406 | }, .{}); |
| 1368 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, for_src, .{ | 1407 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, for_src, .block, .{ |
| 1369 | .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 | }); |
| 1371 | 1410 | ||
| ... | @@ -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 | }); |
| 1388 | 1427 | ||
| ... | @@ -2260,6 +2299,30 @@ pub fn addZIRBinOp( | ... | @@ -2260,6 +2299,30 @@ pub fn addZIRBinOp( |
| 2260 | return &inst.base; | 2299 | return &inst.base; |
| 2261 | } | 2300 | } |
| 2262 | 2301 | ||
| 2302 | pub fn addZIRInstBlock( | ||
| 2303 | mod: *Module, | ||
| 2304 | scope: *Scope, | ||
| 2305 | src: usize, | ||
| 2306 | tag: zir.Inst.Tag, | ||
| 2307 | body: zir.Module.Body, | ||
| 2308 | ) !*zir.Inst.Block { | ||
| 2309 | const gen_zir = scope.getGenZIR(); | ||
| 2310 | try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1); | ||
| 2311 | const inst = try gen_zir.arena.create(zir.Inst.Block); | ||
| 2312 | inst.* = .{ | ||
| 2313 | .base = .{ | ||
| 2314 | .tag = tag, | ||
| 2315 | .src = src, | ||
| 2316 | }, | ||
| 2317 | .positionals = .{ | ||
| 2318 | .body = body, | ||
| 2319 | }, | ||
| 2320 | .kw_args = .{}, | ||
| 2321 | }; | ||
| 2322 | gen_zir.instructions.appendAssumeCapacity(&inst.base); | ||
| 2323 | return inst; | ||
| 2324 | } | ||
| 2325 | |||
| 2263 | pub fn addZIRInst( | 2326 | pub 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 | } |
| 2280 | 2343 | ||
| 2281 | /// TODO The existence of this function is a workaround for a bug in stage1. | ||
| 2282 | pub fn addZIRInstBlock(mod: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Block { | ||
| 2283 | const P = std.meta.fieldInfo(zir.Inst.Block, "positionals").field_type; | ||
| 2284 | return addZIRInstSpecial(mod, scope, src, zir.Inst.Block, P{ .body = body }, .{}); | ||
| 2285 | } | ||
| 2286 | |||
| 2287 | /// 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. |
| 2288 | pub fn addZIRInstLoop(mod: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Loop { | 2345 | pub 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 | } |
| 190 | 190 | ||
| 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 | } |
| 222 | 222 | ||
| 223 | pub fn breakBlock(base: *Inst) ?*Block { | ||
| 224 | return switch (base.tag) { | ||
| 225 | .br => base.castTag(.br).?.block, | ||
| 226 | .brvoid => base.castTag(.brvoid).?.block, | ||
| 227 | else => null, | ||
| 228 | }; | ||
| 229 | } | ||
| 230 | |||
| 223 | pub const NoOp = struct { | 231 | pub const NoOp = struct { |
| 224 | base: Inst, | 232 | base: Inst, |
| 225 | 233 |
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.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, |
| 340 | 347 | ||
| 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 | } |
| 149 | 152 | ||
| 150 | pub fn analyzeBodyValueAsType(mod: *Module, block_scope: *Scope.Block, body: zir.Module.Body) !Type { | 153 | pub fn analyzeBodyValueAsType( |
| 154 | mod: *Module, | ||
| 155 | block_scope: *Scope.Block, | ||
| 156 | zir_result_inst: *zir.Inst, | ||
| 157 | body: zir.Module.Body, | ||
| 158 | ) !Type { | ||
| 151 | 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 | } |
| 162 | 164 | ||
| 163 | 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 { |
| ... | @@ -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 | } |
| 363 | 365 | ||
| 364 | 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 { |
| 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); |
| 522 | 525 | ||
| ... | @@ -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 | } |
| 531 | 534 | ||
| 532 | fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst { | 535 | fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst { |
| 536 | const parent_block = scope.cast(Scope.Block).?; | ||
| 537 | |||
| 538 | var child_block: Scope.Block = .{ | ||
| 539 | .parent = parent_block, | ||
| 540 | .func = parent_block.func, | ||
| 541 | .decl = parent_block.decl, | ||
| 542 | .instructions = .{}, | ||
| 543 | .arena = parent_block.arena, | ||
| 544 | .label = null, | ||
| 545 | .is_comptime = parent_block.is_comptime or is_comptime, | ||
| 546 | }; | ||
| 547 | defer child_block.instructions.deinit(mod.gpa); | ||
| 548 | |||
| 549 | try analyzeBody(mod, &child_block.base, inst.positionals.body); | ||
| 550 | |||
| 551 | const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items); | ||
| 552 | try parent_block.instructions.appendSlice(mod.gpa, copied_instructions); | ||
| 553 | |||
| 554 | return copied_instructions[copied_instructions.len - 1]; | ||
| 555 | } | ||
| 556 | |||
| 557 | fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst { | ||
| 533 | const parent_block = scope.cast(Scope.Block).?; | 558 | const parent_block = scope.cast(Scope.Block).?; |
| 534 | 559 | ||
| 535 | // Reserve space for a Block instruction so that generated Break instructions can | 560 | // Reserve space for a Block instruction so that generated Break instructions can |
| ... | @@ -557,6 +582,7 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerErr | ... | @@ -557,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.?; |
| 562 | 588 | ||
| ... | @@ -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()); |
| 571 | 597 | ||
| 598 | if (label.results.items.len == 0) { | ||
| 599 | // No need for a block instruction. We can put the new instructions directly into the parent block. | ||
| 600 | const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items); | ||
| 601 | try parent_block.instructions.appendSlice(mod.gpa, copied_instructions); | ||
| 602 | return copied_instructions[copied_instructions.len - 1]; | ||
| 603 | } | ||
| 604 | if (label.results.items.len == 1) { | ||
| 605 | const last_inst_index = child_block.instructions.items.len - 1; | ||
| 606 | const last_inst = child_block.instructions.items[last_inst_index]; | ||
| 607 | if (last_inst.breakBlock()) |br_block| { | ||
| 608 | if (br_block == block_inst) { | ||
| 609 | // No need for a block instruction. We can put the new instructions directly into the parent block. | ||
| 610 | // Here we omit the break instruction. | ||
| 611 | const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items[0..last_inst_index]); | ||
| 612 | try parent_block.instructions.appendSlice(mod.gpa, copied_instructions); | ||
| 613 | return label.results.items[0]; | ||
| 614 | } | ||
| 615 | } | ||
| 616 | } | ||
| 617 | // It should be impossible to have the number of results be > 1 in a comptime scope. | ||
| 618 | assert(!child_block.is_comptime); // We should have already got a compile error in the condbr condition. | ||
| 619 | |||
| 572 | // Need to set the type and emit the Block instruction. This allows machine code generation | 620 | // 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 | } |
| 275 | 275 | ||
| 276 | { | 276 | { |
| 277 | var case = ctx.exe("substracting numbers at runtime", linux_x64); | 277 | var case = ctx.exe("subtracting numbers at runtime", linux_x64); |
| 278 | 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'"}); |
| 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 | } |