diff --git a/BRANCH_TODO b/BRANCH_TODO index 6ccb00d410..d96b1fc6fe 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,6 +1,5 @@ * implement lazy struct field resolution; don't resolve struct fields until they are needed. - * decouple AstGen from Module, Compilation * AstGen threadlocal * extern "foo" for vars and for functions * namespace decls table can't reference ZIR memory because it can get modified on updates diff --git a/src/AstGen.zig b/src/AstGen.zig index 853cedeeff..4655116975 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -13,17 +13,11 @@ const assert = std.debug.assert; const ArrayListUnmanaged = std.ArrayListUnmanaged; const Zir = @import("Zir.zig"); -const Module = @import("Module.zig"); const trace = @import("tracy.zig").trace; -const Scope = Module.Scope; -const GenZir = Scope.GenZir; -const InnerError = Module.InnerError; -const Decl = Module.Decl; -const LazySrcLoc = Module.LazySrcLoc; const BuiltinFn = @import("BuiltinFn.zig"); gpa: *Allocator, -file: *Scope.File, +tree: *const ast.Tree, instructions: std.MultiArrayList(Zir.Inst) = .{}, extra: ArrayListUnmanaged(u32) = .{}, string_bytes: ArrayListUnmanaged(u8) = .{}, @@ -37,13 +31,15 @@ fn_block: ?*GenZir = null, /// String table indexes, keeps track of all `@import` operands. imports: std.AutoArrayHashMapUnmanaged(u32, void) = .{}, -pub fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 { +const InnerError = error{ OutOfMemory, AnalysisFail }; + +fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 { const fields = std.meta.fields(@TypeOf(extra)); try astgen.extra.ensureCapacity(astgen.gpa, astgen.extra.items.len + fields.len); return addExtraAssumeCapacity(astgen, extra); } -pub fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 { +fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 { const fields = std.meta.fields(@TypeOf(extra)); const result = @intCast(u32, astgen.extra.items.len); inline for (fields) |field| { @@ -57,24 +53,24 @@ pub fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 { return result; } -pub fn appendRefs(astgen: *AstGen, refs: []const Zir.Inst.Ref) !void { +fn appendRefs(astgen: *AstGen, refs: []const Zir.Inst.Ref) !void { const coerced = @bitCast([]const u32, refs); return astgen.extra.appendSlice(astgen.gpa, coerced); } -pub fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) void { +fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) void { const coerced = @bitCast([]const u32, refs); astgen.extra.appendSliceAssumeCapacity(coerced); } -pub fn generate(gpa: *Allocator, file: *Scope.File) InnerError!Zir { +pub fn generate(gpa: *Allocator, tree: ast.Tree) InnerError!Zir { var arena = std.heap.ArenaAllocator.init(gpa); defer arena.deinit(); var astgen: AstGen = .{ .gpa = gpa, .arena = &arena.allocator, - .file = file, + .tree = &tree, }; defer astgen.deinit(gpa); @@ -83,16 +79,16 @@ pub fn generate(gpa: *Allocator, file: *Scope.File) InnerError!Zir { // We expect at least as many ZIR instructions and extra data items // as AST nodes. - try astgen.instructions.ensureTotalCapacity(gpa, file.tree.nodes.len); + try astgen.instructions.ensureTotalCapacity(gpa, tree.nodes.len); // First few indexes of extra are reserved and set at the end. const reserved_count = @typeInfo(Zir.ExtraIndex).Enum.fields.len; - try astgen.extra.ensureTotalCapacity(gpa, file.tree.nodes.len + reserved_count); + try astgen.extra.ensureTotalCapacity(gpa, tree.nodes.len + reserved_count); astgen.extra.items.len += reserved_count; var gen_scope: GenZir = .{ .force_comptime = true, - .parent = &file.base, + .parent = null, .decl_node_index = 0, .decl_line = 0, .astgen = &astgen, @@ -104,7 +100,7 @@ pub fn generate(gpa: *Allocator, file: *Scope.File) InnerError!Zir { .ast = .{ .main_token = undefined, .enum_token = null, - .members = file.tree.rootDecls(), + .members = tree.rootDecls(), .arg = 0, }, }; @@ -250,7 +246,7 @@ pub const ResultLoc = union(enum) { pub const align_rl: ResultLoc = .{ .ty = .u16_type }; pub const bool_rl: ResultLoc = .{ .ty = .bool_type }; -pub fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref { +fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref { const prev_force_comptime = gz.force_comptime; gz.force_comptime = true; const e = expr(gz, scope, .{ .ty = .type_type }, type_node); @@ -260,7 +256,7 @@ pub fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerErro fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); switch (node_tags[node]) { @@ -453,9 +449,9 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Ins /// When `rl` is discard, ptr, inferred_ptr, or inferred_ptr, the /// result instruction can be used to inspect whether it is isNoReturn() but that is it, /// it must otherwise not be used. -pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { +fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const token_tags = tree.tokens.items(.tag); const node_datas = tree.nodes.items(.data); @@ -888,7 +884,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn } } -pub fn nosuspendExpr( +fn nosuspendExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, @@ -896,7 +892,7 @@ pub fn nosuspendExpr( ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const body_node = node_datas[node].lhs; assert(body_node != 0); @@ -911,7 +907,7 @@ pub fn nosuspendExpr( return rvalue(gz, scope, rl, result, node); } -pub fn suspendExpr( +fn suspendExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, @@ -919,7 +915,7 @@ pub fn suspendExpr( ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const body_node = node_datas[node].lhs; @@ -951,14 +947,14 @@ pub fn suspendExpr( return gz.indexToRef(suspend_inst); } -pub fn awaitExpr( +fn awaitExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const rhs_node = node_datas[node].lhs; @@ -973,14 +969,14 @@ pub fn awaitExpr( return rvalue(gz, scope, rl, result, node); } -pub fn resumeExpr( +fn resumeExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const rhs_node = node_datas[node].lhs; const operand = try expr(gz, scope, .none, rhs_node); @@ -988,7 +984,7 @@ pub fn resumeExpr( return rvalue(gz, scope, rl, result, node); } -pub fn fnProtoExpr( +fn fnProtoExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, @@ -996,7 +992,7 @@ pub fn fnProtoExpr( ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const token_tags = tree.tokens.items(.tag); const is_extern = blk: { @@ -1093,7 +1089,7 @@ pub fn fnProtoExpr( return rvalue(gz, scope, rl, result, fn_proto.ast.proto_node); } -pub fn arrayInitExpr( +fn arrayInitExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, @@ -1101,7 +1097,7 @@ pub fn arrayInitExpr( array_init: ast.full.ArrayInit, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const gpa = astgen.gpa; const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); @@ -1192,7 +1188,7 @@ pub fn arrayInitExpr( } } -pub fn arrayInitExprRlNone( +fn arrayInitExprRlNone( gz: *GenZir, scope: *Scope, rl: ResultLoc, @@ -1215,7 +1211,7 @@ pub fn arrayInitExprRlNone( return init_inst; } -pub fn arrayInitExprRlTy( +fn arrayInitExprRlTy( gz: *GenZir, scope: *Scope, rl: ResultLoc, @@ -1243,7 +1239,7 @@ pub fn arrayInitExprRlTy( return init_inst; } -pub fn arrayInitExprRlPtr( +fn arrayInitExprRlPtr( gz: *GenZir, scope: *Scope, rl: ResultLoc, @@ -1273,7 +1269,7 @@ pub fn arrayInitExprRlPtr( return .void_value; } -pub fn structInitExpr( +fn structInitExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, @@ -1281,7 +1277,7 @@ pub fn structInitExpr( struct_init: ast.full.StructInit, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const gpa = astgen.gpa; if (struct_init.ast.fields.len == 0) { @@ -1351,7 +1347,7 @@ pub fn structInitExpr( } } -pub fn structInitExprRlNone( +fn structInitExprRlNone( gz: *GenZir, scope: *Scope, rl: ResultLoc, @@ -1361,7 +1357,7 @@ pub fn structInitExprRlNone( ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const fields_list = try gpa.alloc(Zir.Inst.StructInitAnon.Item, struct_init.ast.fields.len); defer gpa.free(fields_list); @@ -1386,7 +1382,7 @@ pub fn structInitExprRlNone( return init_inst; } -pub fn structInitExprRlPtr( +fn structInitExprRlPtr( gz: *GenZir, scope: *Scope, rl: ResultLoc, @@ -1396,7 +1392,7 @@ pub fn structInitExprRlPtr( ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const field_ptr_list = try gpa.alloc(Zir.Inst.Index, struct_init.ast.fields.len); defer gpa.free(field_ptr_list); @@ -1418,7 +1414,7 @@ pub fn structInitExprRlPtr( return .void_value; } -pub fn structInitExprRlTy( +fn structInitExprRlTy( gz: *GenZir, scope: *Scope, rl: ResultLoc, @@ -1429,7 +1425,7 @@ pub fn structInitExprRlTy( ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const fields_list = try gpa.alloc(Zir.Inst.StructInit.Item, struct_init.ast.fields.len); defer gpa.free(fields_list); @@ -1486,7 +1482,7 @@ fn comptimeExprAst( if (gz.force_comptime) { return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{}); } - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const body_node = node_datas[node].lhs; gz.force_comptime = true; @@ -1497,7 +1493,7 @@ fn comptimeExprAst( fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const break_label = node_datas[node].lhs; const rhs = node_datas[node].rhs; @@ -1520,7 +1516,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn } else if (block_gz.break_block != 0) { break :blk block_gz.break_block; } - scope = block_gz.parent; + scope = block_gz.parent orelse break; continue; }; @@ -1558,19 +1554,19 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn try unusedResultExpr(parent_gz, defer_scope.parent, expr_node); }, .defer_error => scope = scope.cast(Scope.Defer).?.parent, - else => if (break_label != 0) { - const label_name = try astgen.identifierTokenString(break_label); - return astgen.failTok(break_label, "label not found: '{s}'", .{label_name}); - } else { - return astgen.failNode(node, "break expression outside loop", .{}); - }, } } + if (break_label != 0) { + const label_name = try astgen.identifierTokenString(break_label); + return astgen.failTok(break_label, "label not found: '{s}'", .{label_name}); + } else { + return astgen.failNode(node, "break expression outside loop", .{}); + } } fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const break_label = node_datas[node].lhs; @@ -1582,7 +1578,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) const gen_zir = scope.cast(GenZir).?; const continue_block = gen_zir.continue_block; if (continue_block == 0) { - scope = gen_zir.parent; + scope = gen_zir.parent orelse break; continue; } if (break_label != 0) blk: { @@ -1593,7 +1589,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) } } // found continue but either it has a different label, or no label - scope = gen_zir.parent; + scope = gen_zir.parent orelse break; continue; } @@ -1610,17 +1606,17 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) try unusedResultExpr(parent_gz, defer_scope.parent, expr_node); }, .defer_error => scope = scope.cast(Scope.Defer).?.parent, - else => if (break_label != 0) { - const label_name = try astgen.identifierTokenString(break_label); - return astgen.failTok(break_label, "label not found: '{s}'", .{label_name}); - } else { - return astgen.failNode(node, "continue expression outside loop", .{}); - }, } } + if (break_label != 0) { + const label_name = try astgen.identifierTokenString(break_label); + return astgen.failTok(break_label, "label not found: '{s}'", .{label_name}); + } else { + return astgen.failNode(node, "continue expression outside loop", .{}); + } } -pub fn blockExpr( +fn blockExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, @@ -1631,7 +1627,7 @@ pub fn blockExpr( defer tracy.end(); const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const token_tags = tree.tokens.items(.tag); @@ -1655,7 +1651,7 @@ fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: ast.Toke const gen_zir = scope.cast(GenZir).?; if (gen_zir.label) |prev_label| { if (try astgen.tokenIdentEql(label, prev_label.token)) { - const tree = &astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const label_name = try astgen.identifierTokenString(label); @@ -1670,12 +1666,11 @@ fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: ast.Toke }); } } - scope = gen_zir.parent; + scope = gen_zir.parent orelse return; }, .local_val => scope = scope.cast(Scope.LocalVal).?.parent, .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, - else => return, } } } @@ -1694,7 +1689,7 @@ fn labeledBlockExpr( assert(zir_tag == .block); const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const token_tags = tree.tokens.items(.tag); @@ -1768,7 +1763,7 @@ fn blockExprStmts( statements: []const ast.Node.Index, ) !void { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const node_tags = tree.nodes.items(.tag); @@ -2108,13 +2103,13 @@ fn genDefers( err_code: Zir.Inst.Ref, ) InnerError!void { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); var scope = inner_scope; while (scope != outer_scope) { switch (scope.tag) { - .gen_zir => scope = scope.cast(GenZir).?.parent, + .gen_zir => scope = scope.cast(GenZir).?.parent.?, .local_val => scope = scope.cast(Scope.LocalVal).?.parent, .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, .defer_normal => { @@ -2130,7 +2125,6 @@ fn genDefers( const expr_node = node_datas[defer_scope.defer_node].rhs; try unusedResultExpr(gz, defer_scope.parent, expr_node); }, - else => unreachable, } } } @@ -2161,7 +2155,7 @@ fn varDecl( try emitDbgNode(gz, node); const astgen = gz.astgen; const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const token_tags = tree.tokens.items(.tag); const name_token = var_decl.ast.mut_token + 1; @@ -2201,10 +2195,8 @@ fn varDecl( } s = local_ptr.parent; }, - .gen_zir => s = s.cast(GenZir).?.parent, + .gen_zir => s = s.cast(GenZir).?.parent orelse break, .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, - .file => break, - else => unreachable, }; } @@ -2402,7 +2394,7 @@ fn emitDbgNode(gz: *GenZir, node: ast.Node.Index) !void { if (gz.force_comptime) return; const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_tags = tree.nodes.items(.tag); const token_starts = tree.tokens.items(.start); const decl_start = token_starts[tree.firstToken(gz.decl_node_index)]; @@ -2420,7 +2412,7 @@ fn emitDbgNode(gz: *GenZir, node: ast.Node.Index) !void { fn assign(gz: *GenZir, scope: *Scope, infix_node: ast.Node.Index) InnerError!void { try emitDbgNode(gz, infix_node); const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const main_tokens = tree.nodes.items(.main_token); const node_tags = tree.nodes.items(.tag); @@ -2447,7 +2439,7 @@ fn assignOp( ) InnerError!void { try emitDbgNode(gz, infix_node); const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); @@ -2470,7 +2462,7 @@ fn assignShift( ) InnerError!void { try emitDbgNode(gz, infix_node); const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); @@ -2487,7 +2479,7 @@ fn assignShift( fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const operand = try expr(gz, scope, bool_rl, node_datas[node].lhs); @@ -2497,7 +2489,7 @@ fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inne fn bitNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const operand = try expr(gz, scope, .none, node_datas[node].lhs); @@ -2513,7 +2505,7 @@ fn negation( tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const operand = try expr(gz, scope, .none, node_datas[node].lhs); @@ -2529,7 +2521,7 @@ fn ptrType( ptr_info: ast.full.PtrType, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type); @@ -2612,7 +2604,7 @@ fn ptrType( fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); @@ -2632,7 +2624,7 @@ fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Z fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); @@ -2696,7 +2688,7 @@ fn fnDecl( fn_proto: ast.full.FnProto, ) InnerError!void { const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const token_tags = tree.tokens.items(.tag); // We insert this at the beginning so that its instruction index marks the @@ -2937,7 +2929,7 @@ fn globalVarDecl( var_decl: ast.full.VarDecl, ) InnerError!void { const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const token_tags = tree.tokens.items(.tag); const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var; @@ -3076,7 +3068,7 @@ fn comptimeDecl( node: ast.Node.Index, ) InnerError!void { const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const body_node = node_datas[node].lhs; @@ -3122,7 +3114,7 @@ fn usingnamespaceDecl( node: ast.Node.Index, ) InnerError!void { const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const type_expr = node_datas[node].lhs; @@ -3172,7 +3164,7 @@ fn testDecl( node: ast.Node.Index, ) InnerError!void { const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const body_node = node_datas[node].rhs; @@ -3271,7 +3263,7 @@ fn structDeclInner( const astgen = gz.astgen; const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_tags = tree.nodes.items(.tag); const node_datas = tree.nodes.items(.data); @@ -3483,7 +3475,7 @@ fn unionDeclInner( ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_tags = tree.nodes.items(.tag); const node_datas = tree.nodes.items(.data); @@ -3705,7 +3697,7 @@ fn containerDecl( ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const token_tags = tree.tokens.items(.tag); const node_tags = tree.nodes.items(.tag); const node_datas = tree.nodes.items(.data); @@ -4149,7 +4141,7 @@ fn errorSetDecl( ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const token_tags = tree.tokens.items(.tag); @@ -4189,7 +4181,7 @@ fn tryExpr( operand_node: ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const fn_block = astgen.fn_block orelse { return astgen.failNode(node, "invalid 'try' outside function scope", .{}); @@ -4272,7 +4264,7 @@ fn orelseCatchExpr( payload_token: ?ast.TokenIndex, ) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; var block_scope = parent_gz.makeSubBlock(scope); block_scope.setBreakResultLoc(rl); @@ -4421,14 +4413,14 @@ fn tokenIdentEql(astgen: *AstGen, token1: ast.TokenIndex, token2: ast.TokenIndex return mem.eql(u8, ident_name_1, ident_name_2); } -pub fn fieldAccess( +fn fieldAccess( gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const node_datas = tree.nodes.items(.data); @@ -4455,7 +4447,7 @@ fn arrayAccess( node: ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const node_datas = tree.nodes.items(.data); switch (rl) { @@ -4480,7 +4472,7 @@ fn simpleBinOp( op_inst_tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const result = try gz.addPlNode(op_inst_tag, node, Zir.Inst.Bin{ @@ -4512,7 +4504,7 @@ fn boolBinOp( zir_tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const lhs = try expr(gz, scope, bool_rl, node_datas[node].lhs); @@ -4538,7 +4530,7 @@ fn ifExpr( if_full: ast.full.If, ) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const token_tags = tree.tokens.items(.tag); var block_scope = parent_gz.makeSubBlock(scope); @@ -4765,7 +4757,7 @@ fn whileExpr( while_full: ast.full.While, ) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const token_tags = tree.tokens.items(.tag); if (while_full.label_token) |label_token| { @@ -4967,7 +4959,7 @@ fn forExpr( } // Set up variables and constants. const is_inline = parent_gz.force_comptime or for_full.inline_token != null; - const tree = &astgen.file.tree; + const tree = astgen.tree; const token_tags = tree.tokens.items(.tag); const array_ptr = try expr(parent_gz, scope, .ref, for_full.ast.cond_expr); @@ -5123,111 +5115,6 @@ fn forExpr( ); } -fn getRangeNode( - node_tags: []const ast.Node.Tag, - node_datas: []const ast.Node.Data, - node: ast.Node.Index, -) ?ast.Node.Index { - switch (node_tags[node]) { - .switch_range => return node, - .grouped_expression => unreachable, - else => return null, - } -} - -pub const SwitchProngSrc = union(enum) { - scalar: u32, - multi: Multi, - range: Multi, - - pub const Multi = struct { - prong: u32, - item: u32, - }; - - pub const RangeExpand = enum { none, first, last }; - - /// This function is intended to be called only when it is certain that we need - /// the LazySrcLoc in order to emit a compile error. - pub fn resolve( - prong_src: SwitchProngSrc, - decl: *Decl, - switch_node_offset: i32, - range_expand: RangeExpand, - ) LazySrcLoc { - @setCold(true); - const switch_node = decl.relativeToNodeIndex(switch_node_offset); - const tree = decl.namespace.file_scope.tree; - const main_tokens = tree.nodes.items(.main_token); - const node_datas = tree.nodes.items(.data); - const node_tags = tree.nodes.items(.tag); - const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange); - const case_nodes = tree.extra_data[extra.start..extra.end]; - - var multi_i: u32 = 0; - var scalar_i: u32 = 0; - for (case_nodes) |case_node| { - const case = switch (node_tags[case_node]) { - .switch_case_one => tree.switchCaseOne(case_node), - .switch_case => tree.switchCase(case_node), - else => unreachable, - }; - if (case.ast.values.len == 0) - continue; - if (case.ast.values.len == 1 and - node_tags[case.ast.values[0]] == .identifier and - mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")) - { - continue; - } - const is_multi = case.ast.values.len != 1 or - getRangeNode(node_tags, node_datas, case.ast.values[0]) != null; - - switch (prong_src) { - .scalar => |i| if (!is_multi and i == scalar_i) return LazySrcLoc{ - .node_offset = decl.nodeIndexToRelative(case.ast.values[0]), - }, - .multi => |s| if (is_multi and s.prong == multi_i) { - var item_i: u32 = 0; - for (case.ast.values) |item_node| { - if (getRangeNode(node_tags, node_datas, item_node) != null) - continue; - - if (item_i == s.item) return LazySrcLoc{ - .node_offset = decl.nodeIndexToRelative(item_node), - }; - item_i += 1; - } else unreachable; - }, - .range => |s| if (is_multi and s.prong == multi_i) { - var range_i: u32 = 0; - for (case.ast.values) |item_node| { - const range = getRangeNode(node_tags, node_datas, item_node) orelse continue; - - if (range_i == s.item) switch (range_expand) { - .none => return LazySrcLoc{ - .node_offset = decl.nodeIndexToRelative(item_node), - }, - .first => return LazySrcLoc{ - .node_offset = decl.nodeIndexToRelative(node_datas[range].lhs), - }, - .last => return LazySrcLoc{ - .node_offset = decl.nodeIndexToRelative(node_datas[range].rhs), - }, - }; - range_i += 1; - } else unreachable; - }, - } - if (is_multi) { - multi_i += 1; - } else { - scalar_i += 1; - } - } else unreachable; - } -}; - fn switchExpr( parent_gz: *GenZir, scope: *Scope, @@ -5236,7 +5123,7 @@ fn switchExpr( ) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; const gpa = astgen.gpa; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); @@ -5348,9 +5235,7 @@ fn switchExpr( continue; } - if (case.ast.values.len == 1 and - getRangeNode(node_tags, node_datas, case.ast.values[0]) == null) - { + if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) { scalar_cases_len += 1; } else { multi_cases_len += 1; @@ -5472,7 +5357,7 @@ fn switchExpr( case_scope.instructions.shrinkRetainingCapacity(0); const is_multi_case = case.ast.values.len != 1 or - getRangeNode(node_tags, node_datas, case.ast.values[0]) != null; + node_tags[case.ast.values[0]] == .switch_range; const sub_scope = blk: { const payload_token = case.payload_token orelse break :blk &case_scope.base; @@ -5528,7 +5413,7 @@ fn switchExpr( // items var items_len: u32 = 0; for (case.ast.values) |item_node| { - if (getRangeNode(node_tags, node_datas, item_node) != null) continue; + if (node_tags[item_node] == .switch_range) continue; items_len += 1; const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); @@ -5537,8 +5422,8 @@ fn switchExpr( // ranges var ranges_len: u32 = 0; - for (case.ast.values) |item_node| { - const range = getRangeNode(node_tags, node_datas, item_node) orelse continue; + for (case.ast.values) |range| { + if (node_tags[range] != .switch_range) continue; ranges_len += 1; const first = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].lhs); @@ -5824,7 +5709,7 @@ fn switchExpr( fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const main_tokens = tree.nodes.items(.main_token); @@ -5857,7 +5742,7 @@ fn identifier( defer tracy.end(); const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const ident_token = main_tokens[ident]; @@ -5922,8 +5807,8 @@ fn identifier( } s = local_ptr.parent; }, - .gen_zir => s = s.cast(GenZir).?.parent, - else => break, + .gen_zir => s = s.cast(GenZir).?.parent orelse break, + .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, }; } @@ -5946,7 +5831,7 @@ fn stringLiteral( node: ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const str_lit_token = main_tokens[node]; const str = try astgen.strLitAsString(str_lit_token); @@ -5967,7 +5852,7 @@ fn multilineStringLiteral( node: ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const main_tokens = tree.nodes.items(.main_token); @@ -6006,7 +5891,7 @@ fn multilineStringLiteral( fn charLiteral(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const main_token = main_tokens[node]; const slice = tree.tokenSlice(main_token); @@ -6035,7 +5920,7 @@ fn integerLiteral( node: ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const int_token = main_tokens[node]; const prefixed_bytes = tree.tokenSlice(int_token); @@ -6087,7 +5972,7 @@ fn floatLiteral( ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const arena = astgen.arena; - const tree = &astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const main_token = main_tokens[node]; @@ -6130,7 +6015,7 @@ fn asmExpr( ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const arena = astgen.arena; - const tree = &astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const node_datas = tree.nodes.items(.data); const token_tags = tree.tokens.items(.tag); @@ -6426,7 +6311,7 @@ fn builtinCall( params: []const ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; - const tree = &astgen.file.tree; + const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); const builtin_token = main_tokens[node]; @@ -7406,7 +7291,7 @@ fn rvalue( }, .ref => { // We need a pointer but we have a value. - const tree = &gz.astgen.file.tree; + const tree = gz.astgen.tree; const src_token = tree.firstToken(src_node); return gz.addUnTok(.ref, result, src_token); }, @@ -7498,8 +7383,8 @@ fn rvalue( /// and allocates the result within `astgen.arena`. /// Otherwise, returns a reference to the source code bytes directly. /// See also `appendIdentStr` and `parseStrLit`. -pub fn identifierTokenString(astgen: *AstGen, token: ast.TokenIndex) InnerError![]const u8 { - const tree = &astgen.file.tree; +fn identifierTokenString(astgen: *AstGen, token: ast.TokenIndex) InnerError![]const u8 { + const tree = astgen.tree; const token_tags = tree.tokens.items(.tag); assert(token_tags[token] == .identifier); const ident_name = tree.tokenSlice(token); @@ -7516,12 +7401,12 @@ pub fn identifierTokenString(astgen: *AstGen, token: ast.TokenIndex) InnerError! /// Given an identifier token, obtain the string for it (possibly parsing as a string /// literal if it is @"" syntax), and append the string to `buf`. /// See also `identifierTokenString` and `parseStrLit`. -pub fn appendIdentStr( +fn appendIdentStr( astgen: *AstGen, token: ast.TokenIndex, buf: *ArrayListUnmanaged(u8), ) InnerError!void { - const tree = &astgen.file.tree; + const tree = astgen.tree; const token_tags = tree.tokens.items(.tag); assert(token_tags[token] == .identifier); const ident_name = tree.tokenSlice(token); @@ -7533,14 +7418,14 @@ pub fn appendIdentStr( } /// Appends the result to `buf`. -pub fn parseStrLit( +fn parseStrLit( astgen: *AstGen, token: ast.TokenIndex, buf: *ArrayListUnmanaged(u8), bytes: []const u8, offset: u32, ) InnerError!void { - const tree = &astgen.file.tree; + const tree = astgen.tree; const raw_string = bytes[offset..]; var buf_managed = buf.toManaged(astgen.gpa); const result = std.zig.string_literal.parseAppend(&buf_managed, raw_string); @@ -7598,7 +7483,7 @@ pub fn parseStrLit( } } -pub fn failNode( +fn failNode( astgen: *AstGen, node: ast.Node.Index, comptime format: []const u8, @@ -7607,7 +7492,7 @@ pub fn failNode( return astgen.failNodeNotes(node, format, args, &[0]u32{}); } -pub fn failNodeNotes( +fn failNodeNotes( astgen: *AstGen, node: ast.Node.Index, comptime format: []const u8, @@ -7639,7 +7524,7 @@ pub fn failNodeNotes( return error.AnalysisFail; } -pub fn failTok( +fn failTok( astgen: *AstGen, token: ast.TokenIndex, comptime format: []const u8, @@ -7648,7 +7533,7 @@ pub fn failTok( return astgen.failTokNotes(token, format, args, &[0]u32{}); } -pub fn failTokNotes( +fn failTokNotes( astgen: *AstGen, token: ast.TokenIndex, comptime format: []const u8, @@ -7680,9 +7565,8 @@ pub fn failTokNotes( return error.AnalysisFail; } -/// Same as `fail`, except given an absolute byte offset, and the function sets up the `LazySrcLoc` -/// for pointing at it relatively by subtracting from the containing `Decl`. -pub fn failOff( +/// Same as `fail`, except given an absolute byte offset. +fn failOff( astgen: *AstGen, token: ast.TokenIndex, byte_offset: u32, @@ -7707,7 +7591,7 @@ pub fn failOff( return error.AnalysisFail; } -pub fn errNoteTok( +fn errNoteTok( astgen: *AstGen, token: ast.TokenIndex, comptime format: []const u8, @@ -7730,7 +7614,7 @@ pub fn errNoteTok( }); } -pub fn errNoteNode( +fn errNoteNode( astgen: *AstGen, node: ast.Node.Index, comptime format: []const u8, @@ -7780,7 +7664,7 @@ fn strLitAsString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !IndexSlice { const gpa = astgen.gpa; const string_bytes = &astgen.string_bytes; const str_index = @intCast(u32, string_bytes.items.len); - const token_bytes = astgen.file.tree.tokenSlice(str_lit_token); + const token_bytes = astgen.tree.tokenSlice(str_lit_token); try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0); const key = string_bytes.items[str_index..]; const gop = try astgen.string_table.getOrPut(gpa, key); @@ -7811,9 +7695,934 @@ fn testNameString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !u32 { const gpa = astgen.gpa; const string_bytes = &astgen.string_bytes; const str_index = @intCast(u32, string_bytes.items.len); - const token_bytes = astgen.file.tree.tokenSlice(str_lit_token); + const token_bytes = astgen.tree.tokenSlice(str_lit_token); try string_bytes.append(gpa, 0); // Indicates this is a test. try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0); try string_bytes.append(gpa, 0); return str_index; } + +const Scope = struct { + tag: Tag, + + fn cast(base: *Scope, comptime T: type) ?*T { + if (T == Defer) { + switch (base.tag) { + .defer_normal, .defer_error => return @fieldParentPtr(T, "base", base), + else => return null, + } + } + if (base.tag != T.base_tag) + return null; + + return @fieldParentPtr(T, "base", base); + } + + const Tag = enum { + gen_zir, + local_val, + local_ptr, + defer_normal, + defer_error, + }; + + /// This is always a `const` local and importantly the `inst` is a value type, not a pointer. + /// This structure lives as long as the AST generation of the Block + /// node that contains the variable. + const LocalVal = struct { + const base_tag: Tag = .local_val; + base: Scope = Scope{ .tag = base_tag }, + /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`. + parent: *Scope, + gen_zir: *GenZir, + inst: Zir.Inst.Ref, + /// Source location of the corresponding variable declaration. + token_src: ast.TokenIndex, + /// String table index. + name: u32, + }; + + /// This could be a `const` or `var` local. It has a pointer instead of a value. + /// This structure lives as long as the AST generation of the Block + /// node that contains the variable. + const LocalPtr = struct { + const base_tag: Tag = .local_ptr; + base: Scope = Scope{ .tag = base_tag }, + /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`. + parent: *Scope, + gen_zir: *GenZir, + ptr: Zir.Inst.Ref, + /// Source location of the corresponding variable declaration. + token_src: ast.TokenIndex, + /// String table index. + name: u32, + }; + + const Defer = struct { + base: Scope, + /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`. + parent: *Scope, + defer_node: ast.Node.Index, + }; +}; + +/// This is a temporary structure; references to it are valid only +/// while constructing a `Zir`. +const GenZir = struct { + const base_tag: Scope.Tag = .gen_zir; + base: Scope = Scope{ .tag = base_tag }, + force_comptime: bool, + /// The end of special indexes. `Zir.Inst.Ref` subtracts against this number to convert + /// to `Zir.Inst.Index`. The default here is correct if there are 0 parameters. + ref_start_index: u32 = Zir.Inst.Ref.typed_value_map.len, + /// The containing decl AST node. + decl_node_index: ast.Node.Index, + /// The containing decl line index, absolute. + decl_line: u32, + parent: ?*Scope, + /// All `GenZir` scopes for the same ZIR share this. + astgen: *AstGen, + /// Keeps track of the list of instructions in this scope only. Indexes + /// to instructions in `astgen`. + instructions: ArrayListUnmanaged(Zir.Inst.Index) = .{}, + label: ?Label = null, + break_block: Zir.Inst.Index = 0, + continue_block: Zir.Inst.Index = 0, + /// Only valid when setBreakResultLoc is called. + break_result_loc: AstGen.ResultLoc = undefined, + /// When a block has a pointer result location, here it is. + rl_ptr: Zir.Inst.Ref = .none, + /// When a block has a type result location, here it is. + rl_ty_inst: Zir.Inst.Ref = .none, + /// Keeps track of how many branches of a block did not actually + /// consume the result location. astgen uses this to figure out + /// whether to rely on break instructions or writing to the result + /// pointer for the result instruction. + rvalue_rl_count: usize = 0, + /// Keeps track of how many break instructions there are. When astgen is finished + /// with a block, it can check this against rvalue_rl_count to find out whether + /// the break instructions should be downgraded to break_void. + break_count: usize = 0, + /// Tracks `break :foo bar` instructions so they can possibly be elided later if + /// the labeled block ends up not needing a result location pointer. + labeled_breaks: ArrayListUnmanaged(Zir.Inst.Index) = .{}, + /// Tracks `store_to_block_ptr` instructions that correspond to break instructions + /// so they can possibly be elided later if the labeled block ends up not needing + /// a result location pointer. + labeled_store_to_block_ptr_list: ArrayListUnmanaged(Zir.Inst.Index) = .{}, + + suspend_node: ast.Node.Index = 0, + nosuspend_node: ast.Node.Index = 0, + + fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir { + return .{ + .force_comptime = gz.force_comptime, + .ref_start_index = gz.ref_start_index, + .decl_node_index = gz.decl_node_index, + .decl_line = gz.decl_line, + .parent = scope, + .astgen = gz.astgen, + .suspend_node = gz.suspend_node, + .nosuspend_node = gz.nosuspend_node, + }; + } + + const Label = struct { + token: ast.TokenIndex, + block_inst: Zir.Inst.Index, + used: bool = false, + }; + + fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool { + if (inst_ref == .unreachable_value) return true; + if (gz.refToIndex(inst_ref)) |inst_index| { + return gz.astgen.instructions.items(.tag)[inst_index].isNoReturn(); + } + return false; + } + + fn calcLine(gz: GenZir, node: ast.Node.Index) u32 { + const astgen = gz.astgen; + const tree = astgen.tree; + const node_tags = tree.nodes.items(.tag); + const token_starts = tree.tokens.items(.start); + const decl_start = token_starts[tree.firstToken(gz.decl_node_index)]; + const node_start = token_starts[tree.firstToken(node)]; + const source = tree.source[decl_start..node_start]; + const loc = std.zig.findLineColumn(source, source.len); + return @intCast(u32, gz.decl_line + loc.line); + } + + fn tokSrcLoc(gz: GenZir, token_index: ast.TokenIndex) LazySrcLoc { + return .{ .token_offset = token_index - gz.srcToken() }; + } + + fn nodeSrcLoc(gz: GenZir, node_index: ast.Node.Index) LazySrcLoc { + return .{ .node_offset = gz.nodeIndexToRelative(node_index) }; + } + + fn nodeIndexToRelative(gz: GenZir, node_index: ast.Node.Index) i32 { + return @bitCast(i32, node_index) - @bitCast(i32, gz.decl_node_index); + } + + fn tokenIndexToRelative(gz: GenZir, token: ast.TokenIndex) u32 { + return token - gz.srcToken(); + } + + fn srcToken(gz: GenZir) ast.TokenIndex { + return gz.astgen.tree.firstToken(gz.decl_node_index); + } + + fn indexToRef(gz: GenZir, inst: Zir.Inst.Index) Zir.Inst.Ref { + return @intToEnum(Zir.Inst.Ref, gz.ref_start_index + inst); + } + + fn refToIndex(gz: GenZir, inst: Zir.Inst.Ref) ?Zir.Inst.Index { + const ref_int = @enumToInt(inst); + if (ref_int >= gz.ref_start_index) { + return ref_int - gz.ref_start_index; + } else { + return null; + } + } + + fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void { + // Depending on whether the result location is a pointer or value, different + // ZIR needs to be generated. In the former case we rely on storing to the + // pointer to communicate the result, and use breakvoid; in the latter case + // the block break instructions will have the result values. + // One more complication: when the result location is a pointer, we detect + // the scenario where the result location is not consumed. In this case + // we emit ZIR for the block break instructions to have the result values, + // and then rvalue() on that to pass the value to the result location. + switch (parent_rl) { + .ty => |ty_inst| { + gz.rl_ty_inst = ty_inst; + gz.break_result_loc = parent_rl; + }, + .none_or_ref => { + gz.break_result_loc = .ref; + }, + .discard, .none, .ptr, .ref => { + gz.break_result_loc = parent_rl; + }, + + .inferred_ptr => |ptr| { + gz.rl_ptr = ptr; + gz.break_result_loc = .{ .block_ptr = gz }; + }, + + .block_ptr => |parent_block_scope| { + gz.rl_ty_inst = parent_block_scope.rl_ty_inst; + gz.rl_ptr = parent_block_scope.rl_ptr; + gz.break_result_loc = .{ .block_ptr = gz }; + }, + } + } + + fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void { + const gpa = gz.astgen.gpa; + try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + + @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); + const zir_datas = gz.astgen.instructions.items(.data); + zir_datas[inst].bool_br.payload_index = gz.astgen.addExtraAssumeCapacity( + Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) }, + ); + gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items); + } + + fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void { + const gpa = gz.astgen.gpa; + try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + + @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); + const zir_datas = gz.astgen.instructions.items(.data); + zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity( + Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) }, + ); + gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items); + } + + /// Same as `setBlockBody` except we don't copy instructions which are + /// `store_to_block_ptr` instructions with lhs set to .none. + fn setBlockBodyEliding(gz: GenZir, inst: Zir.Inst.Index) !void { + const gpa = gz.astgen.gpa; + try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + + @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); + const zir_datas = gz.astgen.instructions.items(.data); + const zir_tags = gz.astgen.instructions.items(.tag); + const block_pl_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Block{ + .body_len = @intCast(u32, gz.instructions.items.len), + }); + zir_datas[inst].pl_node.payload_index = block_pl_index; + for (gz.instructions.items) |sub_inst| { + if (zir_tags[sub_inst] == .store_to_block_ptr and + zir_datas[sub_inst].bin.lhs == .none) + { + // Decrement `body_len`. + gz.astgen.extra.items[block_pl_index] -= 1; + continue; + } + gz.astgen.extra.appendAssumeCapacity(sub_inst); + } + } + + fn addFunc(gz: *GenZir, args: struct { + src_node: ast.Node.Index, + param_types: []const Zir.Inst.Ref, + body: []const Zir.Inst.Index, + ret_ty: Zir.Inst.Ref, + cc: Zir.Inst.Ref, + align_inst: Zir.Inst.Ref, + lib_name: u32, + is_var_args: bool, + is_inferred_error: bool, + is_test: bool, + }) !Zir.Inst.Ref { + assert(args.src_node != 0); + assert(args.ret_ty != .none); + const astgen = gz.astgen; + const gpa = astgen.gpa; + + try gz.instructions.ensureUnusedCapacity(gpa, 1); + try astgen.instructions.ensureUnusedCapacity(gpa, 1); + + var src_locs_buffer: [3]u32 = undefined; + var src_locs: []u32 = src_locs_buffer[0..0]; + if (args.body.len != 0) { + const tree = astgen.tree; + const node_tags = tree.nodes.items(.tag); + const node_datas = tree.nodes.items(.data); + const token_starts = tree.tokens.items(.start); + const decl_start = token_starts[tree.firstToken(gz.decl_node_index)]; + const fn_decl = args.src_node; + assert(node_tags[fn_decl] == .fn_decl or node_tags[fn_decl] == .test_decl); + const block = node_datas[fn_decl].rhs; + const lbrace_start = token_starts[tree.firstToken(block)]; + const rbrace_start = token_starts[tree.lastToken(block)]; + const lbrace_source = tree.source[decl_start..lbrace_start]; + const lbrace_loc = std.zig.findLineColumn(lbrace_source, lbrace_source.len); + const rbrace_source = tree.source[lbrace_start..rbrace_start]; + const rbrace_loc = std.zig.findLineColumn(rbrace_source, rbrace_source.len); + const lbrace_line = @intCast(u32, lbrace_loc.line); + const rbrace_line = lbrace_line + @intCast(u32, rbrace_loc.line); + const columns = @intCast(u32, lbrace_loc.column) | + (@intCast(u32, rbrace_loc.column) << 16); + src_locs_buffer[0] = lbrace_line; + src_locs_buffer[1] = rbrace_line; + src_locs_buffer[2] = columns; + src_locs = &src_locs_buffer; + } + + if (args.cc != .none or args.lib_name != 0 or + args.is_var_args or args.is_test or args.align_inst != .none) + { + try astgen.extra.ensureUnusedCapacity( + gpa, + @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len + + args.param_types.len + args.body.len + src_locs.len + + @boolToInt(args.lib_name != 0) + + @boolToInt(args.align_inst != .none) + + @boolToInt(args.cc != .none), + ); + const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{ + .src_node = gz.nodeIndexToRelative(args.src_node), + .return_type = args.ret_ty, + .param_types_len = @intCast(u32, args.param_types.len), + .body_len = @intCast(u32, args.body.len), + }); + if (args.lib_name != 0) { + astgen.extra.appendAssumeCapacity(args.lib_name); + } + if (args.cc != .none) { + astgen.extra.appendAssumeCapacity(@enumToInt(args.cc)); + } + if (args.align_inst != .none) { + astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); + } + astgen.appendRefsAssumeCapacity(args.param_types); + astgen.extra.appendSliceAssumeCapacity(args.body); + astgen.extra.appendSliceAssumeCapacity(src_locs); + + const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); + astgen.instructions.appendAssumeCapacity(.{ + .tag = .extended, + .data = .{ .extended = .{ + .opcode = .func, + .small = @bitCast(u16, Zir.Inst.ExtendedFunc.Small{ + .is_var_args = args.is_var_args, + .is_inferred_error = args.is_inferred_error, + .has_lib_name = args.lib_name != 0, + .has_cc = args.cc != .none, + .has_align = args.align_inst != .none, + .is_test = args.is_test, + }), + .operand = payload_index, + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + return gz.indexToRef(new_index); + } else { + try gz.astgen.extra.ensureUnusedCapacity( + gpa, + @typeInfo(Zir.Inst.Func).Struct.fields.len + + args.param_types.len + args.body.len + src_locs.len, + ); + + const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Func{ + .return_type = args.ret_ty, + .param_types_len = @intCast(u32, args.param_types.len), + .body_len = @intCast(u32, args.body.len), + }); + gz.astgen.appendRefsAssumeCapacity(args.param_types); + gz.astgen.extra.appendSliceAssumeCapacity(args.body); + gz.astgen.extra.appendSliceAssumeCapacity(src_locs); + + const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func; + const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); + gz.astgen.instructions.appendAssumeCapacity(.{ + .tag = tag, + .data = .{ .pl_node = .{ + .src_node = gz.nodeIndexToRelative(args.src_node), + .payload_index = payload_index, + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + return gz.indexToRef(new_index); + } + } + + fn addVar(gz: *GenZir, args: struct { + align_inst: Zir.Inst.Ref, + lib_name: u32, + var_type: Zir.Inst.Ref, + init: Zir.Inst.Ref, + is_extern: bool, + }) !Zir.Inst.Ref { + const astgen = gz.astgen; + const gpa = astgen.gpa; + + try gz.instructions.ensureUnusedCapacity(gpa, 1); + try astgen.instructions.ensureUnusedCapacity(gpa, 1); + + try astgen.extra.ensureUnusedCapacity( + gpa, + @typeInfo(Zir.Inst.ExtendedVar).Struct.fields.len + + @boolToInt(args.lib_name != 0) + + @boolToInt(args.align_inst != .none) + + @boolToInt(args.init != .none), + ); + const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedVar{ + .var_type = args.var_type, + }); + if (args.lib_name != 0) { + astgen.extra.appendAssumeCapacity(args.lib_name); + } + if (args.align_inst != .none) { + astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); + } + if (args.init != .none) { + astgen.extra.appendAssumeCapacity(@enumToInt(args.init)); + } + + const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); + astgen.instructions.appendAssumeCapacity(.{ + .tag = .extended, + .data = .{ .extended = .{ + .opcode = .variable, + .small = @bitCast(u16, Zir.Inst.ExtendedVar.Small{ + .has_lib_name = args.lib_name != 0, + .has_align = args.align_inst != .none, + .has_init = args.init != .none, + .is_extern = args.is_extern, + }), + .operand = payload_index, + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + return gz.indexToRef(new_index); + } + + fn addCall( + gz: *GenZir, + tag: Zir.Inst.Tag, + callee: Zir.Inst.Ref, + args: []const Zir.Inst.Ref, + /// Absolute node index. This function does the conversion to offset from Decl. + src_node: ast.Node.Index, + ) !Zir.Inst.Ref { + assert(callee != .none); + assert(src_node != 0); + const gpa = gz.astgen.gpa; + try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); + try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); + try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + + @typeInfo(Zir.Inst.Call).Struct.fields.len + args.len); + + const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Call{ + .callee = callee, + .args_len = @intCast(u32, args.len), + }); + gz.astgen.appendRefsAssumeCapacity(args); + + const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); + gz.astgen.instructions.appendAssumeCapacity(.{ + .tag = tag, + .data = .{ .pl_node = .{ + .src_node = gz.nodeIndexToRelative(src_node), + .payload_index = payload_index, + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + return gz.indexToRef(new_index); + } + + /// Note that this returns a `Zir.Inst.Index` not a ref. + /// Leaves the `payload_index` field undefined. + fn addBoolBr( + gz: *GenZir, + tag: Zir.Inst.Tag, + lhs: Zir.Inst.Ref, + ) !Zir.Inst.Index { + assert(lhs != .none); + const gpa = gz.astgen.gpa; + try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); + try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); + + const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); + gz.astgen.instructions.appendAssumeCapacity(.{ + .tag = tag, + .data = .{ .bool_br = .{ + .lhs = lhs, + .payload_index = undefined, + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + return new_index; + } + + fn addInt(gz: *GenZir, integer: u64) !Zir.Inst.Ref { + return gz.add(.{ + .tag = .int, + .data = .{ .int = integer }, + }); + } + + fn addIntBig(gz: *GenZir, limbs: []const std.math.big.Limb) !Zir.Inst.Ref { + const astgen = gz.astgen; + const gpa = astgen.gpa; + try gz.instructions.ensureUnusedCapacity(gpa, 1); + try astgen.instructions.ensureUnusedCapacity(gpa, 1); + try astgen.string_bytes.ensureUnusedCapacity(gpa, @sizeOf(std.math.big.Limb) * limbs.len); + + const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); + astgen.instructions.appendAssumeCapacity(.{ + .tag = .int_big, + .data = .{ .str = .{ + .start = @intCast(u32, astgen.string_bytes.items.len), + .len = @intCast(u32, limbs.len), + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + astgen.string_bytes.appendSliceAssumeCapacity(mem.sliceAsBytes(limbs)); + return gz.indexToRef(new_index); + } + + fn addFloat(gz: *GenZir, number: f32, src_node: ast.Node.Index) !Zir.Inst.Ref { + return gz.add(.{ + .tag = .float, + .data = .{ .float = .{ + .src_node = gz.nodeIndexToRelative(src_node), + .number = number, + } }, + }); + } + + fn addUnNode( + gz: *GenZir, + tag: Zir.Inst.Tag, + operand: Zir.Inst.Ref, + /// Absolute node index. This function does the conversion to offset from Decl. + src_node: ast.Node.Index, + ) !Zir.Inst.Ref { + assert(operand != .none); + return gz.add(.{ + .tag = tag, + .data = .{ .un_node = .{ + .operand = operand, + .src_node = gz.nodeIndexToRelative(src_node), + } }, + }); + } + + fn addPlNode( + gz: *GenZir, + tag: Zir.Inst.Tag, + /// Absolute node index. This function does the conversion to offset from Decl. + src_node: ast.Node.Index, + extra: anytype, + ) !Zir.Inst.Ref { + const gpa = gz.astgen.gpa; + try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); + try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); + + const payload_index = try gz.astgen.addExtra(extra); + const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); + gz.astgen.instructions.appendAssumeCapacity(.{ + .tag = tag, + .data = .{ .pl_node = .{ + .src_node = gz.nodeIndexToRelative(src_node), + .payload_index = payload_index, + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + return gz.indexToRef(new_index); + } + + fn addExtendedPayload( + gz: *GenZir, + opcode: Zir.Inst.Extended, + extra: anytype, + ) !Zir.Inst.Ref { + const gpa = gz.astgen.gpa; + + try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); + try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); + + const payload_index = try gz.astgen.addExtra(extra); + const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); + gz.astgen.instructions.appendAssumeCapacity(.{ + .tag = .extended, + .data = .{ .extended = .{ + .opcode = opcode, + .small = undefined, + .operand = payload_index, + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + return gz.indexToRef(new_index); + } + + fn addExtendedMultiOp( + gz: *GenZir, + opcode: Zir.Inst.Extended, + node: ast.Node.Index, + operands: []const Zir.Inst.Ref, + ) !Zir.Inst.Ref { + const astgen = gz.astgen; + const gpa = astgen.gpa; + + try gz.instructions.ensureUnusedCapacity(gpa, 1); + try astgen.instructions.ensureUnusedCapacity(gpa, 1); + try astgen.extra.ensureUnusedCapacity( + gpa, + @typeInfo(Zir.Inst.NodeMultiOp).Struct.fields.len + operands.len, + ); + + const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.NodeMultiOp{ + .src_node = gz.nodeIndexToRelative(node), + }); + const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); + astgen.instructions.appendAssumeCapacity(.{ + .tag = .extended, + .data = .{ .extended = .{ + .opcode = opcode, + .small = @intCast(u16, operands.len), + .operand = payload_index, + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + astgen.appendRefsAssumeCapacity(operands); + return gz.indexToRef(new_index); + } + + fn addArrayTypeSentinel( + gz: *GenZir, + len: Zir.Inst.Ref, + sentinel: Zir.Inst.Ref, + elem_type: Zir.Inst.Ref, + ) !Zir.Inst.Ref { + const gpa = gz.astgen.gpa; + try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); + try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); + + const payload_index = try gz.astgen.addExtra(Zir.Inst.ArrayTypeSentinel{ + .sentinel = sentinel, + .elem_type = elem_type, + }); + const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); + gz.astgen.instructions.appendAssumeCapacity(.{ + .tag = .array_type_sentinel, + .data = .{ .array_type_sentinel = .{ + .len = len, + .payload_index = payload_index, + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + return gz.indexToRef(new_index); + } + + fn addUnTok( + gz: *GenZir, + tag: Zir.Inst.Tag, + operand: Zir.Inst.Ref, + /// Absolute token index. This function does the conversion to Decl offset. + abs_tok_index: ast.TokenIndex, + ) !Zir.Inst.Ref { + assert(operand != .none); + return gz.add(.{ + .tag = tag, + .data = .{ .un_tok = .{ + .operand = operand, + .src_tok = gz.tokenIndexToRelative(abs_tok_index), + } }, + }); + } + + fn addStrTok( + gz: *GenZir, + tag: Zir.Inst.Tag, + str_index: u32, + /// Absolute token index. This function does the conversion to Decl offset. + abs_tok_index: ast.TokenIndex, + ) !Zir.Inst.Ref { + return gz.add(.{ + .tag = tag, + .data = .{ .str_tok = .{ + .start = str_index, + .src_tok = gz.tokenIndexToRelative(abs_tok_index), + } }, + }); + } + + fn addBreak( + gz: *GenZir, + tag: Zir.Inst.Tag, + break_block: Zir.Inst.Index, + operand: Zir.Inst.Ref, + ) !Zir.Inst.Index { + return gz.addAsIndex(.{ + .tag = tag, + .data = .{ .@"break" = .{ + .block_inst = break_block, + .operand = operand, + } }, + }); + } + + fn addBin( + gz: *GenZir, + tag: Zir.Inst.Tag, + lhs: Zir.Inst.Ref, + rhs: Zir.Inst.Ref, + ) !Zir.Inst.Ref { + assert(lhs != .none); + assert(rhs != .none); + return gz.add(.{ + .tag = tag, + .data = .{ .bin = .{ + .lhs = lhs, + .rhs = rhs, + } }, + }); + } + + fn addDecl( + gz: *GenZir, + tag: Zir.Inst.Tag, + decl_index: u32, + src_node: ast.Node.Index, + ) !Zir.Inst.Ref { + return gz.add(.{ + .tag = tag, + .data = .{ .pl_node = .{ + .src_node = gz.nodeIndexToRelative(src_node), + .payload_index = decl_index, + } }, + }); + } + + fn addNode( + gz: *GenZir, + tag: Zir.Inst.Tag, + /// Absolute node index. This function does the conversion to offset from Decl. + src_node: ast.Node.Index, + ) !Zir.Inst.Ref { + return gz.add(.{ + .tag = tag, + .data = .{ .node = gz.nodeIndexToRelative(src_node) }, + }); + } + + fn addNodeExtended( + gz: *GenZir, + opcode: Zir.Inst.Extended, + /// Absolute node index. This function does the conversion to offset from Decl. + src_node: ast.Node.Index, + ) !Zir.Inst.Ref { + return gz.add(.{ + .tag = .extended, + .data = .{ .extended = .{ + .opcode = opcode, + .small = undefined, + .operand = @bitCast(u32, gz.nodeIndexToRelative(src_node)), + } }, + }); + } + + fn addAllocExtended( + gz: *GenZir, + args: struct { + /// Absolute node index. This function does the conversion to offset from Decl. + node: ast.Node.Index, + type_inst: Zir.Inst.Ref, + align_inst: Zir.Inst.Ref, + is_const: bool, + is_comptime: bool, + }, + ) !Zir.Inst.Ref { + const astgen = gz.astgen; + const gpa = astgen.gpa; + + try gz.instructions.ensureUnusedCapacity(gpa, 1); + try astgen.instructions.ensureUnusedCapacity(gpa, 1); + try astgen.extra.ensureUnusedCapacity( + gpa, + @typeInfo(Zir.Inst.AllocExtended).Struct.fields.len + + @as(usize, @boolToInt(args.type_inst != .none)) + + @as(usize, @boolToInt(args.align_inst != .none)), + ); + const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.AllocExtended{ + .src_node = gz.nodeIndexToRelative(args.node), + }); + if (args.type_inst != .none) { + astgen.extra.appendAssumeCapacity(@enumToInt(args.type_inst)); + } + if (args.align_inst != .none) { + astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); + } + + const has_type: u4 = @boolToInt(args.type_inst != .none); + const has_align: u4 = @boolToInt(args.align_inst != .none); + const is_const: u4 = @boolToInt(args.is_const); + const is_comptime: u4 = @boolToInt(args.is_comptime); + const small: u16 = has_type | (has_align << 1) | (is_const << 2) | (is_comptime << 3); + + const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); + astgen.instructions.appendAssumeCapacity(.{ + .tag = .extended, + .data = .{ .extended = .{ + .opcode = .alloc, + .small = small, + .operand = payload_index, + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + return gz.indexToRef(new_index); + } + + fn addAsm( + gz: *GenZir, + args: struct { + /// Absolute node index. This function does the conversion to offset from Decl. + node: ast.Node.Index, + asm_source: Zir.Inst.Ref, + output_type_bits: u32, + is_volatile: bool, + outputs: []const Zir.Inst.Asm.Output, + inputs: []const Zir.Inst.Asm.Input, + clobbers: []const u32, + }, + ) !Zir.Inst.Ref { + const astgen = gz.astgen; + const gpa = astgen.gpa; + + try gz.instructions.ensureUnusedCapacity(gpa, 1); + try astgen.instructions.ensureUnusedCapacity(gpa, 1); + try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Asm).Struct.fields.len + + args.outputs.len * @typeInfo(Zir.Inst.Asm.Output).Struct.fields.len + + args.inputs.len * @typeInfo(Zir.Inst.Asm.Input).Struct.fields.len + + args.clobbers.len); + + const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Asm{ + .src_node = gz.nodeIndexToRelative(args.node), + .asm_source = args.asm_source, + .output_type_bits = args.output_type_bits, + }); + for (args.outputs) |output| { + _ = gz.astgen.addExtraAssumeCapacity(output); + } + for (args.inputs) |input| { + _ = gz.astgen.addExtraAssumeCapacity(input); + } + gz.astgen.extra.appendSliceAssumeCapacity(args.clobbers); + + // * 0b00000000_000XXXXX - `outputs_len`. + // * 0b000000XX_XXX00000 - `inputs_len`. + // * 0b0XXXXX00_00000000 - `clobbers_len`. + // * 0bX0000000_00000000 - is volatile + const small: u16 = @intCast(u16, args.outputs.len) | + @intCast(u16, args.inputs.len << 5) | + @intCast(u16, args.clobbers.len << 10) | + (@as(u16, @boolToInt(args.is_volatile)) << 15); + + const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); + astgen.instructions.appendAssumeCapacity(.{ + .tag = .extended, + .data = .{ .extended = .{ + .opcode = .@"asm", + .small = small, + .operand = payload_index, + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + return gz.indexToRef(new_index); + } + + /// Note that this returns a `Zir.Inst.Index` not a ref. + /// Does *not* append the block instruction to the scope. + /// Leaves the `payload_index` field undefined. + fn addBlock(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index { + const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); + const gpa = gz.astgen.gpa; + try gz.astgen.instructions.append(gpa, .{ + .tag = tag, + .data = .{ .pl_node = .{ + .src_node = gz.nodeIndexToRelative(node), + .payload_index = undefined, + } }, + }); + return new_index; + } + + /// Note that this returns a `Zir.Inst.Index` not a ref. + /// Leaves the `payload_index` field undefined. + fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index { + const gpa = gz.astgen.gpa; + try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); + const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); + try gz.astgen.instructions.append(gpa, .{ + .tag = tag, + .data = .{ .pl_node = .{ + .src_node = gz.nodeIndexToRelative(node), + .payload_index = undefined, + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + return new_index; + } + + fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref { + return gz.indexToRef(try gz.addAsIndex(inst)); + } + + fn addAsIndex(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Index { + const gpa = gz.astgen.gpa; + try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); + try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); + + const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); + gz.astgen.instructions.appendAssumeCapacity(inst); + gz.instructions.appendAssumeCapacity(new_index); + return new_index; + } +}; diff --git a/src/Module.zig b/src/Module.zig index 444e49084c..86b15e9b0b 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -628,12 +628,6 @@ pub const Scope = struct { pub const NameHash = [16]u8; pub fn cast(base: *Scope, comptime T: type) ?*T { - if (T == Defer) { - switch (base.tag) { - .defer_normal, .defer_error => return @fieldParentPtr(T, "base", base), - else => return null, - } - } if (base.tag != T.base_tag) return null; @@ -643,11 +637,6 @@ pub const Scope = struct { pub fn ownerDecl(scope: *Scope) ?*Decl { return switch (scope.tag) { .block => scope.cast(Block).?.sema.owner_decl, - .gen_zir => unreachable, - .local_val => unreachable, - .local_ptr => unreachable, - .defer_normal => unreachable, - .defer_error => unreachable, .file => null, .namespace => null, .decl_ref => scope.cast(DeclRef).?.decl, @@ -657,11 +646,6 @@ pub const Scope = struct { pub fn srcDecl(scope: *Scope) ?*Decl { return switch (scope.tag) { .block => scope.cast(Block).?.src_decl, - .gen_zir => unreachable, - .local_val => unreachable, - .local_ptr => unreachable, - .defer_normal => unreachable, - .defer_error => unreachable, .file => null, .namespace => null, .decl_ref => scope.cast(DeclRef).?.decl, @@ -672,11 +656,6 @@ pub const Scope = struct { pub fn namespace(scope: *Scope) *Namespace { switch (scope.tag) { .block => return scope.cast(Block).?.sema.owner_decl.namespace, - .gen_zir => unreachable, - .local_val => unreachable, - .local_ptr => unreachable, - .defer_normal => unreachable, - .defer_error => unreachable, .file => return scope.cast(File).?.namespace, .namespace => return scope.cast(Namespace).?, .decl_ref => return scope.cast(DeclRef).?.decl.namespace, @@ -690,11 +669,6 @@ pub const Scope = struct { .namespace => return @fieldParentPtr(Namespace, "base", base).file_scope.sub_file_path, .file => return @fieldParentPtr(File, "base", base).sub_file_path, .block => unreachable, - .gen_zir => unreachable, - .local_val => unreachable, - .local_ptr => unreachable, - .defer_normal => unreachable, - .defer_error => unreachable, .decl_ref => unreachable, } } @@ -706,11 +680,6 @@ pub const Scope = struct { cur = switch (cur.tag) { .namespace => return @fieldParentPtr(Namespace, "base", cur).file_scope, .file => return @fieldParentPtr(File, "base", cur), - .gen_zir => return @fieldParentPtr(GenZir, "base", cur).astgen.file, - .local_val => return @fieldParentPtr(LocalVal, "base", cur).gen_zir.astgen.file, - .local_ptr => return @fieldParentPtr(LocalPtr, "base", cur).gen_zir.astgen.file, - .defer_normal => @fieldParentPtr(Defer, "base", cur).parent, - .defer_error => @fieldParentPtr(Defer, "base", cur).parent, .block => return @fieldParentPtr(Block, "base", cur).src_decl.namespace.file_scope, .decl_ref => return @fieldParentPtr(DeclRef, "base", cur).decl.namespace.file_scope, }; @@ -723,15 +692,10 @@ pub const Scope = struct { /// Namespace owned by structs, enums, unions, and opaques for decls. namespace, block, - gen_zir, - local_val, - local_ptr, /// Used for simple error reporting. Only contains a reference to a /// `Decl` for use with `srcDecl` and `ownerDecl`. /// Has no parents or children. decl_ref, - defer_normal, - defer_error, }; /// The container that structs, enums, unions, and opaques have. @@ -1183,907 +1147,6 @@ pub const Scope = struct { } }; - /// This is a temporary structure; references to it are valid only - /// while constructing a `Zir`. - pub const GenZir = struct { - pub const base_tag: Tag = .gen_zir; - base: Scope = Scope{ .tag = base_tag }, - force_comptime: bool, - /// The end of special indexes. `Zir.Inst.Ref` subtracts against this number to convert - /// to `Zir.Inst.Index`. The default here is correct if there are 0 parameters. - ref_start_index: u32 = Zir.Inst.Ref.typed_value_map.len, - /// The containing decl AST node. - decl_node_index: ast.Node.Index, - /// The containing decl line index, absolute. - decl_line: u32, - /// Parents can be: `GenZir`, `File` - parent: *Scope, - /// All `GenZir` scopes for the same ZIR share this. - astgen: *AstGen, - /// Keeps track of the list of instructions in this scope only. Indexes - /// to instructions in `astgen`. - instructions: ArrayListUnmanaged(Zir.Inst.Index) = .{}, - label: ?Label = null, - break_block: Zir.Inst.Index = 0, - continue_block: Zir.Inst.Index = 0, - /// Only valid when setBreakResultLoc is called. - break_result_loc: AstGen.ResultLoc = undefined, - /// When a block has a pointer result location, here it is. - rl_ptr: Zir.Inst.Ref = .none, - /// When a block has a type result location, here it is. - rl_ty_inst: Zir.Inst.Ref = .none, - /// Keeps track of how many branches of a block did not actually - /// consume the result location. astgen uses this to figure out - /// whether to rely on break instructions or writing to the result - /// pointer for the result instruction. - rvalue_rl_count: usize = 0, - /// Keeps track of how many break instructions there are. When astgen is finished - /// with a block, it can check this against rvalue_rl_count to find out whether - /// the break instructions should be downgraded to break_void. - break_count: usize = 0, - /// Tracks `break :foo bar` instructions so they can possibly be elided later if - /// the labeled block ends up not needing a result location pointer. - labeled_breaks: ArrayListUnmanaged(Zir.Inst.Index) = .{}, - /// Tracks `store_to_block_ptr` instructions that correspond to break instructions - /// so they can possibly be elided later if the labeled block ends up not needing - /// a result location pointer. - labeled_store_to_block_ptr_list: ArrayListUnmanaged(Zir.Inst.Index) = .{}, - - suspend_node: ast.Node.Index = 0, - nosuspend_node: ast.Node.Index = 0, - - pub fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir { - return .{ - .force_comptime = gz.force_comptime, - .ref_start_index = gz.ref_start_index, - .decl_node_index = gz.decl_node_index, - .decl_line = gz.decl_line, - .parent = scope, - .astgen = gz.astgen, - .suspend_node = gz.suspend_node, - .nosuspend_node = gz.nosuspend_node, - }; - } - - pub const Label = struct { - token: ast.TokenIndex, - block_inst: Zir.Inst.Index, - used: bool = false, - }; - - pub fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool { - if (inst_ref == .unreachable_value) return true; - if (gz.refToIndex(inst_ref)) |inst_index| { - return gz.astgen.instructions.items(.tag)[inst_index].isNoReturn(); - } - return false; - } - - pub fn calcLine(gz: GenZir, node: ast.Node.Index) u32 { - const astgen = gz.astgen; - const tree = &astgen.file.tree; - const node_tags = tree.nodes.items(.tag); - const token_starts = tree.tokens.items(.start); - const decl_start = token_starts[tree.firstToken(gz.decl_node_index)]; - const node_start = token_starts[tree.firstToken(node)]; - const source = tree.source[decl_start..node_start]; - const loc = std.zig.findLineColumn(source, source.len); - return @intCast(u32, gz.decl_line + loc.line); - } - - pub fn tokSrcLoc(gz: GenZir, token_index: ast.TokenIndex) LazySrcLoc { - return .{ .token_offset = token_index - gz.srcToken() }; - } - - pub fn nodeSrcLoc(gz: GenZir, node_index: ast.Node.Index) LazySrcLoc { - return .{ .node_offset = gz.nodeIndexToRelative(node_index) }; - } - - pub fn nodeIndexToRelative(gz: GenZir, node_index: ast.Node.Index) i32 { - return @bitCast(i32, node_index) - @bitCast(i32, gz.decl_node_index); - } - - pub fn tokenIndexToRelative(gz: GenZir, token: ast.TokenIndex) u32 { - return token - gz.srcToken(); - } - - pub fn srcToken(gz: GenZir) ast.TokenIndex { - return gz.astgen.file.tree.firstToken(gz.decl_node_index); - } - - pub fn indexToRef(gz: GenZir, inst: Zir.Inst.Index) Zir.Inst.Ref { - return @intToEnum(Zir.Inst.Ref, gz.ref_start_index + inst); - } - - pub fn refToIndex(gz: GenZir, inst: Zir.Inst.Ref) ?Zir.Inst.Index { - const ref_int = @enumToInt(inst); - if (ref_int >= gz.ref_start_index) { - return ref_int - gz.ref_start_index; - } else { - return null; - } - } - - pub fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void { - // Depending on whether the result location is a pointer or value, different - // ZIR needs to be generated. In the former case we rely on storing to the - // pointer to communicate the result, and use breakvoid; in the latter case - // the block break instructions will have the result values. - // One more complication: when the result location is a pointer, we detect - // the scenario where the result location is not consumed. In this case - // we emit ZIR for the block break instructions to have the result values, - // and then rvalue() on that to pass the value to the result location. - switch (parent_rl) { - .ty => |ty_inst| { - gz.rl_ty_inst = ty_inst; - gz.break_result_loc = parent_rl; - }, - .none_or_ref => { - gz.break_result_loc = .ref; - }, - .discard, .none, .ptr, .ref => { - gz.break_result_loc = parent_rl; - }, - - .inferred_ptr => |ptr| { - gz.rl_ptr = ptr; - gz.break_result_loc = .{ .block_ptr = gz }; - }, - - .block_ptr => |parent_block_scope| { - gz.rl_ty_inst = parent_block_scope.rl_ty_inst; - gz.rl_ptr = parent_block_scope.rl_ptr; - gz.break_result_loc = .{ .block_ptr = gz }; - }, - } - } - - pub fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void { - const gpa = gz.astgen.gpa; - try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + - @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); - const zir_datas = gz.astgen.instructions.items(.data); - zir_datas[inst].bool_br.payload_index = gz.astgen.addExtraAssumeCapacity( - Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) }, - ); - gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items); - } - - pub fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void { - const gpa = gz.astgen.gpa; - try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + - @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); - const zir_datas = gz.astgen.instructions.items(.data); - zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity( - Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) }, - ); - gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items); - } - - /// Same as `setBlockBody` except we don't copy instructions which are - /// `store_to_block_ptr` instructions with lhs set to .none. - pub fn setBlockBodyEliding(gz: GenZir, inst: Zir.Inst.Index) !void { - const gpa = gz.astgen.gpa; - try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + - @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); - const zir_datas = gz.astgen.instructions.items(.data); - const zir_tags = gz.astgen.instructions.items(.tag); - const block_pl_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Block{ - .body_len = @intCast(u32, gz.instructions.items.len), - }); - zir_datas[inst].pl_node.payload_index = block_pl_index; - for (gz.instructions.items) |sub_inst| { - if (zir_tags[sub_inst] == .store_to_block_ptr and - zir_datas[sub_inst].bin.lhs == .none) - { - // Decrement `body_len`. - gz.astgen.extra.items[block_pl_index] -= 1; - continue; - } - gz.astgen.extra.appendAssumeCapacity(sub_inst); - } - } - - pub fn addFunc(gz: *GenZir, args: struct { - src_node: ast.Node.Index, - param_types: []const Zir.Inst.Ref, - body: []const Zir.Inst.Index, - ret_ty: Zir.Inst.Ref, - cc: Zir.Inst.Ref, - align_inst: Zir.Inst.Ref, - lib_name: u32, - is_var_args: bool, - is_inferred_error: bool, - is_test: bool, - }) !Zir.Inst.Ref { - assert(args.src_node != 0); - assert(args.ret_ty != .none); - const astgen = gz.astgen; - const gpa = astgen.gpa; - - try gz.instructions.ensureUnusedCapacity(gpa, 1); - try astgen.instructions.ensureUnusedCapacity(gpa, 1); - - var src_locs_buffer: [3]u32 = undefined; - var src_locs: []u32 = src_locs_buffer[0..0]; - if (args.body.len != 0) { - const tree = &astgen.file.tree; - const node_tags = tree.nodes.items(.tag); - const node_datas = tree.nodes.items(.data); - const token_starts = tree.tokens.items(.start); - const decl_start = token_starts[tree.firstToken(gz.decl_node_index)]; - const fn_decl = args.src_node; - assert(node_tags[fn_decl] == .fn_decl or node_tags[fn_decl] == .test_decl); - const block = node_datas[fn_decl].rhs; - const lbrace_start = token_starts[tree.firstToken(block)]; - const rbrace_start = token_starts[tree.lastToken(block)]; - const lbrace_source = tree.source[decl_start..lbrace_start]; - const lbrace_loc = std.zig.findLineColumn(lbrace_source, lbrace_source.len); - const rbrace_source = tree.source[lbrace_start..rbrace_start]; - const rbrace_loc = std.zig.findLineColumn(rbrace_source, rbrace_source.len); - const lbrace_line = @intCast(u32, lbrace_loc.line); - const rbrace_line = lbrace_line + @intCast(u32, rbrace_loc.line); - const columns = @intCast(u32, lbrace_loc.column) | - (@intCast(u32, rbrace_loc.column) << 16); - src_locs_buffer[0] = lbrace_line; - src_locs_buffer[1] = rbrace_line; - src_locs_buffer[2] = columns; - src_locs = &src_locs_buffer; - } - - if (args.cc != .none or args.lib_name != 0 or - args.is_var_args or args.is_test or args.align_inst != .none) - { - try astgen.extra.ensureUnusedCapacity( - gpa, - @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len + - args.param_types.len + args.body.len + src_locs.len + - @boolToInt(args.lib_name != 0) + - @boolToInt(args.align_inst != .none) + - @boolToInt(args.cc != .none), - ); - const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{ - .src_node = gz.nodeIndexToRelative(args.src_node), - .return_type = args.ret_ty, - .param_types_len = @intCast(u32, args.param_types.len), - .body_len = @intCast(u32, args.body.len), - }); - if (args.lib_name != 0) { - astgen.extra.appendAssumeCapacity(args.lib_name); - } - if (args.cc != .none) { - astgen.extra.appendAssumeCapacity(@enumToInt(args.cc)); - } - if (args.align_inst != .none) { - astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); - } - astgen.appendRefsAssumeCapacity(args.param_types); - astgen.extra.appendSliceAssumeCapacity(args.body); - astgen.extra.appendSliceAssumeCapacity(src_locs); - - const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); - astgen.instructions.appendAssumeCapacity(.{ - .tag = .extended, - .data = .{ .extended = .{ - .opcode = .func, - .small = @bitCast(u16, Zir.Inst.ExtendedFunc.Small{ - .is_var_args = args.is_var_args, - .is_inferred_error = args.is_inferred_error, - .has_lib_name = args.lib_name != 0, - .has_cc = args.cc != .none, - .has_align = args.align_inst != .none, - .is_test = args.is_test, - }), - .operand = payload_index, - } }, - }); - gz.instructions.appendAssumeCapacity(new_index); - return gz.indexToRef(new_index); - } else { - try gz.astgen.extra.ensureUnusedCapacity( - gpa, - @typeInfo(Zir.Inst.Func).Struct.fields.len + - args.param_types.len + args.body.len + src_locs.len, - ); - - const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Func{ - .return_type = args.ret_ty, - .param_types_len = @intCast(u32, args.param_types.len), - .body_len = @intCast(u32, args.body.len), - }); - gz.astgen.appendRefsAssumeCapacity(args.param_types); - gz.astgen.extra.appendSliceAssumeCapacity(args.body); - gz.astgen.extra.appendSliceAssumeCapacity(src_locs); - - const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func; - const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); - gz.astgen.instructions.appendAssumeCapacity(.{ - .tag = tag, - .data = .{ .pl_node = .{ - .src_node = gz.nodeIndexToRelative(args.src_node), - .payload_index = payload_index, - } }, - }); - gz.instructions.appendAssumeCapacity(new_index); - return gz.indexToRef(new_index); - } - } - - pub fn addVar(gz: *GenZir, args: struct { - align_inst: Zir.Inst.Ref, - lib_name: u32, - var_type: Zir.Inst.Ref, - init: Zir.Inst.Ref, - is_extern: bool, - }) !Zir.Inst.Ref { - const astgen = gz.astgen; - const gpa = astgen.gpa; - - try gz.instructions.ensureUnusedCapacity(gpa, 1); - try astgen.instructions.ensureUnusedCapacity(gpa, 1); - - try astgen.extra.ensureUnusedCapacity( - gpa, - @typeInfo(Zir.Inst.ExtendedVar).Struct.fields.len + - @boolToInt(args.lib_name != 0) + - @boolToInt(args.align_inst != .none) + - @boolToInt(args.init != .none), - ); - const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedVar{ - .var_type = args.var_type, - }); - if (args.lib_name != 0) { - astgen.extra.appendAssumeCapacity(args.lib_name); - } - if (args.align_inst != .none) { - astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); - } - if (args.init != .none) { - astgen.extra.appendAssumeCapacity(@enumToInt(args.init)); - } - - const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); - astgen.instructions.appendAssumeCapacity(.{ - .tag = .extended, - .data = .{ .extended = .{ - .opcode = .variable, - .small = @bitCast(u16, Zir.Inst.ExtendedVar.Small{ - .has_lib_name = args.lib_name != 0, - .has_align = args.align_inst != .none, - .has_init = args.init != .none, - .is_extern = args.is_extern, - }), - .operand = payload_index, - } }, - }); - gz.instructions.appendAssumeCapacity(new_index); - return gz.indexToRef(new_index); - } - - pub fn addCall( - gz: *GenZir, - tag: Zir.Inst.Tag, - callee: Zir.Inst.Ref, - args: []const Zir.Inst.Ref, - /// Absolute node index. This function does the conversion to offset from Decl. - src_node: ast.Node.Index, - ) !Zir.Inst.Ref { - assert(callee != .none); - assert(src_node != 0); - const gpa = gz.astgen.gpa; - try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); - try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); - try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + - @typeInfo(Zir.Inst.Call).Struct.fields.len + args.len); - - const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Call{ - .callee = callee, - .args_len = @intCast(u32, args.len), - }); - gz.astgen.appendRefsAssumeCapacity(args); - - const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); - gz.astgen.instructions.appendAssumeCapacity(.{ - .tag = tag, - .data = .{ .pl_node = .{ - .src_node = gz.nodeIndexToRelative(src_node), - .payload_index = payload_index, - } }, - }); - gz.instructions.appendAssumeCapacity(new_index); - return gz.indexToRef(new_index); - } - - /// Note that this returns a `Zir.Inst.Index` not a ref. - /// Leaves the `payload_index` field undefined. - pub fn addBoolBr( - gz: *GenZir, - tag: Zir.Inst.Tag, - lhs: Zir.Inst.Ref, - ) !Zir.Inst.Index { - assert(lhs != .none); - const gpa = gz.astgen.gpa; - try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); - try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); - - const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); - gz.astgen.instructions.appendAssumeCapacity(.{ - .tag = tag, - .data = .{ .bool_br = .{ - .lhs = lhs, - .payload_index = undefined, - } }, - }); - gz.instructions.appendAssumeCapacity(new_index); - return new_index; - } - - pub fn addInt(gz: *GenZir, integer: u64) !Zir.Inst.Ref { - return gz.add(.{ - .tag = .int, - .data = .{ .int = integer }, - }); - } - - pub fn addIntBig(gz: *GenZir, limbs: []const std.math.big.Limb) !Zir.Inst.Ref { - const astgen = gz.astgen; - const gpa = astgen.gpa; - try gz.instructions.ensureUnusedCapacity(gpa, 1); - try astgen.instructions.ensureUnusedCapacity(gpa, 1); - try astgen.string_bytes.ensureUnusedCapacity(gpa, @sizeOf(std.math.big.Limb) * limbs.len); - - const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); - astgen.instructions.appendAssumeCapacity(.{ - .tag = .int_big, - .data = .{ .str = .{ - .start = @intCast(u32, astgen.string_bytes.items.len), - .len = @intCast(u32, limbs.len), - } }, - }); - gz.instructions.appendAssumeCapacity(new_index); - astgen.string_bytes.appendSliceAssumeCapacity(mem.sliceAsBytes(limbs)); - return gz.indexToRef(new_index); - } - - pub fn addFloat(gz: *GenZir, number: f32, src_node: ast.Node.Index) !Zir.Inst.Ref { - return gz.add(.{ - .tag = .float, - .data = .{ .float = .{ - .src_node = gz.nodeIndexToRelative(src_node), - .number = number, - } }, - }); - } - - pub fn addUnNode( - gz: *GenZir, - tag: Zir.Inst.Tag, - operand: Zir.Inst.Ref, - /// Absolute node index. This function does the conversion to offset from Decl. - src_node: ast.Node.Index, - ) !Zir.Inst.Ref { - assert(operand != .none); - return gz.add(.{ - .tag = tag, - .data = .{ .un_node = .{ - .operand = operand, - .src_node = gz.nodeIndexToRelative(src_node), - } }, - }); - } - - pub fn addPlNode( - gz: *GenZir, - tag: Zir.Inst.Tag, - /// Absolute node index. This function does the conversion to offset from Decl. - src_node: ast.Node.Index, - extra: anytype, - ) !Zir.Inst.Ref { - const gpa = gz.astgen.gpa; - try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); - try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); - - const payload_index = try gz.astgen.addExtra(extra); - const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); - gz.astgen.instructions.appendAssumeCapacity(.{ - .tag = tag, - .data = .{ .pl_node = .{ - .src_node = gz.nodeIndexToRelative(src_node), - .payload_index = payload_index, - } }, - }); - gz.instructions.appendAssumeCapacity(new_index); - return gz.indexToRef(new_index); - } - - pub fn addExtendedPayload( - gz: *GenZir, - opcode: Zir.Inst.Extended, - extra: anytype, - ) !Zir.Inst.Ref { - const gpa = gz.astgen.gpa; - - try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); - try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); - - const payload_index = try gz.astgen.addExtra(extra); - const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); - gz.astgen.instructions.appendAssumeCapacity(.{ - .tag = .extended, - .data = .{ .extended = .{ - .opcode = opcode, - .small = undefined, - .operand = payload_index, - } }, - }); - gz.instructions.appendAssumeCapacity(new_index); - return gz.indexToRef(new_index); - } - - pub fn addExtendedMultiOp( - gz: *GenZir, - opcode: Zir.Inst.Extended, - node: ast.Node.Index, - operands: []const Zir.Inst.Ref, - ) !Zir.Inst.Ref { - const astgen = gz.astgen; - const gpa = astgen.gpa; - - try gz.instructions.ensureUnusedCapacity(gpa, 1); - try astgen.instructions.ensureUnusedCapacity(gpa, 1); - try astgen.extra.ensureUnusedCapacity( - gpa, - @typeInfo(Zir.Inst.NodeMultiOp).Struct.fields.len + operands.len, - ); - - const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.NodeMultiOp{ - .src_node = gz.nodeIndexToRelative(node), - }); - const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); - astgen.instructions.appendAssumeCapacity(.{ - .tag = .extended, - .data = .{ .extended = .{ - .opcode = opcode, - .small = @intCast(u16, operands.len), - .operand = payload_index, - } }, - }); - gz.instructions.appendAssumeCapacity(new_index); - astgen.appendRefsAssumeCapacity(operands); - return gz.indexToRef(new_index); - } - - pub fn addArrayTypeSentinel( - gz: *GenZir, - len: Zir.Inst.Ref, - sentinel: Zir.Inst.Ref, - elem_type: Zir.Inst.Ref, - ) !Zir.Inst.Ref { - const gpa = gz.astgen.gpa; - try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); - try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); - - const payload_index = try gz.astgen.addExtra(Zir.Inst.ArrayTypeSentinel{ - .sentinel = sentinel, - .elem_type = elem_type, - }); - const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); - gz.astgen.instructions.appendAssumeCapacity(.{ - .tag = .array_type_sentinel, - .data = .{ .array_type_sentinel = .{ - .len = len, - .payload_index = payload_index, - } }, - }); - gz.instructions.appendAssumeCapacity(new_index); - return gz.indexToRef(new_index); - } - - pub fn addUnTok( - gz: *GenZir, - tag: Zir.Inst.Tag, - operand: Zir.Inst.Ref, - /// Absolute token index. This function does the conversion to Decl offset. - abs_tok_index: ast.TokenIndex, - ) !Zir.Inst.Ref { - assert(operand != .none); - return gz.add(.{ - .tag = tag, - .data = .{ .un_tok = .{ - .operand = operand, - .src_tok = gz.tokenIndexToRelative(abs_tok_index), - } }, - }); - } - - pub fn addStrTok( - gz: *GenZir, - tag: Zir.Inst.Tag, - str_index: u32, - /// Absolute token index. This function does the conversion to Decl offset. - abs_tok_index: ast.TokenIndex, - ) !Zir.Inst.Ref { - return gz.add(.{ - .tag = tag, - .data = .{ .str_tok = .{ - .start = str_index, - .src_tok = gz.tokenIndexToRelative(abs_tok_index), - } }, - }); - } - - pub fn addBreak( - gz: *GenZir, - tag: Zir.Inst.Tag, - break_block: Zir.Inst.Index, - operand: Zir.Inst.Ref, - ) !Zir.Inst.Index { - return gz.addAsIndex(.{ - .tag = tag, - .data = .{ .@"break" = .{ - .block_inst = break_block, - .operand = operand, - } }, - }); - } - - pub fn addBin( - gz: *GenZir, - tag: Zir.Inst.Tag, - lhs: Zir.Inst.Ref, - rhs: Zir.Inst.Ref, - ) !Zir.Inst.Ref { - assert(lhs != .none); - assert(rhs != .none); - return gz.add(.{ - .tag = tag, - .data = .{ .bin = .{ - .lhs = lhs, - .rhs = rhs, - } }, - }); - } - - pub fn addDecl( - gz: *GenZir, - tag: Zir.Inst.Tag, - decl_index: u32, - src_node: ast.Node.Index, - ) !Zir.Inst.Ref { - return gz.add(.{ - .tag = tag, - .data = .{ .pl_node = .{ - .src_node = gz.nodeIndexToRelative(src_node), - .payload_index = decl_index, - } }, - }); - } - - pub fn addNode( - gz: *GenZir, - tag: Zir.Inst.Tag, - /// Absolute node index. This function does the conversion to offset from Decl. - src_node: ast.Node.Index, - ) !Zir.Inst.Ref { - return gz.add(.{ - .tag = tag, - .data = .{ .node = gz.nodeIndexToRelative(src_node) }, - }); - } - - pub fn addNodeExtended( - gz: *GenZir, - opcode: Zir.Inst.Extended, - /// Absolute node index. This function does the conversion to offset from Decl. - src_node: ast.Node.Index, - ) !Zir.Inst.Ref { - return gz.add(.{ - .tag = .extended, - .data = .{ .extended = .{ - .opcode = opcode, - .small = undefined, - .operand = @bitCast(u32, gz.nodeIndexToRelative(src_node)), - } }, - }); - } - - pub fn addAllocExtended( - gz: *GenZir, - args: struct { - /// Absolute node index. This function does the conversion to offset from Decl. - node: ast.Node.Index, - type_inst: Zir.Inst.Ref, - align_inst: Zir.Inst.Ref, - is_const: bool, - is_comptime: bool, - }, - ) !Zir.Inst.Ref { - const astgen = gz.astgen; - const gpa = astgen.gpa; - - try gz.instructions.ensureUnusedCapacity(gpa, 1); - try astgen.instructions.ensureUnusedCapacity(gpa, 1); - try astgen.extra.ensureUnusedCapacity( - gpa, - @typeInfo(Zir.Inst.AllocExtended).Struct.fields.len + - @as(usize, @boolToInt(args.type_inst != .none)) + - @as(usize, @boolToInt(args.align_inst != .none)), - ); - const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.AllocExtended{ - .src_node = gz.nodeIndexToRelative(args.node), - }); - if (args.type_inst != .none) { - astgen.extra.appendAssumeCapacity(@enumToInt(args.type_inst)); - } - if (args.align_inst != .none) { - astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); - } - - const has_type: u4 = @boolToInt(args.type_inst != .none); - const has_align: u4 = @boolToInt(args.align_inst != .none); - const is_const: u4 = @boolToInt(args.is_const); - const is_comptime: u4 = @boolToInt(args.is_comptime); - const small: u16 = has_type | (has_align << 1) | (is_const << 2) | (is_comptime << 3); - - const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); - astgen.instructions.appendAssumeCapacity(.{ - .tag = .extended, - .data = .{ .extended = .{ - .opcode = .alloc, - .small = small, - .operand = payload_index, - } }, - }); - gz.instructions.appendAssumeCapacity(new_index); - return gz.indexToRef(new_index); - } - - pub fn addAsm( - gz: *GenZir, - args: struct { - /// Absolute node index. This function does the conversion to offset from Decl. - node: ast.Node.Index, - asm_source: Zir.Inst.Ref, - output_type_bits: u32, - is_volatile: bool, - outputs: []const Zir.Inst.Asm.Output, - inputs: []const Zir.Inst.Asm.Input, - clobbers: []const u32, - }, - ) !Zir.Inst.Ref { - const astgen = gz.astgen; - const gpa = astgen.gpa; - - try gz.instructions.ensureUnusedCapacity(gpa, 1); - try astgen.instructions.ensureUnusedCapacity(gpa, 1); - try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Asm).Struct.fields.len + - args.outputs.len * @typeInfo(Zir.Inst.Asm.Output).Struct.fields.len + - args.inputs.len * @typeInfo(Zir.Inst.Asm.Input).Struct.fields.len + - args.clobbers.len); - - const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Asm{ - .src_node = gz.nodeIndexToRelative(args.node), - .asm_source = args.asm_source, - .output_type_bits = args.output_type_bits, - }); - for (args.outputs) |output| { - _ = gz.astgen.addExtraAssumeCapacity(output); - } - for (args.inputs) |input| { - _ = gz.astgen.addExtraAssumeCapacity(input); - } - gz.astgen.extra.appendSliceAssumeCapacity(args.clobbers); - - // * 0b00000000_000XXXXX - `outputs_len`. - // * 0b000000XX_XXX00000 - `inputs_len`. - // * 0b0XXXXX00_00000000 - `clobbers_len`. - // * 0bX0000000_00000000 - is volatile - const small: u16 = @intCast(u16, args.outputs.len) | - @intCast(u16, args.inputs.len << 5) | - @intCast(u16, args.clobbers.len << 10) | - (@as(u16, @boolToInt(args.is_volatile)) << 15); - - const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); - astgen.instructions.appendAssumeCapacity(.{ - .tag = .extended, - .data = .{ .extended = .{ - .opcode = .@"asm", - .small = small, - .operand = payload_index, - } }, - }); - gz.instructions.appendAssumeCapacity(new_index); - return gz.indexToRef(new_index); - } - - /// Note that this returns a `Zir.Inst.Index` not a ref. - /// Does *not* append the block instruction to the scope. - /// Leaves the `payload_index` field undefined. - pub fn addBlock(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index { - const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); - const gpa = gz.astgen.gpa; - try gz.astgen.instructions.append(gpa, .{ - .tag = tag, - .data = .{ .pl_node = .{ - .src_node = gz.nodeIndexToRelative(node), - .payload_index = undefined, - } }, - }); - return new_index; - } - - /// Note that this returns a `Zir.Inst.Index` not a ref. - /// Leaves the `payload_index` field undefined. - pub fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index { - const gpa = gz.astgen.gpa; - try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); - const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); - try gz.astgen.instructions.append(gpa, .{ - .tag = tag, - .data = .{ .pl_node = .{ - .src_node = gz.nodeIndexToRelative(node), - .payload_index = undefined, - } }, - }); - gz.instructions.appendAssumeCapacity(new_index); - return new_index; - } - - pub fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref { - return gz.indexToRef(try gz.addAsIndex(inst)); - } - - pub fn addAsIndex(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Index { - const gpa = gz.astgen.gpa; - try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); - try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); - - const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); - gz.astgen.instructions.appendAssumeCapacity(inst); - gz.instructions.appendAssumeCapacity(new_index); - return new_index; - } - }; - - /// This is always a `const` local and importantly the `inst` is a value type, not a pointer. - /// This structure lives as long as the AST generation of the Block - /// node that contains the variable. - pub const LocalVal = struct { - pub const base_tag: Tag = .local_val; - base: Scope = Scope{ .tag = base_tag }, - /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`. - parent: *Scope, - gen_zir: *GenZir, - inst: Zir.Inst.Ref, - /// Source location of the corresponding variable declaration. - token_src: ast.TokenIndex, - /// String table index. - name: u32, - }; - - /// This could be a `const` or `var` local. It has a pointer instead of a value. - /// This structure lives as long as the AST generation of the Block - /// node that contains the variable. - pub const LocalPtr = struct { - pub const base_tag: Tag = .local_ptr; - base: Scope = Scope{ .tag = base_tag }, - /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`. - parent: *Scope, - gen_zir: *GenZir, - ptr: Zir.Inst.Ref, - /// Source location of the corresponding variable declaration. - token_src: ast.TokenIndex, - /// String table index. - name: u32, - }; - - pub const Defer = struct { - base: Scope, - /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`. - parent: *Scope, - defer_node: ast.Node.Index, - }; - pub const DeclRef = struct { pub const base_tag: Tag = .decl_ref; base: Scope = Scope{ .tag = base_tag }, @@ -3142,7 +2205,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node } file.tree_loaded = true; - file.zir = try AstGen.generate(gpa, file); + file.zir = try AstGen.generate(gpa, file.tree); file.zir_loaded = true; file.status = .success_zir; log.debug("AstGen fresh success: {s}", .{file.sub_file_path}); @@ -4536,7 +3599,6 @@ pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) In } mod.failed_decls.putAssumeCapacityNoClobber(block.sema.owner_decl, err_msg); }, - .gen_zir, .local_val, .local_ptr, .defer_normal, .defer_error => unreachable, .file => unreachable, .namespace => unreachable, .decl_ref => { @@ -4894,3 +3956,95 @@ fn lockAndClearFileCompileError(mod: *Module, file: *Scope.File) void { }, } } + +pub const SwitchProngSrc = union(enum) { + scalar: u32, + multi: Multi, + range: Multi, + + pub const Multi = struct { + prong: u32, + item: u32, + }; + + pub const RangeExpand = enum { none, first, last }; + + /// This function is intended to be called only when it is certain that we need + /// the LazySrcLoc in order to emit a compile error. + pub fn resolve( + prong_src: SwitchProngSrc, + decl: *Decl, + switch_node_offset: i32, + range_expand: RangeExpand, + ) LazySrcLoc { + @setCold(true); + const switch_node = decl.relativeToNodeIndex(switch_node_offset); + const tree = decl.namespace.file_scope.tree; + const main_tokens = tree.nodes.items(.main_token); + const node_datas = tree.nodes.items(.data); + const node_tags = tree.nodes.items(.tag); + const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange); + const case_nodes = tree.extra_data[extra.start..extra.end]; + + var multi_i: u32 = 0; + var scalar_i: u32 = 0; + for (case_nodes) |case_node| { + const case = switch (node_tags[case_node]) { + .switch_case_one => tree.switchCaseOne(case_node), + .switch_case => tree.switchCase(case_node), + else => unreachable, + }; + if (case.ast.values.len == 0) + continue; + if (case.ast.values.len == 1 and + node_tags[case.ast.values[0]] == .identifier and + mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")) + { + continue; + } + const is_multi = case.ast.values.len != 1 or + node_tags[case.ast.values[0]] == .switch_range; + + switch (prong_src) { + .scalar => |i| if (!is_multi and i == scalar_i) return LazySrcLoc{ + .node_offset = decl.nodeIndexToRelative(case.ast.values[0]), + }, + .multi => |s| if (is_multi and s.prong == multi_i) { + var item_i: u32 = 0; + for (case.ast.values) |item_node| { + if (node_tags[item_node] == .switch_range) continue; + + if (item_i == s.item) return LazySrcLoc{ + .node_offset = decl.nodeIndexToRelative(item_node), + }; + item_i += 1; + } else unreachable; + }, + .range => |s| if (is_multi and s.prong == multi_i) { + var range_i: u32 = 0; + for (case.ast.values) |range| { + if (node_tags[range] != .switch_range) continue; + + if (range_i == s.item) switch (range_expand) { + .none => return LazySrcLoc{ + .node_offset = decl.nodeIndexToRelative(range), + }, + .first => return LazySrcLoc{ + .node_offset = decl.nodeIndexToRelative(node_datas[range].lhs), + }, + .last => return LazySrcLoc{ + .node_offset = decl.nodeIndexToRelative(node_datas[range].rhs), + }, + }; + range_i += 1; + } else unreachable; + }, + } + if (is_multi) { + multi_i += 1; + } else { + scalar_i += 1; + } + } else unreachable; + } +}; diff --git a/src/RangeSet.zig b/src/RangeSet.zig index bd511a5921..fd258d55b0 100644 --- a/src/RangeSet.zig +++ b/src/RangeSet.zig @@ -2,7 +2,7 @@ const std = @import("std"); const Order = std.math.Order; const Value = @import("value.zig").Value; const RangeSet = @This(); -const SwitchProngSrc = @import("AstGen.zig").SwitchProngSrc; +const SwitchProngSrc = @import("Module.zig").SwitchProngSrc; ranges: std.ArrayList(Range), diff --git a/src/Sema.zig b/src/Sema.zig index a79a8eaacb..0bc739f352 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -63,7 +63,6 @@ const InnerError = Module.InnerError; const Decl = Module.Decl; const LazySrcLoc = Module.LazySrcLoc; const RangeSet = @import("RangeSet.zig"); -const AstGen = @import("AstGen.zig"); pub fn analyzeFnBody( sema: *Sema, @@ -3361,10 +3360,10 @@ fn analyzeSwitch( // Validate for duplicate items, missing else prong, and invalid range. switch (operand.ty.zigTypeTag()) { .Enum => { - var seen_fields = try gpa.alloc(?AstGen.SwitchProngSrc, operand.ty.enumFieldCount()); + var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand.ty.enumFieldCount()); defer gpa.free(seen_fields); - mem.set(?AstGen.SwitchProngSrc, seen_fields, null); + mem.set(?Module.SwitchProngSrc, seen_fields, null); var extra_index: usize = special.end; { @@ -3989,8 +3988,8 @@ fn resolveSwitchItemVal( block: *Scope.Block, item_ref: Zir.Inst.Ref, switch_node_offset: i32, - switch_prong_src: AstGen.SwitchProngSrc, - range_expand: AstGen.SwitchProngSrc.RangeExpand, + switch_prong_src: Module.SwitchProngSrc, + range_expand: Module.SwitchProngSrc.RangeExpand, ) InnerError!TypedValue { const item = try sema.resolveInst(item_ref); // We have to avoid the other helper functions here because we cannot construct a LazySrcLoc @@ -4014,7 +4013,7 @@ fn validateSwitchRange( first_ref: Zir.Inst.Ref, last_ref: Zir.Inst.Ref, src_node_offset: i32, - switch_prong_src: AstGen.SwitchProngSrc, + switch_prong_src: Module.SwitchProngSrc, ) InnerError!void { const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val; const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val; @@ -4028,7 +4027,7 @@ fn validateSwitchItem( range_set: *RangeSet, item_ref: Zir.Inst.Ref, src_node_offset: i32, - switch_prong_src: AstGen.SwitchProngSrc, + switch_prong_src: Module.SwitchProngSrc, ) InnerError!void { const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src); @@ -4038,10 +4037,10 @@ fn validateSwitchItem( fn validateSwitchItemEnum( sema: *Sema, block: *Scope.Block, - seen_fields: []?AstGen.SwitchProngSrc, + seen_fields: []?Module.SwitchProngSrc, item_ref: Zir.Inst.Ref, src_node_offset: i32, - switch_prong_src: AstGen.SwitchProngSrc, + switch_prong_src: Module.SwitchProngSrc, ) InnerError!void { const mod = sema.mod; const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); @@ -4073,8 +4072,8 @@ fn validateSwitchItemEnum( fn validateSwitchDupe( sema: *Sema, block: *Scope.Block, - maybe_prev_src: ?AstGen.SwitchProngSrc, - switch_prong_src: AstGen.SwitchProngSrc, + maybe_prev_src: ?Module.SwitchProngSrc, + switch_prong_src: Module.SwitchProngSrc, src_node_offset: i32, ) InnerError!void { const prev_prong_src = maybe_prev_src orelse return; @@ -4108,7 +4107,7 @@ fn validateSwitchItemBool( false_count: *u8, item_ref: Zir.Inst.Ref, src_node_offset: i32, - switch_prong_src: AstGen.SwitchProngSrc, + switch_prong_src: Module.SwitchProngSrc, ) InnerError!void { const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; if (item_val.toBool()) { @@ -4122,7 +4121,7 @@ fn validateSwitchItemBool( } } -const ValueSrcMap = std.HashMap(Value, AstGen.SwitchProngSrc, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage); +const ValueSrcMap = std.HashMap(Value, Module.SwitchProngSrc, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage); fn validateSwitchItemSparse( sema: *Sema, @@ -4130,7 +4129,7 @@ fn validateSwitchItemSparse( seen_values: *ValueSrcMap, item_ref: Zir.Inst.Ref, src_node_offset: i32, - switch_prong_src: AstGen.SwitchProngSrc, + switch_prong_src: Module.SwitchProngSrc, ) InnerError!void { const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; const entry = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return; diff --git a/src/main.zig b/src/main.zig index 7094e693d4..d41adc29cb 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3562,7 +3562,7 @@ pub fn cmdAstgen( process.exit(1); } - file.zir = try AstGen.generate(gpa, &file); + file.zir = try AstGen.generate(gpa, file.tree); file.zir_loaded = true; defer file.zir.deinit(gpa);