zig

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

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