zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob b962f58b (402120B) - Raw


      1 //! Ingests an AST and produces ZIR code.
      2 const AstGen = @This();
      3 
      4 const std = @import("std");
      5 const ast = std.zig.ast;
      6 const mem = std.mem;
      7 const Allocator = std.mem.Allocator;
      8 const assert = std.debug.assert;
      9 const ArrayListUnmanaged = std.ArrayListUnmanaged;
     10 
     11 const Zir = @import("Zir.zig");
     12 const trace = @import("tracy.zig").trace;
     13 const BuiltinFn = @import("BuiltinFn.zig");
     14 
     15 gpa: *Allocator,
     16 tree: *const ast.Tree,
     17 instructions: std.MultiArrayList(Zir.Inst) = .{},
     18 extra: ArrayListUnmanaged(u32) = .{},
     19 string_bytes: ArrayListUnmanaged(u8) = .{},
     20 /// Tracks the current byte offset within the source file.
     21 /// Used to populate line deltas in the ZIR. AstGen maintains
     22 /// this "cursor" throughout the entire AST lowering process in order
     23 /// to avoid starting over the line/column scan for every declaration, which
     24 /// would be O(N^2).
     25 source_offset: u32 = 0,
     26 /// Tracks the current line of `source_offset`.
     27 source_line: u32 = 0,
     28 /// Tracks the current column of `source_offset`.
     29 source_column: u32 = 0,
     30 /// Used for temporary allocations; freed after AstGen is complete.
     31 /// The resulting ZIR code has no references to anything in this arena.
     32 arena: *Allocator,
     33 string_table: std.StringHashMapUnmanaged(u32) = .{},
     34 compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{},
     35 /// The topmost block of the current function.
     36 fn_block: ?*GenZir = null,
     37 /// Maps string table indexes to the first `@import` ZIR instruction
     38 /// that uses this string as the operand.
     39 imports: std.AutoArrayHashMapUnmanaged(u32, ast.TokenIndex) = .{},
     40 
     41 const InnerError = error{ OutOfMemory, AnalysisFail };
     42 
     43 fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 {
     44     const fields = std.meta.fields(@TypeOf(extra));
     45     try astgen.extra.ensureUnusedCapacity(astgen.gpa, fields.len);
     46     return addExtraAssumeCapacity(astgen, extra);
     47 }
     48 
     49 fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 {
     50     const fields = std.meta.fields(@TypeOf(extra));
     51     const result = @intCast(u32, astgen.extra.items.len);
     52     inline for (fields) |field| {
     53         astgen.extra.appendAssumeCapacity(switch (field.field_type) {
     54             u32 => @field(extra, field.name),
     55             Zir.Inst.Ref => @enumToInt(@field(extra, field.name)),
     56             i32 => @bitCast(u32, @field(extra, field.name)),
     57             else => @compileError("bad field type"),
     58         });
     59     }
     60     return result;
     61 }
     62 
     63 fn appendRefs(astgen: *AstGen, refs: []const Zir.Inst.Ref) !void {
     64     const coerced = @bitCast([]const u32, refs);
     65     return astgen.extra.appendSlice(astgen.gpa, coerced);
     66 }
     67 
     68 fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) void {
     69     const coerced = @bitCast([]const u32, refs);
     70     astgen.extra.appendSliceAssumeCapacity(coerced);
     71 }
     72 
     73 pub fn generate(gpa: *Allocator, tree: ast.Tree) Allocator.Error!Zir {
     74     var arena = std.heap.ArenaAllocator.init(gpa);
     75     defer arena.deinit();
     76 
     77     var astgen: AstGen = .{
     78         .gpa = gpa,
     79         .arena = &arena.allocator,
     80         .tree = &tree,
     81     };
     82     defer astgen.deinit(gpa);
     83 
     84     // String table indexes 0 and 1 are reserved for special meaning.
     85     try astgen.string_bytes.appendSlice(gpa, &[_]u8{ 0, 0 });
     86 
     87     // We expect at least as many ZIR instructions and extra data items
     88     // as AST nodes.
     89     try astgen.instructions.ensureTotalCapacity(gpa, tree.nodes.len);
     90 
     91     // First few indexes of extra are reserved and set at the end.
     92     const reserved_count = @typeInfo(Zir.ExtraIndex).Enum.fields.len;
     93     try astgen.extra.ensureTotalCapacity(gpa, tree.nodes.len + reserved_count);
     94     astgen.extra.items.len += reserved_count;
     95 
     96     var top_scope: Scope.Top = .{};
     97 
     98     var gen_scope: GenZir = .{
     99         .force_comptime = true,
    100         .in_defer = false,
    101         .parent = &top_scope.base,
    102         .anon_name_strategy = .parent,
    103         .decl_node_index = 0,
    104         .decl_line = 0,
    105         .astgen = &astgen,
    106     };
    107     defer gen_scope.instructions.deinit(gpa);
    108 
    109     const container_decl: ast.full.ContainerDecl = .{
    110         .layout_token = null,
    111         .ast = .{
    112             .main_token = undefined,
    113             .enum_token = null,
    114             .members = tree.rootDecls(),
    115             .arg = 0,
    116         },
    117     };
    118     if (AstGen.structDeclInner(
    119         &gen_scope,
    120         &gen_scope.base,
    121         0,
    122         container_decl,
    123         .Auto,
    124     )) |struct_decl_ref| {
    125         astgen.extra.items[@enumToInt(Zir.ExtraIndex.main_struct)] = @enumToInt(struct_decl_ref);
    126     } else |err| switch (err) {
    127         error.OutOfMemory => return error.OutOfMemory,
    128         error.AnalysisFail => {}, // Handled via compile_errors below.
    129     }
    130 
    131     const err_index = @enumToInt(Zir.ExtraIndex.compile_errors);
    132     if (astgen.compile_errors.items.len == 0) {
    133         astgen.extra.items[err_index] = 0;
    134     } else {
    135         try astgen.extra.ensureUnusedCapacity(gpa, 1 + astgen.compile_errors.items.len *
    136             @typeInfo(Zir.Inst.CompileErrors.Item).Struct.fields.len);
    137 
    138         astgen.extra.items[err_index] = astgen.addExtraAssumeCapacity(Zir.Inst.CompileErrors{
    139             .items_len = @intCast(u32, astgen.compile_errors.items.len),
    140         });
    141 
    142         for (astgen.compile_errors.items) |item| {
    143             _ = astgen.addExtraAssumeCapacity(item);
    144         }
    145     }
    146 
    147     const imports_index = @enumToInt(Zir.ExtraIndex.imports);
    148     if (astgen.imports.count() == 0) {
    149         astgen.extra.items[imports_index] = 0;
    150     } else {
    151         try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Imports).Struct.fields.len +
    152             astgen.imports.count() * @typeInfo(Zir.Inst.Imports.Item).Struct.fields.len);
    153 
    154         astgen.extra.items[imports_index] = astgen.addExtraAssumeCapacity(Zir.Inst.Imports{
    155             .imports_len = @intCast(u32, astgen.imports.count()),
    156         });
    157 
    158         var it = astgen.imports.iterator();
    159         while (it.next()) |entry| {
    160             _ = astgen.addExtraAssumeCapacity(Zir.Inst.Imports.Item{
    161                 .name = entry.key_ptr.*,
    162                 .token = entry.value_ptr.*,
    163             });
    164         }
    165     }
    166 
    167     return Zir{
    168         .instructions = astgen.instructions.toOwnedSlice(),
    169         .string_bytes = astgen.string_bytes.toOwnedSlice(gpa),
    170         .extra = astgen.extra.toOwnedSlice(gpa),
    171     };
    172 }
    173 
    174 pub fn deinit(astgen: *AstGen, gpa: *Allocator) void {
    175     astgen.instructions.deinit(gpa);
    176     astgen.extra.deinit(gpa);
    177     astgen.string_table.deinit(gpa);
    178     astgen.string_bytes.deinit(gpa);
    179     astgen.compile_errors.deinit(gpa);
    180     astgen.imports.deinit(gpa);
    181 }
    182 
    183 pub const ResultLoc = union(enum) {
    184     /// The expression is the right-hand side of assignment to `_`. Only the side-effects of the
    185     /// expression should be generated. The result instruction from the expression must
    186     /// be ignored.
    187     discard,
    188     /// The expression has an inferred type, and it will be evaluated as an rvalue.
    189     none,
    190     /// The expression must generate a pointer rather than a value. For example, the left hand side
    191     /// of an assignment uses this kind of result location.
    192     ref,
    193     /// The callee will accept a ref, but it is not necessary, and the `ResultLoc`
    194     /// may be treated as `none` instead.
    195     none_or_ref,
    196     /// The expression will be coerced into this type, but it will be evaluated as an rvalue.
    197     ty: Zir.Inst.Ref,
    198     /// Same as `ty` but it is guaranteed that Sema will additionall perform the coercion,
    199     /// so no `as` instruction needs to be emitted.
    200     coerced_ty: Zir.Inst.Ref,
    201     /// The expression must store its result into this typed pointer. The result instruction
    202     /// from the expression must be ignored.
    203     ptr: Zir.Inst.Ref,
    204     /// The expression must store its result into this allocation, which has an inferred type.
    205     /// The result instruction from the expression must be ignored.
    206     /// Always an instruction with tag `alloc_inferred`.
    207     inferred_ptr: Zir.Inst.Ref,
    208     /// There is a pointer for the expression to store its result into, however, its type
    209     /// is inferred based on peer type resolution for a `Zir.Inst.Block`.
    210     /// The result instruction from the expression must be ignored.
    211     block_ptr: *GenZir,
    212 
    213     pub const Strategy = struct {
    214         elide_store_to_block_ptr_instructions: bool,
    215         tag: Tag,
    216 
    217         pub const Tag = enum {
    218             /// Both branches will use break_void; result location is used to communicate the
    219             /// result instruction.
    220             break_void,
    221             /// Use break statements to pass the block result value, and call rvalue() at
    222             /// the end depending on rl. Also elide the store_to_block_ptr instructions
    223             /// depending on rl.
    224             break_operand,
    225         };
    226     };
    227 
    228     fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy {
    229         switch (rl) {
    230             // In this branch there will not be any store_to_block_ptr instructions.
    231             .discard, .none, .none_or_ref, .ty, .coerced_ty, .ref => return .{
    232                 .tag = .break_operand,
    233                 .elide_store_to_block_ptr_instructions = false,
    234             },
    235             // The pointer got passed through to the sub-expressions, so we will use
    236             // break_void here.
    237             // In this branch there will not be any store_to_block_ptr instructions.
    238             .ptr => return .{
    239                 .tag = .break_void,
    240                 .elide_store_to_block_ptr_instructions = false,
    241             },
    242             .inferred_ptr, .block_ptr => {
    243                 if (block_scope.rvalue_rl_count == block_scope.break_count) {
    244                     // Neither prong of the if consumed the result location, so we can
    245                     // use break instructions to create an rvalue.
    246                     return .{
    247                         .tag = .break_operand,
    248                         .elide_store_to_block_ptr_instructions = true,
    249                     };
    250                 } else {
    251                     // Allow the store_to_block_ptr instructions to remain so that
    252                     // semantic analysis can turn them into bitcasts.
    253                     return .{
    254                         .tag = .break_void,
    255                         .elide_store_to_block_ptr_instructions = false,
    256                     };
    257                 }
    258             },
    259         }
    260     }
    261 };
    262 
    263 pub const align_rl: ResultLoc = .{ .ty = .u16_type };
    264 pub const bool_rl: ResultLoc = .{ .ty = .bool_type };
    265 pub const type_rl: ResultLoc = .{ .ty = .type_type };
    266 pub const coerced_type_rl: ResultLoc = .{ .coerced_ty = .type_type };
    267 
    268 fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref {
    269     const prev_force_comptime = gz.force_comptime;
    270     gz.force_comptime = true;
    271     defer gz.force_comptime = prev_force_comptime;
    272 
    273     return expr(gz, scope, coerced_type_rl, type_node);
    274 }
    275 
    276 /// Same as `expr` but fails with a compile error if the result type is `noreturn`.
    277 fn reachableExpr(
    278     gz: *GenZir,
    279     scope: *Scope,
    280     rl: ResultLoc,
    281     node: ast.Node.Index,
    282     src_node: ast.Node.Index,
    283 ) InnerError!Zir.Inst.Ref {
    284     const result_inst = try expr(gz, scope, rl, node);
    285     if (gz.refIsNoReturn(result_inst)) {
    286         return gz.astgen.failNodeNotes(src_node, "unreachable code", .{}, &[_]u32{
    287             try gz.astgen.errNoteNode(node, "control flow is diverted here", .{}),
    288         });
    289     }
    290     return result_inst;
    291 }
    292 
    293 fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
    294     const astgen = gz.astgen;
    295     const tree = astgen.tree;
    296     const node_tags = tree.nodes.items(.tag);
    297     const main_tokens = tree.nodes.items(.main_token);
    298     switch (node_tags[node]) {
    299         .root => unreachable,
    300         .@"usingnamespace" => unreachable,
    301         .test_decl => unreachable,
    302         .global_var_decl => unreachable,
    303         .local_var_decl => unreachable,
    304         .simple_var_decl => unreachable,
    305         .aligned_var_decl => unreachable,
    306         .switch_case => unreachable,
    307         .switch_case_one => unreachable,
    308         .container_field_init => unreachable,
    309         .container_field_align => unreachable,
    310         .container_field => unreachable,
    311         .asm_output => unreachable,
    312         .asm_input => unreachable,
    313 
    314         .assign,
    315         .assign_bit_and,
    316         .assign_bit_or,
    317         .assign_bit_shift_left,
    318         .assign_bit_shift_right,
    319         .assign_bit_xor,
    320         .assign_div,
    321         .assign_sub,
    322         .assign_sub_wrap,
    323         .assign_mod,
    324         .assign_add,
    325         .assign_add_wrap,
    326         .assign_mul,
    327         .assign_mul_wrap,
    328         .add,
    329         .add_wrap,
    330         .sub,
    331         .sub_wrap,
    332         .mul,
    333         .mul_wrap,
    334         .div,
    335         .mod,
    336         .bit_and,
    337         .bit_or,
    338         .bit_shift_left,
    339         .bit_shift_right,
    340         .bit_xor,
    341         .bang_equal,
    342         .equal_equal,
    343         .greater_than,
    344         .greater_or_equal,
    345         .less_than,
    346         .less_or_equal,
    347         .array_cat,
    348         .array_mult,
    349         .bool_and,
    350         .bool_or,
    351         .@"asm",
    352         .asm_simple,
    353         .string_literal,
    354         .integer_literal,
    355         .call,
    356         .call_comma,
    357         .async_call,
    358         .async_call_comma,
    359         .call_one,
    360         .call_one_comma,
    361         .async_call_one,
    362         .async_call_one_comma,
    363         .unreachable_literal,
    364         .@"return",
    365         .@"if",
    366         .if_simple,
    367         .@"while",
    368         .while_simple,
    369         .while_cont,
    370         .bool_not,
    371         .address_of,
    372         .float_literal,
    373         .optional_type,
    374         .block,
    375         .block_semicolon,
    376         .block_two,
    377         .block_two_semicolon,
    378         .@"break",
    379         .ptr_type_aligned,
    380         .ptr_type_sentinel,
    381         .ptr_type,
    382         .ptr_type_bit_range,
    383         .array_type,
    384         .array_type_sentinel,
    385         .enum_literal,
    386         .multiline_string_literal,
    387         .char_literal,
    388         .@"defer",
    389         .@"errdefer",
    390         .@"catch",
    391         .error_union,
    392         .merge_error_sets,
    393         .switch_range,
    394         .@"await",
    395         .bit_not,
    396         .negation,
    397         .negation_wrap,
    398         .@"resume",
    399         .@"try",
    400         .slice,
    401         .slice_open,
    402         .slice_sentinel,
    403         .array_init_one,
    404         .array_init_one_comma,
    405         .array_init_dot_two,
    406         .array_init_dot_two_comma,
    407         .array_init_dot,
    408         .array_init_dot_comma,
    409         .array_init,
    410         .array_init_comma,
    411         .struct_init_one,
    412         .struct_init_one_comma,
    413         .struct_init_dot_two,
    414         .struct_init_dot_two_comma,
    415         .struct_init_dot,
    416         .struct_init_dot_comma,
    417         .struct_init,
    418         .struct_init_comma,
    419         .@"switch",
    420         .switch_comma,
    421         .@"for",
    422         .for_simple,
    423         .@"suspend",
    424         .@"continue",
    425         .@"anytype",
    426         .fn_proto_simple,
    427         .fn_proto_multi,
    428         .fn_proto_one,
    429         .fn_proto,
    430         .fn_decl,
    431         .anyframe_type,
    432         .anyframe_literal,
    433         .error_set_decl,
    434         .container_decl,
    435         .container_decl_trailing,
    436         .container_decl_two,
    437         .container_decl_two_trailing,
    438         .container_decl_arg,
    439         .container_decl_arg_trailing,
    440         .tagged_union,
    441         .tagged_union_trailing,
    442         .tagged_union_two,
    443         .tagged_union_two_trailing,
    444         .tagged_union_enum_tag,
    445         .tagged_union_enum_tag_trailing,
    446         .@"comptime",
    447         .@"nosuspend",
    448         .error_value,
    449         => return astgen.failNode(node, "invalid left-hand side to assignment", .{}),
    450 
    451         .builtin_call,
    452         .builtin_call_comma,
    453         .builtin_call_two,
    454         .builtin_call_two_comma,
    455         => {
    456             const builtin_token = main_tokens[node];
    457             const builtin_name = tree.tokenSlice(builtin_token);
    458             // If the builtin is an invalid name, we don't cause an error here; instead
    459             // let it pass, and the error will be "invalid builtin function" later.
    460             if (BuiltinFn.list.get(builtin_name)) |info| {
    461                 if (!info.allows_lvalue) {
    462                     return astgen.failNode(node, "invalid left-hand side to assignment", .{});
    463                 }
    464             }
    465         },
    466 
    467         // These can be assigned to.
    468         .unwrap_optional,
    469         .deref,
    470         .field_access,
    471         .array_access,
    472         .identifier,
    473         .grouped_expression,
    474         .@"orelse",
    475         => {},
    476     }
    477     return expr(gz, scope, .ref, node);
    478 }
    479 
    480 /// Turn Zig AST into untyped ZIR istructions.
    481 /// When `rl` is discard, ptr, inferred_ptr, or inferred_ptr, the
    482 /// result instruction can be used to inspect whether it is isNoReturn() but that is it,
    483 /// it must otherwise not be used.
    484 fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
    485     const astgen = gz.astgen;
    486     const tree = astgen.tree;
    487     const main_tokens = tree.nodes.items(.main_token);
    488     const token_tags = tree.tokens.items(.tag);
    489     const node_datas = tree.nodes.items(.data);
    490     const node_tags = tree.nodes.items(.tag);
    491 
    492     switch (node_tags[node]) {
    493         .root => unreachable, // Top-level declaration.
    494         .@"usingnamespace" => unreachable, // Top-level declaration.
    495         .test_decl => unreachable, // Top-level declaration.
    496         .container_field_init => unreachable, // Top-level declaration.
    497         .container_field_align => unreachable, // Top-level declaration.
    498         .container_field => unreachable, // Top-level declaration.
    499         .fn_decl => unreachable, // Top-level declaration.
    500 
    501         .global_var_decl => unreachable, // Handled in `blockExpr`.
    502         .local_var_decl => unreachable, // Handled in `blockExpr`.
    503         .simple_var_decl => unreachable, // Handled in `blockExpr`.
    504         .aligned_var_decl => unreachable, // Handled in `blockExpr`.
    505         .@"defer" => unreachable, // Handled in `blockExpr`.
    506         .@"errdefer" => unreachable, // Handled in `blockExpr`.
    507 
    508         .switch_case => unreachable, // Handled in `switchExpr`.
    509         .switch_case_one => unreachable, // Handled in `switchExpr`.
    510         .switch_range => unreachable, // Handled in `switchExpr`.
    511 
    512         .asm_output => unreachable, // Handled in `asmExpr`.
    513         .asm_input => unreachable, // Handled in `asmExpr`.
    514 
    515         .@"anytype" => unreachable, // Handled in `containerDecl`.
    516 
    517         .assign => {
    518             try assign(gz, scope, node);
    519             return rvalue(gz, rl, .void_value, node);
    520         },
    521 
    522         .assign_bit_shift_left => {
    523             try assignShift(gz, scope, node, .shl);
    524             return rvalue(gz, rl, .void_value, node);
    525         },
    526         .assign_bit_shift_right => {
    527             try assignShift(gz, scope, node, .shr);
    528             return rvalue(gz, rl, .void_value, node);
    529         },
    530 
    531         .assign_bit_and => {
    532             try assignOp(gz, scope, node, .bit_and);
    533             return rvalue(gz, rl, .void_value, node);
    534         },
    535         .assign_bit_or => {
    536             try assignOp(gz, scope, node, .bit_or);
    537             return rvalue(gz, rl, .void_value, node);
    538         },
    539         .assign_bit_xor => {
    540             try assignOp(gz, scope, node, .xor);
    541             return rvalue(gz, rl, .void_value, node);
    542         },
    543         .assign_div => {
    544             try assignOp(gz, scope, node, .div);
    545             return rvalue(gz, rl, .void_value, node);
    546         },
    547         .assign_sub => {
    548             try assignOp(gz, scope, node, .sub);
    549             return rvalue(gz, rl, .void_value, node);
    550         },
    551         .assign_sub_wrap => {
    552             try assignOp(gz, scope, node, .subwrap);
    553             return rvalue(gz, rl, .void_value, node);
    554         },
    555         .assign_mod => {
    556             try assignOp(gz, scope, node, .mod_rem);
    557             return rvalue(gz, rl, .void_value, node);
    558         },
    559         .assign_add => {
    560             try assignOp(gz, scope, node, .add);
    561             return rvalue(gz, rl, .void_value, node);
    562         },
    563         .assign_add_wrap => {
    564             try assignOp(gz, scope, node, .addwrap);
    565             return rvalue(gz, rl, .void_value, node);
    566         },
    567         .assign_mul => {
    568             try assignOp(gz, scope, node, .mul);
    569             return rvalue(gz, rl, .void_value, node);
    570         },
    571         .assign_mul_wrap => {
    572             try assignOp(gz, scope, node, .mulwrap);
    573             return rvalue(gz, rl, .void_value, node);
    574         },
    575 
    576         // zig fmt: off
    577         .bit_shift_left  => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl),
    578         .bit_shift_right => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr),
    579 
    580         .add      => return simpleBinOp(gz, scope, rl, node, .add),
    581         .add_wrap => return simpleBinOp(gz, scope, rl, node, .addwrap),
    582         .sub      => return simpleBinOp(gz, scope, rl, node, .sub),
    583         .sub_wrap => return simpleBinOp(gz, scope, rl, node, .subwrap),
    584         .mul      => return simpleBinOp(gz, scope, rl, node, .mul),
    585         .mul_wrap => return simpleBinOp(gz, scope, rl, node, .mulwrap),
    586         .div      => return simpleBinOp(gz, scope, rl, node, .div),
    587         .mod      => return simpleBinOp(gz, scope, rl, node, .mod_rem),
    588         .bit_and  => {
    589             const current_ampersand_token = main_tokens[node];
    590             if (token_tags[current_ampersand_token + 1] == .ampersand) {
    591                 const token_starts = tree.tokens.items(.start);
    592                 const current_token_offset = token_starts[current_ampersand_token];
    593                 const next_token_offset = token_starts[current_ampersand_token + 1];
    594                 if (current_token_offset + 1 == next_token_offset) {
    595                     return astgen.failTok(
    596                         current_ampersand_token,
    597                         "`&&` is invalid; note that `and` is boolean AND",
    598                         .{},
    599                     );
    600                 }
    601             }
    602 
    603             return simpleBinOp(gz, scope, rl, node, .bit_and);
    604         },
    605         .bit_or   => return simpleBinOp(gz, scope, rl, node, .bit_or),
    606         .bit_xor  => return simpleBinOp(gz, scope, rl, node, .xor),
    607 
    608         .bang_equal       => return simpleBinOp(gz, scope, rl, node, .cmp_neq),
    609         .equal_equal      => return simpleBinOp(gz, scope, rl, node, .cmp_eq),
    610         .greater_than     => return simpleBinOp(gz, scope, rl, node, .cmp_gt),
    611         .greater_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_gte),
    612         .less_than        => return simpleBinOp(gz, scope, rl, node, .cmp_lt),
    613         .less_or_equal    => return simpleBinOp(gz, scope, rl, node, .cmp_lte),
    614 
    615         .array_cat        => return simpleBinOp(gz, scope, rl, node, .array_cat),
    616         .array_mult       => return simpleBinOp(gz, scope, rl, node, .array_mul),
    617 
    618         .error_union      => return simpleBinOp(gz, scope, rl, node, .error_union_type),
    619         .merge_error_sets => return simpleBinOp(gz, scope, rl, node, .merge_error_sets),
    620 
    621         .bool_and => return boolBinOp(gz, scope, rl, node, .bool_br_and),
    622         .bool_or  => return boolBinOp(gz, scope, rl, node, .bool_br_or),
    623 
    624         .bool_not => return boolNot(gz, scope, rl, node),
    625         .bit_not  => return bitNot(gz, scope, rl, node),
    626 
    627         .negation      => return negation(gz, scope, rl, node, .negate),
    628         .negation_wrap => return negation(gz, scope, rl, node, .negate_wrap),
    629 
    630         .identifier => return identifier(gz, scope, rl, node),
    631 
    632         .asm_simple => return asmExpr(gz, scope, rl, node, tree.asmSimple(node)),
    633         .@"asm"     => return asmExpr(gz, scope, rl, node, tree.asmFull(node)),
    634 
    635         .string_literal           => return stringLiteral(gz, rl, node),
    636         .multiline_string_literal => return multilineStringLiteral(gz, rl, node),
    637 
    638         .integer_literal => return integerLiteral(gz, rl, node),
    639         // zig fmt: on
    640 
    641         .builtin_call_two, .builtin_call_two_comma => {
    642             if (node_datas[node].lhs == 0) {
    643                 const params = [_]ast.Node.Index{};
    644                 return builtinCall(gz, scope, rl, node, &params);
    645             } else if (node_datas[node].rhs == 0) {
    646                 const params = [_]ast.Node.Index{node_datas[node].lhs};
    647                 return builtinCall(gz, scope, rl, node, &params);
    648             } else {
    649                 const params = [_]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs };
    650                 return builtinCall(gz, scope, rl, node, &params);
    651             }
    652         },
    653         .builtin_call, .builtin_call_comma => {
    654             const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
    655             return builtinCall(gz, scope, rl, node, params);
    656         },
    657 
    658         .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => {
    659             var params: [1]ast.Node.Index = undefined;
    660             return callExpr(gz, scope, rl, node, tree.callOne(&params, node));
    661         },
    662         .call, .call_comma, .async_call, .async_call_comma => {
    663             return callExpr(gz, scope, rl, node, tree.callFull(node));
    664         },
    665 
    666         .unreachable_literal => {
    667             _ = try gz.addAsIndex(.{
    668                 .tag = .@"unreachable",
    669                 .data = .{ .@"unreachable" = .{
    670                     .safety = true,
    671                     .src_node = gz.nodeIndexToRelative(node),
    672                 } },
    673             });
    674             return Zir.Inst.Ref.unreachable_value;
    675         },
    676         .@"return" => return ret(gz, scope, node),
    677         .field_access => return fieldAccess(gz, scope, rl, node),
    678         .float_literal => return floatLiteral(gz, rl, node),
    679 
    680         .if_simple => return ifExpr(gz, scope, rl, node, tree.ifSimple(node)),
    681         .@"if" => return ifExpr(gz, scope, rl, node, tree.ifFull(node)),
    682 
    683         .while_simple => return whileExpr(gz, scope, rl, node, tree.whileSimple(node)),
    684         .while_cont => return whileExpr(gz, scope, rl, node, tree.whileCont(node)),
    685         .@"while" => return whileExpr(gz, scope, rl, node, tree.whileFull(node)),
    686 
    687         .for_simple => return forExpr(gz, scope, rl, node, tree.forSimple(node)),
    688         .@"for" => return forExpr(gz, scope, rl, node, tree.forFull(node)),
    689 
    690         .slice_open => {
    691             const lhs = try expr(gz, scope, .ref, node_datas[node].lhs);
    692             const start = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs);
    693             const result = try gz.addPlNode(.slice_start, node, Zir.Inst.SliceStart{
    694                 .lhs = lhs,
    695                 .start = start,
    696             });
    697             switch (rl) {
    698                 .ref, .none_or_ref => return result,
    699                 else => {
    700                     const dereffed = try gz.addUnNode(.load, result, node);
    701                     return rvalue(gz, rl, dereffed, node);
    702                 },
    703             }
    704         },
    705         .slice => {
    706             const lhs = try expr(gz, scope, .ref, node_datas[node].lhs);
    707             const extra = tree.extraData(node_datas[node].rhs, ast.Node.Slice);
    708             const start = try expr(gz, scope, .{ .ty = .usize_type }, extra.start);
    709             const end = try expr(gz, scope, .{ .ty = .usize_type }, extra.end);
    710             const result = try gz.addPlNode(.slice_end, node, Zir.Inst.SliceEnd{
    711                 .lhs = lhs,
    712                 .start = start,
    713                 .end = end,
    714             });
    715             switch (rl) {
    716                 .ref, .none_or_ref => return result,
    717                 else => {
    718                     const dereffed = try gz.addUnNode(.load, result, node);
    719                     return rvalue(gz, rl, dereffed, node);
    720                 },
    721             }
    722         },
    723         .slice_sentinel => {
    724             const lhs = try expr(gz, scope, .ref, node_datas[node].lhs);
    725             const extra = tree.extraData(node_datas[node].rhs, ast.Node.SliceSentinel);
    726             const start = try expr(gz, scope, .{ .ty = .usize_type }, extra.start);
    727             const end = if (extra.end != 0) try expr(gz, scope, .{ .ty = .usize_type }, extra.end) else .none;
    728             const sentinel = try expr(gz, scope, .{ .ty = .usize_type }, extra.sentinel);
    729             const result = try gz.addPlNode(.slice_sentinel, node, Zir.Inst.SliceSentinel{
    730                 .lhs = lhs,
    731                 .start = start,
    732                 .end = end,
    733                 .sentinel = sentinel,
    734             });
    735             switch (rl) {
    736                 .ref, .none_or_ref => return result,
    737                 else => {
    738                     const dereffed = try gz.addUnNode(.load, result, node);
    739                     return rvalue(gz, rl, dereffed, node);
    740                 },
    741             }
    742         },
    743 
    744         .deref => {
    745             const lhs = try expr(gz, scope, .none, node_datas[node].lhs);
    746             switch (rl) {
    747                 .ref, .none_or_ref => return lhs,
    748                 else => {
    749                     const result = try gz.addUnNode(.load, lhs, node);
    750                     return rvalue(gz, rl, result, node);
    751                 },
    752             }
    753         },
    754         .address_of => {
    755             const result = try expr(gz, scope, .ref, node_datas[node].lhs);
    756             return rvalue(gz, rl, result, node);
    757         },
    758         .optional_type => {
    759             const operand = try typeExpr(gz, scope, node_datas[node].lhs);
    760             const result = try gz.addUnNode(.optional_type, operand, node);
    761             return rvalue(gz, rl, result, node);
    762         },
    763         .unwrap_optional => switch (rl) {
    764             .ref => return gz.addUnNode(
    765                 .optional_payload_safe_ptr,
    766                 try expr(gz, scope, .ref, node_datas[node].lhs),
    767                 node,
    768             ),
    769             else => return rvalue(gz, rl, try gz.addUnNode(
    770                 .optional_payload_safe,
    771                 try expr(gz, scope, .none, node_datas[node].lhs),
    772                 node,
    773             ), node),
    774         },
    775         .block_two, .block_two_semicolon => {
    776             const statements = [2]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs };
    777             if (node_datas[node].lhs == 0) {
    778                 return blockExpr(gz, scope, rl, node, statements[0..0]);
    779             } else if (node_datas[node].rhs == 0) {
    780                 return blockExpr(gz, scope, rl, node, statements[0..1]);
    781             } else {
    782                 return blockExpr(gz, scope, rl, node, statements[0..2]);
    783             }
    784         },
    785         .block, .block_semicolon => {
    786             const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
    787             return blockExpr(gz, scope, rl, node, statements);
    788         },
    789         .enum_literal => return simpleStrTok(gz, rl, main_tokens[node], node, .enum_literal),
    790         .error_value => return simpleStrTok(gz, rl, node_datas[node].rhs, node, .error_value),
    791         .anyframe_literal => return rvalue(gz, rl, .anyframe_type, node),
    792         .anyframe_type => {
    793             const return_type = try typeExpr(gz, scope, node_datas[node].rhs);
    794             const result = try gz.addUnNode(.anyframe_type, return_type, node);
    795             return rvalue(gz, rl, result, node);
    796         },
    797         .@"catch" => {
    798             const catch_token = main_tokens[node];
    799             const payload_token: ?ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe)
    800                 catch_token + 2
    801             else
    802                 null;
    803             switch (rl) {
    804                 .ref => return orelseCatchExpr(
    805                     gz,
    806                     scope,
    807                     rl,
    808                     node,
    809                     node_datas[node].lhs,
    810                     .is_non_err_ptr,
    811                     .err_union_payload_unsafe_ptr,
    812                     .err_union_code_ptr,
    813                     node_datas[node].rhs,
    814                     payload_token,
    815                 ),
    816                 else => return orelseCatchExpr(
    817                     gz,
    818                     scope,
    819                     rl,
    820                     node,
    821                     node_datas[node].lhs,
    822                     .is_non_err,
    823                     .err_union_payload_unsafe,
    824                     .err_union_code,
    825                     node_datas[node].rhs,
    826                     payload_token,
    827                 ),
    828             }
    829         },
    830         .@"orelse" => switch (rl) {
    831             .ref => return orelseCatchExpr(
    832                 gz,
    833                 scope,
    834                 rl,
    835                 node,
    836                 node_datas[node].lhs,
    837                 .is_non_null_ptr,
    838                 .optional_payload_unsafe_ptr,
    839                 undefined,
    840                 node_datas[node].rhs,
    841                 null,
    842             ),
    843             else => return orelseCatchExpr(
    844                 gz,
    845                 scope,
    846                 rl,
    847                 node,
    848                 node_datas[node].lhs,
    849                 .is_non_null,
    850                 .optional_payload_unsafe,
    851                 undefined,
    852                 node_datas[node].rhs,
    853                 null,
    854             ),
    855         },
    856 
    857         .ptr_type_aligned => return ptrType(gz, scope, rl, node, tree.ptrTypeAligned(node)),
    858         .ptr_type_sentinel => return ptrType(gz, scope, rl, node, tree.ptrTypeSentinel(node)),
    859         .ptr_type => return ptrType(gz, scope, rl, node, tree.ptrType(node)),
    860         .ptr_type_bit_range => return ptrType(gz, scope, rl, node, tree.ptrTypeBitRange(node)),
    861 
    862         .container_decl,
    863         .container_decl_trailing,
    864         => return containerDecl(gz, scope, rl, node, tree.containerDecl(node)),
    865         .container_decl_two, .container_decl_two_trailing => {
    866             var buffer: [2]ast.Node.Index = undefined;
    867             return containerDecl(gz, scope, rl, node, tree.containerDeclTwo(&buffer, node));
    868         },
    869         .container_decl_arg,
    870         .container_decl_arg_trailing,
    871         => return containerDecl(gz, scope, rl, node, tree.containerDeclArg(node)),
    872 
    873         .tagged_union,
    874         .tagged_union_trailing,
    875         => return containerDecl(gz, scope, rl, node, tree.taggedUnion(node)),
    876         .tagged_union_two, .tagged_union_two_trailing => {
    877             var buffer: [2]ast.Node.Index = undefined;
    878             return containerDecl(gz, scope, rl, node, tree.taggedUnionTwo(&buffer, node));
    879         },
    880         .tagged_union_enum_tag,
    881         .tagged_union_enum_tag_trailing,
    882         => return containerDecl(gz, scope, rl, node, tree.taggedUnionEnumTag(node)),
    883 
    884         .@"break" => return breakExpr(gz, scope, node),
    885         .@"continue" => return continueExpr(gz, scope, node),
    886         .grouped_expression => return expr(gz, scope, rl, node_datas[node].lhs),
    887         .array_type => return arrayType(gz, scope, rl, node),
    888         .array_type_sentinel => return arrayTypeSentinel(gz, scope, rl, node),
    889         .char_literal => return charLiteral(gz, rl, node),
    890         .error_set_decl => return errorSetDecl(gz, rl, node),
    891         .array_access => return arrayAccess(gz, scope, rl, node),
    892         .@"comptime" => return comptimeExprAst(gz, scope, rl, node),
    893         .@"switch", .switch_comma => return switchExpr(gz, scope, rl, node),
    894 
    895         .@"nosuspend" => return nosuspendExpr(gz, scope, rl, node),
    896         .@"suspend" => return suspendExpr(gz, scope, node),
    897         .@"await" => return awaitExpr(gz, scope, rl, node),
    898         .@"resume" => return resumeExpr(gz, scope, rl, node),
    899 
    900         .@"try" => return tryExpr(gz, scope, rl, node, node_datas[node].lhs),
    901 
    902         .array_init_one, .array_init_one_comma => {
    903             var elements: [1]ast.Node.Index = undefined;
    904             return arrayInitExpr(gz, scope, rl, node, tree.arrayInitOne(&elements, node));
    905         },
    906         .array_init_dot_two, .array_init_dot_two_comma => {
    907             var elements: [2]ast.Node.Index = undefined;
    908             return arrayInitExpr(gz, scope, rl, node, tree.arrayInitDotTwo(&elements, node));
    909         },
    910         .array_init_dot,
    911         .array_init_dot_comma,
    912         => return arrayInitExpr(gz, scope, rl, node, tree.arrayInitDot(node)),
    913         .array_init,
    914         .array_init_comma,
    915         => return arrayInitExpr(gz, scope, rl, node, tree.arrayInit(node)),
    916 
    917         .struct_init_one, .struct_init_one_comma => {
    918             var fields: [1]ast.Node.Index = undefined;
    919             return structInitExpr(gz, scope, rl, node, tree.structInitOne(&fields, node));
    920         },
    921         .struct_init_dot_two, .struct_init_dot_two_comma => {
    922             var fields: [2]ast.Node.Index = undefined;
    923             return structInitExpr(gz, scope, rl, node, tree.structInitDotTwo(&fields, node));
    924         },
    925         .struct_init_dot,
    926         .struct_init_dot_comma,
    927         => return structInitExpr(gz, scope, rl, node, tree.structInitDot(node)),
    928         .struct_init,
    929         .struct_init_comma,
    930         => return structInitExpr(gz, scope, rl, node, tree.structInit(node)),
    931 
    932         .fn_proto_simple => {
    933             var params: [1]ast.Node.Index = undefined;
    934             return fnProtoExpr(gz, scope, rl, tree.fnProtoSimple(&params, node));
    935         },
    936         .fn_proto_multi => {
    937             return fnProtoExpr(gz, scope, rl, tree.fnProtoMulti(node));
    938         },
    939         .fn_proto_one => {
    940             var params: [1]ast.Node.Index = undefined;
    941             return fnProtoExpr(gz, scope, rl, tree.fnProtoOne(&params, node));
    942         },
    943         .fn_proto => {
    944             return fnProtoExpr(gz, scope, rl, tree.fnProto(node));
    945         },
    946     }
    947 }
    948 
    949 fn nosuspendExpr(
    950     gz: *GenZir,
    951     scope: *Scope,
    952     rl: ResultLoc,
    953     node: ast.Node.Index,
    954 ) InnerError!Zir.Inst.Ref {
    955     const astgen = gz.astgen;
    956     const tree = astgen.tree;
    957     const node_datas = tree.nodes.items(.data);
    958     const body_node = node_datas[node].lhs;
    959     assert(body_node != 0);
    960     if (gz.nosuspend_node != 0) {
    961         return astgen.failNodeNotes(node, "redundant nosuspend block", .{}, &[_]u32{
    962             try astgen.errNoteNode(gz.nosuspend_node, "other nosuspend block here", .{}),
    963         });
    964     }
    965     gz.nosuspend_node = node;
    966     const result = try expr(gz, scope, rl, body_node);
    967     gz.nosuspend_node = 0;
    968     return rvalue(gz, rl, result, node);
    969 }
    970 
    971 fn suspendExpr(
    972     gz: *GenZir,
    973     scope: *Scope,
    974     node: ast.Node.Index,
    975 ) InnerError!Zir.Inst.Ref {
    976     const astgen = gz.astgen;
    977     const gpa = astgen.gpa;
    978     const tree = astgen.tree;
    979     const node_datas = tree.nodes.items(.data);
    980     const body_node = node_datas[node].lhs;
    981 
    982     if (gz.nosuspend_node != 0) {
    983         return astgen.failNodeNotes(node, "suspend inside nosuspend block", .{}, &[_]u32{
    984             try astgen.errNoteNode(gz.nosuspend_node, "nosuspend block here", .{}),
    985         });
    986     }
    987     if (gz.suspend_node != 0) {
    988         return astgen.failNodeNotes(node, "cannot suspend inside suspend block", .{}, &[_]u32{
    989             try astgen.errNoteNode(gz.suspend_node, "other suspend block here", .{}),
    990         });
    991     }
    992     assert(body_node != 0);
    993 
    994     const suspend_inst = try gz.addBlock(.suspend_block, node);
    995     try gz.instructions.append(gpa, suspend_inst);
    996 
    997     var suspend_scope = gz.makeSubBlock(scope);
    998     suspend_scope.suspend_node = node;
    999     defer suspend_scope.instructions.deinit(gpa);
   1000 
   1001     const body_result = try expr(&suspend_scope, &suspend_scope.base, .none, body_node);
   1002     if (!gz.refIsNoReturn(body_result)) {
   1003         _ = try suspend_scope.addBreak(.break_inline, suspend_inst, .void_value);
   1004     }
   1005     try suspend_scope.setBlockBody(suspend_inst);
   1006 
   1007     return indexToRef(suspend_inst);
   1008 }
   1009 
   1010 fn awaitExpr(
   1011     gz: *GenZir,
   1012     scope: *Scope,
   1013     rl: ResultLoc,
   1014     node: ast.Node.Index,
   1015 ) InnerError!Zir.Inst.Ref {
   1016     const astgen = gz.astgen;
   1017     const tree = astgen.tree;
   1018     const node_datas = tree.nodes.items(.data);
   1019     const rhs_node = node_datas[node].lhs;
   1020 
   1021     if (gz.suspend_node != 0) {
   1022         return astgen.failNodeNotes(node, "cannot await inside suspend block", .{}, &[_]u32{
   1023             try astgen.errNoteNode(gz.suspend_node, "suspend block here", .{}),
   1024         });
   1025     }
   1026     const operand = try expr(gz, scope, .none, rhs_node);
   1027     const tag: Zir.Inst.Tag = if (gz.nosuspend_node != 0) .await_nosuspend else .@"await";
   1028     const result = try gz.addUnNode(tag, operand, node);
   1029     return rvalue(gz, rl, result, node);
   1030 }
   1031 
   1032 fn resumeExpr(
   1033     gz: *GenZir,
   1034     scope: *Scope,
   1035     rl: ResultLoc,
   1036     node: ast.Node.Index,
   1037 ) InnerError!Zir.Inst.Ref {
   1038     const astgen = gz.astgen;
   1039     const tree = astgen.tree;
   1040     const node_datas = tree.nodes.items(.data);
   1041     const rhs_node = node_datas[node].lhs;
   1042     const operand = try expr(gz, scope, .none, rhs_node);
   1043     const result = try gz.addUnNode(.@"resume", operand, node);
   1044     return rvalue(gz, rl, result, node);
   1045 }
   1046 
   1047 fn fnProtoExpr(
   1048     gz: *GenZir,
   1049     scope: *Scope,
   1050     rl: ResultLoc,
   1051     fn_proto: ast.full.FnProto,
   1052 ) InnerError!Zir.Inst.Ref {
   1053     const astgen = gz.astgen;
   1054     const gpa = astgen.gpa;
   1055     const tree = astgen.tree;
   1056     const token_tags = tree.tokens.items(.tag);
   1057 
   1058     const is_extern = blk: {
   1059         const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false;
   1060         break :blk token_tags[maybe_extern_token] == .keyword_extern;
   1061     };
   1062     assert(!is_extern);
   1063 
   1064     const is_var_args = is_var_args: {
   1065         var param_type_i: usize = 0;
   1066         var it = fn_proto.iterate(tree.*);
   1067         while (it.next()) |param| : (param_type_i += 1) {
   1068             const is_comptime = if (param.comptime_noalias) |token|
   1069                 token_tags[token] == .keyword_comptime
   1070             else
   1071                 false;
   1072 
   1073             const is_anytype = if (param.anytype_ellipsis3) |token| blk: {
   1074                 switch (token_tags[token]) {
   1075                     .keyword_anytype => break :blk true,
   1076                     .ellipsis3 => break :is_var_args true,
   1077                     else => unreachable,
   1078                 }
   1079             } else false;
   1080 
   1081             const param_name: u32 = if (param.name_token) |name_token| blk: {
   1082                 if (mem.eql(u8, "_", tree.tokenSlice(name_token)))
   1083                     break :blk 0;
   1084 
   1085                 break :blk try astgen.identAsString(name_token);
   1086             } else 0;
   1087 
   1088             if (is_anytype) {
   1089                 const name_token = param.name_token orelse param.anytype_ellipsis3.?;
   1090 
   1091                 const tag: Zir.Inst.Tag = if (is_comptime)
   1092                     .param_anytype_comptime
   1093                 else
   1094                     .param_anytype;
   1095                 _ = try gz.addStrTok(tag, param_name, name_token);
   1096             } else {
   1097                 const param_type_node = param.type_expr;
   1098                 assert(param_type_node != 0);
   1099                 var param_gz = gz.makeSubBlock(scope);
   1100                 defer param_gz.instructions.deinit(gpa);
   1101                 const param_type = try expr(&param_gz, scope, coerced_type_rl, param_type_node);
   1102                 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);
   1103                 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type);
   1104                 const main_tokens = tree.nodes.items(.main_token);
   1105                 const name_token = param.name_token orelse main_tokens[param_type_node];
   1106                 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
   1107                 const param_inst = try gz.addParam(tag, name_token, param_name, param_gz.instructions.items);
   1108                 assert(param_inst_expected == param_inst);
   1109             }
   1110         }
   1111         break :is_var_args false;
   1112     };
   1113 
   1114     const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
   1115         break :inst try expr(gz, scope, align_rl, fn_proto.ast.align_expr);
   1116     };
   1117     if (fn_proto.ast.section_expr != 0) {
   1118         return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{});
   1119     }
   1120 
   1121     const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
   1122     const is_inferred_error = token_tags[maybe_bang] == .bang;
   1123     if (is_inferred_error) {
   1124         return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
   1125     }
   1126     var ret_gz = gz.makeSubBlock(scope);
   1127     defer ret_gz.instructions.deinit(gpa);
   1128     const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type);
   1129     const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
   1130 
   1131     const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
   1132         try expr(
   1133             gz,
   1134             scope,
   1135             .{ .ty = .calling_convention_type },
   1136             fn_proto.ast.callconv_expr,
   1137         )
   1138     else
   1139         Zir.Inst.Ref.none;
   1140 
   1141     const result = try gz.addFunc(.{
   1142         .src_node = fn_proto.ast.proto_node,
   1143         .param_block = 0,
   1144         .ret_ty = ret_gz.instructions.items,
   1145         .ret_br = ret_br,
   1146         .body = &[0]Zir.Inst.Index{},
   1147         .cc = cc,
   1148         .align_inst = align_inst,
   1149         .lib_name = 0,
   1150         .is_var_args = is_var_args,
   1151         .is_inferred_error = false,
   1152         .is_test = false,
   1153         .is_extern = false,
   1154     });
   1155     return rvalue(gz, rl, result, fn_proto.ast.proto_node);
   1156 }
   1157 
   1158 fn arrayInitExpr(
   1159     gz: *GenZir,
   1160     scope: *Scope,
   1161     rl: ResultLoc,
   1162     node: ast.Node.Index,
   1163     array_init: ast.full.ArrayInit,
   1164 ) InnerError!Zir.Inst.Ref {
   1165     const astgen = gz.astgen;
   1166     const tree = astgen.tree;
   1167     const node_tags = tree.nodes.items(.tag);
   1168     const main_tokens = tree.nodes.items(.main_token);
   1169 
   1170     assert(array_init.ast.elements.len != 0); // Otherwise it would be struct init.
   1171 
   1172     const types: struct {
   1173         array: Zir.Inst.Ref,
   1174         elem: Zir.Inst.Ref,
   1175     } = inst: {
   1176         if (array_init.ast.type_expr == 0) break :inst .{
   1177             .array = .none,
   1178             .elem = .none,
   1179         };
   1180 
   1181         infer: {
   1182             const array_type: ast.full.ArrayType = switch (node_tags[array_init.ast.type_expr]) {
   1183                 .array_type => tree.arrayType(array_init.ast.type_expr),
   1184                 .array_type_sentinel => tree.arrayTypeSentinel(array_init.ast.type_expr),
   1185                 else => break :infer,
   1186             };
   1187             // This intentionally does not support `@"_"` syntax.
   1188             if (node_tags[array_type.ast.elem_count] == .identifier and
   1189                 mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_"))
   1190             {
   1191                 const len_inst = try gz.addInt(array_init.ast.elements.len);
   1192                 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type);
   1193                 if (array_type.ast.sentinel == 0) {
   1194                     const array_type_inst = try gz.addBin(.array_type, len_inst, elem_type);
   1195                     break :inst .{
   1196                         .array = array_type_inst,
   1197                         .elem = elem_type,
   1198                     };
   1199                 } else {
   1200                     const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel);
   1201                     const array_type_inst = try gz.addArrayTypeSentinel(len_inst, elem_type, sentinel);
   1202                     break :inst .{
   1203                         .array = array_type_inst,
   1204                         .elem = elem_type,
   1205                     };
   1206                 }
   1207             }
   1208         }
   1209         const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr);
   1210         const elem_type = try gz.addUnNode(.elem_type, array_type_inst, array_init.ast.type_expr);
   1211         break :inst .{
   1212             .array = array_type_inst,
   1213             .elem = elem_type,
   1214         };
   1215     };
   1216 
   1217     switch (rl) {
   1218         .discard => {
   1219             for (array_init.ast.elements) |elem_init| {
   1220                 _ = try expr(gz, scope, .discard, elem_init);
   1221             }
   1222             return Zir.Inst.Ref.void_value;
   1223         },
   1224         .ref => {
   1225             if (types.array != .none) {
   1226                 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init_ref);
   1227             } else {
   1228                 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref);
   1229             }
   1230         },
   1231         .none, .none_or_ref => {
   1232             if (types.array != .none) {
   1233                 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init);
   1234             } else {
   1235                 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
   1236             }
   1237         },
   1238         .ty, .coerced_ty => |ty_inst| {
   1239             if (types.array != .none) {
   1240                 const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init);
   1241                 return rvalue(gz, rl, result, node);
   1242             } else {
   1243                 const elem_type = try gz.addUnNode(.elem_type, ty_inst, node);
   1244                 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, elem_type, .array_init);
   1245             }
   1246         },
   1247         .ptr, .inferred_ptr => |ptr_inst| {
   1248             return arrayInitExprRlPtr(gz, scope, node, array_init.ast.elements, ptr_inst);
   1249         },
   1250         .block_ptr => |block_gz| {
   1251             return arrayInitExprRlPtr(gz, scope, node, array_init.ast.elements, block_gz.rl_ptr);
   1252         },
   1253     }
   1254 }
   1255 
   1256 fn arrayInitExprRlNone(
   1257     gz: *GenZir,
   1258     scope: *Scope,
   1259     node: ast.Node.Index,
   1260     elements: []const ast.Node.Index,
   1261     tag: Zir.Inst.Tag,
   1262 ) InnerError!Zir.Inst.Ref {
   1263     const astgen = gz.astgen;
   1264     const gpa = astgen.gpa;
   1265     const elem_list = try gpa.alloc(Zir.Inst.Ref, elements.len);
   1266     defer gpa.free(elem_list);
   1267 
   1268     for (elements) |elem_init, i| {
   1269         elem_list[i] = try expr(gz, scope, .none, elem_init);
   1270     }
   1271     const init_inst = try gz.addPlNode(tag, node, Zir.Inst.MultiOp{
   1272         .operands_len = @intCast(u32, elem_list.len),
   1273     });
   1274     try astgen.appendRefs(elem_list);
   1275     return init_inst;
   1276 }
   1277 
   1278 fn arrayInitExprRlTy(
   1279     gz: *GenZir,
   1280     scope: *Scope,
   1281     node: ast.Node.Index,
   1282     elements: []const ast.Node.Index,
   1283     elem_ty_inst: Zir.Inst.Ref,
   1284     tag: Zir.Inst.Tag,
   1285 ) InnerError!Zir.Inst.Ref {
   1286     const astgen = gz.astgen;
   1287     const gpa = astgen.gpa;
   1288 
   1289     const elem_list = try gpa.alloc(Zir.Inst.Ref, elements.len);
   1290     defer gpa.free(elem_list);
   1291 
   1292     const elem_rl: ResultLoc = .{ .ty = elem_ty_inst };
   1293 
   1294     for (elements) |elem_init, i| {
   1295         elem_list[i] = try expr(gz, scope, elem_rl, elem_init);
   1296     }
   1297     const init_inst = try gz.addPlNode(tag, node, Zir.Inst.MultiOp{
   1298         .operands_len = @intCast(u32, elem_list.len),
   1299     });
   1300     try astgen.appendRefs(elem_list);
   1301     return init_inst;
   1302 }
   1303 
   1304 fn arrayInitExprRlPtr(
   1305     gz: *GenZir,
   1306     scope: *Scope,
   1307     node: ast.Node.Index,
   1308     elements: []const ast.Node.Index,
   1309     result_ptr: Zir.Inst.Ref,
   1310 ) InnerError!Zir.Inst.Ref {
   1311     const astgen = gz.astgen;
   1312     const gpa = astgen.gpa;
   1313 
   1314     const elem_ptr_list = try gpa.alloc(Zir.Inst.Index, elements.len);
   1315     defer gpa.free(elem_ptr_list);
   1316 
   1317     for (elements) |elem_init, i| {
   1318         const index_inst = try gz.addInt(i);
   1319         const elem_ptr = try gz.addPlNode(.elem_ptr_node, elem_init, Zir.Inst.Bin{
   1320             .lhs = result_ptr,
   1321             .rhs = index_inst,
   1322         });
   1323         elem_ptr_list[i] = refToIndex(elem_ptr).?;
   1324         _ = try expr(gz, scope, .{ .ptr = elem_ptr }, elem_init);
   1325     }
   1326     _ = try gz.addPlNode(.validate_array_init_ptr, node, Zir.Inst.Block{
   1327         .body_len = @intCast(u32, elem_ptr_list.len),
   1328     });
   1329     try astgen.extra.appendSlice(gpa, elem_ptr_list);
   1330     return .void_value;
   1331 }
   1332 
   1333 fn structInitExpr(
   1334     gz: *GenZir,
   1335     scope: *Scope,
   1336     rl: ResultLoc,
   1337     node: ast.Node.Index,
   1338     struct_init: ast.full.StructInit,
   1339 ) InnerError!Zir.Inst.Ref {
   1340     const astgen = gz.astgen;
   1341     const tree = astgen.tree;
   1342 
   1343     if (struct_init.ast.type_expr == 0) {
   1344         if (struct_init.ast.fields.len == 0) {
   1345             return rvalue(gz, rl, .empty_struct, node);
   1346         }
   1347     } else array: {
   1348         const node_tags = tree.nodes.items(.tag);
   1349         const main_tokens = tree.nodes.items(.main_token);
   1350         const array_type: ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) {
   1351             .array_type => tree.arrayType(struct_init.ast.type_expr),
   1352             .array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr),
   1353             else => break :array,
   1354         };
   1355         const is_inferred_array_len = node_tags[array_type.ast.elem_count] == .identifier and
   1356             // This intentionally does not support `@"_"` syntax.
   1357             mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_");
   1358         if (struct_init.ast.fields.len == 0) {
   1359             if (is_inferred_array_len) {
   1360                 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type);
   1361                 const array_type_inst = if (array_type.ast.sentinel == 0) blk: {
   1362                     break :blk try gz.addBin(.array_type, .zero_usize, elem_type);
   1363                 } else blk: {
   1364                     const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel);
   1365                     break :blk try gz.addArrayTypeSentinel(.zero_usize, elem_type, sentinel);
   1366                 };
   1367                 const result = try gz.addUnNode(.struct_init_empty, array_type_inst, node);
   1368                 return rvalue(gz, rl, result, node);
   1369             }
   1370             const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
   1371             const result = try gz.addUnNode(.struct_init_empty, ty_inst, node);
   1372             return rvalue(gz, rl, result, node);
   1373         } else {
   1374             return astgen.failNode(
   1375                 struct_init.ast.type_expr,
   1376                 "initializing array with struct syntax",
   1377                 .{},
   1378             );
   1379         }
   1380     }
   1381 
   1382     switch (rl) {
   1383         .discard => {
   1384             if (struct_init.ast.type_expr != 0)
   1385                 _ = try typeExpr(gz, scope, struct_init.ast.type_expr);
   1386             for (struct_init.ast.fields) |field_init| {
   1387                 _ = try expr(gz, scope, .discard, field_init);
   1388             }
   1389             return Zir.Inst.Ref.void_value;
   1390         },
   1391         .ref => {
   1392             if (struct_init.ast.type_expr != 0) {
   1393                 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
   1394                 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref);
   1395             } else {
   1396                 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref);
   1397             }
   1398         },
   1399         .none, .none_or_ref => {
   1400             if (struct_init.ast.type_expr != 0) {
   1401                 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
   1402                 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
   1403             } else {
   1404                 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon);
   1405             }
   1406         },
   1407         .ty, .coerced_ty => |ty_inst| {
   1408             if (struct_init.ast.type_expr == 0) {
   1409                 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
   1410             }
   1411             const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
   1412             const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init);
   1413             return rvalue(gz, rl, result, node);
   1414         },
   1415         .ptr, .inferred_ptr => |ptr_inst| return structInitExprRlPtr(gz, scope, node, struct_init, ptr_inst),
   1416         .block_ptr => |block_gz| return structInitExprRlPtr(gz, scope, node, struct_init, block_gz.rl_ptr),
   1417     }
   1418 }
   1419 
   1420 fn structInitExprRlNone(
   1421     gz: *GenZir,
   1422     scope: *Scope,
   1423     node: ast.Node.Index,
   1424     struct_init: ast.full.StructInit,
   1425     tag: Zir.Inst.Tag,
   1426 ) InnerError!Zir.Inst.Ref {
   1427     const astgen = gz.astgen;
   1428     const gpa = astgen.gpa;
   1429     const tree = astgen.tree;
   1430 
   1431     const fields_list = try gpa.alloc(Zir.Inst.StructInitAnon.Item, struct_init.ast.fields.len);
   1432     defer gpa.free(fields_list);
   1433 
   1434     for (struct_init.ast.fields) |field_init, i| {
   1435         const name_token = tree.firstToken(field_init) - 2;
   1436         const str_index = try astgen.identAsString(name_token);
   1437 
   1438         fields_list[i] = .{
   1439             .field_name = str_index,
   1440             .init = try expr(gz, scope, .none, field_init),
   1441         };
   1442     }
   1443     const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInitAnon{
   1444         .fields_len = @intCast(u32, fields_list.len),
   1445     });
   1446     try astgen.extra.ensureUnusedCapacity(gpa, fields_list.len *
   1447         @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len);
   1448     for (fields_list) |field| {
   1449         _ = gz.astgen.addExtraAssumeCapacity(field);
   1450     }
   1451     return init_inst;
   1452 }
   1453 
   1454 fn structInitExprRlPtr(
   1455     gz: *GenZir,
   1456     scope: *Scope,
   1457     node: ast.Node.Index,
   1458     struct_init: ast.full.StructInit,
   1459     result_ptr: Zir.Inst.Ref,
   1460 ) InnerError!Zir.Inst.Ref {
   1461     const astgen = gz.astgen;
   1462     const gpa = astgen.gpa;
   1463     const tree = astgen.tree;
   1464 
   1465     const field_ptr_list = try gpa.alloc(Zir.Inst.Index, struct_init.ast.fields.len);
   1466     defer gpa.free(field_ptr_list);
   1467 
   1468     if (struct_init.ast.type_expr != 0)
   1469         _ = try typeExpr(gz, scope, struct_init.ast.type_expr);
   1470 
   1471     for (struct_init.ast.fields) |field_init, i| {
   1472         const name_token = tree.firstToken(field_init) - 2;
   1473         const str_index = try astgen.identAsString(name_token);
   1474         const field_ptr = try gz.addPlNode(.field_ptr, field_init, Zir.Inst.Field{
   1475             .lhs = result_ptr,
   1476             .field_name_start = str_index,
   1477         });
   1478         field_ptr_list[i] = refToIndex(field_ptr).?;
   1479         _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init);
   1480     }
   1481     _ = try gz.addPlNode(.validate_struct_init_ptr, node, Zir.Inst.Block{
   1482         .body_len = @intCast(u32, field_ptr_list.len),
   1483     });
   1484     try astgen.extra.appendSlice(gpa, field_ptr_list);
   1485     return .void_value;
   1486 }
   1487 
   1488 fn structInitExprRlTy(
   1489     gz: *GenZir,
   1490     scope: *Scope,
   1491     node: ast.Node.Index,
   1492     struct_init: ast.full.StructInit,
   1493     ty_inst: Zir.Inst.Ref,
   1494     tag: Zir.Inst.Tag,
   1495 ) InnerError!Zir.Inst.Ref {
   1496     const astgen = gz.astgen;
   1497     const gpa = astgen.gpa;
   1498     const tree = astgen.tree;
   1499 
   1500     const fields_list = try gpa.alloc(Zir.Inst.StructInit.Item, struct_init.ast.fields.len);
   1501     defer gpa.free(fields_list);
   1502 
   1503     for (struct_init.ast.fields) |field_init, i| {
   1504         const name_token = tree.firstToken(field_init) - 2;
   1505         const str_index = try astgen.identAsString(name_token);
   1506 
   1507         const field_ty_inst = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{
   1508             .container_type = ty_inst,
   1509             .name_start = str_index,
   1510         });
   1511         fields_list[i] = .{
   1512             .field_type = refToIndex(field_ty_inst).?,
   1513             .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init),
   1514         };
   1515     }
   1516     const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInit{
   1517         .fields_len = @intCast(u32, fields_list.len),
   1518     });
   1519     try astgen.extra.ensureUnusedCapacity(gpa, fields_list.len *
   1520         @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len);
   1521     for (fields_list) |field| {
   1522         _ = gz.astgen.addExtraAssumeCapacity(field);
   1523     }
   1524     return init_inst;
   1525 }
   1526 
   1527 /// This calls expr in a comptime scope, and is intended to be called as a helper function.
   1528 /// The one that corresponds to `comptime` expression syntax is `comptimeExprAst`.
   1529 fn comptimeExpr(
   1530     gz: *GenZir,
   1531     scope: *Scope,
   1532     rl: ResultLoc,
   1533     node: ast.Node.Index,
   1534 ) InnerError!Zir.Inst.Ref {
   1535     const prev_force_comptime = gz.force_comptime;
   1536     gz.force_comptime = true;
   1537     defer gz.force_comptime = prev_force_comptime;
   1538 
   1539     return expr(gz, scope, rl, node);
   1540 }
   1541 
   1542 /// This one is for an actual `comptime` syntax, and will emit a compile error if
   1543 /// the scope already has `force_comptime=true`.
   1544 /// See `comptimeExpr` for the helper function for calling expr in a comptime scope.
   1545 fn comptimeExprAst(
   1546     gz: *GenZir,
   1547     scope: *Scope,
   1548     rl: ResultLoc,
   1549     node: ast.Node.Index,
   1550 ) InnerError!Zir.Inst.Ref {
   1551     const astgen = gz.astgen;
   1552     if (gz.force_comptime) {
   1553         return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{});
   1554     }
   1555     const tree = astgen.tree;
   1556     const node_datas = tree.nodes.items(.data);
   1557     const body_node = node_datas[node].lhs;
   1558     gz.force_comptime = true;
   1559     const result = try expr(gz, scope, rl, body_node);
   1560     gz.force_comptime = false;
   1561     return result;
   1562 }
   1563 
   1564 fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
   1565     const astgen = parent_gz.astgen;
   1566     const tree = astgen.tree;
   1567     const node_datas = tree.nodes.items(.data);
   1568     const break_label = node_datas[node].lhs;
   1569     const rhs = node_datas[node].rhs;
   1570 
   1571     // Look for the label in the scope.
   1572     var scope = parent_scope;
   1573     while (true) {
   1574         switch (scope.tag) {
   1575             .gen_zir => {
   1576                 const block_gz = scope.cast(GenZir).?;
   1577 
   1578                 const block_inst = blk: {
   1579                     if (break_label != 0) {
   1580                         if (block_gz.label) |*label| {
   1581                             if (try astgen.tokenIdentEql(label.token, break_label)) {
   1582                                 label.used = true;
   1583                                 break :blk label.block_inst;
   1584                             }
   1585                         }
   1586                     } else if (block_gz.break_block != 0) {
   1587                         break :blk block_gz.break_block;
   1588                     }
   1589                     scope = block_gz.parent;
   1590                     continue;
   1591                 };
   1592 
   1593                 if (rhs == 0) {
   1594                     _ = try parent_gz.addBreak(.@"break", block_inst, .void_value);
   1595                     return Zir.Inst.Ref.unreachable_value;
   1596                 }
   1597                 block_gz.break_count += 1;
   1598                 const prev_rvalue_rl_count = block_gz.rvalue_rl_count;
   1599                 const operand = try expr(parent_gz, parent_scope, block_gz.break_result_loc, rhs);
   1600                 const have_store_to_block = block_gz.rvalue_rl_count != prev_rvalue_rl_count;
   1601 
   1602                 const br = try parent_gz.addBreak(.@"break", block_inst, operand);
   1603 
   1604                 if (block_gz.break_result_loc == .block_ptr) {
   1605                     try block_gz.labeled_breaks.append(astgen.gpa, br);
   1606 
   1607                     if (have_store_to_block) {
   1608                         const zir_tags = parent_gz.astgen.instructions.items(.tag);
   1609                         const zir_datas = parent_gz.astgen.instructions.items(.data);
   1610                         const store_inst = @intCast(u32, zir_tags.len - 2);
   1611                         assert(zir_tags[store_inst] == .store_to_block_ptr);
   1612                         assert(zir_datas[store_inst].bin.lhs == block_gz.rl_ptr);
   1613                         try block_gz.labeled_store_to_block_ptr_list.append(astgen.gpa, store_inst);
   1614                     }
   1615                 }
   1616                 return Zir.Inst.Ref.unreachable_value;
   1617             },
   1618             .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
   1619             .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
   1620             .namespace => break,
   1621             .defer_normal => {
   1622                 const defer_scope = scope.cast(Scope.Defer).?;
   1623                 scope = defer_scope.parent;
   1624                 const expr_node = node_datas[defer_scope.defer_node].rhs;
   1625                 _ = try unusedResultExpr(parent_gz, defer_scope.parent, expr_node);
   1626             },
   1627             .defer_error => scope = scope.cast(Scope.Defer).?.parent,
   1628             .top => unreachable,
   1629         }
   1630     }
   1631     if (break_label != 0) {
   1632         const label_name = try astgen.identifierTokenString(break_label);
   1633         return astgen.failTok(break_label, "label not found: '{s}'", .{label_name});
   1634     } else {
   1635         return astgen.failNode(node, "break expression outside loop", .{});
   1636     }
   1637 }
   1638 
   1639 fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
   1640     const astgen = parent_gz.astgen;
   1641     const tree = astgen.tree;
   1642     const node_datas = tree.nodes.items(.data);
   1643     const break_label = node_datas[node].lhs;
   1644 
   1645     // Look for the label in the scope.
   1646     var scope = parent_scope;
   1647     while (true) {
   1648         switch (scope.tag) {
   1649             .gen_zir => {
   1650                 const gen_zir = scope.cast(GenZir).?;
   1651                 const continue_block = gen_zir.continue_block;
   1652                 if (continue_block == 0) {
   1653                     scope = gen_zir.parent;
   1654                     continue;
   1655                 }
   1656                 if (break_label != 0) blk: {
   1657                     if (gen_zir.label) |*label| {
   1658                         if (try astgen.tokenIdentEql(label.token, break_label)) {
   1659                             label.used = true;
   1660                             break :blk;
   1661                         }
   1662                     }
   1663                     // found continue but either it has a different label, or no label
   1664                     scope = gen_zir.parent;
   1665                     continue;
   1666                 }
   1667 
   1668                 // TODO emit a break_inline if the loop being continued is inline
   1669                 _ = try parent_gz.addBreak(.@"break", continue_block, .void_value);
   1670                 return Zir.Inst.Ref.unreachable_value;
   1671             },
   1672             .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
   1673             .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
   1674             .defer_normal => {
   1675                 const defer_scope = scope.cast(Scope.Defer).?;
   1676                 scope = defer_scope.parent;
   1677                 const expr_node = node_datas[defer_scope.defer_node].rhs;
   1678                 _ = try unusedResultExpr(parent_gz, defer_scope.parent, expr_node);
   1679             },
   1680             .defer_error => scope = scope.cast(Scope.Defer).?.parent,
   1681             .namespace => break,
   1682             .top => unreachable,
   1683         }
   1684     }
   1685     if (break_label != 0) {
   1686         const label_name = try astgen.identifierTokenString(break_label);
   1687         return astgen.failTok(break_label, "label not found: '{s}'", .{label_name});
   1688     } else {
   1689         return astgen.failNode(node, "continue expression outside loop", .{});
   1690     }
   1691 }
   1692 
   1693 fn blockExpr(
   1694     gz: *GenZir,
   1695     scope: *Scope,
   1696     rl: ResultLoc,
   1697     block_node: ast.Node.Index,
   1698     statements: []const ast.Node.Index,
   1699 ) InnerError!Zir.Inst.Ref {
   1700     const tracy = trace(@src());
   1701     defer tracy.end();
   1702 
   1703     const astgen = gz.astgen;
   1704     const tree = astgen.tree;
   1705     const main_tokens = tree.nodes.items(.main_token);
   1706     const token_tags = tree.tokens.items(.tag);
   1707 
   1708     const lbrace = main_tokens[block_node];
   1709     if (token_tags[lbrace - 1] == .colon and
   1710         token_tags[lbrace - 2] == .identifier)
   1711     {
   1712         return labeledBlockExpr(gz, scope, rl, block_node, statements, .block);
   1713     }
   1714 
   1715     try blockExprStmts(gz, scope, statements);
   1716     return rvalue(gz, rl, .void_value, block_node);
   1717 }
   1718 
   1719 fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: ast.TokenIndex) !void {
   1720     // Look for the label in the scope.
   1721     var scope = parent_scope;
   1722     while (true) {
   1723         switch (scope.tag) {
   1724             .gen_zir => {
   1725                 const gen_zir = scope.cast(GenZir).?;
   1726                 if (gen_zir.label) |prev_label| {
   1727                     if (try astgen.tokenIdentEql(label, prev_label.token)) {
   1728                         const label_name = try astgen.identifierTokenString(label);
   1729                         return astgen.failTokNotes(label, "redefinition of label '{s}'", .{
   1730                             label_name,
   1731                         }, &[_]u32{
   1732                             try astgen.errNoteTok(
   1733                                 prev_label.token,
   1734                                 "previous definition here",
   1735                                 .{},
   1736                             ),
   1737                         });
   1738                     }
   1739                 }
   1740                 scope = gen_zir.parent;
   1741             },
   1742             .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
   1743             .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
   1744             .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
   1745             .namespace => break,
   1746             .top => unreachable,
   1747         }
   1748     }
   1749 }
   1750 
   1751 fn labeledBlockExpr(
   1752     gz: *GenZir,
   1753     parent_scope: *Scope,
   1754     rl: ResultLoc,
   1755     block_node: ast.Node.Index,
   1756     statements: []const ast.Node.Index,
   1757     zir_tag: Zir.Inst.Tag,
   1758 ) InnerError!Zir.Inst.Ref {
   1759     const tracy = trace(@src());
   1760     defer tracy.end();
   1761 
   1762     assert(zir_tag == .block);
   1763 
   1764     const astgen = gz.astgen;
   1765     const tree = astgen.tree;
   1766     const main_tokens = tree.nodes.items(.main_token);
   1767     const token_tags = tree.tokens.items(.tag);
   1768 
   1769     const lbrace = main_tokens[block_node];
   1770     const label_token = lbrace - 2;
   1771     assert(token_tags[label_token] == .identifier);
   1772 
   1773     try astgen.checkLabelRedefinition(parent_scope, label_token);
   1774 
   1775     // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct
   1776     // so that break statements can reference it.
   1777     const block_inst = try gz.addBlock(zir_tag, block_node);
   1778     try gz.instructions.append(astgen.gpa, block_inst);
   1779 
   1780     var block_scope = gz.makeSubBlock(parent_scope);
   1781     block_scope.label = GenZir.Label{
   1782         .token = label_token,
   1783         .block_inst = block_inst,
   1784     };
   1785     block_scope.setBreakResultLoc(rl);
   1786     defer block_scope.instructions.deinit(astgen.gpa);
   1787     defer block_scope.labeled_breaks.deinit(astgen.gpa);
   1788     defer block_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);
   1789 
   1790     try blockExprStmts(&block_scope, &block_scope.base, statements);
   1791 
   1792     if (!block_scope.label.?.used) {
   1793         return astgen.failTok(label_token, "unused block label", .{});
   1794     }
   1795 
   1796     const zir_tags = gz.astgen.instructions.items(.tag);
   1797     const zir_datas = gz.astgen.instructions.items(.data);
   1798 
   1799     const strat = rl.strategy(&block_scope);
   1800     switch (strat.tag) {
   1801         .break_void => {
   1802             // The code took advantage of the result location as a pointer.
   1803             // Turn the break instruction operands into void.
   1804             for (block_scope.labeled_breaks.items) |br| {
   1805                 zir_datas[br].@"break".operand = .void_value;
   1806             }
   1807             try block_scope.setBlockBody(block_inst);
   1808 
   1809             return indexToRef(block_inst);
   1810         },
   1811         .break_operand => {
   1812             // All break operands are values that did not use the result location pointer.
   1813             if (strat.elide_store_to_block_ptr_instructions) {
   1814                 for (block_scope.labeled_store_to_block_ptr_list.items) |inst| {
   1815                     // Mark as elided for removal below.
   1816                     assert(zir_tags[inst] == .store_to_block_ptr);
   1817                     zir_datas[inst].bin.lhs = .none;
   1818                 }
   1819                 try block_scope.setBlockBodyEliding(block_inst);
   1820             } else {
   1821                 try block_scope.setBlockBody(block_inst);
   1822             }
   1823             const block_ref = indexToRef(block_inst);
   1824             switch (rl) {
   1825                 .ref => return block_ref,
   1826                 else => return rvalue(gz, rl, block_ref, block_node),
   1827             }
   1828         },
   1829     }
   1830 }
   1831 
   1832 fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Node.Index) !void {
   1833     const astgen = gz.astgen;
   1834     const tree = astgen.tree;
   1835     const node_tags = tree.nodes.items(.tag);
   1836 
   1837     var block_arena = std.heap.ArenaAllocator.init(gz.astgen.gpa);
   1838     defer block_arena.deinit();
   1839 
   1840     var noreturn_src_node: ast.Node.Index = 0;
   1841     var scope = parent_scope;
   1842     for (statements) |statement| {
   1843         if (noreturn_src_node != 0) {
   1844             return astgen.failNodeNotes(
   1845                 statement,
   1846                 "unreachable code",
   1847                 .{},
   1848                 &[_]u32{
   1849                     try astgen.errNoteNode(
   1850                         noreturn_src_node,
   1851                         "control flow is diverted here",
   1852                         .{},
   1853                     ),
   1854                 },
   1855             );
   1856         }
   1857         switch (node_tags[statement]) {
   1858             // zig fmt: off
   1859             .global_var_decl  => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.globalVarDecl(statement)),
   1860             .local_var_decl   => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.localVarDecl(statement)),
   1861             .simple_var_decl  => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.simpleVarDecl(statement)),
   1862             .aligned_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.alignedVarDecl(statement)),
   1863 
   1864             .@"defer"    => scope = try makeDeferScope(scope, statement, &block_arena.allocator, .defer_normal),
   1865             .@"errdefer" => scope = try makeDeferScope(scope, statement, &block_arena.allocator, .defer_error),
   1866 
   1867             .assign => try assign(gz, scope, statement),
   1868 
   1869             .assign_bit_shift_left  => try assignShift(gz, scope, statement, .shl),
   1870             .assign_bit_shift_right => try assignShift(gz, scope, statement, .shr),
   1871 
   1872             .assign_bit_and  => try assignOp(gz, scope, statement, .bit_and),
   1873             .assign_bit_or   => try assignOp(gz, scope, statement, .bit_or),
   1874             .assign_bit_xor  => try assignOp(gz, scope, statement, .xor),
   1875             .assign_div      => try assignOp(gz, scope, statement, .div),
   1876             .assign_sub      => try assignOp(gz, scope, statement, .sub),
   1877             .assign_sub_wrap => try assignOp(gz, scope, statement, .subwrap),
   1878             .assign_mod      => try assignOp(gz, scope, statement, .mod_rem),
   1879             .assign_add      => try assignOp(gz, scope, statement, .add),
   1880             .assign_add_wrap => try assignOp(gz, scope, statement, .addwrap),
   1881             .assign_mul      => try assignOp(gz, scope, statement, .mul),
   1882             .assign_mul_wrap => try assignOp(gz, scope, statement, .mulwrap),
   1883 
   1884             else => noreturn_src_node = try unusedResultExpr(gz, scope, statement),
   1885             // zig fmt: on
   1886         }
   1887     }
   1888 
   1889     try genDefers(gz, parent_scope, scope, .normal_only);
   1890     try checkUsed(gz, parent_scope, scope);
   1891 }
   1892 
   1893 /// Returns AST source node of the thing that is noreturn if the statement is definitely `noreturn`.
   1894 /// Otherwise returns 0.
   1895 fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) InnerError!ast.Node.Index {
   1896     try emitDbgNode(gz, statement);
   1897     // We need to emit an error if the result is not `noreturn` or `void`, but
   1898     // we want to avoid adding the ZIR instruction if possible for performance.
   1899     const maybe_unused_result = try expr(gz, scope, .none, statement);
   1900     var noreturn_src_node: ast.Node.Index = 0;
   1901     const elide_check = if (refToIndex(maybe_unused_result)) |inst| b: {
   1902         // Note that this array becomes invalid after appending more items to it
   1903         // in the above while loop.
   1904         const zir_tags = gz.astgen.instructions.items(.tag);
   1905         switch (zir_tags[inst]) {
   1906             // For some instructions, swap in a slightly different ZIR tag
   1907             // so we can avoid a separate ensure_result_used instruction.
   1908             .call_chkused => unreachable,
   1909             .call => {
   1910                 zir_tags[inst] = .call_chkused;
   1911                 break :b true;
   1912             },
   1913 
   1914             // ZIR instructions that might be a type other than `noreturn` or `void`.
   1915             .add,
   1916             .addwrap,
   1917             .param,
   1918             .param_comptime,
   1919             .param_anytype,
   1920             .param_anytype_comptime,
   1921             .alloc,
   1922             .alloc_mut,
   1923             .alloc_comptime,
   1924             .alloc_inferred,
   1925             .alloc_inferred_mut,
   1926             .alloc_inferred_comptime,
   1927             .array_cat,
   1928             .array_mul,
   1929             .array_type,
   1930             .array_type_sentinel,
   1931             .vector_type,
   1932             .elem_type,
   1933             .indexable_ptr_len,
   1934             .anyframe_type,
   1935             .as,
   1936             .as_node,
   1937             .bit_and,
   1938             .bitcast,
   1939             .bitcast_result_ptr,
   1940             .bit_or,
   1941             .block,
   1942             .block_inline,
   1943             .suspend_block,
   1944             .loop,
   1945             .bool_br_and,
   1946             .bool_br_or,
   1947             .bool_not,
   1948             .call_compile_time,
   1949             .call_nosuspend,
   1950             .call_async,
   1951             .cmp_lt,
   1952             .cmp_lte,
   1953             .cmp_eq,
   1954             .cmp_gte,
   1955             .cmp_gt,
   1956             .cmp_neq,
   1957             .coerce_result_ptr,
   1958             .decl_ref,
   1959             .decl_val,
   1960             .load,
   1961             .div,
   1962             .elem_ptr,
   1963             .elem_val,
   1964             .elem_ptr_node,
   1965             .elem_val_node,
   1966             .field_ptr,
   1967             .field_val,
   1968             .field_ptr_named,
   1969             .field_val_named,
   1970             .func,
   1971             .func_inferred,
   1972             .int,
   1973             .int_big,
   1974             .float,
   1975             .float128,
   1976             .int_type,
   1977             .is_non_null,
   1978             .is_non_null_ptr,
   1979             .is_non_err,
   1980             .is_non_err_ptr,
   1981             .mod_rem,
   1982             .mul,
   1983             .mulwrap,
   1984             .param_type,
   1985             .ref,
   1986             .shl,
   1987             .shr,
   1988             .str,
   1989             .sub,
   1990             .subwrap,
   1991             .negate,
   1992             .negate_wrap,
   1993             .typeof,
   1994             .typeof_elem,
   1995             .xor,
   1996             .optional_type,
   1997             .optional_payload_safe,
   1998             .optional_payload_unsafe,
   1999             .optional_payload_safe_ptr,
   2000             .optional_payload_unsafe_ptr,
   2001             .err_union_payload_safe,
   2002             .err_union_payload_unsafe,
   2003             .err_union_payload_safe_ptr,
   2004             .err_union_payload_unsafe_ptr,
   2005             .err_union_code,
   2006             .err_union_code_ptr,
   2007             .ptr_type,
   2008             .ptr_type_simple,
   2009             .enum_literal,
   2010             .merge_error_sets,
   2011             .error_union_type,
   2012             .bit_not,
   2013             .error_value,
   2014             .error_to_int,
   2015             .int_to_error,
   2016             .slice_start,
   2017             .slice_end,
   2018             .slice_sentinel,
   2019             .import,
   2020             .switch_block,
   2021             .switch_block_multi,
   2022             .switch_block_else,
   2023             .switch_block_else_multi,
   2024             .switch_block_under,
   2025             .switch_block_under_multi,
   2026             .switch_block_ref,
   2027             .switch_block_ref_multi,
   2028             .switch_block_ref_else,
   2029             .switch_block_ref_else_multi,
   2030             .switch_block_ref_under,
   2031             .switch_block_ref_under_multi,
   2032             .switch_capture,
   2033             .switch_capture_ref,
   2034             .switch_capture_multi,
   2035             .switch_capture_multi_ref,
   2036             .switch_capture_else,
   2037             .switch_capture_else_ref,
   2038             .struct_init_empty,
   2039             .struct_init,
   2040             .struct_init_ref,
   2041             .struct_init_anon,
   2042             .struct_init_anon_ref,
   2043             .array_init,
   2044             .array_init_anon,
   2045             .array_init_ref,
   2046             .array_init_anon_ref,
   2047             .union_init_ptr,
   2048             .field_type,
   2049             .field_type_ref,
   2050             .opaque_decl,
   2051             .opaque_decl_anon,
   2052             .opaque_decl_func,
   2053             .error_set_decl,
   2054             .error_set_decl_anon,
   2055             .error_set_decl_func,
   2056             .int_to_enum,
   2057             .enum_to_int,
   2058             .type_info,
   2059             .size_of,
   2060             .bit_size_of,
   2061             .log2_int_type,
   2062             .typeof_log2_int_type,
   2063             .ptr_to_int,
   2064             .align_of,
   2065             .bool_to_int,
   2066             .embed_file,
   2067             .error_name,
   2068             .sqrt,
   2069             .sin,
   2070             .cos,
   2071             .exp,
   2072             .exp2,
   2073             .log,
   2074             .log2,
   2075             .log10,
   2076             .fabs,
   2077             .floor,
   2078             .ceil,
   2079             .trunc,
   2080             .round,
   2081             .tag_name,
   2082             .reify,
   2083             .type_name,
   2084             .frame_type,
   2085             .frame_size,
   2086             .float_to_int,
   2087             .int_to_float,
   2088             .int_to_ptr,
   2089             .float_cast,
   2090             .int_cast,
   2091             .err_set_cast,
   2092             .ptr_cast,
   2093             .truncate,
   2094             .align_cast,
   2095             .has_decl,
   2096             .has_field,
   2097             .clz,
   2098             .ctz,
   2099             .pop_count,
   2100             .byte_swap,
   2101             .bit_reverse,
   2102             .div_exact,
   2103             .div_floor,
   2104             .div_trunc,
   2105             .mod,
   2106             .rem,
   2107             .shl_exact,
   2108             .shr_exact,
   2109             .bit_offset_of,
   2110             .offset_of,
   2111             .cmpxchg_strong,
   2112             .cmpxchg_weak,
   2113             .splat,
   2114             .reduce,
   2115             .shuffle,
   2116             .select,
   2117             .atomic_load,
   2118             .atomic_rmw,
   2119             .atomic_store,
   2120             .mul_add,
   2121             .builtin_call,
   2122             .field_ptr_type,
   2123             .field_parent_ptr,
   2124             .maximum,
   2125             .memcpy,
   2126             .memset,
   2127             .minimum,
   2128             .builtin_async_call,
   2129             .c_import,
   2130             .@"resume",
   2131             .@"await",
   2132             .await_nosuspend,
   2133             .ret_err_value_code,
   2134             .extended,
   2135             => break :b false,
   2136 
   2137             // ZIR instructions that are always `noreturn`.
   2138             .@"break",
   2139             .break_inline,
   2140             .condbr,
   2141             .condbr_inline,
   2142             .compile_error,
   2143             .ret_node,
   2144             .ret_load,
   2145             .ret_coerce,
   2146             .ret_err_value,
   2147             .@"unreachable",
   2148             .repeat,
   2149             .repeat_inline,
   2150             .panic,
   2151             => {
   2152                 noreturn_src_node = statement;
   2153                 break :b true;
   2154             },
   2155 
   2156             // ZIR instructions that are always `void`.
   2157             .breakpoint,
   2158             .fence,
   2159             .dbg_stmt,
   2160             .ensure_result_used,
   2161             .ensure_result_non_error,
   2162             .@"export",
   2163             .set_eval_branch_quota,
   2164             .ensure_err_payload_void,
   2165             .store,
   2166             .store_node,
   2167             .store_to_block_ptr,
   2168             .store_to_inferred_ptr,
   2169             .resolve_inferred_alloc,
   2170             .validate_struct_init_ptr,
   2171             .validate_array_init_ptr,
   2172             .set_align_stack,
   2173             .set_cold,
   2174             .set_float_mode,
   2175             .set_runtime_safety,
   2176             => break :b true,
   2177         }
   2178     } else switch (maybe_unused_result) {
   2179         .none => unreachable,
   2180 
   2181         .unreachable_value => b: {
   2182             noreturn_src_node = statement;
   2183             break :b true;
   2184         },
   2185 
   2186         .void_value => true,
   2187 
   2188         else => false,
   2189     };
   2190     if (!elide_check) {
   2191         _ = try gz.addUnNode(.ensure_result_used, maybe_unused_result, statement);
   2192     }
   2193     return noreturn_src_node;
   2194 }
   2195 
   2196 fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct {
   2197     have_any: bool,
   2198     have_normal: bool,
   2199     have_err: bool,
   2200     need_err_code: bool,
   2201 } {
   2202     const tree = astgen.tree;
   2203     const node_datas = tree.nodes.items(.data);
   2204 
   2205     var have_normal = false;
   2206     var have_err = false;
   2207     var need_err_code = false;
   2208     var scope = inner_scope;
   2209     while (scope != outer_scope) {
   2210         switch (scope.tag) {
   2211             .gen_zir => scope = scope.cast(GenZir).?.parent,
   2212             .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
   2213             .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
   2214             .defer_normal => {
   2215                 const defer_scope = scope.cast(Scope.Defer).?;
   2216                 scope = defer_scope.parent;
   2217 
   2218                 have_normal = true;
   2219             },
   2220             .defer_error => {
   2221                 const defer_scope = scope.cast(Scope.Defer).?;
   2222                 scope = defer_scope.parent;
   2223 
   2224                 have_err = true;
   2225 
   2226                 const have_err_payload = node_datas[defer_scope.defer_node].lhs != 0;
   2227                 need_err_code = need_err_code or have_err_payload;
   2228             },
   2229             .namespace => unreachable,
   2230             .top => unreachable,
   2231         }
   2232     }
   2233     return .{
   2234         .have_any = have_normal or have_err,
   2235         .have_normal = have_normal,
   2236         .have_err = have_err,
   2237         .need_err_code = need_err_code,
   2238     };
   2239 }
   2240 
   2241 const DefersToEmit = union(enum) {
   2242     both: Zir.Inst.Ref, // err code
   2243     both_sans_err,
   2244     normal_only,
   2245 };
   2246 
   2247 fn genDefers(
   2248     gz: *GenZir,
   2249     outer_scope: *Scope,
   2250     inner_scope: *Scope,
   2251     which_ones: DefersToEmit,
   2252 ) InnerError!void {
   2253     const astgen = gz.astgen;
   2254     const tree = astgen.tree;
   2255     const node_datas = tree.nodes.items(.data);
   2256 
   2257     var scope = inner_scope;
   2258     while (scope != outer_scope) {
   2259         switch (scope.tag) {
   2260             .gen_zir => scope = scope.cast(GenZir).?.parent,
   2261             .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
   2262             .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
   2263             .defer_normal => {
   2264                 const defer_scope = scope.cast(Scope.Defer).?;
   2265                 scope = defer_scope.parent;
   2266                 const expr_node = node_datas[defer_scope.defer_node].rhs;
   2267                 const prev_in_defer = gz.in_defer;
   2268                 gz.in_defer = true;
   2269                 defer gz.in_defer = prev_in_defer;
   2270                 _ = try unusedResultExpr(gz, defer_scope.parent, expr_node);
   2271             },
   2272             .defer_error => {
   2273                 const defer_scope = scope.cast(Scope.Defer).?;
   2274                 scope = defer_scope.parent;
   2275                 switch (which_ones) {
   2276                     .both_sans_err => {
   2277                         const expr_node = node_datas[defer_scope.defer_node].rhs;
   2278                         const prev_in_defer = gz.in_defer;
   2279                         gz.in_defer = true;
   2280                         defer gz.in_defer = prev_in_defer;
   2281                         _ = try unusedResultExpr(gz, defer_scope.parent, expr_node);
   2282                     },
   2283                     .both => |err_code| {
   2284                         const expr_node = node_datas[defer_scope.defer_node].rhs;
   2285                         const payload_token = node_datas[defer_scope.defer_node].lhs;
   2286                         const prev_in_defer = gz.in_defer;
   2287                         gz.in_defer = true;
   2288                         defer gz.in_defer = prev_in_defer;
   2289                         var local_val_scope: Scope.LocalVal = undefined;
   2290                         const sub_scope = if (payload_token == 0) defer_scope.parent else blk: {
   2291                             const ident_name = try astgen.identAsString(payload_token);
   2292                             local_val_scope = .{
   2293                                 .parent = defer_scope.parent,
   2294                                 .gen_zir = gz,
   2295                                 .name = ident_name,
   2296                                 .inst = err_code,
   2297                                 .token_src = payload_token,
   2298                                 .id_cat = .@"capture",
   2299                             };
   2300                             break :blk &local_val_scope.base;
   2301                         };
   2302                         _ = try unusedResultExpr(gz, sub_scope, expr_node);
   2303                     },
   2304                     .normal_only => continue,
   2305                 }
   2306             },
   2307             .namespace => unreachable,
   2308             .top => unreachable,
   2309         }
   2310     }
   2311 }
   2312 
   2313 fn checkUsed(
   2314     gz: *GenZir,
   2315     outer_scope: *Scope,
   2316     inner_scope: *Scope,
   2317 ) InnerError!void {
   2318     const astgen = gz.astgen;
   2319 
   2320     var scope = inner_scope;
   2321     while (scope != outer_scope) {
   2322         switch (scope.tag) {
   2323             .gen_zir => scope = scope.cast(GenZir).?.parent,
   2324             .local_val => {
   2325                 const s = scope.cast(Scope.LocalVal).?;
   2326                 if (!s.used) {
   2327                     return astgen.failTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)});
   2328                 }
   2329                 scope = s.parent;
   2330             },
   2331             .local_ptr => {
   2332                 const s = scope.cast(Scope.LocalPtr).?;
   2333                 if (!s.used) {
   2334                     return astgen.failTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)});
   2335                 }
   2336                 scope = s.parent;
   2337             },
   2338             .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
   2339             .namespace => unreachable,
   2340             .top => unreachable,
   2341         }
   2342     }
   2343 }
   2344 
   2345 fn makeDeferScope(
   2346     scope: *Scope,
   2347     node: ast.Node.Index,
   2348     block_arena: *Allocator,
   2349     scope_tag: Scope.Tag,
   2350 ) InnerError!*Scope {
   2351     const defer_scope = try block_arena.create(Scope.Defer);
   2352     defer_scope.* = .{
   2353         .base = .{ .tag = scope_tag },
   2354         .parent = scope,
   2355         .defer_node = node,
   2356     };
   2357     return &defer_scope.base;
   2358 }
   2359 
   2360 fn varDecl(
   2361     gz: *GenZir,
   2362     scope: *Scope,
   2363     node: ast.Node.Index,
   2364     block_arena: *Allocator,
   2365     var_decl: ast.full.VarDecl,
   2366 ) InnerError!*Scope {
   2367     try emitDbgNode(gz, node);
   2368     const astgen = gz.astgen;
   2369     const gpa = astgen.gpa;
   2370     const tree = astgen.tree;
   2371     const token_tags = tree.tokens.items(.tag);
   2372 
   2373     const name_token = var_decl.ast.mut_token + 1;
   2374     const ident_name_raw = tree.tokenSlice(name_token);
   2375     if (mem.eql(u8, ident_name_raw, "_")) {
   2376         return astgen.failTok(name_token, "'_' used as an identifier without @\"_\" syntax", .{});
   2377     }
   2378     const ident_name = try astgen.identAsString(name_token);
   2379 
   2380     try astgen.detectLocalShadowing(scope, ident_name, name_token, ident_name_raw);
   2381 
   2382     if (var_decl.ast.init_node == 0) {
   2383         return astgen.failNode(node, "variables must be initialized", .{});
   2384     }
   2385 
   2386     const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node != 0)
   2387         try expr(gz, scope, align_rl, var_decl.ast.align_node)
   2388     else
   2389         .none;
   2390 
   2391     switch (token_tags[var_decl.ast.mut_token]) {
   2392         .keyword_const => {
   2393             if (var_decl.comptime_token) |comptime_token| {
   2394                 return astgen.failTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{});
   2395             }
   2396 
   2397             // Depending on the type of AST the initialization expression is, we may need an lvalue
   2398             // or an rvalue as a result location. If it is an rvalue, we can use the instruction as
   2399             // the variable, no memory location needed.
   2400             if (align_inst == .none and !nodeMayNeedMemoryLocation(tree, var_decl.ast.init_node)) {
   2401                 const result_loc: ResultLoc = if (var_decl.ast.type_node != 0) .{
   2402                     .ty = try typeExpr(gz, scope, var_decl.ast.type_node),
   2403                 } else .none;
   2404                 const init_inst = try reachableExpr(gz, scope, result_loc, var_decl.ast.init_node, node);
   2405 
   2406                 const sub_scope = try block_arena.create(Scope.LocalVal);
   2407                 sub_scope.* = .{
   2408                     .parent = scope,
   2409                     .gen_zir = gz,
   2410                     .name = ident_name,
   2411                     .inst = init_inst,
   2412                     .token_src = name_token,
   2413                     .id_cat = .@"local constant",
   2414                 };
   2415                 return &sub_scope.base;
   2416             }
   2417 
   2418             // Detect whether the initialization expression actually uses the
   2419             // result location pointer.
   2420             var init_scope = gz.makeSubBlock(scope);
   2421             defer init_scope.instructions.deinit(gpa);
   2422 
   2423             var resolve_inferred_alloc: Zir.Inst.Ref = .none;
   2424             var opt_type_inst: Zir.Inst.Ref = .none;
   2425             if (var_decl.ast.type_node != 0) {
   2426                 const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node);
   2427                 opt_type_inst = type_inst;
   2428                 if (align_inst == .none) {
   2429                     init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node);
   2430                 } else {
   2431                     init_scope.rl_ptr = try gz.addAllocExtended(.{
   2432                         .node = node,
   2433                         .type_inst = type_inst,
   2434                         .align_inst = align_inst,
   2435                         .is_const = true,
   2436                         .is_comptime = false,
   2437                     });
   2438                 }
   2439                 init_scope.rl_ty_inst = type_inst;
   2440             } else {
   2441                 const alloc = if (align_inst == .none)
   2442                     try init_scope.addNode(.alloc_inferred, node)
   2443                 else
   2444                     try gz.addAllocExtended(.{
   2445                         .node = node,
   2446                         .type_inst = .none,
   2447                         .align_inst = align_inst,
   2448                         .is_const = true,
   2449                         .is_comptime = false,
   2450                     });
   2451                 resolve_inferred_alloc = alloc;
   2452                 init_scope.rl_ptr = alloc;
   2453             }
   2454             const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope };
   2455             const init_inst = try reachableExpr(&init_scope, &init_scope.base, init_result_loc, var_decl.ast.init_node, node);
   2456 
   2457             const zir_tags = astgen.instructions.items(.tag);
   2458             const zir_datas = astgen.instructions.items(.data);
   2459 
   2460             const parent_zir = &gz.instructions;
   2461             if (align_inst == .none and init_scope.rvalue_rl_count == 1) {
   2462                 // Result location pointer not used. We don't need an alloc for this
   2463                 // const local, and type inference becomes trivial.
   2464                 // Move the init_scope instructions into the parent scope, eliding
   2465                 // the alloc instruction and the store_to_block_ptr instruction.
   2466                 try parent_zir.ensureUnusedCapacity(gpa, init_scope.instructions.items.len);
   2467                 for (init_scope.instructions.items) |src_inst| {
   2468                     if (indexToRef(src_inst) == init_scope.rl_ptr) continue;
   2469                     if (zir_tags[src_inst] == .store_to_block_ptr) {
   2470                         if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue;
   2471                     }
   2472                     parent_zir.appendAssumeCapacity(src_inst);
   2473                 }
   2474 
   2475                 const sub_scope = try block_arena.create(Scope.LocalVal);
   2476                 sub_scope.* = .{
   2477                     .parent = scope,
   2478                     .gen_zir = gz,
   2479                     .name = ident_name,
   2480                     .inst = init_inst,
   2481                     .token_src = name_token,
   2482                     .id_cat = .@"local constant",
   2483                 };
   2484                 return &sub_scope.base;
   2485             }
   2486             // The initialization expression took advantage of the result location
   2487             // of the const local. In this case we will create an alloc and a LocalPtr for it.
   2488             // Move the init_scope instructions into the parent scope, swapping
   2489             // store_to_block_ptr for store_to_inferred_ptr.
   2490             const expected_len = parent_zir.items.len + init_scope.instructions.items.len;
   2491             try parent_zir.ensureTotalCapacity(gpa, expected_len);
   2492             for (init_scope.instructions.items) |src_inst| {
   2493                 if (zir_tags[src_inst] == .store_to_block_ptr) {
   2494                     if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) {
   2495                         zir_tags[src_inst] = .store_to_inferred_ptr;
   2496                     }
   2497                 }
   2498                 parent_zir.appendAssumeCapacity(src_inst);
   2499             }
   2500             assert(parent_zir.items.len == expected_len);
   2501             if (resolve_inferred_alloc != .none) {
   2502                 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
   2503             }
   2504             const sub_scope = try block_arena.create(Scope.LocalPtr);
   2505             sub_scope.* = .{
   2506                 .parent = scope,
   2507                 .gen_zir = gz,
   2508                 .name = ident_name,
   2509                 .ptr = init_scope.rl_ptr,
   2510                 .token_src = name_token,
   2511                 .maybe_comptime = true,
   2512                 .id_cat = .@"local constant",
   2513             };
   2514             return &sub_scope.base;
   2515         },
   2516         .keyword_var => {
   2517             const is_comptime = var_decl.comptime_token != null or gz.force_comptime;
   2518             var resolve_inferred_alloc: Zir.Inst.Ref = .none;
   2519             const var_data: struct {
   2520                 result_loc: ResultLoc,
   2521                 alloc: Zir.Inst.Ref,
   2522             } = if (var_decl.ast.type_node != 0) a: {
   2523                 const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node);
   2524                 const alloc = alloc: {
   2525                     if (align_inst == .none) {
   2526                         const tag: Zir.Inst.Tag = if (is_comptime) .alloc_comptime else .alloc_mut;
   2527                         break :alloc try gz.addUnNode(tag, type_inst, node);
   2528                     } else {
   2529                         break :alloc try gz.addAllocExtended(.{
   2530                             .node = node,
   2531                             .type_inst = type_inst,
   2532                             .align_inst = align_inst,
   2533                             .is_const = false,
   2534                             .is_comptime = is_comptime,
   2535                         });
   2536                     }
   2537                 };
   2538                 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };
   2539             } else a: {
   2540                 const alloc = alloc: {
   2541                     if (align_inst == .none) {
   2542                         const tag: Zir.Inst.Tag = if (is_comptime) .alloc_inferred_comptime else .alloc_inferred_mut;
   2543                         break :alloc try gz.addNode(tag, node);
   2544                     } else {
   2545                         break :alloc try gz.addAllocExtended(.{
   2546                             .node = node,
   2547                             .type_inst = .none,
   2548                             .align_inst = align_inst,
   2549                             .is_const = false,
   2550                             .is_comptime = is_comptime,
   2551                         });
   2552                     }
   2553                 };
   2554                 resolve_inferred_alloc = alloc;
   2555                 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };
   2556             };
   2557             _ = try reachableExpr(gz, scope, var_data.result_loc, var_decl.ast.init_node, node);
   2558             if (resolve_inferred_alloc != .none) {
   2559                 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
   2560             }
   2561             const sub_scope = try block_arena.create(Scope.LocalPtr);
   2562             sub_scope.* = .{
   2563                 .parent = scope,
   2564                 .gen_zir = gz,
   2565                 .name = ident_name,
   2566                 .ptr = var_data.alloc,
   2567                 .token_src = name_token,
   2568                 .maybe_comptime = is_comptime,
   2569                 .id_cat = .@"local variable",
   2570             };
   2571             return &sub_scope.base;
   2572         },
   2573         else => unreachable,
   2574     }
   2575 }
   2576 
   2577 fn emitDbgNode(gz: *GenZir, node: ast.Node.Index) !void {
   2578     // The instruction emitted here is for debugging runtime code.
   2579     // If the current block will be evaluated only during semantic analysis
   2580     // then no dbg_stmt ZIR instruction is needed.
   2581     if (gz.force_comptime) return;
   2582 
   2583     const astgen = gz.astgen;
   2584     const tree = astgen.tree;
   2585     const source = tree.source;
   2586     const token_starts = tree.tokens.items(.start);
   2587     const node_start = token_starts[tree.firstToken(node)];
   2588 
   2589     astgen.advanceSourceCursor(source, node_start);
   2590     const line = @intCast(u32, astgen.source_line);
   2591     const column = @intCast(u32, astgen.source_column);
   2592 
   2593     _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{
   2594         .dbg_stmt = .{
   2595             .line = line,
   2596             .column = column,
   2597         },
   2598     } });
   2599 }
   2600 
   2601 fn assign(gz: *GenZir, scope: *Scope, infix_node: ast.Node.Index) InnerError!void {
   2602     try emitDbgNode(gz, infix_node);
   2603     const astgen = gz.astgen;
   2604     const tree = astgen.tree;
   2605     const node_datas = tree.nodes.items(.data);
   2606     const main_tokens = tree.nodes.items(.main_token);
   2607     const node_tags = tree.nodes.items(.tag);
   2608 
   2609     const lhs = node_datas[infix_node].lhs;
   2610     const rhs = node_datas[infix_node].rhs;
   2611     if (node_tags[lhs] == .identifier) {
   2612         // This intentionally does not support `@"_"` syntax.
   2613         const ident_name = tree.tokenSlice(main_tokens[lhs]);
   2614         if (mem.eql(u8, ident_name, "_")) {
   2615             _ = try expr(gz, scope, .discard, rhs);
   2616             return;
   2617         }
   2618     }
   2619     const lvalue = try lvalExpr(gz, scope, lhs);
   2620     _ = try expr(gz, scope, .{ .ptr = lvalue }, rhs);
   2621 }
   2622 
   2623 fn assignOp(
   2624     gz: *GenZir,
   2625     scope: *Scope,
   2626     infix_node: ast.Node.Index,
   2627     op_inst_tag: Zir.Inst.Tag,
   2628 ) InnerError!void {
   2629     try emitDbgNode(gz, infix_node);
   2630     const astgen = gz.astgen;
   2631     const tree = astgen.tree;
   2632     const node_datas = tree.nodes.items(.data);
   2633 
   2634     const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);
   2635     const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node);
   2636     const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node);
   2637     const rhs = try expr(gz, scope, .{ .coerced_ty = lhs_type }, node_datas[infix_node].rhs);
   2638 
   2639     const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{
   2640         .lhs = lhs,
   2641         .rhs = rhs,
   2642     });
   2643     _ = try gz.addBin(.store, lhs_ptr, result);
   2644 }
   2645 
   2646 fn assignShift(
   2647     gz: *GenZir,
   2648     scope: *Scope,
   2649     infix_node: ast.Node.Index,
   2650     op_inst_tag: Zir.Inst.Tag,
   2651 ) InnerError!void {
   2652     try emitDbgNode(gz, infix_node);
   2653     const astgen = gz.astgen;
   2654     const tree = astgen.tree;
   2655     const node_datas = tree.nodes.items(.data);
   2656 
   2657     const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);
   2658     const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node);
   2659     const rhs_type = try gz.addUnNode(.typeof_log2_int_type, lhs, infix_node);
   2660     const rhs = try expr(gz, scope, .{ .ty = rhs_type }, node_datas[infix_node].rhs);
   2661 
   2662     const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{
   2663         .lhs = lhs,
   2664         .rhs = rhs,
   2665     });
   2666     _ = try gz.addBin(.store, lhs_ptr, result);
   2667 }
   2668 
   2669 fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
   2670     const astgen = gz.astgen;
   2671     const tree = astgen.tree;
   2672     const node_datas = tree.nodes.items(.data);
   2673 
   2674     const operand = try expr(gz, scope, bool_rl, node_datas[node].lhs);
   2675     const result = try gz.addUnNode(.bool_not, operand, node);
   2676     return rvalue(gz, rl, result, node);
   2677 }
   2678 
   2679 fn bitNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
   2680     const astgen = gz.astgen;
   2681     const tree = astgen.tree;
   2682     const node_datas = tree.nodes.items(.data);
   2683 
   2684     const operand = try expr(gz, scope, .none, node_datas[node].lhs);
   2685     const result = try gz.addUnNode(.bit_not, operand, node);
   2686     return rvalue(gz, rl, result, node);
   2687 }
   2688 
   2689 fn negation(
   2690     gz: *GenZir,
   2691     scope: *Scope,
   2692     rl: ResultLoc,
   2693     node: ast.Node.Index,
   2694     tag: Zir.Inst.Tag,
   2695 ) InnerError!Zir.Inst.Ref {
   2696     const astgen = gz.astgen;
   2697     const tree = astgen.tree;
   2698     const node_datas = tree.nodes.items(.data);
   2699 
   2700     const operand = try expr(gz, scope, .none, node_datas[node].lhs);
   2701     const result = try gz.addUnNode(tag, operand, node);
   2702     return rvalue(gz, rl, result, node);
   2703 }
   2704 
   2705 fn ptrType(
   2706     gz: *GenZir,
   2707     scope: *Scope,
   2708     rl: ResultLoc,
   2709     node: ast.Node.Index,
   2710     ptr_info: ast.full.PtrType,
   2711 ) InnerError!Zir.Inst.Ref {
   2712     const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type);
   2713 
   2714     const simple = ptr_info.ast.align_node == 0 and
   2715         ptr_info.ast.sentinel == 0 and
   2716         ptr_info.ast.bit_range_start == 0;
   2717 
   2718     if (simple) {
   2719         const result = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
   2720             .ptr_type_simple = .{
   2721                 .is_allowzero = ptr_info.allowzero_token != null,
   2722                 .is_mutable = ptr_info.const_token == null,
   2723                 .is_volatile = ptr_info.volatile_token != null,
   2724                 .size = ptr_info.size,
   2725                 .elem_type = elem_type,
   2726             },
   2727         } });
   2728         return rvalue(gz, rl, result, node);
   2729     }
   2730 
   2731     var sentinel_ref: Zir.Inst.Ref = .none;
   2732     var align_ref: Zir.Inst.Ref = .none;
   2733     var bit_start_ref: Zir.Inst.Ref = .none;
   2734     var bit_end_ref: Zir.Inst.Ref = .none;
   2735     var trailing_count: u32 = 0;
   2736 
   2737     if (ptr_info.ast.sentinel != 0) {
   2738         sentinel_ref = try expr(gz, scope, .{ .ty = elem_type }, ptr_info.ast.sentinel);
   2739         trailing_count += 1;
   2740     }
   2741     if (ptr_info.ast.align_node != 0) {
   2742         align_ref = try expr(gz, scope, align_rl, ptr_info.ast.align_node);
   2743         trailing_count += 1;
   2744     }
   2745     if (ptr_info.ast.bit_range_start != 0) {
   2746         assert(ptr_info.ast.bit_range_end != 0);
   2747         bit_start_ref = try expr(gz, scope, .none, ptr_info.ast.bit_range_start);
   2748         bit_end_ref = try expr(gz, scope, .none, ptr_info.ast.bit_range_end);
   2749         trailing_count += 2;
   2750     }
   2751 
   2752     const gpa = gz.astgen.gpa;
   2753     try gz.instructions.ensureUnusedCapacity(gpa, 1);
   2754     try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
   2755     try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.PtrType).Struct.fields.len +
   2756         trailing_count);
   2757 
   2758     const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.PtrType{ .elem_type = elem_type });
   2759     if (sentinel_ref != .none) {
   2760         gz.astgen.extra.appendAssumeCapacity(@enumToInt(sentinel_ref));
   2761     }
   2762     if (align_ref != .none) {
   2763         gz.astgen.extra.appendAssumeCapacity(@enumToInt(align_ref));
   2764     }
   2765     if (bit_start_ref != .none) {
   2766         gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_start_ref));
   2767         gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_end_ref));
   2768     }
   2769 
   2770     const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
   2771     const result = indexToRef(new_index);
   2772     gz.astgen.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{
   2773         .ptr_type = .{
   2774             .flags = .{
   2775                 .is_allowzero = ptr_info.allowzero_token != null,
   2776                 .is_mutable = ptr_info.const_token == null,
   2777                 .is_volatile = ptr_info.volatile_token != null,
   2778                 .has_sentinel = sentinel_ref != .none,
   2779                 .has_align = align_ref != .none,
   2780                 .has_bit_range = bit_start_ref != .none,
   2781             },
   2782             .size = ptr_info.size,
   2783             .payload_index = payload_index,
   2784         },
   2785     } });
   2786     gz.instructions.appendAssumeCapacity(new_index);
   2787 
   2788     return rvalue(gz, rl, result, node);
   2789 }
   2790 
   2791 fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {
   2792     const astgen = gz.astgen;
   2793     const tree = astgen.tree;
   2794     const node_datas = tree.nodes.items(.data);
   2795     const node_tags = tree.nodes.items(.tag);
   2796     const main_tokens = tree.nodes.items(.main_token);
   2797 
   2798     const len_node = node_datas[node].lhs;
   2799     if (node_tags[len_node] == .identifier and
   2800         mem.eql(u8, tree.tokenSlice(main_tokens[len_node]), "_"))
   2801     {
   2802         return astgen.failNode(len_node, "unable to infer array size", .{});
   2803     }
   2804     const len = try expr(gz, scope, .{ .coerced_ty = .usize_type }, len_node);
   2805     const elem_type = try typeExpr(gz, scope, node_datas[node].rhs);
   2806 
   2807     const result = try gz.addBin(.array_type, len, elem_type);
   2808     return rvalue(gz, rl, result, node);
   2809 }
   2810 
   2811 fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {
   2812     const astgen = gz.astgen;
   2813     const tree = astgen.tree;
   2814     const node_datas = tree.nodes.items(.data);
   2815     const node_tags = tree.nodes.items(.tag);
   2816     const main_tokens = tree.nodes.items(.main_token);
   2817     const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel);
   2818 
   2819     const len_node = node_datas[node].lhs;
   2820     if (node_tags[len_node] == .identifier and
   2821         mem.eql(u8, tree.tokenSlice(main_tokens[len_node]), "_"))
   2822     {
   2823         return astgen.failNode(len_node, "unable to infer array size", .{});
   2824     }
   2825     const len = try expr(gz, scope, .{ .coerced_ty = .usize_type }, len_node);
   2826     const elem_type = try typeExpr(gz, scope, extra.elem_type);
   2827     const sentinel = try expr(gz, scope, .{ .coerced_ty = elem_type }, extra.sentinel);
   2828 
   2829     const result = try gz.addArrayTypeSentinel(len, elem_type, sentinel);
   2830     return rvalue(gz, rl, result, node);
   2831 }
   2832 
   2833 const WipDecls = struct {
   2834     decl_index: usize = 0,
   2835     cur_bit_bag: u32 = 0,
   2836     bit_bag: ArrayListUnmanaged(u32) = .{},
   2837     payload: ArrayListUnmanaged(u32) = .{},
   2838 
   2839     const bits_per_field = 4;
   2840     const fields_per_u32 = 32 / bits_per_field;
   2841 
   2842     fn next(
   2843         wip_decls: *WipDecls,
   2844         gpa: *Allocator,
   2845         is_pub: bool,
   2846         is_export: bool,
   2847         has_align: bool,
   2848         has_section: bool,
   2849     ) Allocator.Error!void {
   2850         if (wip_decls.decl_index % fields_per_u32 == 0 and wip_decls.decl_index != 0) {
   2851             try wip_decls.bit_bag.append(gpa, wip_decls.cur_bit_bag);
   2852             wip_decls.cur_bit_bag = 0;
   2853         }
   2854         wip_decls.cur_bit_bag = (wip_decls.cur_bit_bag >> bits_per_field) |
   2855             (@as(u32, @boolToInt(is_pub)) << 28) |
   2856             (@as(u32, @boolToInt(is_export)) << 29) |
   2857             (@as(u32, @boolToInt(has_align)) << 30) |
   2858             (@as(u32, @boolToInt(has_section)) << 31);
   2859         wip_decls.decl_index += 1;
   2860     }
   2861 
   2862     fn deinit(wip_decls: *WipDecls, gpa: *Allocator) void {
   2863         wip_decls.bit_bag.deinit(gpa);
   2864         wip_decls.payload.deinit(gpa);
   2865     }
   2866 };
   2867 
   2868 fn fnDecl(
   2869     astgen: *AstGen,
   2870     gz: *GenZir,
   2871     scope: *Scope,
   2872     wip_decls: *WipDecls,
   2873     decl_node: ast.Node.Index,
   2874     body_node: ast.Node.Index,
   2875     fn_proto: ast.full.FnProto,
   2876 ) InnerError!void {
   2877     const gpa = astgen.gpa;
   2878     const tree = astgen.tree;
   2879     const token_tags = tree.tokens.items(.tag);
   2880 
   2881     const fn_name_token = fn_proto.name_token orelse {
   2882         return astgen.failTok(fn_proto.ast.fn_token, "missing function name", .{});
   2883     };
   2884     const fn_name_str_index = try astgen.identAsString(fn_name_token);
   2885 
   2886     // We insert this at the beginning so that its instruction index marks the
   2887     // start of the top level declaration.
   2888     const block_inst = try gz.addBlock(.block_inline, fn_proto.ast.proto_node);
   2889 
   2890     var decl_gz: GenZir = .{
   2891         .force_comptime = true,
   2892         .in_defer = false,
   2893         .decl_node_index = fn_proto.ast.proto_node,
   2894         .decl_line = gz.calcLine(decl_node),
   2895         .parent = scope,
   2896         .astgen = astgen,
   2897     };
   2898     defer decl_gz.instructions.deinit(gpa);
   2899 
   2900     var fn_gz: GenZir = .{
   2901         .force_comptime = false,
   2902         .in_defer = false,
   2903         .decl_node_index = fn_proto.ast.proto_node,
   2904         .decl_line = decl_gz.decl_line,
   2905         .parent = &decl_gz.base,
   2906         .astgen = astgen,
   2907     };
   2908     defer fn_gz.instructions.deinit(gpa);
   2909 
   2910     // TODO: support noinline
   2911     const is_pub = fn_proto.visib_token != null;
   2912     const is_export = blk: {
   2913         const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false;
   2914         break :blk token_tags[maybe_export_token] == .keyword_export;
   2915     };
   2916     const is_extern = blk: {
   2917         const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false;
   2918         break :blk token_tags[maybe_extern_token] == .keyword_extern;
   2919     };
   2920     const has_inline_keyword = blk: {
   2921         const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false;
   2922         break :blk token_tags[maybe_inline_token] == .keyword_inline;
   2923     };
   2924     try wip_decls.next(gpa, is_pub, is_export, fn_proto.ast.align_expr != 0, fn_proto.ast.section_expr != 0);
   2925 
   2926     var params_scope = &fn_gz.base;
   2927     const is_var_args = is_var_args: {
   2928         var param_type_i: usize = 0;
   2929         var it = fn_proto.iterate(tree.*);
   2930         while (it.next()) |param| : (param_type_i += 1) {
   2931             const is_comptime = if (param.comptime_noalias) |token|
   2932                 token_tags[token] == .keyword_comptime
   2933             else
   2934                 false;
   2935 
   2936             const is_anytype = if (param.anytype_ellipsis3) |token| blk: {
   2937                 switch (token_tags[token]) {
   2938                     .keyword_anytype => break :blk true,
   2939                     .ellipsis3 => break :is_var_args true,
   2940                     else => unreachable,
   2941                 }
   2942             } else false;
   2943 
   2944             const param_name: u32 = if (param.name_token) |name_token| blk: {
   2945                 const name_bytes = tree.tokenSlice(name_token);
   2946                 if (mem.eql(u8, "_", name_bytes))
   2947                     break :blk 0;
   2948 
   2949                 const param_name = try astgen.identAsString(name_token);
   2950                 if (!is_extern) {
   2951                     try astgen.detectLocalShadowing(params_scope, param_name, name_token, name_bytes);
   2952                 }
   2953                 break :blk param_name;
   2954             } else if (!is_extern) {
   2955                 if (param.anytype_ellipsis3) |tok| {
   2956                     return astgen.failTok(tok, "missing parameter name", .{});
   2957                 } else {
   2958                     return astgen.failNode(param.type_expr, "missing parameter name", .{});
   2959                 }
   2960             } else 0;
   2961 
   2962             const param_inst = if (is_anytype) param: {
   2963                 const name_token = param.name_token orelse param.anytype_ellipsis3.?;
   2964                 const tag: Zir.Inst.Tag = if (is_comptime)
   2965                     .param_anytype_comptime
   2966                 else
   2967                     .param_anytype;
   2968                 break :param try decl_gz.addStrTok(tag, param_name, name_token);
   2969             } else param: {
   2970                 const param_type_node = param.type_expr;
   2971                 assert(param_type_node != 0);
   2972                 var param_gz = decl_gz.makeSubBlock(scope);
   2973                 defer param_gz.instructions.deinit(gpa);
   2974                 const param_type = try expr(&param_gz, params_scope, coerced_type_rl, param_type_node);
   2975                 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);
   2976                 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type);
   2977 
   2978                 const main_tokens = tree.nodes.items(.main_token);
   2979                 const name_token = param.name_token orelse main_tokens[param_type_node];
   2980                 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
   2981                 const param_inst = try decl_gz.addParam(tag, name_token, param_name, param_gz.instructions.items);
   2982                 assert(param_inst_expected == param_inst);
   2983                 break :param indexToRef(param_inst);
   2984             };
   2985 
   2986             if (param_name == 0) continue;
   2987 
   2988             const sub_scope = try astgen.arena.create(Scope.LocalVal);
   2989             sub_scope.* = .{
   2990                 .parent = params_scope,
   2991                 .gen_zir = &decl_gz,
   2992                 .name = param_name,
   2993                 .inst = param_inst,
   2994                 .token_src = param.name_token.?,
   2995                 .id_cat = .@"function parameter",
   2996             };
   2997             params_scope = &sub_scope.base;
   2998         }
   2999         break :is_var_args false;
   3000     };
   3001 
   3002     const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: {
   3003         const lib_name_str = try astgen.strLitAsString(lib_name_token);
   3004         break :blk lib_name_str.index;
   3005     } else 0;
   3006 
   3007     const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
   3008     const is_inferred_error = token_tags[maybe_bang] == .bang;
   3009 
   3010     const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
   3011         break :inst try expr(&decl_gz, params_scope, align_rl, fn_proto.ast.align_expr);
   3012     };
   3013     const section_inst: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: {
   3014         break :inst try comptimeExpr(&decl_gz, params_scope, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr);
   3015     };
   3016 
   3017     var ret_gz = decl_gz.makeSubBlock(params_scope);
   3018     defer ret_gz.instructions.deinit(gpa);
   3019     const ret_ty = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type);
   3020     const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
   3021 
   3022     const cc: Zir.Inst.Ref = blk: {
   3023         if (fn_proto.ast.callconv_expr != 0) {
   3024             if (has_inline_keyword) {
   3025                 return astgen.failNode(
   3026                     fn_proto.ast.callconv_expr,
   3027                     "explicit callconv incompatible with inline keyword",
   3028                     .{},
   3029                 );
   3030             }
   3031             break :blk try expr(
   3032                 &decl_gz,
   3033                 params_scope,
   3034                 .{ .ty = .calling_convention_type },
   3035                 fn_proto.ast.callconv_expr,
   3036             );
   3037         } else if (is_extern) {
   3038             // note: https://github.com/ziglang/zig/issues/5269
   3039             break :blk .calling_convention_c;
   3040         } else if (has_inline_keyword) {
   3041             break :blk .calling_convention_inline;
   3042         } else {
   3043             break :blk .none;
   3044         }
   3045     };
   3046 
   3047     const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {
   3048         if (!is_extern) {
   3049             return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{});
   3050         }
   3051         if (is_inferred_error) {
   3052             return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
   3053         }
   3054         break :func try decl_gz.addFunc(.{
   3055             .src_node = decl_node,
   3056             .ret_ty = ret_gz.instructions.items,
   3057             .ret_br = ret_br,
   3058             .param_block = block_inst,
   3059             .body = &[0]Zir.Inst.Index{},
   3060             .cc = cc,
   3061             .align_inst = .none, // passed in the per-decl data
   3062             .lib_name = lib_name,
   3063             .is_var_args = is_var_args,
   3064             .is_inferred_error = false,
   3065             .is_test = false,
   3066             .is_extern = true,
   3067         });
   3068     } else func: {
   3069         if (is_var_args) {
   3070             return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{});
   3071         }
   3072 
   3073         const prev_fn_block = astgen.fn_block;
   3074         astgen.fn_block = &fn_gz;
   3075         defer astgen.fn_block = prev_fn_block;
   3076 
   3077         _ = try expr(&fn_gz, params_scope, .none, body_node);
   3078         try checkUsed(gz, &fn_gz.base, params_scope);
   3079 
   3080         const need_implicit_ret = blk: {
   3081             if (fn_gz.instructions.items.len == 0)
   3082                 break :blk true;
   3083             const last = fn_gz.instructions.items[fn_gz.instructions.items.len - 1];
   3084             const zir_tags = astgen.instructions.items(.tag);
   3085             break :blk !zir_tags[last].isNoReturn();
   3086         };
   3087         if (need_implicit_ret) {
   3088             // Since we are adding the return instruction here, we must handle the coercion.
   3089             // We do this by using the `ret_coerce` instruction.
   3090             _ = try fn_gz.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
   3091         }
   3092 
   3093         break :func try decl_gz.addFunc(.{
   3094             .src_node = decl_node,
   3095             .param_block = block_inst,
   3096             .ret_ty = ret_gz.instructions.items,
   3097             .ret_br = ret_br,
   3098             .body = fn_gz.instructions.items,
   3099             .cc = cc,
   3100             .align_inst = .none, // passed in the per-decl data
   3101             .lib_name = lib_name,
   3102             .is_var_args = is_var_args,
   3103             .is_inferred_error = is_inferred_error,
   3104             .is_test = false,
   3105             .is_extern = false,
   3106         });
   3107     };
   3108 
   3109     // We add this at the end so that its instruction index marks the end range
   3110     // of the top level declaration.
   3111     _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst);
   3112     try decl_gz.setBlockBody(block_inst);
   3113 
   3114     try wip_decls.payload.ensureUnusedCapacity(gpa, 9);
   3115     {
   3116         const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
   3117         const casted = @bitCast([4]u32, contents_hash);
   3118         wip_decls.payload.appendSliceAssumeCapacity(&casted);
   3119     }
   3120     {
   3121         const line_delta = decl_gz.decl_line - gz.decl_line;
   3122         wip_decls.payload.appendAssumeCapacity(line_delta);
   3123     }
   3124     wip_decls.payload.appendAssumeCapacity(fn_name_str_index);
   3125     wip_decls.payload.appendAssumeCapacity(block_inst);
   3126     if (align_inst != .none) {
   3127         wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst));
   3128     }
   3129     if (section_inst != .none) {
   3130         wip_decls.payload.appendAssumeCapacity(@enumToInt(section_inst));
   3131     }
   3132 }
   3133 
   3134 fn globalVarDecl(
   3135     astgen: *AstGen,
   3136     gz: *GenZir,
   3137     scope: *Scope,
   3138     wip_decls: *WipDecls,
   3139     node: ast.Node.Index,
   3140     var_decl: ast.full.VarDecl,
   3141 ) InnerError!void {
   3142     const gpa = astgen.gpa;
   3143     const tree = astgen.tree;
   3144     const token_tags = tree.tokens.items(.tag);
   3145 
   3146     const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
   3147     // We do this at the beginning so that the instruction index marks the range start
   3148     // of the top level declaration.
   3149     const block_inst = try gz.addBlock(.block_inline, node);
   3150 
   3151     const name_token = var_decl.ast.mut_token + 1;
   3152     const name_str_index = try astgen.identAsString(name_token);
   3153 
   3154     var block_scope: GenZir = .{
   3155         .parent = scope,
   3156         .decl_node_index = node,
   3157         .decl_line = gz.calcLine(node),
   3158         .astgen = astgen,
   3159         .force_comptime = true,
   3160         .in_defer = false,
   3161         .anon_name_strategy = .parent,
   3162     };
   3163     defer block_scope.instructions.deinit(gpa);
   3164 
   3165     const is_pub = var_decl.visib_token != null;
   3166     const is_export = blk: {
   3167         const maybe_export_token = var_decl.extern_export_token orelse break :blk false;
   3168         break :blk token_tags[maybe_export_token] == .keyword_export;
   3169     };
   3170     const is_extern = blk: {
   3171         const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
   3172         break :blk token_tags[maybe_extern_token] == .keyword_extern;
   3173     };
   3174     const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node == 0) .none else inst: {
   3175         break :inst try expr(&block_scope, &block_scope.base, align_rl, var_decl.ast.align_node);
   3176     };
   3177     const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: {
   3178         break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .ty = .const_slice_u8_type }, var_decl.ast.section_node);
   3179     };
   3180     try wip_decls.next(gpa, is_pub, is_export, align_inst != .none, section_inst != .none);
   3181 
   3182     const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: {
   3183         if (!is_mutable) {
   3184             return astgen.failTok(tok, "threadlocal variable cannot be constant", .{});
   3185         }
   3186         break :blk true;
   3187     } else false;
   3188 
   3189     const lib_name: u32 = if (var_decl.lib_name) |lib_name_token| blk: {
   3190         const lib_name_str = try astgen.strLitAsString(lib_name_token);
   3191         break :blk lib_name_str.index;
   3192     } else 0;
   3193 
   3194     assert(var_decl.comptime_token == null); // handled by parser
   3195 
   3196     const var_inst: Zir.Inst.Ref = if (var_decl.ast.init_node != 0) vi: {
   3197         if (is_extern) {
   3198             return astgen.failNode(
   3199                 var_decl.ast.init_node,
   3200                 "extern variables have no initializers",
   3201                 .{},
   3202             );
   3203         }
   3204 
   3205         const type_inst: Zir.Inst.Ref = if (var_decl.ast.type_node != 0)
   3206             try expr(
   3207                 &block_scope,
   3208                 &block_scope.base,
   3209                 .{ .ty = .type_type },
   3210                 var_decl.ast.type_node,
   3211             )
   3212         else
   3213             .none;
   3214 
   3215         const init_inst = try expr(
   3216             &block_scope,
   3217             &block_scope.base,
   3218             if (type_inst != .none) .{ .ty = type_inst } else .none,
   3219             var_decl.ast.init_node,
   3220         );
   3221 
   3222         if (is_mutable) {
   3223             const var_inst = try block_scope.addVar(.{
   3224                 .var_type = type_inst,
   3225                 .lib_name = 0,
   3226                 .align_inst = .none, // passed via the decls data
   3227                 .init = init_inst,
   3228                 .is_extern = false,
   3229                 .is_threadlocal = is_threadlocal,
   3230             });
   3231             break :vi var_inst;
   3232         } else {
   3233             break :vi init_inst;
   3234         }
   3235     } else if (!is_extern) {
   3236         return astgen.failNode(node, "variables must be initialized", .{});
   3237     } else if (var_decl.ast.type_node != 0) vi: {
   3238         // Extern variable which has an explicit type.
   3239         const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node);
   3240 
   3241         const var_inst = try block_scope.addVar(.{
   3242             .var_type = type_inst,
   3243             .lib_name = lib_name,
   3244             .align_inst = .none, // passed via the decls data
   3245             .init = .none,
   3246             .is_extern = true,
   3247             .is_threadlocal = is_threadlocal,
   3248         });
   3249         break :vi var_inst;
   3250     } else {
   3251         return astgen.failNode(node, "unable to infer variable type", .{});
   3252     };
   3253     // We do this at the end so that the instruction index marks the end
   3254     // range of a top level declaration.
   3255     _ = try block_scope.addBreak(.break_inline, block_inst, var_inst);
   3256     try block_scope.setBlockBody(block_inst);
   3257 
   3258     try wip_decls.payload.ensureUnusedCapacity(gpa, 9);
   3259     {
   3260         const contents_hash = std.zig.hashSrc(tree.getNodeSource(node));
   3261         const casted = @bitCast([4]u32, contents_hash);
   3262         wip_decls.payload.appendSliceAssumeCapacity(&casted);
   3263     }
   3264     {
   3265         const line_delta = block_scope.decl_line - gz.decl_line;
   3266         wip_decls.payload.appendAssumeCapacity(line_delta);
   3267     }
   3268     wip_decls.payload.appendAssumeCapacity(name_str_index);
   3269     wip_decls.payload.appendAssumeCapacity(block_inst);
   3270     if (align_inst != .none) {
   3271         wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst));
   3272     }
   3273     if (section_inst != .none) {
   3274         wip_decls.payload.appendAssumeCapacity(@enumToInt(section_inst));
   3275     }
   3276 }
   3277 
   3278 fn comptimeDecl(
   3279     astgen: *AstGen,
   3280     gz: *GenZir,
   3281     scope: *Scope,
   3282     wip_decls: *WipDecls,
   3283     node: ast.Node.Index,
   3284 ) InnerError!void {
   3285     const gpa = astgen.gpa;
   3286     const tree = astgen.tree;
   3287     const node_datas = tree.nodes.items(.data);
   3288     const body_node = node_datas[node].lhs;
   3289 
   3290     // Up top so the ZIR instruction index marks the start range of this
   3291     // top-level declaration.
   3292     const block_inst = try gz.addBlock(.block_inline, node);
   3293     try wip_decls.next(gpa, false, false, false, false);
   3294 
   3295     var decl_block: GenZir = .{
   3296         .force_comptime = true,
   3297         .in_defer = false,
   3298         .decl_node_index = node,
   3299         .decl_line = gz.calcLine(node),
   3300         .parent = scope,
   3301         .astgen = astgen,
   3302     };
   3303     defer decl_block.instructions.deinit(gpa);
   3304 
   3305     const block_result = try expr(&decl_block, &decl_block.base, .none, body_node);
   3306     if (decl_block.instructions.items.len == 0 or !decl_block.refIsNoReturn(block_result)) {
   3307         _ = try decl_block.addBreak(.break_inline, block_inst, .void_value);
   3308     }
   3309     try decl_block.setBlockBody(block_inst);
   3310 
   3311     try wip_decls.payload.ensureUnusedCapacity(gpa, 7);
   3312     {
   3313         const contents_hash = std.zig.hashSrc(tree.getNodeSource(node));
   3314         const casted = @bitCast([4]u32, contents_hash);
   3315         wip_decls.payload.appendSliceAssumeCapacity(&casted);
   3316     }
   3317     {
   3318         const line_delta = decl_block.decl_line - gz.decl_line;
   3319         wip_decls.payload.appendAssumeCapacity(line_delta);
   3320     }
   3321     wip_decls.payload.appendAssumeCapacity(0);
   3322     wip_decls.payload.appendAssumeCapacity(block_inst);
   3323 }
   3324 
   3325 fn usingnamespaceDecl(
   3326     astgen: *AstGen,
   3327     gz: *GenZir,
   3328     scope: *Scope,
   3329     wip_decls: *WipDecls,
   3330     node: ast.Node.Index,
   3331 ) InnerError!void {
   3332     const gpa = astgen.gpa;
   3333     const tree = astgen.tree;
   3334     const node_datas = tree.nodes.items(.data);
   3335 
   3336     const type_expr = node_datas[node].lhs;
   3337     const is_pub = blk: {
   3338         const main_tokens = tree.nodes.items(.main_token);
   3339         const token_tags = tree.tokens.items(.tag);
   3340         const main_token = main_tokens[node];
   3341         break :blk (main_token > 0 and token_tags[main_token - 1] == .keyword_pub);
   3342     };
   3343     // Up top so the ZIR instruction index marks the start range of this
   3344     // top-level declaration.
   3345     const block_inst = try gz.addBlock(.block_inline, node);
   3346     try wip_decls.next(gpa, is_pub, true, false, false);
   3347 
   3348     var decl_block: GenZir = .{
   3349         .force_comptime = true,
   3350         .in_defer = false,
   3351         .decl_node_index = node,
   3352         .decl_line = gz.calcLine(node),
   3353         .parent = scope,
   3354         .astgen = astgen,
   3355     };
   3356     defer decl_block.instructions.deinit(gpa);
   3357 
   3358     const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);
   3359     _ = try decl_block.addBreak(.break_inline, block_inst, namespace_inst);
   3360     try decl_block.setBlockBody(block_inst);
   3361 
   3362     try wip_decls.payload.ensureUnusedCapacity(gpa, 7);
   3363     {
   3364         const contents_hash = std.zig.hashSrc(tree.getNodeSource(node));
   3365         const casted = @bitCast([4]u32, contents_hash);
   3366         wip_decls.payload.appendSliceAssumeCapacity(&casted);
   3367     }
   3368     {
   3369         const line_delta = decl_block.decl_line - gz.decl_line;
   3370         wip_decls.payload.appendAssumeCapacity(line_delta);
   3371     }
   3372     wip_decls.payload.appendAssumeCapacity(0);
   3373     wip_decls.payload.appendAssumeCapacity(block_inst);
   3374 }
   3375 
   3376 fn testDecl(
   3377     astgen: *AstGen,
   3378     gz: *GenZir,
   3379     scope: *Scope,
   3380     wip_decls: *WipDecls,
   3381     node: ast.Node.Index,
   3382 ) InnerError!void {
   3383     const gpa = astgen.gpa;
   3384     const tree = astgen.tree;
   3385     const node_datas = tree.nodes.items(.data);
   3386     const body_node = node_datas[node].rhs;
   3387 
   3388     // Up top so the ZIR instruction index marks the start range of this
   3389     // top-level declaration.
   3390     const block_inst = try gz.addBlock(.block_inline, node);
   3391 
   3392     try wip_decls.next(gpa, false, false, false, false);
   3393 
   3394     var decl_block: GenZir = .{
   3395         .force_comptime = true,
   3396         .in_defer = false,
   3397         .decl_node_index = node,
   3398         .decl_line = gz.calcLine(node),
   3399         .parent = scope,
   3400         .astgen = astgen,
   3401     };
   3402     defer decl_block.instructions.deinit(gpa);
   3403 
   3404     const test_name: u32 = blk: {
   3405         const main_tokens = tree.nodes.items(.main_token);
   3406         const token_tags = tree.tokens.items(.tag);
   3407         const test_token = main_tokens[node];
   3408         const str_lit_token = test_token + 1;
   3409         if (token_tags[str_lit_token] == .string_literal) {
   3410             break :blk try astgen.testNameString(str_lit_token);
   3411         }
   3412         // String table index 1 has a special meaning here of test decl with no name.
   3413         break :blk 1;
   3414     };
   3415 
   3416     var fn_block: GenZir = .{
   3417         .force_comptime = false,
   3418         .in_defer = false,
   3419         .decl_node_index = node,
   3420         .decl_line = decl_block.decl_line,
   3421         .parent = &decl_block.base,
   3422         .astgen = astgen,
   3423     };
   3424     defer fn_block.instructions.deinit(gpa);
   3425 
   3426     const prev_fn_block = astgen.fn_block;
   3427     astgen.fn_block = &fn_block;
   3428     defer astgen.fn_block = prev_fn_block;
   3429 
   3430     const block_result = try expr(&fn_block, &fn_block.base, .none, body_node);
   3431     if (fn_block.instructions.items.len == 0 or !fn_block.refIsNoReturn(block_result)) {
   3432         // Since we are adding the return instruction here, we must handle the coercion.
   3433         // We do this by using the `ret_coerce` instruction.
   3434         _ = try fn_block.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
   3435     }
   3436 
   3437     const func_inst = try decl_block.addFunc(.{
   3438         .src_node = node,
   3439         .param_block = block_inst,
   3440         .ret_ty = &.{},
   3441         .ret_br = 0,
   3442         .body = fn_block.instructions.items,
   3443         .cc = .none,
   3444         .align_inst = .none,
   3445         .lib_name = 0,
   3446         .is_var_args = false,
   3447         .is_inferred_error = true,
   3448         .is_test = true,
   3449         .is_extern = false,
   3450     });
   3451 
   3452     _ = try decl_block.addBreak(.break_inline, block_inst, func_inst);
   3453     try decl_block.setBlockBody(block_inst);
   3454 
   3455     try wip_decls.payload.ensureUnusedCapacity(gpa, 7);
   3456     {
   3457         const contents_hash = std.zig.hashSrc(tree.getNodeSource(node));
   3458         const casted = @bitCast([4]u32, contents_hash);
   3459         wip_decls.payload.appendSliceAssumeCapacity(&casted);
   3460     }
   3461     {
   3462         const line_delta = decl_block.decl_line - gz.decl_line;
   3463         wip_decls.payload.appendAssumeCapacity(line_delta);
   3464     }
   3465     wip_decls.payload.appendAssumeCapacity(test_name);
   3466     wip_decls.payload.appendAssumeCapacity(block_inst);
   3467 }
   3468 
   3469 fn structDeclInner(
   3470     gz: *GenZir,
   3471     scope: *Scope,
   3472     node: ast.Node.Index,
   3473     container_decl: ast.full.ContainerDecl,
   3474     layout: std.builtin.TypeInfo.ContainerLayout,
   3475 ) InnerError!Zir.Inst.Ref {
   3476     if (container_decl.ast.members.len == 0) {
   3477         const decl_inst = try gz.reserveInstructionIndex();
   3478         try gz.setStruct(decl_inst, .{
   3479             .src_node = node,
   3480             .layout = layout,
   3481             .fields_len = 0,
   3482             .body_len = 0,
   3483             .decls_len = 0,
   3484             .known_has_bits = false,
   3485         });
   3486         return indexToRef(decl_inst);
   3487     }
   3488 
   3489     const astgen = gz.astgen;
   3490     const gpa = astgen.gpa;
   3491     const tree = astgen.tree;
   3492     const node_tags = tree.nodes.items(.tag);
   3493     const node_datas = tree.nodes.items(.data);
   3494 
   3495     // The struct_decl instruction introduces a scope in which the decls of the struct
   3496     // are in scope, so that field types, alignments, and default value expressions
   3497     // can refer to decls within the struct itself.
   3498     var block_scope: GenZir = .{
   3499         .parent = scope,
   3500         .decl_node_index = node,
   3501         .decl_line = gz.calcLine(node),
   3502         .astgen = astgen,
   3503         .force_comptime = true,
   3504         .in_defer = false,
   3505     };
   3506     defer block_scope.instructions.deinit(gpa);
   3507 
   3508     var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
   3509     defer namespace.decls.deinit(gpa);
   3510 
   3511     try astgen.scanDecls(&namespace, container_decl.ast.members);
   3512 
   3513     var wip_decls: WipDecls = .{};
   3514     defer wip_decls.deinit(gpa);
   3515 
   3516     // We don't know which members are fields until we iterate, so cannot do
   3517     // an accurate ensureCapacity yet.
   3518     var fields_data = ArrayListUnmanaged(u32){};
   3519     defer fields_data.deinit(gpa);
   3520 
   3521     const bits_per_field = 4;
   3522     const fields_per_u32 = 32 / bits_per_field;
   3523     // We only need this if there are greater than fields_per_u32 fields.
   3524     var bit_bag = ArrayListUnmanaged(u32){};
   3525     defer bit_bag.deinit(gpa);
   3526 
   3527     var known_has_bits = false;
   3528     var cur_bit_bag: u32 = 0;
   3529     var field_index: usize = 0;
   3530     for (container_decl.ast.members) |member_node| {
   3531         const member = switch (node_tags[member_node]) {
   3532             .container_field_init => tree.containerFieldInit(member_node),
   3533             .container_field_align => tree.containerFieldAlign(member_node),
   3534             .container_field => tree.containerField(member_node),
   3535 
   3536             .fn_decl => {
   3537                 const fn_proto = node_datas[member_node].lhs;
   3538                 const body = node_datas[member_node].rhs;
   3539                 switch (node_tags[fn_proto]) {
   3540                     .fn_proto_simple => {
   3541                         var params: [1]ast.Node.Index = undefined;
   3542                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(&params, fn_proto)) catch |err| switch (err) {
   3543                             error.OutOfMemory => return error.OutOfMemory,
   3544                             error.AnalysisFail => {},
   3545                         };
   3546                         continue;
   3547                     },
   3548                     .fn_proto_multi => {
   3549                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) {
   3550                             error.OutOfMemory => return error.OutOfMemory,
   3551                             error.AnalysisFail => {},
   3552                         };
   3553                         continue;
   3554                     },
   3555                     .fn_proto_one => {
   3556                         var params: [1]ast.Node.Index = undefined;
   3557                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(&params, fn_proto)) catch |err| switch (err) {
   3558                             error.OutOfMemory => return error.OutOfMemory,
   3559                             error.AnalysisFail => {},
   3560                         };
   3561                         continue;
   3562                     },
   3563                     .fn_proto => {
   3564                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) {
   3565                             error.OutOfMemory => return error.OutOfMemory,
   3566                             error.AnalysisFail => {},
   3567                         };
   3568                         continue;
   3569                     },
   3570                     else => unreachable,
   3571                 }
   3572             },
   3573             .fn_proto_simple => {
   3574                 var params: [1]ast.Node.Index = undefined;
   3575                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(&params, member_node)) catch |err| switch (err) {
   3576                     error.OutOfMemory => return error.OutOfMemory,
   3577                     error.AnalysisFail => {},
   3578                 };
   3579                 continue;
   3580             },
   3581             .fn_proto_multi => {
   3582                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) {
   3583                     error.OutOfMemory => return error.OutOfMemory,
   3584                     error.AnalysisFail => {},
   3585                 };
   3586                 continue;
   3587             },
   3588             .fn_proto_one => {
   3589                 var params: [1]ast.Node.Index = undefined;
   3590                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(&params, member_node)) catch |err| switch (err) {
   3591                     error.OutOfMemory => return error.OutOfMemory,
   3592                     error.AnalysisFail => {},
   3593                 };
   3594                 continue;
   3595             },
   3596             .fn_proto => {
   3597                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) {
   3598                     error.OutOfMemory => return error.OutOfMemory,
   3599                     error.AnalysisFail => {},
   3600                 };
   3601                 continue;
   3602             },
   3603 
   3604             .global_var_decl => {
   3605                 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) {
   3606                     error.OutOfMemory => return error.OutOfMemory,
   3607                     error.AnalysisFail => {},
   3608                 };
   3609                 continue;
   3610             },
   3611             .local_var_decl => {
   3612                 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) {
   3613                     error.OutOfMemory => return error.OutOfMemory,
   3614                     error.AnalysisFail => {},
   3615                 };
   3616                 continue;
   3617             },
   3618             .simple_var_decl => {
   3619                 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) {
   3620                     error.OutOfMemory => return error.OutOfMemory,
   3621                     error.AnalysisFail => {},
   3622                 };
   3623                 continue;
   3624             },
   3625             .aligned_var_decl => {
   3626                 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) {
   3627                     error.OutOfMemory => return error.OutOfMemory,
   3628                     error.AnalysisFail => {},
   3629                 };
   3630                 continue;
   3631             },
   3632 
   3633             .@"comptime" => {
   3634                 astgen.comptimeDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) {
   3635                     error.OutOfMemory => return error.OutOfMemory,
   3636                     error.AnalysisFail => {},
   3637                 };
   3638                 continue;
   3639             },
   3640             .@"usingnamespace" => {
   3641                 astgen.usingnamespaceDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) {
   3642                     error.OutOfMemory => return error.OutOfMemory,
   3643                     error.AnalysisFail => {},
   3644                 };
   3645                 continue;
   3646             },
   3647             .test_decl => {
   3648                 astgen.testDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) {
   3649                     error.OutOfMemory => return error.OutOfMemory,
   3650                     error.AnalysisFail => {},
   3651                 };
   3652                 continue;
   3653             },
   3654             else => unreachable,
   3655         };
   3656         if (field_index % fields_per_u32 == 0 and field_index != 0) {
   3657             try bit_bag.append(gpa, cur_bit_bag);
   3658             cur_bit_bag = 0;
   3659         }
   3660         try fields_data.ensureUnusedCapacity(gpa, 4);
   3661 
   3662         const field_name = try astgen.identAsString(member.ast.name_token);
   3663         fields_data.appendAssumeCapacity(field_name);
   3664 
   3665         if (member.ast.type_expr == 0) {
   3666             return astgen.failTok(member.ast.name_token, "struct field missing type", .{});
   3667         }
   3668 
   3669         const field_type: Zir.Inst.Ref = if (node_tags[member.ast.type_expr] == .@"anytype")
   3670             .none
   3671         else
   3672             try typeExpr(&block_scope, &namespace.base, member.ast.type_expr);
   3673         fields_data.appendAssumeCapacity(@enumToInt(field_type));
   3674 
   3675         known_has_bits = known_has_bits or nodeImpliesRuntimeBits(tree, member.ast.type_expr);
   3676 
   3677         const have_align = member.ast.align_expr != 0;
   3678         const have_value = member.ast.value_expr != 0;
   3679         const is_comptime = member.comptime_token != null;
   3680         const unused = false;
   3681         cur_bit_bag = (cur_bit_bag >> bits_per_field) |
   3682             (@as(u32, @boolToInt(have_align)) << 28) |
   3683             (@as(u32, @boolToInt(have_value)) << 29) |
   3684             (@as(u32, @boolToInt(is_comptime)) << 30) |
   3685             (@as(u32, @boolToInt(unused)) << 31);
   3686 
   3687         if (have_align) {
   3688             const align_inst = try expr(&block_scope, &namespace.base, align_rl, member.ast.align_expr);
   3689             fields_data.appendAssumeCapacity(@enumToInt(align_inst));
   3690         }
   3691         if (have_value) {
   3692             const rl: ResultLoc = if (field_type == .none) .none else .{ .ty = field_type };
   3693 
   3694             const default_inst = try expr(&block_scope, &namespace.base, rl, member.ast.value_expr);
   3695             fields_data.appendAssumeCapacity(@enumToInt(default_inst));
   3696         } else if (member.comptime_token) |comptime_token| {
   3697             return astgen.failTok(comptime_token, "comptime field without default initialization value", .{});
   3698         }
   3699 
   3700         field_index += 1;
   3701     }
   3702     {
   3703         const empty_slot_count = fields_per_u32 - (field_index % fields_per_u32);
   3704         if (empty_slot_count < fields_per_u32) {
   3705             cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_field);
   3706         }
   3707     }
   3708     {
   3709         const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32);
   3710         if (empty_slot_count < WipDecls.fields_per_u32) {
   3711             wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field);
   3712         }
   3713     }
   3714 
   3715     const decl_inst = try gz.reserveInstructionIndex();
   3716     if (block_scope.instructions.items.len != 0) {
   3717         _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
   3718     }
   3719 
   3720     try gz.setStruct(decl_inst, .{
   3721         .src_node = node,
   3722         .layout = layout,
   3723         .body_len = @intCast(u32, block_scope.instructions.items.len),
   3724         .fields_len = @intCast(u32, field_index),
   3725         .decls_len = @intCast(u32, wip_decls.decl_index),
   3726         .known_has_bits = known_has_bits,
   3727     });
   3728 
   3729     try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len +
   3730         @boolToInt(field_index != 0) + fields_data.items.len +
   3731         block_scope.instructions.items.len +
   3732         wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
   3733         wip_decls.payload.items.len);
   3734     astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
   3735     if (wip_decls.decl_index != 0) {
   3736         astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
   3737     }
   3738     astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items);
   3739 
   3740     astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);
   3741 
   3742     astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
   3743     if (field_index != 0) {
   3744         astgen.extra.appendAssumeCapacity(cur_bit_bag);
   3745     }
   3746     astgen.extra.appendSliceAssumeCapacity(fields_data.items);
   3747 
   3748     return indexToRef(decl_inst);
   3749 }
   3750 
   3751 fn unionDeclInner(
   3752     gz: *GenZir,
   3753     scope: *Scope,
   3754     node: ast.Node.Index,
   3755     members: []const ast.Node.Index,
   3756     layout: std.builtin.TypeInfo.ContainerLayout,
   3757     arg_node: ast.Node.Index,
   3758     have_auto_enum: bool,
   3759 ) InnerError!Zir.Inst.Ref {
   3760     const astgen = gz.astgen;
   3761     const gpa = astgen.gpa;
   3762     const tree = astgen.tree;
   3763     const node_tags = tree.nodes.items(.tag);
   3764     const node_datas = tree.nodes.items(.data);
   3765 
   3766     // The union_decl instruction introduces a scope in which the decls of the union
   3767     // are in scope, so that field types, alignments, and default value expressions
   3768     // can refer to decls within the union itself.
   3769     var block_scope: GenZir = .{
   3770         .parent = scope,
   3771         .decl_node_index = node,
   3772         .decl_line = gz.calcLine(node),
   3773         .astgen = astgen,
   3774         .force_comptime = true,
   3775         .in_defer = false,
   3776     };
   3777     defer block_scope.instructions.deinit(gpa);
   3778 
   3779     var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
   3780     defer namespace.decls.deinit(gpa);
   3781 
   3782     try astgen.scanDecls(&namespace, members);
   3783 
   3784     const arg_inst: Zir.Inst.Ref = if (arg_node != 0)
   3785         try typeExpr(gz, &namespace.base, arg_node)
   3786     else
   3787         .none;
   3788 
   3789     var wip_decls: WipDecls = .{};
   3790     defer wip_decls.deinit(gpa);
   3791 
   3792     // We don't know which members are fields until we iterate, so cannot do
   3793     // an accurate ensureCapacity yet.
   3794     var fields_data = ArrayListUnmanaged(u32){};
   3795     defer fields_data.deinit(gpa);
   3796 
   3797     const bits_per_field = 4;
   3798     const fields_per_u32 = 32 / bits_per_field;
   3799     // We only need this if there are greater than fields_per_u32 fields.
   3800     var bit_bag = ArrayListUnmanaged(u32){};
   3801     defer bit_bag.deinit(gpa);
   3802 
   3803     var cur_bit_bag: u32 = 0;
   3804     var field_index: usize = 0;
   3805     for (members) |member_node| {
   3806         const member = switch (node_tags[member_node]) {
   3807             .container_field_init => tree.containerFieldInit(member_node),
   3808             .container_field_align => tree.containerFieldAlign(member_node),
   3809             .container_field => tree.containerField(member_node),
   3810 
   3811             .fn_decl => {
   3812                 const fn_proto = node_datas[member_node].lhs;
   3813                 const body = node_datas[member_node].rhs;
   3814                 switch (node_tags[fn_proto]) {
   3815                     .fn_proto_simple => {
   3816                         var params: [1]ast.Node.Index = undefined;
   3817                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(&params, fn_proto)) catch |err| switch (err) {
   3818                             error.OutOfMemory => return error.OutOfMemory,
   3819                             error.AnalysisFail => {},
   3820                         };
   3821                         continue;
   3822                     },
   3823                     .fn_proto_multi => {
   3824                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) {
   3825                             error.OutOfMemory => return error.OutOfMemory,
   3826                             error.AnalysisFail => {},
   3827                         };
   3828                         continue;
   3829                     },
   3830                     .fn_proto_one => {
   3831                         var params: [1]ast.Node.Index = undefined;
   3832                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(&params, fn_proto)) catch |err| switch (err) {
   3833                             error.OutOfMemory => return error.OutOfMemory,
   3834                             error.AnalysisFail => {},
   3835                         };
   3836                         continue;
   3837                     },
   3838                     .fn_proto => {
   3839                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) {
   3840                             error.OutOfMemory => return error.OutOfMemory,
   3841                             error.AnalysisFail => {},
   3842                         };
   3843                         continue;
   3844                     },
   3845                     else => unreachable,
   3846                 }
   3847             },
   3848             .fn_proto_simple => {
   3849                 var params: [1]ast.Node.Index = undefined;
   3850                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(&params, member_node)) catch |err| switch (err) {
   3851                     error.OutOfMemory => return error.OutOfMemory,
   3852                     error.AnalysisFail => {},
   3853                 };
   3854                 continue;
   3855             },
   3856             .fn_proto_multi => {
   3857                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) {
   3858                     error.OutOfMemory => return error.OutOfMemory,
   3859                     error.AnalysisFail => {},
   3860                 };
   3861                 continue;
   3862             },
   3863             .fn_proto_one => {
   3864                 var params: [1]ast.Node.Index = undefined;
   3865                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(&params, member_node)) catch |err| switch (err) {
   3866                     error.OutOfMemory => return error.OutOfMemory,
   3867                     error.AnalysisFail => {},
   3868                 };
   3869                 continue;
   3870             },
   3871             .fn_proto => {
   3872                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) {
   3873                     error.OutOfMemory => return error.OutOfMemory,
   3874                     error.AnalysisFail => {},
   3875                 };
   3876                 continue;
   3877             },
   3878 
   3879             .global_var_decl => {
   3880                 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) {
   3881                     error.OutOfMemory => return error.OutOfMemory,
   3882                     error.AnalysisFail => {},
   3883                 };
   3884                 continue;
   3885             },
   3886             .local_var_decl => {
   3887                 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) {
   3888                     error.OutOfMemory => return error.OutOfMemory,
   3889                     error.AnalysisFail => {},
   3890                 };
   3891                 continue;
   3892             },
   3893             .simple_var_decl => {
   3894                 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) {
   3895                     error.OutOfMemory => return error.OutOfMemory,
   3896                     error.AnalysisFail => {},
   3897                 };
   3898                 continue;
   3899             },
   3900             .aligned_var_decl => {
   3901                 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) {
   3902                     error.OutOfMemory => return error.OutOfMemory,
   3903                     error.AnalysisFail => {},
   3904                 };
   3905                 continue;
   3906             },
   3907 
   3908             .@"comptime" => {
   3909                 astgen.comptimeDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) {
   3910                     error.OutOfMemory => return error.OutOfMemory,
   3911                     error.AnalysisFail => {},
   3912                 };
   3913                 continue;
   3914             },
   3915             .@"usingnamespace" => {
   3916                 astgen.usingnamespaceDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) {
   3917                     error.OutOfMemory => return error.OutOfMemory,
   3918                     error.AnalysisFail => {},
   3919                 };
   3920                 continue;
   3921             },
   3922             .test_decl => {
   3923                 astgen.testDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) {
   3924                     error.OutOfMemory => return error.OutOfMemory,
   3925                     error.AnalysisFail => {},
   3926                 };
   3927                 continue;
   3928             },
   3929             else => unreachable,
   3930         };
   3931         if (field_index % fields_per_u32 == 0 and field_index != 0) {
   3932             try bit_bag.append(gpa, cur_bit_bag);
   3933             cur_bit_bag = 0;
   3934         }
   3935         if (member.comptime_token) |comptime_token| {
   3936             return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{});
   3937         }
   3938         try fields_data.ensureUnusedCapacity(gpa, if (node_tags[member.ast.type_expr] != .@"anytype") 4 else 3);
   3939 
   3940         const field_name = try astgen.identAsString(member.ast.name_token);
   3941         fields_data.appendAssumeCapacity(field_name);
   3942 
   3943         const have_type = member.ast.type_expr != 0;
   3944         const have_align = member.ast.align_expr != 0;
   3945         const have_value = member.ast.value_expr != 0;
   3946         const unused = false;
   3947         cur_bit_bag = (cur_bit_bag >> bits_per_field) |
   3948             (@as(u32, @boolToInt(have_type)) << 28) |
   3949             (@as(u32, @boolToInt(have_align)) << 29) |
   3950             (@as(u32, @boolToInt(have_value)) << 30) |
   3951             (@as(u32, @boolToInt(unused)) << 31);
   3952 
   3953         if (have_type and node_tags[member.ast.type_expr] != .@"anytype") {
   3954             const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr);
   3955             fields_data.appendAssumeCapacity(@enumToInt(field_type));
   3956         }
   3957         if (have_align) {
   3958             const align_inst = try expr(&block_scope, &block_scope.base, .{ .ty = .u32_type }, member.ast.align_expr);
   3959             fields_data.appendAssumeCapacity(@enumToInt(align_inst));
   3960         }
   3961         if (have_value) {
   3962             if (arg_inst == .none) {
   3963                 return astgen.failNodeNotes(
   3964                     node,
   3965                     "explicitly valued tagged union missing integer tag type",
   3966                     .{},
   3967                     &[_]u32{
   3968                         try astgen.errNoteNode(
   3969                             member.ast.value_expr,
   3970                             "tag value specified here",
   3971                             .{},
   3972                         ),
   3973                     },
   3974                 );
   3975             }
   3976             const tag_value = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr);
   3977             fields_data.appendAssumeCapacity(@enumToInt(tag_value));
   3978         }
   3979 
   3980         field_index += 1;
   3981     }
   3982     if (field_index == 0) {
   3983         return astgen.failNode(node, "union declarations must have at least one tag", .{});
   3984     }
   3985     {
   3986         const empty_slot_count = fields_per_u32 - (field_index % fields_per_u32);
   3987         if (empty_slot_count < fields_per_u32) {
   3988             cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_field);
   3989         }
   3990     }
   3991     {
   3992         const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32);
   3993         if (empty_slot_count < WipDecls.fields_per_u32) {
   3994             wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field);
   3995         }
   3996     }
   3997 
   3998     const decl_inst = try gz.reserveInstructionIndex();
   3999     if (block_scope.instructions.items.len != 0) {
   4000         _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
   4001     }
   4002 
   4003     try gz.setUnion(decl_inst, .{
   4004         .src_node = node,
   4005         .layout = layout,
   4006         .tag_type = arg_inst,
   4007         .body_len = @intCast(u32, block_scope.instructions.items.len),
   4008         .fields_len = @intCast(u32, field_index),
   4009         .decls_len = @intCast(u32, wip_decls.decl_index),
   4010         .auto_enum_tag = have_auto_enum,
   4011     });
   4012 
   4013     try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len +
   4014         1 + fields_data.items.len +
   4015         block_scope.instructions.items.len +
   4016         wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
   4017         wip_decls.payload.items.len);
   4018     astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
   4019     if (wip_decls.decl_index != 0) {
   4020         astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
   4021     }
   4022     astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items);
   4023 
   4024     astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);
   4025 
   4026     astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
   4027     astgen.extra.appendAssumeCapacity(cur_bit_bag);
   4028     astgen.extra.appendSliceAssumeCapacity(fields_data.items);
   4029 
   4030     return indexToRef(decl_inst);
   4031 }
   4032 
   4033 fn containerDecl(
   4034     gz: *GenZir,
   4035     scope: *Scope,
   4036     rl: ResultLoc,
   4037     node: ast.Node.Index,
   4038     container_decl: ast.full.ContainerDecl,
   4039 ) InnerError!Zir.Inst.Ref {
   4040     const astgen = gz.astgen;
   4041     const gpa = astgen.gpa;
   4042     const tree = astgen.tree;
   4043     const token_tags = tree.tokens.items(.tag);
   4044     const node_tags = tree.nodes.items(.tag);
   4045     const node_datas = tree.nodes.items(.data);
   4046 
   4047     const prev_fn_block = astgen.fn_block;
   4048     astgen.fn_block = null;
   4049     defer astgen.fn_block = prev_fn_block;
   4050 
   4051     // We must not create any types until Sema. Here the goal is only to generate
   4052     // ZIR for all the field types, alignments, and default value expressions.
   4053 
   4054     switch (token_tags[container_decl.ast.main_token]) {
   4055         .keyword_struct => {
   4056             const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) {
   4057                 .keyword_packed => std.builtin.TypeInfo.ContainerLayout.Packed,
   4058                 .keyword_extern => std.builtin.TypeInfo.ContainerLayout.Extern,
   4059                 else => unreachable,
   4060             } else std.builtin.TypeInfo.ContainerLayout.Auto;
   4061 
   4062             assert(container_decl.ast.arg == 0);
   4063 
   4064             const result = try structDeclInner(gz, scope, node, container_decl, layout);
   4065             return rvalue(gz, rl, result, node);
   4066         },
   4067         .keyword_union => {
   4068             const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) {
   4069                 .keyword_packed => std.builtin.TypeInfo.ContainerLayout.Packed,
   4070                 .keyword_extern => std.builtin.TypeInfo.ContainerLayout.Extern,
   4071                 else => unreachable,
   4072             } else std.builtin.TypeInfo.ContainerLayout.Auto;
   4073 
   4074             const have_auto_enum = container_decl.ast.enum_token != null;
   4075 
   4076             const result = try unionDeclInner(gz, scope, node, container_decl.ast.members, layout, container_decl.ast.arg, have_auto_enum);
   4077             return rvalue(gz, rl, result, node);
   4078         },
   4079         .keyword_enum => {
   4080             if (container_decl.layout_token) |t| {
   4081                 return astgen.failTok(t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{});
   4082             }
   4083             // Count total fields as well as how many have explicitly provided tag values.
   4084             const counts = blk: {
   4085                 var values: usize = 0;
   4086                 var total_fields: usize = 0;
   4087                 var decls: usize = 0;
   4088                 var nonexhaustive_node: ast.Node.Index = 0;
   4089                 for (container_decl.ast.members) |member_node| {
   4090                     const member = switch (node_tags[member_node]) {
   4091                         .container_field_init => tree.containerFieldInit(member_node),
   4092                         .container_field_align => tree.containerFieldAlign(member_node),
   4093                         .container_field => tree.containerField(member_node),
   4094                         else => {
   4095                             decls += 1;
   4096                             continue;
   4097                         },
   4098                     };
   4099                     if (member.comptime_token) |comptime_token| {
   4100                         return astgen.failTok(comptime_token, "enum fields cannot be marked comptime", .{});
   4101                     }
   4102                     if (member.ast.type_expr != 0) {
   4103                         return astgen.failNodeNotes(
   4104                             member.ast.type_expr,
   4105                             "enum fields do not have types",
   4106                             .{},
   4107                             &[_]u32{
   4108                                 try astgen.errNoteNode(
   4109                                     node,
   4110                                     "consider 'union(enum)' here to make it a tagged union",
   4111                                     .{},
   4112                                 ),
   4113                             },
   4114                         );
   4115                     }
   4116                     // Alignment expressions in enums are caught by the parser.
   4117                     assert(member.ast.align_expr == 0);
   4118 
   4119                     const name_token = member.ast.name_token;
   4120                     if (mem.eql(u8, tree.tokenSlice(name_token), "_")) {
   4121                         if (nonexhaustive_node != 0) {
   4122                             return astgen.failNodeNotes(
   4123                                 member_node,
   4124                                 "redundant non-exhaustive enum mark",
   4125                                 .{},
   4126                                 &[_]u32{
   4127                                     try astgen.errNoteNode(
   4128                                         nonexhaustive_node,
   4129                                         "other mark here",
   4130                                         .{},
   4131                                     ),
   4132                                 },
   4133                             );
   4134                         }
   4135                         nonexhaustive_node = member_node;
   4136                         if (member.ast.value_expr != 0) {
   4137                             return astgen.failNode(member.ast.value_expr, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{});
   4138                         }
   4139                         continue;
   4140                     }
   4141                     total_fields += 1;
   4142                     if (member.ast.value_expr != 0) {
   4143                         if (container_decl.ast.arg == 0) {
   4144                             return astgen.failNode(member.ast.value_expr, "value assigned to enum tag with inferred tag type", .{});
   4145                         }
   4146                         values += 1;
   4147                     }
   4148                 }
   4149                 break :blk .{
   4150                     .total_fields = total_fields,
   4151                     .values = values,
   4152                     .decls = decls,
   4153                     .nonexhaustive_node = nonexhaustive_node,
   4154                 };
   4155             };
   4156             if (counts.total_fields == 0 and counts.nonexhaustive_node == 0) {
   4157                 // One can construct an enum with no tags, and it functions the same as `noreturn`. But
   4158                 // this is only useful for generic code; when explicitly using `enum {}` syntax, there
   4159                 // must be at least one tag.
   4160                 return astgen.failNode(node, "enum declarations must have at least one tag", .{});
   4161             }
   4162             if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) {
   4163                 return astgen.failNodeNotes(
   4164                     node,
   4165                     "non-exhaustive enum missing integer tag type",
   4166                     .{},
   4167                     &[_]u32{
   4168                         try astgen.errNoteNode(
   4169                             counts.nonexhaustive_node,
   4170                             "marked non-exhaustive here",
   4171                             .{},
   4172                         ),
   4173                     },
   4174                 );
   4175             }
   4176             // In this case we must generate ZIR code for the tag values, similar to
   4177             // how structs are handled above.
   4178             const nonexhaustive = counts.nonexhaustive_node != 0;
   4179 
   4180             // The enum_decl instruction introduces a scope in which the decls of the enum
   4181             // are in scope, so that tag values can refer to decls within the enum itself.
   4182             var block_scope: GenZir = .{
   4183                 .parent = scope,
   4184                 .decl_node_index = node,
   4185                 .decl_line = gz.calcLine(node),
   4186                 .astgen = astgen,
   4187                 .force_comptime = true,
   4188                 .in_defer = false,
   4189             };
   4190             defer block_scope.instructions.deinit(gpa);
   4191 
   4192             var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
   4193             defer namespace.decls.deinit(gpa);
   4194 
   4195             try astgen.scanDecls(&namespace, container_decl.ast.members);
   4196 
   4197             const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0)
   4198                 try comptimeExpr(gz, &namespace.base, .{ .ty = .type_type }, container_decl.ast.arg)
   4199             else
   4200                 .none;
   4201 
   4202             var wip_decls: WipDecls = .{};
   4203             defer wip_decls.deinit(gpa);
   4204 
   4205             var fields_data = ArrayListUnmanaged(u32){};
   4206             defer fields_data.deinit(gpa);
   4207 
   4208             try fields_data.ensureTotalCapacity(gpa, counts.total_fields + counts.values);
   4209 
   4210             // We only need this if there are greater than 32 fields.
   4211             var bit_bag = ArrayListUnmanaged(u32){};
   4212             defer bit_bag.deinit(gpa);
   4213 
   4214             var cur_bit_bag: u32 = 0;
   4215             var field_index: usize = 0;
   4216             for (container_decl.ast.members) |member_node| {
   4217                 if (member_node == counts.nonexhaustive_node)
   4218                     continue;
   4219                 const member = switch (node_tags[member_node]) {
   4220                     .container_field_init => tree.containerFieldInit(member_node),
   4221                     .container_field_align => tree.containerFieldAlign(member_node),
   4222                     .container_field => tree.containerField(member_node),
   4223 
   4224                     .fn_decl => {
   4225                         const fn_proto = node_datas[member_node].lhs;
   4226                         const body = node_datas[member_node].rhs;
   4227                         switch (node_tags[fn_proto]) {
   4228                             .fn_proto_simple => {
   4229                                 var params: [1]ast.Node.Index = undefined;
   4230                                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(&params, fn_proto)) catch |err| switch (err) {
   4231                                     error.OutOfMemory => return error.OutOfMemory,
   4232                                     error.AnalysisFail => {},
   4233                                 };
   4234                                 continue;
   4235                             },
   4236                             .fn_proto_multi => {
   4237                                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) {
   4238                                     error.OutOfMemory => return error.OutOfMemory,
   4239                                     error.AnalysisFail => {},
   4240                                 };
   4241                                 continue;
   4242                             },
   4243                             .fn_proto_one => {
   4244                                 var params: [1]ast.Node.Index = undefined;
   4245                                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(&params, fn_proto)) catch |err| switch (err) {
   4246                                     error.OutOfMemory => return error.OutOfMemory,
   4247                                     error.AnalysisFail => {},
   4248                                 };
   4249                                 continue;
   4250                             },
   4251                             .fn_proto => {
   4252                                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) {
   4253                                     error.OutOfMemory => return error.OutOfMemory,
   4254                                     error.AnalysisFail => {},
   4255                                 };
   4256                                 continue;
   4257                             },
   4258                             else => unreachable,
   4259                         }
   4260                     },
   4261                     .fn_proto_simple => {
   4262                         var params: [1]ast.Node.Index = undefined;
   4263                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(&params, member_node)) catch |err| switch (err) {
   4264                             error.OutOfMemory => return error.OutOfMemory,
   4265                             error.AnalysisFail => {},
   4266                         };
   4267                         continue;
   4268                     },
   4269                     .fn_proto_multi => {
   4270                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) {
   4271                             error.OutOfMemory => return error.OutOfMemory,
   4272                             error.AnalysisFail => {},
   4273                         };
   4274                         continue;
   4275                     },
   4276                     .fn_proto_one => {
   4277                         var params: [1]ast.Node.Index = undefined;
   4278                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(&params, member_node)) catch |err| switch (err) {
   4279                             error.OutOfMemory => return error.OutOfMemory,
   4280                             error.AnalysisFail => {},
   4281                         };
   4282                         continue;
   4283                     },
   4284                     .fn_proto => {
   4285                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) {
   4286                             error.OutOfMemory => return error.OutOfMemory,
   4287                             error.AnalysisFail => {},
   4288                         };
   4289                         continue;
   4290                     },
   4291 
   4292                     .global_var_decl => {
   4293                         astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) {
   4294                             error.OutOfMemory => return error.OutOfMemory,
   4295                             error.AnalysisFail => {},
   4296                         };
   4297                         continue;
   4298                     },
   4299                     .local_var_decl => {
   4300                         astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) {
   4301                             error.OutOfMemory => return error.OutOfMemory,
   4302                             error.AnalysisFail => {},
   4303                         };
   4304                         continue;
   4305                     },
   4306                     .simple_var_decl => {
   4307                         astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) {
   4308                             error.OutOfMemory => return error.OutOfMemory,
   4309                             error.AnalysisFail => {},
   4310                         };
   4311                         continue;
   4312                     },
   4313                     .aligned_var_decl => {
   4314                         astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) {
   4315                             error.OutOfMemory => return error.OutOfMemory,
   4316                             error.AnalysisFail => {},
   4317                         };
   4318                         continue;
   4319                     },
   4320 
   4321                     .@"comptime" => {
   4322                         astgen.comptimeDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) {
   4323                             error.OutOfMemory => return error.OutOfMemory,
   4324                             error.AnalysisFail => {},
   4325                         };
   4326                         continue;
   4327                     },
   4328                     .@"usingnamespace" => {
   4329                         astgen.usingnamespaceDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) {
   4330                             error.OutOfMemory => return error.OutOfMemory,
   4331                             error.AnalysisFail => {},
   4332                         };
   4333                         continue;
   4334                     },
   4335                     .test_decl => {
   4336                         astgen.testDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) {
   4337                             error.OutOfMemory => return error.OutOfMemory,
   4338                             error.AnalysisFail => {},
   4339                         };
   4340                         continue;
   4341                     },
   4342                     else => unreachable,
   4343                 };
   4344                 if (field_index % 32 == 0 and field_index != 0) {
   4345                     try bit_bag.append(gpa, cur_bit_bag);
   4346                     cur_bit_bag = 0;
   4347                 }
   4348                 assert(member.comptime_token == null);
   4349                 assert(member.ast.type_expr == 0);
   4350                 assert(member.ast.align_expr == 0);
   4351 
   4352                 const field_name = try astgen.identAsString(member.ast.name_token);
   4353                 fields_data.appendAssumeCapacity(field_name);
   4354 
   4355                 const have_value = member.ast.value_expr != 0;
   4356                 cur_bit_bag = (cur_bit_bag >> 1) |
   4357                     (@as(u32, @boolToInt(have_value)) << 31);
   4358 
   4359                 if (have_value) {
   4360                     if (arg_inst == .none) {
   4361                         return astgen.failNodeNotes(
   4362                             node,
   4363                             "explicitly valued enum missing integer tag type",
   4364                             .{},
   4365                             &[_]u32{
   4366                                 try astgen.errNoteNode(
   4367                                     member.ast.value_expr,
   4368                                     "tag value specified here",
   4369                                     .{},
   4370                                 ),
   4371                             },
   4372                         );
   4373                     }
   4374                     const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .ty = arg_inst }, member.ast.value_expr);
   4375                     fields_data.appendAssumeCapacity(@enumToInt(tag_value_inst));
   4376                 }
   4377 
   4378                 field_index += 1;
   4379             }
   4380             {
   4381                 const empty_slot_count = 32 - (field_index % 32);
   4382                 if (empty_slot_count < 32) {
   4383                     cur_bit_bag >>= @intCast(u5, empty_slot_count);
   4384                 }
   4385             }
   4386             {
   4387                 const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32);
   4388                 if (empty_slot_count < WipDecls.fields_per_u32) {
   4389                     wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field);
   4390                 }
   4391             }
   4392 
   4393             const decl_inst = try gz.reserveInstructionIndex();
   4394             if (block_scope.instructions.items.len != 0) {
   4395                 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
   4396             }
   4397 
   4398             try gz.setEnum(decl_inst, .{
   4399                 .src_node = node,
   4400                 .nonexhaustive = nonexhaustive,
   4401                 .tag_type = arg_inst,
   4402                 .body_len = @intCast(u32, block_scope.instructions.items.len),
   4403                 .fields_len = @intCast(u32, field_index),
   4404                 .decls_len = @intCast(u32, wip_decls.decl_index),
   4405             });
   4406 
   4407             try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len +
   4408                 1 + fields_data.items.len +
   4409                 block_scope.instructions.items.len +
   4410                 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
   4411                 wip_decls.payload.items.len);
   4412             astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
   4413             if (wip_decls.decl_index != 0) {
   4414                 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
   4415             }
   4416             astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items);
   4417 
   4418             astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);
   4419             astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
   4420             astgen.extra.appendAssumeCapacity(cur_bit_bag);
   4421             astgen.extra.appendSliceAssumeCapacity(fields_data.items);
   4422 
   4423             return rvalue(gz, rl, indexToRef(decl_inst), node);
   4424         },
   4425         .keyword_opaque => {
   4426             assert(container_decl.ast.arg == 0);
   4427 
   4428             var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
   4429             defer namespace.decls.deinit(gpa);
   4430 
   4431             try astgen.scanDecls(&namespace, container_decl.ast.members);
   4432 
   4433             var wip_decls: WipDecls = .{};
   4434             defer wip_decls.deinit(gpa);
   4435 
   4436             for (container_decl.ast.members) |member_node| {
   4437                 switch (node_tags[member_node]) {
   4438                     .container_field_init, .container_field_align, .container_field => {},
   4439 
   4440                     .fn_decl => {
   4441                         const fn_proto = node_datas[member_node].lhs;
   4442                         const body = node_datas[member_node].rhs;
   4443                         switch (node_tags[fn_proto]) {
   4444                             .fn_proto_simple => {
   4445                                 var params: [1]ast.Node.Index = undefined;
   4446                                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(&params, fn_proto)) catch |err| switch (err) {
   4447                                     error.OutOfMemory => return error.OutOfMemory,
   4448                                     error.AnalysisFail => {},
   4449                                 };
   4450                                 continue;
   4451                             },
   4452                             .fn_proto_multi => {
   4453                                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) {
   4454                                     error.OutOfMemory => return error.OutOfMemory,
   4455                                     error.AnalysisFail => {},
   4456                                 };
   4457                                 continue;
   4458                             },
   4459                             .fn_proto_one => {
   4460                                 var params: [1]ast.Node.Index = undefined;
   4461                                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(&params, fn_proto)) catch |err| switch (err) {
   4462                                     error.OutOfMemory => return error.OutOfMemory,
   4463                                     error.AnalysisFail => {},
   4464                                 };
   4465                                 continue;
   4466                             },
   4467                             .fn_proto => {
   4468                                 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) {
   4469                                     error.OutOfMemory => return error.OutOfMemory,
   4470                                     error.AnalysisFail => {},
   4471                                 };
   4472                                 continue;
   4473                             },
   4474                             else => unreachable,
   4475                         }
   4476                     },
   4477                     .fn_proto_simple => {
   4478                         var params: [1]ast.Node.Index = undefined;
   4479                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(&params, member_node)) catch |err| switch (err) {
   4480                             error.OutOfMemory => return error.OutOfMemory,
   4481                             error.AnalysisFail => {},
   4482                         };
   4483                         continue;
   4484                     },
   4485                     .fn_proto_multi => {
   4486                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) {
   4487                             error.OutOfMemory => return error.OutOfMemory,
   4488                             error.AnalysisFail => {},
   4489                         };
   4490                         continue;
   4491                     },
   4492                     .fn_proto_one => {
   4493                         var params: [1]ast.Node.Index = undefined;
   4494                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(&params, member_node)) catch |err| switch (err) {
   4495                             error.OutOfMemory => return error.OutOfMemory,
   4496                             error.AnalysisFail => {},
   4497                         };
   4498                         continue;
   4499                     },
   4500                     .fn_proto => {
   4501                         astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) {
   4502                             error.OutOfMemory => return error.OutOfMemory,
   4503                             error.AnalysisFail => {},
   4504                         };
   4505                         continue;
   4506                     },
   4507 
   4508                     .global_var_decl => {
   4509                         astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) {
   4510                             error.OutOfMemory => return error.OutOfMemory,
   4511                             error.AnalysisFail => {},
   4512                         };
   4513                         continue;
   4514                     },
   4515                     .local_var_decl => {
   4516                         astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) {
   4517                             error.OutOfMemory => return error.OutOfMemory,
   4518                             error.AnalysisFail => {},
   4519                         };
   4520                         continue;
   4521                     },
   4522                     .simple_var_decl => {
   4523                         astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) {
   4524                             error.OutOfMemory => return error.OutOfMemory,
   4525                             error.AnalysisFail => {},
   4526                         };
   4527                         continue;
   4528                     },
   4529                     .aligned_var_decl => {
   4530                         astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) {
   4531                             error.OutOfMemory => return error.OutOfMemory,
   4532                             error.AnalysisFail => {},
   4533                         };
   4534                         continue;
   4535                     },
   4536 
   4537                     .@"comptime" => {
   4538                         astgen.comptimeDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) {
   4539                             error.OutOfMemory => return error.OutOfMemory,
   4540                             error.AnalysisFail => {},
   4541                         };
   4542                         continue;
   4543                     },
   4544                     .@"usingnamespace" => {
   4545                         astgen.usingnamespaceDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) {
   4546                             error.OutOfMemory => return error.OutOfMemory,
   4547                             error.AnalysisFail => {},
   4548                         };
   4549                         continue;
   4550                     },
   4551                     .test_decl => {
   4552                         astgen.testDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) {
   4553                             error.OutOfMemory => return error.OutOfMemory,
   4554                             error.AnalysisFail => {},
   4555                         };
   4556                         continue;
   4557                     },
   4558                     else => unreachable,
   4559                 }
   4560             }
   4561             {
   4562                 const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32);
   4563                 if (empty_slot_count < WipDecls.fields_per_u32) {
   4564                     wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field);
   4565                 }
   4566             }
   4567             const tag: Zir.Inst.Tag = switch (gz.anon_name_strategy) {
   4568                 .parent => .opaque_decl,
   4569                 .anon => .opaque_decl_anon,
   4570                 .func => .opaque_decl_func,
   4571             };
   4572             const decl_inst = try gz.addBlock(tag, node);
   4573             try gz.instructions.append(gpa, decl_inst);
   4574 
   4575             try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.OpaqueDecl).Struct.fields.len +
   4576                 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
   4577                 wip_decls.payload.items.len);
   4578             const zir_datas = astgen.instructions.items(.data);
   4579             zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{
   4580                 .decls_len = @intCast(u32, wip_decls.decl_index),
   4581             });
   4582             astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
   4583             if (wip_decls.decl_index != 0) {
   4584                 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
   4585             }
   4586             astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items);
   4587 
   4588             return rvalue(gz, rl, indexToRef(decl_inst), node);
   4589         },
   4590         else => unreachable,
   4591     }
   4592 }
   4593 
   4594 fn errorSetDecl(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
   4595     const astgen = gz.astgen;
   4596     const gpa = astgen.gpa;
   4597     const tree = astgen.tree;
   4598     const main_tokens = tree.nodes.items(.main_token);
   4599     const token_tags = tree.tokens.items(.tag);
   4600 
   4601     var field_names: std.ArrayListUnmanaged(u32) = .{};
   4602     defer field_names.deinit(gpa);
   4603 
   4604     {
   4605         const error_token = main_tokens[node];
   4606         var tok_i = error_token + 2;
   4607         var field_i: usize = 0;
   4608         while (true) : (tok_i += 1) {
   4609             switch (token_tags[tok_i]) {
   4610                 .doc_comment, .comma => {},
   4611                 .identifier => {
   4612                     const str_index = try astgen.identAsString(tok_i);
   4613                     try field_names.append(gpa, str_index);
   4614                     field_i += 1;
   4615                 },
   4616                 .r_brace => break,
   4617                 else => unreachable,
   4618             }
   4619         }
   4620     }
   4621 
   4622     const result = try gz.addPlNode(.error_set_decl, node, Zir.Inst.ErrorSetDecl{
   4623         .fields_len = @intCast(u32, field_names.items.len),
   4624     });
   4625     try astgen.extra.appendSlice(gpa, field_names.items);
   4626     return rvalue(gz, rl, result, node);
   4627 }
   4628 
   4629 fn tryExpr(
   4630     parent_gz: *GenZir,
   4631     scope: *Scope,
   4632     rl: ResultLoc,
   4633     node: ast.Node.Index,
   4634     operand_node: ast.Node.Index,
   4635 ) InnerError!Zir.Inst.Ref {
   4636     const astgen = parent_gz.astgen;
   4637 
   4638     const fn_block = astgen.fn_block orelse {
   4639         return astgen.failNode(node, "'try' outside function scope", .{});
   4640     };
   4641 
   4642     if (parent_gz.in_defer) return astgen.failNode(node, "'try' not allowed inside defer expression", .{});
   4643 
   4644     var block_scope = parent_gz.makeSubBlock(scope);
   4645     block_scope.setBreakResultLoc(rl);
   4646     defer block_scope.instructions.deinit(astgen.gpa);
   4647 
   4648     const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {
   4649         .ref => .ref,
   4650         else => .none,
   4651     };
   4652     const err_ops = switch (rl) {
   4653         // zig fmt: off
   4654         .ref => [3]Zir.Inst.Tag{ .is_non_err_ptr, .err_union_code_ptr, .err_union_payload_unsafe_ptr },
   4655         else => [3]Zir.Inst.Tag{ .is_non_err,     .err_union_code,     .err_union_payload_unsafe },
   4656         // zig fmt: on
   4657     };
   4658     // This could be a pointer or value depending on the `operand_rl` parameter.
   4659     // We cannot use `block_scope.break_result_loc` because that has the bare
   4660     // type, whereas this expression has the optional type. Later we make
   4661     // up for this fact by calling rvalue on the else branch.
   4662     const operand = try expr(&block_scope, &block_scope.base, operand_rl, operand_node);
   4663     const cond = try block_scope.addUnNode(err_ops[0], operand, node);
   4664     const condbr = try block_scope.addCondBr(.condbr, node);
   4665 
   4666     const block = try parent_gz.addBlock(.block, node);
   4667     try parent_gz.instructions.append(astgen.gpa, block);
   4668     try block_scope.setBlockBody(block);
   4669 
   4670     var then_scope = parent_gz.makeSubBlock(scope);
   4671     defer then_scope.instructions.deinit(astgen.gpa);
   4672 
   4673     block_scope.break_count += 1;
   4674     // This could be a pointer or value depending on `err_ops[2]`.
   4675     const unwrapped_payload = try then_scope.addUnNode(err_ops[2], operand, node);
   4676     const then_result = switch (rl) {
   4677         .ref => unwrapped_payload,
   4678         else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node),
   4679     };
   4680 
   4681     var else_scope = parent_gz.makeSubBlock(scope);
   4682     defer else_scope.instructions.deinit(astgen.gpa);
   4683 
   4684     const err_code = try else_scope.addUnNode(err_ops[1], operand, node);
   4685     try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code });
   4686     const else_result = try else_scope.addUnNode(.ret_node, err_code, node);
   4687 
   4688     return finishThenElseBlock(
   4689         parent_gz,
   4690         rl,
   4691         node,
   4692         &block_scope,
   4693         &then_scope,
   4694         &else_scope,
   4695         condbr,
   4696         cond,
   4697         then_result,
   4698         else_result,
   4699         block,
   4700         block,
   4701         .@"break",
   4702     );
   4703 }
   4704 
   4705 fn orelseCatchExpr(
   4706     parent_gz: *GenZir,
   4707     scope: *Scope,
   4708     rl: ResultLoc,
   4709     node: ast.Node.Index,
   4710     lhs: ast.Node.Index,
   4711     cond_op: Zir.Inst.Tag,
   4712     unwrap_op: Zir.Inst.Tag,
   4713     unwrap_code_op: Zir.Inst.Tag,
   4714     rhs: ast.Node.Index,
   4715     payload_token: ?ast.TokenIndex,
   4716 ) InnerError!Zir.Inst.Ref {
   4717     const astgen = parent_gz.astgen;
   4718     const tree = astgen.tree;
   4719 
   4720     var block_scope = parent_gz.makeSubBlock(scope);
   4721     block_scope.setBreakResultLoc(rl);
   4722     defer block_scope.instructions.deinit(astgen.gpa);
   4723 
   4724     const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {
   4725         .ref => .ref,
   4726         else => .none,
   4727     };
   4728     block_scope.break_count += 1;
   4729     // This could be a pointer or value depending on the `operand_rl` parameter.
   4730     // We cannot use `block_scope.break_result_loc` because that has the bare
   4731     // type, whereas this expression has the optional type. Later we make
   4732     // up for this fact by calling rvalue on the else branch.
   4733     const operand = try expr(&block_scope, &block_scope.base, operand_rl, lhs);
   4734     const cond = try block_scope.addUnNode(cond_op, operand, node);
   4735     const condbr = try block_scope.addCondBr(.condbr, node);
   4736 
   4737     const block = try parent_gz.addBlock(.block, node);
   4738     try parent_gz.instructions.append(astgen.gpa, block);
   4739     try block_scope.setBlockBody(block);
   4740 
   4741     var then_scope = parent_gz.makeSubBlock(scope);
   4742     defer then_scope.instructions.deinit(astgen.gpa);
   4743 
   4744     // This could be a pointer or value depending on `unwrap_op`.
   4745     const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node);
   4746     const then_result = switch (rl) {
   4747         .ref => unwrapped_payload,
   4748         else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node),
   4749     };
   4750 
   4751     var else_scope = parent_gz.makeSubBlock(scope);
   4752     defer else_scope.instructions.deinit(astgen.gpa);
   4753 
   4754     var err_val_scope: Scope.LocalVal = undefined;
   4755     const else_sub_scope = blk: {
   4756         const payload = payload_token orelse break :blk &else_scope.base;
   4757         if (mem.eql(u8, tree.tokenSlice(payload), "_")) {
   4758             return astgen.failTok(payload, "discard of error capture; omit it instead", .{});
   4759         }
   4760         const err_name = try astgen.identAsString(payload);
   4761         err_val_scope = .{
   4762             .parent = &else_scope.base,
   4763             .gen_zir = &else_scope,
   4764             .name = err_name,
   4765             .inst = try else_scope.addUnNode(unwrap_code_op, operand, node),
   4766             .token_src = payload,
   4767             .id_cat = .@"capture",
   4768         };
   4769         break :blk &err_val_scope.base;
   4770     };
   4771 
   4772     block_scope.break_count += 1;
   4773     const else_result = try expr(&else_scope, else_sub_scope, block_scope.break_result_loc, rhs);
   4774     try checkUsed(parent_gz, &else_scope.base, else_sub_scope);
   4775 
   4776     // We hold off on the break instructions as well as copying the then/else
   4777     // instructions into place until we know whether to keep store_to_block_ptr
   4778     // instructions or not.
   4779 
   4780     return finishThenElseBlock(
   4781         parent_gz,
   4782         rl,
   4783         node,
   4784         &block_scope,
   4785         &then_scope,
   4786         &else_scope,
   4787         condbr,
   4788         cond,
   4789         then_result,
   4790         else_result,
   4791         block,
   4792         block,
   4793         .@"break",
   4794     );
   4795 }
   4796 
   4797 fn finishThenElseBlock(
   4798     parent_gz: *GenZir,
   4799     rl: ResultLoc,
   4800     node: ast.Node.Index,
   4801     block_scope: *GenZir,
   4802     then_scope: *GenZir,
   4803     else_scope: *GenZir,
   4804     condbr: Zir.Inst.Index,
   4805     cond: Zir.Inst.Ref,
   4806     then_result: Zir.Inst.Ref,
   4807     else_result: Zir.Inst.Ref,
   4808     main_block: Zir.Inst.Index,
   4809     then_break_block: Zir.Inst.Index,
   4810     break_tag: Zir.Inst.Tag,
   4811 ) InnerError!Zir.Inst.Ref {
   4812     // We now have enough information to decide whether the result instruction should
   4813     // be communicated via result location pointer or break instructions.
   4814     const strat = rl.strategy(block_scope);
   4815     switch (strat.tag) {
   4816         .break_void => {
   4817             if (!then_scope.endsWithNoReturn()) {
   4818                 _ = try then_scope.addBreak(break_tag, then_break_block, .void_value);
   4819             }
   4820             if (!else_scope.endsWithNoReturn()) {
   4821                 _ = try else_scope.addBreak(break_tag, main_block, .void_value);
   4822             }
   4823             assert(!strat.elide_store_to_block_ptr_instructions);
   4824             try setCondBrPayload(condbr, cond, then_scope, else_scope);
   4825             return indexToRef(main_block);
   4826         },
   4827         .break_operand => {
   4828             if (!then_scope.endsWithNoReturn()) {
   4829                 _ = try then_scope.addBreak(break_tag, then_break_block, then_result);
   4830             }
   4831             if (else_result != .none) {
   4832                 if (!else_scope.endsWithNoReturn()) {
   4833                     _ = try else_scope.addBreak(break_tag, main_block, else_result);
   4834                 }
   4835             } else {
   4836                 _ = try else_scope.addBreak(break_tag, main_block, .void_value);
   4837             }
   4838             if (strat.elide_store_to_block_ptr_instructions) {
   4839                 try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, else_scope, block_scope.rl_ptr);
   4840             } else {
   4841                 try setCondBrPayload(condbr, cond, then_scope, else_scope);
   4842             }
   4843             const block_ref = indexToRef(main_block);
   4844             switch (rl) {
   4845                 .ref => return block_ref,
   4846                 else => return rvalue(parent_gz, rl, block_ref, node),
   4847             }
   4848         },
   4849     }
   4850 }
   4851 
   4852 /// Return whether the identifier names of two tokens are equal. Resolves @""
   4853 /// tokens without allocating.
   4854 /// OK in theory it could do it without allocating. This implementation
   4855 /// allocates when the @"" form is used.
   4856 fn tokenIdentEql(astgen: *AstGen, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool {
   4857     const ident_name_1 = try astgen.identifierTokenString(token1);
   4858     const ident_name_2 = try astgen.identifierTokenString(token2);
   4859     return mem.eql(u8, ident_name_1, ident_name_2);
   4860 }
   4861 
   4862 fn fieldAccess(
   4863     gz: *GenZir,
   4864     scope: *Scope,
   4865     rl: ResultLoc,
   4866     node: ast.Node.Index,
   4867 ) InnerError!Zir.Inst.Ref {
   4868     const astgen = gz.astgen;
   4869     const tree = astgen.tree;
   4870     const main_tokens = tree.nodes.items(.main_token);
   4871     const node_datas = tree.nodes.items(.data);
   4872 
   4873     const object_node = node_datas[node].lhs;
   4874     const dot_token = main_tokens[node];
   4875     const field_ident = dot_token + 1;
   4876     const str_index = try astgen.identAsString(field_ident);
   4877     switch (rl) {
   4878         .ref => return gz.addPlNode(.field_ptr, node, Zir.Inst.Field{
   4879             .lhs = try expr(gz, scope, .ref, object_node),
   4880             .field_name_start = str_index,
   4881         }),
   4882         else => return rvalue(gz, rl, try gz.addPlNode(.field_val, node, Zir.Inst.Field{
   4883             .lhs = try expr(gz, scope, .none_or_ref, object_node),
   4884             .field_name_start = str_index,
   4885         }), node),
   4886     }
   4887 }
   4888 
   4889 fn arrayAccess(
   4890     gz: *GenZir,
   4891     scope: *Scope,
   4892     rl: ResultLoc,
   4893     node: ast.Node.Index,
   4894 ) InnerError!Zir.Inst.Ref {
   4895     const astgen = gz.astgen;
   4896     const tree = astgen.tree;
   4897     const node_datas = tree.nodes.items(.data);
   4898     switch (rl) {
   4899         .ref => return gz.addBin(
   4900             .elem_ptr,
   4901             try expr(gz, scope, .ref, node_datas[node].lhs),
   4902             try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),
   4903         ),
   4904         else => return rvalue(gz, rl, try gz.addBin(
   4905             .elem_val,
   4906             try expr(gz, scope, .none_or_ref, node_datas[node].lhs),
   4907             try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),
   4908         ), node),
   4909     }
   4910 }
   4911 
   4912 fn simpleBinOp(
   4913     gz: *GenZir,
   4914     scope: *Scope,
   4915     rl: ResultLoc,
   4916     node: ast.Node.Index,
   4917     op_inst_tag: Zir.Inst.Tag,
   4918 ) InnerError!Zir.Inst.Ref {
   4919     const astgen = gz.astgen;
   4920     const tree = astgen.tree;
   4921     const node_datas = tree.nodes.items(.data);
   4922 
   4923     const result = try gz.addPlNode(op_inst_tag, node, Zir.Inst.Bin{
   4924         .lhs = try expr(gz, scope, .none, node_datas[node].lhs),
   4925         .rhs = try expr(gz, scope, .none, node_datas[node].rhs),
   4926     });
   4927     return rvalue(gz, rl, result, node);
   4928 }
   4929 
   4930 fn simpleStrTok(
   4931     gz: *GenZir,
   4932     rl: ResultLoc,
   4933     ident_token: ast.TokenIndex,
   4934     node: ast.Node.Index,
   4935     op_inst_tag: Zir.Inst.Tag,
   4936 ) InnerError!Zir.Inst.Ref {
   4937     const astgen = gz.astgen;
   4938     const str_index = try astgen.identAsString(ident_token);
   4939     const result = try gz.addStrTok(op_inst_tag, str_index, ident_token);
   4940     return rvalue(gz, rl, result, node);
   4941 }
   4942 
   4943 fn boolBinOp(
   4944     gz: *GenZir,
   4945     scope: *Scope,
   4946     rl: ResultLoc,
   4947     node: ast.Node.Index,
   4948     zir_tag: Zir.Inst.Tag,
   4949 ) InnerError!Zir.Inst.Ref {
   4950     const astgen = gz.astgen;
   4951     const tree = astgen.tree;
   4952     const node_datas = tree.nodes.items(.data);
   4953 
   4954     const lhs = try expr(gz, scope, bool_rl, node_datas[node].lhs);
   4955     const bool_br = try gz.addBoolBr(zir_tag, lhs);
   4956 
   4957     var rhs_scope = gz.makeSubBlock(scope);
   4958     defer rhs_scope.instructions.deinit(gz.astgen.gpa);
   4959     const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs);
   4960     if (!gz.refIsNoReturn(rhs)) {
   4961         _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs);
   4962     }
   4963     try rhs_scope.setBoolBrBody(bool_br);
   4964 
   4965     const block_ref = indexToRef(bool_br);
   4966     return rvalue(gz, rl, block_ref, node);
   4967 }
   4968 
   4969 fn ifExpr(
   4970     parent_gz: *GenZir,
   4971     scope: *Scope,
   4972     rl: ResultLoc,
   4973     node: ast.Node.Index,
   4974     if_full: ast.full.If,
   4975 ) InnerError!Zir.Inst.Ref {
   4976     const astgen = parent_gz.astgen;
   4977     const tree = astgen.tree;
   4978     const token_tags = tree.tokens.items(.tag);
   4979 
   4980     var block_scope = parent_gz.makeSubBlock(scope);
   4981     block_scope.setBreakResultLoc(rl);
   4982     defer block_scope.instructions.deinit(astgen.gpa);
   4983 
   4984     const payload_is_ref = if (if_full.payload_token) |payload_token|
   4985         token_tags[payload_token] == .asterisk
   4986     else
   4987         false;
   4988 
   4989     const cond: struct {
   4990         inst: Zir.Inst.Ref,
   4991         bool_bit: Zir.Inst.Ref,
   4992     } = c: {
   4993         if (if_full.error_token) |_| {
   4994             const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;
   4995             const err_union = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr);
   4996             const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err;
   4997             break :c .{
   4998                 .inst = err_union,
   4999                 .bool_bit = try block_scope.addUnNode(tag, err_union, node),
   5000             };
   5001         } else if (if_full.payload_token) |_| {
   5002             const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;
   5003             const optional = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr);
   5004             const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null;
   5005             break :c .{
   5006                 .inst = optional,
   5007                 .bool_bit = try block_scope.addUnNode(tag, optional, node),
   5008             };
   5009         } else {
   5010             const cond = try expr(&block_scope, &block_scope.base, bool_rl, if_full.ast.cond_expr);
   5011             break :c .{
   5012                 .inst = cond,
   5013                 .bool_bit = cond,
   5014             };
   5015         }
   5016     };
   5017 
   5018     const condbr = try block_scope.addCondBr(.condbr, node);
   5019 
   5020     const block = try parent_gz.addBlock(.block, node);
   5021     try parent_gz.instructions.append(astgen.gpa, block);
   5022     try block_scope.setBlockBody(block);
   5023 
   5024     var then_scope = parent_gz.makeSubBlock(scope);
   5025     defer then_scope.instructions.deinit(astgen.gpa);
   5026 
   5027     var payload_val_scope: Scope.LocalVal = undefined;
   5028 
   5029     const then_sub_scope = s: {
   5030         if (if_full.error_token != null) {
   5031             if (if_full.payload_token) |payload_token| {
   5032                 const tag: Zir.Inst.Tag = if (payload_is_ref)
   5033                     .err_union_payload_unsafe_ptr
   5034                 else
   5035                     .err_union_payload_unsafe;
   5036                 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
   5037                 const token_name_index = payload_token + @boolToInt(payload_is_ref);
   5038                 const ident_name = try astgen.identAsString(token_name_index);
   5039                 const token_name_str = tree.tokenSlice(token_name_index);
   5040                 if (mem.eql(u8, "_", token_name_str))
   5041                     break :s &then_scope.base;
   5042                 try astgen.detectLocalShadowing(&then_scope.base, ident_name, token_name_index, token_name_str);
   5043                 payload_val_scope = .{
   5044                     .parent = &then_scope.base,
   5045                     .gen_zir = &then_scope,
   5046                     .name = ident_name,
   5047                     .inst = payload_inst,
   5048                     .token_src = payload_token,
   5049                     .id_cat = .@"capture",
   5050                 };
   5051                 break :s &payload_val_scope.base;
   5052             } else {
   5053                 break :s &then_scope.base;
   5054             }
   5055         } else if (if_full.payload_token) |payload_token| {
   5056             const ident_token = if (payload_is_ref) payload_token + 1 else payload_token;
   5057             const tag: Zir.Inst.Tag = if (payload_is_ref)
   5058                 .optional_payload_unsafe_ptr
   5059             else
   5060                 .optional_payload_unsafe;
   5061             const ident_bytes = tree.tokenSlice(ident_token);
   5062             if (mem.eql(u8, "_", ident_bytes))
   5063                 break :s &then_scope.base;
   5064             const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
   5065             const ident_name = try astgen.identAsString(ident_token);
   5066             try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes);
   5067             payload_val_scope = .{
   5068                 .parent = &then_scope.base,
   5069                 .gen_zir = &then_scope,
   5070                 .name = ident_name,
   5071                 .inst = payload_inst,
   5072                 .token_src = ident_token,
   5073                 .id_cat = .@"capture",
   5074             };
   5075             break :s &payload_val_scope.base;
   5076         } else {
   5077             break :s &then_scope.base;
   5078         }
   5079     };
   5080 
   5081     block_scope.break_count += 1;
   5082     const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, if_full.ast.then_expr);
   5083     try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
   5084     // We hold off on the break instructions as well as copying the then/else
   5085     // instructions into place until we know whether to keep store_to_block_ptr
   5086     // instructions or not.
   5087 
   5088     var else_scope = parent_gz.makeSubBlock(scope);
   5089     defer else_scope.instructions.deinit(astgen.gpa);
   5090 
   5091     const else_node = if_full.ast.else_expr;
   5092     const else_info: struct {
   5093         src: ast.Node.Index,
   5094         result: Zir.Inst.Ref,
   5095     } = if (else_node != 0) blk: {
   5096         block_scope.break_count += 1;
   5097         const sub_scope = s: {
   5098             if (if_full.error_token) |error_token| {
   5099                 const tag: Zir.Inst.Tag = if (payload_is_ref)
   5100                     .err_union_code_ptr
   5101                 else
   5102                     .err_union_code;
   5103                 const payload_inst = try else_scope.addUnNode(tag, cond.inst, node);
   5104                 const ident_name = try astgen.identAsString(error_token);
   5105                 const error_token_str = tree.tokenSlice(error_token);
   5106                 if (mem.eql(u8, "_", error_token_str))
   5107                     break :s &else_scope.base;
   5108                 try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token, error_token_str);
   5109                 payload_val_scope = .{
   5110                     .parent = &else_scope.base,
   5111                     .gen_zir = &else_scope,
   5112                     .name = ident_name,
   5113                     .inst = payload_inst,
   5114                     .token_src = error_token,
   5115                     .id_cat = .@"capture",
   5116                 };
   5117                 break :s &payload_val_scope.base;
   5118             } else {
   5119                 break :s &else_scope.base;
   5120             }
   5121         };
   5122         const e = try expr(&else_scope, sub_scope, block_scope.break_result_loc, else_node);
   5123         try checkUsed(parent_gz, &else_scope.base, sub_scope);
   5124         break :blk .{
   5125             .src = else_node,
   5126             .result = e,
   5127         };
   5128     } else .{
   5129         .src = if_full.ast.then_expr,
   5130         .result = .none,
   5131     };
   5132 
   5133     return finishThenElseBlock(
   5134         parent_gz,
   5135         rl,
   5136         node,
   5137         &block_scope,
   5138         &then_scope,
   5139         &else_scope,
   5140         condbr,
   5141         cond.bool_bit,
   5142         then_result,
   5143         else_info.result,
   5144         block,
   5145         block,
   5146         .@"break",
   5147     );
   5148 }
   5149 
   5150 fn setCondBrPayload(
   5151     condbr: Zir.Inst.Index,
   5152     cond: Zir.Inst.Ref,
   5153     then_scope: *GenZir,
   5154     else_scope: *GenZir,
   5155 ) !void {
   5156     const astgen = then_scope.astgen;
   5157 
   5158     try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len +
   5159         then_scope.instructions.items.len + else_scope.instructions.items.len);
   5160 
   5161     const zir_datas = astgen.instructions.items(.data);
   5162     zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{
   5163         .condition = cond,
   5164         .then_body_len = @intCast(u32, then_scope.instructions.items.len),
   5165         .else_body_len = @intCast(u32, else_scope.instructions.items.len),
   5166     });
   5167     astgen.extra.appendSliceAssumeCapacity(then_scope.instructions.items);
   5168     astgen.extra.appendSliceAssumeCapacity(else_scope.instructions.items);
   5169 }
   5170 
   5171 fn setCondBrPayloadElideBlockStorePtr(
   5172     condbr: Zir.Inst.Index,
   5173     cond: Zir.Inst.Ref,
   5174     then_scope: *GenZir,
   5175     else_scope: *GenZir,
   5176     block_ptr: Zir.Inst.Ref,
   5177 ) !void {
   5178     const astgen = then_scope.astgen;
   5179 
   5180     try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len +
   5181         then_scope.instructions.items.len + else_scope.instructions.items.len);
   5182 
   5183     const zir_tags = astgen.instructions.items(.tag);
   5184     const zir_datas = astgen.instructions.items(.data);
   5185 
   5186     const condbr_pl = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{
   5187         .condition = cond,
   5188         .then_body_len = @intCast(u32, then_scope.instructions.items.len),
   5189         .else_body_len = @intCast(u32, else_scope.instructions.items.len),
   5190     });
   5191     zir_datas[condbr].pl_node.payload_index = condbr_pl;
   5192     const then_body_len_index = condbr_pl + 1;
   5193     const else_body_len_index = condbr_pl + 2;
   5194 
   5195     for (then_scope.instructions.items) |src_inst| {
   5196         if (zir_tags[src_inst] == .store_to_block_ptr) {
   5197             if (zir_datas[src_inst].bin.lhs == block_ptr) {
   5198                 astgen.extra.items[then_body_len_index] -= 1;
   5199                 continue;
   5200             }
   5201         }
   5202         astgen.extra.appendAssumeCapacity(src_inst);
   5203     }
   5204     for (else_scope.instructions.items) |src_inst| {
   5205         if (zir_tags[src_inst] == .store_to_block_ptr) {
   5206             if (zir_datas[src_inst].bin.lhs == block_ptr) {
   5207                 astgen.extra.items[else_body_len_index] -= 1;
   5208                 continue;
   5209             }
   5210         }
   5211         astgen.extra.appendAssumeCapacity(src_inst);
   5212     }
   5213 }
   5214 
   5215 fn whileExpr(
   5216     parent_gz: *GenZir,
   5217     scope: *Scope,
   5218     rl: ResultLoc,
   5219     node: ast.Node.Index,
   5220     while_full: ast.full.While,
   5221 ) InnerError!Zir.Inst.Ref {
   5222     const astgen = parent_gz.astgen;
   5223     const tree = astgen.tree;
   5224     const token_tags = tree.tokens.items(.tag);
   5225 
   5226     if (while_full.label_token) |label_token| {
   5227         try astgen.checkLabelRedefinition(scope, label_token);
   5228     }
   5229 
   5230     const is_inline = parent_gz.force_comptime or while_full.inline_token != null;
   5231     const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;
   5232     const loop_block = try parent_gz.addBlock(loop_tag, node);
   5233     try parent_gz.instructions.append(astgen.gpa, loop_block);
   5234 
   5235     var loop_scope = parent_gz.makeSubBlock(scope);
   5236     loop_scope.setBreakResultLoc(rl);
   5237     defer loop_scope.instructions.deinit(astgen.gpa);
   5238     defer loop_scope.labeled_breaks.deinit(astgen.gpa);
   5239     defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);
   5240 
   5241     var continue_scope = parent_gz.makeSubBlock(&loop_scope.base);
   5242     defer continue_scope.instructions.deinit(astgen.gpa);
   5243 
   5244     const payload_is_ref = if (while_full.payload_token) |payload_token|
   5245         token_tags[payload_token] == .asterisk
   5246     else
   5247         false;
   5248 
   5249     const cond: struct {
   5250         inst: Zir.Inst.Ref,
   5251         bool_bit: Zir.Inst.Ref,
   5252     } = c: {
   5253         if (while_full.error_token) |_| {
   5254             const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;
   5255             const err_union = try expr(&continue_scope, &continue_scope.base, cond_rl, while_full.ast.cond_expr);
   5256             const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err;
   5257             break :c .{
   5258                 .inst = err_union,
   5259                 .bool_bit = try continue_scope.addUnNode(tag, err_union, node),
   5260             };
   5261         } else if (while_full.payload_token) |_| {
   5262             const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;
   5263             const optional = try expr(&continue_scope, &continue_scope.base, cond_rl, while_full.ast.cond_expr);
   5264             const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null;
   5265             break :c .{
   5266                 .inst = optional,
   5267                 .bool_bit = try continue_scope.addUnNode(tag, optional, node),
   5268             };
   5269         } else {
   5270             const cond = try expr(&continue_scope, &continue_scope.base, bool_rl, while_full.ast.cond_expr);
   5271             break :c .{
   5272                 .inst = cond,
   5273                 .bool_bit = cond,
   5274             };
   5275         }
   5276     };
   5277 
   5278     const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr;
   5279     const condbr = try continue_scope.addCondBr(condbr_tag, node);
   5280     const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
   5281     const cond_block = try loop_scope.addBlock(block_tag, node);
   5282     try loop_scope.instructions.append(astgen.gpa, cond_block);
   5283     try continue_scope.setBlockBody(cond_block);
   5284 
   5285     var then_scope = parent_gz.makeSubBlock(&continue_scope.base);
   5286     defer then_scope.instructions.deinit(astgen.gpa);
   5287 
   5288     var payload_val_scope: Scope.LocalVal = undefined;
   5289 
   5290     const then_sub_scope = s: {
   5291         if (while_full.error_token != null) {
   5292             if (while_full.payload_token) |payload_token| {
   5293                 const tag: Zir.Inst.Tag = if (payload_is_ref)
   5294                     .err_union_payload_unsafe_ptr
   5295                 else
   5296                     .err_union_payload_unsafe;
   5297                 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
   5298                 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token;
   5299                 const ident_bytes = tree.tokenSlice(ident_token);
   5300                 if (mem.eql(u8, "_", ident_bytes))
   5301                     break :s &then_scope.base;
   5302                 const payload_name_loc = payload_token + @boolToInt(payload_is_ref);
   5303                 const ident_name = try astgen.identAsString(payload_name_loc);
   5304                 try astgen.detectLocalShadowing(&then_scope.base, ident_name, payload_name_loc, ident_bytes);
   5305                 payload_val_scope = .{
   5306                     .parent = &then_scope.base,
   5307                     .gen_zir = &then_scope,
   5308                     .name = ident_name,
   5309                     .inst = payload_inst,
   5310                     .token_src = payload_token,
   5311                     .id_cat = .@"capture",
   5312                 };
   5313                 break :s &payload_val_scope.base;
   5314             } else {
   5315                 break :s &then_scope.base;
   5316             }
   5317         } else if (while_full.payload_token) |payload_token| {
   5318             const ident_token = if (payload_is_ref) payload_token + 1 else payload_token;
   5319             const tag: Zir.Inst.Tag = if (payload_is_ref)
   5320                 .optional_payload_unsafe_ptr
   5321             else
   5322                 .optional_payload_unsafe;
   5323             const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
   5324             const ident_name = try astgen.identAsString(ident_token);
   5325             const ident_bytes = tree.tokenSlice(ident_token);
   5326             if (mem.eql(u8, "_", ident_bytes))
   5327                 break :s &then_scope.base;
   5328             try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes);
   5329             payload_val_scope = .{
   5330                 .parent = &then_scope.base,
   5331                 .gen_zir = &then_scope,
   5332                 .name = ident_name,
   5333                 .inst = payload_inst,
   5334                 .token_src = ident_token,
   5335                 .id_cat = .@"capture",
   5336             };
   5337             break :s &payload_val_scope.base;
   5338         } else {
   5339             break :s &then_scope.base;
   5340         }
   5341     };
   5342 
   5343     // This code could be improved to avoid emitting the continue expr when there
   5344     // are no jumps to it. This happens when the last statement of a while body is noreturn
   5345     // and there are no `continue` statements.
   5346     // Tracking issue: https://github.com/ziglang/zig/issues/9185
   5347     if (while_full.ast.cont_expr != 0) {
   5348         _ = try expr(&loop_scope, then_sub_scope, .{ .ty = .void_type }, while_full.ast.cont_expr);
   5349     }
   5350     const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;
   5351     _ = try loop_scope.addNode(repeat_tag, node);
   5352 
   5353     try loop_scope.setBlockBody(loop_block);
   5354     loop_scope.break_block = loop_block;
   5355     loop_scope.continue_block = cond_block;
   5356     if (while_full.label_token) |label_token| {
   5357         loop_scope.label = @as(?GenZir.Label, GenZir.Label{
   5358             .token = label_token,
   5359             .block_inst = loop_block,
   5360         });
   5361     }
   5362 
   5363     loop_scope.break_count += 1;
   5364     const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr);
   5365     try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
   5366 
   5367     var else_scope = parent_gz.makeSubBlock(&continue_scope.base);
   5368     defer else_scope.instructions.deinit(astgen.gpa);
   5369 
   5370     const else_node = while_full.ast.else_expr;
   5371     const else_info: struct {
   5372         src: ast.Node.Index,
   5373         result: Zir.Inst.Ref,
   5374     } = if (else_node != 0) blk: {
   5375         loop_scope.break_count += 1;
   5376         const sub_scope = s: {
   5377             if (while_full.error_token) |error_token| {
   5378                 const tag: Zir.Inst.Tag = if (payload_is_ref)
   5379                     .err_union_code_ptr
   5380                 else
   5381                     .err_union_code;
   5382                 const payload_inst = try else_scope.addUnNode(tag, cond.inst, node);
   5383                 const ident_name = try astgen.identAsString(error_token);
   5384                 const ident_bytes = tree.tokenSlice(error_token);
   5385                 if (mem.eql(u8, ident_bytes, "_"))
   5386                     break :s &else_scope.base;
   5387                 try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token, ident_bytes);
   5388                 payload_val_scope = .{
   5389                     .parent = &else_scope.base,
   5390                     .gen_zir = &else_scope,
   5391                     .name = ident_name,
   5392                     .inst = payload_inst,
   5393                     .token_src = error_token,
   5394                     .id_cat = .@"capture",
   5395                 };
   5396                 break :s &payload_val_scope.base;
   5397             } else {
   5398                 break :s &else_scope.base;
   5399             }
   5400         };
   5401         const e = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node);
   5402         try checkUsed(parent_gz, &else_scope.base, sub_scope);
   5403         break :blk .{
   5404             .src = else_node,
   5405             .result = e,
   5406         };
   5407     } else .{
   5408         .src = while_full.ast.then_expr,
   5409         .result = .none,
   5410     };
   5411 
   5412     if (loop_scope.label) |some| {
   5413         if (!some.used) {
   5414             return astgen.failTok(some.token, "unused while loop label", .{});
   5415         }
   5416     }
   5417     const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
   5418     return finishThenElseBlock(
   5419         parent_gz,
   5420         rl,
   5421         node,
   5422         &loop_scope,
   5423         &then_scope,
   5424         &else_scope,
   5425         condbr,
   5426         cond.bool_bit,
   5427         then_result,
   5428         else_info.result,
   5429         loop_block,
   5430         cond_block,
   5431         break_tag,
   5432     );
   5433 }
   5434 
   5435 fn forExpr(
   5436     parent_gz: *GenZir,
   5437     scope: *Scope,
   5438     rl: ResultLoc,
   5439     node: ast.Node.Index,
   5440     for_full: ast.full.While,
   5441 ) InnerError!Zir.Inst.Ref {
   5442     const astgen = parent_gz.astgen;
   5443 
   5444     if (for_full.label_token) |label_token| {
   5445         try astgen.checkLabelRedefinition(scope, label_token);
   5446     }
   5447 
   5448     // Set up variables and constants.
   5449     const is_inline = parent_gz.force_comptime or for_full.inline_token != null;
   5450     const tree = astgen.tree;
   5451     const token_tags = tree.tokens.items(.tag);
   5452 
   5453     const payload_is_ref = if (for_full.payload_token) |payload_token|
   5454         token_tags[payload_token] == .asterisk
   5455     else
   5456         false;
   5457 
   5458     const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;
   5459     const array_ptr = try expr(parent_gz, scope, cond_rl, for_full.ast.cond_expr);
   5460     const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr);
   5461 
   5462     const index_ptr = blk: {
   5463         const index_ptr = try parent_gz.addUnNode(.alloc, .usize_type, node);
   5464         // initialize to zero
   5465         _ = try parent_gz.addBin(.store, index_ptr, .zero_usize);
   5466         break :blk index_ptr;
   5467     };
   5468 
   5469     const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;
   5470     const loop_block = try parent_gz.addBlock(loop_tag, node);
   5471     try parent_gz.instructions.append(astgen.gpa, loop_block);
   5472 
   5473     var loop_scope = parent_gz.makeSubBlock(scope);
   5474     loop_scope.setBreakResultLoc(rl);
   5475     defer loop_scope.instructions.deinit(astgen.gpa);
   5476     defer loop_scope.labeled_breaks.deinit(astgen.gpa);
   5477     defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);
   5478 
   5479     var cond_scope = parent_gz.makeSubBlock(&loop_scope.base);
   5480     defer cond_scope.instructions.deinit(astgen.gpa);
   5481 
   5482     // check condition i < array_expr.len
   5483     const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);
   5484     const cond = try cond_scope.addPlNode(.cmp_lt, for_full.ast.cond_expr, Zir.Inst.Bin{
   5485         .lhs = index,
   5486         .rhs = len,
   5487     });
   5488 
   5489     const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr;
   5490     const condbr = try cond_scope.addCondBr(condbr_tag, node);
   5491     const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
   5492     const cond_block = try loop_scope.addBlock(block_tag, node);
   5493     try loop_scope.instructions.append(astgen.gpa, cond_block);
   5494     try cond_scope.setBlockBody(cond_block);
   5495 
   5496     // Increment the index variable.
   5497     const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);
   5498     const index_plus_one = try loop_scope.addPlNode(.add, node, Zir.Inst.Bin{
   5499         .lhs = index_2,
   5500         .rhs = .one_usize,
   5501     });
   5502     _ = try loop_scope.addBin(.store, index_ptr, index_plus_one);
   5503     const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;
   5504     _ = try loop_scope.addNode(repeat_tag, node);
   5505 
   5506     try loop_scope.setBlockBody(loop_block);
   5507     loop_scope.break_block = loop_block;
   5508     loop_scope.continue_block = cond_block;
   5509     if (for_full.label_token) |label_token| {
   5510         loop_scope.label = @as(?GenZir.Label, GenZir.Label{
   5511             .token = label_token,
   5512             .block_inst = loop_block,
   5513         });
   5514     }
   5515 
   5516     var then_scope = parent_gz.makeSubBlock(&cond_scope.base);
   5517     defer then_scope.instructions.deinit(astgen.gpa);
   5518 
   5519     var payload_val_scope: Scope.LocalVal = undefined;
   5520     var index_scope: Scope.LocalPtr = undefined;
   5521     const then_sub_scope = blk: {
   5522         const payload_token = for_full.payload_token.?;
   5523         const ident = if (token_tags[payload_token] == .asterisk)
   5524             payload_token + 1
   5525         else
   5526             payload_token;
   5527         const is_ptr = ident != payload_token;
   5528         const value_name = tree.tokenSlice(ident);
   5529         var payload_sub_scope: *Scope = undefined;
   5530         if (!mem.eql(u8, value_name, "_")) {
   5531             const name_str_index = try astgen.identAsString(ident);
   5532             const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val;
   5533             const payload_inst = try then_scope.addBin(tag, array_ptr, index);
   5534             try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name);
   5535             payload_val_scope = .{
   5536                 .parent = &then_scope.base,
   5537                 .gen_zir = &then_scope,
   5538                 .name = name_str_index,
   5539                 .inst = payload_inst,
   5540                 .token_src = ident,
   5541                 .id_cat = .@"capture",
   5542             };
   5543             payload_sub_scope = &payload_val_scope.base;
   5544         } else if (is_ptr) {
   5545             return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{});
   5546         } else {
   5547             payload_sub_scope = &then_scope.base;
   5548         }
   5549 
   5550         const index_token = if (token_tags[ident + 1] == .comma)
   5551             ident + 2
   5552         else
   5553             break :blk payload_sub_scope;
   5554         const token_bytes = tree.tokenSlice(index_token);
   5555         if (mem.eql(u8, token_bytes, "_")) {
   5556             return astgen.failTok(index_token, "discard of index capture; omit it instead", .{});
   5557         }
   5558         const index_name = try astgen.identAsString(index_token);
   5559         try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes);
   5560         index_scope = .{
   5561             .parent = payload_sub_scope,
   5562             .gen_zir = &then_scope,
   5563             .name = index_name,
   5564             .ptr = index_ptr,
   5565             .token_src = index_token,
   5566             .maybe_comptime = is_inline,
   5567             .id_cat = .@"loop index capture",
   5568         };
   5569         break :blk &index_scope.base;
   5570     };
   5571 
   5572     loop_scope.break_count += 1;
   5573     const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr);
   5574     try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
   5575 
   5576     var else_scope = parent_gz.makeSubBlock(&cond_scope.base);
   5577     defer else_scope.instructions.deinit(astgen.gpa);
   5578 
   5579     const else_node = for_full.ast.else_expr;
   5580     const else_info: struct {
   5581         src: ast.Node.Index,
   5582         result: Zir.Inst.Ref,
   5583     } = if (else_node != 0) blk: {
   5584         loop_scope.break_count += 1;
   5585         const sub_scope = &else_scope.base;
   5586         break :blk .{
   5587             .src = else_node,
   5588             .result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node),
   5589         };
   5590     } else .{
   5591         .src = for_full.ast.then_expr,
   5592         .result = .none,
   5593     };
   5594 
   5595     if (loop_scope.label) |some| {
   5596         if (!some.used) {
   5597             return astgen.failTok(some.token, "unused for loop label", .{});
   5598         }
   5599     }
   5600     const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
   5601     return finishThenElseBlock(
   5602         parent_gz,
   5603         rl,
   5604         node,
   5605         &loop_scope,
   5606         &then_scope,
   5607         &else_scope,
   5608         condbr,
   5609         cond,
   5610         then_result,
   5611         else_info.result,
   5612         loop_block,
   5613         cond_block,
   5614         break_tag,
   5615     );
   5616 }
   5617 
   5618 fn switchExpr(
   5619     parent_gz: *GenZir,
   5620     scope: *Scope,
   5621     rl: ResultLoc,
   5622     switch_node: ast.Node.Index,
   5623 ) InnerError!Zir.Inst.Ref {
   5624     const astgen = parent_gz.astgen;
   5625     const gpa = astgen.gpa;
   5626     const tree = astgen.tree;
   5627     const node_datas = tree.nodes.items(.data);
   5628     const node_tags = tree.nodes.items(.tag);
   5629     const main_tokens = tree.nodes.items(.main_token);
   5630     const token_tags = tree.tokens.items(.tag);
   5631     const operand_node = node_datas[switch_node].lhs;
   5632     const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange);
   5633     const case_nodes = tree.extra_data[extra.start..extra.end];
   5634 
   5635     // We perform two passes over the AST. This first pass is to collect information
   5636     // for the following variables, make note of the special prong AST node index,
   5637     // and bail out with a compile error if there are multiple special prongs present.
   5638     var any_payload_is_ref = false;
   5639     var scalar_cases_len: u32 = 0;
   5640     var multi_cases_len: u32 = 0;
   5641     var special_prong: Zir.SpecialProng = .none;
   5642     var special_node: ast.Node.Index = 0;
   5643     var else_src: ?ast.TokenIndex = null;
   5644     var underscore_src: ?ast.TokenIndex = null;
   5645     for (case_nodes) |case_node| {
   5646         const case = switch (node_tags[case_node]) {
   5647             .switch_case_one => tree.switchCaseOne(case_node),
   5648             .switch_case => tree.switchCase(case_node),
   5649             else => unreachable,
   5650         };
   5651         if (case.payload_token) |payload_token| {
   5652             if (token_tags[payload_token] == .asterisk) {
   5653                 any_payload_is_ref = true;
   5654             }
   5655         }
   5656         // Check for else/`_` prong.
   5657         if (case.ast.values.len == 0) {
   5658             const case_src = case.ast.arrow_token - 1;
   5659             if (else_src) |src| {
   5660                 return astgen.failTokNotes(
   5661                     case_src,
   5662                     "multiple else prongs in switch expression",
   5663                     .{},
   5664                     &[_]u32{
   5665                         try astgen.errNoteTok(
   5666                             src,
   5667                             "previous else prong here",
   5668                             .{},
   5669                         ),
   5670                     },
   5671                 );
   5672             } else if (underscore_src) |some_underscore| {
   5673                 return astgen.failNodeNotes(
   5674                     switch_node,
   5675                     "else and '_' prong in switch expression",
   5676                     .{},
   5677                     &[_]u32{
   5678                         try astgen.errNoteTok(
   5679                             case_src,
   5680                             "else prong here",
   5681                             .{},
   5682                         ),
   5683                         try astgen.errNoteTok(
   5684                             some_underscore,
   5685                             "'_' prong here",
   5686                             .{},
   5687                         ),
   5688                     },
   5689                 );
   5690             }
   5691             special_node = case_node;
   5692             special_prong = .@"else";
   5693             else_src = case_src;
   5694             continue;
   5695         } else if (case.ast.values.len == 1 and
   5696             node_tags[case.ast.values[0]] == .identifier and
   5697             mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"))
   5698         {
   5699             const case_src = case.ast.arrow_token - 1;
   5700             if (underscore_src) |src| {
   5701                 return astgen.failTokNotes(
   5702                     case_src,
   5703                     "multiple '_' prongs in switch expression",
   5704                     .{},
   5705                     &[_]u32{
   5706                         try astgen.errNoteTok(
   5707                             src,
   5708                             "previous '_' prong here",
   5709                             .{},
   5710                         ),
   5711                     },
   5712                 );
   5713             } else if (else_src) |some_else| {
   5714                 return astgen.failNodeNotes(
   5715                     switch_node,
   5716                     "else and '_' prong in switch expression",
   5717                     .{},
   5718                     &[_]u32{
   5719                         try astgen.errNoteTok(
   5720                             some_else,
   5721                             "else prong here",
   5722                             .{},
   5723                         ),
   5724                         try astgen.errNoteTok(
   5725                             case_src,
   5726                             "'_' prong here",
   5727                             .{},
   5728                         ),
   5729                     },
   5730                 );
   5731             }
   5732             special_node = case_node;
   5733             special_prong = .under;
   5734             underscore_src = case_src;
   5735             continue;
   5736         }
   5737 
   5738         if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) {
   5739             scalar_cases_len += 1;
   5740         } else {
   5741             multi_cases_len += 1;
   5742         }
   5743     }
   5744 
   5745     const operand_rl: ResultLoc = if (any_payload_is_ref) .ref else .none;
   5746     const operand = try expr(parent_gz, scope, operand_rl, operand_node);
   5747     // We need the type of the operand to use as the result location for all the prong items.
   5748     const typeof_tag: Zir.Inst.Tag = if (any_payload_is_ref) .typeof_elem else .typeof;
   5749     const operand_ty_inst = try parent_gz.addUnNode(typeof_tag, operand, operand_node);
   5750     const item_rl: ResultLoc = .{ .ty = operand_ty_inst };
   5751 
   5752     // Contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti.
   5753     // This is the header as well as the optional else prong body, as well as all the
   5754     // scalar cases.
   5755     // At the end we will memcpy this into place.
   5756     var scalar_cases_payload = ArrayListUnmanaged(u32){};
   5757     defer scalar_cases_payload.deinit(gpa);
   5758     // Same deal, but this is only the `extra` data for the multi cases.
   5759     var multi_cases_payload = ArrayListUnmanaged(u32){};
   5760     defer multi_cases_payload.deinit(gpa);
   5761 
   5762     var block_scope = parent_gz.makeSubBlock(scope);
   5763     block_scope.setBreakResultLoc(rl);
   5764     defer block_scope.instructions.deinit(gpa);
   5765 
   5766     // This gets added to the parent block later, after the item expressions.
   5767     const switch_block = try parent_gz.addBlock(undefined, switch_node);
   5768 
   5769     // We re-use this same scope for all cases, including the special prong, if any.
   5770     var case_scope = parent_gz.makeSubBlock(&block_scope.base);
   5771     defer case_scope.instructions.deinit(gpa);
   5772 
   5773     // Do the else/`_` first because it goes first in the payload.
   5774     var capture_val_scope: Scope.LocalVal = undefined;
   5775     if (special_node != 0) {
   5776         const case = switch (node_tags[special_node]) {
   5777             .switch_case_one => tree.switchCaseOne(special_node),
   5778             .switch_case => tree.switchCase(special_node),
   5779             else => unreachable,
   5780         };
   5781         const sub_scope = blk: {
   5782             const payload_token = case.payload_token orelse break :blk &case_scope.base;
   5783             const ident = if (token_tags[payload_token] == .asterisk)
   5784                 payload_token + 1
   5785             else
   5786                 payload_token;
   5787             const is_ptr = ident != payload_token;
   5788             if (mem.eql(u8, tree.tokenSlice(ident), "_")) {
   5789                 if (is_ptr) {
   5790                     return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{});
   5791                 }
   5792                 break :blk &case_scope.base;
   5793             }
   5794             const capture_tag: Zir.Inst.Tag = if (is_ptr)
   5795                 .switch_capture_else_ref
   5796             else
   5797                 .switch_capture_else;
   5798             const capture = try case_scope.add(.{
   5799                 .tag = capture_tag,
   5800                 .data = .{ .switch_capture = .{
   5801                     .switch_inst = switch_block,
   5802                     .prong_index = undefined,
   5803                 } },
   5804             });
   5805             const capture_name = try astgen.identAsString(payload_token);
   5806             capture_val_scope = .{
   5807                 .parent = &case_scope.base,
   5808                 .gen_zir = &case_scope,
   5809                 .name = capture_name,
   5810                 .inst = capture,
   5811                 .token_src = payload_token,
   5812                 .id_cat = .@"capture",
   5813             };
   5814             break :blk &capture_val_scope.base;
   5815         };
   5816         const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
   5817         try checkUsed(parent_gz, &case_scope.base, sub_scope);
   5818         if (!parent_gz.refIsNoReturn(case_result)) {
   5819             block_scope.break_count += 1;
   5820             _ = try case_scope.addBreak(.@"break", switch_block, case_result);
   5821         }
   5822         // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.
   5823         try scalar_cases_payload.ensureUnusedCapacity(gpa, case_scope.instructions.items.len +
   5824             3 + // operand, scalar_cases_len, else body len
   5825             @boolToInt(multi_cases_len != 0));
   5826         scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand));
   5827         scalar_cases_payload.appendAssumeCapacity(scalar_cases_len);
   5828         if (multi_cases_len != 0) {
   5829             scalar_cases_payload.appendAssumeCapacity(multi_cases_len);
   5830         }
   5831         scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len));
   5832         scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items);
   5833     } else {
   5834         // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.
   5835         try scalar_cases_payload.ensureUnusedCapacity(
   5836             gpa,
   5837             @as(usize, 2) + // operand, scalar_cases_len
   5838                 @boolToInt(multi_cases_len != 0),
   5839         );
   5840         scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand));
   5841         scalar_cases_payload.appendAssumeCapacity(scalar_cases_len);
   5842         if (multi_cases_len != 0) {
   5843             scalar_cases_payload.appendAssumeCapacity(multi_cases_len);
   5844         }
   5845     }
   5846 
   5847     // In this pass we generate all the item and prong expressions except the special case.
   5848     var multi_case_index: u32 = 0;
   5849     var scalar_case_index: u32 = 0;
   5850     for (case_nodes) |case_node| {
   5851         if (case_node == special_node)
   5852             continue;
   5853         const case = switch (node_tags[case_node]) {
   5854             .switch_case_one => tree.switchCaseOne(case_node),
   5855             .switch_case => tree.switchCase(case_node),
   5856             else => unreachable,
   5857         };
   5858 
   5859         // Reset the scope.
   5860         case_scope.instructions.shrinkRetainingCapacity(0);
   5861 
   5862         const is_multi_case = case.ast.values.len != 1 or
   5863             node_tags[case.ast.values[0]] == .switch_range;
   5864 
   5865         const sub_scope = blk: {
   5866             const payload_token = case.payload_token orelse break :blk &case_scope.base;
   5867             const ident = if (token_tags[payload_token] == .asterisk)
   5868                 payload_token + 1
   5869             else
   5870                 payload_token;
   5871             const is_ptr = ident != payload_token;
   5872             if (mem.eql(u8, tree.tokenSlice(ident), "_")) {
   5873                 if (is_ptr) {
   5874                     return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{});
   5875                 }
   5876                 break :blk &case_scope.base;
   5877             }
   5878             const is_multi_case_bits: u2 = @boolToInt(is_multi_case);
   5879             const is_ptr_bits: u2 = @boolToInt(is_ptr);
   5880             const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) {
   5881                 0b00 => .switch_capture,
   5882                 0b01 => .switch_capture_ref,
   5883                 0b10 => .switch_capture_multi,
   5884                 0b11 => .switch_capture_multi_ref,
   5885             };
   5886             const capture_index = if (is_multi_case) ci: {
   5887                 multi_case_index += 1;
   5888                 break :ci multi_case_index - 1;
   5889             } else ci: {
   5890                 scalar_case_index += 1;
   5891                 break :ci scalar_case_index - 1;
   5892             };
   5893             const capture = try case_scope.add(.{
   5894                 .tag = capture_tag,
   5895                 .data = .{ .switch_capture = .{
   5896                     .switch_inst = switch_block,
   5897                     .prong_index = capture_index,
   5898                 } },
   5899             });
   5900             const capture_name = try astgen.identAsString(ident);
   5901             capture_val_scope = .{
   5902                 .parent = &case_scope.base,
   5903                 .gen_zir = &case_scope,
   5904                 .name = capture_name,
   5905                 .inst = capture,
   5906                 .token_src = payload_token,
   5907                 .id_cat = .@"capture",
   5908             };
   5909             break :blk &capture_val_scope.base;
   5910         };
   5911 
   5912         if (is_multi_case) {
   5913             // items_len, ranges_len, body_len
   5914             const header_index = multi_cases_payload.items.len;
   5915             try multi_cases_payload.resize(gpa, multi_cases_payload.items.len + 3);
   5916 
   5917             // items
   5918             var items_len: u32 = 0;
   5919             for (case.ast.values) |item_node| {
   5920                 if (node_tags[item_node] == .switch_range) continue;
   5921                 items_len += 1;
   5922 
   5923                 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node);
   5924                 try multi_cases_payload.append(gpa, @enumToInt(item_inst));
   5925             }
   5926 
   5927             // ranges
   5928             var ranges_len: u32 = 0;
   5929             for (case.ast.values) |range| {
   5930                 if (node_tags[range] != .switch_range) continue;
   5931                 ranges_len += 1;
   5932 
   5933                 const first = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].lhs);
   5934                 const last = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].rhs);
   5935                 try multi_cases_payload.appendSlice(gpa, &[_]u32{
   5936                     @enumToInt(first), @enumToInt(last),
   5937                 });
   5938             }
   5939 
   5940             const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
   5941             try checkUsed(parent_gz, &case_scope.base, sub_scope);
   5942             if (!parent_gz.refIsNoReturn(case_result)) {
   5943                 block_scope.break_count += 1;
   5944                 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
   5945             }
   5946 
   5947             multi_cases_payload.items[header_index + 0] = items_len;
   5948             multi_cases_payload.items[header_index + 1] = ranges_len;
   5949             multi_cases_payload.items[header_index + 2] = @intCast(u32, case_scope.instructions.items.len);
   5950             try multi_cases_payload.appendSlice(gpa, case_scope.instructions.items);
   5951         } else {
   5952             const item_node = case.ast.values[0];
   5953             const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node);
   5954             const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
   5955             try checkUsed(parent_gz, &case_scope.base, sub_scope);
   5956             if (!parent_gz.refIsNoReturn(case_result)) {
   5957                 block_scope.break_count += 1;
   5958                 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
   5959             }
   5960             try scalar_cases_payload.ensureUnusedCapacity(gpa, 2 +
   5961                 case_scope.instructions.items.len);
   5962             scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst));
   5963             scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len));
   5964             scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items);
   5965         }
   5966     }
   5967     // Now that the item expressions are generated we can add this.
   5968     try parent_gz.instructions.append(gpa, switch_block);
   5969 
   5970     const ref_bit: u4 = @boolToInt(any_payload_is_ref);
   5971     const multi_bit: u4 = @boolToInt(multi_cases_len != 0);
   5972     const special_prong_bits: u4 = @enumToInt(special_prong);
   5973     comptime {
   5974         assert(@enumToInt(Zir.SpecialProng.none) == 0b00);
   5975         assert(@enumToInt(Zir.SpecialProng.@"else") == 0b01);
   5976         assert(@enumToInt(Zir.SpecialProng.under) == 0b10);
   5977     }
   5978     const zir_tags = astgen.instructions.items(.tag);
   5979     zir_tags[switch_block] = switch ((ref_bit << 3) | (special_prong_bits << 1) | multi_bit) {
   5980         0b0_00_0 => .switch_block,
   5981         0b0_00_1 => .switch_block_multi,
   5982         0b0_01_0 => .switch_block_else,
   5983         0b0_01_1 => .switch_block_else_multi,
   5984         0b0_10_0 => .switch_block_under,
   5985         0b0_10_1 => .switch_block_under_multi,
   5986         0b1_00_0 => .switch_block_ref,
   5987         0b1_00_1 => .switch_block_ref_multi,
   5988         0b1_01_0 => .switch_block_ref_else,
   5989         0b1_01_1 => .switch_block_ref_else_multi,
   5990         0b1_10_0 => .switch_block_ref_under,
   5991         0b1_10_1 => .switch_block_ref_under_multi,
   5992         else => unreachable,
   5993     };
   5994     const payload_index = astgen.extra.items.len;
   5995     const zir_datas = astgen.instructions.items(.data);
   5996     zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index);
   5997     try astgen.extra.ensureUnusedCapacity(gpa, scalar_cases_payload.items.len +
   5998         multi_cases_payload.items.len);
   5999     const strat = rl.strategy(&block_scope);
   6000     switch (strat.tag) {
   6001         .break_operand => {
   6002             // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus
   6003             // `elide_store_to_block_ptr_instructions` will either be true,
   6004             // or all prongs are noreturn.
   6005             if (!strat.elide_store_to_block_ptr_instructions) {
   6006                 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);
   6007                 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);
   6008                 return indexToRef(switch_block);
   6009             }
   6010 
   6011             // There will necessarily be a store_to_block_ptr for
   6012             // all prongs, except for prongs that ended with a noreturn instruction.
   6013             // Elide all the `store_to_block_ptr` instructions.
   6014 
   6015             // The break instructions need to have their operands coerced if the
   6016             // switch's result location is a `ty`. In this case we overwrite the
   6017             // `store_to_block_ptr` instruction with an `as` instruction and repurpose
   6018             // it as the break operand.
   6019 
   6020             var extra_index: usize = 0;
   6021             extra_index += 2;
   6022             extra_index += @boolToInt(multi_cases_len != 0);
   6023             if (special_prong != .none) special_prong: {
   6024                 const body_len_index = extra_index;
   6025                 const body_len = scalar_cases_payload.items[extra_index];
   6026                 extra_index += 1;
   6027                 if (body_len < 2) {
   6028                     extra_index += body_len;
   6029                     astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);
   6030                     break :special_prong;
   6031                 }
   6032                 extra_index += body_len - 2;
   6033                 const store_inst = scalar_cases_payload.items[extra_index];
   6034                 if (zir_tags[store_inst] != .store_to_block_ptr or
   6035                     zir_datas[store_inst].bin.lhs != block_scope.rl_ptr)
   6036                 {
   6037                     extra_index += 2;
   6038                     astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);
   6039                     break :special_prong;
   6040                 }
   6041                 assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
   6042                 if (block_scope.rl_ty_inst != .none) {
   6043                     extra_index += 1;
   6044                     const break_inst = scalar_cases_payload.items[extra_index];
   6045                     extra_index += 1;
   6046                     astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);
   6047                     zir_tags[store_inst] = .as;
   6048                     zir_datas[store_inst].bin = .{
   6049                         .lhs = block_scope.rl_ty_inst,
   6050                         .rhs = zir_datas[break_inst].@"break".operand,
   6051                     };
   6052                     zir_datas[break_inst].@"break".operand = indexToRef(store_inst);
   6053                 } else {
   6054                     scalar_cases_payload.items[body_len_index] -= 1;
   6055                     astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);
   6056                     extra_index += 1;
   6057                     astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]);
   6058                     extra_index += 1;
   6059                 }
   6060             } else {
   6061                 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);
   6062             }
   6063             var scalar_i: u32 = 0;
   6064             while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   6065                 const start_index = extra_index;
   6066                 extra_index += 1;
   6067                 const body_len_index = extra_index;
   6068                 const body_len = scalar_cases_payload.items[extra_index];
   6069                 extra_index += 1;
   6070                 if (body_len < 2) {
   6071                     extra_index += body_len;
   6072                     astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]);
   6073                     continue;
   6074                 }
   6075                 extra_index += body_len - 2;
   6076                 const store_inst = scalar_cases_payload.items[extra_index];
   6077                 if (zir_tags[store_inst] != .store_to_block_ptr or
   6078                     zir_datas[store_inst].bin.lhs != block_scope.rl_ptr)
   6079                 {
   6080                     extra_index += 2;
   6081                     astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]);
   6082                     continue;
   6083                 }
   6084                 if (block_scope.rl_ty_inst != .none) {
   6085                     extra_index += 1;
   6086                     const break_inst = scalar_cases_payload.items[extra_index];
   6087                     extra_index += 1;
   6088                     astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]);
   6089                     zir_tags[store_inst] = .as;
   6090                     zir_datas[store_inst].bin = .{
   6091                         .lhs = block_scope.rl_ty_inst,
   6092                         .rhs = zir_datas[break_inst].@"break".operand,
   6093                     };
   6094                     zir_datas[break_inst].@"break".operand = indexToRef(store_inst);
   6095                 } else {
   6096                     scalar_cases_payload.items[body_len_index] -= 1;
   6097                     astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]);
   6098                     extra_index += 1;
   6099                     astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]);
   6100                     extra_index += 1;
   6101                 }
   6102             }
   6103             extra_index = 0;
   6104             var multi_i: u32 = 0;
   6105             while (multi_i < multi_cases_len) : (multi_i += 1) {
   6106                 const start_index = extra_index;
   6107                 const items_len = multi_cases_payload.items[extra_index];
   6108                 extra_index += 1;
   6109                 const ranges_len = multi_cases_payload.items[extra_index];
   6110                 extra_index += 1;
   6111                 const body_len_index = extra_index;
   6112                 const body_len = multi_cases_payload.items[extra_index];
   6113                 extra_index += 1;
   6114                 extra_index += items_len;
   6115                 extra_index += 2 * ranges_len;
   6116                 if (body_len < 2) {
   6117                     extra_index += body_len;
   6118                     astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]);
   6119                     continue;
   6120                 }
   6121                 extra_index += body_len - 2;
   6122                 const store_inst = multi_cases_payload.items[extra_index];
   6123                 if (zir_tags[store_inst] != .store_to_block_ptr or
   6124                     zir_datas[store_inst].bin.lhs != block_scope.rl_ptr)
   6125                 {
   6126                     extra_index += 2;
   6127                     astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]);
   6128                     continue;
   6129                 }
   6130                 if (block_scope.rl_ty_inst != .none) {
   6131                     extra_index += 1;
   6132                     const break_inst = multi_cases_payload.items[extra_index];
   6133                     extra_index += 1;
   6134                     astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]);
   6135                     zir_tags[store_inst] = .as;
   6136                     zir_datas[store_inst].bin = .{
   6137                         .lhs = block_scope.rl_ty_inst,
   6138                         .rhs = zir_datas[break_inst].@"break".operand,
   6139                     };
   6140                     zir_datas[break_inst].@"break".operand = indexToRef(store_inst);
   6141                 } else {
   6142                     assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
   6143                     multi_cases_payload.items[body_len_index] -= 1;
   6144                     astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]);
   6145                     extra_index += 1;
   6146                     astgen.extra.appendAssumeCapacity(multi_cases_payload.items[extra_index]);
   6147                     extra_index += 1;
   6148                 }
   6149             }
   6150 
   6151             const block_ref = indexToRef(switch_block);
   6152             switch (rl) {
   6153                 .ref => return block_ref,
   6154                 else => return rvalue(parent_gz, rl, block_ref, switch_node),
   6155             }
   6156         },
   6157         .break_void => {
   6158             assert(!strat.elide_store_to_block_ptr_instructions);
   6159             astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);
   6160             astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);
   6161             // Modify all the terminating instruction tags to become `break` variants.
   6162             var extra_index: usize = payload_index;
   6163             extra_index += 2;
   6164             extra_index += @boolToInt(multi_cases_len != 0);
   6165             if (special_prong != .none) {
   6166                 const body_len = astgen.extra.items[extra_index];
   6167                 extra_index += 1;
   6168                 const body = astgen.extra.items[extra_index..][0..body_len];
   6169                 extra_index += body_len;
   6170                 const last = body[body.len - 1];
   6171                 if (zir_tags[last] == .@"break" and
   6172                     zir_datas[last].@"break".block_inst == switch_block)
   6173                 {
   6174                     zir_datas[last].@"break".operand = .void_value;
   6175                 }
   6176             }
   6177             var scalar_i: u32 = 0;
   6178             while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   6179                 extra_index += 1;
   6180                 const body_len = astgen.extra.items[extra_index];
   6181                 extra_index += 1;
   6182                 const body = astgen.extra.items[extra_index..][0..body_len];
   6183                 extra_index += body_len;
   6184                 const last = body[body.len - 1];
   6185                 if (zir_tags[last] == .@"break" and
   6186                     zir_datas[last].@"break".block_inst == switch_block)
   6187                 {
   6188                     zir_datas[last].@"break".operand = .void_value;
   6189                 }
   6190             }
   6191             var multi_i: u32 = 0;
   6192             while (multi_i < multi_cases_len) : (multi_i += 1) {
   6193                 const items_len = astgen.extra.items[extra_index];
   6194                 extra_index += 1;
   6195                 const ranges_len = astgen.extra.items[extra_index];
   6196                 extra_index += 1;
   6197                 const body_len = astgen.extra.items[extra_index];
   6198                 extra_index += 1;
   6199                 extra_index += items_len;
   6200                 extra_index += 2 * ranges_len;
   6201                 const body = astgen.extra.items[extra_index..][0..body_len];
   6202                 extra_index += body_len;
   6203                 const last = body[body.len - 1];
   6204                 if (zir_tags[last] == .@"break" and
   6205                     zir_datas[last].@"break".block_inst == switch_block)
   6206                 {
   6207                     zir_datas[last].@"break".operand = .void_value;
   6208                 }
   6209             }
   6210 
   6211             return indexToRef(switch_block);
   6212         },
   6213     }
   6214 }
   6215 
   6216 fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
   6217     const astgen = gz.astgen;
   6218     const tree = astgen.tree;
   6219     const node_datas = tree.nodes.items(.data);
   6220     const node_tags = tree.nodes.items(.tag);
   6221 
   6222     if (astgen.fn_block == null) {
   6223         return astgen.failNode(node, "'return' outside function scope", .{});
   6224     }
   6225 
   6226     if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{});
   6227 
   6228     const defer_outer = &astgen.fn_block.?.base;
   6229 
   6230     const operand_node = node_datas[node].lhs;
   6231     if (operand_node == 0) {
   6232         // Returning a void value; skip error defers.
   6233         try genDefers(gz, defer_outer, scope, .normal_only);
   6234         _ = try gz.addUnNode(.ret_node, .void_value, node);
   6235         return Zir.Inst.Ref.unreachable_value;
   6236     }
   6237 
   6238     if (node_tags[operand_node] == .error_value) {
   6239         // Hot path for `return error.Foo`. This bypasses result location logic as well as logic
   6240         // for detecting whether to add something to the function's inferred error set.
   6241         const ident_token = node_datas[operand_node].rhs;
   6242         const err_name_str_index = try astgen.identAsString(ident_token);
   6243         const defer_counts = countDefers(astgen, defer_outer, scope);
   6244         if (!defer_counts.need_err_code) {
   6245             try genDefers(gz, defer_outer, scope, .both_sans_err);
   6246             _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token);
   6247             return Zir.Inst.Ref.unreachable_value;
   6248         }
   6249         const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token);
   6250         try genDefers(gz, defer_outer, scope, .{ .both = err_code });
   6251         _ = try gz.addUnNode(.ret_node, err_code, node);
   6252         return Zir.Inst.Ref.unreachable_value;
   6253     }
   6254 
   6255     const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node)) .{
   6256         .ptr = try gz.addNodeExtended(.ret_ptr, node),
   6257     } else .{
   6258         .ty = try gz.addNodeExtended(.ret_type, node),
   6259     };
   6260     const operand = try expr(gz, scope, rl, operand_node);
   6261 
   6262     switch (nodeMayEvalToError(tree, operand_node)) {
   6263         .never => {
   6264             // Returning a value that cannot be an error; skip error defers.
   6265             try genDefers(gz, defer_outer, scope, .normal_only);
   6266             _ = try gz.addUnNode(.ret_node, operand, node);
   6267             return Zir.Inst.Ref.unreachable_value;
   6268         },
   6269         .always => {
   6270             // Value is always an error. Emit both error defers and regular defers.
   6271             const err_code = try gz.addUnNode(.err_union_code, operand, node);
   6272             try genDefers(gz, defer_outer, scope, .{ .both = err_code });
   6273             try gz.addRet(rl, operand, node);
   6274             return Zir.Inst.Ref.unreachable_value;
   6275         },
   6276         .maybe => {
   6277             const defer_counts = countDefers(astgen, defer_outer, scope);
   6278             if (!defer_counts.have_err) {
   6279                 // Only regular defers; no branch needed.
   6280                 try genDefers(gz, defer_outer, scope, .normal_only);
   6281                 try gz.addRet(rl, operand, node);
   6282                 return Zir.Inst.Ref.unreachable_value;
   6283             }
   6284 
   6285             // Emit conditional branch for generating errdefers.
   6286             const is_non_err = try gz.addUnNode(.is_non_err, operand, node);
   6287             const condbr = try gz.addCondBr(.condbr, node);
   6288 
   6289             var then_scope = gz.makeSubBlock(scope);
   6290             defer then_scope.instructions.deinit(astgen.gpa);
   6291 
   6292             try genDefers(&then_scope, defer_outer, scope, .normal_only);
   6293             try then_scope.addRet(rl, operand, node);
   6294 
   6295             var else_scope = gz.makeSubBlock(scope);
   6296             defer else_scope.instructions.deinit(astgen.gpa);
   6297 
   6298             const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{
   6299                 .both = try else_scope.addUnNode(.err_union_code, operand, node),
   6300             };
   6301             try genDefers(&else_scope, defer_outer, scope, which_ones);
   6302             try else_scope.addRet(rl, operand, node);
   6303 
   6304             try setCondBrPayload(condbr, is_non_err, &then_scope, &else_scope);
   6305 
   6306             return Zir.Inst.Ref.unreachable_value;
   6307         },
   6308     }
   6309 }
   6310 
   6311 fn identifier(
   6312     gz: *GenZir,
   6313     scope: *Scope,
   6314     rl: ResultLoc,
   6315     ident: ast.Node.Index,
   6316 ) InnerError!Zir.Inst.Ref {
   6317     const tracy = trace(@src());
   6318     defer tracy.end();
   6319 
   6320     const astgen = gz.astgen;
   6321     const tree = astgen.tree;
   6322     const main_tokens = tree.nodes.items(.main_token);
   6323 
   6324     const ident_token = main_tokens[ident];
   6325     const ident_name_raw = tree.tokenSlice(ident_token);
   6326     if (mem.eql(u8, ident_name_raw, "_")) {
   6327         return astgen.failNode(ident, "'_' used as an identifier without @\"_\" syntax", .{});
   6328     }
   6329     const ident_name = try astgen.identifierTokenString(ident_token);
   6330 
   6331     if (ident_name_raw[0] != '@') {
   6332         if (simple_types.get(ident_name)) |zir_const_ref| {
   6333             return rvalue(gz, rl, zir_const_ref, ident);
   6334         }
   6335 
   6336         if (ident_name.len >= 2) integer: {
   6337             const first_c = ident_name[0];
   6338             if (first_c == 'i' or first_c == 'u') {
   6339                 const signedness: std.builtin.Signedness = switch (first_c == 'i') {
   6340                     true => .signed,
   6341                     false => .unsigned,
   6342                 };
   6343                 const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) {
   6344                     error.Overflow => return astgen.failNode(
   6345                         ident,
   6346                         "primitive integer type '{s}' exceeds maximum bit width of 65535",
   6347                         .{ident_name},
   6348                     ),
   6349                     error.InvalidCharacter => break :integer,
   6350                 };
   6351                 const result = try gz.add(.{
   6352                     .tag = .int_type,
   6353                     .data = .{ .int_type = .{
   6354                         .src_node = gz.nodeIndexToRelative(ident),
   6355                         .signedness = signedness,
   6356                         .bit_count = bit_count,
   6357                     } },
   6358                 });
   6359                 return rvalue(gz, rl, result, ident);
   6360             }
   6361         }
   6362     }
   6363 
   6364     // Local variables, including function parameters.
   6365     const name_str_index = try astgen.identAsString(ident_token);
   6366     var s = scope;
   6367     var found_already: ?ast.Node.Index = null; // we have found a decl with the same name already
   6368     var hit_namespace: ast.Node.Index = 0;
   6369     while (true) switch (s.tag) {
   6370         .local_val => {
   6371             const local_val = s.cast(Scope.LocalVal).?;
   6372 
   6373             if (local_val.name == name_str_index) {
   6374                 local_val.used = true;
   6375                 // Captures of non-locals need to be emitted as decl_val or decl_ref.
   6376                 // This *might* be capturable depending on if it is comptime known.
   6377                 if (hit_namespace == 0) {
   6378                     return rvalue(gz, rl, local_val.inst, ident);
   6379                 }
   6380             }
   6381             s = local_val.parent;
   6382         },
   6383         .local_ptr => {
   6384             const local_ptr = s.cast(Scope.LocalPtr).?;
   6385             if (local_ptr.name == name_str_index) {
   6386                 local_ptr.used = true;
   6387                 if (hit_namespace != 0) {
   6388                     if (local_ptr.maybe_comptime)
   6389                         break
   6390                     else
   6391                         return astgen.failNodeNotes(ident, "mutable '{s}' not accessible from here", .{ident_name}, &.{
   6392                             try astgen.errNoteTok(local_ptr.token_src, "declared mutable here", .{}),
   6393                             try astgen.errNoteNode(hit_namespace, "crosses namespace boundary here", .{}),
   6394                         });
   6395                 }
   6396                 switch (rl) {
   6397                     .ref, .none_or_ref => return local_ptr.ptr,
   6398                     else => {
   6399                         const loaded = try gz.addUnNode(.load, local_ptr.ptr, ident);
   6400                         return rvalue(gz, rl, loaded, ident);
   6401                     },
   6402                 }
   6403             }
   6404             s = local_ptr.parent;
   6405         },
   6406         .gen_zir => s = s.cast(GenZir).?.parent,
   6407         .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
   6408         .namespace => {
   6409             const ns = s.cast(Scope.Namespace).?;
   6410             if (ns.decls.get(name_str_index)) |i| {
   6411                 if (found_already) |f| {
   6412                     return astgen.failNodeNotes(ident, "ambiguous reference", .{}, &.{
   6413                         try astgen.errNoteNode(f, "declared here", .{}),
   6414                         try astgen.errNoteNode(i, "also declared here", .{}),
   6415                     });
   6416                 }
   6417                 // We found a match but must continue looking for ambiguous references to decls.
   6418                 found_already = i;
   6419             }
   6420             hit_namespace = ns.node;
   6421             s = ns.parent;
   6422         },
   6423         .top => break,
   6424     };
   6425 
   6426     // Decl references happen by name rather than ZIR index so that when unrelated
   6427     // decls are modified, ZIR code containing references to them can be unmodified.
   6428     switch (rl) {
   6429         .ref, .none_or_ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
   6430         else => {
   6431             const result = try gz.addStrTok(.decl_val, name_str_index, ident_token);
   6432             return rvalue(gz, rl, result, ident);
   6433         },
   6434     }
   6435 }
   6436 
   6437 fn stringLiteral(
   6438     gz: *GenZir,
   6439     rl: ResultLoc,
   6440     node: ast.Node.Index,
   6441 ) InnerError!Zir.Inst.Ref {
   6442     const astgen = gz.astgen;
   6443     const tree = astgen.tree;
   6444     const main_tokens = tree.nodes.items(.main_token);
   6445     const str_lit_token = main_tokens[node];
   6446     const str = try astgen.strLitAsString(str_lit_token);
   6447     const result = try gz.add(.{
   6448         .tag = .str,
   6449         .data = .{ .str = .{
   6450             .start = str.index,
   6451             .len = str.len,
   6452         } },
   6453     });
   6454     return rvalue(gz, rl, result, node);
   6455 }
   6456 
   6457 fn multilineStringLiteral(
   6458     gz: *GenZir,
   6459     rl: ResultLoc,
   6460     node: ast.Node.Index,
   6461 ) InnerError!Zir.Inst.Ref {
   6462     const astgen = gz.astgen;
   6463     const str = try astgen.strLitNodeAsString(node);
   6464     const result = try gz.add(.{
   6465         .tag = .str,
   6466         .data = .{ .str = .{
   6467             .start = str.index,
   6468             .len = str.len,
   6469         } },
   6470     });
   6471     return rvalue(gz, rl, result, node);
   6472 }
   6473 
   6474 fn charLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {
   6475     const astgen = gz.astgen;
   6476     const tree = astgen.tree;
   6477     const main_tokens = tree.nodes.items(.main_token);
   6478     const main_token = main_tokens[node];
   6479     const slice = tree.tokenSlice(main_token);
   6480 
   6481     switch (std.zig.parseCharLiteral(slice)) {
   6482         .success => |codepoint| {
   6483             const result = try gz.addInt(codepoint);
   6484             return rvalue(gz, rl, result, node);
   6485         },
   6486         .invalid_escape_character => |bad_index| {
   6487             return astgen.failOff(
   6488                 main_token,
   6489                 @intCast(u32, bad_index),
   6490                 "invalid escape character: '{c}'",
   6491                 .{slice[bad_index]},
   6492             );
   6493         },
   6494         .expected_hex_digit => |bad_index| {
   6495             return astgen.failOff(
   6496                 main_token,
   6497                 @intCast(u32, bad_index),
   6498                 "expected hex digit, found '{c}'",
   6499                 .{slice[bad_index]},
   6500             );
   6501         },
   6502         .empty_unicode_escape_sequence => |bad_index| {
   6503             return astgen.failOff(
   6504                 main_token,
   6505                 @intCast(u32, bad_index),
   6506                 "empty unicode escape sequence",
   6507                 .{},
   6508             );
   6509         },
   6510         .expected_hex_digit_or_rbrace => |bad_index| {
   6511             return astgen.failOff(
   6512                 main_token,
   6513                 @intCast(u32, bad_index),
   6514                 "expected hex digit or '}}', found '{c}'",
   6515                 .{slice[bad_index]},
   6516             );
   6517         },
   6518         .unicode_escape_overflow => |bad_index| {
   6519             return astgen.failOff(
   6520                 main_token,
   6521                 @intCast(u32, bad_index),
   6522                 "unicode escape too large to be a valid codepoint",
   6523                 .{},
   6524             );
   6525         },
   6526         .expected_lbrace => |bad_index| {
   6527             return astgen.failOff(
   6528                 main_token,
   6529                 @intCast(u32, bad_index),
   6530                 "expected '{{', found '{c}",
   6531                 .{slice[bad_index]},
   6532             );
   6533         },
   6534         .expected_end => |bad_index| {
   6535             return astgen.failOff(
   6536                 main_token,
   6537                 @intCast(u32, bad_index),
   6538                 "expected ending single quote ('), found '{c}",
   6539                 .{slice[bad_index]},
   6540             );
   6541         },
   6542         .invalid_character => |bad_index| {
   6543             return astgen.failOff(
   6544                 main_token,
   6545                 @intCast(u32, bad_index),
   6546                 "invalid byte in character literal: '{c}'",
   6547                 .{slice[bad_index]},
   6548             );
   6549         },
   6550     }
   6551 }
   6552 
   6553 fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
   6554     const astgen = gz.astgen;
   6555     const tree = astgen.tree;
   6556     const main_tokens = tree.nodes.items(.main_token);
   6557     const int_token = main_tokens[node];
   6558     const prefixed_bytes = tree.tokenSlice(int_token);
   6559     if (std.fmt.parseInt(u64, prefixed_bytes, 0)) |small_int| {
   6560         const result: Zir.Inst.Ref = switch (small_int) {
   6561             0 => .zero,
   6562             1 => .one,
   6563             else => try gz.addInt(small_int),
   6564         };
   6565         return rvalue(gz, rl, result, node);
   6566     } else |err| switch (err) {
   6567         error.InvalidCharacter => unreachable, // Caught by the parser.
   6568         error.Overflow => {},
   6569     }
   6570 
   6571     var base: u8 = 10;
   6572     var non_prefixed: []const u8 = prefixed_bytes;
   6573     if (mem.startsWith(u8, prefixed_bytes, "0x")) {
   6574         base = 16;
   6575         non_prefixed = prefixed_bytes[2..];
   6576     } else if (mem.startsWith(u8, prefixed_bytes, "0o")) {
   6577         base = 8;
   6578         non_prefixed = prefixed_bytes[2..];
   6579     } else if (mem.startsWith(u8, prefixed_bytes, "0b")) {
   6580         base = 2;
   6581         non_prefixed = prefixed_bytes[2..];
   6582     }
   6583 
   6584     const gpa = astgen.gpa;
   6585     var big_int = try std.math.big.int.Managed.init(gpa);
   6586     defer big_int.deinit();
   6587     big_int.setString(base, non_prefixed) catch |err| switch (err) {
   6588         error.InvalidCharacter => unreachable, // caught by parser
   6589         error.InvalidBase => unreachable, // we only pass 16, 8, 2, see above
   6590         error.OutOfMemory => return error.OutOfMemory,
   6591     };
   6592 
   6593     const limbs = big_int.limbs[0..big_int.len()];
   6594     assert(big_int.isPositive());
   6595     const result = try gz.addIntBig(limbs);
   6596     return rvalue(gz, rl, result, node);
   6597 }
   6598 
   6599 fn floatLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
   6600     const astgen = gz.astgen;
   6601     const tree = astgen.tree;
   6602     const main_tokens = tree.nodes.items(.main_token);
   6603 
   6604     const main_token = main_tokens[node];
   6605     const bytes = tree.tokenSlice(main_token);
   6606     const float_number: f128 = if (bytes.len > 2 and bytes[1] == 'x') hex: {
   6607         assert(bytes[0] == '0'); // validated by tokenizer
   6608         break :hex std.fmt.parseHexFloat(f128, bytes) catch |err| switch (err) {
   6609             error.InvalidCharacter => unreachable, // validated by tokenizer
   6610             error.Overflow => return astgen.failNode(node, "number literal cannot be represented in a 128-bit floating point", .{}),
   6611         };
   6612     } else std.fmt.parseFloat(f128, bytes) catch |err| switch (err) {
   6613         error.InvalidCharacter => unreachable, // validated by tokenizer
   6614     };
   6615     // If the value fits into a f64 without losing any precision, store it that way.
   6616     @setFloatMode(.Strict);
   6617     const smaller_float = @floatCast(f64, float_number);
   6618     const bigger_again: f128 = smaller_float;
   6619     if (bigger_again == float_number) {
   6620         const result = try gz.addFloat(smaller_float);
   6621         return rvalue(gz, rl, result, node);
   6622     }
   6623     // We need to use 128 bits. Break the float into 4 u32 values so we can
   6624     // put it into the `extra` array.
   6625     const int_bits = @bitCast(u128, float_number);
   6626     const result = try gz.addPlNode(.float128, node, Zir.Inst.Float128{
   6627         .piece0 = @truncate(u32, int_bits),
   6628         .piece1 = @truncate(u32, int_bits >> 32),
   6629         .piece2 = @truncate(u32, int_bits >> 64),
   6630         .piece3 = @truncate(u32, int_bits >> 96),
   6631     });
   6632     return rvalue(gz, rl, result, node);
   6633 }
   6634 
   6635 fn asmExpr(
   6636     gz: *GenZir,
   6637     scope: *Scope,
   6638     rl: ResultLoc,
   6639     node: ast.Node.Index,
   6640     full: ast.full.Asm,
   6641 ) InnerError!Zir.Inst.Ref {
   6642     const astgen = gz.astgen;
   6643     const tree = astgen.tree;
   6644     const main_tokens = tree.nodes.items(.main_token);
   6645     const node_datas = tree.nodes.items(.data);
   6646     const node_tags = tree.nodes.items(.tag);
   6647     const token_tags = tree.tokens.items(.tag);
   6648 
   6649     const asm_source = switch (node_tags[full.ast.template]) {
   6650         .string_literal => try astgen.strLitAsString(main_tokens[full.ast.template]),
   6651         .multiline_string_literal => try astgen.strLitNodeAsString(full.ast.template),
   6652         else => return astgen.failNode(full.ast.template, "assembly code must use string literal syntax", .{}),
   6653     };
   6654 
   6655     // See https://github.com/ziglang/zig/issues/215 and related issues discussing
   6656     // possible inline assembly improvements. Until then here is status quo AstGen
   6657     // for assembly syntax. It's used by std lib crypto aesni.zig.
   6658     const is_container_asm = astgen.fn_block == null;
   6659     if (is_container_asm) {
   6660         if (full.volatile_token) |t|
   6661             return astgen.failTok(t, "volatile is meaningless on global assembly", .{});
   6662         if (full.outputs.len != 0 or full.inputs.len != 0 or full.first_clobber != null)
   6663             return astgen.failNode(node, "global assembly cannot have inputs, outputs, or clobbers", .{});
   6664     } else {
   6665         if (full.outputs.len == 0 and full.volatile_token == null) {
   6666             return astgen.failNode(node, "assembly expression with no output must be marked volatile", .{});
   6667         }
   6668     }
   6669     if (full.outputs.len > 32) {
   6670         return astgen.failNode(full.outputs[32], "too many asm outputs", .{});
   6671     }
   6672     var outputs_buffer: [32]Zir.Inst.Asm.Output = undefined;
   6673     const outputs = outputs_buffer[0..full.outputs.len];
   6674 
   6675     var output_type_bits: u32 = 0;
   6676 
   6677     for (full.outputs) |output_node, i| {
   6678         const symbolic_name = main_tokens[output_node];
   6679         const name = try astgen.identAsString(symbolic_name);
   6680         const constraint_token = symbolic_name + 2;
   6681         const constraint = (try astgen.strLitAsString(constraint_token)).index;
   6682         const has_arrow = token_tags[symbolic_name + 4] == .arrow;
   6683         if (has_arrow) {
   6684             output_type_bits |= @as(u32, 1) << @intCast(u5, i);
   6685             const out_type_node = node_datas[output_node].lhs;
   6686             const out_type_inst = try typeExpr(gz, scope, out_type_node);
   6687             outputs[i] = .{
   6688                 .name = name,
   6689                 .constraint = constraint,
   6690                 .operand = out_type_inst,
   6691             };
   6692         } else {
   6693             const ident_token = symbolic_name + 4;
   6694             const str_index = try astgen.identAsString(ident_token);
   6695             // TODO this needs extra code for local variables. Have a look at #215 and related
   6696             // issues and decide how to handle outputs. Do we want this to be identifiers?
   6697             // Or maybe we want to force this to be expressions with a pointer type.
   6698             // Until that is figured out this is only hooked up for referencing Decls.
   6699             // TODO we have put this as an identifier lookup just so that we don't get
   6700             // unused vars for outputs. We need to check if this is correct in the future ^^
   6701             // so we just put in this simple lookup. This is a workaround.
   6702             {
   6703                 var s = scope;
   6704                 while (true) switch (s.tag) {
   6705                     .local_val => {
   6706                         const local_val = s.cast(Scope.LocalVal).?;
   6707                         if (local_val.name == str_index) {
   6708                             local_val.used = true;
   6709                             break;
   6710                         }
   6711                         s = local_val.parent;
   6712                     },
   6713                     .local_ptr => {
   6714                         const local_ptr = s.cast(Scope.LocalPtr).?;
   6715                         if (local_ptr.name == str_index) {
   6716                             local_ptr.used = true;
   6717                             break;
   6718                         }
   6719                         s = local_ptr.parent;
   6720                     },
   6721                     .gen_zir => s = s.cast(GenZir).?.parent,
   6722                     .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
   6723                     .namespace, .top => break,
   6724                 };
   6725             }
   6726             const operand = try gz.addStrTok(.decl_ref, str_index, ident_token);
   6727             outputs[i] = .{
   6728                 .name = name,
   6729                 .constraint = constraint,
   6730                 .operand = operand,
   6731             };
   6732         }
   6733     }
   6734 
   6735     if (full.inputs.len > 32) {
   6736         return astgen.failNode(full.inputs[32], "too many asm inputs", .{});
   6737     }
   6738     var inputs_buffer: [32]Zir.Inst.Asm.Input = undefined;
   6739     const inputs = inputs_buffer[0..full.inputs.len];
   6740 
   6741     for (full.inputs) |input_node, i| {
   6742         const symbolic_name = main_tokens[input_node];
   6743         const name = try astgen.identAsString(symbolic_name);
   6744         const constraint_token = symbolic_name + 2;
   6745         const constraint = (try astgen.strLitAsString(constraint_token)).index;
   6746         const operand = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input_node].lhs);
   6747         inputs[i] = .{
   6748             .name = name,
   6749             .constraint = constraint,
   6750             .operand = operand,
   6751         };
   6752     }
   6753 
   6754     var clobbers_buffer: [32]u32 = undefined;
   6755     var clobber_i: usize = 0;
   6756     if (full.first_clobber) |first_clobber| clobbers: {
   6757         // asm ("foo" ::: "a", "b")
   6758         // asm ("foo" ::: "a", "b",)
   6759         var tok_i = first_clobber;
   6760         while (true) : (tok_i += 1) {
   6761             if (clobber_i >= clobbers_buffer.len) {
   6762                 return astgen.failTok(tok_i, "too many asm clobbers", .{});
   6763             }
   6764             clobbers_buffer[clobber_i] = (try astgen.strLitAsString(tok_i)).index;
   6765             clobber_i += 1;
   6766             tok_i += 1;
   6767             switch (token_tags[tok_i]) {
   6768                 .r_paren => break :clobbers,
   6769                 .comma => {
   6770                     if (token_tags[tok_i + 1] == .r_paren) {
   6771                         break :clobbers;
   6772                     } else {
   6773                         continue;
   6774                     }
   6775                 },
   6776                 else => unreachable,
   6777             }
   6778         }
   6779     }
   6780 
   6781     const result = try gz.addAsm(.{
   6782         .node = node,
   6783         .asm_source = asm_source.index,
   6784         .is_volatile = full.volatile_token != null,
   6785         .output_type_bits = output_type_bits,
   6786         .outputs = outputs,
   6787         .inputs = inputs,
   6788         .clobbers = clobbers_buffer[0..clobber_i],
   6789     });
   6790     return rvalue(gz, rl, result, node);
   6791 }
   6792 
   6793 fn as(
   6794     gz: *GenZir,
   6795     scope: *Scope,
   6796     rl: ResultLoc,
   6797     node: ast.Node.Index,
   6798     lhs: ast.Node.Index,
   6799     rhs: ast.Node.Index,
   6800 ) InnerError!Zir.Inst.Ref {
   6801     const dest_type = try typeExpr(gz, scope, lhs);
   6802     switch (rl) {
   6803         .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty => {
   6804             const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);
   6805             return rvalue(gz, rl, result, node);
   6806         },
   6807         .ptr, .inferred_ptr => |result_ptr| {
   6808             return asRlPtr(gz, scope, rl, node, result_ptr, rhs, dest_type);
   6809         },
   6810         .block_ptr => |block_scope| {
   6811             return asRlPtr(gz, scope, rl, node, block_scope.rl_ptr, rhs, dest_type);
   6812         },
   6813     }
   6814 }
   6815 
   6816 fn unionInit(
   6817     gz: *GenZir,
   6818     scope: *Scope,
   6819     rl: ResultLoc,
   6820     node: ast.Node.Index,
   6821     params: []const ast.Node.Index,
   6822 ) InnerError!Zir.Inst.Ref {
   6823     const union_type = try typeExpr(gz, scope, params[0]);
   6824     const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
   6825     switch (rl) {
   6826         .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => {
   6827             _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{
   6828                 .container_type = union_type,
   6829                 .field_name = field_name,
   6830             });
   6831             const result = try expr(gz, scope, .{ .ty = union_type }, params[2]);
   6832             return rvalue(gz, rl, result, node);
   6833         },
   6834         .ptr => |result_ptr| {
   6835             return unionInitRlPtr(gz, scope, node, result_ptr, params[2], union_type, field_name);
   6836         },
   6837         .block_ptr => |block_scope| {
   6838             return unionInitRlPtr(gz, scope, node, block_scope.rl_ptr, params[2], union_type, field_name);
   6839         },
   6840     }
   6841 }
   6842 
   6843 fn unionInitRlPtr(
   6844     parent_gz: *GenZir,
   6845     scope: *Scope,
   6846     node: ast.Node.Index,
   6847     result_ptr: Zir.Inst.Ref,
   6848     expr_node: ast.Node.Index,
   6849     union_type: Zir.Inst.Ref,
   6850     field_name: Zir.Inst.Ref,
   6851 ) InnerError!Zir.Inst.Ref {
   6852     const union_init_ptr = try parent_gz.addPlNode(.union_init_ptr, node, Zir.Inst.UnionInitPtr{
   6853         .result_ptr = result_ptr,
   6854         .union_type = union_type,
   6855         .field_name = field_name,
   6856     });
   6857     // TODO check if we need to do the elision like below in asRlPtr
   6858     return expr(parent_gz, scope, .{ .ptr = union_init_ptr }, expr_node);
   6859 }
   6860 
   6861 fn asRlPtr(
   6862     parent_gz: *GenZir,
   6863     scope: *Scope,
   6864     rl: ResultLoc,
   6865     src_node: ast.Node.Index,
   6866     result_ptr: Zir.Inst.Ref,
   6867     operand_node: ast.Node.Index,
   6868     dest_type: Zir.Inst.Ref,
   6869 ) InnerError!Zir.Inst.Ref {
   6870     // Detect whether this expr() call goes into rvalue() to store the result into the
   6871     // result location. If it does, elide the coerce_result_ptr instruction
   6872     // as well as the store instruction, instead passing the result as an rvalue.
   6873     const astgen = parent_gz.astgen;
   6874 
   6875     var as_scope = parent_gz.makeSubBlock(scope);
   6876     defer as_scope.instructions.deinit(astgen.gpa);
   6877 
   6878     as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr);
   6879     const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node);
   6880     const parent_zir = &parent_gz.instructions;
   6881     if (as_scope.rvalue_rl_count == 1) {
   6882         // Busted! This expression didn't actually need a pointer.
   6883         const zir_tags = astgen.instructions.items(.tag);
   6884         const zir_datas = astgen.instructions.items(.data);
   6885         try parent_zir.ensureUnusedCapacity(astgen.gpa, as_scope.instructions.items.len);
   6886         for (as_scope.instructions.items) |src_inst| {
   6887             if (indexToRef(src_inst) == as_scope.rl_ptr) continue;
   6888             if (zir_tags[src_inst] == .store_to_block_ptr) {
   6889                 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue;
   6890             }
   6891             parent_zir.appendAssumeCapacity(src_inst);
   6892         }
   6893         const casted_result = try parent_gz.addBin(.as, dest_type, result);
   6894         return rvalue(parent_gz, rl, casted_result, operand_node);
   6895     } else {
   6896         try parent_zir.appendSlice(astgen.gpa, as_scope.instructions.items);
   6897         return result;
   6898     }
   6899 }
   6900 
   6901 fn bitCast(
   6902     gz: *GenZir,
   6903     scope: *Scope,
   6904     rl: ResultLoc,
   6905     node: ast.Node.Index,
   6906     lhs: ast.Node.Index,
   6907     rhs: ast.Node.Index,
   6908 ) InnerError!Zir.Inst.Ref {
   6909     const astgen = gz.astgen;
   6910     const dest_type = try typeExpr(gz, scope, lhs);
   6911     switch (rl) {
   6912         .none, .none_or_ref, .discard, .ty, .coerced_ty => {
   6913             const operand = try expr(gz, scope, .none, rhs);
   6914             const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{
   6915                 .lhs = dest_type,
   6916                 .rhs = operand,
   6917             });
   6918             return rvalue(gz, rl, result, node);
   6919         },
   6920         .ref => {
   6921             return astgen.failNode(node, "cannot take address of `@bitCast` result", .{});
   6922         },
   6923         .ptr, .inferred_ptr => |result_ptr| {
   6924             return bitCastRlPtr(gz, scope, node, dest_type, result_ptr, rhs);
   6925         },
   6926         .block_ptr => |block| {
   6927             return bitCastRlPtr(gz, scope, node, dest_type, block.rl_ptr, rhs);
   6928         },
   6929     }
   6930 }
   6931 
   6932 fn bitCastRlPtr(
   6933     gz: *GenZir,
   6934     scope: *Scope,
   6935     node: ast.Node.Index,
   6936     dest_type: Zir.Inst.Ref,
   6937     result_ptr: Zir.Inst.Ref,
   6938     rhs: ast.Node.Index,
   6939 ) InnerError!Zir.Inst.Ref {
   6940     const casted_result_ptr = try gz.addPlNode(.bitcast_result_ptr, node, Zir.Inst.Bin{
   6941         .lhs = dest_type,
   6942         .rhs = result_ptr,
   6943     });
   6944     return expr(gz, scope, .{ .ptr = casted_result_ptr }, rhs);
   6945 }
   6946 
   6947 fn typeOf(
   6948     gz: *GenZir,
   6949     scope: *Scope,
   6950     rl: ResultLoc,
   6951     node: ast.Node.Index,
   6952     params: []const ast.Node.Index,
   6953 ) InnerError!Zir.Inst.Ref {
   6954     if (params.len < 1) {
   6955         return gz.astgen.failNode(node, "expected at least 1 argument, found 0", .{});
   6956     }
   6957     if (params.len == 1) {
   6958         const expr_result = try reachableExpr(gz, scope, .none, params[0], node);
   6959         const result = try gz.addUnNode(.typeof, expr_result, node);
   6960         return rvalue(gz, rl, result, node);
   6961     }
   6962     const arena = gz.astgen.arena;
   6963     var items = try arena.alloc(Zir.Inst.Ref, params.len);
   6964     for (params) |param, param_i| {
   6965         items[param_i] = try reachableExpr(gz, scope, .none, param, node);
   6966     }
   6967 
   6968     const result = try gz.addExtendedMultiOp(.typeof_peer, node, items);
   6969     return rvalue(gz, rl, result, node);
   6970 }
   6971 
   6972 fn builtinCall(
   6973     gz: *GenZir,
   6974     scope: *Scope,
   6975     rl: ResultLoc,
   6976     node: ast.Node.Index,
   6977     params: []const ast.Node.Index,
   6978 ) InnerError!Zir.Inst.Ref {
   6979     const astgen = gz.astgen;
   6980     const tree = astgen.tree;
   6981     const main_tokens = tree.nodes.items(.main_token);
   6982 
   6983     const builtin_token = main_tokens[node];
   6984     const builtin_name = tree.tokenSlice(builtin_token);
   6985 
   6986     // We handle the different builtins manually because they have different semantics depending
   6987     // on the function. For example, `@as` and others participate in result location semantics,
   6988     // and `@cImport` creates a special scope that collects a .c source code text buffer.
   6989     // Also, some builtins have a variable number of parameters.
   6990 
   6991     const info = BuiltinFn.list.get(builtin_name) orelse {
   6992         return astgen.failNode(node, "invalid builtin function: '{s}'", .{
   6993             builtin_name,
   6994         });
   6995     };
   6996     if (info.param_count) |expected| {
   6997         if (expected != params.len) {
   6998             const s = if (expected == 1) "" else "s";
   6999             return astgen.failNode(node, "expected {d} argument{s}, found {d}", .{
   7000                 expected, s, params.len,
   7001             });
   7002         }
   7003     }
   7004 
   7005     // zig fmt: off
   7006     switch (info.tag) {
   7007         .import => {
   7008             const node_tags = tree.nodes.items(.tag);
   7009             const operand_node = params[0];
   7010 
   7011             if (node_tags[operand_node] != .string_literal) {
   7012                 // Spec reference: https://github.com/ziglang/zig/issues/2206
   7013                 return astgen.failNode(operand_node, "@import operand must be a string literal", .{});
   7014             }
   7015             const str_lit_token = main_tokens[operand_node];
   7016             const str = try astgen.strLitAsString(str_lit_token);
   7017             const result = try gz.addStrTok(.import, str.index, str_lit_token);
   7018             const gop = try astgen.imports.getOrPut(astgen.gpa, str.index);
   7019             if (!gop.found_existing) {
   7020                 gop.value_ptr.* = str_lit_token;
   7021             }
   7022             return rvalue(gz, rl, result, node);
   7023         },
   7024         .compile_log => {
   7025             const arg_refs = try astgen.gpa.alloc(Zir.Inst.Ref, params.len);
   7026             defer astgen.gpa.free(arg_refs);
   7027 
   7028             for (params) |param, i| arg_refs[i] = try expr(gz, scope, .none, param);
   7029 
   7030             const result = try gz.addExtendedMultiOp(.compile_log, node, arg_refs);
   7031             return rvalue(gz, rl, result, node);
   7032         },
   7033         .field => {
   7034             const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
   7035             if (rl == .ref) {
   7036                 return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{
   7037                     .lhs = try expr(gz, scope, .ref, params[0]),
   7038                     .field_name = field_name,
   7039                 });
   7040             }
   7041             const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{
   7042                 .lhs = try expr(gz, scope, .none, params[0]),
   7043                 .field_name = field_name,
   7044             });
   7045             return rvalue(gz, rl, result, node);
   7046         },
   7047         .as         => return as(       gz, scope, rl, node, params[0], params[1]),
   7048         .bit_cast   => return bitCast(  gz, scope, rl, node, params[0], params[1]),
   7049         .TypeOf     => return typeOf(   gz, scope, rl, node, params),
   7050         .union_init => return unionInit(gz, scope, rl, node, params),
   7051         .c_import   => return cImport(  gz, scope, rl, node, params[0]),
   7052 
   7053         .@"export" => {
   7054             const node_tags = tree.nodes.items(.tag);
   7055             const node_datas = tree.nodes.items(.data);
   7056             // This function causes a Decl to be exported. The first parameter is not an expression,
   7057             // but an identifier of the Decl to be exported.
   7058             var namespace: Zir.Inst.Ref = .none;
   7059             var decl_name: u32 = 0;
   7060             switch (node_tags[params[0]]) {
   7061                 .identifier => {
   7062                     const ident_token = main_tokens[params[0]];
   7063                     decl_name = try astgen.identAsString(ident_token);
   7064                     {
   7065                         var s = scope;
   7066                         while (true) switch (s.tag) {
   7067                             .local_val => {
   7068                                 const local_val = s.cast(Scope.LocalVal).?;
   7069                                 if (local_val.name == decl_name) {
   7070                                     local_val.used = true;
   7071                                     break;
   7072                                 }
   7073                                 s = local_val.parent;
   7074                             },
   7075                             .local_ptr => {
   7076                                 const local_ptr = s.cast(Scope.LocalPtr).?;
   7077                                 if (local_ptr.name == decl_name) {
   7078                                     if (!local_ptr.maybe_comptime)
   7079                                         return astgen.failNode(params[0], "unable to export runtime-known value", .{});
   7080                                     local_ptr.used = true;
   7081                                     break;
   7082                                 }
   7083                                 s = local_ptr.parent;
   7084                             },
   7085                             .gen_zir => s = s.cast(GenZir).?.parent,
   7086                             .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
   7087                             .namespace, .top => break,
   7088                         };
   7089                     }
   7090                 },
   7091                 .field_access => {
   7092                     const namespace_node = node_datas[params[0]].lhs;
   7093                     namespace = try typeExpr(gz, scope, namespace_node);
   7094                     const dot_token = main_tokens[params[0]];
   7095                     const field_ident = dot_token + 1;
   7096                     decl_name = try astgen.identAsString(field_ident);
   7097                 },
   7098                 else => return astgen.failNode(
   7099                     params[0], "symbol to export must identify a declaration", .{},
   7100                 ),
   7101             }
   7102             const options = try comptimeExpr(gz, scope, .{ .ty = .export_options_type }, params[1]);
   7103             _ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{
   7104                 .namespace = namespace,
   7105                 .decl_name = decl_name,
   7106                 .options = options,
   7107             });
   7108             return rvalue(gz, rl, .void_value, node);
   7109         },
   7110         .@"extern" => {
   7111             const type_inst = try typeExpr(gz, scope, params[0]);
   7112             const options = try comptimeExpr(gz, scope, .{ .ty = .extern_options_type }, params[1]);
   7113             const result = try gz.addExtendedPayload(.builtin_extern, Zir.Inst.BinNode{
   7114                 .node = gz.nodeIndexToRelative(node),
   7115                 .lhs = type_inst,
   7116                 .rhs = options,
   7117             });
   7118             return rvalue(gz, rl, result, node);
   7119         },
   7120 
   7121         .breakpoint => return simpleNoOpVoid(gz, rl, node, .breakpoint),
   7122         .fence      => return simpleNoOpVoid(gz, rl, node, .fence),
   7123 
   7124         .This               => return rvalue(gz, rl, try gz.addNodeExtended(.this,               node), node),
   7125         .return_address     => return rvalue(gz, rl, try gz.addNodeExtended(.ret_addr,           node), node),
   7126         .src                => return rvalue(gz, rl, try gz.addNodeExtended(.builtin_src,        node), node),
   7127         .error_return_trace => return rvalue(gz, rl, try gz.addNodeExtended(.error_return_trace, node), node),
   7128         .frame              => return rvalue(gz, rl, try gz.addNodeExtended(.frame,              node), node),
   7129         .frame_address      => return rvalue(gz, rl, try gz.addNodeExtended(.frame_address,      node), node),
   7130 
   7131         .type_info   => return simpleUnOpType(gz, scope, rl, node, params[0], .type_info),
   7132         .size_of     => return simpleUnOpType(gz, scope, rl, node, params[0], .size_of),
   7133         .bit_size_of => return simpleUnOpType(gz, scope, rl, node, params[0], .bit_size_of),
   7134         .align_of    => return simpleUnOpType(gz, scope, rl, node, params[0], .align_of),
   7135 
   7136         .ptr_to_int            => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .ptr_to_int),
   7137         .error_to_int          => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .error_to_int),
   7138         .int_to_error          => return simpleUnOp(gz, scope, rl, node, .{ .ty = .u16_type },                params[0], .int_to_error),
   7139         .compile_error         => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type },     params[0], .compile_error),
   7140         .set_eval_branch_quota => return simpleUnOp(gz, scope, rl, node, .{ .ty = .u32_type },                params[0], .set_eval_branch_quota),
   7141         .enum_to_int           => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .enum_to_int),
   7142         .bool_to_int           => return simpleUnOp(gz, scope, rl, node, bool_rl,                             params[0], .bool_to_int),
   7143         .embed_file            => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type },     params[0], .embed_file),
   7144         .error_name            => return simpleUnOp(gz, scope, rl, node, .{ .ty = .anyerror_type },           params[0], .error_name),
   7145         .panic                 => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type },     params[0], .panic),
   7146         .set_align_stack       => return simpleUnOp(gz, scope, rl, node, align_rl,                            params[0], .set_align_stack),
   7147         .set_cold              => return simpleUnOp(gz, scope, rl, node, bool_rl,                             params[0], .set_cold),
   7148         .set_float_mode        => return simpleUnOp(gz, scope, rl, node, .{ .coerced_ty = .float_mode_type }, params[0], .set_float_mode),
   7149         .set_runtime_safety    => return simpleUnOp(gz, scope, rl, node, bool_rl,                             params[0], .set_runtime_safety),
   7150         .sqrt                  => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .sqrt),
   7151         .sin                   => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .sin),
   7152         .cos                   => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .cos),
   7153         .exp                   => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .exp),
   7154         .exp2                  => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .exp2),
   7155         .log                   => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .log),
   7156         .log2                  => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .log2),
   7157         .log10                 => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .log10),
   7158         .fabs                  => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .fabs),
   7159         .floor                 => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .floor),
   7160         .ceil                  => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .ceil),
   7161         .trunc                 => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .trunc),
   7162         .round                 => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .round),
   7163         .tag_name              => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .tag_name),
   7164         .Type                  => return simpleUnOp(gz, scope, rl, node, .{ .coerced_ty = .type_info_type },  params[0], .reify),
   7165         .type_name             => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .type_name),
   7166         .Frame                 => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .frame_type),
   7167         .frame_size            => return simpleUnOp(gz, scope, rl, node, .none,                               params[0], .frame_size),
   7168 
   7169         .float_to_int => return typeCast(gz, scope, rl, node, params[0], params[1], .float_to_int),
   7170         .int_to_float => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_float),
   7171         .int_to_ptr   => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_ptr),
   7172         .int_to_enum  => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_enum),
   7173         .float_cast   => return typeCast(gz, scope, rl, node, params[0], params[1], .float_cast),
   7174         .int_cast     => return typeCast(gz, scope, rl, node, params[0], params[1], .int_cast),
   7175         .err_set_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .err_set_cast),
   7176         .ptr_cast     => return typeCast(gz, scope, rl, node, params[0], params[1], .ptr_cast),
   7177         .truncate     => return typeCast(gz, scope, rl, node, params[0], params[1], .truncate),
   7178         .align_cast => {
   7179             const dest_align = try comptimeExpr(gz, scope, align_rl, params[0]);
   7180             const rhs = try expr(gz, scope, .none, params[1]);
   7181             const result = try gz.addPlNode(.align_cast, node, Zir.Inst.Bin{
   7182                 .lhs = dest_align,
   7183                 .rhs = rhs,
   7184             });
   7185             return rvalue(gz, rl, result, node);
   7186         },
   7187 
   7188         .has_decl  => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_decl),
   7189         .has_field => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_field),
   7190 
   7191         .clz         => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .clz),
   7192         .ctz         => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .ctz),
   7193         .pop_count   => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .pop_count),
   7194         .byte_swap   => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .byte_swap),
   7195         .bit_reverse => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .bit_reverse),
   7196 
   7197         .div_exact => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_exact),
   7198         .div_floor => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_floor),
   7199         .div_trunc => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_trunc),
   7200         .mod       => return divBuiltin(gz, scope, rl, node, params[0], params[1], .mod),
   7201         .rem       => return divBuiltin(gz, scope, rl, node, params[0], params[1], .rem),
   7202 
   7203         .shl_exact => return shiftOp(gz, scope, rl, node, params[0], params[1], .shl_exact),
   7204         .shr_exact => return shiftOp(gz, scope, rl, node, params[0], params[1], .shr_exact),
   7205 
   7206         .bit_offset_of  => return offsetOf(gz, scope, rl, node, params[0], params[1], .bit_offset_of),
   7207         .offset_of => return offsetOf(gz, scope, rl, node, params[0], params[1], .offset_of),
   7208 
   7209         .c_undef   => return simpleCBuiltin(gz, scope, rl, node, params[0], .c_undef),
   7210         .c_include => return simpleCBuiltin(gz, scope, rl, node, params[0], .c_include),
   7211 
   7212         .cmpxchg_strong => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_strong),
   7213         .cmpxchg_weak   => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_weak),
   7214 
   7215         .wasm_memory_size => {
   7216             const operand = try expr(gz, scope, .{ .ty = .u32_type }, params[0]);
   7217             const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{
   7218                 .node = gz.nodeIndexToRelative(node),
   7219                 .operand = operand,
   7220             });
   7221             return rvalue(gz, rl, result, node);
   7222         },
   7223         .wasm_memory_grow => {
   7224             const index_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[0]);
   7225             const delta_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[1]);
   7226             const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{
   7227                 .node = gz.nodeIndexToRelative(node),
   7228                 .lhs = index_arg,
   7229                 .rhs = delta_arg,
   7230             });
   7231             return rvalue(gz, rl, result, node);
   7232         },
   7233         .c_define => {
   7234             const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[0]);
   7235             const value = try comptimeExpr(gz, scope, .none, params[1]);
   7236             const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{
   7237                 .node = gz.nodeIndexToRelative(node),
   7238                 .lhs = name,
   7239                 .rhs = value,
   7240             });
   7241             return rvalue(gz, rl, result, node);
   7242         },
   7243 
   7244         .splat => {
   7245             const len = try expr(gz, scope, .{ .ty = .u32_type }, params[0]);
   7246             const scalar = try expr(gz, scope, .none, params[1]);
   7247             const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{
   7248                 .lhs = len,
   7249                 .rhs = scalar,
   7250             });
   7251             return rvalue(gz, rl, result, node);
   7252         },
   7253         .reduce => {
   7254             const op = try expr(gz, scope, .{ .ty = .reduce_op_type }, params[0]);
   7255             const scalar = try expr(gz, scope, .none, params[1]);
   7256             const result = try gz.addPlNode(.reduce, node, Zir.Inst.Bin{
   7257                 .lhs = op,
   7258                 .rhs = scalar,
   7259             });
   7260             return rvalue(gz, rl, result, node);
   7261         },
   7262 
   7263         .maximum => {
   7264             const a = try expr(gz, scope, .none, params[0]);
   7265             const b = try expr(gz, scope, .none, params[1]);
   7266             const result = try gz.addPlNode(.maximum, node, Zir.Inst.Bin{
   7267                 .lhs = a,
   7268                 .rhs = b,
   7269             });
   7270             return rvalue(gz, rl, result, node);
   7271         },
   7272         .minimum => {
   7273             const a = try expr(gz, scope, .none, params[0]);
   7274             const b = try expr(gz, scope, .none, params[1]);
   7275             const result = try gz.addPlNode(.minimum, node, Zir.Inst.Bin{
   7276                 .lhs = a,
   7277                 .rhs = b,
   7278             });
   7279             return rvalue(gz, rl, result, node);
   7280         },
   7281 
   7282         .add_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .add_with_overflow),
   7283         .sub_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .sub_with_overflow),
   7284         .mul_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .mul_with_overflow),
   7285         .shl_with_overflow => {
   7286             const int_type = try typeExpr(gz, scope, params[0]);
   7287             const log2_int_type = try gz.addUnNode(.log2_int_type, int_type, params[0]);
   7288             const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
   7289                 .ptr_type_simple = .{
   7290                     .is_allowzero = false,
   7291                     .is_mutable = true,
   7292                     .is_volatile = false,
   7293                     .size = .One,
   7294                     .elem_type = int_type,
   7295                 },
   7296             } });
   7297             const lhs = try expr(gz, scope, .{ .ty = int_type }, params[1]);
   7298             const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, params[2]);
   7299             const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[3]);
   7300             const result = try gz.addExtendedPayload(.shl_with_overflow, Zir.Inst.OverflowArithmetic{
   7301                 .node = gz.nodeIndexToRelative(node),
   7302                 .lhs = lhs,
   7303                 .rhs = rhs,
   7304                 .ptr = ptr,
   7305             });
   7306             return rvalue(gz, rl, result, node);
   7307         },
   7308 
   7309         .atomic_load => {
   7310             const int_type = try typeExpr(gz, scope, params[0]);
   7311             const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
   7312                 .ptr_type_simple = .{
   7313                     .is_allowzero = false,
   7314                     .is_mutable = false,
   7315                     .is_volatile = false,
   7316                     .size = .One,
   7317                     .elem_type = int_type,
   7318                 },
   7319             } });
   7320             const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]);
   7321             const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[2]);
   7322             const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.Bin{
   7323                 .lhs = ptr,
   7324                 .rhs = ordering,
   7325             });
   7326             return rvalue(gz, rl, result, node);
   7327         },
   7328         .atomic_rmw => {
   7329             const int_type = try typeExpr(gz, scope, params[0]);
   7330             const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
   7331                 .ptr_type_simple = .{
   7332                     .is_allowzero = false,
   7333                     .is_mutable = true,
   7334                     .is_volatile = false,
   7335                     .size = .One,
   7336                     .elem_type = int_type,
   7337                 },
   7338             } });
   7339             const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]);
   7340             const operation = try expr(gz, scope, .{ .ty = .atomic_rmw_op_type }, params[2]);
   7341             const operand = try expr(gz, scope, .{ .ty = int_type }, params[3]);
   7342             const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[4]);
   7343             const result = try gz.addPlNode(.atomic_rmw, node, Zir.Inst.AtomicRmw{
   7344                 .ptr = ptr,
   7345                 .operation = operation,
   7346                 .operand = operand,
   7347                 .ordering = ordering,
   7348             });
   7349             return rvalue(gz, rl, result, node);
   7350         },
   7351         .atomic_store => {
   7352             const int_type = try typeExpr(gz, scope, params[0]);
   7353             const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
   7354                 .ptr_type_simple = .{
   7355                     .is_allowzero = false,
   7356                     .is_mutable = true,
   7357                     .is_volatile = false,
   7358                     .size = .One,
   7359                     .elem_type = int_type,
   7360                 },
   7361             } });
   7362             const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]);
   7363             const operand = try expr(gz, scope, .{ .ty = int_type }, params[2]);
   7364             const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[3]);
   7365             const result = try gz.addPlNode(.atomic_store, node, Zir.Inst.AtomicStore{
   7366                 .ptr = ptr,
   7367                 .operand = operand,
   7368                 .ordering = ordering,
   7369             });
   7370             return rvalue(gz, rl, result, node);
   7371         },
   7372         .mul_add => {
   7373             const float_type = try typeExpr(gz, scope, params[0]);
   7374             const mulend1 = try expr(gz, scope, .{ .ty = float_type }, params[1]);
   7375             const mulend2 = try expr(gz, scope, .{ .ty = float_type }, params[2]);
   7376             const addend = try expr(gz, scope, .{ .ty = float_type }, params[3]);
   7377             const result = try gz.addPlNode(.mul_add, node, Zir.Inst.MulAdd{
   7378                 .mulend1 = mulend1,
   7379                 .mulend2 = mulend2,
   7380                 .addend = addend,
   7381             });
   7382             return rvalue(gz, rl, result, node);
   7383         },
   7384         .call => {
   7385             const options = try comptimeExpr(gz, scope, .{ .ty = .call_options_type }, params[0]);
   7386             const callee = try expr(gz, scope, .none, params[1]);
   7387             const args = try expr(gz, scope, .none, params[2]);
   7388             const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{
   7389                 .options = options,
   7390                 .callee = callee,
   7391                 .args = args,
   7392             });
   7393             return rvalue(gz, rl, result, node);
   7394         },
   7395         .field_parent_ptr => {
   7396             const parent_type = try typeExpr(gz, scope, params[0]);
   7397             const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
   7398             const field_ptr_type = try gz.addBin(.field_ptr_type, parent_type, field_name);
   7399             const result = try gz.addPlNode(.field_parent_ptr, node, Zir.Inst.FieldParentPtr{
   7400                 .parent_type = parent_type,
   7401                 .field_name = field_name,
   7402                 .field_ptr = try expr(gz, scope, .{ .ty = field_ptr_type }, params[2]),
   7403             });
   7404             return rvalue(gz, rl, result, node);
   7405         },
   7406         .memcpy => {
   7407             const result = try gz.addPlNode(.memcpy, node, Zir.Inst.Memcpy{
   7408                 .dest = try expr(gz, scope, .{ .ty = .manyptr_u8_type }, params[0]),
   7409                 .source = try expr(gz, scope, .{ .ty = .manyptr_const_u8_type }, params[1]),
   7410                 .byte_count = try expr(gz, scope, .{ .ty = .usize_type }, params[2]),
   7411             });
   7412             return rvalue(gz, rl, result, node);
   7413         },
   7414         .memset => {
   7415             const result = try gz.addPlNode(.memset, node, Zir.Inst.Memset{
   7416                 .dest = try expr(gz, scope, .{ .ty = .manyptr_u8_type }, params[0]),
   7417                 .byte = try expr(gz, scope, .{ .ty = .u8_type }, params[1]),
   7418                 .byte_count = try expr(gz, scope, .{ .ty = .usize_type }, params[2]),
   7419             });
   7420             return rvalue(gz, rl, result, node);
   7421         },
   7422         .shuffle => {
   7423             const result = try gz.addPlNode(.shuffle, node, Zir.Inst.Shuffle{
   7424                 .elem_type = try typeExpr(gz, scope, params[0]),
   7425                 .a = try expr(gz, scope, .none, params[1]),
   7426                 .b = try expr(gz, scope, .none, params[2]),
   7427                 .mask = try comptimeExpr(gz, scope, .none, params[3]),
   7428             });
   7429             return rvalue(gz, rl, result, node);
   7430         },
   7431         .select => {
   7432             const result = try gz.addPlNode(.select, node, Zir.Inst.Select{
   7433                 .elem_type = try typeExpr(gz, scope, params[0]),
   7434                 .pred = try expr(gz, scope, .none, params[1]),
   7435                 .a = try expr(gz, scope, .none, params[2]),
   7436                 .b = try expr(gz, scope, .none, params[3]),
   7437             });
   7438             return rvalue(gz, rl, result, node);
   7439         },
   7440         .async_call => {
   7441             const result = try gz.addPlNode(.builtin_async_call, node, Zir.Inst.AsyncCall{
   7442                 .frame_buffer = try expr(gz, scope, .none, params[0]),
   7443                 .result_ptr = try expr(gz, scope, .none, params[1]),
   7444                 .fn_ptr = try expr(gz, scope, .none, params[2]),
   7445                 .args = try expr(gz, scope, .none, params[3]),
   7446             });
   7447             return rvalue(gz, rl, result, node);
   7448         },
   7449         .Vector => {
   7450             const result = try gz.addPlNode(.vector_type, node, Zir.Inst.Bin{
   7451                 .lhs = try comptimeExpr(gz, scope, .{.ty = .u32_type}, params[0]),
   7452                 .rhs = try typeExpr(gz, scope, params[1]),
   7453             });
   7454             return rvalue(gz, rl, result, node);
   7455         },
   7456 
   7457     }
   7458     // zig fmt: on
   7459 }
   7460 
   7461 fn simpleNoOpVoid(
   7462     gz: *GenZir,
   7463     rl: ResultLoc,
   7464     node: ast.Node.Index,
   7465     tag: Zir.Inst.Tag,
   7466 ) InnerError!Zir.Inst.Ref {
   7467     _ = try gz.addNode(tag, node);
   7468     return rvalue(gz, rl, .void_value, node);
   7469 }
   7470 
   7471 fn hasDeclOrField(
   7472     gz: *GenZir,
   7473     scope: *Scope,
   7474     rl: ResultLoc,
   7475     node: ast.Node.Index,
   7476     lhs_node: ast.Node.Index,
   7477     rhs_node: ast.Node.Index,
   7478     tag: Zir.Inst.Tag,
   7479 ) InnerError!Zir.Inst.Ref {
   7480     const container_type = try typeExpr(gz, scope, lhs_node);
   7481     const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, rhs_node);
   7482     const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{
   7483         .lhs = container_type,
   7484         .rhs = name,
   7485     });
   7486     return rvalue(gz, rl, result, node);
   7487 }
   7488 
   7489 fn typeCast(
   7490     gz: *GenZir,
   7491     scope: *Scope,
   7492     rl: ResultLoc,
   7493     node: ast.Node.Index,
   7494     lhs_node: ast.Node.Index,
   7495     rhs_node: ast.Node.Index,
   7496     tag: Zir.Inst.Tag,
   7497 ) InnerError!Zir.Inst.Ref {
   7498     const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{
   7499         .lhs = try typeExpr(gz, scope, lhs_node),
   7500         .rhs = try expr(gz, scope, .none, rhs_node),
   7501     });
   7502     return rvalue(gz, rl, result, node);
   7503 }
   7504 
   7505 fn simpleUnOpType(
   7506     gz: *GenZir,
   7507     scope: *Scope,
   7508     rl: ResultLoc,
   7509     node: ast.Node.Index,
   7510     operand_node: ast.Node.Index,
   7511     tag: Zir.Inst.Tag,
   7512 ) InnerError!Zir.Inst.Ref {
   7513     const operand = try typeExpr(gz, scope, operand_node);
   7514     const result = try gz.addUnNode(tag, operand, node);
   7515     return rvalue(gz, rl, result, node);
   7516 }
   7517 
   7518 fn simpleUnOp(
   7519     gz: *GenZir,
   7520     scope: *Scope,
   7521     rl: ResultLoc,
   7522     node: ast.Node.Index,
   7523     operand_rl: ResultLoc,
   7524     operand_node: ast.Node.Index,
   7525     tag: Zir.Inst.Tag,
   7526 ) InnerError!Zir.Inst.Ref {
   7527     const operand = try expr(gz, scope, operand_rl, operand_node);
   7528     const result = try gz.addUnNode(tag, operand, node);
   7529     return rvalue(gz, rl, result, node);
   7530 }
   7531 
   7532 fn cmpxchg(
   7533     gz: *GenZir,
   7534     scope: *Scope,
   7535     rl: ResultLoc,
   7536     node: ast.Node.Index,
   7537     params: []const ast.Node.Index,
   7538     tag: Zir.Inst.Tag,
   7539 ) InnerError!Zir.Inst.Ref {
   7540     const int_type = try typeExpr(gz, scope, params[0]);
   7541     const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
   7542         .ptr_type_simple = .{
   7543             .is_allowzero = false,
   7544             .is_mutable = true,
   7545             .is_volatile = false,
   7546             .size = .One,
   7547             .elem_type = int_type,
   7548         },
   7549     } });
   7550     const result = try gz.addPlNode(tag, node, Zir.Inst.Cmpxchg{
   7551         // zig fmt: off
   7552         .ptr            = try expr(gz, scope, .{ .ty = ptr_type },              params[1]),
   7553         .expected_value = try expr(gz, scope, .{ .ty = int_type },              params[2]),
   7554         .new_value      = try expr(gz, scope, .{ .ty = int_type },              params[3]),
   7555         .success_order  = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[4]),
   7556         .fail_order     = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[5]),
   7557         // zig fmt: on
   7558     });
   7559     return rvalue(gz, rl, result, node);
   7560 }
   7561 
   7562 fn bitBuiltin(
   7563     gz: *GenZir,
   7564     scope: *Scope,
   7565     rl: ResultLoc,
   7566     node: ast.Node.Index,
   7567     int_type_node: ast.Node.Index,
   7568     operand_node: ast.Node.Index,
   7569     tag: Zir.Inst.Tag,
   7570 ) InnerError!Zir.Inst.Ref {
   7571     const int_type = try typeExpr(gz, scope, int_type_node);
   7572     const operand = try expr(gz, scope, .{ .ty = int_type }, operand_node);
   7573     const result = try gz.addUnNode(tag, operand, node);
   7574     return rvalue(gz, rl, result, node);
   7575 }
   7576 
   7577 fn divBuiltin(
   7578     gz: *GenZir,
   7579     scope: *Scope,
   7580     rl: ResultLoc,
   7581     node: ast.Node.Index,
   7582     lhs_node: ast.Node.Index,
   7583     rhs_node: ast.Node.Index,
   7584     tag: Zir.Inst.Tag,
   7585 ) InnerError!Zir.Inst.Ref {
   7586     const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{
   7587         .lhs = try expr(gz, scope, .none, lhs_node),
   7588         .rhs = try expr(gz, scope, .none, rhs_node),
   7589     });
   7590     return rvalue(gz, rl, result, node);
   7591 }
   7592 
   7593 fn simpleCBuiltin(
   7594     gz: *GenZir,
   7595     scope: *Scope,
   7596     rl: ResultLoc,
   7597     node: ast.Node.Index,
   7598     operand_node: ast.Node.Index,
   7599     tag: Zir.Inst.Extended,
   7600 ) InnerError!Zir.Inst.Ref {
   7601     const operand = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, operand_node);
   7602     _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{
   7603         .node = gz.nodeIndexToRelative(node),
   7604         .operand = operand,
   7605     });
   7606     return rvalue(gz, rl, .void_value, node);
   7607 }
   7608 
   7609 fn offsetOf(
   7610     gz: *GenZir,
   7611     scope: *Scope,
   7612     rl: ResultLoc,
   7613     node: ast.Node.Index,
   7614     lhs_node: ast.Node.Index,
   7615     rhs_node: ast.Node.Index,
   7616     tag: Zir.Inst.Tag,
   7617 ) InnerError!Zir.Inst.Ref {
   7618     const type_inst = try typeExpr(gz, scope, lhs_node);
   7619     const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, rhs_node);
   7620     const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{
   7621         .lhs = type_inst,
   7622         .rhs = field_name,
   7623     });
   7624     return rvalue(gz, rl, result, node);
   7625 }
   7626 
   7627 fn shiftOp(
   7628     gz: *GenZir,
   7629     scope: *Scope,
   7630     rl: ResultLoc,
   7631     node: ast.Node.Index,
   7632     lhs_node: ast.Node.Index,
   7633     rhs_node: ast.Node.Index,
   7634     tag: Zir.Inst.Tag,
   7635 ) InnerError!Zir.Inst.Ref {
   7636     const lhs = try expr(gz, scope, .none, lhs_node);
   7637     const log2_int_type = try gz.addUnNode(.typeof_log2_int_type, lhs, lhs_node);
   7638     const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, rhs_node);
   7639     const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{
   7640         .lhs = lhs,
   7641         .rhs = rhs,
   7642     });
   7643     return rvalue(gz, rl, result, node);
   7644 }
   7645 
   7646 fn cImport(
   7647     gz: *GenZir,
   7648     scope: *Scope,
   7649     rl: ResultLoc,
   7650     node: ast.Node.Index,
   7651     body_node: ast.Node.Index,
   7652 ) InnerError!Zir.Inst.Ref {
   7653     const astgen = gz.astgen;
   7654     const gpa = astgen.gpa;
   7655 
   7656     var block_scope = gz.makeSubBlock(scope);
   7657     block_scope.force_comptime = true;
   7658     defer block_scope.instructions.deinit(gpa);
   7659 
   7660     const block_inst = try gz.addBlock(.c_import, node);
   7661     const block_result = try expr(&block_scope, &block_scope.base, .none, body_node);
   7662     if (!gz.refIsNoReturn(block_result)) {
   7663         _ = try block_scope.addBreak(.break_inline, block_inst, .void_value);
   7664     }
   7665     try block_scope.setBlockBody(block_inst);
   7666     try gz.instructions.append(gpa, block_inst);
   7667 
   7668     return rvalue(gz, rl, .void_value, node);
   7669 }
   7670 
   7671 fn overflowArithmetic(
   7672     gz: *GenZir,
   7673     scope: *Scope,
   7674     rl: ResultLoc,
   7675     node: ast.Node.Index,
   7676     params: []const ast.Node.Index,
   7677     tag: Zir.Inst.Extended,
   7678 ) InnerError!Zir.Inst.Ref {
   7679     const int_type = try typeExpr(gz, scope, params[0]);
   7680     const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
   7681         .ptr_type_simple = .{
   7682             .is_allowzero = false,
   7683             .is_mutable = true,
   7684             .is_volatile = false,
   7685             .size = .One,
   7686             .elem_type = int_type,
   7687         },
   7688     } });
   7689     const lhs = try expr(gz, scope, .{ .ty = int_type }, params[1]);
   7690     const rhs = try expr(gz, scope, .{ .ty = int_type }, params[2]);
   7691     const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[3]);
   7692     const result = try gz.addExtendedPayload(tag, Zir.Inst.OverflowArithmetic{
   7693         .node = gz.nodeIndexToRelative(node),
   7694         .lhs = lhs,
   7695         .rhs = rhs,
   7696         .ptr = ptr,
   7697     });
   7698     return rvalue(gz, rl, result, node);
   7699 }
   7700 
   7701 fn callExpr(
   7702     gz: *GenZir,
   7703     scope: *Scope,
   7704     rl: ResultLoc,
   7705     node: ast.Node.Index,
   7706     call: ast.full.Call,
   7707 ) InnerError!Zir.Inst.Ref {
   7708     const astgen = gz.astgen;
   7709     const lhs = try expr(gz, scope, .none, call.ast.fn_expr);
   7710 
   7711     const args = try astgen.gpa.alloc(Zir.Inst.Ref, call.ast.params.len);
   7712     defer astgen.gpa.free(args);
   7713 
   7714     for (call.ast.params) |param_node, i| {
   7715         const param_type = try gz.add(.{
   7716             .tag = .param_type,
   7717             .data = .{ .param_type = .{
   7718                 .callee = lhs,
   7719                 .param_index = @intCast(u32, i),
   7720             } },
   7721         });
   7722         args[i] = try expr(gz, scope, .{ .coerced_ty = param_type }, param_node);
   7723     }
   7724 
   7725     const modifier: std.builtin.CallOptions.Modifier = blk: {
   7726         if (gz.force_comptime) {
   7727             break :blk .compile_time;
   7728         }
   7729         if (call.async_token != null) {
   7730             break :blk .async_kw;
   7731         }
   7732         if (gz.nosuspend_node != 0) {
   7733             break :blk .no_async;
   7734         }
   7735         break :blk .auto;
   7736     };
   7737     const result: Zir.Inst.Ref = res: {
   7738         const tag: Zir.Inst.Tag = switch (modifier) {
   7739             .auto => .call,
   7740             .async_kw => .call_async,
   7741             .never_tail => unreachable,
   7742             .never_inline => unreachable,
   7743             .no_async => .call_nosuspend,
   7744             .always_tail => unreachable,
   7745             .always_inline => unreachable,
   7746             .compile_time => .call_compile_time,
   7747         };
   7748         break :res try gz.addCall(tag, lhs, args, node);
   7749     };
   7750     return rvalue(gz, rl, result, node); // TODO function call with result location
   7751 }
   7752 
   7753 pub const simple_types = std.ComptimeStringMap(Zir.Inst.Ref, .{
   7754     .{ "anyerror", .anyerror_type },
   7755     .{ "anyframe", .anyframe_type },
   7756     .{ "bool", .bool_type },
   7757     .{ "c_int", .c_int_type },
   7758     .{ "c_long", .c_long_type },
   7759     .{ "c_longdouble", .c_longdouble_type },
   7760     .{ "c_longlong", .c_longlong_type },
   7761     .{ "c_short", .c_short_type },
   7762     .{ "c_uint", .c_uint_type },
   7763     .{ "c_ulong", .c_ulong_type },
   7764     .{ "c_ulonglong", .c_ulonglong_type },
   7765     .{ "c_ushort", .c_ushort_type },
   7766     .{ "c_void", .c_void_type },
   7767     .{ "comptime_float", .comptime_float_type },
   7768     .{ "comptime_int", .comptime_int_type },
   7769     .{ "f128", .f128_type },
   7770     .{ "f16", .f16_type },
   7771     .{ "f32", .f32_type },
   7772     .{ "f64", .f64_type },
   7773     .{ "false", .bool_false },
   7774     .{ "i16", .i16_type },
   7775     .{ "i32", .i32_type },
   7776     .{ "i64", .i64_type },
   7777     .{ "i128", .i128_type },
   7778     .{ "i8", .i8_type },
   7779     .{ "isize", .isize_type },
   7780     .{ "noreturn", .noreturn_type },
   7781     .{ "null", .null_value },
   7782     .{ "true", .bool_true },
   7783     .{ "type", .type_type },
   7784     .{ "u16", .u16_type },
   7785     .{ "u32", .u32_type },
   7786     .{ "u64", .u64_type },
   7787     .{ "u128", .u128_type },
   7788     .{ "u1", .u1_type },
   7789     .{ "u8", .u8_type },
   7790     .{ "undefined", .undef },
   7791     .{ "usize", .usize_type },
   7792     .{ "void", .void_type },
   7793 });
   7794 
   7795 fn nodeMayNeedMemoryLocation(tree: *const ast.Tree, start_node: ast.Node.Index) bool {
   7796     const node_tags = tree.nodes.items(.tag);
   7797     const node_datas = tree.nodes.items(.data);
   7798     const main_tokens = tree.nodes.items(.main_token);
   7799     const token_tags = tree.tokens.items(.tag);
   7800 
   7801     var node = start_node;
   7802     while (true) {
   7803         switch (node_tags[node]) {
   7804             .root,
   7805             .@"usingnamespace",
   7806             .test_decl,
   7807             .switch_case,
   7808             .switch_case_one,
   7809             .container_field_init,
   7810             .container_field_align,
   7811             .container_field,
   7812             .asm_output,
   7813             .asm_input,
   7814             => unreachable,
   7815 
   7816             .@"return",
   7817             .@"break",
   7818             .@"continue",
   7819             .bit_not,
   7820             .bool_not,
   7821             .global_var_decl,
   7822             .local_var_decl,
   7823             .simple_var_decl,
   7824             .aligned_var_decl,
   7825             .@"defer",
   7826             .@"errdefer",
   7827             .address_of,
   7828             .optional_type,
   7829             .negation,
   7830             .negation_wrap,
   7831             .@"resume",
   7832             .array_type,
   7833             .array_type_sentinel,
   7834             .ptr_type_aligned,
   7835             .ptr_type_sentinel,
   7836             .ptr_type,
   7837             .ptr_type_bit_range,
   7838             .@"suspend",
   7839             .@"anytype",
   7840             .fn_proto_simple,
   7841             .fn_proto_multi,
   7842             .fn_proto_one,
   7843             .fn_proto,
   7844             .fn_decl,
   7845             .anyframe_type,
   7846             .anyframe_literal,
   7847             .integer_literal,
   7848             .float_literal,
   7849             .enum_literal,
   7850             .string_literal,
   7851             .multiline_string_literal,
   7852             .char_literal,
   7853             .unreachable_literal,
   7854             .identifier,
   7855             .error_set_decl,
   7856             .container_decl,
   7857             .container_decl_trailing,
   7858             .container_decl_two,
   7859             .container_decl_two_trailing,
   7860             .container_decl_arg,
   7861             .container_decl_arg_trailing,
   7862             .tagged_union,
   7863             .tagged_union_trailing,
   7864             .tagged_union_two,
   7865             .tagged_union_two_trailing,
   7866             .tagged_union_enum_tag,
   7867             .tagged_union_enum_tag_trailing,
   7868             .@"asm",
   7869             .asm_simple,
   7870             .add,
   7871             .add_wrap,
   7872             .array_cat,
   7873             .array_mult,
   7874             .assign,
   7875             .assign_bit_and,
   7876             .assign_bit_or,
   7877             .assign_bit_shift_left,
   7878             .assign_bit_shift_right,
   7879             .assign_bit_xor,
   7880             .assign_div,
   7881             .assign_sub,
   7882             .assign_sub_wrap,
   7883             .assign_mod,
   7884             .assign_add,
   7885             .assign_add_wrap,
   7886             .assign_mul,
   7887             .assign_mul_wrap,
   7888             .bang_equal,
   7889             .bit_and,
   7890             .bit_or,
   7891             .bit_shift_left,
   7892             .bit_shift_right,
   7893             .bit_xor,
   7894             .bool_and,
   7895             .bool_or,
   7896             .div,
   7897             .equal_equal,
   7898             .error_union,
   7899             .greater_or_equal,
   7900             .greater_than,
   7901             .less_or_equal,
   7902             .less_than,
   7903             .merge_error_sets,
   7904             .mod,
   7905             .mul,
   7906             .mul_wrap,
   7907             .switch_range,
   7908             .field_access,
   7909             .sub,
   7910             .sub_wrap,
   7911             .slice,
   7912             .slice_open,
   7913             .slice_sentinel,
   7914             .deref,
   7915             .array_access,
   7916             .error_value,
   7917             .while_simple, // This variant cannot have an else expression.
   7918             .while_cont, // This variant cannot have an else expression.
   7919             .for_simple, // This variant cannot have an else expression.
   7920             .if_simple, // This variant cannot have an else expression.
   7921             => return false,
   7922 
   7923             // Forward the question to the LHS sub-expression.
   7924             .grouped_expression,
   7925             .@"try",
   7926             .@"await",
   7927             .@"comptime",
   7928             .@"nosuspend",
   7929             .unwrap_optional,
   7930             => node = node_datas[node].lhs,
   7931 
   7932             // Forward the question to the RHS sub-expression.
   7933             .@"catch",
   7934             .@"orelse",
   7935             => node = node_datas[node].rhs,
   7936 
   7937             // True because these are exactly the expressions we need memory locations for.
   7938             .array_init_one,
   7939             .array_init_one_comma,
   7940             .array_init_dot_two,
   7941             .array_init_dot_two_comma,
   7942             .array_init_dot,
   7943             .array_init_dot_comma,
   7944             .array_init,
   7945             .array_init_comma,
   7946             .struct_init_one,
   7947             .struct_init_one_comma,
   7948             .struct_init_dot_two,
   7949             .struct_init_dot_two_comma,
   7950             .struct_init_dot,
   7951             .struct_init_dot_comma,
   7952             .struct_init,
   7953             .struct_init_comma,
   7954             => return true,
   7955 
   7956             // True because depending on comptime conditions, sub-expressions
   7957             // may be the kind that need memory locations.
   7958             .@"while", // This variant always has an else expression.
   7959             .@"if", // This variant always has an else expression.
   7960             .@"for", // This variant always has an else expression.
   7961             .@"switch",
   7962             .switch_comma,
   7963             .call_one,
   7964             .call_one_comma,
   7965             .async_call_one,
   7966             .async_call_one_comma,
   7967             .call,
   7968             .call_comma,
   7969             .async_call,
   7970             .async_call_comma,
   7971             => return true,
   7972 
   7973             .block_two,
   7974             .block_two_semicolon,
   7975             .block,
   7976             .block_semicolon,
   7977             => {
   7978                 const lbrace = main_tokens[node];
   7979                 if (token_tags[lbrace - 1] == .colon) {
   7980                     // Labeled blocks may need a memory location to forward
   7981                     // to their break statements.
   7982                     return true;
   7983                 } else {
   7984                     return false;
   7985                 }
   7986             },
   7987 
   7988             .builtin_call,
   7989             .builtin_call_comma,
   7990             .builtin_call_two,
   7991             .builtin_call_two_comma,
   7992             => {
   7993                 const builtin_token = main_tokens[node];
   7994                 const builtin_name = tree.tokenSlice(builtin_token);
   7995                 // If the builtin is an invalid name, we don't cause an error here; instead
   7996                 // let it pass, and the error will be "invalid builtin function" later.
   7997                 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return false;
   7998                 return builtin_info.needs_mem_loc;
   7999             },
   8000         }
   8001     }
   8002 }
   8003 
   8004 fn nodeMayEvalToError(tree: *const ast.Tree, start_node: ast.Node.Index) enum { never, always, maybe } {
   8005     const node_tags = tree.nodes.items(.tag);
   8006     const node_datas = tree.nodes.items(.data);
   8007     const main_tokens = tree.nodes.items(.main_token);
   8008     const token_tags = tree.tokens.items(.tag);
   8009 
   8010     var node = start_node;
   8011     while (true) {
   8012         switch (node_tags[node]) {
   8013             .root,
   8014             .@"usingnamespace",
   8015             .test_decl,
   8016             .switch_case,
   8017             .switch_case_one,
   8018             .container_field_init,
   8019             .container_field_align,
   8020             .container_field,
   8021             .asm_output,
   8022             .asm_input,
   8023             => unreachable,
   8024 
   8025             .error_value => return .always,
   8026 
   8027             .@"asm",
   8028             .asm_simple,
   8029             .identifier,
   8030             .field_access,
   8031             .deref,
   8032             .array_access,
   8033             .while_simple,
   8034             .while_cont,
   8035             .for_simple,
   8036             .if_simple,
   8037             .@"while",
   8038             .@"if",
   8039             .@"for",
   8040             .@"switch",
   8041             .switch_comma,
   8042             .call_one,
   8043             .call_one_comma,
   8044             .async_call_one,
   8045             .async_call_one_comma,
   8046             .call,
   8047             .call_comma,
   8048             .async_call,
   8049             .async_call_comma,
   8050             => return .maybe,
   8051 
   8052             .@"return",
   8053             .@"break",
   8054             .@"continue",
   8055             .bit_not,
   8056             .bool_not,
   8057             .global_var_decl,
   8058             .local_var_decl,
   8059             .simple_var_decl,
   8060             .aligned_var_decl,
   8061             .@"defer",
   8062             .@"errdefer",
   8063             .address_of,
   8064             .optional_type,
   8065             .negation,
   8066             .negation_wrap,
   8067             .@"resume",
   8068             .array_type,
   8069             .array_type_sentinel,
   8070             .ptr_type_aligned,
   8071             .ptr_type_sentinel,
   8072             .ptr_type,
   8073             .ptr_type_bit_range,
   8074             .@"suspend",
   8075             .@"anytype",
   8076             .fn_proto_simple,
   8077             .fn_proto_multi,
   8078             .fn_proto_one,
   8079             .fn_proto,
   8080             .fn_decl,
   8081             .anyframe_type,
   8082             .anyframe_literal,
   8083             .integer_literal,
   8084             .float_literal,
   8085             .enum_literal,
   8086             .string_literal,
   8087             .multiline_string_literal,
   8088             .char_literal,
   8089             .unreachable_literal,
   8090             .error_set_decl,
   8091             .container_decl,
   8092             .container_decl_trailing,
   8093             .container_decl_two,
   8094             .container_decl_two_trailing,
   8095             .container_decl_arg,
   8096             .container_decl_arg_trailing,
   8097             .tagged_union,
   8098             .tagged_union_trailing,
   8099             .tagged_union_two,
   8100             .tagged_union_two_trailing,
   8101             .tagged_union_enum_tag,
   8102             .tagged_union_enum_tag_trailing,
   8103             .add,
   8104             .add_wrap,
   8105             .array_cat,
   8106             .array_mult,
   8107             .assign,
   8108             .assign_bit_and,
   8109             .assign_bit_or,
   8110             .assign_bit_shift_left,
   8111             .assign_bit_shift_right,
   8112             .assign_bit_xor,
   8113             .assign_div,
   8114             .assign_sub,
   8115             .assign_sub_wrap,
   8116             .assign_mod,
   8117             .assign_add,
   8118             .assign_add_wrap,
   8119             .assign_mul,
   8120             .assign_mul_wrap,
   8121             .bang_equal,
   8122             .bit_and,
   8123             .bit_or,
   8124             .bit_shift_left,
   8125             .bit_shift_right,
   8126             .bit_xor,
   8127             .bool_and,
   8128             .bool_or,
   8129             .div,
   8130             .equal_equal,
   8131             .error_union,
   8132             .greater_or_equal,
   8133             .greater_than,
   8134             .less_or_equal,
   8135             .less_than,
   8136             .merge_error_sets,
   8137             .mod,
   8138             .mul,
   8139             .mul_wrap,
   8140             .switch_range,
   8141             .sub,
   8142             .sub_wrap,
   8143             .slice,
   8144             .slice_open,
   8145             .slice_sentinel,
   8146             .array_init_one,
   8147             .array_init_one_comma,
   8148             .array_init_dot_two,
   8149             .array_init_dot_two_comma,
   8150             .array_init_dot,
   8151             .array_init_dot_comma,
   8152             .array_init,
   8153             .array_init_comma,
   8154             .struct_init_one,
   8155             .struct_init_one_comma,
   8156             .struct_init_dot_two,
   8157             .struct_init_dot_two_comma,
   8158             .struct_init_dot,
   8159             .struct_init_dot_comma,
   8160             .struct_init,
   8161             .struct_init_comma,
   8162             => return .never,
   8163 
   8164             // Forward the question to the LHS sub-expression.
   8165             .grouped_expression,
   8166             .@"try",
   8167             .@"await",
   8168             .@"comptime",
   8169             .@"nosuspend",
   8170             .unwrap_optional,
   8171             => node = node_datas[node].lhs,
   8172 
   8173             // Forward the question to the RHS sub-expression.
   8174             .@"catch",
   8175             .@"orelse",
   8176             => node = node_datas[node].rhs,
   8177 
   8178             .block_two,
   8179             .block_two_semicolon,
   8180             .block,
   8181             .block_semicolon,
   8182             => {
   8183                 const lbrace = main_tokens[node];
   8184                 if (token_tags[lbrace - 1] == .colon) {
   8185                     // Labeled blocks may need a memory location to forward
   8186                     // to their break statements.
   8187                     return .maybe;
   8188                 } else {
   8189                     return .never;
   8190                 }
   8191             },
   8192 
   8193             .builtin_call,
   8194             .builtin_call_comma,
   8195             .builtin_call_two,
   8196             .builtin_call_two_comma,
   8197             => {
   8198                 const builtin_token = main_tokens[node];
   8199                 const builtin_name = tree.tokenSlice(builtin_token);
   8200                 // If the builtin is an invalid name, we don't cause an error here; instead
   8201                 // let it pass, and the error will be "invalid builtin function" later.
   8202                 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return .maybe;
   8203                 if (builtin_info.tag == .err_set_cast) {
   8204                     return .always;
   8205                 } else {
   8206                     return .never;
   8207                 }
   8208             },
   8209         }
   8210     }
   8211 }
   8212 
   8213 fn nodeImpliesRuntimeBits(tree: *const ast.Tree, start_node: ast.Node.Index) bool {
   8214     const node_tags = tree.nodes.items(.tag);
   8215     const node_datas = tree.nodes.items(.data);
   8216 
   8217     var node = start_node;
   8218     while (true) {
   8219         switch (node_tags[node]) {
   8220             .root,
   8221             .@"usingnamespace",
   8222             .test_decl,
   8223             .switch_case,
   8224             .switch_case_one,
   8225             .container_field_init,
   8226             .container_field_align,
   8227             .container_field,
   8228             .asm_output,
   8229             .asm_input,
   8230             .global_var_decl,
   8231             .local_var_decl,
   8232             .simple_var_decl,
   8233             .aligned_var_decl,
   8234             => unreachable,
   8235 
   8236             .@"return",
   8237             .@"break",
   8238             .@"continue",
   8239             .bit_not,
   8240             .bool_not,
   8241             .@"defer",
   8242             .@"errdefer",
   8243             .address_of,
   8244             .negation,
   8245             .negation_wrap,
   8246             .@"resume",
   8247             .array_type,
   8248             .@"suspend",
   8249             .@"anytype",
   8250             .fn_decl,
   8251             .anyframe_literal,
   8252             .integer_literal,
   8253             .float_literal,
   8254             .enum_literal,
   8255             .string_literal,
   8256             .multiline_string_literal,
   8257             .char_literal,
   8258             .unreachable_literal,
   8259             .identifier,
   8260             .error_set_decl,
   8261             .container_decl,
   8262             .container_decl_trailing,
   8263             .container_decl_two,
   8264             .container_decl_two_trailing,
   8265             .container_decl_arg,
   8266             .container_decl_arg_trailing,
   8267             .tagged_union,
   8268             .tagged_union_trailing,
   8269             .tagged_union_two,
   8270             .tagged_union_two_trailing,
   8271             .tagged_union_enum_tag,
   8272             .tagged_union_enum_tag_trailing,
   8273             .@"asm",
   8274             .asm_simple,
   8275             .add,
   8276             .add_wrap,
   8277             .array_cat,
   8278             .array_mult,
   8279             .assign,
   8280             .assign_bit_and,
   8281             .assign_bit_or,
   8282             .assign_bit_shift_left,
   8283             .assign_bit_shift_right,
   8284             .assign_bit_xor,
   8285             .assign_div,
   8286             .assign_sub,
   8287             .assign_sub_wrap,
   8288             .assign_mod,
   8289             .assign_add,
   8290             .assign_add_wrap,
   8291             .assign_mul,
   8292             .assign_mul_wrap,
   8293             .bang_equal,
   8294             .bit_and,
   8295             .bit_or,
   8296             .bit_shift_left,
   8297             .bit_shift_right,
   8298             .bit_xor,
   8299             .bool_and,
   8300             .bool_or,
   8301             .div,
   8302             .equal_equal,
   8303             .error_union,
   8304             .greater_or_equal,
   8305             .greater_than,
   8306             .less_or_equal,
   8307             .less_than,
   8308             .merge_error_sets,
   8309             .mod,
   8310             .mul,
   8311             .mul_wrap,
   8312             .switch_range,
   8313             .field_access,
   8314             .sub,
   8315             .sub_wrap,
   8316             .slice,
   8317             .slice_open,
   8318             .slice_sentinel,
   8319             .deref,
   8320             .array_access,
   8321             .error_value,
   8322             .while_simple,
   8323             .while_cont,
   8324             .for_simple,
   8325             .if_simple,
   8326             .@"catch",
   8327             .@"orelse",
   8328             .array_init_one,
   8329             .array_init_one_comma,
   8330             .array_init_dot_two,
   8331             .array_init_dot_two_comma,
   8332             .array_init_dot,
   8333             .array_init_dot_comma,
   8334             .array_init,
   8335             .array_init_comma,
   8336             .struct_init_one,
   8337             .struct_init_one_comma,
   8338             .struct_init_dot_two,
   8339             .struct_init_dot_two_comma,
   8340             .struct_init_dot,
   8341             .struct_init_dot_comma,
   8342             .struct_init,
   8343             .struct_init_comma,
   8344             .@"while",
   8345             .@"if",
   8346             .@"for",
   8347             .@"switch",
   8348             .switch_comma,
   8349             .call_one,
   8350             .call_one_comma,
   8351             .async_call_one,
   8352             .async_call_one_comma,
   8353             .call,
   8354             .call_comma,
   8355             .async_call,
   8356             .async_call_comma,
   8357             .block_two,
   8358             .block_two_semicolon,
   8359             .block,
   8360             .block_semicolon,
   8361             .builtin_call,
   8362             .builtin_call_comma,
   8363             .builtin_call_two,
   8364             .builtin_call_two_comma,
   8365             => return false,
   8366 
   8367             // Forward the question to the LHS sub-expression.
   8368             .grouped_expression,
   8369             .@"try",
   8370             .@"await",
   8371             .@"comptime",
   8372             .@"nosuspend",
   8373             .unwrap_optional,
   8374             => node = node_datas[node].lhs,
   8375 
   8376             .fn_proto_simple,
   8377             .fn_proto_multi,
   8378             .fn_proto_one,
   8379             .fn_proto,
   8380             .ptr_type_aligned,
   8381             .ptr_type_sentinel,
   8382             .ptr_type,
   8383             .ptr_type_bit_range,
   8384             .optional_type,
   8385             .anyframe_type,
   8386             .array_type_sentinel,
   8387             => return true,
   8388         }
   8389     }
   8390 }
   8391 
   8392 /// Applies `rl` semantics to `inst`. Expressions which do not do their own handling of
   8393 /// result locations must call this function on their result.
   8394 /// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer.
   8395 /// If the `ResultLoc` is `ty`, it will coerce the result to the type.
   8396 fn rvalue(
   8397     gz: *GenZir,
   8398     rl: ResultLoc,
   8399     result: Zir.Inst.Ref,
   8400     src_node: ast.Node.Index,
   8401 ) InnerError!Zir.Inst.Ref {
   8402     switch (rl) {
   8403         .none, .none_or_ref, .coerced_ty => return result,
   8404         .discard => {
   8405             // Emit a compile error for discarding error values.
   8406             _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);
   8407             return result;
   8408         },
   8409         .ref => {
   8410             // We need a pointer but we have a value.
   8411             const tree = gz.astgen.tree;
   8412             const src_token = tree.firstToken(src_node);
   8413             return gz.addUnTok(.ref, result, src_token);
   8414         },
   8415         .ty => |ty_inst| {
   8416             // Quickly eliminate some common, unnecessary type coercion.
   8417             const as_ty = @as(u64, @enumToInt(Zir.Inst.Ref.type_type)) << 32;
   8418             const as_comptime_int = @as(u64, @enumToInt(Zir.Inst.Ref.comptime_int_type)) << 32;
   8419             const as_bool = @as(u64, @enumToInt(Zir.Inst.Ref.bool_type)) << 32;
   8420             const as_usize = @as(u64, @enumToInt(Zir.Inst.Ref.usize_type)) << 32;
   8421             const as_void = @as(u64, @enumToInt(Zir.Inst.Ref.void_type)) << 32;
   8422             switch ((@as(u64, @enumToInt(ty_inst)) << 32) | @as(u64, @enumToInt(result))) {
   8423                 as_ty | @enumToInt(Zir.Inst.Ref.u1_type),
   8424                 as_ty | @enumToInt(Zir.Inst.Ref.u8_type),
   8425                 as_ty | @enumToInt(Zir.Inst.Ref.i8_type),
   8426                 as_ty | @enumToInt(Zir.Inst.Ref.u16_type),
   8427                 as_ty | @enumToInt(Zir.Inst.Ref.i16_type),
   8428                 as_ty | @enumToInt(Zir.Inst.Ref.u32_type),
   8429                 as_ty | @enumToInt(Zir.Inst.Ref.i32_type),
   8430                 as_ty | @enumToInt(Zir.Inst.Ref.u64_type),
   8431                 as_ty | @enumToInt(Zir.Inst.Ref.i64_type),
   8432                 as_ty | @enumToInt(Zir.Inst.Ref.usize_type),
   8433                 as_ty | @enumToInt(Zir.Inst.Ref.isize_type),
   8434                 as_ty | @enumToInt(Zir.Inst.Ref.c_short_type),
   8435                 as_ty | @enumToInt(Zir.Inst.Ref.c_ushort_type),
   8436                 as_ty | @enumToInt(Zir.Inst.Ref.c_int_type),
   8437                 as_ty | @enumToInt(Zir.Inst.Ref.c_uint_type),
   8438                 as_ty | @enumToInt(Zir.Inst.Ref.c_long_type),
   8439                 as_ty | @enumToInt(Zir.Inst.Ref.c_ulong_type),
   8440                 as_ty | @enumToInt(Zir.Inst.Ref.c_longlong_type),
   8441                 as_ty | @enumToInt(Zir.Inst.Ref.c_ulonglong_type),
   8442                 as_ty | @enumToInt(Zir.Inst.Ref.c_longdouble_type),
   8443                 as_ty | @enumToInt(Zir.Inst.Ref.f16_type),
   8444                 as_ty | @enumToInt(Zir.Inst.Ref.f32_type),
   8445                 as_ty | @enumToInt(Zir.Inst.Ref.f64_type),
   8446                 as_ty | @enumToInt(Zir.Inst.Ref.f128_type),
   8447                 as_ty | @enumToInt(Zir.Inst.Ref.c_void_type),
   8448                 as_ty | @enumToInt(Zir.Inst.Ref.bool_type),
   8449                 as_ty | @enumToInt(Zir.Inst.Ref.void_type),
   8450                 as_ty | @enumToInt(Zir.Inst.Ref.type_type),
   8451                 as_ty | @enumToInt(Zir.Inst.Ref.anyerror_type),
   8452                 as_ty | @enumToInt(Zir.Inst.Ref.comptime_int_type),
   8453                 as_ty | @enumToInt(Zir.Inst.Ref.comptime_float_type),
   8454                 as_ty | @enumToInt(Zir.Inst.Ref.noreturn_type),
   8455                 as_ty | @enumToInt(Zir.Inst.Ref.null_type),
   8456                 as_ty | @enumToInt(Zir.Inst.Ref.undefined_type),
   8457                 as_ty | @enumToInt(Zir.Inst.Ref.fn_noreturn_no_args_type),
   8458                 as_ty | @enumToInt(Zir.Inst.Ref.fn_void_no_args_type),
   8459                 as_ty | @enumToInt(Zir.Inst.Ref.fn_naked_noreturn_no_args_type),
   8460                 as_ty | @enumToInt(Zir.Inst.Ref.fn_ccc_void_no_args_type),
   8461                 as_ty | @enumToInt(Zir.Inst.Ref.single_const_pointer_to_comptime_int_type),
   8462                 as_ty | @enumToInt(Zir.Inst.Ref.const_slice_u8_type),
   8463                 as_ty | @enumToInt(Zir.Inst.Ref.enum_literal_type),
   8464                 as_comptime_int | @enumToInt(Zir.Inst.Ref.zero),
   8465                 as_comptime_int | @enumToInt(Zir.Inst.Ref.one),
   8466                 as_bool | @enumToInt(Zir.Inst.Ref.bool_true),
   8467                 as_bool | @enumToInt(Zir.Inst.Ref.bool_false),
   8468                 as_usize | @enumToInt(Zir.Inst.Ref.zero_usize),
   8469                 as_usize | @enumToInt(Zir.Inst.Ref.one_usize),
   8470                 as_void | @enumToInt(Zir.Inst.Ref.void_value),
   8471                 => return result, // type of result is already correct
   8472 
   8473                 // Need an explicit type coercion instruction.
   8474                 else => return gz.addPlNode(.as_node, src_node, Zir.Inst.As{
   8475                     .dest_type = ty_inst,
   8476                     .operand = result,
   8477                 }),
   8478             }
   8479         },
   8480         .ptr => |ptr_inst| {
   8481             _ = try gz.addPlNode(.store_node, src_node, Zir.Inst.Bin{
   8482                 .lhs = ptr_inst,
   8483                 .rhs = result,
   8484             });
   8485             return result;
   8486         },
   8487         .inferred_ptr => |alloc| {
   8488             _ = try gz.addBin(.store_to_inferred_ptr, alloc, result);
   8489             return result;
   8490         },
   8491         .block_ptr => |block_scope| {
   8492             block_scope.rvalue_rl_count += 1;
   8493             _ = try gz.addBin(.store_to_block_ptr, block_scope.rl_ptr, result);
   8494             return result;
   8495         },
   8496     }
   8497 }
   8498 
   8499 /// Given an identifier token, obtain the string for it.
   8500 /// If the token uses @"" syntax, parses as a string, reports errors if applicable,
   8501 /// and allocates the result within `astgen.arena`.
   8502 /// Otherwise, returns a reference to the source code bytes directly.
   8503 /// See also `appendIdentStr` and `parseStrLit`.
   8504 fn identifierTokenString(astgen: *AstGen, token: ast.TokenIndex) InnerError![]const u8 {
   8505     const tree = astgen.tree;
   8506     const token_tags = tree.tokens.items(.tag);
   8507     assert(token_tags[token] == .identifier);
   8508     const ident_name = tree.tokenSlice(token);
   8509     if (!mem.startsWith(u8, ident_name, "@")) {
   8510         return ident_name;
   8511     }
   8512     var buf: ArrayListUnmanaged(u8) = .{};
   8513     defer buf.deinit(astgen.gpa);
   8514     try astgen.parseStrLit(token, &buf, ident_name, 1);
   8515     const duped = try astgen.arena.dupe(u8, buf.items);
   8516     return duped;
   8517 }
   8518 
   8519 /// Given an identifier token, obtain the string for it (possibly parsing as a string
   8520 /// literal if it is @"" syntax), and append the string to `buf`.
   8521 /// See also `identifierTokenString` and `parseStrLit`.
   8522 fn appendIdentStr(
   8523     astgen: *AstGen,
   8524     token: ast.TokenIndex,
   8525     buf: *ArrayListUnmanaged(u8),
   8526 ) InnerError!void {
   8527     const tree = astgen.tree;
   8528     const token_tags = tree.tokens.items(.tag);
   8529     assert(token_tags[token] == .identifier);
   8530     const ident_name = tree.tokenSlice(token);
   8531     if (!mem.startsWith(u8, ident_name, "@")) {
   8532         return buf.appendSlice(astgen.gpa, ident_name);
   8533     } else {
   8534         return astgen.parseStrLit(token, buf, ident_name, 1);
   8535     }
   8536 }
   8537 
   8538 /// Appends the result to `buf`.
   8539 fn parseStrLit(
   8540     astgen: *AstGen,
   8541     token: ast.TokenIndex,
   8542     buf: *ArrayListUnmanaged(u8),
   8543     bytes: []const u8,
   8544     offset: u32,
   8545 ) InnerError!void {
   8546     const raw_string = bytes[offset..];
   8547     var buf_managed = buf.toManaged(astgen.gpa);
   8548     const result = std.zig.string_literal.parseAppend(&buf_managed, raw_string);
   8549     buf.* = buf_managed.toUnmanaged();
   8550     switch (try result) {
   8551         .success => return,
   8552         .invalid_character => |bad_index| {
   8553             return astgen.failOff(
   8554                 token,
   8555                 offset + @intCast(u32, bad_index),
   8556                 "invalid string literal character: '{c}'",
   8557                 .{raw_string[bad_index]},
   8558             );
   8559         },
   8560         .expected_hex_digits => |bad_index| {
   8561             return astgen.failOff(
   8562                 token,
   8563                 offset + @intCast(u32, bad_index),
   8564                 "expected hex digits after '\\x'",
   8565                 .{},
   8566             );
   8567         },
   8568         .invalid_hex_escape => |bad_index| {
   8569             return astgen.failOff(
   8570                 token,
   8571                 offset + @intCast(u32, bad_index),
   8572                 "invalid hex digit: '{c}'",
   8573                 .{raw_string[bad_index]},
   8574             );
   8575         },
   8576         .invalid_unicode_escape => |bad_index| {
   8577             return astgen.failOff(
   8578                 token,
   8579                 offset + @intCast(u32, bad_index),
   8580                 "invalid unicode digit: '{c}'",
   8581                 .{raw_string[bad_index]},
   8582             );
   8583         },
   8584         .missing_matching_rbrace => |bad_index| {
   8585             return astgen.failOff(
   8586                 token,
   8587                 offset + @intCast(u32, bad_index),
   8588                 "missing matching '}}' character",
   8589                 .{},
   8590             );
   8591         },
   8592         .expected_unicode_digits => |bad_index| {
   8593             return astgen.failOff(
   8594                 token,
   8595                 offset + @intCast(u32, bad_index),
   8596                 "expected unicode digits after '\\u'",
   8597                 .{},
   8598             );
   8599         },
   8600     }
   8601 }
   8602 
   8603 fn failNode(
   8604     astgen: *AstGen,
   8605     node: ast.Node.Index,
   8606     comptime format: []const u8,
   8607     args: anytype,
   8608 ) InnerError {
   8609     return astgen.failNodeNotes(node, format, args, &[0]u32{});
   8610 }
   8611 
   8612 fn failNodeNotes(
   8613     astgen: *AstGen,
   8614     node: ast.Node.Index,
   8615     comptime format: []const u8,
   8616     args: anytype,
   8617     notes: []const u32,
   8618 ) InnerError {
   8619     @setCold(true);
   8620     const string_bytes = &astgen.string_bytes;
   8621     const msg = @intCast(u32, string_bytes.items.len);
   8622     {
   8623         var managed = string_bytes.toManaged(astgen.gpa);
   8624         defer string_bytes.* = managed.toUnmanaged();
   8625         try managed.writer().print(format ++ "\x00", args);
   8626     }
   8627     const notes_index: u32 = if (notes.len != 0) blk: {
   8628         const notes_start = astgen.extra.items.len;
   8629         try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len);
   8630         astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));
   8631         astgen.extra.appendSliceAssumeCapacity(notes);
   8632         break :blk @intCast(u32, notes_start);
   8633     } else 0;
   8634     try astgen.compile_errors.append(astgen.gpa, .{
   8635         .msg = msg,
   8636         .node = node,
   8637         .token = 0,
   8638         .byte_offset = 0,
   8639         .notes = notes_index,
   8640     });
   8641     return error.AnalysisFail;
   8642 }
   8643 
   8644 fn failTok(
   8645     astgen: *AstGen,
   8646     token: ast.TokenIndex,
   8647     comptime format: []const u8,
   8648     args: anytype,
   8649 ) InnerError {
   8650     return astgen.failTokNotes(token, format, args, &[0]u32{});
   8651 }
   8652 
   8653 fn failTokNotes(
   8654     astgen: *AstGen,
   8655     token: ast.TokenIndex,
   8656     comptime format: []const u8,
   8657     args: anytype,
   8658     notes: []const u32,
   8659 ) InnerError {
   8660     @setCold(true);
   8661     const string_bytes = &astgen.string_bytes;
   8662     const msg = @intCast(u32, string_bytes.items.len);
   8663     {
   8664         var managed = string_bytes.toManaged(astgen.gpa);
   8665         defer string_bytes.* = managed.toUnmanaged();
   8666         try managed.writer().print(format ++ "\x00", args);
   8667     }
   8668     const notes_index: u32 = if (notes.len != 0) blk: {
   8669         const notes_start = astgen.extra.items.len;
   8670         try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len);
   8671         astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));
   8672         astgen.extra.appendSliceAssumeCapacity(notes);
   8673         break :blk @intCast(u32, notes_start);
   8674     } else 0;
   8675     try astgen.compile_errors.append(astgen.gpa, .{
   8676         .msg = msg,
   8677         .node = 0,
   8678         .token = token,
   8679         .byte_offset = 0,
   8680         .notes = notes_index,
   8681     });
   8682     return error.AnalysisFail;
   8683 }
   8684 
   8685 /// Same as `fail`, except given an absolute byte offset.
   8686 fn failOff(
   8687     astgen: *AstGen,
   8688     token: ast.TokenIndex,
   8689     byte_offset: u32,
   8690     comptime format: []const u8,
   8691     args: anytype,
   8692 ) InnerError {
   8693     @setCold(true);
   8694     const string_bytes = &astgen.string_bytes;
   8695     const msg = @intCast(u32, string_bytes.items.len);
   8696     {
   8697         var managed = string_bytes.toManaged(astgen.gpa);
   8698         defer string_bytes.* = managed.toUnmanaged();
   8699         try managed.writer().print(format ++ "\x00", args);
   8700     }
   8701     try astgen.compile_errors.append(astgen.gpa, .{
   8702         .msg = msg,
   8703         .node = 0,
   8704         .token = token,
   8705         .byte_offset = byte_offset,
   8706         .notes = 0,
   8707     });
   8708     return error.AnalysisFail;
   8709 }
   8710 
   8711 fn errNoteTok(
   8712     astgen: *AstGen,
   8713     token: ast.TokenIndex,
   8714     comptime format: []const u8,
   8715     args: anytype,
   8716 ) Allocator.Error!u32 {
   8717     @setCold(true);
   8718     const string_bytes = &astgen.string_bytes;
   8719     const msg = @intCast(u32, string_bytes.items.len);
   8720     {
   8721         var managed = string_bytes.toManaged(astgen.gpa);
   8722         defer string_bytes.* = managed.toUnmanaged();
   8723         try managed.writer().print(format ++ "\x00", args);
   8724     }
   8725     return astgen.addExtra(Zir.Inst.CompileErrors.Item{
   8726         .msg = msg,
   8727         .node = 0,
   8728         .token = token,
   8729         .byte_offset = 0,
   8730         .notes = 0,
   8731     });
   8732 }
   8733 
   8734 fn errNoteNode(
   8735     astgen: *AstGen,
   8736     node: ast.Node.Index,
   8737     comptime format: []const u8,
   8738     args: anytype,
   8739 ) Allocator.Error!u32 {
   8740     @setCold(true);
   8741     const string_bytes = &astgen.string_bytes;
   8742     const msg = @intCast(u32, string_bytes.items.len);
   8743     {
   8744         var managed = string_bytes.toManaged(astgen.gpa);
   8745         defer string_bytes.* = managed.toUnmanaged();
   8746         try managed.writer().print(format ++ "\x00", args);
   8747     }
   8748     return astgen.addExtra(Zir.Inst.CompileErrors.Item{
   8749         .msg = msg,
   8750         .node = node,
   8751         .token = 0,
   8752         .byte_offset = 0,
   8753         .notes = 0,
   8754     });
   8755 }
   8756 
   8757 fn identAsString(astgen: *AstGen, ident_token: ast.TokenIndex) !u32 {
   8758     const gpa = astgen.gpa;
   8759     const string_bytes = &astgen.string_bytes;
   8760     const str_index = @intCast(u32, string_bytes.items.len);
   8761     try astgen.appendIdentStr(ident_token, string_bytes);
   8762     const key = string_bytes.items[str_index..];
   8763     const gop = try astgen.string_table.getOrPut(gpa, key);
   8764     if (gop.found_existing) {
   8765         string_bytes.shrinkRetainingCapacity(str_index);
   8766         return gop.value_ptr.*;
   8767     } else {
   8768         // We have to dupe the key into the arena, otherwise the memory
   8769         // becomes invalidated when string_bytes gets data appended.
   8770         // TODO https://github.com/ziglang/zig/issues/8528
   8771         gop.key_ptr.* = try astgen.arena.dupe(u8, key);
   8772         gop.value_ptr.* = str_index;
   8773         try string_bytes.append(gpa, 0);
   8774         return str_index;
   8775     }
   8776 }
   8777 
   8778 const IndexSlice = struct { index: u32, len: u32 };
   8779 
   8780 fn strLitAsString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !IndexSlice {
   8781     const gpa = astgen.gpa;
   8782     const string_bytes = &astgen.string_bytes;
   8783     const str_index = @intCast(u32, string_bytes.items.len);
   8784     const token_bytes = astgen.tree.tokenSlice(str_lit_token);
   8785     try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0);
   8786     const key = string_bytes.items[str_index..];
   8787     const gop = try astgen.string_table.getOrPut(gpa, key);
   8788     if (gop.found_existing) {
   8789         string_bytes.shrinkRetainingCapacity(str_index);
   8790         return IndexSlice{
   8791             .index = gop.value_ptr.*,
   8792             .len = @intCast(u32, key.len),
   8793         };
   8794     } else {
   8795         // We have to dupe the key into the arena, otherwise the memory
   8796         // becomes invalidated when string_bytes gets data appended.
   8797         // TODO https://github.com/ziglang/zig/issues/8528
   8798         gop.key_ptr.* = try astgen.arena.dupe(u8, key);
   8799         gop.value_ptr.* = str_index;
   8800         // Still need a null byte because we are using the same table
   8801         // to lookup null terminated strings, so if we get a match, it has to
   8802         // be null terminated for that to work.
   8803         try string_bytes.append(gpa, 0);
   8804         return IndexSlice{
   8805             .index = str_index,
   8806             .len = @intCast(u32, key.len),
   8807         };
   8808     }
   8809 }
   8810 
   8811 fn strLitNodeAsString(astgen: *AstGen, node: ast.Node.Index) !IndexSlice {
   8812     const tree = astgen.tree;
   8813     const node_datas = tree.nodes.items(.data);
   8814 
   8815     const start = node_datas[node].lhs;
   8816     const end = node_datas[node].rhs;
   8817 
   8818     const gpa = astgen.gpa;
   8819     const string_bytes = &astgen.string_bytes;
   8820     const str_index = string_bytes.items.len;
   8821 
   8822     // First line: do not append a newline.
   8823     var tok_i = start;
   8824     {
   8825         const slice = tree.tokenSlice(tok_i);
   8826         const line_bytes = slice[2 .. slice.len - 1];
   8827         try string_bytes.appendSlice(gpa, line_bytes);
   8828         tok_i += 1;
   8829     }
   8830     // Following lines: each line prepends a newline.
   8831     while (tok_i <= end) : (tok_i += 1) {
   8832         const slice = tree.tokenSlice(tok_i);
   8833         const line_bytes = slice[2 .. slice.len - 1];
   8834         try string_bytes.ensureUnusedCapacity(gpa, line_bytes.len + 1);
   8835         string_bytes.appendAssumeCapacity('\n');
   8836         string_bytes.appendSliceAssumeCapacity(line_bytes);
   8837     }
   8838     const len = string_bytes.items.len - str_index;
   8839     try string_bytes.append(gpa, 0);
   8840     return IndexSlice{
   8841         .index = @intCast(u32, str_index),
   8842         .len = @intCast(u32, len),
   8843     };
   8844 }
   8845 
   8846 fn testNameString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !u32 {
   8847     const gpa = astgen.gpa;
   8848     const string_bytes = &astgen.string_bytes;
   8849     const str_index = @intCast(u32, string_bytes.items.len);
   8850     const token_bytes = astgen.tree.tokenSlice(str_lit_token);
   8851     try string_bytes.append(gpa, 0); // Indicates this is a test.
   8852     try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0);
   8853     try string_bytes.append(gpa, 0);
   8854     return str_index;
   8855 }
   8856 
   8857 const Scope = struct {
   8858     tag: Tag,
   8859 
   8860     fn cast(base: *Scope, comptime T: type) ?*T {
   8861         if (T == Defer) {
   8862             switch (base.tag) {
   8863                 .defer_normal, .defer_error => return @fieldParentPtr(T, "base", base),
   8864                 else => return null,
   8865             }
   8866         }
   8867         if (base.tag != T.base_tag)
   8868             return null;
   8869 
   8870         return @fieldParentPtr(T, "base", base);
   8871     }
   8872 
   8873     const Tag = enum {
   8874         gen_zir,
   8875         local_val,
   8876         local_ptr,
   8877         defer_normal,
   8878         defer_error,
   8879         namespace,
   8880         top,
   8881     };
   8882 
   8883     /// The category of identifier. These tag names are user-visible in compile errors.
   8884     const IdCat = enum {
   8885         @"function parameter",
   8886         @"local constant",
   8887         @"local variable",
   8888         @"loop index capture",
   8889         @"capture",
   8890     };
   8891 
   8892     /// This is always a `const` local and importantly the `inst` is a value type, not a pointer.
   8893     /// This structure lives as long as the AST generation of the Block
   8894     /// node that contains the variable.
   8895     const LocalVal = struct {
   8896         const base_tag: Tag = .local_val;
   8897         base: Scope = Scope{ .tag = base_tag },
   8898         /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.
   8899         parent: *Scope,
   8900         gen_zir: *GenZir,
   8901         inst: Zir.Inst.Ref,
   8902         /// Source location of the corresponding variable declaration.
   8903         token_src: ast.TokenIndex,
   8904         /// String table index.
   8905         name: u32,
   8906         id_cat: IdCat,
   8907         /// Track whether the name has been referenced.
   8908         used: bool = false,
   8909     };
   8910 
   8911     /// This could be a `const` or `var` local. It has a pointer instead of a value.
   8912     /// This structure lives as long as the AST generation of the Block
   8913     /// node that contains the variable.
   8914     const LocalPtr = struct {
   8915         const base_tag: Tag = .local_ptr;
   8916         base: Scope = Scope{ .tag = base_tag },
   8917         /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.
   8918         parent: *Scope,
   8919         gen_zir: *GenZir,
   8920         ptr: Zir.Inst.Ref,
   8921         /// Source location of the corresponding variable declaration.
   8922         token_src: ast.TokenIndex,
   8923         /// String table index.
   8924         name: u32,
   8925         id_cat: IdCat,
   8926         /// true means we find out during Sema whether the value is comptime.
   8927         /// false means it is already known at AstGen the value is runtime-known.
   8928         maybe_comptime: bool,
   8929         /// Track whether the name has been referenced.
   8930         used: bool = false,
   8931     };
   8932 
   8933     const Defer = struct {
   8934         base: Scope,
   8935         /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.
   8936         parent: *Scope,
   8937         defer_node: ast.Node.Index,
   8938     };
   8939 
   8940     /// Represents a global scope that has any number of declarations in it.
   8941     /// Each declaration has this as the parent scope.
   8942     const Namespace = struct {
   8943         const base_tag: Tag = .namespace;
   8944         base: Scope = Scope{ .tag = base_tag },
   8945 
   8946         parent: *Scope,
   8947         /// Maps string table index to the source location of declaration,
   8948         /// for the purposes of reporting name shadowing compile errors.
   8949         decls: std.AutoHashMapUnmanaged(u32, ast.Node.Index) = .{},
   8950         node: ast.Node.Index,
   8951     };
   8952 
   8953     const Top = struct {
   8954         const base_tag: Scope.Tag = .top;
   8955         base: Scope = Scope{ .tag = base_tag },
   8956     };
   8957 };
   8958 
   8959 /// This is a temporary structure; references to it are valid only
   8960 /// while constructing a `Zir`.
   8961 const GenZir = struct {
   8962     const base_tag: Scope.Tag = .gen_zir;
   8963     base: Scope = Scope{ .tag = base_tag },
   8964     force_comptime: bool,
   8965     in_defer: bool,
   8966     /// How decls created in this scope should be named.
   8967     anon_name_strategy: Zir.Inst.NameStrategy = .anon,
   8968     /// The containing decl AST node.
   8969     decl_node_index: ast.Node.Index,
   8970     /// The containing decl line index, absolute.
   8971     decl_line: u32,
   8972     parent: *Scope,
   8973     /// All `GenZir` scopes for the same ZIR share this.
   8974     astgen: *AstGen,
   8975     /// Keeps track of the list of instructions in this scope only. Indexes
   8976     /// to instructions in `astgen`.
   8977     instructions: ArrayListUnmanaged(Zir.Inst.Index) = .{},
   8978     label: ?Label = null,
   8979     break_block: Zir.Inst.Index = 0,
   8980     continue_block: Zir.Inst.Index = 0,
   8981     /// Only valid when setBreakResultLoc is called.
   8982     break_result_loc: AstGen.ResultLoc = undefined,
   8983     /// When a block has a pointer result location, here it is.
   8984     rl_ptr: Zir.Inst.Ref = .none,
   8985     /// When a block has a type result location, here it is.
   8986     rl_ty_inst: Zir.Inst.Ref = .none,
   8987     /// Keeps track of how many branches of a block did not actually
   8988     /// consume the result location. astgen uses this to figure out
   8989     /// whether to rely on break instructions or writing to the result
   8990     /// pointer for the result instruction.
   8991     rvalue_rl_count: usize = 0,
   8992     /// Keeps track of how many break instructions there are. When astgen is finished
   8993     /// with a block, it can check this against rvalue_rl_count to find out whether
   8994     /// the break instructions should be downgraded to break_void.
   8995     break_count: usize = 0,
   8996     /// Tracks `break :foo bar` instructions so they can possibly be elided later if
   8997     /// the labeled block ends up not needing a result location pointer.
   8998     labeled_breaks: ArrayListUnmanaged(Zir.Inst.Index) = .{},
   8999     /// Tracks `store_to_block_ptr` instructions that correspond to break instructions
   9000     /// so they can possibly be elided later if the labeled block ends up not needing
   9001     /// a result location pointer.
   9002     labeled_store_to_block_ptr_list: ArrayListUnmanaged(Zir.Inst.Index) = .{},
   9003 
   9004     suspend_node: ast.Node.Index = 0,
   9005     nosuspend_node: ast.Node.Index = 0,
   9006 
   9007     fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir {
   9008         return .{
   9009             .force_comptime = gz.force_comptime,
   9010             .in_defer = gz.in_defer,
   9011             .decl_node_index = gz.decl_node_index,
   9012             .decl_line = gz.decl_line,
   9013             .parent = scope,
   9014             .astgen = gz.astgen,
   9015             .suspend_node = gz.suspend_node,
   9016             .nosuspend_node = gz.nosuspend_node,
   9017         };
   9018     }
   9019 
   9020     const Label = struct {
   9021         token: ast.TokenIndex,
   9022         block_inst: Zir.Inst.Index,
   9023         used: bool = false,
   9024     };
   9025 
   9026     fn endsWithNoReturn(gz: GenZir) bool {
   9027         const tags = gz.astgen.instructions.items(.tag);
   9028         if (gz.instructions.items.len == 0) return false;
   9029         const last_inst = gz.instructions.items[gz.instructions.items.len - 1];
   9030         return tags[last_inst].isNoReturn();
   9031     }
   9032 
   9033     /// TODO all uses of this should be replaced with uses of `endsWithNoReturn`.
   9034     fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool {
   9035         if (inst_ref == .unreachable_value) return true;
   9036         if (refToIndex(inst_ref)) |inst_index| {
   9037             return gz.astgen.instructions.items(.tag)[inst_index].isNoReturn();
   9038         }
   9039         return false;
   9040     }
   9041 
   9042     fn calcLine(gz: GenZir, node: ast.Node.Index) u32 {
   9043         const astgen = gz.astgen;
   9044         const tree = astgen.tree;
   9045         const source = tree.source;
   9046         const token_starts = tree.tokens.items(.start);
   9047         const node_start = token_starts[tree.firstToken(node)];
   9048 
   9049         astgen.advanceSourceCursor(source, node_start);
   9050 
   9051         return @intCast(u32, gz.decl_line + astgen.source_line);
   9052     }
   9053 
   9054     fn tokSrcLoc(gz: GenZir, token_index: ast.TokenIndex) LazySrcLoc {
   9055         return .{ .token_offset = token_index - gz.srcToken() };
   9056     }
   9057 
   9058     fn nodeSrcLoc(gz: GenZir, node_index: ast.Node.Index) LazySrcLoc {
   9059         return .{ .node_offset = gz.nodeIndexToRelative(node_index) };
   9060     }
   9061 
   9062     fn nodeIndexToRelative(gz: GenZir, node_index: ast.Node.Index) i32 {
   9063         return @bitCast(i32, node_index) - @bitCast(i32, gz.decl_node_index);
   9064     }
   9065 
   9066     fn tokenIndexToRelative(gz: GenZir, token: ast.TokenIndex) u32 {
   9067         return token - gz.srcToken();
   9068     }
   9069 
   9070     fn srcToken(gz: GenZir) ast.TokenIndex {
   9071         return gz.astgen.tree.firstToken(gz.decl_node_index);
   9072     }
   9073 
   9074     fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void {
   9075         // Depending on whether the result location is a pointer or value, different
   9076         // ZIR needs to be generated. In the former case we rely on storing to the
   9077         // pointer to communicate the result, and use breakvoid; in the latter case
   9078         // the block break instructions will have the result values.
   9079         // One more complication: when the result location is a pointer, we detect
   9080         // the scenario where the result location is not consumed. In this case
   9081         // we emit ZIR for the block break instructions to have the result values,
   9082         // and then rvalue() on that to pass the value to the result location.
   9083         switch (parent_rl) {
   9084             .ty, .coerced_ty => |ty_inst| {
   9085                 gz.rl_ty_inst = ty_inst;
   9086                 gz.break_result_loc = parent_rl;
   9087             },
   9088             .none_or_ref => {
   9089                 gz.break_result_loc = .ref;
   9090             },
   9091             .discard, .none, .ptr, .ref => {
   9092                 gz.break_result_loc = parent_rl;
   9093             },
   9094 
   9095             .inferred_ptr => |ptr| {
   9096                 gz.rl_ptr = ptr;
   9097                 gz.break_result_loc = .{ .block_ptr = gz };
   9098             },
   9099 
   9100             .block_ptr => |parent_block_scope| {
   9101                 gz.rl_ty_inst = parent_block_scope.rl_ty_inst;
   9102                 gz.rl_ptr = parent_block_scope.rl_ptr;
   9103                 gz.break_result_loc = .{ .block_ptr = gz };
   9104             },
   9105         }
   9106     }
   9107 
   9108     fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void {
   9109         const gpa = gz.astgen.gpa;
   9110         try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len +
   9111             gz.instructions.items.len);
   9112         const zir_datas = gz.astgen.instructions.items(.data);
   9113         zir_datas[inst].bool_br.payload_index = gz.astgen.addExtraAssumeCapacity(
   9114             Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) },
   9115         );
   9116         gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items);
   9117     }
   9118 
   9119     fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void {
   9120         const gpa = gz.astgen.gpa;
   9121         try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len +
   9122             gz.instructions.items.len);
   9123         const zir_datas = gz.astgen.instructions.items(.data);
   9124         zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity(
   9125             Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) },
   9126         );
   9127         gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items);
   9128     }
   9129 
   9130     /// Same as `setBlockBody` except we don't copy instructions which are
   9131     /// `store_to_block_ptr` instructions with lhs set to .none.
   9132     fn setBlockBodyEliding(gz: GenZir, inst: Zir.Inst.Index) !void {
   9133         const gpa = gz.astgen.gpa;
   9134         try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len +
   9135             gz.instructions.items.len);
   9136         const zir_datas = gz.astgen.instructions.items(.data);
   9137         const zir_tags = gz.astgen.instructions.items(.tag);
   9138         const block_pl_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Block{
   9139             .body_len = @intCast(u32, gz.instructions.items.len),
   9140         });
   9141         zir_datas[inst].pl_node.payload_index = block_pl_index;
   9142         for (gz.instructions.items) |sub_inst| {
   9143             if (zir_tags[sub_inst] == .store_to_block_ptr and
   9144                 zir_datas[sub_inst].bin.lhs == .none)
   9145             {
   9146                 // Decrement `body_len`.
   9147                 gz.astgen.extra.items[block_pl_index] -= 1;
   9148                 continue;
   9149             }
   9150             gz.astgen.extra.appendAssumeCapacity(sub_inst);
   9151         }
   9152     }
   9153 
   9154     fn addFunc(gz: *GenZir, args: struct {
   9155         src_node: ast.Node.Index,
   9156         body: []const Zir.Inst.Index,
   9157         param_block: Zir.Inst.Index,
   9158         ret_ty: []const Zir.Inst.Index,
   9159         ret_br: Zir.Inst.Index,
   9160         cc: Zir.Inst.Ref,
   9161         align_inst: Zir.Inst.Ref,
   9162         lib_name: u32,
   9163         is_var_args: bool,
   9164         is_inferred_error: bool,
   9165         is_test: bool,
   9166         is_extern: bool,
   9167     }) !Zir.Inst.Ref {
   9168         assert(args.src_node != 0);
   9169         const astgen = gz.astgen;
   9170         const gpa = astgen.gpa;
   9171 
   9172         try gz.instructions.ensureUnusedCapacity(gpa, 1);
   9173         try astgen.instructions.ensureUnusedCapacity(gpa, 1);
   9174 
   9175         var src_locs_buffer: [3]u32 = undefined;
   9176         var src_locs: []u32 = src_locs_buffer[0..0];
   9177         if (args.body.len != 0) {
   9178             const tree = astgen.tree;
   9179             const node_tags = tree.nodes.items(.tag);
   9180             const node_datas = tree.nodes.items(.data);
   9181             const token_starts = tree.tokens.items(.start);
   9182             const fn_decl = args.src_node;
   9183             assert(node_tags[fn_decl] == .fn_decl or node_tags[fn_decl] == .test_decl);
   9184             const block = node_datas[fn_decl].rhs;
   9185             const lbrace_start = token_starts[tree.firstToken(block)];
   9186             const rbrace_start = token_starts[tree.lastToken(block)];
   9187 
   9188             astgen.advanceSourceCursor(tree.source, lbrace_start);
   9189             const lbrace_line = @intCast(u32, astgen.source_line);
   9190             const lbrace_column = @intCast(u32, astgen.source_column);
   9191 
   9192             astgen.advanceSourceCursor(tree.source, rbrace_start);
   9193             const rbrace_line = @intCast(u32, astgen.source_line);
   9194             const rbrace_column = @intCast(u32, astgen.source_column);
   9195 
   9196             const columns = lbrace_column | (rbrace_column << 16);
   9197             src_locs_buffer[0] = lbrace_line;
   9198             src_locs_buffer[1] = rbrace_line;
   9199             src_locs_buffer[2] = columns;
   9200             src_locs = &src_locs_buffer;
   9201         }
   9202 
   9203         if (args.cc != .none or args.lib_name != 0 or
   9204             args.is_var_args or args.is_test or args.align_inst != .none or
   9205             args.is_extern)
   9206         {
   9207             try astgen.extra.ensureUnusedCapacity(
   9208                 gpa,
   9209                 @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +
   9210                     args.ret_ty.len + args.body.len + src_locs.len +
   9211                     @boolToInt(args.lib_name != 0) +
   9212                     @boolToInt(args.align_inst != .none) +
   9213                     @boolToInt(args.cc != .none),
   9214             );
   9215             const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{
   9216                 .src_node = gz.nodeIndexToRelative(args.src_node),
   9217                 .param_block = args.param_block,
   9218                 .ret_body_len = @intCast(u32, args.ret_ty.len),
   9219                 .body_len = @intCast(u32, args.body.len),
   9220             });
   9221             if (args.lib_name != 0) {
   9222                 astgen.extra.appendAssumeCapacity(args.lib_name);
   9223             }
   9224             if (args.cc != .none) {
   9225                 astgen.extra.appendAssumeCapacity(@enumToInt(args.cc));
   9226             }
   9227             if (args.align_inst != .none) {
   9228                 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
   9229             }
   9230             astgen.extra.appendSliceAssumeCapacity(args.ret_ty);
   9231             astgen.extra.appendSliceAssumeCapacity(args.body);
   9232             astgen.extra.appendSliceAssumeCapacity(src_locs);
   9233 
   9234             const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
   9235             if (args.ret_br != 0) {
   9236                 astgen.instructions.items(.data)[args.ret_br].@"break".block_inst = new_index;
   9237             }
   9238             astgen.instructions.appendAssumeCapacity(.{
   9239                 .tag = .extended,
   9240                 .data = .{ .extended = .{
   9241                     .opcode = .func,
   9242                     .small = @bitCast(u16, Zir.Inst.ExtendedFunc.Small{
   9243                         .is_var_args = args.is_var_args,
   9244                         .is_inferred_error = args.is_inferred_error,
   9245                         .has_lib_name = args.lib_name != 0,
   9246                         .has_cc = args.cc != .none,
   9247                         .has_align = args.align_inst != .none,
   9248                         .is_test = args.is_test,
   9249                         .is_extern = args.is_extern,
   9250                     }),
   9251                     .operand = payload_index,
   9252                 } },
   9253             });
   9254             gz.instructions.appendAssumeCapacity(new_index);
   9255             return indexToRef(new_index);
   9256         } else {
   9257             try astgen.extra.ensureUnusedCapacity(
   9258                 gpa,
   9259                 @typeInfo(Zir.Inst.Func).Struct.fields.len +
   9260                     args.ret_ty.len + args.body.len + src_locs.len,
   9261             );
   9262 
   9263             const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{
   9264                 .param_block = args.param_block,
   9265                 .ret_body_len = @intCast(u32, args.ret_ty.len),
   9266                 .body_len = @intCast(u32, args.body.len),
   9267             });
   9268             astgen.extra.appendSliceAssumeCapacity(args.ret_ty);
   9269             astgen.extra.appendSliceAssumeCapacity(args.body);
   9270             astgen.extra.appendSliceAssumeCapacity(src_locs);
   9271 
   9272             const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func;
   9273             const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
   9274             if (args.ret_br != 0) {
   9275                 astgen.instructions.items(.data)[args.ret_br].@"break".block_inst = new_index;
   9276             }
   9277             astgen.instructions.appendAssumeCapacity(.{
   9278                 .tag = tag,
   9279                 .data = .{ .pl_node = .{
   9280                     .src_node = gz.nodeIndexToRelative(args.src_node),
   9281                     .payload_index = payload_index,
   9282                 } },
   9283             });
   9284             gz.instructions.appendAssumeCapacity(new_index);
   9285             return indexToRef(new_index);
   9286         }
   9287     }
   9288 
   9289     fn addVar(gz: *GenZir, args: struct {
   9290         align_inst: Zir.Inst.Ref,
   9291         lib_name: u32,
   9292         var_type: Zir.Inst.Ref,
   9293         init: Zir.Inst.Ref,
   9294         is_extern: bool,
   9295         is_threadlocal: bool,
   9296     }) !Zir.Inst.Ref {
   9297         const astgen = gz.astgen;
   9298         const gpa = astgen.gpa;
   9299 
   9300         try gz.instructions.ensureUnusedCapacity(gpa, 1);
   9301         try astgen.instructions.ensureUnusedCapacity(gpa, 1);
   9302 
   9303         try astgen.extra.ensureUnusedCapacity(
   9304             gpa,
   9305             @typeInfo(Zir.Inst.ExtendedVar).Struct.fields.len +
   9306                 @boolToInt(args.lib_name != 0) +
   9307                 @boolToInt(args.align_inst != .none) +
   9308                 @boolToInt(args.init != .none),
   9309         );
   9310         const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedVar{
   9311             .var_type = args.var_type,
   9312         });
   9313         if (args.lib_name != 0) {
   9314             astgen.extra.appendAssumeCapacity(args.lib_name);
   9315         }
   9316         if (args.align_inst != .none) {
   9317             astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
   9318         }
   9319         if (args.init != .none) {
   9320             astgen.extra.appendAssumeCapacity(@enumToInt(args.init));
   9321         }
   9322 
   9323         const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
   9324         astgen.instructions.appendAssumeCapacity(.{
   9325             .tag = .extended,
   9326             .data = .{ .extended = .{
   9327                 .opcode = .variable,
   9328                 .small = @bitCast(u16, Zir.Inst.ExtendedVar.Small{
   9329                     .has_lib_name = args.lib_name != 0,
   9330                     .has_align = args.align_inst != .none,
   9331                     .has_init = args.init != .none,
   9332                     .is_extern = args.is_extern,
   9333                     .is_threadlocal = args.is_threadlocal,
   9334                 }),
   9335                 .operand = payload_index,
   9336             } },
   9337         });
   9338         gz.instructions.appendAssumeCapacity(new_index);
   9339         return indexToRef(new_index);
   9340     }
   9341 
   9342     fn addCall(
   9343         gz: *GenZir,
   9344         tag: Zir.Inst.Tag,
   9345         callee: Zir.Inst.Ref,
   9346         args: []const Zir.Inst.Ref,
   9347         /// Absolute node index. This function does the conversion to offset from Decl.
   9348         src_node: ast.Node.Index,
   9349     ) !Zir.Inst.Ref {
   9350         assert(callee != .none);
   9351         assert(src_node != 0);
   9352         const gpa = gz.astgen.gpa;
   9353         try gz.instructions.ensureUnusedCapacity(gpa, 1);
   9354         try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
   9355         try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Call).Struct.fields.len +
   9356             args.len);
   9357 
   9358         const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Call{
   9359             .callee = callee,
   9360             .args_len = @intCast(u32, args.len),
   9361         });
   9362         gz.astgen.appendRefsAssumeCapacity(args);
   9363 
   9364         const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
   9365         gz.astgen.instructions.appendAssumeCapacity(.{
   9366             .tag = tag,
   9367             .data = .{ .pl_node = .{
   9368                 .src_node = gz.nodeIndexToRelative(src_node),
   9369                 .payload_index = payload_index,
   9370             } },
   9371         });
   9372         gz.instructions.appendAssumeCapacity(new_index);
   9373         return indexToRef(new_index);
   9374     }
   9375 
   9376     /// Note that this returns a `Zir.Inst.Index` not a ref.
   9377     /// Leaves the `payload_index` field undefined.
   9378     fn addBoolBr(
   9379         gz: *GenZir,
   9380         tag: Zir.Inst.Tag,
   9381         lhs: Zir.Inst.Ref,
   9382     ) !Zir.Inst.Index {
   9383         assert(lhs != .none);
   9384         const gpa = gz.astgen.gpa;
   9385         try gz.instructions.ensureUnusedCapacity(gpa, 1);
   9386         try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
   9387 
   9388         const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
   9389         gz.astgen.instructions.appendAssumeCapacity(.{
   9390             .tag = tag,
   9391             .data = .{ .bool_br = .{
   9392                 .lhs = lhs,
   9393                 .payload_index = undefined,
   9394             } },
   9395         });
   9396         gz.instructions.appendAssumeCapacity(new_index);
   9397         return new_index;
   9398     }
   9399 
   9400     fn addInt(gz: *GenZir, integer: u64) !Zir.Inst.Ref {
   9401         return gz.add(.{
   9402             .tag = .int,
   9403             .data = .{ .int = integer },
   9404         });
   9405     }
   9406 
   9407     fn addIntBig(gz: *GenZir, limbs: []const std.math.big.Limb) !Zir.Inst.Ref {
   9408         const astgen = gz.astgen;
   9409         const gpa = astgen.gpa;
   9410         try gz.instructions.ensureUnusedCapacity(gpa, 1);
   9411         try astgen.instructions.ensureUnusedCapacity(gpa, 1);
   9412         try astgen.string_bytes.ensureUnusedCapacity(gpa, @sizeOf(std.math.big.Limb) * limbs.len);
   9413 
   9414         const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
   9415         astgen.instructions.appendAssumeCapacity(.{
   9416             .tag = .int_big,
   9417             .data = .{ .str = .{
   9418                 .start = @intCast(u32, astgen.string_bytes.items.len),
   9419                 .len = @intCast(u32, limbs.len),
   9420             } },
   9421         });
   9422         gz.instructions.appendAssumeCapacity(new_index);
   9423         astgen.string_bytes.appendSliceAssumeCapacity(mem.sliceAsBytes(limbs));
   9424         return indexToRef(new_index);
   9425     }
   9426 
   9427     fn addFloat(gz: *GenZir, number: f64) !Zir.Inst.Ref {
   9428         return gz.add(.{
   9429             .tag = .float,
   9430             .data = .{ .float = number },
   9431         });
   9432     }
   9433 
   9434     fn addUnNode(
   9435         gz: *GenZir,
   9436         tag: Zir.Inst.Tag,
   9437         operand: Zir.Inst.Ref,
   9438         /// Absolute node index. This function does the conversion to offset from Decl.
   9439         src_node: ast.Node.Index,
   9440     ) !Zir.Inst.Ref {
   9441         assert(operand != .none);
   9442         return gz.add(.{
   9443             .tag = tag,
   9444             .data = .{ .un_node = .{
   9445                 .operand = operand,
   9446                 .src_node = gz.nodeIndexToRelative(src_node),
   9447             } },
   9448         });
   9449     }
   9450 
   9451     fn addPlNode(
   9452         gz: *GenZir,
   9453         tag: Zir.Inst.Tag,
   9454         /// Absolute node index. This function does the conversion to offset from Decl.
   9455         src_node: ast.Node.Index,
   9456         extra: anytype,
   9457     ) !Zir.Inst.Ref {
   9458         const gpa = gz.astgen.gpa;
   9459         try gz.instructions.ensureUnusedCapacity(gpa, 1);
   9460         try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
   9461 
   9462         const payload_index = try gz.astgen.addExtra(extra);
   9463         const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
   9464         gz.astgen.instructions.appendAssumeCapacity(.{
   9465             .tag = tag,
   9466             .data = .{ .pl_node = .{
   9467                 .src_node = gz.nodeIndexToRelative(src_node),
   9468                 .payload_index = payload_index,
   9469             } },
   9470         });
   9471         gz.instructions.appendAssumeCapacity(new_index);
   9472         return indexToRef(new_index);
   9473     }
   9474 
   9475     fn addParam(
   9476         gz: *GenZir,
   9477         tag: Zir.Inst.Tag,
   9478         /// Absolute token index. This function does the conversion to Decl offset.
   9479         abs_tok_index: ast.TokenIndex,
   9480         name: u32,
   9481         body: []const u32,
   9482     ) !Zir.Inst.Index {
   9483         const gpa = gz.astgen.gpa;
   9484         try gz.instructions.ensureUnusedCapacity(gpa, 1);
   9485         try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
   9486         try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Param).Struct.fields.len +
   9487             body.len);
   9488 
   9489         const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Param{
   9490             .name = name,
   9491             .body_len = @intCast(u32, body.len),
   9492         });
   9493         gz.astgen.extra.appendSliceAssumeCapacity(body);
   9494 
   9495         const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
   9496         gz.astgen.instructions.appendAssumeCapacity(.{
   9497             .tag = tag,
   9498             .data = .{ .pl_tok = .{
   9499                 .src_tok = gz.tokenIndexToRelative(abs_tok_index),
   9500                 .payload_index = payload_index,
   9501             } },
   9502         });
   9503         gz.instructions.appendAssumeCapacity(new_index);
   9504         return new_index;
   9505     }
   9506 
   9507     fn addExtendedPayload(
   9508         gz: *GenZir,
   9509         opcode: Zir.Inst.Extended,
   9510         extra: anytype,
   9511     ) !Zir.Inst.Ref {
   9512         const gpa = gz.astgen.gpa;
   9513 
   9514         try gz.instructions.ensureUnusedCapacity(gpa, 1);
   9515         try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
   9516 
   9517         const payload_index = try gz.astgen.addExtra(extra);
   9518         const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
   9519         gz.astgen.instructions.appendAssumeCapacity(.{
   9520             .tag = .extended,
   9521             .data = .{ .extended = .{
   9522                 .opcode = opcode,
   9523                 .small = undefined,
   9524                 .operand = payload_index,
   9525             } },
   9526         });
   9527         gz.instructions.appendAssumeCapacity(new_index);
   9528         return indexToRef(new_index);
   9529     }
   9530 
   9531     fn addExtendedMultiOp(
   9532         gz: *GenZir,
   9533         opcode: Zir.Inst.Extended,
   9534         node: ast.Node.Index,
   9535         operands: []const Zir.Inst.Ref,
   9536     ) !Zir.Inst.Ref {
   9537         const astgen = gz.astgen;
   9538         const gpa = astgen.gpa;
   9539 
   9540         try gz.instructions.ensureUnusedCapacity(gpa, 1);
   9541         try astgen.instructions.ensureUnusedCapacity(gpa, 1);
   9542         try astgen.extra.ensureUnusedCapacity(
   9543             gpa,
   9544             @typeInfo(Zir.Inst.NodeMultiOp).Struct.fields.len + operands.len,
   9545         );
   9546 
   9547         const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.NodeMultiOp{
   9548             .src_node = gz.nodeIndexToRelative(node),
   9549         });
   9550         const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
   9551         astgen.instructions.appendAssumeCapacity(.{
   9552             .tag = .extended,
   9553             .data = .{ .extended = .{
   9554                 .opcode = opcode,
   9555                 .small = @intCast(u16, operands.len),
   9556                 .operand = payload_index,
   9557             } },
   9558         });
   9559         gz.instructions.appendAssumeCapacity(new_index);
   9560         astgen.appendRefsAssumeCapacity(operands);
   9561         return indexToRef(new_index);
   9562     }
   9563 
   9564     fn addArrayTypeSentinel(
   9565         gz: *GenZir,
   9566         len: Zir.Inst.Ref,
   9567         sentinel: Zir.Inst.Ref,
   9568         elem_type: Zir.Inst.Ref,
   9569     ) !Zir.Inst.Ref {
   9570         const gpa = gz.astgen.gpa;
   9571         try gz.instructions.ensureUnusedCapacity(gpa, 1);
   9572         try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
   9573 
   9574         const payload_index = try gz.astgen.addExtra(Zir.Inst.ArrayTypeSentinel{
   9575             .sentinel = sentinel,
   9576             .elem_type = elem_type,
   9577         });
   9578         const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
   9579         gz.astgen.instructions.appendAssumeCapacity(.{
   9580             .tag = .array_type_sentinel,
   9581             .data = .{ .array_type_sentinel = .{
   9582                 .len = len,
   9583                 .payload_index = payload_index,
   9584             } },
   9585         });
   9586         gz.instructions.appendAssumeCapacity(new_index);
   9587         return indexToRef(new_index);
   9588     }
   9589 
   9590     fn addUnTok(
   9591         gz: *GenZir,
   9592         tag: Zir.Inst.Tag,
   9593         operand: Zir.Inst.Ref,
   9594         /// Absolute token index. This function does the conversion to Decl offset.
   9595         abs_tok_index: ast.TokenIndex,
   9596     ) !Zir.Inst.Ref {
   9597         assert(operand != .none);
   9598         return gz.add(.{
   9599             .tag = tag,
   9600             .data = .{ .un_tok = .{
   9601                 .operand = operand,
   9602                 .src_tok = gz.tokenIndexToRelative(abs_tok_index),
   9603             } },
   9604         });
   9605     }
   9606 
   9607     fn addStrTok(
   9608         gz: *GenZir,
   9609         tag: Zir.Inst.Tag,
   9610         str_index: u32,
   9611         /// Absolute token index. This function does the conversion to Decl offset.
   9612         abs_tok_index: ast.TokenIndex,
   9613     ) !Zir.Inst.Ref {
   9614         return gz.add(.{
   9615             .tag = tag,
   9616             .data = .{ .str_tok = .{
   9617                 .start = str_index,
   9618                 .src_tok = gz.tokenIndexToRelative(abs_tok_index),
   9619             } },
   9620         });
   9621     }
   9622 
   9623     fn addBreak(
   9624         gz: *GenZir,
   9625         tag: Zir.Inst.Tag,
   9626         break_block: Zir.Inst.Index,
   9627         operand: Zir.Inst.Ref,
   9628     ) !Zir.Inst.Index {
   9629         return gz.addAsIndex(.{
   9630             .tag = tag,
   9631             .data = .{ .@"break" = .{
   9632                 .block_inst = break_block,
   9633                 .operand = operand,
   9634             } },
   9635         });
   9636     }
   9637 
   9638     fn addBin(
   9639         gz: *GenZir,
   9640         tag: Zir.Inst.Tag,
   9641         lhs: Zir.Inst.Ref,
   9642         rhs: Zir.Inst.Ref,
   9643     ) !Zir.Inst.Ref {
   9644         assert(lhs != .none);
   9645         assert(rhs != .none);
   9646         return gz.add(.{
   9647             .tag = tag,
   9648             .data = .{ .bin = .{
   9649                 .lhs = lhs,
   9650                 .rhs = rhs,
   9651             } },
   9652         });
   9653     }
   9654 
   9655     fn addDecl(
   9656         gz: *GenZir,
   9657         tag: Zir.Inst.Tag,
   9658         decl_index: u32,
   9659         src_node: ast.Node.Index,
   9660     ) !Zir.Inst.Ref {
   9661         return gz.add(.{
   9662             .tag = tag,
   9663             .data = .{ .pl_node = .{
   9664                 .src_node = gz.nodeIndexToRelative(src_node),
   9665                 .payload_index = decl_index,
   9666             } },
   9667         });
   9668     }
   9669 
   9670     fn addNode(
   9671         gz: *GenZir,
   9672         tag: Zir.Inst.Tag,
   9673         /// Absolute node index. This function does the conversion to offset from Decl.
   9674         src_node: ast.Node.Index,
   9675     ) !Zir.Inst.Ref {
   9676         return gz.add(.{
   9677             .tag = tag,
   9678             .data = .{ .node = gz.nodeIndexToRelative(src_node) },
   9679         });
   9680     }
   9681 
   9682     fn addNodeExtended(
   9683         gz: *GenZir,
   9684         opcode: Zir.Inst.Extended,
   9685         /// Absolute node index. This function does the conversion to offset from Decl.
   9686         src_node: ast.Node.Index,
   9687     ) !Zir.Inst.Ref {
   9688         return gz.add(.{
   9689             .tag = .extended,
   9690             .data = .{ .extended = .{
   9691                 .opcode = opcode,
   9692                 .small = undefined,
   9693                 .operand = @bitCast(u32, gz.nodeIndexToRelative(src_node)),
   9694             } },
   9695         });
   9696     }
   9697 
   9698     fn addAllocExtended(
   9699         gz: *GenZir,
   9700         args: struct {
   9701             /// Absolute node index. This function does the conversion to offset from Decl.
   9702             node: ast.Node.Index,
   9703             type_inst: Zir.Inst.Ref,
   9704             align_inst: Zir.Inst.Ref,
   9705             is_const: bool,
   9706             is_comptime: bool,
   9707         },
   9708     ) !Zir.Inst.Ref {
   9709         const astgen = gz.astgen;
   9710         const gpa = astgen.gpa;
   9711 
   9712         try gz.instructions.ensureUnusedCapacity(gpa, 1);
   9713         try astgen.instructions.ensureUnusedCapacity(gpa, 1);
   9714         try astgen.extra.ensureUnusedCapacity(
   9715             gpa,
   9716             @typeInfo(Zir.Inst.AllocExtended).Struct.fields.len +
   9717                 @as(usize, @boolToInt(args.type_inst != .none)) +
   9718                 @as(usize, @boolToInt(args.align_inst != .none)),
   9719         );
   9720         const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.AllocExtended{
   9721             .src_node = gz.nodeIndexToRelative(args.node),
   9722         });
   9723         if (args.type_inst != .none) {
   9724             astgen.extra.appendAssumeCapacity(@enumToInt(args.type_inst));
   9725         }
   9726         if (args.align_inst != .none) {
   9727             astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
   9728         }
   9729 
   9730         const has_type: u4 = @boolToInt(args.type_inst != .none);
   9731         const has_align: u4 = @boolToInt(args.align_inst != .none);
   9732         const is_const: u4 = @boolToInt(args.is_const);
   9733         const is_comptime: u4 = @boolToInt(args.is_comptime);
   9734         const small: u16 = has_type | (has_align << 1) | (is_const << 2) | (is_comptime << 3);
   9735 
   9736         const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
   9737         astgen.instructions.appendAssumeCapacity(.{
   9738             .tag = .extended,
   9739             .data = .{ .extended = .{
   9740                 .opcode = .alloc,
   9741                 .small = small,
   9742                 .operand = payload_index,
   9743             } },
   9744         });
   9745         gz.instructions.appendAssumeCapacity(new_index);
   9746         return indexToRef(new_index);
   9747     }
   9748 
   9749     fn addAsm(
   9750         gz: *GenZir,
   9751         args: struct {
   9752             /// Absolute node index. This function does the conversion to offset from Decl.
   9753             node: ast.Node.Index,
   9754             asm_source: u32,
   9755             output_type_bits: u32,
   9756             is_volatile: bool,
   9757             outputs: []const Zir.Inst.Asm.Output,
   9758             inputs: []const Zir.Inst.Asm.Input,
   9759             clobbers: []const u32,
   9760         },
   9761     ) !Zir.Inst.Ref {
   9762         const astgen = gz.astgen;
   9763         const gpa = astgen.gpa;
   9764 
   9765         try gz.instructions.ensureUnusedCapacity(gpa, 1);
   9766         try astgen.instructions.ensureUnusedCapacity(gpa, 1);
   9767         try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Asm).Struct.fields.len +
   9768             args.outputs.len * @typeInfo(Zir.Inst.Asm.Output).Struct.fields.len +
   9769             args.inputs.len * @typeInfo(Zir.Inst.Asm.Input).Struct.fields.len +
   9770             args.clobbers.len);
   9771 
   9772         const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Asm{
   9773             .src_node = gz.nodeIndexToRelative(args.node),
   9774             .asm_source = args.asm_source,
   9775             .output_type_bits = args.output_type_bits,
   9776         });
   9777         for (args.outputs) |output| {
   9778             _ = gz.astgen.addExtraAssumeCapacity(output);
   9779         }
   9780         for (args.inputs) |input| {
   9781             _ = gz.astgen.addExtraAssumeCapacity(input);
   9782         }
   9783         gz.astgen.extra.appendSliceAssumeCapacity(args.clobbers);
   9784 
   9785         //  * 0b00000000_000XXXXX - `outputs_len`.
   9786         //  * 0b000000XX_XXX00000 - `inputs_len`.
   9787         //  * 0b0XXXXX00_00000000 - `clobbers_len`.
   9788         //  * 0bX0000000_00000000 - is volatile
   9789         const small: u16 = @intCast(u16, args.outputs.len) |
   9790             @intCast(u16, args.inputs.len << 5) |
   9791             @intCast(u16, args.clobbers.len << 10) |
   9792             (@as(u16, @boolToInt(args.is_volatile)) << 15);
   9793 
   9794         const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
   9795         astgen.instructions.appendAssumeCapacity(.{
   9796             .tag = .extended,
   9797             .data = .{ .extended = .{
   9798                 .opcode = .@"asm",
   9799                 .small = small,
   9800                 .operand = payload_index,
   9801             } },
   9802         });
   9803         gz.instructions.appendAssumeCapacity(new_index);
   9804         return indexToRef(new_index);
   9805     }
   9806 
   9807     /// Note that this returns a `Zir.Inst.Index` not a ref.
   9808     /// Does *not* append the block instruction to the scope.
   9809     /// Leaves the `payload_index` field undefined.
   9810     fn addBlock(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index {
   9811         const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
   9812         const gpa = gz.astgen.gpa;
   9813         try gz.astgen.instructions.append(gpa, .{
   9814             .tag = tag,
   9815             .data = .{ .pl_node = .{
   9816                 .src_node = gz.nodeIndexToRelative(node),
   9817                 .payload_index = undefined,
   9818             } },
   9819         });
   9820         return new_index;
   9821     }
   9822 
   9823     /// Note that this returns a `Zir.Inst.Index` not a ref.
   9824     /// Leaves the `payload_index` field undefined.
   9825     fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index {
   9826         const gpa = gz.astgen.gpa;
   9827         try gz.instructions.ensureUnusedCapacity(gpa, 1);
   9828         const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
   9829         try gz.astgen.instructions.append(gpa, .{
   9830             .tag = tag,
   9831             .data = .{ .pl_node = .{
   9832                 .src_node = gz.nodeIndexToRelative(node),
   9833                 .payload_index = undefined,
   9834             } },
   9835         });
   9836         gz.instructions.appendAssumeCapacity(new_index);
   9837         return new_index;
   9838     }
   9839 
   9840     fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
   9841         src_node: ast.Node.Index,
   9842         body_len: u32,
   9843         fields_len: u32,
   9844         decls_len: u32,
   9845         layout: std.builtin.TypeInfo.ContainerLayout,
   9846         known_has_bits: bool,
   9847     }) !void {
   9848         const astgen = gz.astgen;
   9849         const gpa = astgen.gpa;
   9850 
   9851         try astgen.extra.ensureUnusedCapacity(gpa, 4);
   9852         const payload_index = @intCast(u32, astgen.extra.items.len);
   9853 
   9854         if (args.src_node != 0) {
   9855             const node_offset = gz.nodeIndexToRelative(args.src_node);
   9856             astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset));
   9857         }
   9858         if (args.body_len != 0) {
   9859             astgen.extra.appendAssumeCapacity(args.body_len);
   9860         }
   9861         if (args.fields_len != 0) {
   9862             astgen.extra.appendAssumeCapacity(args.fields_len);
   9863         }
   9864         if (args.decls_len != 0) {
   9865             astgen.extra.appendAssumeCapacity(args.decls_len);
   9866         }
   9867         astgen.instructions.set(inst, .{
   9868             .tag = .extended,
   9869             .data = .{ .extended = .{
   9870                 .opcode = .struct_decl,
   9871                 .small = @bitCast(u16, Zir.Inst.StructDecl.Small{
   9872                     .has_src_node = args.src_node != 0,
   9873                     .has_body_len = args.body_len != 0,
   9874                     .has_fields_len = args.fields_len != 0,
   9875                     .has_decls_len = args.decls_len != 0,
   9876                     .known_has_bits = args.known_has_bits,
   9877                     .name_strategy = gz.anon_name_strategy,
   9878                     .layout = args.layout,
   9879                 }),
   9880                 .operand = payload_index,
   9881             } },
   9882         });
   9883     }
   9884 
   9885     fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
   9886         src_node: ast.Node.Index,
   9887         tag_type: Zir.Inst.Ref,
   9888         body_len: u32,
   9889         fields_len: u32,
   9890         decls_len: u32,
   9891         layout: std.builtin.TypeInfo.ContainerLayout,
   9892         auto_enum_tag: bool,
   9893     }) !void {
   9894         const astgen = gz.astgen;
   9895         const gpa = astgen.gpa;
   9896 
   9897         try astgen.extra.ensureUnusedCapacity(gpa, 5);
   9898         const payload_index = @intCast(u32, astgen.extra.items.len);
   9899 
   9900         if (args.src_node != 0) {
   9901             const node_offset = gz.nodeIndexToRelative(args.src_node);
   9902             astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset));
   9903         }
   9904         if (args.tag_type != .none) {
   9905             astgen.extra.appendAssumeCapacity(@enumToInt(args.tag_type));
   9906         }
   9907         if (args.body_len != 0) {
   9908             astgen.extra.appendAssumeCapacity(args.body_len);
   9909         }
   9910         if (args.fields_len != 0) {
   9911             astgen.extra.appendAssumeCapacity(args.fields_len);
   9912         }
   9913         if (args.decls_len != 0) {
   9914             astgen.extra.appendAssumeCapacity(args.decls_len);
   9915         }
   9916         astgen.instructions.set(inst, .{
   9917             .tag = .extended,
   9918             .data = .{ .extended = .{
   9919                 .opcode = .union_decl,
   9920                 .small = @bitCast(u16, Zir.Inst.UnionDecl.Small{
   9921                     .has_src_node = args.src_node != 0,
   9922                     .has_tag_type = args.tag_type != .none,
   9923                     .has_body_len = args.body_len != 0,
   9924                     .has_fields_len = args.fields_len != 0,
   9925                     .has_decls_len = args.decls_len != 0,
   9926                     .name_strategy = gz.anon_name_strategy,
   9927                     .layout = args.layout,
   9928                     .auto_enum_tag = args.auto_enum_tag,
   9929                 }),
   9930                 .operand = payload_index,
   9931             } },
   9932         });
   9933     }
   9934 
   9935     fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
   9936         src_node: ast.Node.Index,
   9937         tag_type: Zir.Inst.Ref,
   9938         body_len: u32,
   9939         fields_len: u32,
   9940         decls_len: u32,
   9941         nonexhaustive: bool,
   9942     }) !void {
   9943         const astgen = gz.astgen;
   9944         const gpa = astgen.gpa;
   9945 
   9946         try astgen.extra.ensureUnusedCapacity(gpa, 5);
   9947         const payload_index = @intCast(u32, astgen.extra.items.len);
   9948 
   9949         if (args.src_node != 0) {
   9950             const node_offset = gz.nodeIndexToRelative(args.src_node);
   9951             astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset));
   9952         }
   9953         if (args.tag_type != .none) {
   9954             astgen.extra.appendAssumeCapacity(@enumToInt(args.tag_type));
   9955         }
   9956         if (args.body_len != 0) {
   9957             astgen.extra.appendAssumeCapacity(args.body_len);
   9958         }
   9959         if (args.fields_len != 0) {
   9960             astgen.extra.appendAssumeCapacity(args.fields_len);
   9961         }
   9962         if (args.decls_len != 0) {
   9963             astgen.extra.appendAssumeCapacity(args.decls_len);
   9964         }
   9965         astgen.instructions.set(inst, .{
   9966             .tag = .extended,
   9967             .data = .{ .extended = .{
   9968                 .opcode = .enum_decl,
   9969                 .small = @bitCast(u16, Zir.Inst.EnumDecl.Small{
   9970                     .has_src_node = args.src_node != 0,
   9971                     .has_tag_type = args.tag_type != .none,
   9972                     .has_body_len = args.body_len != 0,
   9973                     .has_fields_len = args.fields_len != 0,
   9974                     .has_decls_len = args.decls_len != 0,
   9975                     .name_strategy = gz.anon_name_strategy,
   9976                     .nonexhaustive = args.nonexhaustive,
   9977                 }),
   9978                 .operand = payload_index,
   9979             } },
   9980         });
   9981     }
   9982 
   9983     fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref {
   9984         return indexToRef(try gz.addAsIndex(inst));
   9985     }
   9986 
   9987     fn addAsIndex(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Index {
   9988         const gpa = gz.astgen.gpa;
   9989         try gz.instructions.ensureUnusedCapacity(gpa, 1);
   9990         try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
   9991 
   9992         const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
   9993         gz.astgen.instructions.appendAssumeCapacity(inst);
   9994         gz.instructions.appendAssumeCapacity(new_index);
   9995         return new_index;
   9996     }
   9997 
   9998     fn reserveInstructionIndex(gz: *GenZir) !Zir.Inst.Index {
   9999         const gpa = gz.astgen.gpa;
  10000         try gz.instructions.ensureUnusedCapacity(gpa, 1);
  10001         try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
  10002 
  10003         const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
  10004         gz.astgen.instructions.len += 1;
  10005         gz.instructions.appendAssumeCapacity(new_index);
  10006         return new_index;
  10007     }
  10008 
  10009     fn addRet(gz: *GenZir, rl: ResultLoc, operand: Zir.Inst.Ref, node: ast.Node.Index) !void {
  10010         switch (rl) {
  10011             .ptr => |ret_ptr| _ = try gz.addUnNode(.ret_load, ret_ptr, node),
  10012             .ty => _ = try gz.addUnNode(.ret_node, operand, node),
  10013             else => unreachable,
  10014         }
  10015     }
  10016 };
  10017 
  10018 /// This can only be for short-lived references; the memory becomes invalidated
  10019 /// when another string is added.
  10020 fn nullTerminatedString(astgen: AstGen, index: usize) [*:0]const u8 {
  10021     return @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + index;
  10022 }
  10023 
  10024 fn isPrimitive(name: []const u8) bool {
  10025     if (simple_types.get(name) != null) return true;
  10026     if (name.len < 2) return false;
  10027     const first_c = name[0];
  10028     if (first_c != 'i' and first_c != 'u') return false;
  10029     if (std.fmt.parseInt(u16, name[1..], 10)) |_| {
  10030         return true;
  10031     } else |err| switch (err) {
  10032         error.Overflow => return true,
  10033         error.InvalidCharacter => return false,
  10034     }
  10035 }
  10036 
  10037 /// Local variables shadowing detection, including function parameters and primitives.
  10038 fn detectLocalShadowing(
  10039     astgen: *AstGen,
  10040     scope: *Scope,
  10041     ident_name: u32,
  10042     name_token: ast.TokenIndex,
  10043     token_bytes: []const u8,
  10044 ) !void {
  10045     const gpa = astgen.gpa;
  10046     if (token_bytes[0] != '@' and isPrimitive(token_bytes)) {
  10047         return astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{
  10048             token_bytes,
  10049         }, &[_]u32{
  10050             try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{
  10051                 token_bytes,
  10052             }),
  10053         });
  10054     }
  10055 
  10056     var s = scope;
  10057     while (true) switch (s.tag) {
  10058         .local_val => {
  10059             const local_val = s.cast(Scope.LocalVal).?;
  10060             if (local_val.name == ident_name) {
  10061                 const name_slice = mem.span(astgen.nullTerminatedString(ident_name));
  10062                 const name = try gpa.dupe(u8, name_slice);
  10063                 defer gpa.free(name);
  10064                 return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{
  10065                     @tagName(local_val.id_cat), name,
  10066                 }, &[_]u32{
  10067                     try astgen.errNoteTok(
  10068                         local_val.token_src,
  10069                         "previous declaration here",
  10070                         .{},
  10071                     ),
  10072                 });
  10073             }
  10074             s = local_val.parent;
  10075         },
  10076         .local_ptr => {
  10077             const local_ptr = s.cast(Scope.LocalPtr).?;
  10078             if (local_ptr.name == ident_name) {
  10079                 const name_slice = mem.span(astgen.nullTerminatedString(ident_name));
  10080                 const name = try gpa.dupe(u8, name_slice);
  10081                 defer gpa.free(name);
  10082                 return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{
  10083                     @tagName(local_ptr.id_cat), name,
  10084                 }, &[_]u32{
  10085                     try astgen.errNoteTok(
  10086                         local_ptr.token_src,
  10087                         "previous declaration here",
  10088                         .{},
  10089                     ),
  10090                 });
  10091             }
  10092             s = local_ptr.parent;
  10093         },
  10094         .namespace => {
  10095             const ns = s.cast(Scope.Namespace).?;
  10096             const decl_node = ns.decls.get(ident_name) orelse {
  10097                 s = ns.parent;
  10098                 continue;
  10099             };
  10100             const name_slice = mem.span(astgen.nullTerminatedString(ident_name));
  10101             const name = try gpa.dupe(u8, name_slice);
  10102             defer gpa.free(name);
  10103             return astgen.failTokNotes(name_token, "local shadows declaration of '{s}'", .{
  10104                 name,
  10105             }, &[_]u32{
  10106                 try astgen.errNoteNode(decl_node, "declared here", .{}),
  10107             });
  10108         },
  10109         .gen_zir => s = s.cast(GenZir).?.parent,
  10110         .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
  10111         .top => break,
  10112     };
  10113 }
  10114 
  10115 fn advanceSourceCursor(astgen: *AstGen, source: []const u8, end: usize) void {
  10116     var i = astgen.source_offset;
  10117     var line = astgen.source_line;
  10118     var column = astgen.source_column;
  10119     while (i < end) : (i += 1) {
  10120         if (source[i] == '\n') {
  10121             line += 1;
  10122             column = 0;
  10123         } else {
  10124             column += 1;
  10125         }
  10126     }
  10127     astgen.source_offset = i;
  10128     astgen.source_line = line;
  10129     astgen.source_column = column;
  10130 }
  10131 
  10132 const ref_start_index: u32 = Zir.Inst.Ref.typed_value_map.len;
  10133 
  10134 fn indexToRef(inst: Zir.Inst.Index) Zir.Inst.Ref {
  10135     return @intToEnum(Zir.Inst.Ref, ref_start_index + inst);
  10136 }
  10137 
  10138 fn refToIndex(inst: Zir.Inst.Ref) ?Zir.Inst.Index {
  10139     const ref_int = @enumToInt(inst);
  10140     if (ref_int >= ref_start_index) {
  10141         return ref_int - ref_start_index;
  10142     } else {
  10143         return null;
  10144     }
  10145 }
  10146 
  10147 fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const ast.Node.Index) !void {
  10148     const gpa = astgen.gpa;
  10149     const tree = astgen.tree;
  10150     const node_tags = tree.nodes.items(.tag);
  10151     const main_tokens = tree.nodes.items(.main_token);
  10152     for (members) |member_node| {
  10153         const name_token = switch (node_tags[member_node]) {
  10154             .fn_decl,
  10155             .fn_proto_simple,
  10156             .fn_proto_multi,
  10157             .fn_proto_one,
  10158             .fn_proto,
  10159             .global_var_decl,
  10160             .local_var_decl,
  10161             .simple_var_decl,
  10162             .aligned_var_decl,
  10163             => main_tokens[member_node] + 1,
  10164 
  10165             else => continue,
  10166         };
  10167 
  10168         const token_bytes = astgen.tree.tokenSlice(name_token);
  10169         if (token_bytes[0] != '@' and isPrimitive(token_bytes)) {
  10170             switch (astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{
  10171                 token_bytes,
  10172             }, &[_]u32{
  10173                 try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{
  10174                     token_bytes,
  10175                 }),
  10176             })) {
  10177                 error.AnalysisFail => continue,
  10178                 error.OutOfMemory => return error.OutOfMemory,
  10179             }
  10180         }
  10181 
  10182         const name_str_index = try astgen.identAsString(name_token);
  10183         const gop = try namespace.decls.getOrPut(gpa, name_str_index);
  10184         if (gop.found_existing) {
  10185             const name = try gpa.dupe(u8, mem.span(astgen.nullTerminatedString(name_str_index)));
  10186             defer gpa.free(name);
  10187             switch (astgen.failNodeNotes(member_node, "redeclaration of '{s}'", .{
  10188                 name,
  10189             }, &[_]u32{
  10190                 try astgen.errNoteNode(gop.value_ptr.*, "other declaration here", .{}),
  10191             })) {
  10192                 error.AnalysisFail => continue,
  10193                 error.OutOfMemory => return error.OutOfMemory,
  10194             }
  10195         }
  10196         gop.value_ptr.* = member_node;
  10197     }
  10198 }