zig

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

blob ae00a985 (1307370B) - Raw


      1 //! Semantic analysis of ZIR instructions.
      2 //! Shared to every Block. Stored on the stack.
      3 //! State used for compiling a ZIR into AIR.
      4 //! Transforms untyped ZIR instructions into semantically-analyzed AIR instructions.
      5 //! Does type checking, comptime control flow, and safety-check generation.
      6 //! This is the the heart of the Zig compiler.
      7 
      8 mod: *Module,
      9 /// Alias to `mod.gpa`.
     10 gpa: Allocator,
     11 /// Points to the temporary arena allocator of the Sema.
     12 /// This arena will be cleared when the sema is destroyed.
     13 arena: Allocator,
     14 /// Points to the arena allocator for the owner_decl.
     15 /// This arena will persist until the decl is invalidated.
     16 perm_arena: Allocator,
     17 code: Zir,
     18 air_instructions: std.MultiArrayList(Air.Inst) = .{},
     19 air_extra: std.ArrayListUnmanaged(u32) = .{},
     20 air_values: std.ArrayListUnmanaged(Value) = .{},
     21 /// Maps ZIR to AIR.
     22 inst_map: InstMap = .{},
     23 /// When analyzing an inline function call, owner_decl is the Decl of the caller
     24 /// and `src_decl` of `Block` is the `Decl` of the callee.
     25 /// This `Decl` owns the arena memory of this `Sema`.
     26 owner_decl: *Decl,
     27 owner_decl_index: Decl.Index,
     28 /// For an inline or comptime function call, this will be the root parent function
     29 /// which contains the callsite. Corresponds to `owner_decl`.
     30 owner_func: ?*Module.Fn,
     31 /// The function this ZIR code is the body of, according to the source code.
     32 /// This starts out the same as `owner_func` and then diverges in the case of
     33 /// an inline or comptime function call.
     34 func: ?*Module.Fn,
     35 /// When semantic analysis needs to know the return type of the function whose body
     36 /// is being analyzed, this `Type` should be used instead of going through `func`.
     37 /// This will correctly handle the case of a comptime/inline function call of a
     38 /// generic function which uses a type expression for the return type.
     39 /// The type will be `void` in the case that `func` is `null`.
     40 fn_ret_ty: Type,
     41 branch_quota: u32 = default_branch_quota,
     42 branch_count: u32 = 0,
     43 /// Populated when returning `error.ComptimeBreak`. Used to communicate the
     44 /// break instruction up the stack to find the corresponding Block.
     45 comptime_break_inst: Zir.Inst.Index = undefined,
     46 /// This field is updated when a new source location becomes active, so that
     47 /// instructions which do not have explicitly mapped source locations still have
     48 /// access to the source location set by the previous instruction which did
     49 /// contain a mapped source location.
     50 src: LazySrcLoc = .{ .token_offset = 0 },
     51 decl_val_table: std.AutoHashMapUnmanaged(Decl.Index, Air.Inst.Ref) = .{},
     52 /// When doing a generic function instantiation, this array collects a
     53 /// `Value` object for each parameter that is comptime known and thus elided
     54 /// from the generated function. This memory is allocated by a parent `Sema` and
     55 /// owned by the values arena of the Sema owner_decl.
     56 comptime_args: []TypedValue = &.{},
     57 /// Marks the function instruction that `comptime_args` applies to so that we
     58 /// don't accidentally apply it to a function prototype which is used in the
     59 /// type expression of a generic function parameter.
     60 comptime_args_fn_inst: Zir.Inst.Index = 0,
     61 /// When `comptime_args` is provided, this field is also provided. It was used as
     62 /// the key in the `monomorphed_funcs` set. The `func` instruction is supposed
     63 /// to use this instead of allocating a fresh one. This avoids an unnecessary
     64 /// extra hash table lookup in the `monomorphed_funcs` set.
     65 /// Sema will set this to null when it takes ownership.
     66 preallocated_new_func: ?*Module.Fn = null,
     67 /// The key is `constant` AIR instructions to types that must be fully resolved
     68 /// after the current function body analysis is done.
     69 /// TODO: after upgrading to use InternPool change the key here to be an
     70 /// InternPool value index.
     71 types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{},
     72 /// These are lazily created runtime blocks from inline_block instructions.
     73 /// They are created when an inline_break passes through a runtime condition, because
     74 /// Sema must convert comptime control flow to runtime control flow, which means
     75 /// breaking from a block.
     76 post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},
     77 /// Populated with the last compile error created.
     78 err: ?*Module.ErrorMsg = null,
     79 /// True when analyzing a generic instantiation. Used to suppress some errors.
     80 is_generic_instantiation: bool = false,
     81 /// Set to true when analyzing a func type instruction so that nested generic
     82 /// function types will emit generic poison instead of a partial type.
     83 no_partial_func_ty: bool = false,
     84 
     85 const std = @import("std");
     86 const math = std.math;
     87 const mem = std.mem;
     88 const Allocator = std.mem.Allocator;
     89 const assert = std.debug.assert;
     90 const log = std.log.scoped(.sema);
     91 
     92 const Sema = @This();
     93 const Value = @import("value.zig").Value;
     94 const Type = @import("type.zig").Type;
     95 const TypedValue = @import("TypedValue.zig");
     96 const Air = @import("Air.zig");
     97 const Zir = @import("Zir.zig");
     98 const Module = @import("Module.zig");
     99 const trace = @import("tracy.zig").trace;
    100 const Namespace = Module.Namespace;
    101 const CompileError = Module.CompileError;
    102 const SemaError = Module.SemaError;
    103 const Decl = Module.Decl;
    104 const CaptureScope = Module.CaptureScope;
    105 const WipCaptureScope = Module.WipCaptureScope;
    106 const LazySrcLoc = Module.LazySrcLoc;
    107 const RangeSet = @import("RangeSet.zig");
    108 const target_util = @import("target.zig");
    109 const Package = @import("Package.zig");
    110 const crash_report = @import("crash_report.zig");
    111 const build_options = @import("build_options");
    112 
    113 pub const default_branch_quota = 1000;
    114 pub const default_reference_trace_len = 2;
    115 
    116 pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref);
    117 
    118 /// This is the context needed to semantically analyze ZIR instructions and
    119 /// produce AIR instructions.
    120 /// This is a temporary structure stored on the stack; references to it are valid only
    121 /// during semantic analysis of the block.
    122 pub const Block = struct {
    123     parent: ?*Block,
    124     /// Shared among all child blocks.
    125     sema: *Sema,
    126     /// The namespace to use for lookups from this source block
    127     /// When analyzing fields, this is different from src_decl.src_namepsace.
    128     namespace: *Namespace,
    129     /// The AIR instructions generated for this block.
    130     instructions: std.ArrayListUnmanaged(Air.Inst.Index),
    131     // `param` instructions are collected here to be used by the `func` instruction.
    132     params: std.ArrayListUnmanaged(Param) = .{},
    133 
    134     wip_capture_scope: *CaptureScope,
    135 
    136     label: ?*Label = null,
    137     inlining: ?*Inlining,
    138     /// If runtime_index is not 0 then one of these is guaranteed to be non null.
    139     runtime_cond: ?LazySrcLoc = null,
    140     runtime_loop: ?LazySrcLoc = null,
    141     /// This Decl is the Decl according to the Zig source code corresponding to this Block.
    142     /// This can vary during inline or comptime function calls. See `Sema.owner_decl`
    143     /// for the one that will be the same for all Block instances.
    144     src_decl: Decl.Index,
    145     /// Non zero if a non-inline loop or a runtime conditional have been encountered.
    146     /// Stores to to comptime variables are only allowed when var.runtime_index <= runtime_index.
    147     runtime_index: Value.RuntimeIndex = .zero,
    148     inline_block: Zir.Inst.Index = 0,
    149 
    150     is_comptime: bool,
    151     is_typeof: bool = false,
    152     is_coerce_result_ptr: bool = false,
    153 
    154     /// when null, it is determined by build mode, changed by @setRuntimeSafety
    155     want_safety: ?bool = null,
    156 
    157     /// What mode to generate float operations in, set by @setFloatMode
    158     float_mode: std.builtin.FloatMode = .Strict,
    159 
    160     c_import_buf: ?*std.ArrayList(u8) = null,
    161 
    162     /// type of `err` in `else => |err|`
    163     switch_else_err_ty: ?Type = null,
    164 
    165     const Param = struct {
    166         /// `noreturn` means `anytype`.
    167         ty: Type,
    168         is_comptime: bool,
    169         name: []const u8,
    170     };
    171 
    172     /// This `Block` maps a block ZIR instruction to the corresponding
    173     /// AIR instruction for break instruction analysis.
    174     pub const Label = struct {
    175         zir_block: Zir.Inst.Index,
    176         merges: Merges,
    177     };
    178 
    179     /// This `Block` indicates that an inline function call is happening
    180     /// and return instructions should be analyzed as a break instruction
    181     /// to this AIR block instruction.
    182     /// It is shared among all the blocks in an inline or comptime called
    183     /// function.
    184     pub const Inlining = struct {
    185         comptime_result: Air.Inst.Ref,
    186         merges: Merges,
    187     };
    188 
    189     pub const Merges = struct {
    190         block_inst: Air.Inst.Index,
    191         /// Separate array list from break_inst_list so that it can be passed directly
    192         /// to resolvePeerTypes.
    193         results: std.ArrayListUnmanaged(Air.Inst.Ref),
    194         /// Keeps track of the break instructions so that the operand can be replaced
    195         /// if we need to add type coercion at the end of block analysis.
    196         /// Same indexes, capacity, length as `results`.
    197         br_list: std.ArrayListUnmanaged(Air.Inst.Index),
    198     };
    199 
    200     /// For debugging purposes.
    201     pub fn dump(block: *Block, mod: Module) void {
    202         Zir.dumpBlock(mod, block);
    203     }
    204 
    205     pub fn makeSubBlock(parent: *Block) Block {
    206         return .{
    207             .parent = parent,
    208             .sema = parent.sema,
    209             .src_decl = parent.src_decl,
    210             .namespace = parent.namespace,
    211             .instructions = .{},
    212             .wip_capture_scope = parent.wip_capture_scope,
    213             .label = null,
    214             .inlining = parent.inlining,
    215             .is_comptime = parent.is_comptime,
    216             .is_typeof = parent.is_typeof,
    217             .runtime_cond = parent.runtime_cond,
    218             .runtime_loop = parent.runtime_loop,
    219             .runtime_index = parent.runtime_index,
    220             .want_safety = parent.want_safety,
    221             .float_mode = parent.float_mode,
    222             .c_import_buf = parent.c_import_buf,
    223             .switch_else_err_ty = parent.switch_else_err_ty,
    224         };
    225     }
    226 
    227     pub fn wantSafety(block: *const Block) bool {
    228         return block.want_safety orelse switch (block.sema.mod.optimizeMode()) {
    229             .Debug => true,
    230             .ReleaseSafe => true,
    231             .ReleaseFast => false,
    232             .ReleaseSmall => false,
    233         };
    234     }
    235 
    236     pub fn getFileScope(block: *Block) *Module.File {
    237         return block.namespace.file_scope;
    238     }
    239 
    240     fn addTy(
    241         block: *Block,
    242         tag: Air.Inst.Tag,
    243         ty: Type,
    244     ) error{OutOfMemory}!Air.Inst.Ref {
    245         return block.addInst(.{
    246             .tag = tag,
    247             .data = .{ .ty = ty },
    248         });
    249     }
    250 
    251     fn addTyOp(
    252         block: *Block,
    253         tag: Air.Inst.Tag,
    254         ty: Type,
    255         operand: Air.Inst.Ref,
    256     ) error{OutOfMemory}!Air.Inst.Ref {
    257         return block.addInst(.{
    258             .tag = tag,
    259             .data = .{ .ty_op = .{
    260                 .ty = try block.sema.addType(ty),
    261                 .operand = operand,
    262             } },
    263         });
    264     }
    265 
    266     fn addBitCast(block: *Block, ty: Type, operand: Air.Inst.Ref) Allocator.Error!Air.Inst.Ref {
    267         return block.addInst(.{
    268             .tag = .bitcast,
    269             .data = .{ .ty_op = .{
    270                 .ty = try block.sema.addType(ty),
    271                 .operand = operand,
    272             } },
    273         });
    274     }
    275 
    276     fn addNoOp(block: *Block, tag: Air.Inst.Tag) error{OutOfMemory}!Air.Inst.Ref {
    277         return block.addInst(.{
    278             .tag = tag,
    279             .data = .{ .no_op = {} },
    280         });
    281     }
    282 
    283     fn addUnOp(
    284         block: *Block,
    285         tag: Air.Inst.Tag,
    286         operand: Air.Inst.Ref,
    287     ) error{OutOfMemory}!Air.Inst.Ref {
    288         return block.addInst(.{
    289             .tag = tag,
    290             .data = .{ .un_op = operand },
    291         });
    292     }
    293 
    294     fn addBr(
    295         block: *Block,
    296         target_block: Air.Inst.Index,
    297         operand: Air.Inst.Ref,
    298     ) error{OutOfMemory}!Air.Inst.Ref {
    299         return block.addInst(.{
    300             .tag = .br,
    301             .data = .{ .br = .{
    302                 .block_inst = target_block,
    303                 .operand = operand,
    304             } },
    305         });
    306     }
    307 
    308     fn addBinOp(
    309         block: *Block,
    310         tag: Air.Inst.Tag,
    311         lhs: Air.Inst.Ref,
    312         rhs: Air.Inst.Ref,
    313     ) error{OutOfMemory}!Air.Inst.Ref {
    314         return block.addInst(.{
    315             .tag = tag,
    316             .data = .{ .bin_op = .{
    317                 .lhs = lhs,
    318                 .rhs = rhs,
    319             } },
    320         });
    321     }
    322 
    323     fn addArg(block: *Block, ty: Type) error{OutOfMemory}!Air.Inst.Ref {
    324         return block.addInst(.{
    325             .tag = .arg,
    326             .data = .{ .ty = ty },
    327         });
    328     }
    329 
    330     fn addStructFieldPtr(
    331         block: *Block,
    332         struct_ptr: Air.Inst.Ref,
    333         field_index: u32,
    334         ptr_field_ty: Type,
    335     ) !Air.Inst.Ref {
    336         const ty = try block.sema.addType(ptr_field_ty);
    337         const tag: Air.Inst.Tag = switch (field_index) {
    338             0 => .struct_field_ptr_index_0,
    339             1 => .struct_field_ptr_index_1,
    340             2 => .struct_field_ptr_index_2,
    341             3 => .struct_field_ptr_index_3,
    342             else => {
    343                 return block.addInst(.{
    344                     .tag = .struct_field_ptr,
    345                     .data = .{ .ty_pl = .{
    346                         .ty = ty,
    347                         .payload = try block.sema.addExtra(Air.StructField{
    348                             .struct_operand = struct_ptr,
    349                             .field_index = field_index,
    350                         }),
    351                     } },
    352                 });
    353             },
    354         };
    355         return block.addInst(.{
    356             .tag = tag,
    357             .data = .{ .ty_op = .{
    358                 .ty = ty,
    359                 .operand = struct_ptr,
    360             } },
    361         });
    362     }
    363 
    364     fn addStructFieldVal(
    365         block: *Block,
    366         struct_val: Air.Inst.Ref,
    367         field_index: u32,
    368         field_ty: Type,
    369     ) !Air.Inst.Ref {
    370         return block.addInst(.{
    371             .tag = .struct_field_val,
    372             .data = .{ .ty_pl = .{
    373                 .ty = try block.sema.addType(field_ty),
    374                 .payload = try block.sema.addExtra(Air.StructField{
    375                     .struct_operand = struct_val,
    376                     .field_index = field_index,
    377                 }),
    378             } },
    379         });
    380     }
    381 
    382     fn addSliceElemPtr(
    383         block: *Block,
    384         slice: Air.Inst.Ref,
    385         elem_index: Air.Inst.Ref,
    386         elem_ptr_ty: Type,
    387     ) !Air.Inst.Ref {
    388         return block.addInst(.{
    389             .tag = .slice_elem_ptr,
    390             .data = .{ .ty_pl = .{
    391                 .ty = try block.sema.addType(elem_ptr_ty),
    392                 .payload = try block.sema.addExtra(Air.Bin{
    393                     .lhs = slice,
    394                     .rhs = elem_index,
    395                 }),
    396             } },
    397         });
    398     }
    399 
    400     fn addPtrElemPtr(
    401         block: *Block,
    402         array_ptr: Air.Inst.Ref,
    403         elem_index: Air.Inst.Ref,
    404         elem_ptr_ty: Type,
    405     ) !Air.Inst.Ref {
    406         const ty_ref = try block.sema.addType(elem_ptr_ty);
    407         return block.addPtrElemPtrTypeRef(array_ptr, elem_index, ty_ref);
    408     }
    409 
    410     fn addPtrElemPtrTypeRef(
    411         block: *Block,
    412         array_ptr: Air.Inst.Ref,
    413         elem_index: Air.Inst.Ref,
    414         elem_ptr_ty: Air.Inst.Ref,
    415     ) !Air.Inst.Ref {
    416         return block.addInst(.{
    417             .tag = .ptr_elem_ptr,
    418             .data = .{ .ty_pl = .{
    419                 .ty = elem_ptr_ty,
    420                 .payload = try block.sema.addExtra(Air.Bin{
    421                     .lhs = array_ptr,
    422                     .rhs = elem_index,
    423                 }),
    424             } },
    425         });
    426     }
    427 
    428     fn addCmpVector(block: *Block, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref, cmp_op: std.math.CompareOperator, vector_ty: Air.Inst.Ref) !Air.Inst.Ref {
    429         return block.addInst(.{
    430             .tag = if (block.float_mode == .Optimized) .cmp_vector_optimized else .cmp_vector,
    431             .data = .{ .ty_pl = .{
    432                 .ty = vector_ty,
    433                 .payload = try block.sema.addExtra(Air.VectorCmp{
    434                     .lhs = lhs,
    435                     .rhs = rhs,
    436                     .op = Air.VectorCmp.encodeOp(cmp_op),
    437                 }),
    438             } },
    439         });
    440     }
    441 
    442     fn addAggregateInit(
    443         block: *Block,
    444         aggregate_ty: Type,
    445         elements: []const Air.Inst.Ref,
    446     ) !Air.Inst.Ref {
    447         const sema = block.sema;
    448         const ty_ref = try sema.addType(aggregate_ty);
    449         try sema.air_extra.ensureUnusedCapacity(sema.gpa, elements.len);
    450         const extra_index = @intCast(u32, sema.air_extra.items.len);
    451         sema.appendRefsAssumeCapacity(elements);
    452 
    453         return block.addInst(.{
    454             .tag = .aggregate_init,
    455             .data = .{ .ty_pl = .{
    456                 .ty = ty_ref,
    457                 .payload = extra_index,
    458             } },
    459         });
    460     }
    461 
    462     fn addUnionInit(
    463         block: *Block,
    464         union_ty: Type,
    465         field_index: u32,
    466         init: Air.Inst.Ref,
    467     ) !Air.Inst.Ref {
    468         return block.addInst(.{
    469             .tag = .union_init,
    470             .data = .{ .ty_pl = .{
    471                 .ty = try block.sema.addType(union_ty),
    472                 .payload = try block.sema.addExtra(Air.UnionInit{
    473                     .field_index = field_index,
    474                     .init = init,
    475                 }),
    476             } },
    477         });
    478     }
    479 
    480     pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {
    481         return Air.indexToRef(try block.addInstAsIndex(inst));
    482     }
    483 
    484     pub fn addInstAsIndex(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Index {
    485         const sema = block.sema;
    486         const gpa = sema.gpa;
    487 
    488         try sema.air_instructions.ensureUnusedCapacity(gpa, 1);
    489         try block.instructions.ensureUnusedCapacity(gpa, 1);
    490 
    491         const result_index = @intCast(Air.Inst.Index, sema.air_instructions.len);
    492         sema.air_instructions.appendAssumeCapacity(inst);
    493         block.instructions.appendAssumeCapacity(result_index);
    494         return result_index;
    495     }
    496 
    497     fn addUnreachable(block: *Block, src: LazySrcLoc, safety_check: bool) !void {
    498         if (safety_check and block.wantSafety()) {
    499             _ = try block.sema.safetyPanic(block, src, .unreach);
    500         } else {
    501             _ = try block.addNoOp(.unreach);
    502         }
    503     }
    504 
    505     pub fn startAnonDecl(block: *Block, src: LazySrcLoc) !WipAnonDecl {
    506         return WipAnonDecl{
    507             .block = block,
    508             .src = src,
    509             .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa),
    510             .finished = false,
    511         };
    512     }
    513 
    514     pub const WipAnonDecl = struct {
    515         block: *Block,
    516         src: LazySrcLoc,
    517         new_decl_arena: std.heap.ArenaAllocator,
    518         finished: bool,
    519 
    520         pub fn arena(wad: *WipAnonDecl) Allocator {
    521             return wad.new_decl_arena.allocator();
    522         }
    523 
    524         pub fn deinit(wad: *WipAnonDecl) void {
    525             if (!wad.finished) {
    526                 wad.new_decl_arena.deinit();
    527             }
    528             wad.* = undefined;
    529         }
    530 
    531         /// `alignment` value of 0 means to use ABI alignment.
    532         pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value, alignment: u32) !Decl.Index {
    533             const sema = wad.block.sema;
    534             // Do this ahead of time because `createAnonymousDecl` depends on calling
    535             // `type.hasRuntimeBits()`.
    536             _ = try sema.typeHasRuntimeBits(wad.block, wad.src, ty);
    537             const new_decl_index = try sema.mod.createAnonymousDecl(wad.block, .{
    538                 .ty = ty,
    539                 .val = val,
    540             });
    541             const new_decl = sema.mod.declPtr(new_decl_index);
    542             new_decl.@"align" = alignment;
    543             errdefer sema.mod.abortAnonDecl(new_decl_index);
    544             try new_decl.finalizeNewArena(&wad.new_decl_arena);
    545             wad.finished = true;
    546             return new_decl_index;
    547         }
    548     };
    549 };
    550 
    551 const LabeledBlock = struct {
    552     block: Block,
    553     label: Block.Label,
    554 
    555     fn destroy(lb: *LabeledBlock, gpa: Allocator) void {
    556         lb.block.instructions.deinit(gpa);
    557         lb.label.merges.results.deinit(gpa);
    558         lb.label.merges.br_list.deinit(gpa);
    559         gpa.destroy(lb);
    560     }
    561 };
    562 
    563 pub fn deinit(sema: *Sema) void {
    564     const gpa = sema.gpa;
    565     sema.air_instructions.deinit(gpa);
    566     sema.air_extra.deinit(gpa);
    567     sema.air_values.deinit(gpa);
    568     sema.inst_map.deinit(gpa);
    569     sema.decl_val_table.deinit(gpa);
    570     sema.types_to_resolve.deinit(gpa);
    571     {
    572         var it = sema.post_hoc_blocks.iterator();
    573         while (it.next()) |entry| {
    574             const labeled_block = entry.value_ptr.*;
    575             labeled_block.destroy(gpa);
    576         }
    577         sema.post_hoc_blocks.deinit(gpa);
    578     }
    579     sema.* = undefined;
    580 }
    581 
    582 /// Returns only the result from the body that is specified.
    583 /// Only appropriate to call when it is determined at comptime that this body
    584 /// has no peers.
    585 fn resolveBody(
    586     sema: *Sema,
    587     block: *Block,
    588     body: []const Zir.Inst.Index,
    589     /// This is the instruction that a break instruction within `body` can
    590     /// use to return from the body.
    591     body_inst: Zir.Inst.Index,
    592 ) CompileError!Air.Inst.Ref {
    593     const break_data = (try sema.analyzeBodyBreak(block, body)) orelse
    594         return Air.Inst.Ref.unreachable_value;
    595     // For comptime control flow, we need to detect when `analyzeBody` reports
    596     // that we need to break from an outer block. In such case we
    597     // use Zig's error mechanism to send control flow up the stack until
    598     // we find the corresponding block to this break.
    599     if (block.is_comptime and break_data.block_inst != body_inst) {
    600         sema.comptime_break_inst = break_data.inst;
    601         return error.ComptimeBreak;
    602     }
    603     return try sema.resolveInst(break_data.operand);
    604 }
    605 
    606 pub fn analyzeBody(
    607     sema: *Sema,
    608     block: *Block,
    609     body: []const Zir.Inst.Index,
    610 ) !void {
    611     _ = sema.analyzeBodyInner(block, body) catch |err| switch (err) {
    612         error.ComptimeBreak => unreachable, // unexpected comptime control flow
    613         else => |e| return e,
    614     };
    615 }
    616 
    617 const BreakData = struct {
    618     block_inst: Zir.Inst.Index,
    619     operand: Zir.Inst.Ref,
    620     inst: Zir.Inst.Index,
    621 };
    622 
    623 pub fn analyzeBodyBreak(
    624     sema: *Sema,
    625     block: *Block,
    626     body: []const Zir.Inst.Index,
    627 ) CompileError!?BreakData {
    628     const break_inst = sema.analyzeBodyInner(block, body) catch |err| switch (err) {
    629         error.ComptimeBreak => sema.comptime_break_inst,
    630         else => |e| return e,
    631     };
    632     if (block.instructions.items.len != 0 and
    633         sema.typeOf(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1])).isNoReturn())
    634         return null;
    635     const break_data = sema.code.instructions.items(.data)[break_inst].@"break";
    636     return BreakData{
    637         .block_inst = break_data.block_inst,
    638         .operand = break_data.operand,
    639         .inst = break_inst,
    640     };
    641 }
    642 
    643 /// ZIR instructions which are always `noreturn` return this. This matches the
    644 /// return type of `analyzeBody` so that we can tail call them.
    645 /// Only appropriate to return when the instruction is known to be NoReturn
    646 /// solely based on the ZIR tag.
    647 const always_noreturn: CompileError!Zir.Inst.Index = @as(Zir.Inst.Index, undefined);
    648 
    649 /// This function is the main loop of `Sema` and it can be used in two different ways:
    650 /// * The traditional way where there are N breaks out of the block and peer type
    651 ///   resolution is done on the break operands. In this case, the `Zir.Inst.Index`
    652 ///   part of the return value will be `undefined`, and callsites should ignore it,
    653 ///   finding the block result value via the block scope.
    654 /// * The "flat" way. There is only 1 break out of the block, and it is with a `break_inline`
    655 ///   instruction. In this case, the `Zir.Inst.Index` part of the return value will be
    656 ///   the break instruction. This communicates both which block the break applies to, as
    657 ///   well as the operand. No block scope needs to be created for this strategy.
    658 fn analyzeBodyInner(
    659     sema: *Sema,
    660     block: *Block,
    661     body: []const Zir.Inst.Index,
    662 ) CompileError!Zir.Inst.Index {
    663     // No tracy calls here, to avoid interfering with the tail call mechanism.
    664 
    665     const parent_capture_scope = block.wip_capture_scope;
    666 
    667     var wip_captures = WipCaptureScope{
    668         .finalized = true,
    669         .scope = parent_capture_scope,
    670         .perm_arena = sema.perm_arena,
    671         .gpa = sema.gpa,
    672     };
    673     defer if (wip_captures.scope != parent_capture_scope) {
    674         wip_captures.deinit();
    675     };
    676 
    677     const map = &sema.inst_map;
    678     const tags = sema.code.instructions.items(.tag);
    679     const datas = sema.code.instructions.items(.data);
    680 
    681     var orig_captures: usize = parent_capture_scope.captures.count();
    682 
    683     var crash_info = crash_report.prepAnalyzeBody(sema, block, body);
    684     crash_info.push();
    685     defer crash_info.pop();
    686 
    687     var dbg_block_begins: u32 = 0;
    688 
    689     // We use a while(true) loop here to avoid a redundant way of breaking out of
    690     // the loop. The only way to break out of the loop is with a `noreturn`
    691     // instruction.
    692     var i: usize = 0;
    693     const result = while (true) {
    694         crash_info.setBodyIndex(i);
    695         const inst = body[i];
    696         std.log.scoped(.sema_zir).debug("sema ZIR {s} %{d}", .{
    697             sema.mod.declPtr(block.src_decl).src_namespace.file_scope.sub_file_path, inst,
    698         });
    699         const air_inst: Air.Inst.Ref = switch (tags[inst]) {
    700             // zig fmt: off
    701             .alloc                        => try sema.zirAlloc(block, inst),
    702             .alloc_inferred               => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
    703             .alloc_inferred_mut           => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
    704             .alloc_inferred_comptime      => try sema.zirAllocInferredComptime(inst, Type.initTag(.inferred_alloc_const)),
    705             .alloc_inferred_comptime_mut  => try sema.zirAllocInferredComptime(inst, Type.initTag(.inferred_alloc_mut)),
    706             .alloc_mut                    => try sema.zirAllocMut(block, inst),
    707             .alloc_comptime_mut           => try sema.zirAllocComptime(block, inst),
    708             .make_ptr_const               => try sema.zirMakePtrConst(block, inst),
    709             .anyframe_type                => try sema.zirAnyframeType(block, inst),
    710             .array_cat                    => try sema.zirArrayCat(block, inst),
    711             .array_mul                    => try sema.zirArrayMul(block, inst),
    712             .array_type                   => try sema.zirArrayType(block, inst),
    713             .array_type_sentinel          => try sema.zirArrayTypeSentinel(block, inst),
    714             .vector_type                  => try sema.zirVectorType(block, inst),
    715             .as                           => try sema.zirAs(block, inst),
    716             .as_node                      => try sema.zirAsNode(block, inst),
    717             .as_shift_operand             => try sema.zirAsShiftOperand(block, inst),
    718             .bit_and                      => try sema.zirBitwise(block, inst, .bit_and),
    719             .bit_not                      => try sema.zirBitNot(block, inst),
    720             .bit_or                       => try sema.zirBitwise(block, inst, .bit_or),
    721             .bitcast                      => try sema.zirBitcast(block, inst),
    722             .suspend_block                => try sema.zirSuspendBlock(block, inst),
    723             .bool_not                     => try sema.zirBoolNot(block, inst),
    724             .bool_br_and                  => try sema.zirBoolBr(block, inst, false),
    725             .bool_br_or                   => try sema.zirBoolBr(block, inst, true),
    726             .c_import                     => try sema.zirCImport(block, inst),
    727             .call                         => try sema.zirCall(block, inst),
    728             .closure_get                  => try sema.zirClosureGet(block, inst),
    729             .cmp_lt                       => try sema.zirCmp(block, inst, .lt),
    730             .cmp_lte                      => try sema.zirCmp(block, inst, .lte),
    731             .cmp_eq                       => try sema.zirCmpEq(block, inst, .eq, Air.Inst.Tag.fromCmpOp(.eq, block.float_mode == .Optimized)),
    732             .cmp_gte                      => try sema.zirCmp(block, inst, .gte),
    733             .cmp_gt                       => try sema.zirCmp(block, inst, .gt),
    734             .cmp_neq                      => try sema.zirCmpEq(block, inst, .neq, Air.Inst.Tag.fromCmpOp(.neq, block.float_mode == .Optimized)),
    735             .coerce_result_ptr            => try sema.zirCoerceResultPtr(block, inst),
    736             .decl_ref                     => try sema.zirDeclRef(block, inst),
    737             .decl_val                     => try sema.zirDeclVal(block, inst),
    738             .load                         => try sema.zirLoad(block, inst),
    739             .elem_ptr                     => try sema.zirElemPtr(block, inst),
    740             .elem_ptr_node                => try sema.zirElemPtrNode(block, inst),
    741             .elem_ptr_imm                 => try sema.zirElemPtrImm(block, inst),
    742             .elem_val                     => try sema.zirElemVal(block, inst),
    743             .elem_val_node                => try sema.zirElemValNode(block, inst),
    744             .elem_type_index              => try sema.zirElemTypeIndex(block, inst),
    745             .enum_literal                 => try sema.zirEnumLiteral(block, inst),
    746             .enum_to_int                  => try sema.zirEnumToInt(block, inst),
    747             .int_to_enum                  => try sema.zirIntToEnum(block, inst),
    748             .err_union_code               => try sema.zirErrUnionCode(block, inst),
    749             .err_union_code_ptr           => try sema.zirErrUnionCodePtr(block, inst),
    750             .err_union_payload_unsafe     => try sema.zirErrUnionPayload(block, inst),
    751             .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst),
    752             .error_union_type             => try sema.zirErrorUnionType(block, inst),
    753             .error_value                  => try sema.zirErrorValue(block, inst),
    754             .field_ptr                    => try sema.zirFieldPtr(block, inst, false),
    755             .field_ptr_init               => try sema.zirFieldPtr(block, inst, true),
    756             .field_ptr_named              => try sema.zirFieldPtrNamed(block, inst),
    757             .field_val                    => try sema.zirFieldVal(block, inst),
    758             .field_val_named              => try sema.zirFieldValNamed(block, inst),
    759             .field_call_bind              => try sema.zirFieldCallBind(block, inst),
    760             .func                         => try sema.zirFunc(block, inst, false),
    761             .func_inferred                => try sema.zirFunc(block, inst, true),
    762             .func_fancy                   => try sema.zirFuncFancy(block, inst),
    763             .import                       => try sema.zirImport(block, inst),
    764             .indexable_ptr_len            => try sema.zirIndexablePtrLen(block, inst),
    765             .int                          => try sema.zirInt(block, inst),
    766             .int_big                      => try sema.zirIntBig(block, inst),
    767             .float                        => try sema.zirFloat(block, inst),
    768             .float128                     => try sema.zirFloat128(block, inst),
    769             .int_type                     => try sema.zirIntType(block, inst),
    770             .is_non_err                   => try sema.zirIsNonErr(block, inst),
    771             .is_non_err_ptr               => try sema.zirIsNonErrPtr(block, inst),
    772             .is_non_null                  => try sema.zirIsNonNull(block, inst),
    773             .is_non_null_ptr              => try sema.zirIsNonNullPtr(block, inst),
    774             .merge_error_sets             => try sema.zirMergeErrorSets(block, inst),
    775             .negate                       => try sema.zirNegate(block, inst),
    776             .negate_wrap                  => try sema.zirNegateWrap(block, inst),
    777             .optional_payload_safe        => try sema.zirOptionalPayload(block, inst, true),
    778             .optional_payload_safe_ptr    => try sema.zirOptionalPayloadPtr(block, inst, true),
    779             .optional_payload_unsafe      => try sema.zirOptionalPayload(block, inst, false),
    780             .optional_payload_unsafe_ptr  => try sema.zirOptionalPayloadPtr(block, inst, false),
    781             .optional_type                => try sema.zirOptionalType(block, inst),
    782             .ptr_type                     => try sema.zirPtrType(block, inst),
    783             .overflow_arithmetic_ptr      => try sema.zirOverflowArithmeticPtr(block, inst),
    784             .ref                          => try sema.zirRef(block, inst),
    785             .ret_err_value_code           => try sema.zirRetErrValueCode(inst),
    786             .shr                          => try sema.zirShr(block, inst, .shr),
    787             .shr_exact                    => try sema.zirShr(block, inst, .shr_exact),
    788             .slice_end                    => try sema.zirSliceEnd(block, inst),
    789             .slice_sentinel               => try sema.zirSliceSentinel(block, inst),
    790             .slice_start                  => try sema.zirSliceStart(block, inst),
    791             .str                          => try sema.zirStr(block, inst),
    792             .switch_block                 => try sema.zirSwitchBlock(block, inst),
    793             .switch_cond                  => try sema.zirSwitchCond(block, inst, false),
    794             .switch_cond_ref              => try sema.zirSwitchCond(block, inst, true),
    795             .switch_capture               => try sema.zirSwitchCapture(block, inst, false, false),
    796             .switch_capture_ref           => try sema.zirSwitchCapture(block, inst, false, true),
    797             .switch_capture_multi         => try sema.zirSwitchCapture(block, inst, true, false),
    798             .switch_capture_multi_ref     => try sema.zirSwitchCapture(block, inst, true, true),
    799             .type_info                    => try sema.zirTypeInfo(block, inst),
    800             .size_of                      => try sema.zirSizeOf(block, inst),
    801             .bit_size_of                  => try sema.zirBitSizeOf(block, inst),
    802             .typeof                       => try sema.zirTypeof(block, inst),
    803             .typeof_builtin               => try sema.zirTypeofBuiltin(block, inst),
    804             .log2_int_type                => try sema.zirLog2IntType(block, inst),
    805             .typeof_log2_int_type         => try sema.zirTypeofLog2IntType(block, inst),
    806             .xor                          => try sema.zirBitwise(block, inst, .xor),
    807             .struct_init_empty            => try sema.zirStructInitEmpty(block, inst),
    808             .struct_init                  => try sema.zirStructInit(block, inst, false),
    809             .struct_init_ref              => try sema.zirStructInit(block, inst, true),
    810             .struct_init_anon             => try sema.zirStructInitAnon(block, inst, false),
    811             .struct_init_anon_ref         => try sema.zirStructInitAnon(block, inst, true),
    812             .array_init                   => try sema.zirArrayInit(block, inst, false),
    813             .array_init_ref               => try sema.zirArrayInit(block, inst, true),
    814             .array_init_anon              => try sema.zirArrayInitAnon(block, inst, false),
    815             .array_init_anon_ref          => try sema.zirArrayInitAnon(block, inst, true),
    816             .union_init                   => try sema.zirUnionInit(block, inst),
    817             .field_type                   => try sema.zirFieldType(block, inst),
    818             .field_type_ref               => try sema.zirFieldTypeRef(block, inst),
    819             .ptr_to_int                   => try sema.zirPtrToInt(block, inst),
    820             .align_of                     => try sema.zirAlignOf(block, inst),
    821             .bool_to_int                  => try sema.zirBoolToInt(block, inst),
    822             .embed_file                   => try sema.zirEmbedFile(block, inst),
    823             .error_name                   => try sema.zirErrorName(block, inst),
    824             .tag_name                     => try sema.zirTagName(block, inst),
    825             .type_name                    => try sema.zirTypeName(block, inst),
    826             .frame_type                   => try sema.zirFrameType(block, inst),
    827             .frame_size                   => try sema.zirFrameSize(block, inst),
    828             .float_to_int                 => try sema.zirFloatToInt(block, inst),
    829             .int_to_float                 => try sema.zirIntToFloat(block, inst),
    830             .int_to_ptr                   => try sema.zirIntToPtr(block, inst),
    831             .float_cast                   => try sema.zirFloatCast(block, inst),
    832             .int_cast                     => try sema.zirIntCast(block, inst),
    833             .ptr_cast                     => try sema.zirPtrCast(block, inst),
    834             .truncate                     => try sema.zirTruncate(block, inst),
    835             .align_cast                   => try sema.zirAlignCast(block, inst),
    836             .has_decl                     => try sema.zirHasDecl(block, inst),
    837             .has_field                    => try sema.zirHasField(block, inst),
    838             .byte_swap                    => try sema.zirByteSwap(block, inst),
    839             .bit_reverse                  => try sema.zirBitReverse(block, inst),
    840             .bit_offset_of                => try sema.zirBitOffsetOf(block, inst),
    841             .offset_of                    => try sema.zirOffsetOf(block, inst),
    842             .splat                        => try sema.zirSplat(block, inst),
    843             .reduce                       => try sema.zirReduce(block, inst),
    844             .shuffle                      => try sema.zirShuffle(block, inst),
    845             .atomic_load                  => try sema.zirAtomicLoad(block, inst),
    846             .atomic_rmw                   => try sema.zirAtomicRmw(block, inst),
    847             .mul_add                      => try sema.zirMulAdd(block, inst),
    848             .builtin_call                 => try sema.zirBuiltinCall(block, inst),
    849             .field_parent_ptr             => try sema.zirFieldParentPtr(block, inst),
    850             .@"resume"                    => try sema.zirResume(block, inst),
    851             .@"await"                     => try sema.zirAwait(block, inst),
    852             .array_base_ptr               => try sema.zirArrayBasePtr(block, inst),
    853             .field_base_ptr               => try sema.zirFieldBasePtr(block, inst),
    854 
    855             .clz       => try sema.zirBitCount(block, inst, .clz,      Value.clz),
    856             .ctz       => try sema.zirBitCount(block, inst, .ctz,      Value.ctz),
    857             .pop_count => try sema.zirBitCount(block, inst, .popcount, Value.popCount),
    858 
    859             .sqrt  => try sema.zirUnaryMath(block, inst, .sqrt, Value.sqrt),
    860             .sin   => try sema.zirUnaryMath(block, inst, .sin, Value.sin),
    861             .cos   => try sema.zirUnaryMath(block, inst, .cos, Value.cos),
    862             .tan   => try sema.zirUnaryMath(block, inst, .tan, Value.tan),
    863             .exp   => try sema.zirUnaryMath(block, inst, .exp, Value.exp),
    864             .exp2  => try sema.zirUnaryMath(block, inst, .exp2, Value.exp2),
    865             .log   => try sema.zirUnaryMath(block, inst, .log, Value.log),
    866             .log2  => try sema.zirUnaryMath(block, inst, .log2, Value.log2),
    867             .log10 => try sema.zirUnaryMath(block, inst, .log10, Value.log10),
    868             .fabs  => try sema.zirUnaryMath(block, inst, .fabs, Value.fabs),
    869             .floor => try sema.zirUnaryMath(block, inst, .floor, Value.floor),
    870             .ceil  => try sema.zirUnaryMath(block, inst, .ceil, Value.ceil),
    871             .round => try sema.zirUnaryMath(block, inst, .round, Value.round),
    872             .trunc => try sema.zirUnaryMath(block, inst, .trunc_float, Value.trunc),
    873 
    874             .error_set_decl      => try sema.zirErrorSetDecl(block, inst, .parent),
    875             .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
    876             .error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func),
    877 
    878             .add       => try sema.zirArithmetic(block, inst, .add),
    879             .addwrap   => try sema.zirArithmetic(block, inst, .addwrap),
    880             .add_sat   => try sema.zirArithmetic(block, inst, .add_sat),
    881             .mul       => try sema.zirArithmetic(block, inst, .mul),
    882             .mulwrap   => try sema.zirArithmetic(block, inst, .mulwrap),
    883             .mul_sat   => try sema.zirArithmetic(block, inst, .mul_sat),
    884             .sub       => try sema.zirArithmetic(block, inst, .sub),
    885             .subwrap   => try sema.zirArithmetic(block, inst, .subwrap),
    886             .sub_sat   => try sema.zirArithmetic(block, inst, .sub_sat),
    887 
    888             .div       => try sema.zirDiv(block, inst),
    889             .div_exact => try sema.zirDivExact(block, inst),
    890             .div_floor => try sema.zirDivFloor(block, inst),
    891             .div_trunc => try sema.zirDivTrunc(block, inst),
    892 
    893             .mod_rem   => try sema.zirModRem(block, inst),
    894             .mod       => try sema.zirMod(block, inst),
    895             .rem       => try sema.zirRem(block, inst),
    896 
    897             .maximum => try sema.zirMinMax(block, inst, .max),
    898             .minimum => try sema.zirMinMax(block, inst, .min),
    899 
    900             .shl       => try sema.zirShl(block, inst, .shl),
    901             .shl_exact => try sema.zirShl(block, inst, .shl_exact),
    902             .shl_sat   => try sema.zirShl(block, inst, .shl_sat),
    903 
    904             .ret_ptr  => try sema.zirRetPtr(block, inst),
    905             .ret_type => try sema.addType(sema.fn_ret_ty),
    906 
    907             // Instructions that we know to *always* be noreturn based solely on their tag.
    908             // These functions match the return type of analyzeBody so that we can
    909             // tail call them here.
    910             .compile_error  => break sema.zirCompileError(block, inst),
    911             .ret_tok        => break sema.zirRetTok(block, inst),
    912             .ret_node       => break sema.zirRetNode(block, inst),
    913             .ret_load       => break sema.zirRetLoad(block, inst),
    914             .ret_err_value  => break sema.zirRetErrValue(block, inst),
    915             .@"unreachable" => break sema.zirUnreachable(block, inst),
    916             .panic          => break sema.zirPanic(block, inst, false),
    917             .panic_comptime => break sema.zirPanic(block, inst, true),
    918             // zig fmt: on
    919 
    920             .extended => ext: {
    921                 const extended = datas[inst].extended;
    922                 break :ext switch (extended.opcode) {
    923                     // zig fmt: off
    924                     .variable              => try sema.zirVarExtended(       block, extended),
    925                     .struct_decl           => try sema.zirStructDecl(        block, extended, inst),
    926                     .enum_decl             => try sema.zirEnumDecl(          block, extended, inst),
    927                     .union_decl            => try sema.zirUnionDecl(         block, extended, inst),
    928                     .opaque_decl           => try sema.zirOpaqueDecl(        block, extended, inst),
    929                     .this                  => try sema.zirThis(              block, extended),
    930                     .ret_addr              => try sema.zirRetAddr(           block, extended),
    931                     .builtin_src           => try sema.zirBuiltinSrc(        block, extended),
    932                     .error_return_trace    => try sema.zirErrorReturnTrace(  block, extended),
    933                     .frame                 => try sema.zirFrame(             block, extended),
    934                     .frame_address         => try sema.zirFrameAddress(      block, extended),
    935                     .alloc                 => try sema.zirAllocExtended(     block, extended),
    936                     .builtin_extern        => try sema.zirBuiltinExtern(     block, extended),
    937                     .@"asm"                => try sema.zirAsm(               block, extended),
    938                     .typeof_peer           => try sema.zirTypeofPeer(        block, extended),
    939                     .compile_log           => try sema.zirCompileLog(        block, extended),
    940                     .add_with_overflow     => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
    941                     .sub_with_overflow     => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
    942                     .mul_with_overflow     => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
    943                     .shl_with_overflow     => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
    944                     .c_undef               => try sema.zirCUndef(            block, extended),
    945                     .c_include             => try sema.zirCInclude(          block, extended),
    946                     .c_define              => try sema.zirCDefine(           block, extended),
    947                     .wasm_memory_size      => try sema.zirWasmMemorySize(    block, extended),
    948                     .wasm_memory_grow      => try sema.zirWasmMemoryGrow(    block, extended),
    949                     .prefetch              => try sema.zirPrefetch(          block, extended),
    950                     .field_call_bind_named => try sema.zirFieldCallBindNamed(block, extended),
    951                     .err_set_cast          => try sema.zirErrSetCast(        block, extended),
    952                     .await_nosuspend       => try sema.zirAwaitNosuspend(    block, extended),
    953                     .select                => try sema.zirSelect(            block, extended),
    954                     .error_to_int          => try sema.zirErrorToInt(        block, extended),
    955                     .int_to_error          => try sema.zirIntToError(        block, extended),
    956                     .reify                 => try sema.zirReify(             block, extended, inst),
    957                     .builtin_async_call    => try sema.zirBuiltinAsyncCall(  block, extended),
    958                     .cmpxchg               => try sema.zirCmpxchg(           block, extended),
    959 
    960                     // zig fmt: on
    961                     .fence => {
    962                         try sema.zirFence(block, extended);
    963                         i += 1;
    964                         continue;
    965                     },
    966                     .set_float_mode => {
    967                         try sema.zirSetFloatMode(block, extended);
    968                         i += 1;
    969                         continue;
    970                     },
    971                     .set_align_stack => {
    972                         try sema.zirSetAlignStack(block, extended);
    973                         i += 1;
    974                         continue;
    975                     },
    976                     .breakpoint => {
    977                         if (!block.is_comptime) {
    978                             _ = try block.addNoOp(.breakpoint);
    979                         }
    980                         i += 1;
    981                         continue;
    982                     },
    983                 };
    984             },
    985 
    986             // Instructions that we know can *never* be noreturn based solely on
    987             // their tag. We avoid needlessly checking if they are noreturn and
    988             // continue the loop.
    989             // We also know that they cannot be referenced later, so we avoid
    990             // putting them into the map.
    991             .dbg_stmt => {
    992                 try sema.zirDbgStmt(block, inst);
    993                 i += 1;
    994                 continue;
    995             },
    996             .dbg_var_ptr => {
    997                 try sema.zirDbgVar(block, inst, .dbg_var_ptr);
    998                 i += 1;
    999                 continue;
   1000             },
   1001             .dbg_var_val => {
   1002                 try sema.zirDbgVar(block, inst, .dbg_var_val);
   1003                 i += 1;
   1004                 continue;
   1005             },
   1006             .dbg_block_begin => {
   1007                 dbg_block_begins += 1;
   1008                 try sema.zirDbgBlockBegin(block);
   1009                 i += 1;
   1010                 continue;
   1011             },
   1012             .dbg_block_end => {
   1013                 dbg_block_begins -= 1;
   1014                 try sema.zirDbgBlockEnd(block);
   1015                 i += 1;
   1016                 continue;
   1017             },
   1018             .ensure_err_payload_void => {
   1019                 try sema.zirEnsureErrPayloadVoid(block, inst);
   1020                 i += 1;
   1021                 continue;
   1022             },
   1023             .ensure_result_non_error => {
   1024                 try sema.zirEnsureResultNonError(block, inst);
   1025                 i += 1;
   1026                 continue;
   1027             },
   1028             .ensure_result_used => {
   1029                 try sema.zirEnsureResultUsed(block, inst);
   1030                 i += 1;
   1031                 continue;
   1032             },
   1033             .set_eval_branch_quota => {
   1034                 try sema.zirSetEvalBranchQuota(block, inst);
   1035                 i += 1;
   1036                 continue;
   1037             },
   1038             .atomic_store => {
   1039                 try sema.zirAtomicStore(block, inst);
   1040                 i += 1;
   1041                 continue;
   1042             },
   1043             .store => {
   1044                 try sema.zirStore(block, inst);
   1045                 i += 1;
   1046                 continue;
   1047             },
   1048             .store_node => {
   1049                 try sema.zirStoreNode(block, inst);
   1050                 i += 1;
   1051                 continue;
   1052             },
   1053             .store_to_block_ptr => {
   1054                 try sema.zirStoreToBlockPtr(block, inst);
   1055                 i += 1;
   1056                 continue;
   1057             },
   1058             .store_to_inferred_ptr => {
   1059                 try sema.zirStoreToInferredPtr(block, inst);
   1060                 i += 1;
   1061                 continue;
   1062             },
   1063             .resolve_inferred_alloc => {
   1064                 try sema.zirResolveInferredAlloc(block, inst);
   1065                 i += 1;
   1066                 continue;
   1067             },
   1068             .validate_array_init_ty => {
   1069                 try sema.validateArrayInitTy(block, inst);
   1070                 i += 1;
   1071                 continue;
   1072             },
   1073             .validate_struct_init_ty => {
   1074                 try sema.validateStructInitTy(block, inst);
   1075                 i += 1;
   1076                 continue;
   1077             },
   1078             .validate_struct_init => {
   1079                 try sema.zirValidateStructInit(block, inst, false);
   1080                 i += 1;
   1081                 continue;
   1082             },
   1083             .validate_struct_init_comptime => {
   1084                 try sema.zirValidateStructInit(block, inst, true);
   1085                 i += 1;
   1086                 continue;
   1087             },
   1088             .validate_array_init => {
   1089                 try sema.zirValidateArrayInit(block, inst, false);
   1090                 i += 1;
   1091                 continue;
   1092             },
   1093             .validate_array_init_comptime => {
   1094                 try sema.zirValidateArrayInit(block, inst, true);
   1095                 i += 1;
   1096                 continue;
   1097             },
   1098             .validate_deref => {
   1099                 try sema.zirValidateDeref(block, inst);
   1100                 i += 1;
   1101                 continue;
   1102             },
   1103             .@"export" => {
   1104                 try sema.zirExport(block, inst);
   1105                 i += 1;
   1106                 continue;
   1107             },
   1108             .export_value => {
   1109                 try sema.zirExportValue(block, inst);
   1110                 i += 1;
   1111                 continue;
   1112             },
   1113             .set_cold => {
   1114                 try sema.zirSetCold(block, inst);
   1115                 i += 1;
   1116                 continue;
   1117             },
   1118             .set_runtime_safety => {
   1119                 try sema.zirSetRuntimeSafety(block, inst);
   1120                 i += 1;
   1121                 continue;
   1122             },
   1123             .param => {
   1124                 try sema.zirParam(block, inst, false);
   1125                 i += 1;
   1126                 continue;
   1127             },
   1128             .param_comptime => {
   1129                 try sema.zirParam(block, inst, true);
   1130                 i += 1;
   1131                 continue;
   1132             },
   1133             .param_anytype => {
   1134                 try sema.zirParamAnytype(block, inst, false);
   1135                 i += 1;
   1136                 continue;
   1137             },
   1138             .param_anytype_comptime => {
   1139                 try sema.zirParamAnytype(block, inst, true);
   1140                 i += 1;
   1141                 continue;
   1142             },
   1143             .closure_capture => {
   1144                 try sema.zirClosureCapture(block, inst);
   1145                 i += 1;
   1146                 continue;
   1147             },
   1148             .memcpy => {
   1149                 try sema.zirMemcpy(block, inst);
   1150                 i += 1;
   1151                 continue;
   1152             },
   1153             .memset => {
   1154                 try sema.zirMemset(block, inst);
   1155                 i += 1;
   1156                 continue;
   1157             },
   1158             .check_comptime_control_flow => {
   1159                 if (!block.is_comptime) {
   1160                     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   1161                     const src = inst_data.src();
   1162                     const inline_block = Zir.refToIndex(inst_data.operand).?;
   1163 
   1164                     var check_block = block;
   1165                     const target_runtime_index = while (true) {
   1166                         if (check_block.inline_block == inline_block) {
   1167                             break check_block.runtime_index;
   1168                         }
   1169                         check_block = check_block.parent.?;
   1170                     } else unreachable;
   1171 
   1172                     if (@enumToInt(target_runtime_index) < @enumToInt(block.runtime_index)) {
   1173                         const runtime_src = block.runtime_cond orelse block.runtime_loop.?;
   1174                         const msg = msg: {
   1175                             const msg = try sema.errMsg(block, src, "comptime control flow inside runtime block", .{});
   1176                             errdefer msg.destroy(sema.gpa);
   1177 
   1178                             try sema.errNote(block, runtime_src, msg, "runtime control flow here", .{});
   1179                             break :msg msg;
   1180                         };
   1181                         return sema.failWithOwnedErrorMsg(msg);
   1182                     }
   1183                 }
   1184                 i += 1;
   1185                 continue;
   1186             },
   1187 
   1188             // Special case instructions to handle comptime control flow.
   1189             .@"break" => {
   1190                 if (block.is_comptime) {
   1191                     break inst; // same as break_inline
   1192                 } else {
   1193                     break sema.zirBreak(block, inst);
   1194                 }
   1195             },
   1196             .break_inline => {
   1197                 if (block.is_comptime) {
   1198                     break inst;
   1199                 } else {
   1200                     sema.comptime_break_inst = inst;
   1201                     return error.ComptimeBreak;
   1202                 }
   1203             },
   1204             .repeat => {
   1205                 if (block.is_comptime) {
   1206                     // Send comptime control flow back to the beginning of this block.
   1207                     const src = LazySrcLoc.nodeOffset(datas[inst].node);
   1208                     try sema.emitBackwardBranch(block, src);
   1209                     if (wip_captures.scope.captures.count() != orig_captures) {
   1210                         try wip_captures.reset(parent_capture_scope);
   1211                         block.wip_capture_scope = wip_captures.scope;
   1212                         orig_captures = 0;
   1213                     }
   1214                     i = 0;
   1215                     continue;
   1216                 } else {
   1217                     const src_node = sema.code.instructions.items(.data)[inst].node;
   1218                     const src = LazySrcLoc.nodeOffset(src_node);
   1219                     try sema.requireFunctionBlock(block, src);
   1220                     break always_noreturn;
   1221                 }
   1222             },
   1223             .repeat_inline => {
   1224                 // Send comptime control flow back to the beginning of this block.
   1225                 const src = LazySrcLoc.nodeOffset(datas[inst].node);
   1226                 try sema.emitBackwardBranch(block, src);
   1227                 if (wip_captures.scope.captures.count() != orig_captures) {
   1228                     try wip_captures.reset(parent_capture_scope);
   1229                     block.wip_capture_scope = wip_captures.scope;
   1230                     orig_captures = 0;
   1231                 }
   1232                 i = 0;
   1233                 continue;
   1234             },
   1235             .loop => blk: {
   1236                 if (!block.is_comptime) break :blk try sema.zirLoop(block, inst);
   1237                 // Same as `block_inline`. TODO https://github.com/ziglang/zig/issues/8220
   1238                 const inst_data = datas[inst].pl_node;
   1239                 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
   1240                 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
   1241                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
   1242                     break always_noreturn;
   1243                 if (inst == break_data.block_inst) {
   1244                     break :blk try sema.resolveInst(break_data.operand);
   1245                 } else {
   1246                     break break_data.inst;
   1247                 }
   1248             },
   1249             .block => blk: {
   1250                 if (!block.is_comptime) break :blk try sema.zirBlock(block, inst);
   1251                 // Same as `block_inline`. TODO https://github.com/ziglang/zig/issues/8220
   1252                 const inst_data = datas[inst].pl_node;
   1253                 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
   1254                 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
   1255                 // If this block contains a function prototype, we need to reset the
   1256                 // current list of parameters and restore it later.
   1257                 // Note: this probably needs to be resolved in a more general manner.
   1258                 const prev_params = block.params;
   1259                 block.params = .{};
   1260                 defer {
   1261                     block.params.deinit(sema.gpa);
   1262                     block.params = prev_params;
   1263                 }
   1264                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
   1265                     break always_noreturn;
   1266                 if (inst == break_data.block_inst) {
   1267                     break :blk try sema.resolveInst(break_data.operand);
   1268                 } else {
   1269                     break break_data.inst;
   1270                 }
   1271             },
   1272             .block_inline => blk: {
   1273                 // Directly analyze the block body without introducing a new block.
   1274                 // However, in the case of a corresponding break_inline which reaches
   1275                 // through a runtime conditional branch, we must retroactively emit
   1276                 // a block, so we remember the block index here just in case.
   1277                 const block_index = block.instructions.items.len;
   1278                 const inst_data = datas[inst].pl_node;
   1279                 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
   1280                 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
   1281                 const gpa = sema.gpa;
   1282                 // If this block contains a function prototype, we need to reset the
   1283                 // current list of parameters and restore it later.
   1284                 // Note: this probably needs to be resolved in a more general manner.
   1285                 const prev_params = block.params;
   1286                 const prev_inline_block = block.inline_block;
   1287                 if (tags[inline_body[inline_body.len - 1]] == .repeat_inline) {
   1288                     block.inline_block = inline_body[0];
   1289                 }
   1290                 block.params = .{};
   1291                 defer {
   1292                     block.params.deinit(gpa);
   1293                     block.params = prev_params;
   1294                     block.inline_block = prev_inline_block;
   1295                 }
   1296                 const opt_break_data = try sema.analyzeBodyBreak(block, inline_body);
   1297                 // A runtime conditional branch that needs a post-hoc block to be
   1298                 // emitted communicates this by mapping the block index into the inst map.
   1299                 if (map.get(inst)) |new_block_ref| ph: {
   1300                     // Comptime control flow populates the map, so we don't actually know
   1301                     // if this is a post-hoc runtime block until we check the
   1302                     // post_hoc_block map.
   1303                     const new_block_inst = Air.refToIndex(new_block_ref) orelse break :ph;
   1304                     const labeled_block = sema.post_hoc_blocks.get(new_block_inst) orelse
   1305                         break :ph;
   1306 
   1307                     // In this case we need to move all the instructions starting at
   1308                     // block_index from the current block into this new one.
   1309 
   1310                     if (opt_break_data) |break_data| {
   1311                         // This is a comptime break which we now change to a runtime break
   1312                         // since it crosses a runtime branch.
   1313                         // It may pass through our currently being analyzed block_inline or it
   1314                         // may point directly to it. In the latter case, this modifies the
   1315                         // block that we are about to look up in the post_hoc_blocks map below.
   1316                         try sema.addRuntimeBreak(block, break_data);
   1317                     } else {
   1318                         // Here the comptime control flow ends with noreturn; however
   1319                         // we have runtime control flow continuing after this block.
   1320                         // This branch is therefore handled by the `i += 1; continue;`
   1321                         // logic below.
   1322                     }
   1323 
   1324                     try labeled_block.block.instructions.appendSlice(gpa, block.instructions.items[block_index..]);
   1325                     block.instructions.items.len = block_index;
   1326 
   1327                     const block_result = try sema.analyzeBlockBody(block, inst_data.src(), &labeled_block.block, &labeled_block.label.merges);
   1328                     {
   1329                         // Destroy the ad-hoc block entry so that it does not interfere with
   1330                         // the next iteration of comptime control flow, if any.
   1331                         labeled_block.destroy(gpa);
   1332                         assert(sema.post_hoc_blocks.remove(new_block_inst));
   1333                     }
   1334                     try map.put(gpa, inst, block_result);
   1335                     i += 1;
   1336                     continue;
   1337                 }
   1338 
   1339                 const break_data = opt_break_data orelse break always_noreturn;
   1340                 if (inst == break_data.block_inst) {
   1341                     break :blk try sema.resolveInst(break_data.operand);
   1342                 } else {
   1343                     break break_data.inst;
   1344                 }
   1345             },
   1346             .condbr => blk: {
   1347                 if (!block.is_comptime) break sema.zirCondbr(block, inst);
   1348                 // Same as condbr_inline. TODO https://github.com/ziglang/zig/issues/8220
   1349                 const inst_data = datas[inst].pl_node;
   1350                 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
   1351                 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
   1352                 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
   1353                 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
   1354                 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime known");
   1355                 const inline_body = if (cond.val.toBool()) then_body else else_body;
   1356 
   1357                 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src);
   1358                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
   1359                     break always_noreturn;
   1360                 if (inst == break_data.block_inst) {
   1361                     break :blk try sema.resolveInst(break_data.operand);
   1362                 } else {
   1363                     break break_data.inst;
   1364                 }
   1365             },
   1366             .condbr_inline => blk: {
   1367                 const inst_data = datas[inst].pl_node;
   1368                 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
   1369                 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
   1370                 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
   1371                 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
   1372                 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime known");
   1373                 const inline_body = if (cond.val.toBool()) then_body else else_body;
   1374                 const old_runtime_index = block.runtime_index;
   1375                 defer block.runtime_index = old_runtime_index;
   1376                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
   1377                     break always_noreturn;
   1378                 if (inst == break_data.block_inst) {
   1379                     break :blk try sema.resolveInst(break_data.operand);
   1380                 } else {
   1381                     break break_data.inst;
   1382                 }
   1383             },
   1384             .@"try" => blk: {
   1385                 if (!block.is_comptime) break :blk try sema.zirTry(block, inst);
   1386                 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1387                 const src = inst_data.src();
   1388                 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   1389                 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
   1390                 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
   1391                 const err_union = try sema.resolveInst(extra.data.operand);
   1392                 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);
   1393                 assert(is_non_err != .none);
   1394                 const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err, "try operand inside comptime block must be comptime known");
   1395                 if (is_non_err_tv.val.toBool()) {
   1396                     const err_union_ty = sema.typeOf(err_union);
   1397                     break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false);
   1398                 }
   1399                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
   1400                     break always_noreturn;
   1401                 if (inst == break_data.block_inst) {
   1402                     break :blk try sema.resolveInst(break_data.operand);
   1403                 } else {
   1404                     break break_data.inst;
   1405                 }
   1406             },
   1407             //.try_inline => blk: {
   1408             //    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1409             //    const src = inst_data.src();
   1410             //    const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   1411             //    const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
   1412             //    const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
   1413             //    const operand = try sema.resolveInst(extra.data.operand);
   1414             //    const operand_ty = sema.typeOf(operand);
   1415             //    const is_ptr = operand_ty.zigTypeTag() == .Pointer;
   1416             //    const err_union = if (is_ptr)
   1417             //        try sema.analyzeLoad(block, src, operand, operand_src)
   1418             //    else
   1419             //        operand;
   1420             //    const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);
   1421             //    assert(is_non_err != .none);
   1422             //    const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err);
   1423             //    if (is_non_err_tv.val.toBool()) {
   1424             //        if (is_ptr) {
   1425             //            break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
   1426             //        } else {
   1427             //            const err_union_ty = sema.typeOf(err_union);
   1428             //            break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false);
   1429             //        }
   1430             //    }
   1431             //    const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
   1432             //        break always_noreturn;
   1433             //    if (inst == break_data.block_inst) {
   1434             //        break :blk try sema.resolveInst(break_data.operand);
   1435             //    } else {
   1436             //        break break_data.inst;
   1437             //    }
   1438             //},
   1439             .try_ptr => blk: {
   1440                 if (!block.is_comptime) break :blk try sema.zirTryPtr(block, inst);
   1441                 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1442                 const src = inst_data.src();
   1443                 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   1444                 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
   1445                 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
   1446                 const operand = try sema.resolveInst(extra.data.operand);
   1447                 const err_union = try sema.analyzeLoad(block, src, operand, operand_src);
   1448                 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);
   1449                 assert(is_non_err != .none);
   1450                 const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err, "try operand inside comptime block must be comptime known");
   1451                 if (is_non_err_tv.val.toBool()) {
   1452                     break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
   1453                 }
   1454                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
   1455                     break always_noreturn;
   1456                 if (inst == break_data.block_inst) {
   1457                     break :blk try sema.resolveInst(break_data.operand);
   1458                 } else {
   1459                     break break_data.inst;
   1460                 }
   1461             },
   1462             //.try_ptr_inline => blk: {
   1463             //    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1464             //    const src = inst_data.src();
   1465             //    const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   1466             //    const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
   1467             //    const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
   1468             //    const operand = try sema.resolveInst(extra.data.operand);
   1469             //    const err_union = try sema.analyzeLoad(block, src, operand, operand_src);
   1470             //    const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);
   1471             //    assert(is_non_err != .none);
   1472             //    const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err);
   1473             //    if (is_non_err_tv.val.toBool()) {
   1474             //        break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
   1475             //    }
   1476             //    const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
   1477             //        break always_noreturn;
   1478             //    if (inst == break_data.block_inst) {
   1479             //        break :blk try sema.resolveInst(break_data.operand);
   1480             //    } else {
   1481             //        break break_data.inst;
   1482             //    }
   1483             //},
   1484             .@"defer" => blk: {
   1485                 const inst_data = sema.code.instructions.items(.data)[inst].@"defer";
   1486                 const defer_body = sema.code.extra[inst_data.index..][0..inst_data.len];
   1487                 const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) {
   1488                     error.ComptimeBreak => sema.comptime_break_inst,
   1489                     else => |e| return e,
   1490                 };
   1491                 if (break_inst != defer_body[defer_body.len - 1]) break always_noreturn;
   1492                 break :blk Air.Inst.Ref.void_value;
   1493             },
   1494             .defer_err_code => blk: {
   1495                 const inst_data = sema.code.instructions.items(.data)[inst].defer_err_code;
   1496                 const extra = sema.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data;
   1497                 const defer_body = sema.code.extra[extra.index..][0..extra.len];
   1498                 const err_code = try sema.resolveInst(inst_data.err_code);
   1499                 try sema.inst_map.put(sema.gpa, extra.remapped_err_code, err_code);
   1500                 const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) {
   1501                     error.ComptimeBreak => sema.comptime_break_inst,
   1502                     else => |e| return e,
   1503                 };
   1504                 if (break_inst != defer_body[defer_body.len - 1]) break always_noreturn;
   1505                 break :blk Air.Inst.Ref.void_value;
   1506             },
   1507         };
   1508         if (sema.typeOf(air_inst).isNoReturn())
   1509             break always_noreturn;
   1510         try map.put(sema.gpa, inst, air_inst);
   1511         i += 1;
   1512     } else unreachable;
   1513 
   1514     // balance out dbg_block_begins in case of early noreturn
   1515     const noreturn_inst = block.instructions.popOrNull();
   1516     while (dbg_block_begins > 0) {
   1517         dbg_block_begins -= 1;
   1518         if (block.is_comptime or sema.mod.comp.bin_file.options.strip) continue;
   1519 
   1520         _ = try block.addInst(.{
   1521             .tag = .dbg_block_end,
   1522             .data = undefined,
   1523         });
   1524     }
   1525     if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some);
   1526 
   1527     if (!wip_captures.finalized) {
   1528         try wip_captures.finalize();
   1529         block.wip_capture_scope = parent_capture_scope;
   1530     }
   1531 
   1532     return result;
   1533 }
   1534 
   1535 pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
   1536     var i: usize = @enumToInt(zir_ref);
   1537 
   1538     // First section of indexes correspond to a set number of constant values.
   1539     if (i < Zir.Inst.Ref.typed_value_map.len) {
   1540         // We intentionally map the same indexes to the same values between ZIR and AIR.
   1541         return zir_ref;
   1542     }
   1543     i -= Zir.Inst.Ref.typed_value_map.len;
   1544 
   1545     // Finally, the last section of indexes refers to the map of ZIR=>AIR.
   1546     const inst = sema.inst_map.get(@intCast(u32, i)).?;
   1547     const ty = sema.typeOf(inst);
   1548     if (ty.tag() == .generic_poison) return error.GenericPoison;
   1549     return inst;
   1550 }
   1551 
   1552 fn resolveConstBool(
   1553     sema: *Sema,
   1554     block: *Block,
   1555     src: LazySrcLoc,
   1556     zir_ref: Zir.Inst.Ref,
   1557     reason: []const u8,
   1558 ) !bool {
   1559     const air_inst = try sema.resolveInst(zir_ref);
   1560     const wanted_type = Type.bool;
   1561     const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
   1562     const val = try sema.resolveConstValue(block, src, coerced_inst, reason);
   1563     return val.toBool();
   1564 }
   1565 
   1566 pub fn resolveConstString(
   1567     sema: *Sema,
   1568     block: *Block,
   1569     src: LazySrcLoc,
   1570     zir_ref: Zir.Inst.Ref,
   1571     reason: []const u8,
   1572 ) ![]u8 {
   1573     const air_inst = try sema.resolveInst(zir_ref);
   1574     const wanted_type = Type.initTag(.const_slice_u8);
   1575     const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
   1576     const val = try sema.resolveConstValue(block, src, coerced_inst, reason);
   1577     return val.toAllocatedBytes(wanted_type, sema.arena, sema.mod);
   1578 }
   1579 
   1580 pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type {
   1581     const air_inst = try sema.resolveInst(zir_ref);
   1582     const ty = try sema.analyzeAsType(block, src, air_inst);
   1583     if (ty.tag() == .generic_poison) return error.GenericPoison;
   1584     return ty;
   1585 }
   1586 
   1587 fn analyzeAsType(
   1588     sema: *Sema,
   1589     block: *Block,
   1590     src: LazySrcLoc,
   1591     air_inst: Air.Inst.Ref,
   1592 ) !Type {
   1593     const wanted_type = Type.initTag(.@"type");
   1594     const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
   1595     const val = try sema.resolveConstValue(block, src, coerced_inst, "types must be comptime known");
   1596     var buffer: Value.ToTypeBuffer = undefined;
   1597     const ty = val.toType(&buffer);
   1598     return ty.copy(sema.arena);
   1599 }
   1600 
   1601 pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void {
   1602     const backend_supports_error_return_tracing =
   1603         sema.mod.comp.bin_file.options.use_llvm;
   1604     if (!backend_supports_error_return_tracing) {
   1605         // TODO implement this feature in all the backends and then delete this branch
   1606         return;
   1607     }
   1608 
   1609     var err_trace_block = block.makeSubBlock();
   1610     err_trace_block.is_comptime = false;
   1611     defer err_trace_block.instructions.deinit(sema.gpa);
   1612 
   1613     const src: LazySrcLoc = .unneeded;
   1614 
   1615     // var addrs: [err_return_trace_addr_count]usize = undefined;
   1616     const err_return_trace_addr_count = 32;
   1617     const addr_arr_ty = try Type.array(sema.arena, err_return_trace_addr_count, null, Type.usize, sema.mod);
   1618     const addrs_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, addr_arr_ty));
   1619 
   1620     // var st: StackTrace = undefined;
   1621     const unresolved_stack_trace_ty = try sema.getBuiltinType(&err_trace_block, src, "StackTrace");
   1622     const stack_trace_ty = try sema.resolveTypeFields(&err_trace_block, src, unresolved_stack_trace_ty);
   1623     const st_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty));
   1624 
   1625     // st.instruction_addresses = &addrs;
   1626     const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "instruction_addresses", src, true);
   1627     try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store);
   1628 
   1629     // st.index = 0;
   1630     const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src, true);
   1631     try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, .zero_usize, src, .store);
   1632 
   1633     // @errorReturnTrace() = &st;
   1634     _ = try err_trace_block.addUnOp(.set_err_return_trace, st_ptr);
   1635 
   1636     try block.instructions.insertSlice(sema.gpa, last_arg_index, err_trace_block.instructions.items);
   1637 }
   1638 
   1639 /// May return Value Tags: `variable`, `undef`.
   1640 /// See `resolveConstValue` for an alternative.
   1641 /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned.
   1642 fn resolveValue(
   1643     sema: *Sema,
   1644     block: *Block,
   1645     src: LazySrcLoc,
   1646     air_ref: Air.Inst.Ref,
   1647     reason: []const u8,
   1648 ) CompileError!Value {
   1649     if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| {
   1650         if (val.tag() == .generic_poison) return error.GenericPoison;
   1651         return val;
   1652     }
   1653     return sema.failWithNeededComptime(block, src, reason);
   1654 }
   1655 
   1656 /// Value Tag `variable` will cause a compile error.
   1657 /// Value Tag `undef` may be returned.
   1658 fn resolveConstMaybeUndefVal(
   1659     sema: *Sema,
   1660     block: *Block,
   1661     src: LazySrcLoc,
   1662     inst: Air.Inst.Ref,
   1663     reason: []const u8,
   1664 ) CompileError!Value {
   1665     if (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) |val| {
   1666         switch (val.tag()) {
   1667             .variable => return sema.failWithNeededComptime(block, src, reason),
   1668             .generic_poison => return error.GenericPoison,
   1669             else => return val,
   1670         }
   1671     }
   1672     return sema.failWithNeededComptime(block, src, reason);
   1673 }
   1674 
   1675 /// Will not return Value Tags: `variable`, `undef`. Instead they will emit compile errors.
   1676 /// See `resolveValue` for an alternative.
   1677 fn resolveConstValue(
   1678     sema: *Sema,
   1679     block: *Block,
   1680     src: LazySrcLoc,
   1681     air_ref: Air.Inst.Ref,
   1682     reason: []const u8,
   1683 ) CompileError!Value {
   1684     if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| {
   1685         switch (val.tag()) {
   1686             .undef => return sema.failWithUseOfUndef(block, src),
   1687             .variable => return sema.failWithNeededComptime(block, src, reason),
   1688             .generic_poison => return error.GenericPoison,
   1689             else => return val,
   1690         }
   1691     }
   1692     return sema.failWithNeededComptime(block, src, reason);
   1693 }
   1694 
   1695 /// Value Tag `variable` causes this function to return `null`.
   1696 /// Value Tag `undef` causes this function to return a compile error.
   1697 fn resolveDefinedValue(
   1698     sema: *Sema,
   1699     block: *Block,
   1700     src: LazySrcLoc,
   1701     air_ref: Air.Inst.Ref,
   1702 ) CompileError!?Value {
   1703     if (try sema.resolveMaybeUndefVal(block, src, air_ref)) |val| {
   1704         if (val.isUndef()) {
   1705             if (block.is_typeof) return null;
   1706             return sema.failWithUseOfUndef(block, src);
   1707         }
   1708         return val;
   1709     }
   1710     return null;
   1711 }
   1712 
   1713 /// Value Tag `variable` causes this function to return `null`.
   1714 /// Value Tag `undef` causes this function to return the Value.
   1715 /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned.
   1716 fn resolveMaybeUndefVal(
   1717     sema: *Sema,
   1718     block: *Block,
   1719     src: LazySrcLoc,
   1720     inst: Air.Inst.Ref,
   1721 ) CompileError!?Value {
   1722     const val = (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) orelse return null;
   1723     switch (val.tag()) {
   1724         .variable => return null,
   1725         .generic_poison => return error.GenericPoison,
   1726         else => return val,
   1727     }
   1728 }
   1729 
   1730 /// Value Tag `variable` results in `null`.
   1731 /// Value Tag `undef` results in the Value.
   1732 /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned.
   1733 /// Value Tag `decl_ref` and `decl_ref_mut` or any nested such value results in `null`.
   1734 fn resolveMaybeUndefValIntable(
   1735     sema: *Sema,
   1736     block: *Block,
   1737     src: LazySrcLoc,
   1738     inst: Air.Inst.Ref,
   1739 ) CompileError!?Value {
   1740     const val = (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) orelse return null;
   1741     var check = val;
   1742     while (true) switch (check.tag()) {
   1743         .variable, .decl_ref, .decl_ref_mut, .comptime_field_ptr => return null,
   1744         .field_ptr => check = check.castTag(.field_ptr).?.data.container_ptr,
   1745         .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr,
   1746         .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr,
   1747         .generic_poison => return error.GenericPoison,
   1748         else => {
   1749             try sema.resolveLazyValue(block, src, val);
   1750             return val;
   1751         },
   1752     };
   1753 }
   1754 
   1755 /// Returns all Value tags including `variable` and `undef`.
   1756 fn resolveMaybeUndefValAllowVariables(
   1757     sema: *Sema,
   1758     block: *Block,
   1759     src: LazySrcLoc,
   1760     inst: Air.Inst.Ref,
   1761 ) CompileError!?Value {
   1762     // First section of indexes correspond to a set number of constant values.
   1763     var i: usize = @enumToInt(inst);
   1764     if (i < Air.Inst.Ref.typed_value_map.len) {
   1765         return Air.Inst.Ref.typed_value_map[i].val;
   1766     }
   1767     i -= Air.Inst.Ref.typed_value_map.len;
   1768 
   1769     if (try sema.typeHasOnePossibleValue(block, src, sema.typeOf(inst))) |opv| {
   1770         return opv;
   1771     }
   1772     const air_tags = sema.air_instructions.items(.tag);
   1773     switch (air_tags[i]) {
   1774         .constant => {
   1775             const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;
   1776             const val = sema.air_values.items[ty_pl.payload];
   1777             if (val.tag() == .runtime_int) return null;
   1778             return val;
   1779         },
   1780         .const_ty => {
   1781             return try sema.air_instructions.items(.data)[i].ty.toValue(sema.arena);
   1782         },
   1783         else => return null,
   1784     }
   1785 }
   1786 
   1787 fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: []const u8) CompileError {
   1788     const msg = msg: {
   1789         const msg = try sema.errMsg(block, src, "unable to resolve comptime value", .{});
   1790         errdefer msg.destroy(sema.gpa);
   1791 
   1792         try sema.errNote(block, src, msg, "{s}", .{reason});
   1793         break :msg msg;
   1794     };
   1795     return sema.failWithOwnedErrorMsg(msg);
   1796 }
   1797 
   1798 fn failWithUseOfUndef(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError {
   1799     return sema.fail(block, src, "use of undefined value here causes undefined behavior", .{});
   1800 }
   1801 
   1802 fn failWithDivideByZero(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError {
   1803     return sema.fail(block, src, "division by zero here causes undefined behavior", .{});
   1804 }
   1805 
   1806 fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: Type, rhs_ty: Type) CompileError {
   1807     return sema.fail(block, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{
   1808         lhs_ty.fmt(sema.mod), rhs_ty.fmt(sema.mod),
   1809     });
   1810 }
   1811 
   1812 fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, optional_ty: Type) CompileError {
   1813     return sema.fail(block, src, "expected optional type, found '{}'", .{optional_ty.fmt(sema.mod)});
   1814 }
   1815 
   1816 fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
   1817     const msg = msg: {
   1818         const msg = try sema.errMsg(block, src, "type '{}' does not support array initialization syntax", .{
   1819             ty.fmt(sema.mod),
   1820         });
   1821         errdefer msg.destroy(sema.gpa);
   1822         if (ty.isSlice()) {
   1823             try sema.errNote(block, src, msg, "inferred array length is specified with an underscore: '[_]{}'", .{ty.elemType2().fmt(sema.mod)});
   1824         }
   1825         break :msg msg;
   1826     };
   1827     return sema.failWithOwnedErrorMsg(msg);
   1828 }
   1829 
   1830 fn failWithStructInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
   1831     return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{
   1832         ty.fmt(sema.mod),
   1833     });
   1834 }
   1835 
   1836 fn failWithErrorSetCodeMissing(
   1837     sema: *Sema,
   1838     block: *Block,
   1839     src: LazySrcLoc,
   1840     dest_err_set_ty: Type,
   1841     src_err_set_ty: Type,
   1842 ) CompileError {
   1843     return sema.fail(block, src, "expected type '{}', found type '{}'", .{
   1844         dest_err_set_ty.fmt(sema.mod), src_err_set_ty.fmt(sema.mod),
   1845     });
   1846 }
   1847 
   1848 fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: usize) CompileError {
   1849     if (int_ty.zigTypeTag() == .Vector) {
   1850         const msg = msg: {
   1851             const msg = try sema.errMsg(block, src, "overflow of vector type '{}' with value '{}'", .{
   1852                 int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod),
   1853             });
   1854             errdefer msg.destroy(sema.gpa);
   1855             try sema.errNote(block, src, msg, "when computing vector element at index '{d}'", .{vector_index});
   1856             break :msg msg;
   1857         };
   1858         return sema.failWithOwnedErrorMsg(msg);
   1859     }
   1860     return sema.fail(block, src, "overflow of integer type '{}' with value '{}'", .{
   1861         int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod),
   1862     });
   1863 }
   1864 
   1865 fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazySrcLoc, container_ty: Type, field_index: usize) CompileError {
   1866     const msg = msg: {
   1867         const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{});
   1868         errdefer msg.destroy(sema.gpa);
   1869 
   1870         const decl_index = container_ty.getOwnerDeclOrNull() orelse break :msg msg;
   1871         const decl = sema.mod.declPtr(decl_index);
   1872         const tree = decl.getFileScope().getTree(sema.gpa) catch |err| {
   1873             log.err("unable to load AST to report compile error: {s}", .{@errorName(err)});
   1874             return error.AnalysisFail;
   1875         };
   1876         const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index);
   1877         const default_value_src: LazySrcLoc = .{ .node_offset_field_default = field_src.node_offset.x };
   1878 
   1879         try sema.mod.errNoteNonLazy(default_value_src.toSrcLoc(decl), msg, "default value set here", .{});
   1880         break :msg msg;
   1881     };
   1882     return sema.failWithOwnedErrorMsg(msg);
   1883 }
   1884 
   1885 fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError {
   1886     const msg = msg: {
   1887         const msg = try sema.errMsg(block, src, "async has not been implemented in the self-hosted compiler yet", .{});
   1888         errdefer msg.destroy(sema.gpa);
   1889 
   1890         try sema.errNote(block, src, msg, "to use async enable the stage1 compiler with either '-fstage1' or by setting '.use_stage1 = true` in your 'build.zig' script", .{});
   1891         break :msg msg;
   1892     };
   1893     return sema.failWithOwnedErrorMsg(msg);
   1894 }
   1895 
   1896 /// We don't return a pointer to the new error note because the pointer
   1897 /// becomes invalid when you add another one.
   1898 fn errNote(
   1899     sema: *Sema,
   1900     block: *Block,
   1901     src: LazySrcLoc,
   1902     parent: *Module.ErrorMsg,
   1903     comptime format: []const u8,
   1904     args: anytype,
   1905 ) error{OutOfMemory}!void {
   1906     const mod = sema.mod;
   1907     const src_decl = mod.declPtr(block.src_decl);
   1908     return mod.errNoteNonLazy(src.toSrcLoc(src_decl), parent, format, args);
   1909 }
   1910 
   1911 fn addFieldErrNote(
   1912     sema: *Sema,
   1913     container_ty: Type,
   1914     field_index: usize,
   1915     parent: *Module.ErrorMsg,
   1916     comptime format: []const u8,
   1917     args: anytype,
   1918 ) !void {
   1919     const mod = sema.mod;
   1920     const decl_index = container_ty.getOwnerDecl();
   1921     const decl = mod.declPtr(decl_index);
   1922     const tree = decl.getFileScope().getTree(sema.gpa) catch |err| {
   1923         log.err("unable to load AST to report compile error: {s}", .{@errorName(err)});
   1924         return error.AnalysisFail;
   1925     };
   1926     const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index);
   1927     try mod.errNoteNonLazy(field_src.toSrcLoc(decl), parent, format, args);
   1928 }
   1929 
   1930 fn errMsg(
   1931     sema: *Sema,
   1932     block: *Block,
   1933     src: LazySrcLoc,
   1934     comptime format: []const u8,
   1935     args: anytype,
   1936 ) error{OutOfMemory}!*Module.ErrorMsg {
   1937     const mod = sema.mod;
   1938     const src_decl = mod.declPtr(block.src_decl);
   1939     return Module.ErrorMsg.create(sema.gpa, src.toSrcLoc(src_decl), format, args);
   1940 }
   1941 
   1942 pub fn fail(
   1943     sema: *Sema,
   1944     block: *Block,
   1945     src: LazySrcLoc,
   1946     comptime format: []const u8,
   1947     args: anytype,
   1948 ) CompileError {
   1949     const err_msg = try sema.errMsg(block, src, format, args);
   1950     return sema.failWithOwnedErrorMsg(err_msg);
   1951 }
   1952 
   1953 fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
   1954     @setCold(true);
   1955 
   1956     if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) {
   1957         std.debug.print("compile error during Sema: {s}, src: {s}:{}\n", .{
   1958             err_msg.msg,
   1959             err_msg.src_loc.file_scope.sub_file_path,
   1960             err_msg.src_loc.lazy,
   1961         });
   1962         crash_report.compilerPanic("unexpected compile error occurred", null, null);
   1963     }
   1964 
   1965     const mod = sema.mod;
   1966     ref: {
   1967         errdefer err_msg.destroy(mod.gpa);
   1968         if (err_msg.src_loc.lazy == .unneeded) {
   1969             return error.NeededSourceLocation;
   1970         }
   1971         try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
   1972         try mod.failed_files.ensureUnusedCapacity(mod.gpa, 1);
   1973 
   1974         const max_references = blk: {
   1975             if (sema.mod.comp.reference_trace) |num| break :blk num;
   1976             // Do not add multiple traces without explicit request.
   1977             if (sema.mod.failed_decls.count() != 0) break :ref;
   1978             break :blk default_reference_trace_len;
   1979         };
   1980 
   1981         var referenced_by = if (sema.func) |some| some.owner_decl else sema.owner_decl_index;
   1982         var reference_stack = std.ArrayList(Module.ErrorMsg.Trace).init(sema.gpa);
   1983         defer reference_stack.deinit();
   1984 
   1985         // Avoid infinite loops.
   1986         var seen = std.AutoHashMap(Module.Decl.Index, void).init(sema.gpa);
   1987         defer seen.deinit();
   1988 
   1989         var cur_reference_trace: u32 = 0;
   1990         while (sema.mod.reference_table.get(referenced_by)) |ref| : (cur_reference_trace += 1) {
   1991             const gop = try seen.getOrPut(ref.referencer);
   1992             if (gop.found_existing) break;
   1993             if (cur_reference_trace < max_references) {
   1994                 const decl = sema.mod.declPtr(ref.referencer);
   1995                 try reference_stack.append(.{ .decl = decl.name, .src_loc = ref.src.toSrcLoc(decl) });
   1996             }
   1997             referenced_by = ref.referencer;
   1998         }
   1999         if (sema.mod.comp.reference_trace == null and cur_reference_trace > 0) {
   2000             try reference_stack.append(.{
   2001                 .decl = null,
   2002                 .src_loc = undefined,
   2003                 .hidden = 0,
   2004             });
   2005         } else if (cur_reference_trace > max_references) {
   2006             try reference_stack.append(.{
   2007                 .decl = undefined,
   2008                 .src_loc = undefined,
   2009                 .hidden = cur_reference_trace - max_references,
   2010             });
   2011         }
   2012         err_msg.reference_trace = reference_stack.toOwnedSlice();
   2013     }
   2014     if (sema.owner_func) |func| {
   2015         func.state = .sema_failure;
   2016     } else {
   2017         sema.owner_decl.analysis = .sema_failure;
   2018         sema.owner_decl.generation = mod.generation;
   2019     }
   2020     const gop = mod.failed_decls.getOrPutAssumeCapacity(sema.owner_decl_index);
   2021     if (gop.found_existing) {
   2022         // If there are multiple errors for the same Decl, prefer the first one added.
   2023         sema.err = null;
   2024         err_msg.destroy(mod.gpa);
   2025     } else {
   2026         sema.err = err_msg;
   2027         gop.value_ptr.* = err_msg;
   2028     }
   2029     return error.AnalysisFail;
   2030 }
   2031 
   2032 const align_ty = Type.u29;
   2033 
   2034 fn analyzeAsAlign(
   2035     sema: *Sema,
   2036     block: *Block,
   2037     src: LazySrcLoc,
   2038     air_ref: Air.Inst.Ref,
   2039 ) !u32 {
   2040     const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, "alignment must be comptime known");
   2041     const alignment = @intCast(u32, alignment_big); // We coerce to u16 in the prev line.
   2042     try sema.validateAlign(block, src, alignment);
   2043     return alignment;
   2044 }
   2045 
   2046 fn validateAlign(
   2047     sema: *Sema,
   2048     block: *Block,
   2049     src: LazySrcLoc,
   2050     alignment: u32,
   2051 ) !void {
   2052     if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{});
   2053     if (!std.math.isPowerOfTwo(alignment)) {
   2054         return sema.fail(block, src, "alignment value '{d}' is not a power of two", .{
   2055             alignment,
   2056         });
   2057     }
   2058 }
   2059 
   2060 pub fn resolveAlign(
   2061     sema: *Sema,
   2062     block: *Block,
   2063     src: LazySrcLoc,
   2064     zir_ref: Zir.Inst.Ref,
   2065 ) !u32 {
   2066     const air_ref = try sema.resolveInst(zir_ref);
   2067     return analyzeAsAlign(sema, block, src, air_ref);
   2068 }
   2069 
   2070 fn resolveInt(
   2071     sema: *Sema,
   2072     block: *Block,
   2073     src: LazySrcLoc,
   2074     zir_ref: Zir.Inst.Ref,
   2075     dest_ty: Type,
   2076     reason: []const u8,
   2077 ) !u64 {
   2078     const air_ref = try sema.resolveInst(zir_ref);
   2079     return analyzeAsInt(sema, block, src, air_ref, dest_ty, reason);
   2080 }
   2081 
   2082 fn analyzeAsInt(
   2083     sema: *Sema,
   2084     block: *Block,
   2085     src: LazySrcLoc,
   2086     air_ref: Air.Inst.Ref,
   2087     dest_ty: Type,
   2088     reason: []const u8,
   2089 ) !u64 {
   2090     const coerced = try sema.coerce(block, dest_ty, air_ref, src);
   2091     const val = try sema.resolveConstValue(block, src, coerced, reason);
   2092     const target = sema.mod.getTarget();
   2093     return (try val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?;
   2094 }
   2095 
   2096 // Returns a compile error if the value has tag `variable`. See `resolveInstValue` for
   2097 // a function that does not.
   2098 pub fn resolveInstConst(
   2099     sema: *Sema,
   2100     block: *Block,
   2101     src: LazySrcLoc,
   2102     zir_ref: Zir.Inst.Ref,
   2103     reason: []const u8,
   2104 ) CompileError!TypedValue {
   2105     const air_ref = try sema.resolveInst(zir_ref);
   2106     const val = try sema.resolveConstValue(block, src, air_ref, reason);
   2107     return TypedValue{
   2108         .ty = sema.typeOf(air_ref),
   2109         .val = val,
   2110     };
   2111 }
   2112 
   2113 // Value Tag may be `undef` or `variable`.
   2114 // See `resolveInstConst` for an alternative.
   2115 pub fn resolveInstValue(
   2116     sema: *Sema,
   2117     block: *Block,
   2118     src: LazySrcLoc,
   2119     zir_ref: Zir.Inst.Ref,
   2120     reason: []const u8,
   2121 ) CompileError!TypedValue {
   2122     const air_ref = try sema.resolveInst(zir_ref);
   2123     const val = try sema.resolveValue(block, src, air_ref, reason);
   2124     return TypedValue{
   2125         .ty = sema.typeOf(air_ref),
   2126         .val = val,
   2127     };
   2128 }
   2129 
   2130 fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   2131     const tracy = trace(@src());
   2132     defer tracy.end();
   2133 
   2134     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2135     const src = inst_data.src();
   2136     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   2137     const pointee_ty = try sema.resolveType(block, src, extra.lhs);
   2138     const ptr = try sema.resolveInst(extra.rhs);
   2139     const target = sema.mod.getTarget();
   2140     const addr_space = target_util.defaultAddressSpace(target, .local);
   2141 
   2142     if (Air.refToIndex(ptr)) |ptr_inst| {
   2143         if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {
   2144             const air_datas = sema.air_instructions.items(.data);
   2145             const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
   2146             switch (ptr_val.tag()) {
   2147                 .inferred_alloc => {
   2148                     const inferred_alloc = &ptr_val.castTag(.inferred_alloc).?.data;
   2149                     // Add the stored instruction to the set we will use to resolve peer types
   2150                     // for the inferred allocation.
   2151                     // This instruction will not make it to codegen; it is only to participate
   2152                     // in the `stored_inst_list` of the `inferred_alloc`.
   2153                     var trash_block = block.makeSubBlock();
   2154                     defer trash_block.instructions.deinit(sema.gpa);
   2155                     const operand = try trash_block.addBitCast(pointee_ty, .void_value);
   2156 
   2157                     try sema.requireFunctionBlock(block, src);
   2158                     const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
   2159                         .pointee_type = pointee_ty,
   2160                         .@"align" = inferred_alloc.alignment,
   2161                         .@"addrspace" = addr_space,
   2162                     });
   2163                     const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);
   2164 
   2165                     try inferred_alloc.prongs.append(sema.arena, .{
   2166                         .stored_inst = operand,
   2167                         .placeholder = Air.refToIndex(bitcasted_ptr).?,
   2168                     });
   2169 
   2170                     return bitcasted_ptr;
   2171                 },
   2172                 .inferred_alloc_comptime => {
   2173                     const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
   2174                     // There will be only one coerce_result_ptr because we are running at comptime.
   2175                     // The alloc will turn into a Decl.
   2176                     var anon_decl = try block.startAnonDecl(src);
   2177                     defer anon_decl.deinit();
   2178                     iac.data.decl_index = try anon_decl.finish(
   2179                         try pointee_ty.copy(anon_decl.arena()),
   2180                         Value.undef,
   2181                         iac.data.alignment,
   2182                     );
   2183                     if (iac.data.alignment != 0) {
   2184                         try sema.resolveTypeLayout(block, src, pointee_ty);
   2185                     }
   2186                     const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
   2187                         .pointee_type = pointee_ty,
   2188                         .@"align" = iac.data.alignment,
   2189                         .@"addrspace" = addr_space,
   2190                     });
   2191                     return sema.addConstant(
   2192                         ptr_ty,
   2193                         try Value.Tag.decl_ref_mut.create(sema.arena, .{
   2194                             .decl_index = iac.data.decl_index,
   2195                             .runtime_index = block.runtime_index,
   2196                         }),
   2197                     );
   2198                 },
   2199                 else => {},
   2200             }
   2201         }
   2202     }
   2203 
   2204     // Make a dummy store through the pointer to test the coercion.
   2205     // We will then use the generated instructions to decide what
   2206     // kind of transformations to make on the result pointer.
   2207     var trash_block = block.makeSubBlock();
   2208     trash_block.is_comptime = false;
   2209     trash_block.is_coerce_result_ptr = true;
   2210     defer trash_block.instructions.deinit(sema.gpa);
   2211 
   2212     const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr));
   2213     const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value);
   2214     return coerceResultPtr(sema, block, src, ptr, dummy_ptr, dummy_operand, &trash_block);
   2215 }
   2216 
   2217 fn coerceResultPtr(
   2218     sema: *Sema,
   2219     block: *Block,
   2220     src: LazySrcLoc,
   2221     ptr: Air.Inst.Ref,
   2222     dummy_ptr: Air.Inst.Ref,
   2223     dummy_operand: Air.Inst.Ref,
   2224     trash_block: *Block,
   2225 ) CompileError!Air.Inst.Ref {
   2226     const target = sema.mod.getTarget();
   2227     const addr_space = target_util.defaultAddressSpace(target, .local);
   2228     const pointee_ty = sema.typeOf(dummy_operand);
   2229     const prev_trash_len = trash_block.instructions.items.len;
   2230 
   2231     try sema.storePtr2(trash_block, src, dummy_ptr, src, dummy_operand, src, .bitcast);
   2232 
   2233     {
   2234         const air_tags = sema.air_instructions.items(.tag);
   2235 
   2236         //std.debug.print("dummy storePtr instructions:\n", .{});
   2237         //for (trash_block.instructions.items) |item| {
   2238         //    std.debug.print("  {s}\n", .{@tagName(air_tags[item])});
   2239         //}
   2240 
   2241         // The last one is always `store`.
   2242         const trash_inst = trash_block.instructions.items[trash_block.instructions.items.len - 1];
   2243         if (air_tags[trash_inst] != .store) {
   2244             // no store instruction is generated for zero sized types
   2245             assert((try sema.typeHasOnePossibleValue(block, src, pointee_ty)) != null);
   2246         } else {
   2247             trash_block.instructions.items.len -= 1;
   2248             assert(trash_inst == sema.air_instructions.len - 1);
   2249             sema.air_instructions.len -= 1;
   2250         }
   2251     }
   2252 
   2253     const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
   2254         .pointee_type = pointee_ty,
   2255         .@"addrspace" = addr_space,
   2256     });
   2257 
   2258     var new_ptr = ptr;
   2259 
   2260     while (true) {
   2261         const air_tags = sema.air_instructions.items(.tag);
   2262         const air_datas = sema.air_instructions.items(.data);
   2263 
   2264         if (trash_block.instructions.items.len == prev_trash_len) {
   2265             if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
   2266                 return sema.addConstant(ptr_ty, ptr_val);
   2267             }
   2268             if (pointee_ty.eql(Type.@"null", sema.mod)) {
   2269                 const opt_ty = sema.typeOf(new_ptr).childType();
   2270                 const null_inst = try sema.addConstant(opt_ty, Value.@"null");
   2271                 _ = try block.addBinOp(.store, new_ptr, null_inst);
   2272                 return Air.Inst.Ref.void_value;
   2273             }
   2274             return sema.bitCast(block, ptr_ty, new_ptr, src);
   2275         }
   2276 
   2277         const trash_inst = trash_block.instructions.pop();
   2278 
   2279         switch (air_tags[trash_inst]) {
   2280             .bitcast => {
   2281                 const ty_op = air_datas[trash_inst].ty_op;
   2282                 const operand_ty = sema.typeOf(ty_op.operand);
   2283                 const ptr_operand_ty = try Type.ptr(sema.arena, sema.mod, .{
   2284                     .pointee_type = operand_ty,
   2285                     .@"addrspace" = addr_space,
   2286                 });
   2287                 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
   2288                     new_ptr = try sema.addConstant(ptr_operand_ty, ptr_val);
   2289                 } else {
   2290                     new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src);
   2291                 }
   2292             },
   2293             .wrap_optional => {
   2294                 new_ptr = try sema.analyzeOptionalPayloadPtr(block, src, new_ptr, false, true);
   2295             },
   2296             .wrap_errunion_err => {
   2297                 return sema.fail(block, src, "TODO coerce_result_ptr wrap_errunion_err", .{});
   2298             },
   2299             .wrap_errunion_payload => {
   2300                 new_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, new_ptr, false, true);
   2301             },
   2302             else => {
   2303                 if (std.debug.runtime_safety) {
   2304                     std.debug.panic("unexpected AIR tag for coerce_result_ptr: {}", .{
   2305                         air_tags[trash_inst],
   2306                     });
   2307                 } else {
   2308                     unreachable;
   2309                 }
   2310             },
   2311         }
   2312     }
   2313 }
   2314 
   2315 pub fn analyzeStructDecl(
   2316     sema: *Sema,
   2317     new_decl: *Decl,
   2318     inst: Zir.Inst.Index,
   2319     struct_obj: *Module.Struct,
   2320 ) SemaError!void {
   2321     const extended = sema.code.instructions.items(.data)[inst].extended;
   2322     assert(extended.opcode == .struct_decl);
   2323     const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
   2324 
   2325     struct_obj.known_non_opv = small.known_non_opv;
   2326     if (small.known_comptime_only) {
   2327         struct_obj.requires_comptime = .yes;
   2328     }
   2329 
   2330     var extra_index: usize = extended.operand;
   2331     extra_index += @boolToInt(small.has_src_node);
   2332     extra_index += @boolToInt(small.has_fields_len);
   2333     const decls_len = if (small.has_decls_len) blk: {
   2334         const decls_len = sema.code.extra[extra_index];
   2335         extra_index += 1;
   2336         break :blk decls_len;
   2337     } else 0;
   2338 
   2339     if (small.has_backing_int) {
   2340         const backing_int_body_len = sema.code.extra[extra_index];
   2341         extra_index += 1; // backing_int_body_len
   2342         if (backing_int_body_len == 0) {
   2343             extra_index += 1; // backing_int_ref
   2344         } else {
   2345             extra_index += backing_int_body_len; // backing_int_body_inst
   2346         }
   2347     }
   2348 
   2349     _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra_index, decls_len, new_decl);
   2350 }
   2351 
   2352 fn zirStructDecl(
   2353     sema: *Sema,
   2354     block: *Block,
   2355     extended: Zir.Inst.Extended.InstData,
   2356     inst: Zir.Inst.Index,
   2357 ) CompileError!Air.Inst.Ref {
   2358     const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
   2359     const src: LazySrcLoc = if (small.has_src_node) blk: {
   2360         const node_offset = @bitCast(i32, sema.code.extra[extended.operand]);
   2361         break :blk LazySrcLoc.nodeOffset(node_offset);
   2362     } else sema.src;
   2363 
   2364     var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
   2365     errdefer new_decl_arena.deinit();
   2366     const new_decl_arena_allocator = new_decl_arena.allocator();
   2367 
   2368     const mod = sema.mod;
   2369     const struct_obj = try new_decl_arena_allocator.create(Module.Struct);
   2370     const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
   2371     const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty);
   2372     const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
   2373         .ty = Type.type,
   2374         .val = struct_val,
   2375     }, small.name_strategy, "struct", inst);
   2376     const new_decl = mod.declPtr(new_decl_index);
   2377     new_decl.owns_tv = true;
   2378     errdefer mod.abortAnonDecl(new_decl_index);
   2379     struct_obj.* = .{
   2380         .owner_decl = new_decl_index,
   2381         .fields = .{},
   2382         .zir_index = inst,
   2383         .layout = small.layout,
   2384         .status = .none,
   2385         .known_non_opv = undefined,
   2386         .namespace = .{
   2387             .parent = block.namespace,
   2388             .ty = struct_ty,
   2389             .file_scope = block.getFileScope(),
   2390         },
   2391     };
   2392     std.log.scoped(.module).debug("create struct {*} owned by {*} ({s})", .{
   2393         &struct_obj.namespace, new_decl, new_decl.name,
   2394     });
   2395     try sema.analyzeStructDecl(new_decl, inst, struct_obj);
   2396     try new_decl.finalizeNewArena(&new_decl_arena);
   2397     return sema.analyzeDeclVal(block, src, new_decl_index);
   2398 }
   2399 
   2400 fn createAnonymousDeclTypeNamed(
   2401     sema: *Sema,
   2402     block: *Block,
   2403     src: LazySrcLoc,
   2404     typed_value: TypedValue,
   2405     name_strategy: Zir.Inst.NameStrategy,
   2406     anon_prefix: []const u8,
   2407     inst: ?Zir.Inst.Index,
   2408 ) !Decl.Index {
   2409     const mod = sema.mod;
   2410     const namespace = block.namespace;
   2411     const src_scope = block.wip_capture_scope;
   2412     const src_decl = mod.declPtr(block.src_decl);
   2413     const src_node = src_decl.relativeToNodeIndex(src.node_offset.x);
   2414     const new_decl_index = try mod.allocateNewDecl(namespace, src_node, src_scope);
   2415     errdefer mod.destroyDecl(new_decl_index);
   2416 
   2417     switch (name_strategy) {
   2418         .anon => {
   2419             // It would be neat to have "struct:line:column" but this name has
   2420             // to survive incremental updates, where it may have been shifted down
   2421             // or up to a different line, but unchanged, and thus not unnecessarily
   2422             // semantically analyzed.
   2423             // This name is also used as the key in the parent namespace so it cannot be
   2424             // renamed.
   2425             const name = try std.fmt.allocPrintZ(sema.gpa, "{s}__{s}_{d}", .{
   2426                 src_decl.name, anon_prefix, @enumToInt(new_decl_index),
   2427             });
   2428             errdefer sema.gpa.free(name);
   2429             try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
   2430             return new_decl_index;
   2431         },
   2432         .parent => {
   2433             const name = try sema.gpa.dupeZ(u8, mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0));
   2434             errdefer sema.gpa.free(name);
   2435             try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
   2436             return new_decl_index;
   2437         },
   2438         .func => {
   2439             const fn_info = sema.code.getFnInfo(sema.func.?.zir_body_inst);
   2440             const zir_tags = sema.code.instructions.items(.tag);
   2441 
   2442             var buf = std.ArrayList(u8).init(sema.gpa);
   2443             defer buf.deinit();
   2444             try buf.appendSlice(mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0));
   2445             try buf.appendSlice("(");
   2446 
   2447             var arg_i: usize = 0;
   2448             for (fn_info.param_body) |zir_inst| switch (zir_tags[zir_inst]) {
   2449                 .param, .param_comptime, .param_anytype, .param_anytype_comptime => {
   2450                     const arg = sema.inst_map.get(zir_inst).?;
   2451                     // The comptime call code in analyzeCall already did this, so we're
   2452                     // just repeating it here and it's guaranteed to work.
   2453                     const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg, undefined) catch unreachable;
   2454 
   2455                     if (arg_i != 0) try buf.appendSlice(",");
   2456                     try buf.writer().print("{}", .{arg_val.fmtValue(sema.typeOf(arg), sema.mod)});
   2457 
   2458                     arg_i += 1;
   2459                     continue;
   2460                 },
   2461                 else => continue,
   2462             };
   2463 
   2464             try buf.appendSlice(")");
   2465             const name = try buf.toOwnedSliceSentinel(0);
   2466             errdefer sema.gpa.free(name);
   2467             try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
   2468             return new_decl_index;
   2469         },
   2470         .dbg_var => {
   2471             const ref = Zir.indexToRef(inst.?);
   2472             const zir_tags = sema.code.instructions.items(.tag);
   2473             const zir_data = sema.code.instructions.items(.data);
   2474             var i = inst.?;
   2475             while (i < zir_tags.len) : (i += 1) switch (zir_tags[i]) {
   2476                 .dbg_var_ptr, .dbg_var_val => {
   2477                     if (zir_data[i].str_op.operand != ref) continue;
   2478 
   2479                     const name = try std.fmt.allocPrintZ(sema.gpa, "{s}.{s}", .{
   2480                         src_decl.name, zir_data[i].str_op.getStr(sema.code),
   2481                     });
   2482                     errdefer sema.gpa.free(name);
   2483 
   2484                     try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
   2485                     return new_decl_index;
   2486                 },
   2487                 else => {},
   2488             };
   2489             return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null);
   2490         },
   2491     }
   2492 }
   2493 
   2494 fn zirEnumDecl(
   2495     sema: *Sema,
   2496     block: *Block,
   2497     extended: Zir.Inst.Extended.InstData,
   2498     inst: Zir.Inst.Index,
   2499 ) CompileError!Air.Inst.Ref {
   2500     const tracy = trace(@src());
   2501     defer tracy.end();
   2502 
   2503     const mod = sema.mod;
   2504     const gpa = sema.gpa;
   2505     const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small);
   2506     var extra_index: usize = extended.operand;
   2507 
   2508     const src: LazySrcLoc = if (small.has_src_node) blk: {
   2509         const node_offset = @bitCast(i32, sema.code.extra[extra_index]);
   2510         extra_index += 1;
   2511         break :blk LazySrcLoc.nodeOffset(node_offset);
   2512     } else sema.src;
   2513     const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x };
   2514 
   2515     const tag_type_ref = if (small.has_tag_type) blk: {
   2516         const tag_type_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   2517         extra_index += 1;
   2518         break :blk tag_type_ref;
   2519     } else .none;
   2520 
   2521     const body_len = if (small.has_body_len) blk: {
   2522         const body_len = sema.code.extra[extra_index];
   2523         extra_index += 1;
   2524         break :blk body_len;
   2525     } else 0;
   2526 
   2527     const fields_len = if (small.has_fields_len) blk: {
   2528         const fields_len = sema.code.extra[extra_index];
   2529         extra_index += 1;
   2530         break :blk fields_len;
   2531     } else 0;
   2532 
   2533     const decls_len = if (small.has_decls_len) blk: {
   2534         const decls_len = sema.code.extra[extra_index];
   2535         extra_index += 1;
   2536         break :blk decls_len;
   2537     } else 0;
   2538 
   2539     var done = false;
   2540 
   2541     var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
   2542     errdefer if (!done) new_decl_arena.deinit();
   2543     const new_decl_arena_allocator = new_decl_arena.allocator();
   2544 
   2545     const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull);
   2546     const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumFull);
   2547     enum_ty_payload.* = .{
   2548         .base = .{ .tag = if (small.nonexhaustive) .enum_nonexhaustive else .enum_full },
   2549         .data = enum_obj,
   2550     };
   2551     const enum_ty = Type.initPayload(&enum_ty_payload.base);
   2552     const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
   2553     const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
   2554         .ty = Type.type,
   2555         .val = enum_val,
   2556     }, small.name_strategy, "enum", inst);
   2557     const new_decl = mod.declPtr(new_decl_index);
   2558     new_decl.owns_tv = true;
   2559     errdefer if (!done) mod.abortAnonDecl(new_decl_index);
   2560 
   2561     enum_obj.* = .{
   2562         .owner_decl = new_decl_index,
   2563         .tag_ty = Type.@"null",
   2564         .tag_ty_inferred = true,
   2565         .fields = .{},
   2566         .values = .{},
   2567         .namespace = .{
   2568             .parent = block.namespace,
   2569             .ty = enum_ty,
   2570             .file_scope = block.getFileScope(),
   2571         },
   2572     };
   2573     std.log.scoped(.module).debug("create enum {*} owned by {*} ({s})", .{
   2574         &enum_obj.namespace, new_decl, new_decl.name,
   2575     });
   2576 
   2577     try new_decl.finalizeNewArena(&new_decl_arena);
   2578     const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index);
   2579     done = true;
   2580 
   2581     var decl_arena = new_decl.value_arena.?.promote(gpa);
   2582     defer new_decl.value_arena.?.* = decl_arena.state;
   2583     const decl_arena_allocator = decl_arena.allocator();
   2584 
   2585     extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);
   2586 
   2587     const body = sema.code.extra[extra_index..][0..body_len];
   2588     extra_index += body.len;
   2589 
   2590     const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
   2591     const body_end = extra_index;
   2592     extra_index += bit_bags_count;
   2593 
   2594     {
   2595         // We create a block for the field type instructions because they
   2596         // may need to reference Decls from inside the enum namespace.
   2597         // Within the field type, default value, and alignment expressions, the "owner decl"
   2598         // should be the enum itself.
   2599 
   2600         const prev_owner_decl = sema.owner_decl;
   2601         const prev_owner_decl_index = sema.owner_decl_index;
   2602         sema.owner_decl = new_decl;
   2603         sema.owner_decl_index = new_decl_index;
   2604         defer {
   2605             sema.owner_decl = prev_owner_decl;
   2606             sema.owner_decl_index = prev_owner_decl_index;
   2607         }
   2608 
   2609         const prev_owner_func = sema.owner_func;
   2610         sema.owner_func = null;
   2611         defer sema.owner_func = prev_owner_func;
   2612 
   2613         const prev_func = sema.func;
   2614         sema.func = null;
   2615         defer sema.func = prev_func;
   2616 
   2617         var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope);
   2618         defer wip_captures.deinit();
   2619 
   2620         var enum_block: Block = .{
   2621             .parent = null,
   2622             .sema = sema,
   2623             .src_decl = new_decl_index,
   2624             .namespace = &enum_obj.namespace,
   2625             .wip_capture_scope = wip_captures.scope,
   2626             .instructions = .{},
   2627             .inlining = null,
   2628             .is_comptime = true,
   2629         };
   2630         defer assert(enum_block.instructions.items.len == 0); // should all be comptime instructions
   2631 
   2632         if (body.len != 0) {
   2633             try sema.analyzeBody(&enum_block, body);
   2634         }
   2635 
   2636         try wip_captures.finalize();
   2637 
   2638         if (tag_type_ref != .none) {
   2639             const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref);
   2640             if (ty.zigTypeTag() != .Int and ty.zigTypeTag() != .ComptimeInt) {
   2641                 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)});
   2642             }
   2643             enum_obj.tag_ty = try ty.copy(decl_arena_allocator);
   2644             enum_obj.tag_ty_inferred = false;
   2645         } else if (fields_len == 0) {
   2646             enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, 0);
   2647             enum_obj.tag_ty_inferred = true;
   2648         } else {
   2649             const bits = std.math.log2_int_ceil(usize, fields_len);
   2650             enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, bits);
   2651             enum_obj.tag_ty_inferred = true;
   2652         }
   2653     }
   2654 
   2655     if (small.nonexhaustive and enum_obj.tag_ty.zigTypeTag() != .ComptimeInt) {
   2656         if (fields_len > 1 and std.math.log2_int(u64, fields_len) == enum_obj.tag_ty.bitSize(sema.mod.getTarget())) {
   2657             return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
   2658         }
   2659     }
   2660 
   2661     try enum_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
   2662     const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
   2663         if (bag != 0) break true;
   2664     } else false;
   2665     if (any_values) {
   2666         try enum_obj.values.ensureTotalCapacityContext(decl_arena_allocator, fields_len, .{
   2667             .ty = enum_obj.tag_ty,
   2668             .mod = mod,
   2669         });
   2670     }
   2671 
   2672     var bit_bag_index: usize = body_end;
   2673     var cur_bit_bag: u32 = undefined;
   2674     var field_i: u32 = 0;
   2675     var last_tag_val: ?Value = null;
   2676     var tag_val_buf: Value.Payload.U64 = undefined;
   2677     while (field_i < fields_len) : (field_i += 1) {
   2678         if (field_i % 32 == 0) {
   2679             cur_bit_bag = sema.code.extra[bit_bag_index];
   2680             bit_bag_index += 1;
   2681         }
   2682         const has_tag_value = @truncate(u1, cur_bit_bag) != 0;
   2683         cur_bit_bag >>= 1;
   2684 
   2685         const field_name_zir = sema.code.nullTerminatedString(sema.code.extra[extra_index]);
   2686         extra_index += 1;
   2687 
   2688         // doc comment
   2689         extra_index += 1;
   2690 
   2691         // This string needs to outlive the ZIR code.
   2692         const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
   2693 
   2694         const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name);
   2695         if (gop_field.found_existing) {
   2696             const tree = try sema.getAstTree(block);
   2697             const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);
   2698             const other_tag_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_field.index);
   2699             const msg = msg: {
   2700                 const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name});
   2701                 errdefer msg.destroy(gpa);
   2702                 try sema.errNote(block, other_tag_src, msg, "other field here", .{});
   2703                 break :msg msg;
   2704             };
   2705             return sema.failWithOwnedErrorMsg(msg);
   2706         }
   2707 
   2708         if (has_tag_value) {
   2709             const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   2710             extra_index += 1;
   2711             // TODO: if we need to report an error here, use a source location
   2712             // that points to this default value expression rather than the struct.
   2713             // But only resolve the source location if we need to emit a compile error.
   2714             const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref, "enum tag value must be comptime known")).val;
   2715             last_tag_val = tag_val;
   2716             const copied_tag_val = try tag_val.copy(decl_arena_allocator);
   2717             const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{
   2718                 .ty = enum_obj.tag_ty,
   2719                 .mod = mod,
   2720             });
   2721             if (gop_val.found_existing) {
   2722                 const tree = try sema.getAstTree(block);
   2723                 const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);
   2724                 const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_val.index);
   2725                 const msg = msg: {
   2726                     const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)});
   2727                     errdefer msg.destroy(gpa);
   2728                     try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
   2729                     break :msg msg;
   2730                 };
   2731                 return sema.failWithOwnedErrorMsg(msg);
   2732             }
   2733         } else if (any_values) {
   2734             const tag_val = if (last_tag_val) |val|
   2735                 try sema.intAdd(block, src, val, Value.one, enum_obj.tag_ty)
   2736             else
   2737                 Value.zero;
   2738             last_tag_val = tag_val;
   2739             const copied_tag_val = try tag_val.copy(decl_arena_allocator);
   2740             const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{
   2741                 .ty = enum_obj.tag_ty,
   2742                 .mod = mod,
   2743             });
   2744             if (gop_val.found_existing) {
   2745                 const tree = try sema.getAstTree(block);
   2746                 const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);
   2747                 const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_val.index);
   2748                 const msg = msg: {
   2749                     const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)});
   2750                     errdefer msg.destroy(gpa);
   2751                     try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
   2752                     break :msg msg;
   2753                 };
   2754                 return sema.failWithOwnedErrorMsg(msg);
   2755             }
   2756         } else {
   2757             tag_val_buf = .{
   2758                 .base = .{ .tag = .int_u64 },
   2759                 .data = field_i,
   2760             };
   2761             last_tag_val = Value.initPayload(&tag_val_buf.base);
   2762         }
   2763 
   2764         if (!(try sema.intFitsInType(block, src, last_tag_val.?, enum_obj.tag_ty, null))) {
   2765             const tree = try sema.getAstTree(block);
   2766             const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);
   2767             const msg = try sema.errMsg(block, field_src, "enumeration value '{}' too large for type '{}'", .{
   2768                 last_tag_val.?.fmtValue(enum_obj.tag_ty, mod), enum_obj.tag_ty.fmt(mod),
   2769             });
   2770             return sema.failWithOwnedErrorMsg(msg);
   2771         }
   2772     }
   2773     return decl_val;
   2774 }
   2775 
   2776 fn zirUnionDecl(
   2777     sema: *Sema,
   2778     block: *Block,
   2779     extended: Zir.Inst.Extended.InstData,
   2780     inst: Zir.Inst.Index,
   2781 ) CompileError!Air.Inst.Ref {
   2782     const tracy = trace(@src());
   2783     defer tracy.end();
   2784 
   2785     const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
   2786     var extra_index: usize = extended.operand;
   2787 
   2788     const src: LazySrcLoc = if (small.has_src_node) blk: {
   2789         const node_offset = @bitCast(i32, sema.code.extra[extra_index]);
   2790         extra_index += 1;
   2791         break :blk LazySrcLoc.nodeOffset(node_offset);
   2792     } else sema.src;
   2793 
   2794     extra_index += @boolToInt(small.has_tag_type);
   2795     extra_index += @boolToInt(small.has_body_len);
   2796     extra_index += @boolToInt(small.has_fields_len);
   2797 
   2798     const decls_len = if (small.has_decls_len) blk: {
   2799         const decls_len = sema.code.extra[extra_index];
   2800         extra_index += 1;
   2801         break :blk decls_len;
   2802     } else 0;
   2803 
   2804     var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
   2805     errdefer new_decl_arena.deinit();
   2806     const new_decl_arena_allocator = new_decl_arena.allocator();
   2807 
   2808     const union_obj = try new_decl_arena_allocator.create(Module.Union);
   2809     const type_tag = if (small.has_tag_type or small.auto_enum_tag)
   2810         Type.Tag.union_tagged
   2811     else if (small.layout != .Auto)
   2812         Type.Tag.@"union"
   2813     else switch (block.sema.mod.optimizeMode()) {
   2814         .Debug, .ReleaseSafe => Type.Tag.union_safety_tagged,
   2815         .ReleaseFast, .ReleaseSmall => Type.Tag.@"union",
   2816     };
   2817     const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);
   2818     union_payload.* = .{
   2819         .base = .{ .tag = type_tag },
   2820         .data = union_obj,
   2821     };
   2822     const union_ty = Type.initPayload(&union_payload.base);
   2823     const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
   2824     const mod = sema.mod;
   2825     const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
   2826         .ty = Type.type,
   2827         .val = union_val,
   2828     }, small.name_strategy, "union", inst);
   2829     const new_decl = mod.declPtr(new_decl_index);
   2830     new_decl.owns_tv = true;
   2831     errdefer mod.abortAnonDecl(new_decl_index);
   2832     union_obj.* = .{
   2833         .owner_decl = new_decl_index,
   2834         .tag_ty = Type.initTag(.@"null"),
   2835         .fields = .{},
   2836         .zir_index = inst,
   2837         .layout = small.layout,
   2838         .status = .none,
   2839         .namespace = .{
   2840             .parent = block.namespace,
   2841             .ty = union_ty,
   2842             .file_scope = block.getFileScope(),
   2843         },
   2844     };
   2845     std.log.scoped(.module).debug("create union {*} owned by {*} ({s})", .{
   2846         &union_obj.namespace, new_decl, new_decl.name,
   2847     });
   2848 
   2849     _ = try mod.scanNamespace(&union_obj.namespace, extra_index, decls_len, new_decl);
   2850 
   2851     try new_decl.finalizeNewArena(&new_decl_arena);
   2852     return sema.analyzeDeclVal(block, src, new_decl_index);
   2853 }
   2854 
   2855 fn zirOpaqueDecl(
   2856     sema: *Sema,
   2857     block: *Block,
   2858     extended: Zir.Inst.Extended.InstData,
   2859     inst: Zir.Inst.Index,
   2860 ) CompileError!Air.Inst.Ref {
   2861     const tracy = trace(@src());
   2862     defer tracy.end();
   2863 
   2864     const mod = sema.mod;
   2865     const gpa = sema.gpa;
   2866     const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small);
   2867     var extra_index: usize = extended.operand;
   2868 
   2869     const src: LazySrcLoc = if (small.has_src_node) blk: {
   2870         const node_offset = @bitCast(i32, sema.code.extra[extra_index]);
   2871         extra_index += 1;
   2872         break :blk LazySrcLoc.nodeOffset(node_offset);
   2873     } else sema.src;
   2874 
   2875     const decls_len = if (small.has_decls_len) blk: {
   2876         const decls_len = sema.code.extra[extra_index];
   2877         extra_index += 1;
   2878         break :blk decls_len;
   2879     } else 0;
   2880 
   2881     var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
   2882     errdefer new_decl_arena.deinit();
   2883     const new_decl_arena_allocator = new_decl_arena.allocator();
   2884 
   2885     const opaque_obj = try new_decl_arena_allocator.create(Module.Opaque);
   2886     const opaque_ty_payload = try new_decl_arena_allocator.create(Type.Payload.Opaque);
   2887     opaque_ty_payload.* = .{
   2888         .base = .{ .tag = .@"opaque" },
   2889         .data = opaque_obj,
   2890     };
   2891     const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
   2892     const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty);
   2893     const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
   2894         .ty = Type.type,
   2895         .val = opaque_val,
   2896     }, small.name_strategy, "opaque", inst);
   2897     const new_decl = mod.declPtr(new_decl_index);
   2898     new_decl.owns_tv = true;
   2899     errdefer mod.abortAnonDecl(new_decl_index);
   2900 
   2901     opaque_obj.* = .{
   2902         .owner_decl = new_decl_index,
   2903         .namespace = .{
   2904             .parent = block.namespace,
   2905             .ty = opaque_ty,
   2906             .file_scope = block.getFileScope(),
   2907         },
   2908     };
   2909     std.log.scoped(.module).debug("create opaque {*} owned by {*} ({s})", .{
   2910         &opaque_obj.namespace, new_decl, new_decl.name,
   2911     });
   2912 
   2913     extra_index = try mod.scanNamespace(&opaque_obj.namespace, extra_index, decls_len, new_decl);
   2914 
   2915     try new_decl.finalizeNewArena(&new_decl_arena);
   2916     return sema.analyzeDeclVal(block, src, new_decl_index);
   2917 }
   2918 
   2919 fn zirErrorSetDecl(
   2920     sema: *Sema,
   2921     block: *Block,
   2922     inst: Zir.Inst.Index,
   2923     name_strategy: Zir.Inst.NameStrategy,
   2924 ) CompileError!Air.Inst.Ref {
   2925     const tracy = trace(@src());
   2926     defer tracy.end();
   2927 
   2928     const gpa = sema.gpa;
   2929     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2930     const src = inst_data.src();
   2931     const extra = sema.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index);
   2932 
   2933     var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
   2934     errdefer new_decl_arena.deinit();
   2935     const new_decl_arena_allocator = new_decl_arena.allocator();
   2936 
   2937     const error_set = try new_decl_arena_allocator.create(Module.ErrorSet);
   2938     const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set);
   2939     const error_set_val = try Value.Tag.ty.create(new_decl_arena_allocator, error_set_ty);
   2940     const mod = sema.mod;
   2941     const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
   2942         .ty = Type.type,
   2943         .val = error_set_val,
   2944     }, name_strategy, "error", inst);
   2945     const new_decl = mod.declPtr(new_decl_index);
   2946     new_decl.owns_tv = true;
   2947     errdefer mod.abortAnonDecl(new_decl_index);
   2948 
   2949     var names = Module.ErrorSet.NameMap{};
   2950     try names.ensureUnusedCapacity(new_decl_arena_allocator, extra.data.fields_len);
   2951 
   2952     var extra_index = @intCast(u32, extra.end);
   2953     const extra_index_end = extra_index + (extra.data.fields_len * 2);
   2954     while (extra_index < extra_index_end) : (extra_index += 2) { // +2 to skip over doc_string
   2955         const str_index = sema.code.extra[extra_index];
   2956         const kv = try mod.getErrorValue(sema.code.nullTerminatedString(str_index));
   2957         const result = names.getOrPutAssumeCapacity(kv.key);
   2958         assert(!result.found_existing); // verified in AstGen
   2959     }
   2960 
   2961     // names must be sorted.
   2962     Module.ErrorSet.sortNames(&names);
   2963 
   2964     error_set.* = .{
   2965         .owner_decl = new_decl_index,
   2966         .names = names,
   2967     };
   2968     try new_decl.finalizeNewArena(&new_decl_arena);
   2969     return sema.analyzeDeclVal(block, src, new_decl_index);
   2970 }
   2971 
   2972 fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   2973     const tracy = trace(@src());
   2974     defer tracy.end();
   2975 
   2976     const inst_data = sema.code.instructions.items(.data)[inst].node;
   2977     const src = LazySrcLoc.nodeOffset(inst_data);
   2978 
   2979     if (block.is_comptime or try sema.typeRequiresComptime(sema.fn_ret_ty)) {
   2980         const fn_ret_ty = try sema.resolveTypeFields(block, src, sema.fn_ret_ty);
   2981         return sema.analyzeComptimeAlloc(block, fn_ret_ty, 0, src);
   2982     }
   2983 
   2984     const target = sema.mod.getTarget();
   2985     const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
   2986         .pointee_type = sema.fn_ret_ty,
   2987         .@"addrspace" = target_util.defaultAddressSpace(target, .local),
   2988     });
   2989 
   2990     if (block.inlining != null) {
   2991         // We are inlining a function call; this should be emitted as an alloc, not a ret_ptr.
   2992         // TODO when functions gain result location support, the inlining struct in
   2993         // Block should contain the return pointer, and we would pass that through here.
   2994         return block.addTy(.alloc, ptr_type);
   2995     }
   2996 
   2997     return block.addTy(.ret_ptr, ptr_type);
   2998 }
   2999 
   3000 fn zirRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   3001     const tracy = trace(@src());
   3002     defer tracy.end();
   3003 
   3004     const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
   3005     const operand = try sema.resolveInst(inst_data.operand);
   3006     return sema.analyzeRef(block, inst_data.src(), operand);
   3007 }
   3008 
   3009 fn zirEnsureResultUsed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   3010     const tracy = trace(@src());
   3011     defer tracy.end();
   3012 
   3013     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3014     const operand = try sema.resolveInst(inst_data.operand);
   3015     const src = inst_data.src();
   3016 
   3017     return sema.ensureResultUsed(block, operand, src);
   3018 }
   3019 
   3020 fn ensureResultUsed(
   3021     sema: *Sema,
   3022     block: *Block,
   3023     operand: Air.Inst.Ref,
   3024     src: LazySrcLoc,
   3025 ) CompileError!void {
   3026     const operand_ty = sema.typeOf(operand);
   3027     switch (operand_ty.zigTypeTag()) {
   3028         .Void, .NoReturn => return,
   3029         .ErrorSet, .ErrorUnion => {
   3030             const msg = msg: {
   3031                 const msg = try sema.errMsg(block, src, "error is ignored", .{});
   3032                 errdefer msg.destroy(sema.gpa);
   3033                 try sema.errNote(block, src, msg, "consider using `try`, `catch`, or `if`", .{});
   3034                 break :msg msg;
   3035             };
   3036             return sema.failWithOwnedErrorMsg(msg);
   3037         },
   3038         else => {
   3039             const msg = msg: {
   3040                 const msg = try sema.errMsg(block, src, "value of type '{}' ignored", .{operand_ty.fmt(sema.mod)});
   3041                 errdefer msg.destroy(sema.gpa);
   3042                 try sema.errNote(block, src, msg, "all non-void values must be used", .{});
   3043                 try sema.errNote(block, src, msg, "this error can be suppressed by assigning the value to '_'", .{});
   3044                 break :msg msg;
   3045             };
   3046             return sema.failWithOwnedErrorMsg(msg);
   3047         },
   3048     }
   3049 }
   3050 
   3051 fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   3052     const tracy = trace(@src());
   3053     defer tracy.end();
   3054 
   3055     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3056     const operand = try sema.resolveInst(inst_data.operand);
   3057     const src = inst_data.src();
   3058     const operand_ty = sema.typeOf(operand);
   3059     switch (operand_ty.zigTypeTag()) {
   3060         .ErrorSet, .ErrorUnion => {
   3061             const msg = msg: {
   3062                 const msg = try sema.errMsg(block, src, "error is discarded", .{});
   3063                 errdefer msg.destroy(sema.gpa);
   3064                 try sema.errNote(block, src, msg, "consider using `try`, `catch`, or `if`", .{});
   3065                 break :msg msg;
   3066             };
   3067             return sema.failWithOwnedErrorMsg(msg);
   3068         },
   3069         else => return,
   3070     }
   3071 }
   3072 
   3073 fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   3074     const tracy = trace(@src());
   3075     defer tracy.end();
   3076 
   3077     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3078     const src = inst_data.src();
   3079     const object = try sema.resolveInst(inst_data.operand);
   3080     const object_ty = sema.typeOf(object);
   3081 
   3082     const is_pointer_to = object_ty.isSinglePointer();
   3083 
   3084     const array_ty = if (is_pointer_to)
   3085         object_ty.childType()
   3086     else
   3087         object_ty;
   3088 
   3089     if (!array_ty.isIndexable()) {
   3090         const msg = msg: {
   3091             const msg = try sema.errMsg(
   3092                 block,
   3093                 src,
   3094                 "type '{}' does not support indexing",
   3095                 .{array_ty.fmt(sema.mod)},
   3096             );
   3097             errdefer msg.destroy(sema.gpa);
   3098             try sema.errNote(
   3099                 block,
   3100                 src,
   3101                 msg,
   3102                 "for loop operand must be an array, slice, tuple, or vector",
   3103                 .{},
   3104             );
   3105             break :msg msg;
   3106         };
   3107         return sema.failWithOwnedErrorMsg(msg);
   3108     }
   3109 
   3110     return sema.fieldVal(block, src, object, "len", src);
   3111 }
   3112 
   3113 fn zirAllocExtended(
   3114     sema: *Sema,
   3115     block: *Block,
   3116     extended: Zir.Inst.Extended.InstData,
   3117 ) CompileError!Air.Inst.Ref {
   3118     const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand);
   3119     const src = LazySrcLoc.nodeOffset(extra.data.src_node);
   3120     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = extra.data.src_node };
   3121     const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = extra.data.src_node };
   3122     const small = @bitCast(Zir.Inst.AllocExtended.Small, extended.small);
   3123 
   3124     var extra_index: usize = extra.end;
   3125 
   3126     const var_ty: Type = if (small.has_type) blk: {
   3127         const type_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   3128         extra_index += 1;
   3129         break :blk try sema.resolveType(block, ty_src, type_ref);
   3130     } else undefined;
   3131 
   3132     const alignment: u32 = if (small.has_align) blk: {
   3133         const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   3134         extra_index += 1;
   3135         const alignment = try sema.resolveAlign(block, align_src, align_ref);
   3136         break :blk alignment;
   3137     } else 0;
   3138 
   3139     const inferred_alloc_ty = if (small.is_const)
   3140         Type.initTag(.inferred_alloc_const)
   3141     else
   3142         Type.initTag(.inferred_alloc_mut);
   3143 
   3144     if (block.is_comptime or small.is_comptime) {
   3145         if (small.has_type) {
   3146             return sema.analyzeComptimeAlloc(block, var_ty, alignment, ty_src);
   3147         } else {
   3148             return sema.addConstant(
   3149                 inferred_alloc_ty,
   3150                 try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
   3151                     .decl_index = undefined,
   3152                     .alignment = alignment,
   3153                 }),
   3154             );
   3155         }
   3156     }
   3157 
   3158     if (small.has_type) {
   3159         if (!small.is_const) {
   3160             try sema.validateVarType(block, ty_src, var_ty, false);
   3161         }
   3162         const target = sema.mod.getTarget();
   3163         try sema.requireFunctionBlock(block, src);
   3164         try sema.resolveTypeLayout(block, src, var_ty);
   3165         const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
   3166             .pointee_type = var_ty,
   3167             .@"align" = alignment,
   3168             .@"addrspace" = target_util.defaultAddressSpace(target, .local),
   3169         });
   3170         return block.addTy(.alloc, ptr_type);
   3171     }
   3172 
   3173     // `Sema.addConstant` does not add the instruction to the block because it is
   3174     // not needed in the case of constant values. However here, we plan to "downgrade"
   3175     // to a normal instruction when we hit `resolve_inferred_alloc`. So we append
   3176     // to the block even though it is currently a `.constant`.
   3177     const result = try sema.addConstant(
   3178         inferred_alloc_ty,
   3179         try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = alignment }),
   3180     );
   3181     try sema.requireFunctionBlock(block, src);
   3182     try block.instructions.append(sema.gpa, Air.refToIndex(result).?);
   3183     return result;
   3184 }
   3185 
   3186 fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   3187     const tracy = trace(@src());
   3188     defer tracy.end();
   3189 
   3190     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3191     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
   3192     const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
   3193     return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src);
   3194 }
   3195 
   3196 fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   3197     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3198     const src = inst_data.src();
   3199     const alloc = try sema.resolveInst(inst_data.operand);
   3200     const alloc_ty = sema.typeOf(alloc);
   3201 
   3202     var ptr_info = alloc_ty.ptrInfo().data;
   3203     const elem_ty = ptr_info.pointee_type;
   3204 
   3205     // Detect if all stores to an `.alloc` were comptime known.
   3206     ct: {
   3207         var search_index: usize = block.instructions.items.len;
   3208         const air_tags = sema.air_instructions.items(.tag);
   3209         const air_datas = sema.air_instructions.items(.data);
   3210 
   3211         const store_inst = while (true) {
   3212             if (search_index == 0) break :ct;
   3213             search_index -= 1;
   3214 
   3215             const candidate = block.instructions.items[search_index];
   3216             switch (air_tags[candidate]) {
   3217                 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
   3218                 .store => break candidate,
   3219                 else => break :ct,
   3220             }
   3221         } else unreachable; // TODO shouldn't need this
   3222 
   3223         while (true) {
   3224             if (search_index == 0) break :ct;
   3225             search_index -= 1;
   3226 
   3227             const candidate = block.instructions.items[search_index];
   3228             switch (air_tags[candidate]) {
   3229                 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
   3230                 .alloc => {
   3231                     if (Air.indexToRef(candidate) != alloc) break :ct;
   3232                     break;
   3233                 },
   3234                 else => break :ct,
   3235             }
   3236         }
   3237 
   3238         const store_op = air_datas[store_inst].bin_op;
   3239         const store_val = (try sema.resolveMaybeUndefVal(block, src, store_op.rhs)) orelse break :ct;
   3240         if (store_op.lhs != alloc) break :ct;
   3241 
   3242         // Remove all the unnecessary runtime instructions.
   3243         block.instructions.shrinkRetainingCapacity(search_index);
   3244 
   3245         var anon_decl = try block.startAnonDecl(src);
   3246         defer anon_decl.deinit();
   3247         return sema.analyzeDeclRef(try anon_decl.finish(
   3248             try elem_ty.copy(anon_decl.arena()),
   3249             try store_val.copy(anon_decl.arena()),
   3250             ptr_info.@"align",
   3251         ));
   3252     }
   3253 
   3254     ptr_info.mutable = false;
   3255     const const_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
   3256 
   3257     // Detect if a comptime value simply needs to have its type changed.
   3258     if (try sema.resolveMaybeUndefVal(block, inst_data.src(), alloc)) |val| {
   3259         return sema.addConstant(const_ptr_ty, val);
   3260     }
   3261 
   3262     try sema.requireFunctionBlock(block, src);
   3263     return block.addBitCast(const_ptr_ty, alloc);
   3264 }
   3265 
   3266 fn zirAllocInferredComptime(
   3267     sema: *Sema,
   3268     inst: Zir.Inst.Index,
   3269     inferred_alloc_ty: Type,
   3270 ) CompileError!Air.Inst.Ref {
   3271     const src_node = sema.code.instructions.items(.data)[inst].node;
   3272     const src = LazySrcLoc.nodeOffset(src_node);
   3273     sema.src = src;
   3274     return sema.addConstant(
   3275         inferred_alloc_ty,
   3276         try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
   3277             .decl_index = undefined,
   3278             .alignment = 0,
   3279         }),
   3280     );
   3281 }
   3282 
   3283 fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   3284     const tracy = trace(@src());
   3285     defer tracy.end();
   3286 
   3287     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3288     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
   3289     const var_decl_src = inst_data.src();
   3290     const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
   3291     if (block.is_comptime) {
   3292         return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src);
   3293     }
   3294     const target = sema.mod.getTarget();
   3295     const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
   3296         .pointee_type = var_ty,
   3297         .@"addrspace" = target_util.defaultAddressSpace(target, .local),
   3298     });
   3299     try sema.requireFunctionBlock(block, var_decl_src);
   3300     try sema.queueFullTypeResolution(var_ty);
   3301     return block.addTy(.alloc, ptr_type);
   3302 }
   3303 
   3304 fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   3305     const tracy = trace(@src());
   3306     defer tracy.end();
   3307 
   3308     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3309     const var_decl_src = inst_data.src();
   3310     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
   3311     const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
   3312     if (block.is_comptime) {
   3313         return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src);
   3314     }
   3315     try sema.validateVarType(block, ty_src, var_ty, false);
   3316     const target = sema.mod.getTarget();
   3317     const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
   3318         .pointee_type = var_ty,
   3319         .@"addrspace" = target_util.defaultAddressSpace(target, .local),
   3320     });
   3321     try sema.requireFunctionBlock(block, var_decl_src);
   3322     try sema.queueFullTypeResolution(var_ty);
   3323     return block.addTy(.alloc, ptr_type);
   3324 }
   3325 
   3326 fn zirAllocInferred(
   3327     sema: *Sema,
   3328     block: *Block,
   3329     inst: Zir.Inst.Index,
   3330     inferred_alloc_ty: Type,
   3331 ) CompileError!Air.Inst.Ref {
   3332     const tracy = trace(@src());
   3333     defer tracy.end();
   3334 
   3335     const src_node = sema.code.instructions.items(.data)[inst].node;
   3336     const src = LazySrcLoc.nodeOffset(src_node);
   3337     sema.src = src;
   3338 
   3339     if (block.is_comptime) {
   3340         return sema.addConstant(
   3341             inferred_alloc_ty,
   3342             try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
   3343                 .decl_index = undefined,
   3344                 .alignment = 0,
   3345             }),
   3346         );
   3347     }
   3348 
   3349     // `Sema.addConstant` does not add the instruction to the block because it is
   3350     // not needed in the case of constant values. However here, we plan to "downgrade"
   3351     // to a normal instruction when we hit `resolve_inferred_alloc`. So we append
   3352     // to the block even though it is currently a `.constant`.
   3353     const result = try sema.addConstant(
   3354         inferred_alloc_ty,
   3355         try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = 0 }),
   3356     );
   3357     try sema.requireFunctionBlock(block, src);
   3358     try block.instructions.append(sema.gpa, Air.refToIndex(result).?);
   3359     return result;
   3360 }
   3361 
   3362 fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   3363     const tracy = trace(@src());
   3364     defer tracy.end();
   3365 
   3366     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3367     const src = inst_data.src();
   3368     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
   3369     const ptr = try sema.resolveInst(inst_data.operand);
   3370     const ptr_inst = Air.refToIndex(ptr).?;
   3371     assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant);
   3372     const value_index = sema.air_instructions.items(.data)[ptr_inst].ty_pl.payload;
   3373     const ptr_val = sema.air_values.items[value_index];
   3374     const var_is_mut = switch (sema.typeOf(ptr).tag()) {
   3375         .inferred_alloc_const => false,
   3376         .inferred_alloc_mut => true,
   3377         else => unreachable,
   3378     };
   3379     const target = sema.mod.getTarget();
   3380 
   3381     switch (ptr_val.tag()) {
   3382         .inferred_alloc_comptime => {
   3383             const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
   3384             const decl_index = iac.data.decl_index;
   3385             try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index);
   3386 
   3387             const decl = sema.mod.declPtr(decl_index);
   3388             const final_elem_ty = try decl.ty.copy(sema.arena);
   3389             const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
   3390                 .pointee_type = final_elem_ty,
   3391                 .mutable = var_is_mut,
   3392                 .@"align" = iac.data.alignment,
   3393                 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
   3394             });
   3395             const final_ptr_ty_inst = try sema.addType(final_ptr_ty);
   3396             sema.air_instructions.items(.data)[ptr_inst].ty_pl.ty = final_ptr_ty_inst;
   3397 
   3398             if (var_is_mut) {
   3399                 sema.air_values.items[value_index] = try Value.Tag.decl_ref_mut.create(sema.arena, .{
   3400                     .decl_index = decl_index,
   3401                     .runtime_index = block.runtime_index,
   3402                 });
   3403             } else {
   3404                 sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, decl_index);
   3405             }
   3406         },
   3407         .inferred_alloc => {
   3408             const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
   3409             const peer_inst_list = inferred_alloc.data.prongs.items(.stored_inst);
   3410             const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none);
   3411 
   3412             const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
   3413                 .pointee_type = final_elem_ty,
   3414                 .mutable = var_is_mut,
   3415                 .@"align" = inferred_alloc.data.alignment,
   3416                 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
   3417             });
   3418 
   3419             if (var_is_mut) {
   3420                 try sema.validateVarType(block, ty_src, final_elem_ty, false);
   3421             } else ct: {
   3422                 // Detect if the value is comptime known. In such case, the
   3423                 // last 3 AIR instructions of the block will look like this:
   3424                 //
   3425                 //   %a = constant
   3426                 //   %b = bitcast(%a)
   3427                 //   %c = store(%b, %d)
   3428                 //
   3429                 // If `%d` is comptime-known, then we want to store the value
   3430                 // inside an anonymous Decl and then erase these three AIR
   3431                 // instructions from the block, replacing the inst_map entry
   3432                 // corresponding to the ZIR alloc instruction with a constant
   3433                 // decl_ref pointing at our new Decl.
   3434                 // dbg_stmt instructions may be interspersed into this pattern
   3435                 // which must be ignored.
   3436                 if (block.instructions.items.len < 3) break :ct;
   3437                 var search_index: usize = block.instructions.items.len;
   3438                 const air_tags = sema.air_instructions.items(.tag);
   3439                 const air_datas = sema.air_instructions.items(.data);
   3440 
   3441                 const store_inst = while (true) {
   3442                     if (search_index == 0) break :ct;
   3443                     search_index -= 1;
   3444 
   3445                     const candidate = block.instructions.items[search_index];
   3446                     switch (air_tags[candidate]) {
   3447                         .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
   3448                         .store => break candidate,
   3449                         else => break :ct,
   3450                     }
   3451                 } else unreachable; // TODO shouldn't need this
   3452 
   3453                 const bitcast_inst = while (true) {
   3454                     if (search_index == 0) break :ct;
   3455                     search_index -= 1;
   3456 
   3457                     const candidate = block.instructions.items[search_index];
   3458                     switch (air_tags[candidate]) {
   3459                         .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
   3460                         .bitcast => break candidate,
   3461                         else => break :ct,
   3462                     }
   3463                 } else unreachable; // TODO shouldn't need this
   3464 
   3465                 const const_inst = while (true) {
   3466                     if (search_index == 0) break :ct;
   3467                     search_index -= 1;
   3468 
   3469                     const candidate = block.instructions.items[search_index];
   3470                     switch (air_tags[candidate]) {
   3471                         .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
   3472                         .constant => break candidate,
   3473                         else => break :ct,
   3474                     }
   3475                 } else unreachable; // TODO shouldn't need this
   3476 
   3477                 const store_op = air_datas[store_inst].bin_op;
   3478                 const store_val = (try sema.resolveMaybeUndefVal(block, src, store_op.rhs)) orelse break :ct;
   3479                 if (store_op.lhs != Air.indexToRef(bitcast_inst)) break :ct;
   3480                 if (air_datas[bitcast_inst].ty_op.operand != Air.indexToRef(const_inst)) break :ct;
   3481 
   3482                 const new_decl_index = d: {
   3483                     var anon_decl = try block.startAnonDecl(src);
   3484                     defer anon_decl.deinit();
   3485                     const new_decl_index = try anon_decl.finish(
   3486                         try final_elem_ty.copy(anon_decl.arena()),
   3487                         try store_val.copy(anon_decl.arena()),
   3488                         inferred_alloc.data.alignment,
   3489                     );
   3490                     break :d new_decl_index;
   3491                 };
   3492                 try sema.mod.declareDeclDependency(sema.owner_decl_index, new_decl_index);
   3493 
   3494                 // Even though we reuse the constant instruction, we still remove it from the
   3495                 // block so that codegen does not see it.
   3496                 block.instructions.shrinkRetainingCapacity(search_index);
   3497                 sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, new_decl_index);
   3498                 // if bitcast ty ref needs to be made const, make_ptr_const
   3499                 // ZIR handles it later, so we can just use the ty ref here.
   3500                 air_datas[ptr_inst].ty_pl.ty = air_datas[bitcast_inst].ty_op.ty;
   3501 
   3502                 // Unless the block is comptime, `alloc_inferred` always produces
   3503                 // a runtime constant. The final inferred type needs to be
   3504                 // fully resolved so it can be lowered in codegen.
   3505                 try sema.resolveTypeFully(block, ty_src, final_elem_ty);
   3506 
   3507                 return;
   3508             }
   3509 
   3510             try sema.requireFunctionBlock(block, src);
   3511             try sema.queueFullTypeResolution(final_elem_ty);
   3512 
   3513             // Change it to a normal alloc.
   3514             sema.air_instructions.set(ptr_inst, .{
   3515                 .tag = .alloc,
   3516                 .data = .{ .ty = final_ptr_ty },
   3517             });
   3518 
   3519             // Now we need to go back over all the coerce_result_ptr instructions, which
   3520             // previously inserted a bitcast as a placeholder, and do the logic as if
   3521             // the new result ptr type was available.
   3522             const placeholders = inferred_alloc.data.prongs.items(.placeholder);
   3523             const gpa = sema.gpa;
   3524 
   3525             var trash_block = block.makeSubBlock();
   3526             trash_block.is_comptime = false;
   3527             trash_block.is_coerce_result_ptr = true;
   3528             defer trash_block.instructions.deinit(gpa);
   3529 
   3530             const mut_final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
   3531                 .pointee_type = final_elem_ty,
   3532                 .mutable = true,
   3533                 .@"align" = inferred_alloc.data.alignment,
   3534                 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
   3535             });
   3536             const dummy_ptr = try trash_block.addTy(.alloc, mut_final_ptr_ty);
   3537             const empty_trash_count = trash_block.instructions.items.len;
   3538 
   3539             for (placeholders) |bitcast_inst, i| {
   3540                 const sub_ptr_ty = sema.typeOf(Air.indexToRef(bitcast_inst));
   3541 
   3542                 if (mut_final_ptr_ty.eql(sub_ptr_ty, sema.mod)) {
   3543                     // New result location type is the same as the old one; nothing
   3544                     // to do here.
   3545                     continue;
   3546                 }
   3547 
   3548                 var bitcast_block = block.makeSubBlock();
   3549                 defer bitcast_block.instructions.deinit(gpa);
   3550 
   3551                 trash_block.instructions.shrinkRetainingCapacity(empty_trash_count);
   3552                 const sub_ptr = try coerceResultPtr(sema, &bitcast_block, src, ptr, dummy_ptr, peer_inst_list[i], &trash_block);
   3553 
   3554                 assert(bitcast_block.instructions.items.len > 0);
   3555                 // If only one instruction is produced then we can replace the bitcast
   3556                 // placeholder instruction with this instruction; no need for an entire block.
   3557                 if (bitcast_block.instructions.items.len == 1) {
   3558                     const only_inst = bitcast_block.instructions.items[0];
   3559                     sema.air_instructions.set(bitcast_inst, sema.air_instructions.get(only_inst));
   3560                     continue;
   3561                 }
   3562 
   3563                 // Here we replace the placeholder bitcast instruction with a block
   3564                 // that does the coerce_result_ptr logic.
   3565                 _ = try bitcast_block.addBr(bitcast_inst, sub_ptr);
   3566                 const ty_inst = sema.air_instructions.items(.data)[bitcast_inst].ty_op.ty;
   3567                 try sema.air_extra.ensureUnusedCapacity(
   3568                     gpa,
   3569                     @typeInfo(Air.Block).Struct.fields.len + bitcast_block.instructions.items.len,
   3570                 );
   3571                 sema.air_instructions.set(bitcast_inst, .{
   3572                     .tag = .block,
   3573                     .data = .{ .ty_pl = .{
   3574                         .ty = ty_inst,
   3575                         .payload = sema.addExtraAssumeCapacity(Air.Block{
   3576                             .body_len = @intCast(u32, bitcast_block.instructions.items.len),
   3577                         }),
   3578                     } },
   3579                 });
   3580                 sema.air_extra.appendSliceAssumeCapacity(bitcast_block.instructions.items);
   3581             }
   3582         },
   3583         else => unreachable,
   3584     }
   3585 }
   3586 
   3587 fn zirArrayBasePtr(
   3588     sema: *Sema,
   3589     block: *Block,
   3590     inst: Zir.Inst.Index,
   3591 ) CompileError!Air.Inst.Ref {
   3592     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3593     const src = inst_data.src();
   3594 
   3595     const start_ptr = try sema.resolveInst(inst_data.operand);
   3596     var base_ptr = start_ptr;
   3597     while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) {
   3598         .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
   3599         .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
   3600         else => break,
   3601     };
   3602 
   3603     const elem_ty = sema.typeOf(base_ptr).childType();
   3604     switch (elem_ty.zigTypeTag()) {
   3605         .Array, .Vector => return base_ptr,
   3606         .Struct => if (elem_ty.isTuple()) {
   3607             // TODO validate element count
   3608             return base_ptr;
   3609         },
   3610         else => {},
   3611     }
   3612     return sema.failWithArrayInitNotSupported(block, src, sema.typeOf(start_ptr).childType());
   3613 }
   3614 
   3615 fn zirFieldBasePtr(
   3616     sema: *Sema,
   3617     block: *Block,
   3618     inst: Zir.Inst.Index,
   3619 ) CompileError!Air.Inst.Ref {
   3620     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3621     const src = inst_data.src();
   3622 
   3623     const start_ptr = try sema.resolveInst(inst_data.operand);
   3624     var base_ptr = start_ptr;
   3625     while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) {
   3626         .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
   3627         .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
   3628         else => break,
   3629     };
   3630 
   3631     const elem_ty = sema.typeOf(base_ptr).childType();
   3632     switch (elem_ty.zigTypeTag()) {
   3633         .Struct, .Union => return base_ptr,
   3634         else => {},
   3635     }
   3636     return sema.failWithStructInitNotSupported(block, src, sema.typeOf(start_ptr).childType());
   3637 }
   3638 
   3639 fn validateArrayInitTy(
   3640     sema: *Sema,
   3641     block: *Block,
   3642     inst: Zir.Inst.Index,
   3643 ) CompileError!void {
   3644     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   3645     const src = inst_data.src();
   3646     const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node };
   3647     const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data;
   3648     const ty = try sema.resolveType(block, ty_src, extra.ty);
   3649 
   3650     switch (ty.zigTypeTag()) {
   3651         .Array => {
   3652             const array_len = ty.arrayLen();
   3653             if (extra.init_count != array_len) {
   3654                 return sema.fail(block, src, "expected {d} array elements; found {d}", .{
   3655                     array_len, extra.init_count,
   3656                 });
   3657             }
   3658             return;
   3659         },
   3660         .Vector => {
   3661             const array_len = ty.arrayLen();
   3662             if (extra.init_count != array_len) {
   3663                 return sema.fail(block, src, "expected {d} vector elements; found {d}", .{
   3664                     array_len, extra.init_count,
   3665                 });
   3666             }
   3667             return;
   3668         },
   3669         .Struct => if (ty.isTuple()) {
   3670             const array_len = ty.arrayLen();
   3671             if (extra.init_count > array_len) {
   3672                 return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{
   3673                     array_len, extra.init_count,
   3674                 });
   3675             }
   3676             return;
   3677         },
   3678         else => {},
   3679     }
   3680     return sema.failWithArrayInitNotSupported(block, ty_src, ty);
   3681 }
   3682 
   3683 fn validateStructInitTy(
   3684     sema: *Sema,
   3685     block: *Block,
   3686     inst: Zir.Inst.Index,
   3687 ) CompileError!void {
   3688     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3689     const src = inst_data.src();
   3690     const ty = try sema.resolveType(block, src, inst_data.operand);
   3691 
   3692     switch (ty.zigTypeTag()) {
   3693         .Struct, .Union => return,
   3694         else => {},
   3695     }
   3696     return sema.failWithStructInitNotSupported(block, src, ty);
   3697 }
   3698 
   3699 fn zirValidateStructInit(
   3700     sema: *Sema,
   3701     block: *Block,
   3702     inst: Zir.Inst.Index,
   3703     is_comptime: bool,
   3704 ) CompileError!void {
   3705     const tracy = trace(@src());
   3706     defer tracy.end();
   3707 
   3708     const validate_inst = sema.code.instructions.items(.data)[inst].pl_node;
   3709     const init_src = validate_inst.src();
   3710     const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index);
   3711     const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len];
   3712     const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
   3713     const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
   3714     const object_ptr = try sema.resolveInst(field_ptr_extra.lhs);
   3715     const agg_ty = sema.typeOf(object_ptr).childType();
   3716     switch (agg_ty.zigTypeTag()) {
   3717         .Struct => return sema.validateStructInit(
   3718             block,
   3719             agg_ty,
   3720             init_src,
   3721             instrs,
   3722             is_comptime,
   3723         ),
   3724         .Union => return sema.validateUnionInit(
   3725             block,
   3726             agg_ty,
   3727             init_src,
   3728             instrs,
   3729             object_ptr,
   3730             is_comptime,
   3731         ),
   3732         else => unreachable,
   3733     }
   3734 }
   3735 
   3736 fn validateUnionInit(
   3737     sema: *Sema,
   3738     block: *Block,
   3739     union_ty: Type,
   3740     init_src: LazySrcLoc,
   3741     instrs: []const Zir.Inst.Index,
   3742     union_ptr: Air.Inst.Ref,
   3743     is_comptime: bool,
   3744 ) CompileError!void {
   3745     if (instrs.len != 1) {
   3746         const msg = msg: {
   3747             const msg = try sema.errMsg(
   3748                 block,
   3749                 init_src,
   3750                 "cannot initialize multiple union fields at once, unions can only have one active field",
   3751                 .{},
   3752             );
   3753             errdefer msg.destroy(sema.gpa);
   3754 
   3755             for (instrs[1..]) |inst| {
   3756                 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   3757                 const inst_src: LazySrcLoc = .{ .node_offset_initializer = inst_data.src_node };
   3758                 try sema.errNote(block, inst_src, msg, "additional initializer here", .{});
   3759             }
   3760             try sema.addDeclaredHereNote(msg, union_ty);
   3761             break :msg msg;
   3762         };
   3763         return sema.failWithOwnedErrorMsg(msg);
   3764     }
   3765 
   3766     if ((is_comptime or block.is_comptime) and
   3767         (try sema.resolveDefinedValue(block, init_src, union_ptr)) != null)
   3768     {
   3769         // In this case, comptime machinery already did everything. No work to do here.
   3770         return;
   3771     }
   3772 
   3773     const field_ptr = instrs[0];
   3774     const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node;
   3775     const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node };
   3776     const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
   3777     const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
   3778     // Validate the field access but ignore the index since we want the tag enum field index.
   3779     _ = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
   3780     const air_tags = sema.air_instructions.items(.tag);
   3781     const air_datas = sema.air_instructions.items(.data);
   3782     const field_ptr_air_ref = sema.inst_map.get(field_ptr).?;
   3783     const field_ptr_air_inst = Air.refToIndex(field_ptr_air_ref).?;
   3784 
   3785     // Our task here is to determine if the union is comptime-known. In such case,
   3786     // we erase the runtime AIR instructions for initializing the union, and replace
   3787     // the mapping with the comptime value. Either way, we will need to populate the tag.
   3788 
   3789     // We expect to see something like this in the current block AIR:
   3790     //   %a = alloc(*const U)
   3791     //   %b = bitcast(*U, %a)
   3792     //   %c = field_ptr(..., %b)
   3793     //   %e!= store(%c!, %d!)
   3794     // If %d is a comptime operand, the union is comptime.
   3795     // If the union is comptime, we want `first_block_index`
   3796     // to point at %c so that the bitcast becomes the last instruction in the block.
   3797     //
   3798     // In the case of a comptime-known pointer to a union, the
   3799     // the field_ptr instruction is missing, so we have to pattern-match
   3800     // based only on the store instructions.
   3801     // `first_block_index` needs to point to the `field_ptr` if it exists;
   3802     // the `store` otherwise.
   3803     //
   3804     // It's also possible for there to be no store instruction, in the case
   3805     // of nested `coerce_result_ptr` instructions. If we see the `field_ptr`
   3806     // but we have not found a `store`, treat as a runtime-known field.
   3807     var first_block_index = block.instructions.items.len;
   3808     var block_index = block.instructions.items.len - 1;
   3809     var init_val: ?Value = null;
   3810     while (block_index > 0) : (block_index -= 1) {
   3811         const store_inst = block.instructions.items[block_index];
   3812         if (store_inst == field_ptr_air_inst) break;
   3813         if (air_tags[store_inst] != .store) continue;
   3814         const bin_op = air_datas[store_inst].bin_op;
   3815         var lhs = bin_op.lhs;
   3816         if (Air.refToIndex(lhs)) |lhs_index| {
   3817             if (air_tags[lhs_index] == .bitcast) {
   3818                 lhs = air_datas[lhs_index].ty_op.operand;
   3819                 block_index -= 1;
   3820             }
   3821         }
   3822         if (lhs != field_ptr_air_ref) continue;
   3823         while (block_index > 0) : (block_index -= 1) {
   3824             const block_inst = block.instructions.items[block_index - 1];
   3825             if (air_tags[block_inst] != .dbg_stmt) break;
   3826         }
   3827         if (block_index > 0 and
   3828             field_ptr_air_inst == block.instructions.items[block_index - 1])
   3829         {
   3830             first_block_index = @minimum(first_block_index, block_index - 1);
   3831         } else {
   3832             first_block_index = @minimum(first_block_index, block_index);
   3833         }
   3834         init_val = try sema.resolveMaybeUndefValAllowVariables(block, init_src, bin_op.rhs);
   3835         break;
   3836     }
   3837 
   3838     const tag_ty = union_ty.unionTagTypeHypothetical();
   3839     const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
   3840     const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
   3841 
   3842     if (init_val) |val| {
   3843         // Our task is to delete all the `field_ptr` and `store` instructions, and insert
   3844         // instead a single `store` to the result ptr with a comptime union value.
   3845         block.instructions.shrinkRetainingCapacity(first_block_index);
   3846 
   3847         const union_val = try Value.Tag.@"union".create(sema.arena, .{
   3848             .tag = tag_val,
   3849             .val = val,
   3850         });
   3851         const union_init = try sema.addConstant(union_ty, union_val);
   3852         try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store);
   3853         return;
   3854     }
   3855 
   3856     try sema.requireFunctionBlock(block, init_src);
   3857     const new_tag = try sema.addConstant(tag_ty, tag_val);
   3858     _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag);
   3859 }
   3860 
   3861 fn validateStructInit(
   3862     sema: *Sema,
   3863     block: *Block,
   3864     struct_ty: Type,
   3865     init_src: LazySrcLoc,
   3866     instrs: []const Zir.Inst.Index,
   3867     is_comptime: bool,
   3868 ) CompileError!void {
   3869     const gpa = sema.gpa;
   3870 
   3871     // Maps field index to field_ptr index of where it was already initialized.
   3872     const found_fields = try gpa.alloc(Zir.Inst.Index, struct_ty.structFieldCount());
   3873     defer gpa.free(found_fields);
   3874     mem.set(Zir.Inst.Index, found_fields, 0);
   3875 
   3876     var struct_ptr_zir_ref: Zir.Inst.Ref = undefined;
   3877 
   3878     for (instrs) |field_ptr| {
   3879         const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node;
   3880         const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node };
   3881         const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
   3882         struct_ptr_zir_ref = field_ptr_extra.lhs;
   3883         const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
   3884         const field_index = if (struct_ty.isTuple())
   3885             try sema.tupleFieldIndex(block, struct_ty, field_name, field_src)
   3886         else
   3887             try sema.structFieldIndex(block, struct_ty, field_name, field_src);
   3888         if (found_fields[field_index] != 0) {
   3889             const other_field_ptr = found_fields[field_index];
   3890             const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node;
   3891             const other_field_src: LazySrcLoc = .{ .node_offset_initializer = other_field_ptr_data.src_node };
   3892             const msg = msg: {
   3893                 const msg = try sema.errMsg(block, field_src, "duplicate field", .{});
   3894                 errdefer msg.destroy(gpa);
   3895                 try sema.errNote(block, other_field_src, msg, "other field here", .{});
   3896                 break :msg msg;
   3897             };
   3898             return sema.failWithOwnedErrorMsg(msg);
   3899         }
   3900         found_fields[field_index] = field_ptr;
   3901     }
   3902 
   3903     var root_msg: ?*Module.ErrorMsg = null;
   3904     errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
   3905 
   3906     const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);
   3907     if ((is_comptime or block.is_comptime) and
   3908         (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null)
   3909     {
   3910         try sema.resolveStructLayout(block, init_src, struct_ty);
   3911         // In this case the only thing we need to do is evaluate the implicit
   3912         // store instructions for default field values, and report any missing fields.
   3913         // Avoid the cost of the extra machinery for detecting a comptime struct init value.
   3914         for (found_fields) |field_ptr, i| {
   3915             if (field_ptr != 0) continue;
   3916 
   3917             const default_val = struct_ty.structFieldDefaultValue(i);
   3918             if (default_val.tag() == .unreachable_value) {
   3919                 if (struct_ty.isTuple()) {
   3920                     const template = "missing tuple field with index {d}";
   3921                     if (root_msg) |msg| {
   3922                         try sema.errNote(block, init_src, msg, template, .{i});
   3923                     } else {
   3924                         root_msg = try sema.errMsg(block, init_src, template, .{i});
   3925                     }
   3926                     continue;
   3927                 }
   3928                 const field_name = struct_ty.structFieldName(i);
   3929                 const template = "missing struct field: {s}";
   3930                 const args = .{field_name};
   3931                 if (root_msg) |msg| {
   3932                     try sema.errNote(block, init_src, msg, template, args);
   3933                 } else {
   3934                     root_msg = try sema.errMsg(block, init_src, template, args);
   3935                 }
   3936                 continue;
   3937             }
   3938 
   3939             const field_src = init_src; // TODO better source location
   3940             const default_field_ptr = if (struct_ty.isTuple())
   3941                 try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true)
   3942             else
   3943                 try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true);
   3944             const field_ty = sema.typeOf(default_field_ptr).childType();
   3945             const init = try sema.addConstant(field_ty, default_val);
   3946             try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
   3947         }
   3948 
   3949         if (root_msg) |msg| {
   3950             if (struct_ty.castTag(.@"struct")) |struct_obj| {
   3951                 const mod = sema.mod;
   3952                 const fqn = try struct_obj.data.getFullyQualifiedName(mod);
   3953                 defer gpa.free(fqn);
   3954                 try mod.errNoteNonLazy(
   3955                     struct_obj.data.srcLoc(mod),
   3956                     msg,
   3957                     "struct '{s}' declared here",
   3958                     .{fqn},
   3959                 );
   3960             }
   3961             return sema.failWithOwnedErrorMsg(msg);
   3962         }
   3963 
   3964         return;
   3965     }
   3966 
   3967     var struct_is_comptime = true;
   3968     var first_block_index = block.instructions.items.len;
   3969 
   3970     const air_tags = sema.air_instructions.items(.tag);
   3971     const air_datas = sema.air_instructions.items(.data);
   3972 
   3973     // We collect the comptime field values in case the struct initialization
   3974     // ends up being comptime-known.
   3975     const field_values = try sema.arena.alloc(Value, struct_ty.structFieldCount());
   3976 
   3977     field: for (found_fields) |field_ptr, i| {
   3978         if (field_ptr != 0) {
   3979             const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node;
   3980             const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node };
   3981 
   3982             // Determine whether the value stored to this pointer is comptime-known.
   3983             const field_ty = struct_ty.structFieldType(i);
   3984             if (try sema.typeHasOnePossibleValue(block, field_src, field_ty)) |opv| {
   3985                 field_values[i] = opv;
   3986                 continue;
   3987             }
   3988 
   3989             const field_ptr_air_ref = sema.inst_map.get(field_ptr).?;
   3990             const field_ptr_air_inst = Air.refToIndex(field_ptr_air_ref).?;
   3991 
   3992             //std.debug.print("validateStructInit (field_ptr_air_inst=%{d}):\n", .{
   3993             //    field_ptr_air_inst,
   3994             //});
   3995             //for (block.instructions.items) |item| {
   3996             //    std.debug.print("  %{d} = {s}\n", .{item, @tagName(air_tags[item])});
   3997             //}
   3998 
   3999             // We expect to see something like this in the current block AIR:
   4000             //   %a = field_ptr(...)
   4001             //   store(%a, %b)
   4002             // If %b is a comptime operand, this field is comptime.
   4003             //
   4004             // However, in the case of a comptime-known pointer to a struct, the
   4005             // the field_ptr instruction is missing, so we have to pattern-match
   4006             // based only on the store instructions.
   4007             // `first_block_index` needs to point to the `field_ptr` if it exists;
   4008             // the `store` otherwise.
   4009             //
   4010             // It's also possible for there to be no store instruction, in the case
   4011             // of nested `coerce_result_ptr` instructions. If we see the `field_ptr`
   4012             // but we have not found a `store`, treat as a runtime-known field.
   4013 
   4014             // Possible performance enhancement: save the `block_index` between iterations
   4015             // of the for loop.
   4016             var block_index = block.instructions.items.len - 1;
   4017             while (block_index > 0) : (block_index -= 1) {
   4018                 const store_inst = block.instructions.items[block_index];
   4019                 if (store_inst == field_ptr_air_inst) {
   4020                     struct_is_comptime = false;
   4021                     continue :field;
   4022                 }
   4023                 if (air_tags[store_inst] != .store) continue;
   4024                 const bin_op = air_datas[store_inst].bin_op;
   4025                 var lhs = bin_op.lhs;
   4026                 {
   4027                     const lhs_index = Air.refToIndex(lhs) orelse continue;
   4028                     if (air_tags[lhs_index] == .bitcast) {
   4029                         lhs = air_datas[lhs_index].ty_op.operand;
   4030                         block_index -= 1;
   4031                     }
   4032                 }
   4033                 if (lhs != field_ptr_air_ref) continue;
   4034                 while (block_index > 0) : (block_index -= 1) {
   4035                     const block_inst = block.instructions.items[block_index - 1];
   4036                     if (air_tags[block_inst] != .dbg_stmt) break;
   4037                 }
   4038                 if (block_index > 0 and
   4039                     field_ptr_air_inst == block.instructions.items[block_index - 1])
   4040                 {
   4041                     first_block_index = @minimum(first_block_index, block_index - 1);
   4042                 } else {
   4043                     first_block_index = @minimum(first_block_index, block_index);
   4044                 }
   4045                 if (try sema.resolveMaybeUndefValAllowVariables(block, field_src, bin_op.rhs)) |val| {
   4046                     field_values[i] = val;
   4047                 } else {
   4048                     struct_is_comptime = false;
   4049                 }
   4050                 continue :field;
   4051             }
   4052             struct_is_comptime = false;
   4053             continue :field;
   4054         }
   4055 
   4056         const default_val = struct_ty.structFieldDefaultValue(i);
   4057         if (default_val.tag() == .unreachable_value) {
   4058             if (struct_ty.isTuple()) {
   4059                 const template = "missing tuple field with index {d}";
   4060                 if (root_msg) |msg| {
   4061                     try sema.errNote(block, init_src, msg, template, .{i});
   4062                 } else {
   4063                     root_msg = try sema.errMsg(block, init_src, template, .{i});
   4064                 }
   4065                 continue;
   4066             }
   4067             const field_name = struct_ty.structFieldName(i);
   4068             const template = "missing struct field: {s}";
   4069             const args = .{field_name};
   4070             if (root_msg) |msg| {
   4071                 try sema.errNote(block, init_src, msg, template, args);
   4072             } else {
   4073                 root_msg = try sema.errMsg(block, init_src, template, args);
   4074             }
   4075             continue;
   4076         }
   4077         field_values[i] = default_val;
   4078     }
   4079 
   4080     if (root_msg) |msg| {
   4081         root_msg = null;
   4082         if (struct_ty.castTag(.@"struct")) |struct_obj| {
   4083             const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
   4084             defer gpa.free(fqn);
   4085             try sema.mod.errNoteNonLazy(
   4086                 struct_obj.data.srcLoc(sema.mod),
   4087                 msg,
   4088                 "struct '{s}' declared here",
   4089                 .{fqn},
   4090             );
   4091         }
   4092         return sema.failWithOwnedErrorMsg(msg);
   4093     }
   4094 
   4095     if (struct_is_comptime) {
   4096         // Our task is to delete all the `field_ptr` and `store` instructions, and insert
   4097         // instead a single `store` to the struct_ptr with a comptime struct value.
   4098 
   4099         block.instructions.shrinkRetainingCapacity(first_block_index);
   4100         const struct_val = try Value.Tag.aggregate.create(sema.arena, field_values);
   4101         const struct_init = try sema.addConstant(struct_ty, struct_val);
   4102         try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
   4103         return;
   4104     }
   4105     try sema.resolveStructLayout(block, init_src, struct_ty);
   4106 
   4107     // Our task is to insert `store` instructions for all the default field values.
   4108     for (found_fields) |field_ptr, i| {
   4109         if (field_ptr != 0) continue;
   4110 
   4111         const field_src = init_src; // TODO better source location
   4112         const default_field_ptr = if (struct_ty.isTuple())
   4113             try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true)
   4114         else
   4115             try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true);
   4116         const field_ty = sema.typeOf(default_field_ptr).childType();
   4117         const init = try sema.addConstant(field_ty, field_values[i]);
   4118         try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
   4119     }
   4120 }
   4121 
   4122 fn zirValidateArrayInit(
   4123     sema: *Sema,
   4124     block: *Block,
   4125     inst: Zir.Inst.Index,
   4126     is_comptime: bool,
   4127 ) CompileError!void {
   4128     const validate_inst = sema.code.instructions.items(.data)[inst].pl_node;
   4129     const init_src = validate_inst.src();
   4130     const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index);
   4131     const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len];
   4132     const first_elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
   4133     const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data;
   4134     const array_ptr = try sema.resolveInst(elem_ptr_extra.ptr);
   4135     const array_ty = sema.typeOf(array_ptr).childType();
   4136     const array_len = array_ty.arrayLen();
   4137 
   4138     if (instrs.len != array_len and array_ty.isTuple()) {
   4139         const struct_obj = array_ty.castTag(.tuple).?.data;
   4140         var root_msg: ?*Module.ErrorMsg = null;
   4141         errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
   4142 
   4143         for (struct_obj.values) |default_val, i| {
   4144             if (i < instrs.len) continue;
   4145 
   4146             if (default_val.tag() == .unreachable_value) {
   4147                 const template = "missing tuple field with index {d}";
   4148                 if (root_msg) |msg| {
   4149                     try sema.errNote(block, init_src, msg, template, .{i});
   4150                 } else {
   4151                     root_msg = try sema.errMsg(block, init_src, template, .{i});
   4152                 }
   4153             }
   4154         }
   4155 
   4156         if (root_msg) |msg| {
   4157             root_msg = null;
   4158             return sema.failWithOwnedErrorMsg(msg);
   4159         }
   4160     }
   4161 
   4162     if ((is_comptime or block.is_comptime) and
   4163         (try sema.resolveDefinedValue(block, init_src, array_ptr)) != null)
   4164     {
   4165         // In this case the comptime machinery will have evaluated the store instructions
   4166         // at comptime so we have almost nothing to do here. However, in case of a
   4167         // sentinel-terminated array, the sentinel will not have been populated by
   4168         // any ZIR instructions at comptime; we need to do that here.
   4169         if (array_ty.sentinel()) |sentinel_val| {
   4170             const array_len_ref = try sema.addIntUnsigned(Type.usize, array_len);
   4171             const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true);
   4172             const sentinel = try sema.addConstant(array_ty.childType(), sentinel_val);
   4173             try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store);
   4174         }
   4175         return;
   4176     }
   4177 
   4178     var array_is_comptime = true;
   4179     var first_block_index = block.instructions.items.len;
   4180 
   4181     // Collect the comptime element values in case the array literal ends up
   4182     // being comptime-known.
   4183     const array_len_s = try sema.usizeCast(block, init_src, array_ty.arrayLenIncludingSentinel());
   4184     const element_vals = try sema.arena.alloc(Value, array_len_s);
   4185     const opt_opv = try sema.typeHasOnePossibleValue(block, init_src, array_ty);
   4186     const air_tags = sema.air_instructions.items(.tag);
   4187     const air_datas = sema.air_instructions.items(.data);
   4188 
   4189     outer: for (instrs) |elem_ptr, i| {
   4190         const elem_ptr_data = sema.code.instructions.items(.data)[elem_ptr].pl_node;
   4191         const elem_src = LazySrcLoc.nodeOffset(elem_ptr_data.src_node);
   4192 
   4193         // Determine whether the value stored to this pointer is comptime-known.
   4194 
   4195         if (array_ty.isTuple()) {
   4196             if (array_ty.structFieldValueComptime(i)) |opv| {
   4197                 element_vals[i] = opv;
   4198                 continue;
   4199             }
   4200         } else {
   4201             // Array has one possible value, so value is always comptime-known
   4202             if (opt_opv) |opv| {
   4203                 element_vals[i] = opv;
   4204                 continue;
   4205             }
   4206         }
   4207 
   4208         const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;
   4209         const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?;
   4210         // Find the block index of the elem_ptr so that we can look at the next
   4211         // instruction after it within the same block.
   4212         // Possible performance enhancement: save the `block_index` between iterations
   4213         // of the for loop.
   4214         var block_index = block.instructions.items.len - 1;
   4215         while (block.instructions.items[block_index] != elem_ptr_air_inst) {
   4216             if (block_index == 0) {
   4217                 array_is_comptime = true;
   4218                 continue :outer;
   4219             }
   4220             block_index -= 1;
   4221         }
   4222         first_block_index = @minimum(first_block_index, block_index);
   4223 
   4224         // If the next instructon is a store with a comptime operand, this element
   4225         // is comptime.
   4226         const next_air_inst = block.instructions.items[block_index + 1];
   4227         switch (air_tags[next_air_inst]) {
   4228             .store => {
   4229                 const bin_op = air_datas[next_air_inst].bin_op;
   4230                 var lhs = bin_op.lhs;
   4231                 if (Air.refToIndex(lhs)) |lhs_index| {
   4232                     if (air_tags[lhs_index] == .bitcast) {
   4233                         lhs = air_datas[lhs_index].ty_op.operand;
   4234                         block_index -= 1;
   4235                     }
   4236                 }
   4237                 if (lhs != elem_ptr_air_ref) {
   4238                     array_is_comptime = false;
   4239                     continue;
   4240                 }
   4241                 if (try sema.resolveMaybeUndefValAllowVariables(block, elem_src, bin_op.rhs)) |val| {
   4242                     element_vals[i] = val;
   4243                 } else {
   4244                     array_is_comptime = false;
   4245                 }
   4246                 continue;
   4247             },
   4248             .bitcast => {
   4249                 // %a = bitcast(*arr_ty, %array_base)
   4250                 // %b = ptr_elem_ptr(%a, %index)
   4251                 // %c = bitcast(*elem_ty, %b)
   4252                 // %d = store(%c, %val)
   4253                 if (air_datas[next_air_inst].ty_op.operand != elem_ptr_air_ref) {
   4254                     array_is_comptime = false;
   4255                     continue;
   4256                 }
   4257                 const store_inst = block.instructions.items[block_index + 2];
   4258                 if (air_tags[store_inst] != .store) {
   4259                     array_is_comptime = false;
   4260                     continue;
   4261                 }
   4262                 const bin_op = air_datas[store_inst].bin_op;
   4263                 if (bin_op.lhs != Air.indexToRef(next_air_inst)) {
   4264                     array_is_comptime = false;
   4265                     continue;
   4266                 }
   4267                 if (try sema.resolveMaybeUndefValAllowVariables(block, elem_src, bin_op.rhs)) |val| {
   4268                     element_vals[i] = val;
   4269                 } else {
   4270                     array_is_comptime = false;
   4271                 }
   4272                 continue;
   4273             },
   4274             else => {
   4275                 array_is_comptime = false;
   4276                 continue;
   4277             },
   4278         }
   4279     }
   4280 
   4281     if (array_is_comptime) {
   4282         if (try sema.resolveDefinedValue(block, init_src, array_ptr)) |ptr_val| {
   4283             if (ptr_val.tag() == .comptime_field_ptr) {
   4284                 // This store was validated by the individual elem ptrs.
   4285                 return;
   4286             }
   4287         }
   4288 
   4289         // Our task is to delete all the `elem_ptr` and `store` instructions, and insert
   4290         // instead a single `store` to the array_ptr with a comptime struct value.
   4291         // Also to populate the sentinel value, if any.
   4292         if (array_ty.sentinel()) |sentinel_val| {
   4293             element_vals[instrs.len] = sentinel_val;
   4294         }
   4295 
   4296         block.instructions.shrinkRetainingCapacity(first_block_index);
   4297 
   4298         const array_val = try Value.Tag.aggregate.create(sema.arena, element_vals);
   4299         const array_init = try sema.addConstant(array_ty, array_val);
   4300         try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
   4301     }
   4302 }
   4303 
   4304 fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   4305     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   4306     const src = inst_data.src();
   4307     const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
   4308     const operand = try sema.resolveInst(inst_data.operand);
   4309     const operand_ty = sema.typeOf(operand);
   4310 
   4311     if (operand_ty.zigTypeTag() != .Pointer) {
   4312         return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(sema.mod)});
   4313     } else switch (operand_ty.ptrSize()) {
   4314         .One, .C => {},
   4315         .Many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(sema.mod)}),
   4316         .Slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(sema.mod)}),
   4317     }
   4318 
   4319     const elem_ty = operand_ty.elemType2();
   4320     if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
   4321         if (val.isUndef()) {
   4322             return sema.fail(block, src, "cannot dereference undefined value", .{});
   4323         }
   4324     } else if (!(try sema.validateRunTimeType(block, src, elem_ty, false))) {
   4325         const msg = msg: {
   4326             const msg = try sema.errMsg(
   4327                 block,
   4328                 src,
   4329                 "values of type '{}' must be comptime known, but operand value is runtime known",
   4330                 .{elem_ty.fmt(sema.mod)},
   4331             );
   4332             errdefer msg.destroy(sema.gpa);
   4333 
   4334             const src_decl = sema.mod.declPtr(block.src_decl);
   4335             try sema.explainWhyTypeIsComptime(block, src, msg, src.toSrcLoc(src_decl), elem_ty);
   4336             break :msg msg;
   4337         };
   4338         return sema.failWithOwnedErrorMsg(msg);
   4339     }
   4340 }
   4341 
   4342 fn failWithBadMemberAccess(
   4343     sema: *Sema,
   4344     block: *Block,
   4345     agg_ty: Type,
   4346     field_src: LazySrcLoc,
   4347     field_name: []const u8,
   4348 ) CompileError {
   4349     const kw_name = switch (agg_ty.zigTypeTag()) {
   4350         .Union => "union",
   4351         .Struct => "struct",
   4352         .Opaque => "opaque",
   4353         .Enum => "enum",
   4354         else => unreachable,
   4355     };
   4356     const msg = msg: {
   4357         const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{s}'", .{
   4358             kw_name, agg_ty.fmt(sema.mod), field_name,
   4359         });
   4360         errdefer msg.destroy(sema.gpa);
   4361         try sema.addDeclaredHereNote(msg, agg_ty);
   4362         break :msg msg;
   4363     };
   4364     return sema.failWithOwnedErrorMsg(msg);
   4365 }
   4366 
   4367 fn failWithBadStructFieldAccess(
   4368     sema: *Sema,
   4369     block: *Block,
   4370     struct_obj: *Module.Struct,
   4371     field_src: LazySrcLoc,
   4372     field_name: []const u8,
   4373 ) CompileError {
   4374     const gpa = sema.gpa;
   4375 
   4376     const fqn = try struct_obj.getFullyQualifiedName(sema.mod);
   4377     defer gpa.free(fqn);
   4378 
   4379     const msg = msg: {
   4380         const msg = try sema.errMsg(
   4381             block,
   4382             field_src,
   4383             "no field named '{s}' in struct '{s}'",
   4384             .{ field_name, fqn },
   4385         );
   4386         errdefer msg.destroy(gpa);
   4387         try sema.mod.errNoteNonLazy(struct_obj.srcLoc(sema.mod), msg, "struct declared here", .{});
   4388         break :msg msg;
   4389     };
   4390     return sema.failWithOwnedErrorMsg(msg);
   4391 }
   4392 
   4393 fn failWithBadUnionFieldAccess(
   4394     sema: *Sema,
   4395     block: *Block,
   4396     union_obj: *Module.Union,
   4397     field_src: LazySrcLoc,
   4398     field_name: []const u8,
   4399 ) CompileError {
   4400     const gpa = sema.gpa;
   4401 
   4402     const fqn = try union_obj.getFullyQualifiedName(sema.mod);
   4403     defer gpa.free(fqn);
   4404 
   4405     const msg = msg: {
   4406         const msg = try sema.errMsg(
   4407             block,
   4408             field_src,
   4409             "no field named '{s}' in union '{s}'",
   4410             .{ field_name, fqn },
   4411         );
   4412         errdefer msg.destroy(gpa);
   4413         try sema.mod.errNoteNonLazy(union_obj.srcLoc(sema.mod), msg, "union declared here", .{});
   4414         break :msg msg;
   4415     };
   4416     return sema.failWithOwnedErrorMsg(msg);
   4417 }
   4418 
   4419 fn addDeclaredHereNote(sema: *Sema, parent: *Module.ErrorMsg, decl_ty: Type) !void {
   4420     const src_loc = decl_ty.declSrcLocOrNull(sema.mod) orelse return;
   4421     const category = switch (decl_ty.zigTypeTag()) {
   4422         .Union => "union",
   4423         .Struct => "struct",
   4424         .Enum => "enum",
   4425         .Opaque => "opaque",
   4426         .ErrorSet => "error set",
   4427         else => unreachable,
   4428     };
   4429     try sema.mod.errNoteNonLazy(src_loc, parent, "{s} declared here", .{category});
   4430 }
   4431 
   4432 fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   4433     const tracy = trace(@src());
   4434     defer tracy.end();
   4435 
   4436     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
   4437     const ptr = sema.inst_map.get(Zir.refToIndex(bin_inst.lhs).?) orelse {
   4438         // This is an elided instruction, but AstGen was unable to omit it.
   4439         return;
   4440     };
   4441     const operand = try sema.resolveInst(bin_inst.rhs);
   4442     const src: LazySrcLoc = sema.src;
   4443     blk: {
   4444         const ptr_inst = Air.refToIndex(ptr) orelse break :blk;
   4445         if (sema.air_instructions.items(.tag)[ptr_inst] != .constant) break :blk;
   4446         const air_datas = sema.air_instructions.items(.data);
   4447         const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
   4448         switch (ptr_val.tag()) {
   4449             .inferred_alloc_comptime => {
   4450                 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
   4451                 return sema.storeToInferredAllocComptime(block, src, operand, iac);
   4452             },
   4453             .inferred_alloc => {
   4454                 const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
   4455                 return sema.storeToInferredAlloc(block, src, ptr, operand, inferred_alloc);
   4456             },
   4457             else => break :blk,
   4458         }
   4459     }
   4460 
   4461     return sema.storePtr(block, src, ptr, operand);
   4462 }
   4463 
   4464 fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   4465     const tracy = trace(@src());
   4466     defer tracy.end();
   4467 
   4468     const src: LazySrcLoc = sema.src;
   4469     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
   4470     const ptr = try sema.resolveInst(bin_inst.lhs);
   4471     const operand = try sema.resolveInst(bin_inst.rhs);
   4472     const ptr_inst = Air.refToIndex(ptr).?;
   4473     assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant);
   4474     const air_datas = sema.air_instructions.items(.data);
   4475     const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
   4476 
   4477     switch (ptr_val.tag()) {
   4478         .inferred_alloc_comptime => {
   4479             const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
   4480             return sema.storeToInferredAllocComptime(block, src, operand, iac);
   4481         },
   4482         .inferred_alloc => {
   4483             const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
   4484             return sema.storeToInferredAlloc(block, src, ptr, operand, inferred_alloc);
   4485         },
   4486         else => unreachable,
   4487     }
   4488 }
   4489 
   4490 fn storeToInferredAlloc(
   4491     sema: *Sema,
   4492     block: *Block,
   4493     src: LazySrcLoc,
   4494     ptr: Air.Inst.Ref,
   4495     operand: Air.Inst.Ref,
   4496     inferred_alloc: *Value.Payload.InferredAlloc,
   4497 ) CompileError!void {
   4498     const operand_ty = sema.typeOf(operand);
   4499     // Create a runtime bitcast instruction with exactly the type the pointer wants.
   4500     const target = sema.mod.getTarget();
   4501     const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
   4502         .pointee_type = operand_ty,
   4503         .@"align" = inferred_alloc.data.alignment,
   4504         .@"addrspace" = target_util.defaultAddressSpace(target, .local),
   4505     });
   4506     const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);
   4507     // Add the stored instruction to the set we will use to resolve peer types
   4508     // for the inferred allocation.
   4509     try inferred_alloc.data.prongs.append(sema.arena, .{
   4510         .stored_inst = operand,
   4511         .placeholder = Air.refToIndex(bitcasted_ptr).?,
   4512     });
   4513     return sema.storePtr2(block, src, bitcasted_ptr, src, operand, src, .bitcast);
   4514 }
   4515 
   4516 fn storeToInferredAllocComptime(
   4517     sema: *Sema,
   4518     block: *Block,
   4519     src: LazySrcLoc,
   4520     operand: Air.Inst.Ref,
   4521     iac: *Value.Payload.InferredAllocComptime,
   4522 ) CompileError!void {
   4523     const operand_ty = sema.typeOf(operand);
   4524     // There will be only one store_to_inferred_ptr because we are running at comptime.
   4525     // The alloc will turn into a Decl.
   4526     if (try sema.resolveMaybeUndefValAllowVariables(block, src, operand)) |operand_val| store: {
   4527         if (operand_val.tag() == .variable) break :store;
   4528         var anon_decl = try block.startAnonDecl(src);
   4529         defer anon_decl.deinit();
   4530         iac.data.decl_index = try anon_decl.finish(
   4531             try operand_ty.copy(anon_decl.arena()),
   4532             try operand_val.copy(anon_decl.arena()),
   4533             iac.data.alignment,
   4534         );
   4535         return;
   4536     }
   4537 
   4538     return sema.failWithNeededComptime(block, src, "value being stored to a comptime variable must be comptime known");
   4539 }
   4540 
   4541 fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   4542     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   4543     const src = inst_data.src();
   4544     const quota = @intCast(u32, try sema.resolveInt(block, src, inst_data.operand, Type.u32, "eval branch quota must be comptime known"));
   4545     sema.branch_quota = @maximum(sema.branch_quota, quota);
   4546 }
   4547 
   4548 fn zirStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   4549     const tracy = trace(@src());
   4550     defer tracy.end();
   4551 
   4552     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
   4553     const ptr = try sema.resolveInst(bin_inst.lhs);
   4554     const value = try sema.resolveInst(bin_inst.rhs);
   4555     return sema.storePtr(block, sema.src, ptr, value);
   4556 }
   4557 
   4558 fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   4559     const tracy = trace(@src());
   4560     defer tracy.end();
   4561 
   4562     const zir_tags = sema.code.instructions.items(.tag);
   4563     const zir_datas = sema.code.instructions.items(.data);
   4564     const inst_data = zir_datas[inst].pl_node;
   4565     const src = inst_data.src();
   4566     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   4567     const ptr = try sema.resolveInst(extra.lhs);
   4568     const operand = try sema.resolveInst(extra.rhs);
   4569 
   4570     const is_ret = if (Zir.refToIndex(extra.lhs)) |ptr_index|
   4571         zir_tags[ptr_index] == .ret_ptr
   4572     else
   4573         false;
   4574 
   4575     // Check for the possibility of this pattern:
   4576     //   %a = ret_ptr
   4577     //   %b = store(%a, %c)
   4578     // Where %c is an error union or error set. In such case we need to add
   4579     // to the current function's inferred error set, if any.
   4580     if (is_ret and (sema.typeOf(operand).zigTypeTag() == .ErrorUnion or
   4581         sema.typeOf(operand).zigTypeTag() == .ErrorSet) and
   4582         sema.fn_ret_ty.zigTypeTag() == .ErrorUnion)
   4583     {
   4584         try sema.addToInferredErrorSet(operand);
   4585     }
   4586 
   4587     return sema.storePtr2(block, src, ptr, src, operand, src, if (is_ret) .ret_ptr else .store);
   4588 }
   4589 
   4590 fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   4591     const tracy = trace(@src());
   4592     defer tracy.end();
   4593 
   4594     const bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code);
   4595     return sema.addStrLit(block, bytes);
   4596 }
   4597 
   4598 fn addStrLit(sema: *Sema, block: *Block, zir_bytes: []const u8) CompileError!Air.Inst.Ref {
   4599     // `zir_bytes` references memory inside the ZIR module, which can get deallocated
   4600     // after semantic analysis is complete, for example in the case of the initialization
   4601     // expression of a variable declaration.
   4602     const mod = sema.mod;
   4603     const gpa = sema.gpa;
   4604     const string_bytes = &mod.string_literal_bytes;
   4605     const StringLiteralAdapter = Module.StringLiteralAdapter;
   4606     const StringLiteralContext = Module.StringLiteralContext;
   4607     try string_bytes.ensureUnusedCapacity(gpa, zir_bytes.len);
   4608     const gop = try mod.string_literal_table.getOrPutContextAdapted(gpa, zir_bytes, StringLiteralAdapter{
   4609         .bytes = string_bytes,
   4610     }, StringLiteralContext{
   4611         .bytes = string_bytes,
   4612     });
   4613     if (!gop.found_existing) {
   4614         gop.key_ptr.* = .{
   4615             .index = @intCast(u32, string_bytes.items.len),
   4616             .len = @intCast(u32, zir_bytes.len),
   4617         };
   4618         string_bytes.appendSliceAssumeCapacity(zir_bytes);
   4619         gop.value_ptr.* = .none;
   4620     }
   4621     const decl_index = gop.value_ptr.unwrap() orelse di: {
   4622         var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
   4623         defer anon_decl.deinit();
   4624 
   4625         const decl_index = try anon_decl.finish(
   4626             try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), gop.key_ptr.len),
   4627             try Value.Tag.str_lit.create(anon_decl.arena(), gop.key_ptr.*),
   4628             0, // default alignment
   4629         );
   4630 
   4631         // Needed so that `Decl.clearValues` will additionally set the corresponding
   4632         // string literal table value back to `Decl.OptionalIndex.none`.
   4633         mod.declPtr(decl_index).owns_tv = true;
   4634 
   4635         gop.value_ptr.* = decl_index.toOptional();
   4636         break :di decl_index;
   4637     };
   4638     return sema.analyzeDeclRef(decl_index);
   4639 }
   4640 
   4641 fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   4642     _ = block;
   4643     const tracy = trace(@src());
   4644     defer tracy.end();
   4645 
   4646     const int = sema.code.instructions.items(.data)[inst].int;
   4647     return sema.addIntUnsigned(Type.initTag(.comptime_int), int);
   4648 }
   4649 
   4650 fn zirIntBig(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   4651     _ = block;
   4652     const tracy = trace(@src());
   4653     defer tracy.end();
   4654 
   4655     const arena = sema.arena;
   4656     const int = sema.code.instructions.items(.data)[inst].str;
   4657     const byte_count = int.len * @sizeOf(std.math.big.Limb);
   4658     const limb_bytes = sema.code.string_bytes[int.start..][0..byte_count];
   4659     const limbs = try arena.alloc(std.math.big.Limb, int.len);
   4660     mem.copy(u8, mem.sliceAsBytes(limbs), limb_bytes);
   4661 
   4662     return sema.addConstant(
   4663         Type.initTag(.comptime_int),
   4664         try Value.Tag.int_big_positive.create(arena, limbs),
   4665     );
   4666 }
   4667 
   4668 fn zirFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   4669     _ = block;
   4670     const arena = sema.arena;
   4671     const number = sema.code.instructions.items(.data)[inst].float;
   4672     return sema.addConstant(
   4673         Type.initTag(.comptime_float),
   4674         try Value.Tag.float_64.create(arena, number),
   4675     );
   4676 }
   4677 
   4678 fn zirFloat128(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   4679     _ = block;
   4680     const arena = sema.arena;
   4681     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   4682     const extra = sema.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data;
   4683     const number = extra.get();
   4684     return sema.addConstant(
   4685         Type.initTag(.comptime_float),
   4686         try Value.Tag.float_128.create(arena, number),
   4687     );
   4688 }
   4689 
   4690 fn zirCompileError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
   4691     const tracy = trace(@src());
   4692     defer tracy.end();
   4693 
   4694     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   4695     const src = inst_data.src();
   4696     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   4697     const msg = try sema.resolveConstString(block, operand_src, inst_data.operand, "compile error string must be comptime known");
   4698     return sema.fail(block, src, "{s}", .{msg});
   4699 }
   4700 
   4701 fn zirCompileLog(
   4702     sema: *Sema,
   4703     block: *Block,
   4704     extended: Zir.Inst.Extended.InstData,
   4705 ) CompileError!Air.Inst.Ref {
   4706     var managed = sema.mod.compile_log_text.toManaged(sema.gpa);
   4707     defer sema.mod.compile_log_text = managed.moveToUnmanaged();
   4708     const writer = managed.writer();
   4709 
   4710     const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand);
   4711     const src_node = extra.data.src_node;
   4712     const src = LazySrcLoc.nodeOffset(src_node);
   4713     const args = sema.code.refSlice(extra.end, extended.small);
   4714 
   4715     for (args) |arg_ref, i| {
   4716         if (i != 0) try writer.print(", ", .{});
   4717 
   4718         const arg = try sema.resolveInst(arg_ref);
   4719         const arg_ty = sema.typeOf(arg);
   4720         if (try sema.resolveMaybeUndefVal(block, src, arg)) |val| {
   4721             try sema.resolveLazyValue(block, src, val);
   4722             try writer.print("@as({}, {})", .{
   4723                 arg_ty.fmt(sema.mod), val.fmtValue(arg_ty, sema.mod),
   4724             });
   4725         } else {
   4726             try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(sema.mod)});
   4727         }
   4728     }
   4729     try writer.print("\n", .{});
   4730 
   4731     const decl_index = if (sema.func) |some| some.owner_decl else sema.owner_decl_index;
   4732     const gop = try sema.mod.compile_log_decls.getOrPut(sema.gpa, decl_index);
   4733     if (!gop.found_existing) {
   4734         gop.value_ptr.* = src_node;
   4735     }
   4736     return Air.Inst.Ref.void_value;
   4737 }
   4738 
   4739 fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index, force_comptime: bool) CompileError!Zir.Inst.Index {
   4740     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   4741     const src = inst_data.src();
   4742     const msg_inst = try sema.resolveInst(inst_data.operand);
   4743 
   4744     if (block.is_comptime or force_comptime) {
   4745         return sema.fail(block, src, "encountered @panic at comptime", .{});
   4746     }
   4747     try sema.requireFunctionBlock(block, src);
   4748     return sema.panicWithMsg(block, src, msg_inst);
   4749 }
   4750 
   4751 fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   4752     const tracy = trace(@src());
   4753     defer tracy.end();
   4754 
   4755     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   4756     const src = inst_data.src();
   4757     const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
   4758     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
   4759     const gpa = sema.gpa;
   4760 
   4761     // AIR expects a block outside the loop block too.
   4762     // Reserve space for a Loop instruction so that generated Break instructions can
   4763     // point to it, even if it doesn't end up getting used because the code ends up being
   4764     // comptime evaluated.
   4765     const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
   4766     const loop_inst = block_inst + 1;
   4767     try sema.air_instructions.ensureUnusedCapacity(gpa, 2);
   4768     sema.air_instructions.appendAssumeCapacity(.{
   4769         .tag = .block,
   4770         .data = undefined,
   4771     });
   4772     sema.air_instructions.appendAssumeCapacity(.{
   4773         .tag = .loop,
   4774         .data = .{ .ty_pl = .{
   4775             .ty = .noreturn_type,
   4776             .payload = undefined,
   4777         } },
   4778     });
   4779     var label: Block.Label = .{
   4780         .zir_block = inst,
   4781         .merges = .{
   4782             .results = .{},
   4783             .br_list = .{},
   4784             .block_inst = block_inst,
   4785         },
   4786     };
   4787     var child_block = parent_block.makeSubBlock();
   4788     child_block.label = &label;
   4789     child_block.runtime_cond = null;
   4790     child_block.runtime_loop = src;
   4791     child_block.runtime_index.increment();
   4792     const merges = &child_block.label.?.merges;
   4793 
   4794     defer child_block.instructions.deinit(gpa);
   4795     defer merges.results.deinit(gpa);
   4796     defer merges.br_list.deinit(gpa);
   4797 
   4798     var loop_block = child_block.makeSubBlock();
   4799     defer loop_block.instructions.deinit(gpa);
   4800 
   4801     try sema.analyzeBody(&loop_block, body);
   4802 
   4803     try child_block.instructions.append(gpa, loop_inst);
   4804 
   4805     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
   4806         loop_block.instructions.items.len);
   4807     sema.air_instructions.items(.data)[loop_inst].ty_pl.payload = sema.addExtraAssumeCapacity(
   4808         Air.Block{ .body_len = @intCast(u32, loop_block.instructions.items.len) },
   4809     );
   4810     sema.air_extra.appendSliceAssumeCapacity(loop_block.instructions.items);
   4811     return sema.analyzeBlockBody(parent_block, src, &child_block, merges);
   4812 }
   4813 
   4814 fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   4815     const tracy = trace(@src());
   4816     defer tracy.end();
   4817 
   4818     const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
   4819     const src = pl_node.src();
   4820     const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index);
   4821     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
   4822 
   4823     // we check this here to avoid undefined symbols
   4824     if (!@import("build_options").have_llvm)
   4825         return sema.fail(parent_block, src, "cannot do C import on Zig compiler not built with LLVM-extension", .{});
   4826 
   4827     var c_import_buf = std.ArrayList(u8).init(sema.gpa);
   4828     defer c_import_buf.deinit();
   4829 
   4830     var child_block: Block = .{
   4831         .parent = parent_block,
   4832         .sema = sema,
   4833         .src_decl = parent_block.src_decl,
   4834         .namespace = parent_block.namespace,
   4835         .wip_capture_scope = parent_block.wip_capture_scope,
   4836         .instructions = .{},
   4837         .inlining = parent_block.inlining,
   4838         .is_comptime = parent_block.is_comptime,
   4839         .c_import_buf = &c_import_buf,
   4840         .runtime_cond = parent_block.runtime_cond,
   4841         .runtime_loop = parent_block.runtime_loop,
   4842         .runtime_index = parent_block.runtime_index,
   4843     };
   4844     defer child_block.instructions.deinit(sema.gpa);
   4845 
   4846     // Ignore the result, all the relevant operations have written to c_import_buf already.
   4847     _ = try sema.analyzeBodyBreak(&child_block, body);
   4848 
   4849     const mod = sema.mod;
   4850     const c_import_res = mod.comp.cImport(c_import_buf.items) catch |err|
   4851         return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
   4852 
   4853     if (c_import_res.errors.len != 0) {
   4854         const msg = msg: {
   4855             const msg = try sema.errMsg(&child_block, src, "C import failed", .{});
   4856             errdefer msg.destroy(sema.gpa);
   4857 
   4858             if (!mod.comp.bin_file.options.link_libc)
   4859                 try sema.errNote(&child_block, src, msg, "libc headers not available; compilation does not link against libc", .{});
   4860 
   4861             for (c_import_res.errors) |_| {
   4862                 // TODO integrate with LazySrcLoc
   4863                 // try mod.errNoteNonLazy(.{}, msg, "{s}", .{clang_err.msg_ptr[0..clang_err.msg_len]});
   4864                 // if (clang_err.filename_ptr) |p| p[0..clang_err.filename_len] else "(no file)",
   4865                 // clang_err.line + 1,
   4866                 // clang_err.column + 1,
   4867             }
   4868             @import("clang.zig").Stage2ErrorMsg.delete(c_import_res.errors.ptr, c_import_res.errors.len);
   4869             break :msg msg;
   4870         };
   4871         return sema.failWithOwnedErrorMsg(msg);
   4872     }
   4873     const c_import_pkg = Package.create(
   4874         sema.gpa,
   4875         null,
   4876         c_import_res.out_zig_path,
   4877     ) catch |err| switch (err) {
   4878         error.OutOfMemory => return error.OutOfMemory,
   4879         else => unreachable, // we pass null for root_src_dir_path
   4880     };
   4881 
   4882     const result = mod.importPkg(c_import_pkg) catch |err|
   4883         return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
   4884 
   4885     mod.astGenFile(result.file) catch |err|
   4886         return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
   4887 
   4888     try mod.semaFile(result.file);
   4889     const file_root_decl_index = result.file.root_decl.unwrap().?;
   4890     const file_root_decl = mod.declPtr(file_root_decl_index);
   4891     try mod.declareDeclDependency(sema.owner_decl_index, file_root_decl_index);
   4892     return sema.addConstant(file_root_decl.ty, file_root_decl.val);
   4893 }
   4894 
   4895 fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   4896     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   4897     const src = inst_data.src();
   4898     return sema.failWithUseOfAsync(parent_block, src);
   4899 }
   4900 
   4901 fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   4902     const tracy = trace(@src());
   4903     defer tracy.end();
   4904 
   4905     const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
   4906     const src = pl_node.src();
   4907     const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index);
   4908     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
   4909     const gpa = sema.gpa;
   4910 
   4911     // Reserve space for a Block instruction so that generated Break instructions can
   4912     // point to it, even if it doesn't end up getting used because the code ends up being
   4913     // comptime evaluated.
   4914     const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
   4915     try sema.air_instructions.append(gpa, .{
   4916         .tag = .block,
   4917         .data = undefined,
   4918     });
   4919 
   4920     var label: Block.Label = .{
   4921         .zir_block = inst,
   4922         .merges = .{
   4923             .results = .{},
   4924             .br_list = .{},
   4925             .block_inst = block_inst,
   4926         },
   4927     };
   4928 
   4929     var child_block: Block = .{
   4930         .parent = parent_block,
   4931         .sema = sema,
   4932         .src_decl = parent_block.src_decl,
   4933         .namespace = parent_block.namespace,
   4934         .wip_capture_scope = parent_block.wip_capture_scope,
   4935         .instructions = .{},
   4936         .label = &label,
   4937         .inlining = parent_block.inlining,
   4938         .is_comptime = parent_block.is_comptime,
   4939         .want_safety = parent_block.want_safety,
   4940         .float_mode = parent_block.float_mode,
   4941         .runtime_cond = parent_block.runtime_cond,
   4942         .runtime_loop = parent_block.runtime_loop,
   4943         .runtime_index = parent_block.runtime_index,
   4944     };
   4945 
   4946     defer child_block.instructions.deinit(gpa);
   4947     defer label.merges.results.deinit(gpa);
   4948     defer label.merges.br_list.deinit(gpa);
   4949 
   4950     return sema.resolveBlockBody(parent_block, src, &child_block, body, inst, &label.merges);
   4951 }
   4952 
   4953 fn resolveBlockBody(
   4954     sema: *Sema,
   4955     parent_block: *Block,
   4956     src: LazySrcLoc,
   4957     child_block: *Block,
   4958     body: []const Zir.Inst.Index,
   4959     /// This is the instruction that a break instruction within `body` can
   4960     /// use to return from the body.
   4961     body_inst: Zir.Inst.Index,
   4962     merges: *Block.Merges,
   4963 ) CompileError!Air.Inst.Ref {
   4964     if (child_block.is_comptime) {
   4965         return sema.resolveBody(child_block, body, body_inst);
   4966     } else {
   4967         if (sema.analyzeBodyInner(child_block, body)) |_| {
   4968             return sema.analyzeBlockBody(parent_block, src, child_block, merges);
   4969         } else |err| switch (err) {
   4970             error.ComptimeBreak => {
   4971                 // Comptime control flow is happening, however child_block may still contain
   4972                 // runtime instructions which need to be copied to the parent block.
   4973                 try parent_block.instructions.appendSlice(sema.gpa, child_block.instructions.items);
   4974 
   4975                 const break_inst = sema.comptime_break_inst;
   4976                 const break_data = sema.code.instructions.items(.data)[break_inst].@"break";
   4977                 if (break_data.block_inst == body_inst) {
   4978                     return try sema.resolveInst(break_data.operand);
   4979                 } else {
   4980                     return error.ComptimeBreak;
   4981                 }
   4982             },
   4983             else => |e| return e,
   4984         }
   4985     }
   4986 }
   4987 
   4988 fn analyzeBlockBody(
   4989     sema: *Sema,
   4990     parent_block: *Block,
   4991     src: LazySrcLoc,
   4992     child_block: *Block,
   4993     merges: *Block.Merges,
   4994 ) CompileError!Air.Inst.Ref {
   4995     const tracy = trace(@src());
   4996     defer tracy.end();
   4997 
   4998     const gpa = sema.gpa;
   4999     const mod = sema.mod;
   5000 
   5001     // Blocks must terminate with noreturn instruction.
   5002     assert(child_block.instructions.items.len != 0);
   5003     assert(sema.typeOf(Air.indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1])).isNoReturn());
   5004 
   5005     if (merges.results.items.len == 0) {
   5006         // No need for a block instruction. We can put the new instructions
   5007         // directly into the parent block.
   5008         try parent_block.instructions.appendSlice(gpa, child_block.instructions.items);
   5009         return Air.indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1]);
   5010     }
   5011     if (merges.results.items.len == 1) {
   5012         const last_inst_index = child_block.instructions.items.len - 1;
   5013         const last_inst = child_block.instructions.items[last_inst_index];
   5014         if (sema.getBreakBlock(last_inst)) |br_block| {
   5015             if (br_block == merges.block_inst) {
   5016                 // No need for a block instruction. We can put the new instructions directly
   5017                 // into the parent block. Here we omit the break instruction.
   5018                 const without_break = child_block.instructions.items[0..last_inst_index];
   5019                 try parent_block.instructions.appendSlice(gpa, without_break);
   5020                 return merges.results.items[0];
   5021             }
   5022         }
   5023     }
   5024     // It is impossible to have the number of results be > 1 in a comptime scope.
   5025     assert(!child_block.is_comptime); // Should already got a compile error in the condbr condition.
   5026 
   5027     // Need to set the type and emit the Block instruction. This allows machine code generation
   5028     // to emit a jump instruction to after the block when it encounters the break.
   5029     try parent_block.instructions.append(gpa, merges.block_inst);
   5030     const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .none);
   5031     // TODO add note "missing else causes void value"
   5032 
   5033     const type_src = src; // TODO: better source location
   5034     const valid_rt = try sema.validateRunTimeType(child_block, type_src, resolved_ty, false);
   5035     if (!valid_rt) {
   5036         const msg = msg: {
   5037             const msg = try sema.errMsg(child_block, type_src, "value with comptime only type '{}' depends on runtime control flow", .{resolved_ty.fmt(mod)});
   5038             errdefer msg.destroy(sema.gpa);
   5039 
   5040             const runtime_src = child_block.runtime_cond orelse child_block.runtime_loop.?;
   5041             try sema.errNote(child_block, runtime_src, msg, "runtime control flow here", .{});
   5042 
   5043             const child_src_decl = mod.declPtr(child_block.src_decl);
   5044             try sema.explainWhyTypeIsComptime(child_block, type_src, msg, type_src.toSrcLoc(child_src_decl), resolved_ty);
   5045 
   5046             break :msg msg;
   5047         };
   5048         return sema.failWithOwnedErrorMsg(msg);
   5049     }
   5050     const ty_inst = try sema.addType(resolved_ty);
   5051     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
   5052         child_block.instructions.items.len);
   5053     sema.air_instructions.items(.data)[merges.block_inst] = .{ .ty_pl = .{
   5054         .ty = ty_inst,
   5055         .payload = sema.addExtraAssumeCapacity(Air.Block{
   5056             .body_len = @intCast(u32, child_block.instructions.items.len),
   5057         }),
   5058     } };
   5059     sema.air_extra.appendSliceAssumeCapacity(child_block.instructions.items);
   5060     // Now that the block has its type resolved, we need to go back into all the break
   5061     // instructions, and insert type coercion on the operands.
   5062     for (merges.br_list.items) |br| {
   5063         const br_operand = sema.air_instructions.items(.data)[br].br.operand;
   5064         const br_operand_src = src;
   5065         const br_operand_ty = sema.typeOf(br_operand);
   5066         if (br_operand_ty.eql(resolved_ty, mod)) {
   5067             // No type coercion needed.
   5068             continue;
   5069         }
   5070         var coerce_block = parent_block.makeSubBlock();
   5071         defer coerce_block.instructions.deinit(gpa);
   5072         const coerced_operand = try sema.coerce(&coerce_block, resolved_ty, br_operand, br_operand_src);
   5073         // If no instructions were produced, such as in the case of a coercion of a
   5074         // constant value to a new type, we can simply point the br operand to it.
   5075         if (coerce_block.instructions.items.len == 0) {
   5076             sema.air_instructions.items(.data)[br].br.operand = coerced_operand;
   5077             continue;
   5078         }
   5079         assert(coerce_block.instructions.items[coerce_block.instructions.items.len - 1] ==
   5080             Air.refToIndex(coerced_operand).?);
   5081 
   5082         // Convert the br instruction to a block instruction that has the coercion
   5083         // and then a new br inside that returns the coerced instruction.
   5084         const sub_block_len = @intCast(u32, coerce_block.instructions.items.len + 1);
   5085         try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
   5086             sub_block_len);
   5087         try sema.air_instructions.ensureUnusedCapacity(gpa, 1);
   5088         const sub_br_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
   5089 
   5090         sema.air_instructions.items(.tag)[br] = .block;
   5091         sema.air_instructions.items(.data)[br] = .{ .ty_pl = .{
   5092             .ty = Air.Inst.Ref.noreturn_type,
   5093             .payload = sema.addExtraAssumeCapacity(Air.Block{
   5094                 .body_len = sub_block_len,
   5095             }),
   5096         } };
   5097         sema.air_extra.appendSliceAssumeCapacity(coerce_block.instructions.items);
   5098         sema.air_extra.appendAssumeCapacity(sub_br_inst);
   5099 
   5100         sema.air_instructions.appendAssumeCapacity(.{
   5101             .tag = .br,
   5102             .data = .{ .br = .{
   5103                 .block_inst = merges.block_inst,
   5104                 .operand = coerced_operand,
   5105             } },
   5106         });
   5107     }
   5108     return Air.indexToRef(merges.block_inst);
   5109 }
   5110 
   5111 fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   5112     const tracy = trace(@src());
   5113     defer tracy.end();
   5114 
   5115     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   5116     const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data;
   5117     const src = inst_data.src();
   5118     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   5119     const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   5120     const decl_name = sema.code.nullTerminatedString(extra.decl_name);
   5121     if (extra.namespace != .none) {
   5122         return sema.fail(block, src, "TODO: implement exporting with field access", .{});
   5123     }
   5124     const decl_index = try sema.lookupIdentifier(block, operand_src, decl_name);
   5125     const options = sema.resolveExportOptions(block, .unneeded, extra.options) catch |err| switch (err) {
   5126         error.NeededSourceLocation => {
   5127             _ = try sema.resolveExportOptions(block, options_src, extra.options);
   5128             return error.AnalysisFail;
   5129         },
   5130         else => |e| return e,
   5131     };
   5132     try sema.analyzeExport(block, src, options, decl_index);
   5133 }
   5134 
   5135 fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   5136     const tracy = trace(@src());
   5137     defer tracy.end();
   5138 
   5139     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   5140     const extra = sema.code.extraData(Zir.Inst.ExportValue, inst_data.payload_index).data;
   5141     const src = inst_data.src();
   5142     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   5143     const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   5144     const operand = try sema.resolveInstConst(block, operand_src, extra.operand, "export target must be comptime known");
   5145     const options = sema.resolveExportOptions(block, .unneeded, extra.options) catch |err| switch (err) {
   5146         error.NeededSourceLocation => {
   5147             _ = try sema.resolveExportOptions(block, options_src, extra.options);
   5148             return error.AnalysisFail;
   5149         },
   5150         else => |e| return e,
   5151     };
   5152     const decl_index = switch (operand.val.tag()) {
   5153         .function => operand.val.castTag(.function).?.data.owner_decl,
   5154         else => return sema.fail(block, operand_src, "TODO implement exporting arbitrary Value objects", .{}), // TODO put this Value into an anonymous Decl and then export it.
   5155     };
   5156     try sema.analyzeExport(block, src, options, decl_index);
   5157 }
   5158 
   5159 pub fn analyzeExport(
   5160     sema: *Sema,
   5161     block: *Block,
   5162     src: LazySrcLoc,
   5163     borrowed_options: std.builtin.ExportOptions,
   5164     exported_decl_index: Decl.Index,
   5165 ) !void {
   5166     const Export = Module.Export;
   5167     const mod = sema.mod;
   5168 
   5169     if (borrowed_options.linkage == .Internal) {
   5170         return;
   5171     }
   5172 
   5173     try mod.ensureDeclAnalyzed(exported_decl_index);
   5174     const exported_decl = mod.declPtr(exported_decl_index);
   5175 
   5176     if (!try sema.validateExternType(block, src, exported_decl.ty, .other)) {
   5177         const msg = msg: {
   5178             const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(sema.mod)});
   5179             errdefer msg.destroy(sema.gpa);
   5180 
   5181             const src_decl = sema.mod.declPtr(block.src_decl);
   5182             try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), exported_decl.ty, .other);
   5183 
   5184             try sema.addDeclaredHereNote(msg, exported_decl.ty);
   5185             break :msg msg;
   5186         };
   5187         return sema.failWithOwnedErrorMsg(msg);
   5188     }
   5189 
   5190     const gpa = mod.gpa;
   5191 
   5192     try mod.decl_exports.ensureUnusedCapacity(gpa, 1);
   5193     try mod.export_owners.ensureUnusedCapacity(gpa, 1);
   5194 
   5195     const new_export = try gpa.create(Export);
   5196     errdefer gpa.destroy(new_export);
   5197 
   5198     const symbol_name = try gpa.dupe(u8, borrowed_options.name);
   5199     errdefer gpa.free(symbol_name);
   5200 
   5201     const section: ?[]const u8 = if (borrowed_options.section) |s| try gpa.dupe(u8, s) else null;
   5202     errdefer if (section) |s| gpa.free(s);
   5203 
   5204     new_export.* = .{
   5205         .options = .{
   5206             .name = symbol_name,
   5207             .linkage = borrowed_options.linkage,
   5208             .section = section,
   5209             .visibility = borrowed_options.visibility,
   5210         },
   5211         .src = src,
   5212         .link = switch (mod.comp.bin_file.tag) {
   5213             .coff => .{ .coff = .{} },
   5214             .elf => .{ .elf = .{} },
   5215             .macho => .{ .macho = .{} },
   5216             .plan9 => .{ .plan9 = null },
   5217             .c => .{ .c = {} },
   5218             .wasm => .{ .wasm = .{} },
   5219             .spirv => .{ .spirv = {} },
   5220             .nvptx => .{ .nvptx = {} },
   5221         },
   5222         .owner_decl = sema.owner_decl_index,
   5223         .src_decl = block.src_decl,
   5224         .exported_decl = exported_decl_index,
   5225         .status = .in_progress,
   5226     };
   5227 
   5228     // Add to export_owners table.
   5229     const eo_gop = mod.export_owners.getOrPutAssumeCapacity(sema.owner_decl_index);
   5230     if (!eo_gop.found_existing) {
   5231         eo_gop.value_ptr.* = &[0]*Export{};
   5232     }
   5233     eo_gop.value_ptr.* = try gpa.realloc(eo_gop.value_ptr.*, eo_gop.value_ptr.len + 1);
   5234     eo_gop.value_ptr.*[eo_gop.value_ptr.len - 1] = new_export;
   5235     errdefer eo_gop.value_ptr.* = gpa.shrink(eo_gop.value_ptr.*, eo_gop.value_ptr.len - 1);
   5236 
   5237     // Add to exported_decl table.
   5238     const de_gop = mod.decl_exports.getOrPutAssumeCapacity(exported_decl_index);
   5239     if (!de_gop.found_existing) {
   5240         de_gop.value_ptr.* = &[0]*Export{};
   5241     }
   5242     de_gop.value_ptr.* = try gpa.realloc(de_gop.value_ptr.*, de_gop.value_ptr.len + 1);
   5243     de_gop.value_ptr.*[de_gop.value_ptr.len - 1] = new_export;
   5244     errdefer de_gop.value_ptr.* = gpa.shrink(de_gop.value_ptr.*, de_gop.value_ptr.len - 1);
   5245 }
   5246 
   5247 fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
   5248     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
   5249     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
   5250     const src = LazySrcLoc.nodeOffset(extra.node);
   5251     const alignment = try sema.resolveAlign(block, operand_src, extra.operand);
   5252     if (alignment > 256) {
   5253         return sema.fail(block, src, "attempt to @setAlignStack({d}); maximum is 256", .{
   5254             alignment,
   5255         });
   5256     }
   5257     const func = sema.func orelse
   5258         return sema.fail(block, src, "@setAlignStack outside function body", .{});
   5259 
   5260     const fn_owner_decl = sema.mod.declPtr(func.owner_decl);
   5261     switch (fn_owner_decl.ty.fnCallingConvention()) {
   5262         .Naked => return sema.fail(block, src, "@setAlignStack in naked function", .{}),
   5263         .Inline => return sema.fail(block, src, "@setAlignStack in inline function", .{}),
   5264         else => if (block.inlining != null) {
   5265             return sema.fail(block, src, "@setAlignStack in inline call", .{});
   5266         },
   5267     }
   5268 
   5269     const gop = try sema.mod.align_stack_fns.getOrPut(sema.mod.gpa, func);
   5270     if (gop.found_existing) {
   5271         const msg = msg: {
   5272             const msg = try sema.errMsg(block, src, "multiple @setAlignStack in the same function body", .{});
   5273             errdefer msg.destroy(sema.gpa);
   5274             try sema.errNote(block, gop.value_ptr.src, msg, "other instance here", .{});
   5275             break :msg msg;
   5276         };
   5277         return sema.failWithOwnedErrorMsg(msg);
   5278     }
   5279     gop.value_ptr.* = .{ .alignment = alignment, .src = src };
   5280 }
   5281 
   5282 fn zirSetCold(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   5283     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   5284     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   5285     const is_cold = try sema.resolveConstBool(block, operand_src, inst_data.operand, "operand to @setCold must be comptime known");
   5286     const func = sema.func orelse return; // does nothing outside a function
   5287     func.is_cold = is_cold;
   5288 }
   5289 
   5290 fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
   5291     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
   5292     const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
   5293     block.float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, "FloatMode", "operand to @setFloatMode must be comptime known");
   5294 }
   5295 
   5296 fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   5297     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   5298     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   5299     block.want_safety = try sema.resolveConstBool(block, operand_src, inst_data.operand, "operand to @setRuntimeSafety must be comptime known");
   5300 }
   5301 
   5302 fn zirFence(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
   5303     if (block.is_comptime) return;
   5304 
   5305     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
   5306     const order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
   5307     const order = try sema.resolveAtomicOrder(block, order_src, extra.operand, "atomic order of @fence must be comptime known");
   5308 
   5309     if (@enumToInt(order) < @enumToInt(std.builtin.AtomicOrder.Acquire)) {
   5310         return sema.fail(block, order_src, "atomic ordering must be Acquire or stricter", .{});
   5311     }
   5312 
   5313     _ = try block.addInst(.{
   5314         .tag = .fence,
   5315         .data = .{ .fence = order },
   5316     });
   5317 }
   5318 
   5319 fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
   5320     const tracy = trace(@src());
   5321     defer tracy.end();
   5322 
   5323     const inst_data = sema.code.instructions.items(.data)[inst].@"break";
   5324     const operand = try sema.resolveInst(inst_data.operand);
   5325     const zir_block = inst_data.block_inst;
   5326 
   5327     var block = start_block;
   5328     while (true) {
   5329         if (block.label) |label| {
   5330             if (label.zir_block == zir_block) {
   5331                 const br_ref = try start_block.addBr(label.merges.block_inst, operand);
   5332                 try label.merges.results.append(sema.gpa, operand);
   5333                 try label.merges.br_list.append(sema.gpa, Air.refToIndex(br_ref).?);
   5334                 block.runtime_index.increment();
   5335                 if (block.runtime_cond == null and block.runtime_loop == null) {
   5336                     block.runtime_cond = start_block.runtime_cond orelse start_block.runtime_loop;
   5337                     block.runtime_loop = start_block.runtime_loop;
   5338                 }
   5339                 return inst;
   5340             }
   5341         }
   5342         block = block.parent.?;
   5343     }
   5344 }
   5345 
   5346 fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   5347     // We do not set sema.src here because dbg_stmt instructions are only emitted for
   5348     // ZIR code that possibly will need to generate runtime code. So error messages
   5349     // and other source locations must not rely on sema.src being set from dbg_stmt
   5350     // instructions.
   5351     if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return;
   5352 
   5353     const inst_data = sema.code.instructions.items(.data)[inst].dbg_stmt;
   5354     _ = try block.addInst(.{
   5355         .tag = .dbg_stmt,
   5356         .data = .{ .dbg_stmt = .{
   5357             .line = inst_data.line,
   5358             .column = inst_data.column,
   5359         } },
   5360     });
   5361 }
   5362 
   5363 fn zirDbgBlockBegin(sema: *Sema, block: *Block) CompileError!void {
   5364     if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return;
   5365 
   5366     _ = try block.addInst(.{
   5367         .tag = .dbg_block_begin,
   5368         .data = undefined,
   5369     });
   5370 }
   5371 
   5372 fn zirDbgBlockEnd(sema: *Sema, block: *Block) CompileError!void {
   5373     if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return;
   5374 
   5375     _ = try block.addInst(.{
   5376         .tag = .dbg_block_end,
   5377         .data = undefined,
   5378     });
   5379 }
   5380 
   5381 fn zirDbgVar(
   5382     sema: *Sema,
   5383     block: *Block,
   5384     inst: Zir.Inst.Index,
   5385     air_tag: Air.Inst.Tag,
   5386 ) CompileError!void {
   5387     if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return;
   5388 
   5389     const str_op = sema.code.instructions.items(.data)[inst].str_op;
   5390     const operand = try sema.resolveInst(str_op.operand);
   5391     const name = str_op.getStr(sema.code);
   5392     try sema.addDbgVar(block, operand, air_tag, name);
   5393 }
   5394 
   5395 fn addDbgVar(
   5396     sema: *Sema,
   5397     block: *Block,
   5398     operand: Air.Inst.Ref,
   5399     air_tag: Air.Inst.Tag,
   5400     name: []const u8,
   5401 ) CompileError!void {
   5402     const operand_ty = sema.typeOf(operand);
   5403     switch (air_tag) {
   5404         .dbg_var_ptr => {
   5405             if (!(try sema.typeHasRuntimeBits(block, sema.src, operand_ty.childType()))) return;
   5406         },
   5407         .dbg_var_val => {
   5408             if (!(try sema.typeHasRuntimeBits(block, sema.src, operand_ty))) return;
   5409         },
   5410         else => unreachable,
   5411     }
   5412 
   5413     try sema.queueFullTypeResolution(operand_ty);
   5414 
   5415     // Add the name to the AIR.
   5416     const name_extra_index = @intCast(u32, sema.air_extra.items.len);
   5417     const elements_used = name.len / 4 + 1;
   5418     try sema.air_extra.ensureUnusedCapacity(sema.gpa, elements_used);
   5419     const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
   5420     mem.copy(u8, buffer, name);
   5421     buffer[name.len] = 0;
   5422     sema.air_extra.items.len += elements_used;
   5423 
   5424     _ = try block.addInst(.{
   5425         .tag = air_tag,
   5426         .data = .{ .pl_op = .{
   5427             .payload = name_extra_index,
   5428             .operand = operand,
   5429         } },
   5430     });
   5431 }
   5432 
   5433 fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   5434     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
   5435     const src = inst_data.src();
   5436     const decl_name = inst_data.get(sema.code);
   5437     const decl_index = try sema.lookupIdentifier(block, src, decl_name);
   5438     try sema.addReferencedBy(block, src, decl_index);
   5439     return sema.analyzeDeclRef(decl_index);
   5440 }
   5441 
   5442 fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   5443     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
   5444     const src = inst_data.src();
   5445     const decl_name = inst_data.get(sema.code);
   5446     const decl = try sema.lookupIdentifier(block, src, decl_name);
   5447     return sema.analyzeDeclVal(block, src, decl);
   5448 }
   5449 
   5450 fn lookupIdentifier(sema: *Sema, block: *Block, src: LazySrcLoc, name: []const u8) !Decl.Index {
   5451     var namespace = block.namespace;
   5452     while (true) {
   5453         if (try sema.lookupInNamespace(block, src, namespace, name, false)) |decl_index| {
   5454             return decl_index;
   5455         }
   5456         namespace = namespace.parent orelse break;
   5457     }
   5458     unreachable; // AstGen detects use of undeclared identifier errors.
   5459 }
   5460 
   5461 /// This looks up a member of a specific namespace. It is affected by `usingnamespace` but
   5462 /// only for ones in the specified namespace.
   5463 fn lookupInNamespace(
   5464     sema: *Sema,
   5465     block: *Block,
   5466     src: LazySrcLoc,
   5467     namespace: *Namespace,
   5468     ident_name: []const u8,
   5469     observe_usingnamespace: bool,
   5470 ) CompileError!?Decl.Index {
   5471     const mod = sema.mod;
   5472 
   5473     const namespace_decl_index = namespace.getDeclIndex();
   5474     const namespace_decl = sema.mod.declPtr(namespace_decl_index);
   5475     if (namespace_decl.analysis == .file_failure) {
   5476         try mod.declareDeclDependency(sema.owner_decl_index, namespace_decl_index);
   5477         return error.AnalysisFail;
   5478     }
   5479 
   5480     if (observe_usingnamespace and namespace.usingnamespace_set.count() != 0) {
   5481         const src_file = block.namespace.file_scope;
   5482 
   5483         const gpa = sema.gpa;
   5484         var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Namespace, void) = .{};
   5485         defer checked_namespaces.deinit(gpa);
   5486 
   5487         // Keep track of name conflicts for error notes.
   5488         var candidates: std.ArrayListUnmanaged(Decl.Index) = .{};
   5489         defer candidates.deinit(gpa);
   5490 
   5491         try checked_namespaces.put(gpa, namespace, {});
   5492         var check_i: usize = 0;
   5493 
   5494         while (check_i < checked_namespaces.count()) : (check_i += 1) {
   5495             const check_ns = checked_namespaces.keys()[check_i];
   5496             if (check_ns.decls.getKeyAdapted(ident_name, Module.DeclAdapter{ .mod = mod })) |decl_index| {
   5497                 // Skip decls which are not marked pub, which are in a different
   5498                 // file than the `a.b`/`@hasDecl` syntax.
   5499                 const decl = mod.declPtr(decl_index);
   5500                 if (decl.is_pub or src_file == decl.getFileScope()) {
   5501                     try candidates.append(gpa, decl_index);
   5502                 }
   5503             }
   5504             var it = check_ns.usingnamespace_set.iterator();
   5505             while (it.next()) |entry| {
   5506                 const sub_usingnamespace_decl_index = entry.key_ptr.*;
   5507                 // Skip the decl we're currently analysing.
   5508                 if (sub_usingnamespace_decl_index == sema.owner_decl_index) continue;
   5509                 const sub_usingnamespace_decl = mod.declPtr(sub_usingnamespace_decl_index);
   5510                 const sub_is_pub = entry.value_ptr.*;
   5511                 if (!sub_is_pub and src_file != sub_usingnamespace_decl.getFileScope()) {
   5512                     // Skip usingnamespace decls which are not marked pub, which are in
   5513                     // a different file than the `a.b`/`@hasDecl` syntax.
   5514                     continue;
   5515                 }
   5516                 try sema.ensureDeclAnalyzed(sub_usingnamespace_decl_index);
   5517                 const ns_ty = sub_usingnamespace_decl.val.castTag(.ty).?.data;
   5518                 const sub_ns = ns_ty.getNamespace().?;
   5519                 try checked_namespaces.put(gpa, sub_ns, {});
   5520             }
   5521         }
   5522 
   5523         {
   5524             var i: usize = 0;
   5525             while (i < candidates.items.len) {
   5526                 if (candidates.items[i] == sema.owner_decl_index) {
   5527                     _ = candidates.orderedRemove(i);
   5528                 } else {
   5529                     i += 1;
   5530                 }
   5531             }
   5532         }
   5533 
   5534         switch (candidates.items.len) {
   5535             0 => {},
   5536             1 => {
   5537                 const decl_index = candidates.items[0];
   5538                 try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
   5539                 return decl_index;
   5540             },
   5541             else => {
   5542                 const msg = msg: {
   5543                     const msg = try sema.errMsg(block, src, "ambiguous reference", .{});
   5544                     errdefer msg.destroy(gpa);
   5545                     for (candidates.items) |candidate_index| {
   5546                         const candidate = mod.declPtr(candidate_index);
   5547                         const src_loc = candidate.srcLoc();
   5548                         try mod.errNoteNonLazy(src_loc, msg, "declared here", .{});
   5549                     }
   5550                     break :msg msg;
   5551                 };
   5552                 return sema.failWithOwnedErrorMsg(msg);
   5553             },
   5554         }
   5555     } else if (namespace.decls.getKeyAdapted(ident_name, Module.DeclAdapter{ .mod = mod })) |decl_index| {
   5556         try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
   5557         return decl_index;
   5558     }
   5559 
   5560     log.debug("{*} ({s}) depends on non-existence of '{s}' in {*} ({s})", .{
   5561         sema.owner_decl, sema.owner_decl.name, ident_name, namespace_decl, namespace_decl.name,
   5562     });
   5563     // TODO This dependency is too strong. Really, it should only be a dependency
   5564     // on the non-existence of `ident_name` in the namespace. We can lessen the number of
   5565     // outdated declarations by making this dependency more sophisticated.
   5566     try mod.declareDeclDependency(sema.owner_decl_index, namespace_decl_index);
   5567     return null;
   5568 }
   5569 
   5570 fn funcDeclSrc(sema: *Sema, block: *Block, src: LazySrcLoc, func_inst: Air.Inst.Ref) !?Module.SrcLoc {
   5571     const func_val = (try sema.resolveMaybeUndefVal(block, src, func_inst)) orelse return null;
   5572     if (func_val.isUndef()) return null;
   5573     const owner_decl_index = switch (func_val.tag()) {
   5574         .extern_fn => func_val.castTag(.extern_fn).?.data.owner_decl,
   5575         .function => func_val.castTag(.function).?.data.owner_decl,
   5576         .decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl,
   5577         else => return null,
   5578     };
   5579     const owner_decl = sema.mod.declPtr(owner_decl_index);
   5580     return owner_decl.srcLoc();
   5581 }
   5582 
   5583 fn zirCall(
   5584     sema: *Sema,
   5585     block: *Block,
   5586     inst: Zir.Inst.Index,
   5587 ) CompileError!Air.Inst.Ref {
   5588     const tracy = trace(@src());
   5589     defer tracy.end();
   5590 
   5591     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   5592     const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
   5593     const call_src = inst_data.src();
   5594     const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index);
   5595     const args_len = extra.data.flags.args_len;
   5596 
   5597     const modifier = @intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier);
   5598     const ensure_result_used = extra.data.flags.ensure_result_used;
   5599 
   5600     var func = try sema.resolveInst(extra.data.callee);
   5601     var resolved_args: []Air.Inst.Ref = undefined;
   5602     var arg_index: u32 = 0;
   5603 
   5604     const func_type = sema.typeOf(func);
   5605 
   5606     // Desugar bound functions here
   5607     var bound_arg_src: ?LazySrcLoc = null;
   5608     if (func_type.tag() == .bound_fn) {
   5609         bound_arg_src = func_src;
   5610         const bound_func = try sema.resolveValue(block, .unneeded, func, undefined);
   5611         const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
   5612         func = bound_data.func_inst;
   5613         resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
   5614         resolved_args[arg_index] = bound_data.arg0_inst;
   5615         arg_index += 1;
   5616     } else {
   5617         resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
   5618     }
   5619     const total_args = args_len + @boolToInt(bound_arg_src != null);
   5620 
   5621     const callee_ty = sema.typeOf(func);
   5622     const func_ty = func_ty: {
   5623         switch (callee_ty.zigTypeTag()) {
   5624             .Fn => break :func_ty callee_ty,
   5625             .Pointer => {
   5626                 const ptr_info = callee_ty.ptrInfo().data;
   5627                 if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) {
   5628                     break :func_ty ptr_info.pointee_type;
   5629                 }
   5630             },
   5631             else => {},
   5632         }
   5633         return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
   5634     };
   5635     const func_ty_info = func_ty.fnInfo();
   5636 
   5637     const fn_params_len = func_ty_info.param_types.len;
   5638     check_args: {
   5639         if (func_ty_info.is_var_args) {
   5640             assert(func_ty_info.cc == .C);
   5641             if (total_args >= fn_params_len) break :check_args;
   5642         } else if (fn_params_len == total_args) {
   5643             break :check_args;
   5644         }
   5645 
   5646         const decl_src = try sema.funcDeclSrc(block, func_src, func);
   5647         const member_str = if (bound_arg_src != null) "member function " else "";
   5648         const variadic_str = if (func_ty_info.is_var_args) "at least " else "";
   5649         const msg = msg: {
   5650             const msg = try sema.errMsg(
   5651                 block,
   5652                 func_src,
   5653                 "{s}expected {s}{d} argument(s), found {d}",
   5654                 .{
   5655                     member_str,
   5656                     variadic_str,
   5657                     fn_params_len - @boolToInt(bound_arg_src != null),
   5658                     args_len,
   5659                 },
   5660             );
   5661             errdefer msg.destroy(sema.gpa);
   5662 
   5663             if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{});
   5664             break :msg msg;
   5665         };
   5666         return sema.failWithOwnedErrorMsg(msg);
   5667     }
   5668 
   5669     const args_body = sema.code.extra[extra.end..];
   5670 
   5671     const parent_comptime = block.is_comptime;
   5672     // `extra_index` and `arg_index` are separate since the bound function is passed as the first argument.
   5673     var extra_index: usize = 0;
   5674     var arg_start: u32 = args_len;
   5675     while (extra_index < args_len) : ({
   5676         extra_index += 1;
   5677         arg_index += 1;
   5678     }) {
   5679         const arg_end = sema.code.extra[extra.end + extra_index];
   5680         defer arg_start = arg_end;
   5681 
   5682         const param_ty = if (arg_index >= fn_params_len or
   5683             func_ty_info.param_types[arg_index].tag() == .generic_poison)
   5684             Type.initTag(.var_args_param)
   5685         else
   5686             func_ty_info.param_types[arg_index];
   5687 
   5688         const old_comptime = block.is_comptime;
   5689         defer block.is_comptime = old_comptime;
   5690         // Generate args to comptime params in comptime block.
   5691         block.is_comptime = parent_comptime;
   5692         if (arg_index < fn_params_len and func_ty_info.comptime_params[arg_index]) {
   5693             block.is_comptime = true;
   5694         }
   5695 
   5696         const param_ty_inst = try sema.addType(param_ty);
   5697         try sema.inst_map.put(sema.gpa, inst, param_ty_inst);
   5698 
   5699         const resolved = try sema.resolveBody(block, args_body[arg_start..arg_end], inst);
   5700         if (sema.typeOf(resolved).zigTypeTag() == .NoReturn) {
   5701             return resolved;
   5702         }
   5703         resolved_args[arg_index] = resolved;
   5704     }
   5705 
   5706     return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src);
   5707 }
   5708 
   5709 const GenericCallAdapter = struct {
   5710     generic_fn: *Module.Fn,
   5711     precomputed_hash: u64,
   5712     func_ty_info: Type.Payload.Function.Data,
   5713     args: []const Arg,
   5714     module: *Module,
   5715 
   5716     const Arg = struct {
   5717         ty: Type,
   5718         val: Value,
   5719         is_anytype: bool,
   5720     };
   5721 
   5722     pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool {
   5723         _ = adapted_key;
   5724         // Checking for equality may happen on an item that has been inserted
   5725         // into the map but is not yet fully initialized. In such case, the
   5726         // two initialized fields are `hash` and `generic_owner_decl`.
   5727         if (ctx.generic_fn.owner_decl != other_key.generic_owner_decl.unwrap().?) return false;
   5728 
   5729         const other_comptime_args = other_key.comptime_args.?;
   5730         for (other_comptime_args[0..ctx.func_ty_info.param_types.len]) |other_arg, i| {
   5731             const this_arg = ctx.args[i];
   5732             const this_is_comptime = this_arg.val.tag() != .generic_poison;
   5733             const other_is_comptime = other_arg.val.tag() != .generic_poison;
   5734             const this_is_anytype = this_arg.is_anytype;
   5735             const other_is_anytype = other_key.isAnytypeParam(ctx.module, @intCast(u32, i));
   5736 
   5737             if (other_is_anytype != this_is_anytype) return false;
   5738             if (other_is_comptime != this_is_comptime) return false;
   5739 
   5740             if (this_is_anytype) {
   5741                 // Both are anytype parameters.
   5742                 if (!this_arg.ty.eql(other_arg.ty, ctx.module)) {
   5743                     return false;
   5744                 }
   5745                 if (this_is_comptime) {
   5746                     // Both are comptime and anytype parameters with matching types.
   5747                     if (!this_arg.val.eql(other_arg.val, other_arg.ty, ctx.module)) {
   5748                         return false;
   5749                     }
   5750                 }
   5751             } else if (this_is_comptime) {
   5752                 // Both are comptime parameters but not anytype parameters.
   5753                 // We assert no error is possible here because any lazy values must be resolved
   5754                 // before inserting into the generic function hash map.
   5755                 const is_eql = Value.eqlAdvanced(
   5756                     this_arg.val,
   5757                     this_arg.ty,
   5758                     other_arg.val,
   5759                     other_arg.ty,
   5760                     ctx.module,
   5761                     null,
   5762                 ) catch unreachable;
   5763                 if (!is_eql) {
   5764                     return false;
   5765                 }
   5766             }
   5767         }
   5768         return true;
   5769     }
   5770 
   5771     /// The implementation of the hash is in semantic analysis of function calls, so
   5772     /// that any errors when computing the hash can be properly reported.
   5773     pub fn hash(ctx: @This(), adapted_key: void) u64 {
   5774         _ = adapted_key;
   5775         return ctx.precomputed_hash;
   5776     }
   5777 };
   5778 
   5779 fn addComptimeReturnTypeNote(
   5780     sema: *Sema,
   5781     block: *Block,
   5782     func: Air.Inst.Ref,
   5783     func_src: LazySrcLoc,
   5784     return_ty: Type,
   5785     parent: *Module.ErrorMsg,
   5786     requires_comptime: bool,
   5787 ) !void {
   5788     if (!requires_comptime) return;
   5789 
   5790     const src_loc = if (try sema.funcDeclSrc(block, func_src, func)) |capture| blk: {
   5791         var src_loc = capture;
   5792         src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 };
   5793         break :blk src_loc;
   5794     } else blk: {
   5795         const src_decl = sema.mod.declPtr(block.src_decl);
   5796         break :blk func_src.toSrcLoc(src_decl);
   5797     };
   5798     if (return_ty.tag() == .generic_poison) {
   5799         return sema.mod.errNoteNonLazy(src_loc, parent, "generic function is instantiated with a comptime only return type", .{});
   5800     }
   5801     try sema.mod.errNoteNonLazy(
   5802         src_loc,
   5803         parent,
   5804         "function is being called at comptime because it returns a comptime only type '{}'",
   5805         .{return_ty.fmt(sema.mod)},
   5806     );
   5807     try sema.explainWhyTypeIsComptime(block, func_src, parent, src_loc, return_ty);
   5808 }
   5809 
   5810 fn analyzeCall(
   5811     sema: *Sema,
   5812     block: *Block,
   5813     func: Air.Inst.Ref,
   5814     func_src: LazySrcLoc,
   5815     call_src: LazySrcLoc,
   5816     modifier: std.builtin.CallOptions.Modifier,
   5817     ensure_result_used: bool,
   5818     uncasted_args: []const Air.Inst.Ref,
   5819     bound_arg_src: ?LazySrcLoc,
   5820 ) CompileError!Air.Inst.Ref {
   5821     const mod = sema.mod;
   5822 
   5823     const callee_ty = sema.typeOf(func);
   5824     const func_ty = func_ty: {
   5825         switch (callee_ty.zigTypeTag()) {
   5826             .Fn => break :func_ty callee_ty,
   5827             .Pointer => {
   5828                 const ptr_info = callee_ty.ptrInfo().data;
   5829                 if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) {
   5830                     break :func_ty ptr_info.pointee_type;
   5831                 }
   5832             },
   5833             else => {},
   5834         }
   5835         return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
   5836     };
   5837 
   5838     const func_ty_info = func_ty.fnInfo();
   5839     const cc = func_ty_info.cc;
   5840     if (cc == .Naked) {
   5841         const decl_src = try sema.funcDeclSrc(block, func_src, func);
   5842         const msg = msg: {
   5843             const msg = try sema.errMsg(
   5844                 block,
   5845                 func_src,
   5846                 "unable to call function with naked calling convention",
   5847                 .{},
   5848             );
   5849             errdefer msg.destroy(sema.gpa);
   5850 
   5851             if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{});
   5852             break :msg msg;
   5853         };
   5854         return sema.failWithOwnedErrorMsg(msg);
   5855     }
   5856     const fn_params_len = func_ty_info.param_types.len;
   5857     if (func_ty_info.is_var_args) {
   5858         assert(cc == .C);
   5859         if (uncasted_args.len < fn_params_len) {
   5860             // TODO add error note: declared here
   5861             return sema.fail(
   5862                 block,
   5863                 func_src,
   5864                 "expected at least {d} argument(s), found {d}",
   5865                 .{ fn_params_len, uncasted_args.len },
   5866             );
   5867         }
   5868     } else if (fn_params_len != uncasted_args.len) {
   5869         // TODO add error note: declared here
   5870         return sema.fail(
   5871             block,
   5872             call_src,
   5873             "expected {d} argument(s), found {d}",
   5874             .{ fn_params_len, uncasted_args.len },
   5875         );
   5876     }
   5877 
   5878     const call_tag: Air.Inst.Tag = switch (modifier) {
   5879         .auto,
   5880         .always_inline,
   5881         .compile_time,
   5882         .no_async,
   5883         => Air.Inst.Tag.call,
   5884 
   5885         .never_tail => Air.Inst.Tag.call_never_tail,
   5886         .never_inline => Air.Inst.Tag.call_never_inline,
   5887         .always_tail => Air.Inst.Tag.call_always_tail,
   5888 
   5889         .async_kw => return sema.failWithUseOfAsync(block, call_src),
   5890     };
   5891 
   5892     if (modifier == .never_inline and func_ty_info.cc == .Inline) {
   5893         return sema.fail(block, call_src, "no-inline call of inline function", .{});
   5894     }
   5895 
   5896     const gpa = sema.gpa;
   5897 
   5898     var is_generic_call = func_ty_info.is_generic;
   5899     var is_comptime_call = block.is_comptime or modifier == .compile_time;
   5900     var comptime_only_ret_ty = false;
   5901     if (!is_comptime_call) {
   5902         if (sema.typeRequiresComptime(func_ty_info.return_type)) |ct| {
   5903             is_comptime_call = ct;
   5904             comptime_only_ret_ty = ct;
   5905         } else |err| switch (err) {
   5906             error.GenericPoison => is_generic_call = true,
   5907             else => |e| return e,
   5908         }
   5909     }
   5910     var is_inline_call = is_comptime_call or modifier == .always_inline or
   5911         func_ty_info.cc == .Inline;
   5912 
   5913     if (!is_inline_call and is_generic_call) {
   5914         if (sema.instantiateGenericCall(
   5915             block,
   5916             func,
   5917             func_src,
   5918             call_src,
   5919             func_ty_info,
   5920             ensure_result_used,
   5921             uncasted_args,
   5922             call_tag,
   5923             bound_arg_src,
   5924         )) |some| {
   5925             return some;
   5926         } else |err| switch (err) {
   5927             error.GenericPoison => {
   5928                 is_inline_call = true;
   5929             },
   5930             error.ComptimeReturn => {
   5931                 is_inline_call = true;
   5932                 is_comptime_call = true;
   5933                 comptime_only_ret_ty = true;
   5934             },
   5935             else => |e| return e,
   5936         }
   5937     }
   5938 
   5939     if (is_comptime_call and modifier == .never_inline) {
   5940         return sema.fail(block, call_src, "unable to perform 'never_inline' call at compile-time", .{});
   5941     }
   5942 
   5943     const result: Air.Inst.Ref = if (is_inline_call) res: {
   5944         const func_val = sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime known") catch |err| {
   5945             if (err == error.AnalysisFail and sema.err != null) {
   5946                 try sema.addComptimeReturnTypeNote(block, func, func_src, func_ty_info.return_type, sema.err.?, comptime_only_ret_ty);
   5947             }
   5948             return err;
   5949         };
   5950         const module_fn = switch (func_val.tag()) {
   5951             .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data,
   5952             .function => func_val.castTag(.function).?.data,
   5953             .extern_fn => return sema.fail(block, call_src, "{s} call of extern function", .{
   5954                 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
   5955             }),
   5956             else => unreachable,
   5957         };
   5958 
   5959         // Analyze the ZIR. The same ZIR gets analyzed into a runtime function
   5960         // or an inlined call depending on what union tag the `label` field is
   5961         // set to in the `Block`.
   5962         // This block instruction will be used to capture the return value from the
   5963         // inlined function.
   5964         const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
   5965         try sema.air_instructions.append(gpa, .{
   5966             .tag = .block,
   5967             .data = undefined,
   5968         });
   5969         // This one is shared among sub-blocks within the same callee, but not
   5970         // shared among the entire inline/comptime call stack.
   5971         var inlining: Block.Inlining = .{
   5972             .comptime_result = undefined,
   5973             .merges = .{
   5974                 .results = .{},
   5975                 .br_list = .{},
   5976                 .block_inst = block_inst,
   5977             },
   5978         };
   5979         // In order to save a bit of stack space, directly modify Sema rather
   5980         // than create a child one.
   5981         const parent_zir = sema.code;
   5982         const fn_owner_decl = mod.declPtr(module_fn.owner_decl);
   5983         sema.code = fn_owner_decl.getFileScope().zir;
   5984         defer sema.code = parent_zir;
   5985 
   5986         const parent_inst_map = sema.inst_map;
   5987         sema.inst_map = .{};
   5988         defer {
   5989             sema.inst_map.deinit(gpa);
   5990             sema.inst_map = parent_inst_map;
   5991         }
   5992 
   5993         const parent_func = sema.func;
   5994         sema.func = module_fn;
   5995         defer sema.func = parent_func;
   5996 
   5997         var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, fn_owner_decl.src_scope);
   5998         defer wip_captures.deinit();
   5999 
   6000         var child_block: Block = .{
   6001             .parent = null,
   6002             .sema = sema,
   6003             .src_decl = module_fn.owner_decl,
   6004             .namespace = fn_owner_decl.src_namespace,
   6005             .wip_capture_scope = wip_captures.scope,
   6006             .instructions = .{},
   6007             .label = null,
   6008             .inlining = &inlining,
   6009             .is_comptime = is_comptime_call,
   6010         };
   6011 
   6012         const merges = &child_block.inlining.?.merges;
   6013 
   6014         defer child_block.instructions.deinit(gpa);
   6015         defer merges.results.deinit(gpa);
   6016         defer merges.br_list.deinit(gpa);
   6017 
   6018         // If it's a comptime function call, we need to memoize it as long as no external
   6019         // comptime memory is mutated.
   6020         var memoized_call_key: Module.MemoizedCall.Key = undefined;
   6021         var delete_memoized_call_key = false;
   6022         defer if (delete_memoized_call_key) gpa.free(memoized_call_key.args);
   6023         if (is_comptime_call) {
   6024             memoized_call_key = .{
   6025                 .func = module_fn,
   6026                 .args = try gpa.alloc(TypedValue, func_ty_info.param_types.len),
   6027             };
   6028             delete_memoized_call_key = true;
   6029         }
   6030 
   6031         try sema.emitBackwardBranch(block, call_src);
   6032 
   6033         // Whether this call should be memoized, set to false if the call can mutate
   6034         // comptime state.
   6035         var should_memoize = true;
   6036 
   6037         var new_fn_info = fn_owner_decl.ty.fnInfo();
   6038         new_fn_info.param_types = try sema.arena.alloc(Type, new_fn_info.param_types.len);
   6039         new_fn_info.comptime_params = (try sema.arena.alloc(bool, new_fn_info.param_types.len)).ptr;
   6040 
   6041         // This will have return instructions analyzed as break instructions to
   6042         // the block_inst above. Here we are performing "comptime/inline semantic analysis"
   6043         // for a function body, which means we must map the parameter ZIR instructions to
   6044         // the AIR instructions of the callsite. The callee could be a generic function
   6045         // which means its parameter type expressions must be resolved in order and used
   6046         // to successively coerce the arguments.
   6047         const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst);
   6048         var arg_i: usize = 0;
   6049         for (fn_info.param_body) |inst| {
   6050             sema.analyzeInlineCallArg(
   6051                 block,
   6052                 &child_block,
   6053                 .unneeded,
   6054                 inst,
   6055                 new_fn_info,
   6056                 &arg_i,
   6057                 uncasted_args,
   6058                 is_comptime_call,
   6059                 &should_memoize,
   6060                 memoized_call_key,
   6061                 // last 4 arguments are only used when reporting errors
   6062                 undefined,
   6063                 undefined,
   6064                 undefined,
   6065                 undefined,
   6066             ) catch |err| switch (err) {
   6067                 error.NeededSourceLocation => {
   6068                     _ = sema.inst_map.remove(inst);
   6069                     const decl = sema.mod.declPtr(block.src_decl);
   6070                     try sema.analyzeInlineCallArg(
   6071                         block,
   6072                         &child_block,
   6073                         Module.argSrc(call_src.node_offset.x, sema.gpa, decl, arg_i, bound_arg_src),
   6074                         inst,
   6075                         new_fn_info,
   6076                         &arg_i,
   6077                         uncasted_args,
   6078                         is_comptime_call,
   6079                         &should_memoize,
   6080                         memoized_call_key,
   6081                         func,
   6082                         func_src,
   6083                         func_ty_info.return_type,
   6084                         comptime_only_ret_ty,
   6085                     );
   6086                     return error.AnalysisFail;
   6087                 },
   6088                 else => |e| return e,
   6089             };
   6090         }
   6091 
   6092         // In case it is a generic function with an expression for the return type that depends
   6093         // on parameters, we must now do the same for the return type as we just did with
   6094         // each of the parameters, resolving the return type and providing it to the child
   6095         // `Sema` so that it can be used for the `ret_ptr` instruction.
   6096         const ret_ty_inst = if (fn_info.ret_ty_body.len != 0)
   6097             try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst)
   6098         else
   6099             try sema.resolveInst(fn_info.ret_ty_ref);
   6100         const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
   6101         const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);
   6102         // Create a fresh inferred error set type for inline/comptime calls.
   6103         const fn_ret_ty = blk: {
   6104             if (module_fn.hasInferredErrorSet(mod)) {
   6105                 const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode);
   6106                 node.data = .{ .func = module_fn };
   6107                 if (parent_func) |some| {
   6108                     some.inferred_error_sets.prepend(node);
   6109                 }
   6110 
   6111                 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data);
   6112                 break :blk try Type.Tag.error_union.create(sema.arena, .{
   6113                     .error_set = error_set_ty,
   6114                     .payload = bare_return_type,
   6115                 });
   6116             }
   6117             break :blk bare_return_type;
   6118         };
   6119         new_fn_info.return_type = fn_ret_ty;
   6120         const parent_fn_ret_ty = sema.fn_ret_ty;
   6121         sema.fn_ret_ty = fn_ret_ty;
   6122         defer sema.fn_ret_ty = parent_fn_ret_ty;
   6123 
   6124         // This `res2` is here instead of directly breaking from `res` due to a stage1
   6125         // bug generating invalid LLVM IR.
   6126         const res2: Air.Inst.Ref = res2: {
   6127             if (should_memoize and is_comptime_call) {
   6128                 if (mod.memoized_calls.getContext(memoized_call_key, .{ .module = mod })) |result| {
   6129                     const ty_inst = try sema.addType(fn_ret_ty);
   6130                     try sema.air_values.append(gpa, result.val);
   6131                     sema.air_instructions.set(block_inst, .{
   6132                         .tag = .constant,
   6133                         .data = .{ .ty_pl = .{
   6134                             .ty = ty_inst,
   6135                             .payload = @intCast(u32, sema.air_values.items.len - 1),
   6136                         } },
   6137                     });
   6138                     break :res2 Air.indexToRef(block_inst);
   6139                 }
   6140             }
   6141 
   6142             const new_func_resolved_ty = try Type.Tag.function.create(sema.arena, new_fn_info);
   6143             if (!is_comptime_call) {
   6144                 try sema.emitDbgInline(block, parent_func.?, module_fn, new_func_resolved_ty, .dbg_inline_begin);
   6145 
   6146                 const zir_tags = sema.code.instructions.items(.tag);
   6147                 for (fn_info.param_body) |param| switch (zir_tags[param]) {
   6148                     .param, .param_comptime => {
   6149                         const inst_data = sema.code.instructions.items(.data)[param].pl_tok;
   6150                         const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);
   6151                         const param_name = sema.code.nullTerminatedString(extra.data.name);
   6152                         const inst = sema.inst_map.get(param).?;
   6153 
   6154                         try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name);
   6155                     },
   6156                     .param_anytype, .param_anytype_comptime => {
   6157                         const inst_data = sema.code.instructions.items(.data)[param].str_tok;
   6158                         const param_name = inst_data.get(sema.code);
   6159                         const inst = sema.inst_map.get(param).?;
   6160 
   6161                         try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name);
   6162                     },
   6163                     else => continue,
   6164                 };
   6165             }
   6166 
   6167             const result = result: {
   6168                 sema.analyzeBody(&child_block, fn_info.body) catch |err| switch (err) {
   6169                     error.ComptimeReturn => break :result inlining.comptime_result,
   6170                     error.AnalysisFail => {
   6171                         const err_msg = sema.err orelse return err;
   6172                         try sema.errNote(block, call_src, err_msg, "called from here", .{});
   6173                         err_msg.clearTrace(sema.gpa);
   6174                         return err;
   6175                     },
   6176                     else => |e| return e,
   6177                 };
   6178                 break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges);
   6179             };
   6180 
   6181             if (!is_comptime_call and sema.typeOf(result).zigTypeTag() != .NoReturn) {
   6182                 try sema.emitDbgInline(
   6183                     block,
   6184                     module_fn,
   6185                     parent_func.?,
   6186                     mod.declPtr(parent_func.?.owner_decl).ty,
   6187                     .dbg_inline_end,
   6188                 );
   6189             }
   6190 
   6191             if (should_memoize and is_comptime_call) {
   6192                 const result_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, result, undefined);
   6193 
   6194                 // TODO: check whether any external comptime memory was mutated by the
   6195                 // comptime function call. If so, then do not memoize the call here.
   6196                 // TODO: re-evaluate whether memoized_calls needs its own arena. I think
   6197                 // it should be fine to use the Decl arena for the function.
   6198                 {
   6199                     var arena_allocator = std.heap.ArenaAllocator.init(gpa);
   6200                     errdefer arena_allocator.deinit();
   6201                     const arena = arena_allocator.allocator();
   6202 
   6203                     for (memoized_call_key.args) |*arg| {
   6204                         arg.* = try arg.*.copy(arena);
   6205                     }
   6206 
   6207                     try mod.memoized_calls.putContext(gpa, memoized_call_key, .{
   6208                         .val = try result_val.copy(arena),
   6209                         .arena = arena_allocator.state,
   6210                     }, .{ .module = mod });
   6211                     delete_memoized_call_key = false;
   6212                 }
   6213             }
   6214 
   6215             break :res2 result;
   6216         };
   6217 
   6218         try wip_captures.finalize();
   6219 
   6220         break :res res2;
   6221     } else res: {
   6222         assert(!func_ty_info.is_generic);
   6223         try sema.requireFunctionBlock(block, call_src);
   6224 
   6225         const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);
   6226         for (uncasted_args) |uncasted_arg, i| {
   6227             if (i < fn_params_len) {
   6228                 const param_ty = func_ty.fnParamType(i);
   6229                 args[i] = sema.analyzeCallArg(
   6230                     block,
   6231                     .unneeded,
   6232                     param_ty,
   6233                     uncasted_arg,
   6234                 ) catch |err| switch (err) {
   6235                     error.NeededSourceLocation => {
   6236                         const decl = sema.mod.declPtr(block.src_decl);
   6237                         _ = try sema.analyzeCallArg(
   6238                             block,
   6239                             Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src),
   6240                             param_ty,
   6241                             uncasted_arg,
   6242                         );
   6243                         return error.AnalysisFail;
   6244                     },
   6245                     else => |e| return e,
   6246                 };
   6247             } else {
   6248                 args[i] = sema.coerceVarArgParam(block, uncasted_arg, .unneeded) catch |err| switch (err) {
   6249                     error.NeededSourceLocation => {
   6250                         const decl = sema.mod.declPtr(block.src_decl);
   6251                         _ = try sema.coerceVarArgParam(
   6252                             block,
   6253                             uncasted_arg,
   6254                             Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src),
   6255                         );
   6256                         return error.AnalysisFail;
   6257                     },
   6258                     else => |e| return e,
   6259                 };
   6260             }
   6261         }
   6262 
   6263         try sema.queueFullTypeResolution(func_ty_info.return_type);
   6264         if (sema.owner_func != null and func_ty_info.return_type.isError()) {
   6265             sema.owner_func.?.calls_or_awaits_errorable_fn = true;
   6266         }
   6267 
   6268         try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
   6269             args.len);
   6270         const func_inst = try block.addInst(.{
   6271             .tag = call_tag,
   6272             .data = .{ .pl_op = .{
   6273                 .operand = func,
   6274                 .payload = sema.addExtraAssumeCapacity(Air.Call{
   6275                     .args_len = @intCast(u32, args.len),
   6276                 }),
   6277             } },
   6278         });
   6279         sema.appendRefsAssumeCapacity(args);
   6280         break :res func_inst;
   6281     };
   6282 
   6283     if (ensure_result_used) {
   6284         try sema.ensureResultUsed(block, result, call_src);
   6285     }
   6286     if (call_tag == .call_always_tail) {
   6287         return sema.handleTailCall(block, call_src, func_ty, result);
   6288     }
   6289     return result;
   6290 }
   6291 
   6292 fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref {
   6293     const target = sema.mod.getTarget();
   6294     const backend = sema.mod.comp.getZigBackend();
   6295     if (!target_util.supportsTailCall(target, backend)) {
   6296         return sema.fail(block, call_src, "unable to perform tail call: compiler backend '{s}' does not support tail calls on target architecture '{s}' with the selected CPU feature flags", .{
   6297             @tagName(backend), @tagName(target.cpu.arch),
   6298         });
   6299     }
   6300     const func_decl = sema.mod.declPtr(sema.owner_func.?.owner_decl);
   6301     if (!func_ty.eql(func_decl.ty, sema.mod)) {
   6302         return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{
   6303             func_ty.fmt(sema.mod), func_decl.ty.fmt(sema.mod),
   6304         });
   6305     }
   6306     _ = try block.addUnOp(.ret, result);
   6307     return Air.Inst.Ref.unreachable_value;
   6308 }
   6309 
   6310 fn analyzeInlineCallArg(
   6311     sema: *Sema,
   6312     arg_block: *Block,
   6313     param_block: *Block,
   6314     arg_src: LazySrcLoc,
   6315     inst: Zir.Inst.Index,
   6316     new_fn_info: Type.Payload.Function.Data,
   6317     arg_i: *usize,
   6318     uncasted_args: []const Air.Inst.Ref,
   6319     is_comptime_call: bool,
   6320     should_memoize: *bool,
   6321     memoized_call_key: Module.MemoizedCall.Key,
   6322     func: Air.Inst.Ref,
   6323     func_src: LazySrcLoc,
   6324     ret_ty: Type,
   6325     comptime_only_ret_ty: bool,
   6326 ) !void {
   6327     const zir_tags = sema.code.instructions.items(.tag);
   6328     switch (zir_tags[inst]) {
   6329         .param, .param_comptime => {
   6330             // Evaluate the parameter type expression now that previous ones have
   6331             // been mapped, and coerce the corresponding argument to it.
   6332             const pl_tok = sema.code.instructions.items(.data)[inst].pl_tok;
   6333             const param_src = pl_tok.src();
   6334             const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index);
   6335             const param_body = sema.code.extra[extra.end..][0..extra.data.body_len];
   6336             const param_ty_inst = try sema.resolveBody(param_block, param_body, inst);
   6337             const param_ty = try sema.analyzeAsType(param_block, param_src, param_ty_inst);
   6338             new_fn_info.param_types[arg_i.*] = param_ty;
   6339             const uncasted_arg = uncasted_args[arg_i.*];
   6340             if (try sema.typeRequiresComptime(param_ty)) {
   6341                 _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime only type must be comptime known") catch |err| {
   6342                     if (err == error.AnalysisFail and sema.err != null) {
   6343                         try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
   6344                     }
   6345                     return err;
   6346                 };
   6347             }
   6348             const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src);
   6349             try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
   6350 
   6351             if (is_comptime_call) {
   6352                 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known") catch |err| {
   6353                     if (err == error.AnalysisFail and sema.err != null) {
   6354                         try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
   6355                     }
   6356                     return err;
   6357                 };
   6358                 switch (arg_val.tag()) {
   6359                     .generic_poison, .generic_poison_type => {
   6360                         // This function is currently evaluated as part of an as-of-yet unresolvable
   6361                         // parameter or return type.
   6362                         return error.GenericPoison;
   6363                     },
   6364                     else => {
   6365                         // Needed so that lazy values do not trigger
   6366                         // assertion due to type not being resolved
   6367                         // when the hash function is called.
   6368                         try sema.resolveLazyValue(arg_block, arg_src, arg_val);
   6369                     },
   6370                 }
   6371                 should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState();
   6372                 memoized_call_key.args[arg_i.*] = .{
   6373                     .ty = param_ty,
   6374                     .val = arg_val,
   6375                 };
   6376             }
   6377 
   6378             arg_i.* += 1;
   6379         },
   6380         .param_anytype, .param_anytype_comptime => {
   6381             // No coercion needed.
   6382             const uncasted_arg = uncasted_args[arg_i.*];
   6383             new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg);
   6384             try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
   6385 
   6386             if (is_comptime_call) {
   6387                 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known") catch |err| {
   6388                     if (err == error.AnalysisFail and sema.err != null) {
   6389                         try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
   6390                     }
   6391                     return err;
   6392                 };
   6393                 switch (arg_val.tag()) {
   6394                     .generic_poison, .generic_poison_type => {
   6395                         // This function is currently evaluated as part of an as-of-yet unresolvable
   6396                         // parameter or return type.
   6397                         return error.GenericPoison;
   6398                     },
   6399                     else => {
   6400                         // Needed so that lazy values do not trigger
   6401                         // assertion due to type not being resolved
   6402                         // when the hash function is called.
   6403                         try sema.resolveLazyValue(arg_block, arg_src, arg_val);
   6404                     },
   6405                 }
   6406                 should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState();
   6407                 memoized_call_key.args[arg_i.*] = .{
   6408                     .ty = sema.typeOf(uncasted_arg),
   6409                     .val = arg_val,
   6410                 };
   6411             }
   6412 
   6413             arg_i.* += 1;
   6414         },
   6415         else => {},
   6416     }
   6417 }
   6418 
   6419 fn analyzeCallArg(
   6420     sema: *Sema,
   6421     block: *Block,
   6422     arg_src: LazySrcLoc,
   6423     param_ty: Type,
   6424     uncasted_arg: Air.Inst.Ref,
   6425 ) !Air.Inst.Ref {
   6426     try sema.resolveTypeFully(block, arg_src, param_ty);
   6427     return sema.coerce(block, param_ty, uncasted_arg, arg_src);
   6428 }
   6429 
   6430 fn analyzeGenericCallArg(
   6431     sema: *Sema,
   6432     block: *Block,
   6433     arg_src: LazySrcLoc,
   6434     uncasted_arg: Air.Inst.Ref,
   6435     comptime_arg: TypedValue,
   6436     runtime_args: []Air.Inst.Ref,
   6437     new_fn_info: Type.Payload.Function.Data,
   6438     runtime_i: *u32,
   6439 ) !void {
   6440     const is_runtime = comptime_arg.val.tag() == .generic_poison and
   6441         comptime_arg.ty.hasRuntimeBits() and
   6442         !(try sema.typeRequiresComptime(comptime_arg.ty));
   6443     if (is_runtime) {
   6444         const param_ty = new_fn_info.param_types[runtime_i.*];
   6445         const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
   6446         try sema.queueFullTypeResolution(param_ty);
   6447         runtime_args[runtime_i.*] = casted_arg;
   6448         runtime_i.* += 1;
   6449     }
   6450 }
   6451 
   6452 fn analyzeGenericCallArgVal(sema: *Sema, block: *Block, arg_src: LazySrcLoc, uncasted_arg: Air.Inst.Ref) !Value {
   6453     const arg_val = try sema.resolveValue(block, arg_src, uncasted_arg, "parameter is comptime");
   6454     try sema.resolveLazyValue(block, arg_src, arg_val);
   6455     return arg_val;
   6456 }
   6457 
   6458 fn instantiateGenericCall(
   6459     sema: *Sema,
   6460     block: *Block,
   6461     func: Air.Inst.Ref,
   6462     func_src: LazySrcLoc,
   6463     call_src: LazySrcLoc,
   6464     func_ty_info: Type.Payload.Function.Data,
   6465     ensure_result_used: bool,
   6466     uncasted_args: []const Air.Inst.Ref,
   6467     call_tag: Air.Inst.Tag,
   6468     bound_arg_src: ?LazySrcLoc,
   6469 ) CompileError!Air.Inst.Ref {
   6470     const mod = sema.mod;
   6471     const gpa = sema.gpa;
   6472 
   6473     const func_val = try sema.resolveConstValue(block, func_src, func, "generic function being called must be comptime known");
   6474     const module_fn = switch (func_val.tag()) {
   6475         .function => func_val.castTag(.function).?.data,
   6476         .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data,
   6477         else => unreachable,
   6478     };
   6479     // Check the Module's generic function map with an adapted context, so that we
   6480     // can match against `uncasted_args` rather than doing the work below to create a
   6481     // generic Scope only to junk it if it matches an existing instantiation.
   6482     const fn_owner_decl = mod.declPtr(module_fn.owner_decl);
   6483     const namespace = fn_owner_decl.src_namespace;
   6484     const fn_zir = namespace.file_scope.zir;
   6485     const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst);
   6486     const zir_tags = fn_zir.instructions.items(.tag);
   6487 
   6488     // This hash must match `Module.MonomorphedFuncsContext.hash`.
   6489     // For parameters explicitly marked comptime and simple parameter type expressions,
   6490     // we know whether a parameter is elided from a monomorphed function, and can
   6491     // use it in the hash here. However, for parameter type expressions that are not
   6492     // explicitly marked comptime and rely on previous parameter comptime values, we
   6493     // don't find out until after generating a monomorphed function whether the parameter
   6494     // type ended up being a "must-be-comptime-known" type.
   6495     var hasher = std.hash.Wyhash.init(0);
   6496     std.hash.autoHash(&hasher, @ptrToInt(module_fn));
   6497 
   6498     const generic_args = try sema.arena.alloc(GenericCallAdapter.Arg, func_ty_info.param_types.len);
   6499     {
   6500         var i: usize = 0;
   6501         for (fn_info.param_body) |inst| {
   6502             var is_comptime = false;
   6503             var is_anytype = false;
   6504             switch (zir_tags[inst]) {
   6505                 .param => {
   6506                     is_comptime = func_ty_info.paramIsComptime(i);
   6507                 },
   6508                 .param_comptime => {
   6509                     is_comptime = true;
   6510                 },
   6511                 .param_anytype => {
   6512                     is_anytype = true;
   6513                     is_comptime = func_ty_info.paramIsComptime(i);
   6514                 },
   6515                 .param_anytype_comptime => {
   6516                     is_anytype = true;
   6517                     is_comptime = true;
   6518                 },
   6519                 else => continue,
   6520             }
   6521 
   6522             const arg_ty = sema.typeOf(uncasted_args[i]);
   6523 
   6524             if (is_comptime) {
   6525                 const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[i]) catch |err| switch (err) {
   6526                     error.NeededSourceLocation => {
   6527                         const decl = sema.mod.declPtr(block.src_decl);
   6528                         const arg_src = Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src);
   6529                         _ = try sema.analyzeGenericCallArgVal(block, arg_src, uncasted_args[i]);
   6530                         return error.AnalysisFail;
   6531                     },
   6532                     else => |e| return e,
   6533                 };
   6534                 arg_val.hash(arg_ty, &hasher, mod);
   6535                 if (is_anytype) {
   6536                     arg_ty.hashWithHasher(&hasher, mod);
   6537                     generic_args[i] = .{
   6538                         .ty = arg_ty,
   6539                         .val = arg_val,
   6540                         .is_anytype = true,
   6541                     };
   6542                 } else {
   6543                     generic_args[i] = .{
   6544                         .ty = arg_ty,
   6545                         .val = arg_val,
   6546                         .is_anytype = false,
   6547                     };
   6548                 }
   6549             } else if (is_anytype) {
   6550                 arg_ty.hashWithHasher(&hasher, mod);
   6551                 generic_args[i] = .{
   6552                     .ty = arg_ty,
   6553                     .val = Value.initTag(.generic_poison),
   6554                     .is_anytype = true,
   6555                 };
   6556             } else {
   6557                 generic_args[i] = .{
   6558                     .ty = arg_ty,
   6559                     .val = Value.initTag(.generic_poison),
   6560                     .is_anytype = false,
   6561                 };
   6562             }
   6563 
   6564             i += 1;
   6565         }
   6566     }
   6567 
   6568     const precomputed_hash = hasher.final();
   6569 
   6570     const adapter: GenericCallAdapter = .{
   6571         .generic_fn = module_fn,
   6572         .precomputed_hash = precomputed_hash,
   6573         .func_ty_info = func_ty_info,
   6574         .args = generic_args,
   6575         .module = mod,
   6576     };
   6577     const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter);
   6578     const callee = if (!gop.found_existing) callee: {
   6579         const new_module_func = try gpa.create(Module.Fn);
   6580         errdefer gpa.destroy(new_module_func);
   6581 
   6582         // This ensures that we can operate on the hash map before the Module.Fn
   6583         // struct is fully initialized.
   6584         new_module_func.hash = precomputed_hash;
   6585         new_module_func.generic_owner_decl = module_fn.owner_decl.toOptional();
   6586         new_module_func.comptime_args = null;
   6587         gop.key_ptr.* = new_module_func;
   6588         errdefer assert(mod.monomorphed_funcs.remove(new_module_func));
   6589 
   6590         try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);
   6591 
   6592         // Create a Decl for the new function.
   6593         const src_decl_index = namespace.getDeclIndex();
   6594         const src_decl = mod.declPtr(src_decl_index);
   6595         const new_decl_index = try mod.allocateNewDecl(namespace, fn_owner_decl.src_node, src_decl.src_scope);
   6596         errdefer mod.destroyDecl(new_decl_index);
   6597         const new_decl = mod.declPtr(new_decl_index);
   6598         // TODO better names for generic function instantiations
   6599         const decl_name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{
   6600             fn_owner_decl.name, @enumToInt(new_decl_index),
   6601         });
   6602         new_decl.name = decl_name;
   6603         new_decl.src_line = fn_owner_decl.src_line;
   6604         new_decl.is_pub = fn_owner_decl.is_pub;
   6605         new_decl.is_exported = fn_owner_decl.is_exported;
   6606         new_decl.has_align = fn_owner_decl.has_align;
   6607         new_decl.has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace;
   6608         new_decl.@"linksection" = fn_owner_decl.@"linksection";
   6609         new_decl.@"addrspace" = fn_owner_decl.@"addrspace";
   6610         new_decl.zir_decl_index = fn_owner_decl.zir_decl_index;
   6611         new_decl.alive = true; // This Decl is called at runtime.
   6612         new_decl.analysis = .in_progress;
   6613         new_decl.generation = mod.generation;
   6614 
   6615         namespace.anon_decls.putAssumeCapacityNoClobber(new_decl_index, {});
   6616         errdefer assert(namespace.anon_decls.orderedRemove(new_decl_index));
   6617 
   6618         // The generic function Decl is guaranteed to be the first dependency
   6619         // of each of its instantiations.
   6620         assert(new_decl.dependencies.keys().len == 0);
   6621         try mod.declareDeclDependency(new_decl_index, module_fn.owner_decl);
   6622         // Resolving the new function type below will possibly declare more decl dependencies
   6623         // and so we remove them all here in case of error.
   6624         errdefer {
   6625             for (new_decl.dependencies.keys()) |dep_index| {
   6626                 const dep = mod.declPtr(dep_index);
   6627                 dep.removeDependant(new_decl_index);
   6628             }
   6629         }
   6630 
   6631         var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
   6632         errdefer new_decl_arena.deinit();
   6633         const new_decl_arena_allocator = new_decl_arena.allocator();
   6634 
   6635         // Re-run the block that creates the function, with the comptime parameters
   6636         // pre-populated inside `inst_map`. This causes `param_comptime` and
   6637         // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a
   6638         // new, monomorphized function, with the comptime parameters elided.
   6639         var child_sema: Sema = .{
   6640             .mod = mod,
   6641             .gpa = gpa,
   6642             .arena = sema.arena,
   6643             .perm_arena = new_decl_arena_allocator,
   6644             .code = fn_zir,
   6645             .owner_decl = new_decl,
   6646             .owner_decl_index = new_decl_index,
   6647             .func = null,
   6648             .fn_ret_ty = Type.void,
   6649             .owner_func = null,
   6650             .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len),
   6651             .comptime_args_fn_inst = module_fn.zir_body_inst,
   6652             .preallocated_new_func = new_module_func,
   6653             .is_generic_instantiation = true,
   6654         };
   6655         defer child_sema.deinit();
   6656 
   6657         var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope);
   6658         defer wip_captures.deinit();
   6659 
   6660         var child_block: Block = .{
   6661             .parent = null,
   6662             .sema = &child_sema,
   6663             .src_decl = new_decl_index,
   6664             .namespace = namespace,
   6665             .wip_capture_scope = wip_captures.scope,
   6666             .instructions = .{},
   6667             .inlining = null,
   6668             .is_comptime = true,
   6669         };
   6670         defer {
   6671             child_block.instructions.deinit(gpa);
   6672             child_block.params.deinit(gpa);
   6673         }
   6674 
   6675         try child_sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, uncasted_args.len));
   6676         var arg_i: usize = 0;
   6677         for (fn_info.param_body) |inst| {
   6678             var is_comptime = false;
   6679             var is_anytype = false;
   6680             switch (zir_tags[inst]) {
   6681                 .param => {
   6682                     is_comptime = func_ty_info.paramIsComptime(arg_i);
   6683                 },
   6684                 .param_comptime => {
   6685                     is_comptime = true;
   6686                 },
   6687                 .param_anytype => {
   6688                     is_anytype = true;
   6689                     is_comptime = func_ty_info.paramIsComptime(arg_i);
   6690                 },
   6691                 .param_anytype_comptime => {
   6692                     is_anytype = true;
   6693                     is_comptime = true;
   6694                 },
   6695                 else => continue,
   6696             }
   6697             const arg = uncasted_args[arg_i];
   6698             if (is_comptime) {
   6699                 if (try sema.resolveMaybeUndefVal(block, .unneeded, arg)) |arg_val| {
   6700                     const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val);
   6701                     child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
   6702                 } else {
   6703                     return sema.failWithNeededComptime(block, .unneeded, undefined);
   6704                 }
   6705             } else if (is_anytype) {
   6706                 const arg_ty = sema.typeOf(arg);
   6707                 if (try sema.typeRequiresComptime(arg_ty)) {
   6708                     const arg_val = try sema.resolveConstValue(block, .unneeded, arg, undefined);
   6709                     const child_arg = try child_sema.addConstant(arg_ty, arg_val);
   6710                     child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
   6711                 } else {
   6712                     // We insert into the map an instruction which is runtime-known
   6713                     // but has the type of the argument.
   6714                     const child_arg = try child_block.addArg(arg_ty);
   6715                     child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
   6716                 }
   6717             }
   6718             arg_i += 1;
   6719         }
   6720         const new_func_inst = child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst) catch |err| {
   6721             // TODO look up the compile error that happened here and attach a note to it
   6722             // pointing here, at the generic instantiation callsite.
   6723             if (sema.owner_func) |owner_func| {
   6724                 owner_func.state = .dependency_failure;
   6725             } else {
   6726                 sema.owner_decl.analysis = .dependency_failure;
   6727             }
   6728             return err;
   6729         };
   6730         const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst, undefined) catch unreachable;
   6731         const new_func = new_func_val.castTag(.function).?.data;
   6732         errdefer new_func.deinit(gpa);
   6733         assert(new_func == new_module_func);
   6734 
   6735         arg_i = 0;
   6736         for (fn_info.param_body) |inst| {
   6737             var is_comptime = false;
   6738             switch (zir_tags[inst]) {
   6739                 .param => {
   6740                     is_comptime = func_ty_info.paramIsComptime(arg_i);
   6741                 },
   6742                 .param_comptime => {
   6743                     is_comptime = true;
   6744                 },
   6745                 .param_anytype => {
   6746                     is_comptime = func_ty_info.paramIsComptime(arg_i);
   6747                 },
   6748                 .param_anytype_comptime => {
   6749                     is_comptime = true;
   6750                 },
   6751                 else => continue,
   6752             }
   6753 
   6754             // We populate the Type here regardless because it is needed by
   6755             // `GenericCallAdapter.eql` as well as function body analysis.
   6756             // Whether it is anytype is communicated by `isAnytypeParam`.
   6757             const arg = child_sema.inst_map.get(inst).?;
   6758             const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator);
   6759 
   6760             if (try sema.typeRequiresComptime(copied_arg_ty)) {
   6761                 is_comptime = true;
   6762             }
   6763 
   6764             if (is_comptime) {
   6765                 const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(
   6766                     &child_block,
   6767                     .unneeded,
   6768                     arg,
   6769                 ) catch unreachable).?;
   6770                 child_sema.comptime_args[arg_i] = .{
   6771                     .ty = copied_arg_ty,
   6772                     .val = try arg_val.copy(new_decl_arena_allocator),
   6773                 };
   6774             } else {
   6775                 child_sema.comptime_args[arg_i] = .{
   6776                     .ty = copied_arg_ty,
   6777                     .val = Value.initTag(.generic_poison),
   6778                 };
   6779             }
   6780 
   6781             arg_i += 1;
   6782         }
   6783 
   6784         try wip_captures.finalize();
   6785 
   6786         // Populate the Decl ty/val with the function and its type.
   6787         new_decl.ty = try child_sema.typeOf(new_func_inst).copy(new_decl_arena_allocator);
   6788         // If the call evaluated to a return type that requires comptime, never mind
   6789         // our generic instantiation. Instead we need to perform a comptime call.
   6790         const new_fn_info = new_decl.ty.fnInfo();
   6791         if (try sema.typeRequiresComptime(new_fn_info.return_type)) {
   6792             return error.ComptimeReturn;
   6793         }
   6794         // Similarly, if the call evaluated to a generic type we need to instead
   6795         // call it inline.
   6796         if (new_fn_info.is_generic or new_fn_info.cc == .Inline) {
   6797             return error.GenericPoison;
   6798         }
   6799 
   6800         new_decl.val = try Value.Tag.function.create(new_decl_arena_allocator, new_func);
   6801         new_decl.@"align" = 0;
   6802         new_decl.has_tv = true;
   6803         new_decl.owns_tv = true;
   6804         new_decl.analysis = .complete;
   6805 
   6806         log.debug("generic function '{s}' instantiated with type {}", .{
   6807             new_decl.name, new_decl.ty.fmtDebug(),
   6808         });
   6809 
   6810         // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field
   6811         // will be populated, ensuring it will have `analyzeBody` called with the ZIR
   6812         // parameters mapped appropriately.
   6813         try mod.comp.bin_file.allocateDeclIndexes(new_decl_index);
   6814         try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func });
   6815 
   6816         try new_decl.finalizeNewArena(&new_decl_arena);
   6817         break :callee new_func;
   6818     } else gop.key_ptr.*;
   6819 
   6820     callee.branch_quota = @maximum(callee.branch_quota, sema.branch_quota);
   6821 
   6822     const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl);
   6823 
   6824     // Make a runtime call to the new function, making sure to omit the comptime args.
   6825     try sema.requireFunctionBlock(block, call_src);
   6826 
   6827     const comptime_args = callee.comptime_args.?;
   6828     const func_ty = mod.declPtr(callee.owner_decl).ty;
   6829     const new_fn_info = func_ty.fnInfo();
   6830     const runtime_args_len = @intCast(u32, new_fn_info.param_types.len);
   6831     const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len);
   6832     {
   6833         var runtime_i: u32 = 0;
   6834         var total_i: u32 = 0;
   6835         for (fn_info.param_body) |inst| {
   6836             switch (zir_tags[inst]) {
   6837                 .param_comptime, .param_anytype_comptime, .param, .param_anytype => {},
   6838                 else => continue,
   6839             }
   6840             sema.analyzeGenericCallArg(
   6841                 block,
   6842                 .unneeded,
   6843                 uncasted_args[total_i],
   6844                 comptime_args[total_i],
   6845                 runtime_args,
   6846                 new_fn_info,
   6847                 &runtime_i,
   6848             ) catch |err| switch (err) {
   6849                 error.NeededSourceLocation => {
   6850                     const decl = sema.mod.declPtr(block.src_decl);
   6851                     _ = try sema.analyzeGenericCallArg(
   6852                         block,
   6853                         Module.argSrc(call_src.node_offset.x, sema.gpa, decl, total_i, bound_arg_src),
   6854                         uncasted_args[total_i],
   6855                         comptime_args[total_i],
   6856                         runtime_args,
   6857                         new_fn_info,
   6858                         &runtime_i,
   6859                     );
   6860                     return error.AnalysisFail;
   6861                 },
   6862                 else => |e| return e,
   6863             };
   6864             total_i += 1;
   6865         }
   6866 
   6867         try sema.queueFullTypeResolution(new_fn_info.return_type);
   6868     }
   6869 
   6870     if (sema.owner_func != null and new_fn_info.return_type.isError()) {
   6871         sema.owner_func.?.calls_or_awaits_errorable_fn = true;
   6872     }
   6873 
   6874     try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
   6875         runtime_args_len);
   6876     const result = try block.addInst(.{
   6877         .tag = call_tag,
   6878         .data = .{ .pl_op = .{
   6879             .operand = callee_inst,
   6880             .payload = sema.addExtraAssumeCapacity(Air.Call{
   6881                 .args_len = runtime_args_len,
   6882             }),
   6883         } },
   6884     });
   6885     sema.appendRefsAssumeCapacity(runtime_args);
   6886 
   6887     if (ensure_result_used) {
   6888         try sema.ensureResultUsed(block, result, call_src);
   6889     }
   6890     if (call_tag == .call_always_tail) {
   6891         return sema.handleTailCall(block, call_src, func_ty, result);
   6892     }
   6893     return result;
   6894 }
   6895 
   6896 fn emitDbgInline(
   6897     sema: *Sema,
   6898     block: *Block,
   6899     old_func: *Module.Fn,
   6900     new_func: *Module.Fn,
   6901     new_func_ty: Type,
   6902     tag: Air.Inst.Tag,
   6903 ) CompileError!void {
   6904     if (sema.mod.comp.bin_file.options.strip) return;
   6905 
   6906     // Recursive inline call; no dbg_inline needed.
   6907     if (old_func == new_func) return;
   6908 
   6909     try sema.air_values.append(sema.gpa, try Value.Tag.function.create(sema.arena, new_func));
   6910     _ = try block.addInst(.{
   6911         .tag = tag,
   6912         .data = .{ .ty_pl = .{
   6913             .ty = try sema.addType(new_func_ty),
   6914             .payload = @intCast(u32, sema.air_values.items.len - 1),
   6915         } },
   6916     });
   6917 }
   6918 
   6919 fn zirIntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   6920     _ = block;
   6921     const tracy = trace(@src());
   6922     defer tracy.end();
   6923 
   6924     const int_type = sema.code.instructions.items(.data)[inst].int_type;
   6925     const ty = try Module.makeIntType(sema.arena, int_type.signedness, int_type.bit_count);
   6926 
   6927     return sema.addType(ty);
   6928 }
   6929 
   6930 fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   6931     const tracy = trace(@src());
   6932     defer tracy.end();
   6933 
   6934     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   6935     const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
   6936     const child_type = try sema.resolveType(block, operand_src, inst_data.operand);
   6937     if (child_type.zigTypeTag() == .Opaque) {
   6938         return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(sema.mod)});
   6939     } else if (child_type.zigTypeTag() == .Null) {
   6940         return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(sema.mod)});
   6941     }
   6942     const opt_type = try Type.optional(sema.arena, child_type);
   6943 
   6944     return sema.addType(opt_type);
   6945 }
   6946 
   6947 fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   6948     const bin = sema.code.instructions.items(.data)[inst].bin;
   6949     const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs);
   6950     assert(indexable_ty.isIndexable()); // validated by a previous instruction
   6951     if (indexable_ty.zigTypeTag() == .Struct) {
   6952         const elem_type = indexable_ty.tupleFields().types[@enumToInt(bin.rhs)];
   6953         return sema.addType(elem_type);
   6954     } else {
   6955         const elem_type = indexable_ty.elemType2();
   6956         return sema.addType(elem_type);
   6957     }
   6958 }
   6959 
   6960 fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   6961     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   6962     const elem_type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   6963     const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   6964     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   6965     const len = try sema.resolveInt(block, len_src, extra.lhs, Type.u32, "vector length must be comptime known");
   6966     const elem_type = try sema.resolveType(block, elem_type_src, extra.rhs);
   6967     try sema.checkVectorElemType(block, elem_type_src, elem_type);
   6968     const vector_type = try Type.Tag.vector.create(sema.arena, .{
   6969         .len = @intCast(u32, len),
   6970         .elem_type = elem_type,
   6971     });
   6972     return sema.addType(vector_type);
   6973 }
   6974 
   6975 fn zirArrayType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   6976     const tracy = trace(@src());
   6977     defer tracy.end();
   6978 
   6979     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   6980     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   6981     const len_src: LazySrcLoc = .{ .node_offset_array_type_len = inst_data.src_node };
   6982     const elem_src: LazySrcLoc = .{ .node_offset_array_type_elem = inst_data.src_node };
   6983     const len = try sema.resolveInt(block, len_src, extra.lhs, Type.usize, "array length must be comptime known");
   6984     const elem_type = try sema.resolveType(block, elem_src, extra.rhs);
   6985     const array_ty = try Type.array(sema.arena, len, null, elem_type, sema.mod);
   6986 
   6987     return sema.addType(array_ty);
   6988 }
   6989 
   6990 fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   6991     const tracy = trace(@src());
   6992     defer tracy.end();
   6993 
   6994     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   6995     const extra = sema.code.extraData(Zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data;
   6996     const len_src: LazySrcLoc = .{ .node_offset_array_type_len = inst_data.src_node };
   6997     const sentinel_src: LazySrcLoc = .{ .node_offset_array_type_sentinel = inst_data.src_node };
   6998     const elem_src: LazySrcLoc = .{ .node_offset_array_type_elem = inst_data.src_node };
   6999     const len = try sema.resolveInt(block, len_src, extra.len, Type.usize, "array length must be comptime known");
   7000     const elem_type = try sema.resolveType(block, elem_src, extra.elem_type);
   7001     const uncasted_sentinel = try sema.resolveInst(extra.sentinel);
   7002     const sentinel = try sema.coerce(block, elem_type, uncasted_sentinel, sentinel_src);
   7003     const sentinel_val = try sema.resolveConstValue(block, sentinel_src, sentinel, "array sentinel value must be comptime known");
   7004     const array_ty = try Type.array(sema.arena, len, sentinel_val, elem_type, sema.mod);
   7005 
   7006     return sema.addType(array_ty);
   7007 }
   7008 
   7009 fn zirAnyframeType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   7010     const tracy = trace(@src());
   7011     defer tracy.end();
   7012 
   7013     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   7014     if (true) {
   7015         return sema.failWithUseOfAsync(block, inst_data.src());
   7016     }
   7017     const operand_src: LazySrcLoc = .{ .node_offset_anyframe_type = inst_data.src_node };
   7018     const return_type = try sema.resolveType(block, operand_src, inst_data.operand);
   7019     const anyframe_type = try Type.Tag.anyframe_T.create(sema.arena, return_type);
   7020 
   7021     return sema.addType(anyframe_type);
   7022 }
   7023 
   7024 fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   7025     const tracy = trace(@src());
   7026     defer tracy.end();
   7027 
   7028     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   7029     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   7030     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   7031     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
   7032     const error_set = try sema.resolveType(block, lhs_src, extra.lhs);
   7033     const payload = try sema.resolveType(block, rhs_src, extra.rhs);
   7034 
   7035     if (error_set.zigTypeTag() != .ErrorSet) {
   7036         return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{
   7037             error_set.fmt(sema.mod),
   7038         });
   7039     }
   7040     if (payload.zigTypeTag() == .Opaque) {
   7041         return sema.fail(block, rhs_src, "error union with payload of opaque type '{}' not allowed", .{
   7042             payload.fmt(sema.mod),
   7043         });
   7044     } else if (payload.zigTypeTag() == .ErrorSet) {
   7045         return sema.fail(block, rhs_src, "error union with payload of error set type '{}' not allowed", .{
   7046             payload.fmt(sema.mod),
   7047         });
   7048     }
   7049     const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod);
   7050     return sema.addType(err_union_ty);
   7051 }
   7052 
   7053 fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   7054     _ = block;
   7055     const tracy = trace(@src());
   7056     defer tracy.end();
   7057 
   7058     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
   7059 
   7060     // Create an anonymous error set type with only this error value, and return the value.
   7061     const kv = try sema.mod.getErrorValue(inst_data.get(sema.code));
   7062     const result_type = try Type.Tag.error_set_single.create(sema.arena, kv.key);
   7063     return sema.addConstant(
   7064         result_type,
   7065         try Value.Tag.@"error".create(sema.arena, .{
   7066             .name = kv.key,
   7067         }),
   7068     );
   7069 }
   7070 
   7071 fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
   7072     const tracy = trace(@src());
   7073     defer tracy.end();
   7074 
   7075     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
   7076     const src = LazySrcLoc.nodeOffset(extra.node);
   7077     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
   7078     const uncasted_operand = try sema.resolveInst(extra.operand);
   7079     const operand = try sema.coerce(block, Type.anyerror, uncasted_operand, operand_src);
   7080 
   7081     if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {
   7082         if (val.isUndef()) {
   7083             return sema.addConstUndef(Type.err_int);
   7084         }
   7085         switch (val.tag()) {
   7086             .@"error" => {
   7087                 const payload = try sema.arena.create(Value.Payload.U64);
   7088                 payload.* = .{
   7089                     .base = .{ .tag = .int_u64 },
   7090                     .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value,
   7091                 };
   7092                 return sema.addConstant(Type.err_int, Value.initPayload(&payload.base));
   7093             },
   7094 
   7095             // This is not a valid combination with the type `anyerror`.
   7096             .the_only_possible_value => unreachable,
   7097 
   7098             // Assume it's already encoded as an integer.
   7099             else => return sema.addConstant(Type.err_int, val),
   7100         }
   7101     }
   7102 
   7103     const op_ty = sema.typeOf(uncasted_operand);
   7104     try sema.resolveInferredErrorSetTy(block, src, op_ty);
   7105     if (!op_ty.isAnyError()) {
   7106         const names = op_ty.errorSetNames();
   7107         switch (names.len) {
   7108             0 => return sema.addConstant(Type.err_int, Value.zero),
   7109             1 => return sema.addIntUnsigned(Type.err_int, sema.mod.global_error_set.get(names[0]).?),
   7110             else => {},
   7111         }
   7112     }
   7113 
   7114     try sema.requireRuntimeBlock(block, src, operand_src);
   7115     return block.addBitCast(Type.err_int, operand);
   7116 }
   7117 
   7118 fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
   7119     const tracy = trace(@src());
   7120     defer tracy.end();
   7121 
   7122     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
   7123     const src = LazySrcLoc.nodeOffset(extra.node);
   7124     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
   7125     const uncasted_operand = try sema.resolveInst(extra.operand);
   7126     const operand = try sema.coerce(block, Type.err_int, uncasted_operand, operand_src);
   7127     const target = sema.mod.getTarget();
   7128 
   7129     if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| {
   7130         const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(target));
   7131         if (int > sema.mod.global_error_set.count() or int == 0)
   7132             return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int});
   7133         const payload = try sema.arena.create(Value.Payload.Error);
   7134         payload.* = .{
   7135             .base = .{ .tag = .@"error" },
   7136             .data = .{ .name = sema.mod.error_name_list.items[int] },
   7137         };
   7138         return sema.addConstant(Type.anyerror, Value.initPayload(&payload.base));
   7139     }
   7140     try sema.requireRuntimeBlock(block, src, operand_src);
   7141     if (block.wantSafety()) {
   7142         const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand);
   7143         const zero_val = try sema.addConstant(Type.err_int, Value.zero);
   7144         const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val);
   7145         const ok = try block.addBinOp(.bit_and, is_lt_len, is_non_zero);
   7146         try sema.addSafetyCheck(block, ok, .invalid_error_code);
   7147     }
   7148     return block.addInst(.{
   7149         .tag = .bitcast,
   7150         .data = .{ .ty_op = .{
   7151             .ty = Air.Inst.Ref.anyerror_type,
   7152             .operand = operand,
   7153         } },
   7154     });
   7155 }
   7156 
   7157 fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   7158     const tracy = trace(@src());
   7159     defer tracy.end();
   7160 
   7161     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   7162     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   7163     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
   7164     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   7165     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
   7166     const lhs = try sema.resolveInst(extra.lhs);
   7167     const rhs = try sema.resolveInst(extra.rhs);
   7168     if (sema.typeOf(lhs).zigTypeTag() == .Bool and sema.typeOf(rhs).zigTypeTag() == .Bool) {
   7169         const msg = msg: {
   7170             const msg = try sema.errMsg(block, lhs_src, "expected error set type, found 'bool'", .{});
   7171             errdefer msg.destroy(sema.gpa);
   7172             try sema.errNote(block, src, msg, "'||' merges error sets; 'or' performs boolean OR", .{});
   7173             break :msg msg;
   7174         };
   7175         return sema.failWithOwnedErrorMsg(msg);
   7176     }
   7177     const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs);
   7178     const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs);
   7179     if (lhs_ty.zigTypeTag() != .ErrorSet)
   7180         return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{lhs_ty.fmt(sema.mod)});
   7181     if (rhs_ty.zigTypeTag() != .ErrorSet)
   7182         return sema.fail(block, rhs_src, "expected error set type, found '{}'", .{rhs_ty.fmt(sema.mod)});
   7183 
   7184     // Anything merged with anyerror is anyerror.
   7185     if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror) {
   7186         return Air.Inst.Ref.anyerror_type;
   7187     }
   7188 
   7189     if (lhs_ty.castTag(.error_set_inferred)) |payload| {
   7190         try sema.resolveInferredErrorSet(block, src, payload.data);
   7191         // isAnyError might have changed from a false negative to a true positive after resolution.
   7192         if (lhs_ty.isAnyError()) {
   7193             return Air.Inst.Ref.anyerror_type;
   7194         }
   7195     }
   7196     if (rhs_ty.castTag(.error_set_inferred)) |payload| {
   7197         try sema.resolveInferredErrorSet(block, src, payload.data);
   7198         // isAnyError might have changed from a false negative to a true positive after resolution.
   7199         if (rhs_ty.isAnyError()) {
   7200             return Air.Inst.Ref.anyerror_type;
   7201         }
   7202     }
   7203 
   7204     const err_set_ty = try lhs_ty.errorSetMerge(sema.arena, rhs_ty);
   7205     return sema.addType(err_set_ty);
   7206 }
   7207 
   7208 fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   7209     _ = block;
   7210     const tracy = trace(@src());
   7211     defer tracy.end();
   7212 
   7213     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
   7214     const duped_name = try sema.arena.dupe(u8, inst_data.get(sema.code));
   7215     return sema.addConstant(
   7216         Type.initTag(.enum_literal),
   7217         try Value.Tag.enum_literal.create(sema.arena, duped_name),
   7218     );
   7219 }
   7220 
   7221 fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   7222     const arena = sema.arena;
   7223     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   7224     const src = inst_data.src();
   7225     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   7226     const operand = try sema.resolveInst(inst_data.operand);
   7227     const operand_ty = sema.typeOf(operand);
   7228 
   7229     const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag()) {
   7230         .Enum => operand,
   7231         .Union => blk: {
   7232             const tag_ty = operand_ty.unionTagType() orelse {
   7233                 return sema.fail(
   7234                     block,
   7235                     operand_src,
   7236                     "untagged union '{}' cannot be converted to integer",
   7237                     .{src},
   7238                 );
   7239             };
   7240             break :blk try sema.unionToTag(block, tag_ty, operand, operand_src);
   7241         },
   7242         else => {
   7243             return sema.fail(block, operand_src, "expected enum or tagged union, found '{}'", .{
   7244                 operand_ty.fmt(sema.mod),
   7245             });
   7246         },
   7247     };
   7248     const enum_tag_ty = sema.typeOf(enum_tag);
   7249 
   7250     var int_tag_type_buffer: Type.Payload.Bits = undefined;
   7251     const int_tag_ty = try enum_tag_ty.intTagType(&int_tag_type_buffer).copy(arena);
   7252 
   7253     if (try sema.typeHasOnePossibleValue(block, src, enum_tag_ty)) |opv| {
   7254         return sema.addConstant(int_tag_ty, opv);
   7255     }
   7256 
   7257     if (try sema.resolveMaybeUndefVal(block, operand_src, enum_tag)) |enum_tag_val| {
   7258         var buffer: Value.Payload.U64 = undefined;
   7259         const val = enum_tag_val.enumToInt(enum_tag_ty, &buffer);
   7260         return sema.addConstant(int_tag_ty, try val.copy(sema.arena));
   7261     }
   7262 
   7263     try sema.requireRuntimeBlock(block, src, operand_src);
   7264     return block.addBitCast(int_tag_ty, enum_tag);
   7265 }
   7266 
   7267 fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   7268     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   7269     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   7270     const src = inst_data.src();
   7271     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   7272     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   7273     const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
   7274     const operand = try sema.resolveInst(extra.rhs);
   7275 
   7276     if (dest_ty.zigTypeTag() != .Enum) {
   7277         return sema.fail(block, dest_ty_src, "expected enum, found '{}'", .{dest_ty.fmt(sema.mod)});
   7278     }
   7279     _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand));
   7280 
   7281     if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |int_val| {
   7282         if (dest_ty.isNonexhaustiveEnum()) {
   7283             return sema.addConstant(dest_ty, int_val);
   7284         }
   7285         if (int_val.isUndef()) {
   7286             return sema.failWithUseOfUndef(block, operand_src);
   7287         }
   7288         if (!(try sema.enumHasInt(block, src, dest_ty, int_val))) {
   7289             const msg = msg: {
   7290                 const msg = try sema.errMsg(
   7291                     block,
   7292                     src,
   7293                     "enum '{}' has no tag with value '{}'",
   7294                     .{ dest_ty.fmt(sema.mod), int_val.fmtValue(sema.typeOf(operand), sema.mod) },
   7295                 );
   7296                 errdefer msg.destroy(sema.gpa);
   7297                 try sema.addDeclaredHereNote(msg, dest_ty);
   7298                 break :msg msg;
   7299             };
   7300             return sema.failWithOwnedErrorMsg(msg);
   7301         }
   7302         return sema.addConstant(dest_ty, int_val);
   7303     }
   7304 
   7305     try sema.requireRuntimeBlock(block, src, operand_src);
   7306     const result = try block.addTyOp(.intcast, dest_ty, operand);
   7307     if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum() and sema.mod.comp.bin_file.options.use_llvm) {
   7308         const ok = try block.addUnOp(.is_named_enum_value, result);
   7309         try sema.addSafetyCheck(block, ok, .invalid_enum_value);
   7310     }
   7311     return result;
   7312 }
   7313 
   7314 /// Pointer in, pointer out.
   7315 fn zirOptionalPayloadPtr(
   7316     sema: *Sema,
   7317     block: *Block,
   7318     inst: Zir.Inst.Index,
   7319     safety_check: bool,
   7320 ) CompileError!Air.Inst.Ref {
   7321     const tracy = trace(@src());
   7322     defer tracy.end();
   7323 
   7324     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   7325     const optional_ptr = try sema.resolveInst(inst_data.operand);
   7326     const src = inst_data.src();
   7327 
   7328     return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false);
   7329 }
   7330 
   7331 fn analyzeOptionalPayloadPtr(
   7332     sema: *Sema,
   7333     block: *Block,
   7334     src: LazySrcLoc,
   7335     optional_ptr: Air.Inst.Ref,
   7336     safety_check: bool,
   7337     initializing: bool,
   7338 ) CompileError!Air.Inst.Ref {
   7339     const optional_ptr_ty = sema.typeOf(optional_ptr);
   7340     assert(optional_ptr_ty.zigTypeTag() == .Pointer);
   7341 
   7342     const opt_type = optional_ptr_ty.elemType();
   7343     if (opt_type.zigTypeTag() != .Optional) {
   7344         return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(sema.mod)});
   7345     }
   7346 
   7347     const child_type = try opt_type.optionalChildAlloc(sema.arena);
   7348     const child_pointer = try Type.ptr(sema.arena, sema.mod, .{
   7349         .pointee_type = child_type,
   7350         .mutable = !optional_ptr_ty.isConstPtr(),
   7351         .@"addrspace" = optional_ptr_ty.ptrAddressSpace(),
   7352     });
   7353 
   7354     if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| {
   7355         if (initializing) {
   7356             if (!ptr_val.isComptimeMutablePtr()) {
   7357                 // If the pointer resulting from this function was stored at comptime,
   7358                 // the optional non-null bit would be set that way. But in this case,
   7359                 // we need to emit a runtime instruction to do it.
   7360                 try sema.requireFunctionBlock(block, src);
   7361                 _ = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);
   7362             }
   7363             return sema.addConstant(
   7364                 child_pointer,
   7365                 try Value.Tag.opt_payload_ptr.create(sema.arena, .{
   7366                     .container_ptr = ptr_val,
   7367                     .container_ty = optional_ptr_ty.childType(),
   7368                 }),
   7369             );
   7370         }
   7371         if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| {
   7372             if (val.isNull()) {
   7373                 return sema.fail(block, src, "unable to unwrap null", .{});
   7374             }
   7375             // The same Value represents the pointer to the optional and the payload.
   7376             return sema.addConstant(
   7377                 child_pointer,
   7378                 try Value.Tag.opt_payload_ptr.create(sema.arena, .{
   7379                     .container_ptr = ptr_val,
   7380                     .container_ty = optional_ptr_ty.childType(),
   7381                 }),
   7382             );
   7383         }
   7384     }
   7385 
   7386     try sema.requireRuntimeBlock(block, src, null);
   7387     if (safety_check and block.wantSafety()) {
   7388         const is_non_null = try block.addUnOp(.is_non_null_ptr, optional_ptr);
   7389         try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
   7390     }
   7391     const air_tag: Air.Inst.Tag = if (initializing)
   7392         .optional_payload_ptr_set
   7393     else
   7394         .optional_payload_ptr;
   7395     return block.addTyOp(air_tag, child_pointer, optional_ptr);
   7396 }
   7397 
   7398 /// Value in, value out.
   7399 fn zirOptionalPayload(
   7400     sema: *Sema,
   7401     block: *Block,
   7402     inst: Zir.Inst.Index,
   7403     safety_check: bool,
   7404 ) CompileError!Air.Inst.Ref {
   7405     const tracy = trace(@src());
   7406     defer tracy.end();
   7407 
   7408     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   7409     const src = inst_data.src();
   7410     const operand = try sema.resolveInst(inst_data.operand);
   7411     const operand_ty = sema.typeOf(operand);
   7412     const result_ty = switch (operand_ty.zigTypeTag()) {
   7413         .Optional => try operand_ty.optionalChildAlloc(sema.arena),
   7414         .Pointer => t: {
   7415             if (operand_ty.ptrSize() != .C) {
   7416                 return sema.failWithExpectedOptionalType(block, src, operand_ty);
   7417             }
   7418             // TODO https://github.com/ziglang/zig/issues/6597
   7419             if (true) break :t operand_ty;
   7420             const ptr_info = operand_ty.ptrInfo().data;
   7421             break :t try Type.ptr(sema.arena, sema.mod, .{
   7422                 .pointee_type = try ptr_info.pointee_type.copy(sema.arena),
   7423                 .@"align" = ptr_info.@"align",
   7424                 .@"addrspace" = ptr_info.@"addrspace",
   7425                 .mutable = ptr_info.mutable,
   7426                 .@"allowzero" = ptr_info.@"allowzero",
   7427                 .@"volatile" = ptr_info.@"volatile",
   7428                 .size = .One,
   7429             });
   7430         },
   7431         else => return sema.failWithExpectedOptionalType(block, src, operand_ty),
   7432     };
   7433 
   7434     if (try sema.resolveDefinedValue(block, src, operand)) |val| {
   7435         if (val.isNull()) {
   7436             return sema.fail(block, src, "unable to unwrap null", .{});
   7437         }
   7438         if (val.castTag(.opt_payload)) |payload| {
   7439             return sema.addConstant(result_ty, payload.data);
   7440         }
   7441         return sema.addConstant(result_ty, val);
   7442     }
   7443 
   7444     try sema.requireRuntimeBlock(block, src, null);
   7445     if (safety_check and block.wantSafety()) {
   7446         const is_non_null = try block.addUnOp(.is_non_null, operand);
   7447         try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
   7448     }
   7449     return block.addTyOp(.optional_payload, result_ty, operand);
   7450 }
   7451 
   7452 /// Value in, value out
   7453 fn zirErrUnionPayload(
   7454     sema: *Sema,
   7455     block: *Block,
   7456     inst: Zir.Inst.Index,
   7457 ) CompileError!Air.Inst.Ref {
   7458     const tracy = trace(@src());
   7459     defer tracy.end();
   7460 
   7461     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   7462     const src = inst_data.src();
   7463     const operand = try sema.resolveInst(inst_data.operand);
   7464     const operand_src = src;
   7465     const err_union_ty = sema.typeOf(operand);
   7466     if (err_union_ty.zigTypeTag() != .ErrorUnion) {
   7467         return sema.fail(block, operand_src, "expected error union type, found '{}'", .{
   7468             err_union_ty.fmt(sema.mod),
   7469         });
   7470     }
   7471     return sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false);
   7472 }
   7473 
   7474 fn analyzeErrUnionPayload(
   7475     sema: *Sema,
   7476     block: *Block,
   7477     src: LazySrcLoc,
   7478     err_union_ty: Type,
   7479     operand: Zir.Inst.Ref,
   7480     operand_src: LazySrcLoc,
   7481     safety_check: bool,
   7482 ) CompileError!Air.Inst.Ref {
   7483     const payload_ty = err_union_ty.errorUnionPayload();
   7484     if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {
   7485         if (val.getError()) |name| {
   7486             return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
   7487         }
   7488         const data = val.castTag(.eu_payload).?.data;
   7489         return sema.addConstant(payload_ty, data);
   7490     }
   7491 
   7492     try sema.requireRuntimeBlock(block, src, null);
   7493 
   7494     // If the error set has no fields then no safety check is needed.
   7495     if (safety_check and block.wantSafety() and
   7496         !err_union_ty.errorUnionSet().errorSetIsEmpty())
   7497     {
   7498         try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err);
   7499     }
   7500 
   7501     return block.addTyOp(.unwrap_errunion_payload, payload_ty, operand);
   7502 }
   7503 
   7504 /// Pointer in, pointer out.
   7505 fn zirErrUnionPayloadPtr(
   7506     sema: *Sema,
   7507     block: *Block,
   7508     inst: Zir.Inst.Index,
   7509 ) CompileError!Air.Inst.Ref {
   7510     const tracy = trace(@src());
   7511     defer tracy.end();
   7512 
   7513     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   7514     const operand = try sema.resolveInst(inst_data.operand);
   7515     const src = inst_data.src();
   7516 
   7517     return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
   7518 }
   7519 
   7520 fn analyzeErrUnionPayloadPtr(
   7521     sema: *Sema,
   7522     block: *Block,
   7523     src: LazySrcLoc,
   7524     operand: Air.Inst.Ref,
   7525     safety_check: bool,
   7526     initializing: bool,
   7527 ) CompileError!Air.Inst.Ref {
   7528     const operand_ty = sema.typeOf(operand);
   7529     assert(operand_ty.zigTypeTag() == .Pointer);
   7530 
   7531     if (operand_ty.elemType().zigTypeTag() != .ErrorUnion) {
   7532         return sema.fail(block, src, "expected error union type, found '{}'", .{
   7533             operand_ty.elemType().fmt(sema.mod),
   7534         });
   7535     }
   7536 
   7537     const err_union_ty = operand_ty.elemType();
   7538     const payload_ty = err_union_ty.errorUnionPayload();
   7539     const operand_pointer_ty = try Type.ptr(sema.arena, sema.mod, .{
   7540         .pointee_type = payload_ty,
   7541         .mutable = !operand_ty.isConstPtr(),
   7542         .@"addrspace" = operand_ty.ptrAddressSpace(),
   7543     });
   7544 
   7545     if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| {
   7546         if (initializing) {
   7547             if (!ptr_val.isComptimeMutablePtr()) {
   7548                 // If the pointer resulting from this function was stored at comptime,
   7549                 // the error union error code would be set that way. But in this case,
   7550                 // we need to emit a runtime instruction to do it.
   7551                 try sema.requireRuntimeBlock(block, src, null);
   7552                 _ = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand);
   7553             }
   7554             return sema.addConstant(
   7555                 operand_pointer_ty,
   7556                 try Value.Tag.eu_payload_ptr.create(sema.arena, .{
   7557                     .container_ptr = ptr_val,
   7558                     .container_ty = operand_ty.elemType(),
   7559                 }),
   7560             );
   7561         }
   7562         if (try sema.pointerDeref(block, src, ptr_val, operand_ty)) |val| {
   7563             if (val.getError()) |name| {
   7564                 return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
   7565             }
   7566 
   7567             return sema.addConstant(
   7568                 operand_pointer_ty,
   7569                 try Value.Tag.eu_payload_ptr.create(sema.arena, .{
   7570                     .container_ptr = ptr_val,
   7571                     .container_ty = operand_ty.elemType(),
   7572                 }),
   7573             );
   7574         }
   7575     }
   7576 
   7577     try sema.requireRuntimeBlock(block, src, null);
   7578 
   7579     // If the error set has no fields then no safety check is needed.
   7580     if (safety_check and block.wantSafety() and
   7581         !err_union_ty.errorUnionSet().errorSetIsEmpty())
   7582     {
   7583         try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);
   7584     }
   7585 
   7586     const air_tag: Air.Inst.Tag = if (initializing)
   7587         .errunion_payload_ptr_set
   7588     else
   7589         .unwrap_errunion_payload_ptr;
   7590     return block.addTyOp(air_tag, operand_pointer_ty, operand);
   7591 }
   7592 
   7593 /// Value in, value out
   7594 fn zirErrUnionCode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   7595     const tracy = trace(@src());
   7596     defer tracy.end();
   7597 
   7598     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   7599     const src = inst_data.src();
   7600     const operand = try sema.resolveInst(inst_data.operand);
   7601     const operand_ty = sema.typeOf(operand);
   7602     if (operand_ty.zigTypeTag() != .ErrorUnion) {
   7603         return sema.fail(block, src, "expected error union type, found '{}'", .{
   7604             operand_ty.fmt(sema.mod),
   7605         });
   7606     }
   7607 
   7608     const result_ty = operand_ty.errorUnionSet();
   7609 
   7610     if (try sema.resolveDefinedValue(block, src, operand)) |val| {
   7611         assert(val.getError() != null);
   7612         return sema.addConstant(result_ty, val);
   7613     }
   7614 
   7615     try sema.requireRuntimeBlock(block, src, null);
   7616     return block.addTyOp(.unwrap_errunion_err, result_ty, operand);
   7617 }
   7618 
   7619 /// Pointer in, value out
   7620 fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   7621     const tracy = trace(@src());
   7622     defer tracy.end();
   7623 
   7624     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   7625     const src = inst_data.src();
   7626     const operand = try sema.resolveInst(inst_data.operand);
   7627     const operand_ty = sema.typeOf(operand);
   7628     assert(operand_ty.zigTypeTag() == .Pointer);
   7629 
   7630     if (operand_ty.elemType().zigTypeTag() != .ErrorUnion) {
   7631         return sema.fail(block, src, "expected error union type, found '{}'", .{
   7632             operand_ty.elemType().fmt(sema.mod),
   7633         });
   7634     }
   7635 
   7636     const result_ty = operand_ty.elemType().errorUnionSet();
   7637 
   7638     if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {
   7639         if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| {
   7640             assert(val.getError() != null);
   7641             return sema.addConstant(result_ty, val);
   7642         }
   7643     }
   7644 
   7645     try sema.requireRuntimeBlock(block, src, null);
   7646     return block.addTyOp(.unwrap_errunion_err_ptr, result_ty, operand);
   7647 }
   7648 
   7649 fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   7650     const tracy = trace(@src());
   7651     defer tracy.end();
   7652 
   7653     const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
   7654     const src = inst_data.src();
   7655     const operand = try sema.resolveInst(inst_data.operand);
   7656     const operand_ty = sema.typeOf(operand);
   7657     if (operand_ty.zigTypeTag() != .ErrorUnion) {
   7658         return sema.fail(block, src, "expected error union type, found '{}'", .{
   7659             operand_ty.fmt(sema.mod),
   7660         });
   7661     }
   7662     if (operand_ty.errorUnionPayload().zigTypeTag() != .Void) {
   7663         return sema.fail(block, src, "expression value is ignored", .{});
   7664     }
   7665 }
   7666 
   7667 fn zirFunc(
   7668     sema: *Sema,
   7669     block: *Block,
   7670     inst: Zir.Inst.Index,
   7671     inferred_error_set: bool,
   7672 ) CompileError!Air.Inst.Ref {
   7673     const tracy = trace(@src());
   7674     defer tracy.end();
   7675 
   7676     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   7677     const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
   7678     const target = sema.mod.getTarget();
   7679     const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = inst_data.src_node };
   7680 
   7681     var extra_index = extra.end;
   7682 
   7683     const ret_ty: Type = switch (extra.data.ret_body_len) {
   7684         0 => Type.void,
   7685         1 => blk: {
   7686             const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   7687             extra_index += 1;
   7688             if (sema.resolveType(block, ret_ty_src, ret_ty_ref)) |ret_ty| {
   7689                 break :blk ret_ty;
   7690             } else |err| switch (err) {
   7691                 error.GenericPoison => {
   7692                     break :blk Type.initTag(.generic_poison);
   7693                 },
   7694                 else => |e| return e,
   7695             }
   7696         },
   7697         else => blk: {
   7698             const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
   7699             extra_index += ret_ty_body.len;
   7700 
   7701             const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type, "return type must be comptime known");
   7702             var buffer: Value.ToTypeBuffer = undefined;
   7703             break :blk try ret_ty_val.toType(&buffer).copy(sema.arena);
   7704         },
   7705     };
   7706 
   7707     var src_locs: Zir.Inst.Func.SrcLocs = undefined;
   7708     const has_body = extra.data.body_len != 0;
   7709     if (has_body) {
   7710         extra_index += extra.data.body_len;
   7711         src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
   7712     }
   7713 
   7714     // If this instruction has a body it means it's the type of the `owner_decl`
   7715     // otherwise it's a function type without a `callconv` attribute and should
   7716     // never be `.C`.
   7717     // NOTE: revisit when doing #1717
   7718     const cc: std.builtin.CallingConvention = if (sema.owner_decl.is_exported and has_body)
   7719         .C
   7720     else
   7721         .Unspecified;
   7722 
   7723     return sema.funcCommon(
   7724         block,
   7725         inst_data.src_node,
   7726         inst,
   7727         0,
   7728         target_util.defaultAddressSpace(target, .function),
   7729         FuncLinkSection.default,
   7730         cc,
   7731         ret_ty,
   7732         false,
   7733         inferred_error_set,
   7734         false,
   7735         has_body,
   7736         src_locs,
   7737         null,
   7738         0,
   7739         false,
   7740     );
   7741 }
   7742 
   7743 fn resolveGenericBody(
   7744     sema: *Sema,
   7745     block: *Block,
   7746     src: LazySrcLoc,
   7747     body: []const Zir.Inst.Index,
   7748     func_inst: Zir.Inst.Index,
   7749     dest_ty: Type,
   7750     reason: []const u8,
   7751 ) !Value {
   7752     assert(body.len != 0);
   7753 
   7754     const err = err: {
   7755         // Make sure any nested param instructions don't clobber our work.
   7756         const prev_params = block.params;
   7757         block.params = .{};
   7758         defer {
   7759             block.params.deinit(sema.gpa);
   7760             block.params = prev_params;
   7761         }
   7762         const uncasted = sema.resolveBody(block, body, func_inst) catch |err| break :err err;
   7763         const result = sema.coerce(block, dest_ty, uncasted, src) catch |err| break :err err;
   7764         const val = sema.resolveConstValue(block, src, result, reason) catch |err| break :err err;
   7765         return val;
   7766     };
   7767     switch (err) {
   7768         error.GenericPoison => {
   7769             if (dest_ty.tag() == .type) {
   7770                 return Value.initTag(.generic_poison_type);
   7771             } else {
   7772                 return Value.initTag(.generic_poison);
   7773             }
   7774         },
   7775         else => |e| return e,
   7776     }
   7777 }
   7778 
   7779 /// Given a library name, examines if the library name should end up in
   7780 /// `link.File.Options.system_libs` table (for example, libc is always
   7781 /// specified via dedicated flag `link.File.Options.link_libc` instead),
   7782 /// and puts it there if it doesn't exist.
   7783 /// It also dupes the library name which can then be saved as part of the
   7784 /// respective `Decl` (either `ExternFn` or `Var`).
   7785 /// The liveness of the duped library name is tied to liveness of `Module`.
   7786 /// To deallocate, call `deinit` on the respective `Decl` (`ExternFn` or `Var`).
   7787 fn handleExternLibName(
   7788     sema: *Sema,
   7789     block: *Block,
   7790     src_loc: LazySrcLoc,
   7791     lib_name: []const u8,
   7792 ) CompileError![:0]u8 {
   7793     blk: {
   7794         const mod = sema.mod;
   7795         const comp = mod.comp;
   7796         const target = mod.getTarget();
   7797         log.debug("extern fn symbol expected in lib '{s}'", .{lib_name});
   7798         if (target_util.is_libc_lib_name(target, lib_name)) {
   7799             if (!comp.bin_file.options.link_libc and !comp.bin_file.options.parent_compilation_link_libc) {
   7800                 return sema.fail(
   7801                     block,
   7802                     src_loc,
   7803                     "dependency on libc must be explicitly specified in the build command",
   7804                     .{},
   7805                 );
   7806             }
   7807             comp.bin_file.options.link_libc = true;
   7808             break :blk;
   7809         }
   7810         if (target_util.is_libcpp_lib_name(target, lib_name)) {
   7811             if (!comp.bin_file.options.link_libcpp) {
   7812                 return sema.fail(
   7813                     block,
   7814                     src_loc,
   7815                     "dependency on libc++ must be explicitly specified in the build command",
   7816                     .{},
   7817                 );
   7818             }
   7819             comp.bin_file.options.link_libcpp = true;
   7820             break :blk;
   7821         }
   7822         if (mem.eql(u8, lib_name, "unwind")) {
   7823             comp.bin_file.options.link_libunwind = true;
   7824             break :blk;
   7825         }
   7826         if (!target.isWasm() and !comp.bin_file.options.pic) {
   7827             return sema.fail(
   7828                 block,
   7829                 src_loc,
   7830                 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
   7831                 .{ lib_name, lib_name },
   7832             );
   7833         }
   7834         comp.stage1AddLinkLib(lib_name) catch |err| {
   7835             return sema.fail(block, src_loc, "unable to add link lib '{s}': {s}", .{
   7836                 lib_name, @errorName(err),
   7837             });
   7838         };
   7839     }
   7840     return sema.gpa.dupeZ(u8, lib_name);
   7841 }
   7842 
   7843 const FuncLinkSection = union(enum) {
   7844     generic,
   7845     default,
   7846     explicit: [*:0]const u8,
   7847 };
   7848 
   7849 fn funcCommon(
   7850     sema: *Sema,
   7851     block: *Block,
   7852     src_node_offset: i32,
   7853     func_inst: Zir.Inst.Index,
   7854     /// null means generic poison
   7855     alignment: ?u32,
   7856     /// null means generic poison
   7857     address_space: ?std.builtin.AddressSpace,
   7858     /// outer null means generic poison; inner null means default link section
   7859     section: FuncLinkSection,
   7860     /// null means generic poison
   7861     cc: ?std.builtin.CallingConvention,
   7862     /// this might be Type.generic_poison
   7863     bare_return_type: Type,
   7864     var_args: bool,
   7865     inferred_error_set: bool,
   7866     is_extern: bool,
   7867     has_body: bool,
   7868     src_locs: Zir.Inst.Func.SrcLocs,
   7869     opt_lib_name: ?[]const u8,
   7870     noalias_bits: u32,
   7871     is_noinline: bool,
   7872 ) CompileError!Air.Inst.Ref {
   7873     const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
   7874     const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset };
   7875 
   7876     var is_generic = bare_return_type.tag() == .generic_poison or
   7877         alignment == null or
   7878         address_space == null or
   7879         section == .generic or
   7880         cc == null;
   7881 
   7882     var destroy_fn_on_error = false;
   7883     const new_func: *Module.Fn = new_func: {
   7884         if (!has_body) break :new_func undefined;
   7885         if (sema.comptime_args_fn_inst == func_inst) {
   7886             const new_func = sema.preallocated_new_func.?;
   7887             sema.preallocated_new_func = null; // take ownership
   7888             break :new_func new_func;
   7889         }
   7890         destroy_fn_on_error = true;
   7891         const new_func = try sema.gpa.create(Module.Fn);
   7892         // Set this here so that the inferred return type can be printed correctly if it appears in an error.
   7893         new_func.owner_decl = sema.owner_decl_index;
   7894         break :new_func new_func;
   7895     };
   7896     errdefer if (destroy_fn_on_error) sema.gpa.destroy(new_func);
   7897 
   7898     var maybe_inferred_error_set_node: ?*Module.Fn.InferredErrorSetListNode = null;
   7899     errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node);
   7900     // Note: no need to errdefer since this will still be in its default state at the end of the function.
   7901 
   7902     const target = sema.mod.getTarget();
   7903     const fn_ty: Type = fn_ty: {
   7904         // Hot path for some common function types.
   7905         // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.
   7906         if (!is_generic and block.params.items.len == 0 and !var_args and !inferred_error_set and
   7907             alignment.? == 0 and
   7908             address_space.? == target_util.defaultAddressSpace(target, .function) and
   7909             section == .default)
   7910         {
   7911             if (bare_return_type.zigTypeTag() == .NoReturn and cc.? == .Unspecified) {
   7912                 break :fn_ty Type.initTag(.fn_noreturn_no_args);
   7913             }
   7914 
   7915             if (bare_return_type.zigTypeTag() == .Void and cc.? == .Unspecified) {
   7916                 break :fn_ty Type.initTag(.fn_void_no_args);
   7917             }
   7918 
   7919             if (bare_return_type.zigTypeTag() == .NoReturn and cc.? == .Naked) {
   7920                 break :fn_ty Type.initTag(.fn_naked_noreturn_no_args);
   7921             }
   7922 
   7923             if (bare_return_type.zigTypeTag() == .Void and cc.? == .C) {
   7924                 break :fn_ty Type.initTag(.fn_ccc_void_no_args);
   7925             }
   7926         }
   7927 
   7928         // These locals are pulled out from the init expression below to work around
   7929         // a stage1 compiler bug.
   7930         // In the case of generic calling convention, or generic alignment, we use
   7931         // default values which are only meaningful for the generic function, *not*
   7932         // the instantiation, which can depend on comptime parameters.
   7933         // Related proposal: https://github.com/ziglang/zig/issues/11834
   7934         const cc_workaround = cc orelse .Unspecified;
   7935         const align_workaround = alignment orelse 0;
   7936 
   7937         const param_types = try sema.arena.alloc(Type, block.params.items.len);
   7938         const comptime_params = try sema.arena.alloc(bool, block.params.items.len);
   7939         for (block.params.items) |param, i| {
   7940             param_types[i] = param.ty;
   7941             sema.analyzeParameter(
   7942                 block,
   7943                 .unneeded,
   7944                 param,
   7945                 comptime_params,
   7946                 i,
   7947                 &is_generic,
   7948                 cc_workaround,
   7949                 has_body,
   7950             ) catch |err| switch (err) {
   7951                 error.NeededSourceLocation => {
   7952                     const decl = sema.mod.declPtr(block.src_decl);
   7953                     try sema.analyzeParameter(
   7954                         block,
   7955                         Module.paramSrc(src_node_offset, sema.gpa, decl, i),
   7956                         param,
   7957                         comptime_params,
   7958                         i,
   7959                         &is_generic,
   7960                         cc_workaround,
   7961                         has_body,
   7962                     );
   7963                     return error.AnalysisFail;
   7964                 },
   7965                 else => |e| return e,
   7966             };
   7967         }
   7968 
   7969         var ret_ty_requires_comptime = false;
   7970         const ret_poison = if (sema.typeRequiresComptime(bare_return_type)) |ret_comptime| rp: {
   7971             ret_ty_requires_comptime = ret_comptime;
   7972             break :rp bare_return_type.tag() == .generic_poison;
   7973         } else |err| switch (err) {
   7974             error.GenericPoison => rp: {
   7975                 is_generic = true;
   7976                 break :rp true;
   7977             },
   7978             else => |e| return e,
   7979         };
   7980 
   7981         const return_type = if (!inferred_error_set or ret_poison)
   7982             bare_return_type
   7983         else blk: {
   7984             const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode);
   7985             node.data = .{ .func = new_func };
   7986             maybe_inferred_error_set_node = node;
   7987 
   7988             const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data);
   7989             break :blk try Type.Tag.error_union.create(sema.arena, .{
   7990                 .error_set = error_set_ty,
   7991                 .payload = bare_return_type,
   7992             });
   7993         };
   7994 
   7995         if (!bare_return_type.isValidReturnType()) {
   7996             const opaque_str = if (bare_return_type.zigTypeTag() == .Opaque) "opaque " else "";
   7997             const msg = msg: {
   7998                 const msg = try sema.errMsg(block, ret_ty_src, "{s}return type '{}' not allowed", .{
   7999                     opaque_str, bare_return_type.fmt(sema.mod),
   8000                 });
   8001                 errdefer msg.destroy(sema.gpa);
   8002 
   8003                 try sema.addDeclaredHereNote(msg, bare_return_type);
   8004                 break :msg msg;
   8005             };
   8006             return sema.failWithOwnedErrorMsg(msg);
   8007         }
   8008         if (!Type.fnCallingConventionAllowsZigTypes(cc_workaround) and !try sema.validateExternType(block, ret_ty_src, return_type, .ret_ty)) {
   8009             const msg = msg: {
   8010                 const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{
   8011                     return_type.fmt(sema.mod), @tagName(cc_workaround),
   8012                 });
   8013                 errdefer msg.destroy(sema.gpa);
   8014 
   8015                 const src_decl = sema.mod.declPtr(block.src_decl);
   8016                 try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl), return_type, .ret_ty);
   8017 
   8018                 try sema.addDeclaredHereNote(msg, return_type);
   8019                 break :msg msg;
   8020             };
   8021             return sema.failWithOwnedErrorMsg(msg);
   8022         }
   8023 
   8024         // If the return type is comptime only but not dependent on parameters then all parameter types also need to be comptime
   8025         if (!sema.is_generic_instantiation and has_body and ret_ty_requires_comptime) comptime_check: {
   8026             for (block.params.items) |param| {
   8027                 if (!param.is_comptime) break;
   8028             } else break :comptime_check;
   8029 
   8030             const msg = try sema.errMsg(
   8031                 block,
   8032                 ret_ty_src,
   8033                 "function with comptime only return type '{}' requires all parameters to be comptime",
   8034                 .{return_type.fmt(sema.mod)},
   8035             );
   8036             try sema.explainWhyTypeIsComptime(block, ret_ty_src, msg, ret_ty_src.toSrcLoc(sema.owner_decl), return_type);
   8037 
   8038             const tags = sema.code.instructions.items(.tag);
   8039             const data = sema.code.instructions.items(.data);
   8040             const param_body = sema.code.getParamBody(func_inst);
   8041             for (block.params.items) |param, i| {
   8042                 if (!param.is_comptime) {
   8043                     const param_index = param_body[i];
   8044                     const param_src = switch (tags[param_index]) {
   8045                         .param => data[param_index].pl_tok.src(),
   8046                         .param_anytype => data[param_index].str_tok.src(),
   8047                         else => unreachable,
   8048                     };
   8049                     if (param.name.len != 0) {
   8050                         try sema.errNote(block, param_src, msg, "param '{s}' is required to be comptime", .{param.name});
   8051                     } else {
   8052                         try sema.errNote(block, param_src, msg, "param is required to be comptime", .{});
   8053                     }
   8054                 }
   8055             }
   8056             return sema.failWithOwnedErrorMsg(msg);
   8057         }
   8058 
   8059         const arch = sema.mod.getTarget().cpu.arch;
   8060         if (switch (cc_workaround) {
   8061             .Unspecified, .C, .Naked, .Async, .Inline => null,
   8062             .Interrupt => switch (arch) {
   8063                 .i386, .x86_64, .avr, .msp430 => null,
   8064                 else => @as([]const u8, "i386, x86_64, AVR, and MSP430"),
   8065             },
   8066             .Signal => switch (arch) {
   8067                 .avr => null,
   8068                 else => @as([]const u8, "AVR"),
   8069             },
   8070             .Stdcall, .Fastcall, .Thiscall => switch (arch) {
   8071                 .i386 => null,
   8072                 else => @as([]const u8, "i386"),
   8073             },
   8074             .Vectorcall => switch (arch) {
   8075                 .i386, .aarch64, .aarch64_be, .aarch64_32 => null,
   8076                 else => @as([]const u8, "i386 and AArch64"),
   8077             },
   8078             .APCS, .AAPCS, .AAPCSVFP => switch (arch) {
   8079                 .arm, .armeb, .aarch64, .aarch64_be, .aarch64_32, .thumb, .thumbeb => null,
   8080                 else => @as([]const u8, "ARM"),
   8081             },
   8082             .SysV, .Win64 => switch (arch) {
   8083                 .x86_64 => null,
   8084                 else => @as([]const u8, "x86_64"),
   8085             },
   8086             .PtxKernel => switch (arch) {
   8087                 .nvptx, .nvptx64 => null,
   8088                 else => @as([]const u8, "nvptx and nvptx64"),
   8089             },
   8090         }) |allowed_platform| {
   8091             return sema.fail(block, cc_src, "callconv '{s}' is only available on {s}, not {s}", .{
   8092                 @tagName(cc_workaround),
   8093                 allowed_platform,
   8094                 @tagName(arch),
   8095             });
   8096         }
   8097 
   8098         if (cc_workaround == .Inline and is_noinline) {
   8099             return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
   8100         }
   8101         if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;
   8102         for (comptime_params) |ct| is_generic = is_generic or ct;
   8103         is_generic = is_generic or ret_ty_requires_comptime;
   8104 
   8105         break :fn_ty try Type.Tag.function.create(sema.arena, .{
   8106             .param_types = param_types,
   8107             .comptime_params = comptime_params.ptr,
   8108             .return_type = return_type,
   8109             .cc = cc_workaround,
   8110             .cc_is_generic = cc == null,
   8111             .alignment = align_workaround,
   8112             .align_is_generic = alignment == null,
   8113             .section_is_generic = section == .generic,
   8114             .addrspace_is_generic = address_space == null,
   8115             .is_var_args = var_args,
   8116             .is_generic = is_generic,
   8117             .noalias_bits = noalias_bits,
   8118         });
   8119     };
   8120 
   8121     if (sema.owner_decl.owns_tv) {
   8122         switch (section) {
   8123             .generic => sema.owner_decl.@"linksection" = undefined,
   8124             .default => sema.owner_decl.@"linksection" = null,
   8125             .explicit => |s| sema.owner_decl.@"linksection" = s,
   8126         }
   8127         if (alignment) |a| sema.owner_decl.@"align" = a;
   8128         if (address_space) |a| sema.owner_decl.@"addrspace" = a;
   8129     }
   8130 
   8131     if (is_extern) {
   8132         const new_extern_fn = try sema.gpa.create(Module.ExternFn);
   8133         errdefer sema.gpa.destroy(new_extern_fn);
   8134 
   8135         new_extern_fn.* = Module.ExternFn{
   8136             .owner_decl = sema.owner_decl_index,
   8137             .lib_name = null,
   8138         };
   8139 
   8140         if (opt_lib_name) |lib_name| {
   8141             new_extern_fn.lib_name = try sema.handleExternLibName(block, .{
   8142                 .node_offset_lib_name = src_node_offset,
   8143             }, lib_name);
   8144         }
   8145 
   8146         const extern_fn_payload = try sema.arena.create(Value.Payload.ExternFn);
   8147         extern_fn_payload.* = .{
   8148             .base = .{ .tag = .extern_fn },
   8149             .data = new_extern_fn,
   8150         };
   8151         return sema.addConstant(fn_ty, Value.initPayload(&extern_fn_payload.base));
   8152     }
   8153 
   8154     if (!has_body) {
   8155         return sema.addType(fn_ty);
   8156     }
   8157 
   8158     const is_inline = fn_ty.fnCallingConvention() == .Inline;
   8159     const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;
   8160 
   8161     const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == func_inst) blk: {
   8162         break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;
   8163     } else null;
   8164 
   8165     const hash = new_func.hash;
   8166     const generic_owner_decl = if (comptime_args == null) .none else new_func.generic_owner_decl;
   8167     const fn_payload = try sema.arena.create(Value.Payload.Function);
   8168     new_func.* = .{
   8169         .state = anal_state,
   8170         .zir_body_inst = func_inst,
   8171         .owner_decl = sema.owner_decl_index,
   8172         .generic_owner_decl = generic_owner_decl,
   8173         .comptime_args = comptime_args,
   8174         .hash = hash,
   8175         .lbrace_line = src_locs.lbrace_line,
   8176         .rbrace_line = src_locs.rbrace_line,
   8177         .lbrace_column = @truncate(u16, src_locs.columns),
   8178         .rbrace_column = @truncate(u16, src_locs.columns >> 16),
   8179         .branch_quota = default_branch_quota,
   8180         .is_noinline = is_noinline,
   8181     };
   8182     if (maybe_inferred_error_set_node) |node| {
   8183         new_func.inferred_error_sets.prepend(node);
   8184     }
   8185     maybe_inferred_error_set_node = null;
   8186     fn_payload.* = .{
   8187         .base = .{ .tag = .function },
   8188         .data = new_func,
   8189     };
   8190     return sema.addConstant(fn_ty, Value.initPayload(&fn_payload.base));
   8191 }
   8192 
   8193 fn analyzeParameter(
   8194     sema: *Sema,
   8195     block: *Block,
   8196     param_src: LazySrcLoc,
   8197     param: Block.Param,
   8198     comptime_params: []bool,
   8199     i: usize,
   8200     is_generic: *bool,
   8201     cc: std.builtin.CallingConvention,
   8202     has_body: bool,
   8203 ) !void {
   8204     const requires_comptime = try sema.typeRequiresComptime(param.ty);
   8205     comptime_params[i] = param.is_comptime or requires_comptime;
   8206     const this_generic = param.ty.tag() == .generic_poison;
   8207     is_generic.* = is_generic.* or this_generic;
   8208     if (param.is_comptime and !Type.fnCallingConventionAllowsZigTypes(cc)) {
   8209         return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
   8210     }
   8211     if (this_generic and !sema.no_partial_func_ty and !Type.fnCallingConventionAllowsZigTypes(cc)) {
   8212         return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
   8213     }
   8214     if (!param.ty.isValidParamType()) {
   8215         const opaque_str = if (param.ty.zigTypeTag() == .Opaque) "opaque " else "";
   8216         const msg = msg: {
   8217             const msg = try sema.errMsg(block, param_src, "parameter of {s}type '{}' not allowed", .{
   8218                 opaque_str, param.ty.fmt(sema.mod),
   8219             });
   8220             errdefer msg.destroy(sema.gpa);
   8221 
   8222             try sema.addDeclaredHereNote(msg, param.ty);
   8223             break :msg msg;
   8224         };
   8225         return sema.failWithOwnedErrorMsg(msg);
   8226     }
   8227     if (!this_generic and !Type.fnCallingConventionAllowsZigTypes(cc) and !try sema.validateExternType(block, param_src, param.ty, .param_ty)) {
   8228         const msg = msg: {
   8229             const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{
   8230                 param.ty.fmt(sema.mod), @tagName(cc),
   8231             });
   8232             errdefer msg.destroy(sema.gpa);
   8233 
   8234             const src_decl = sema.mod.declPtr(block.src_decl);
   8235             try sema.explainWhyTypeIsNotExtern(msg, param_src.toSrcLoc(src_decl), param.ty, .param_ty);
   8236 
   8237             try sema.addDeclaredHereNote(msg, param.ty);
   8238             break :msg msg;
   8239         };
   8240         return sema.failWithOwnedErrorMsg(msg);
   8241     }
   8242     if (!sema.is_generic_instantiation and requires_comptime and !param.is_comptime and has_body) {
   8243         const msg = msg: {
   8244             const msg = try sema.errMsg(block, param_src, "parameter of type '{}' must be declared comptime", .{
   8245                 param.ty.fmt(sema.mod),
   8246             });
   8247             errdefer msg.destroy(sema.gpa);
   8248 
   8249             try sema.addDeclaredHereNote(msg, param.ty);
   8250             break :msg msg;
   8251         };
   8252         return sema.failWithOwnedErrorMsg(msg);
   8253     }
   8254 }
   8255 
   8256 fn zirParam(
   8257     sema: *Sema,
   8258     block: *Block,
   8259     inst: Zir.Inst.Index,
   8260     comptime_syntax: bool,
   8261 ) CompileError!void {
   8262     const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
   8263     const src = inst_data.src();
   8264     const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);
   8265     const param_name = sema.code.nullTerminatedString(extra.data.name);
   8266     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
   8267 
   8268     // We could be in a generic function instantiation, or we could be evaluating a generic
   8269     // function without any comptime args provided.
   8270     const param_ty = param_ty: {
   8271         const err = err: {
   8272             // Make sure any nested param instructions don't clobber our work.
   8273             const prev_params = block.params;
   8274             const prev_preallocated_new_func = sema.preallocated_new_func;
   8275             const prev_no_partial_func_type = sema.no_partial_func_ty;
   8276             block.params = .{};
   8277             sema.preallocated_new_func = null;
   8278             sema.no_partial_func_ty = true;
   8279             defer {
   8280                 block.params.deinit(sema.gpa);
   8281                 block.params = prev_params;
   8282                 sema.preallocated_new_func = prev_preallocated_new_func;
   8283                 sema.no_partial_func_ty = prev_no_partial_func_type;
   8284             }
   8285 
   8286             if (sema.resolveBody(block, body, inst)) |param_ty_inst| {
   8287                 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| {
   8288                     break :param_ty param_ty;
   8289                 } else |err| break :err err;
   8290             } else |err| break :err err;
   8291         };
   8292         switch (err) {
   8293             error.GenericPoison => {
   8294                 // The type is not available until the generic instantiation.
   8295                 // We result the param instruction with a poison value and
   8296                 // insert an anytype parameter.
   8297                 try block.params.append(sema.gpa, .{
   8298                     .ty = Type.initTag(.generic_poison),
   8299                     .is_comptime = comptime_syntax,
   8300                     .name = param_name,
   8301                 });
   8302                 try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison);
   8303                 return;
   8304             },
   8305             else => |e| return e,
   8306         }
   8307     };
   8308     const is_comptime = sema.typeRequiresComptime(param_ty) catch |err| switch (err) {
   8309         error.GenericPoison => {
   8310             // The type is not available until the generic instantiation.
   8311             // We result the param instruction with a poison value and
   8312             // insert an anytype parameter.
   8313             try block.params.append(sema.gpa, .{
   8314                 .ty = Type.initTag(.generic_poison),
   8315                 .is_comptime = comptime_syntax,
   8316                 .name = param_name,
   8317             });
   8318             try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison);
   8319             return;
   8320         },
   8321         else => |e| return e,
   8322     } or comptime_syntax;
   8323     if (sema.inst_map.get(inst)) |arg| {
   8324         if (is_comptime) {
   8325             // We have a comptime value for this parameter so it should be elided from the
   8326             // function type of the function instruction in this block.
   8327             const coerced_arg = try sema.coerce(block, param_ty, arg, src);
   8328             sema.inst_map.putAssumeCapacity(inst, coerced_arg);
   8329             return;
   8330         }
   8331         // Even though a comptime argument is provided, the generic function wants to treat
   8332         // this as a runtime parameter.
   8333         assert(sema.inst_map.remove(inst));
   8334     }
   8335 
   8336     if (sema.preallocated_new_func != null) {
   8337         if (try sema.typeHasOnePossibleValue(block, src, param_ty)) |opv| {
   8338             // In this case we are instantiating a generic function call with a non-comptime
   8339             // non-anytype parameter that ended up being a one-possible-type.
   8340             // We don't want the parameter to be part of the instantiated function type.
   8341             const result = try sema.addConstant(param_ty, opv);
   8342             try sema.inst_map.put(sema.gpa, inst, result);
   8343             return;
   8344         }
   8345     }
   8346 
   8347     try block.params.append(sema.gpa, .{
   8348         .ty = param_ty,
   8349         .is_comptime = comptime_syntax,
   8350         .name = param_name,
   8351     });
   8352 
   8353     if (is_comptime) {
   8354         // If this is a comptime parameter we can add a constant generic_poison
   8355         // since this is also a generic parameter.
   8356         const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));
   8357         try sema.inst_map.putNoClobber(sema.gpa, inst, result);
   8358     } else {
   8359         // Otherwise we need a dummy runtime instruction.
   8360         const result_index = @intCast(Air.Inst.Index, sema.air_instructions.len);
   8361         try sema.air_instructions.append(sema.gpa, .{
   8362             .tag = .alloc,
   8363             .data = .{ .ty = param_ty },
   8364         });
   8365         const result = Air.indexToRef(result_index);
   8366         try sema.inst_map.putNoClobber(sema.gpa, inst, result);
   8367     }
   8368 }
   8369 
   8370 fn zirParamAnytype(
   8371     sema: *Sema,
   8372     block: *Block,
   8373     inst: Zir.Inst.Index,
   8374     comptime_syntax: bool,
   8375 ) CompileError!void {
   8376     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
   8377     const src = inst_data.src();
   8378     const param_name = inst_data.get(sema.code);
   8379 
   8380     if (sema.inst_map.get(inst)) |air_ref| {
   8381         const param_ty = sema.typeOf(air_ref);
   8382         if (comptime_syntax or try sema.typeRequiresComptime(param_ty)) {
   8383             // We have a comptime value for this parameter so it should be elided from the
   8384             // function type of the function instruction in this block.
   8385             return;
   8386         }
   8387         if (null != try sema.typeHasOnePossibleValue(block, src, param_ty)) {
   8388             return;
   8389         }
   8390         // The map is already populated but we do need to add a runtime parameter.
   8391         try block.params.append(sema.gpa, .{
   8392             .ty = param_ty,
   8393             .is_comptime = false,
   8394             .name = param_name,
   8395         });
   8396         return;
   8397     }
   8398 
   8399     // We are evaluating a generic function without any comptime args provided.
   8400 
   8401     try block.params.append(sema.gpa, .{
   8402         .ty = Type.initTag(.generic_poison),
   8403         .is_comptime = comptime_syntax,
   8404         .name = param_name,
   8405     });
   8406     try sema.inst_map.put(sema.gpa, inst, .generic_poison);
   8407 }
   8408 
   8409 fn zirAs(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8410     const tracy = trace(@src());
   8411     defer tracy.end();
   8412 
   8413     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
   8414     return sema.analyzeAs(block, sema.src, bin_inst.lhs, bin_inst.rhs, false);
   8415 }
   8416 
   8417 fn zirAsNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8418     const tracy = trace(@src());
   8419     defer tracy.end();
   8420 
   8421     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8422     const src = inst_data.src();
   8423     const extra = sema.code.extraData(Zir.Inst.As, inst_data.payload_index).data;
   8424     sema.src = src;
   8425     return sema.analyzeAs(block, src, extra.dest_type, extra.operand, false);
   8426 }
   8427 
   8428 fn zirAsShiftOperand(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8429     const tracy = trace(@src());
   8430     defer tracy.end();
   8431 
   8432     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8433     const src = inst_data.src();
   8434     const extra = sema.code.extraData(Zir.Inst.As, inst_data.payload_index).data;
   8435     return sema.analyzeAs(block, src, extra.dest_type, extra.operand, true);
   8436 }
   8437 
   8438 fn analyzeAs(
   8439     sema: *Sema,
   8440     block: *Block,
   8441     src: LazySrcLoc,
   8442     zir_dest_type: Zir.Inst.Ref,
   8443     zir_operand: Zir.Inst.Ref,
   8444     no_cast_to_comptime_int: bool,
   8445 ) CompileError!Air.Inst.Ref {
   8446     const is_ret = if (Zir.refToIndex(zir_dest_type)) |ptr_index|
   8447         sema.code.instructions.items(.tag)[ptr_index] == .ret_type
   8448     else
   8449         false;
   8450     const dest_ty = try sema.resolveType(block, src, zir_dest_type);
   8451     const operand = try sema.resolveInst(zir_operand);
   8452     if (dest_ty.tag() == .var_args_param) return operand;
   8453     if (dest_ty.zigTypeTag() == .NoReturn) {
   8454         return sema.fail(block, src, "cannot cast to noreturn", .{});
   8455     }
   8456     return sema.coerceExtra(block, dest_ty, operand, src, .{ .is_ret = is_ret, .no_cast_to_comptime_int = no_cast_to_comptime_int }) catch |err| switch (err) {
   8457         error.NotCoercible => unreachable,
   8458         else => |e| return e,
   8459     };
   8460 }
   8461 
   8462 fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8463     const tracy = trace(@src());
   8464     defer tracy.end();
   8465 
   8466     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   8467     const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   8468     const ptr = try sema.resolveInst(inst_data.operand);
   8469     const ptr_ty = sema.typeOf(ptr);
   8470     if (!ptr_ty.isPtrAtRuntime()) {
   8471         return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)});
   8472     }
   8473     if (try sema.resolveMaybeUndefValIntable(block, ptr_src, ptr)) |ptr_val| {
   8474         return sema.addConstant(Type.usize, ptr_val);
   8475     }
   8476     try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
   8477     return block.addUnOp(.ptrtoint, ptr);
   8478 }
   8479 
   8480 fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8481     const tracy = trace(@src());
   8482     defer tracy.end();
   8483 
   8484     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8485     const src = inst_data.src();
   8486     const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
   8487     const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
   8488     const field_name = sema.code.nullTerminatedString(extra.field_name_start);
   8489     const object = try sema.resolveInst(extra.lhs);
   8490     return sema.fieldVal(block, src, object, field_name, field_name_src);
   8491 }
   8492 
   8493 fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: bool) CompileError!Air.Inst.Ref {
   8494     const tracy = trace(@src());
   8495     defer tracy.end();
   8496 
   8497     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8498     const src = inst_data.src();
   8499     const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
   8500     const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
   8501     const field_name = sema.code.nullTerminatedString(extra.field_name_start);
   8502     const object_ptr = try sema.resolveInst(extra.lhs);
   8503     return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing);
   8504 }
   8505 
   8506 fn zirFieldCallBind(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8507     const tracy = trace(@src());
   8508     defer tracy.end();
   8509 
   8510     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8511     const src = inst_data.src();
   8512     const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
   8513     const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
   8514     const field_name = sema.code.nullTerminatedString(extra.field_name_start);
   8515     const object_ptr = try sema.resolveInst(extra.lhs);
   8516     return sema.fieldCallBind(block, src, object_ptr, field_name, field_name_src);
   8517 }
   8518 
   8519 fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8520     const tracy = trace(@src());
   8521     defer tracy.end();
   8522 
   8523     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8524     const src = inst_data.src();
   8525     const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   8526     const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
   8527     const object = try sema.resolveInst(extra.lhs);
   8528     const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime known");
   8529     return sema.fieldVal(block, src, object, field_name, field_name_src);
   8530 }
   8531 
   8532 fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8533     const tracy = trace(@src());
   8534     defer tracy.end();
   8535 
   8536     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8537     const src = inst_data.src();
   8538     const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   8539     const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
   8540     const object_ptr = try sema.resolveInst(extra.lhs);
   8541     const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime known");
   8542     return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false);
   8543 }
   8544 
   8545 fn zirFieldCallBindNamed(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
   8546     const tracy = trace(@src());
   8547     defer tracy.end();
   8548 
   8549     const extra = sema.code.extraData(Zir.Inst.FieldNamedNode, extended.operand).data;
   8550     const src = LazySrcLoc.nodeOffset(extra.node);
   8551     const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
   8552     const object_ptr = try sema.resolveInst(extra.lhs);
   8553     const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime known");
   8554     return sema.fieldCallBind(block, src, object_ptr, field_name, field_name_src);
   8555 }
   8556 
   8557 fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8558     const tracy = trace(@src());
   8559     defer tracy.end();
   8560 
   8561     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8562     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   8563     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   8564     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   8565 
   8566     const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
   8567     const operand = try sema.resolveInst(extra.rhs);
   8568 
   8569     return sema.intCast(block, inst_data.src(), dest_ty, dest_ty_src, operand, operand_src, true);
   8570 }
   8571 
   8572 fn intCast(
   8573     sema: *Sema,
   8574     block: *Block,
   8575     src: LazySrcLoc,
   8576     dest_ty: Type,
   8577     dest_ty_src: LazySrcLoc,
   8578     operand: Air.Inst.Ref,
   8579     operand_src: LazySrcLoc,
   8580     runtime_safety: bool,
   8581 ) CompileError!Air.Inst.Ref {
   8582     const operand_ty = sema.typeOf(operand);
   8583     const dest_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, dest_ty, dest_ty_src);
   8584     const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
   8585 
   8586     if (try sema.isComptimeKnown(block, operand_src, operand)) {
   8587         return sema.coerce(block, dest_ty, operand, operand_src);
   8588     } else if (dest_scalar_ty.zigTypeTag() == .ComptimeInt) {
   8589         return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{});
   8590     }
   8591 
   8592     try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, dest_ty_src, operand_src);
   8593     const is_vector = dest_ty.zigTypeTag() == .Vector;
   8594 
   8595     if ((try sema.typeHasOnePossibleValue(block, dest_ty_src, dest_ty))) |opv| {
   8596         // requirement: intCast(u0, input) iff input == 0
   8597         if (runtime_safety and block.wantSafety()) {
   8598             try sema.requireRuntimeBlock(block, src, operand_src);
   8599             const target = sema.mod.getTarget();
   8600             const wanted_info = dest_scalar_ty.intInfo(target);
   8601             const wanted_bits = wanted_info.bits;
   8602 
   8603             if (wanted_bits == 0) {
   8604                 const zero_inst = try sema.addConstant(sema.typeOf(operand), Value.zero);
   8605                 const is_in_range = try block.addBinOp(.cmp_eq, operand, zero_inst);
   8606                 try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data);
   8607             }
   8608         }
   8609 
   8610         return sema.addConstant(dest_ty, opv);
   8611     }
   8612 
   8613     try sema.requireRuntimeBlock(block, src, operand_src);
   8614     if (runtime_safety and block.wantSafety()) {
   8615         const target = sema.mod.getTarget();
   8616         const actual_info = operand_scalar_ty.intInfo(target);
   8617         const wanted_info = dest_scalar_ty.intInfo(target);
   8618         const actual_bits = actual_info.bits;
   8619         const wanted_bits = wanted_info.bits;
   8620         const actual_value_bits = actual_bits - @boolToInt(actual_info.signedness == .signed);
   8621         const wanted_value_bits = wanted_bits - @boolToInt(wanted_info.signedness == .signed);
   8622 
   8623         // range shrinkage
   8624         // requirement: int value fits into target type
   8625         if (wanted_value_bits < actual_value_bits) {
   8626             const dest_max_val_scalar = try dest_scalar_ty.maxInt(sema.arena, target);
   8627             const dest_max_val = if (is_vector)
   8628                 try Value.Tag.repeated.create(sema.arena, dest_max_val_scalar)
   8629             else
   8630                 dest_max_val_scalar;
   8631             const dest_max = try sema.addConstant(operand_ty, dest_max_val);
   8632             const diff = try block.addBinOp(.subwrap, dest_max, operand);
   8633 
   8634             if (actual_info.signedness == .signed) {
   8635                 // Reinterpret the sign-bit as part of the value. This will make
   8636                 // negative differences (`operand` > `dest_max`) appear too big.
   8637                 const unsigned_operand_ty = try Type.Tag.int_unsigned.create(sema.arena, actual_bits);
   8638                 const diff_unsigned = try block.addBitCast(unsigned_operand_ty, diff);
   8639 
   8640                 // If the destination type is signed, then we need to double its
   8641                 // range to account for negative values.
   8642                 const dest_range_val = if (wanted_info.signedness == .signed) range_val: {
   8643                     const range_minus_one = try dest_max_val.shl(Value.one, unsigned_operand_ty, sema.arena, target);
   8644                     break :range_val try sema.intAdd(block, operand_src, range_minus_one, Value.one, unsigned_operand_ty);
   8645                 } else dest_max_val;
   8646                 const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val);
   8647 
   8648                 const ok = if (is_vector) ok: {
   8649                     const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte, try sema.addType(operand_ty));
   8650                     const all_in_range = try block.addInst(.{
   8651                         .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
   8652                         .data = .{ .reduce = .{
   8653                             .operand = is_in_range,
   8654                             .operation = .And,
   8655                         } },
   8656                     });
   8657                     break :ok all_in_range;
   8658                 } else ok: {
   8659                     const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range);
   8660                     break :ok is_in_range;
   8661                 };
   8662                 // TODO negative_to_unsigned?
   8663                 try sema.addSafetyCheck(block, ok, .cast_truncated_data);
   8664             } else {
   8665                 const ok = if (is_vector) ok: {
   8666                     const is_in_range = try block.addCmpVector(diff, dest_max, .lte, try sema.addType(operand_ty));
   8667                     const all_in_range = try block.addInst(.{
   8668                         .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
   8669                         .data = .{ .reduce = .{
   8670                             .operand = is_in_range,
   8671                             .operation = .And,
   8672                         } },
   8673                     });
   8674                     break :ok all_in_range;
   8675                 } else ok: {
   8676                     const is_in_range = try block.addBinOp(.cmp_lte, diff, dest_max);
   8677                     break :ok is_in_range;
   8678                 };
   8679                 try sema.addSafetyCheck(block, ok, .cast_truncated_data);
   8680             }
   8681         } else if (actual_info.signedness == .signed and wanted_info.signedness == .unsigned) {
   8682             // no shrinkage, yes sign loss
   8683             // requirement: signed to unsigned >= 0
   8684             const ok = if (is_vector) ok: {
   8685                 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
   8686                 const zero_inst = try sema.addConstant(operand_ty, zero_val);
   8687                 const is_in_range = try block.addCmpVector(operand, zero_inst, .gte, try sema.addType(operand_ty));
   8688                 const all_in_range = try block.addInst(.{
   8689                     .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
   8690                     .data = .{ .reduce = .{
   8691                         .operand = is_in_range,
   8692                         .operation = .And,
   8693                     } },
   8694                 });
   8695                 break :ok all_in_range;
   8696             } else ok: {
   8697                 const zero_inst = try sema.addConstant(operand_ty, Value.zero);
   8698                 const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst);
   8699                 break :ok is_in_range;
   8700             };
   8701             try sema.addSafetyCheck(block, ok, .negative_to_unsigned);
   8702         }
   8703     }
   8704     return block.addTyOp(.intcast, dest_ty, operand);
   8705 }
   8706 
   8707 fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8708     const tracy = trace(@src());
   8709     defer tracy.end();
   8710 
   8711     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8712     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   8713     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   8714     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   8715 
   8716     const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
   8717     const operand = try sema.resolveInst(extra.rhs);
   8718     const operand_ty = sema.typeOf(operand);
   8719     switch (dest_ty.zigTypeTag()) {
   8720         .AnyFrame,
   8721         .ComptimeFloat,
   8722         .ComptimeInt,
   8723         .EnumLiteral,
   8724         .ErrorSet,
   8725         .ErrorUnion,
   8726         .Fn,
   8727         .Frame,
   8728         .NoReturn,
   8729         .Null,
   8730         .Opaque,
   8731         .Optional,
   8732         .Type,
   8733         .Undefined,
   8734         .Void,
   8735         => return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)}),
   8736 
   8737         .Enum => {
   8738             const msg = msg: {
   8739                 const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)});
   8740                 errdefer msg.destroy(sema.gpa);
   8741                 switch (operand_ty.zigTypeTag()) {
   8742                     .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToEnum to cast from '{}'", .{operand_ty.fmt(sema.mod)}),
   8743                     else => {},
   8744                 }
   8745 
   8746                 break :msg msg;
   8747             };
   8748             return sema.failWithOwnedErrorMsg(msg);
   8749         },
   8750 
   8751         .Pointer => {
   8752             const msg = msg: {
   8753                 const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)});
   8754                 errdefer msg.destroy(sema.gpa);
   8755                 switch (operand_ty.zigTypeTag()) {
   8756                     .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToPtr to cast from '{}'", .{operand_ty.fmt(sema.mod)}),
   8757                     .Pointer => try sema.errNote(block, dest_ty_src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(sema.mod)}),
   8758                     else => {},
   8759                 }
   8760 
   8761                 break :msg msg;
   8762             };
   8763             return sema.failWithOwnedErrorMsg(msg);
   8764         },
   8765         .Struct, .Union => if (dest_ty.containerLayout() == .Auto) {
   8766             const container = switch (dest_ty.zigTypeTag()) {
   8767                 .Struct => "struct",
   8768                 .Union => "union",
   8769                 else => unreachable,
   8770             };
   8771             return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}', {s} does not have a guaranteed in-memory layout", .{
   8772                 dest_ty.fmt(sema.mod), container,
   8773             });
   8774         },
   8775         .BoundFn => @panic("TODO remove this type from the language and compiler"),
   8776 
   8777         .Array,
   8778         .Bool,
   8779         .Float,
   8780         .Int,
   8781         .Vector,
   8782         => {},
   8783     }
   8784     switch (operand_ty.zigTypeTag()) {
   8785         .AnyFrame,
   8786         .ComptimeFloat,
   8787         .ComptimeInt,
   8788         .EnumLiteral,
   8789         .ErrorSet,
   8790         .ErrorUnion,
   8791         .Fn,
   8792         .Frame,
   8793         .NoReturn,
   8794         .Null,
   8795         .Opaque,
   8796         .Optional,
   8797         .Type,
   8798         .Undefined,
   8799         .Void,
   8800         => return sema.fail(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)}),
   8801 
   8802         .Enum => {
   8803             const msg = msg: {
   8804                 const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)});
   8805                 errdefer msg.destroy(sema.gpa);
   8806                 switch (dest_ty.zigTypeTag()) {
   8807                     .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @enumToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}),
   8808                     else => {},
   8809                 }
   8810 
   8811                 break :msg msg;
   8812             };
   8813             return sema.failWithOwnedErrorMsg(msg);
   8814         },
   8815         .Pointer => {
   8816             const msg = msg: {
   8817                 const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)});
   8818                 errdefer msg.destroy(sema.gpa);
   8819                 switch (dest_ty.zigTypeTag()) {
   8820                     .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @ptrToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}),
   8821                     .Pointer => try sema.errNote(block, operand_src, msg, "use @ptrCast to cast to '{}'", .{dest_ty.fmt(sema.mod)}),
   8822                     else => {},
   8823                 }
   8824 
   8825                 break :msg msg;
   8826             };
   8827             return sema.failWithOwnedErrorMsg(msg);
   8828         },
   8829         .Struct, .Union => if (operand_ty.containerLayout() == .Auto) {
   8830             const container = switch (operand_ty.zigTypeTag()) {
   8831                 .Struct => "struct",
   8832                 .Union => "union",
   8833                 else => unreachable,
   8834             };
   8835             return sema.fail(block, operand_src, "cannot @bitCast from '{}', {s} does not have a guaranteed in-memory layout", .{
   8836                 operand_ty.fmt(sema.mod), container,
   8837             });
   8838         },
   8839         .BoundFn => @panic("TODO remove this type from the language and compiler"),
   8840 
   8841         .Array,
   8842         .Bool,
   8843         .Float,
   8844         .Int,
   8845         .Vector,
   8846         => {},
   8847     }
   8848     return sema.bitCast(block, dest_ty, operand, operand_src);
   8849 }
   8850 
   8851 fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8852     const tracy = trace(@src());
   8853     defer tracy.end();
   8854 
   8855     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8856     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   8857     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   8858     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   8859 
   8860     const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
   8861     const operand = try sema.resolveInst(extra.rhs);
   8862 
   8863     const target = sema.mod.getTarget();
   8864     const dest_is_comptime_float = switch (dest_ty.zigTypeTag()) {
   8865         .ComptimeFloat => true,
   8866         .Float => false,
   8867         else => return sema.fail(
   8868             block,
   8869             dest_ty_src,
   8870             "expected float type, found '{}'",
   8871             .{dest_ty.fmt(sema.mod)},
   8872         ),
   8873     };
   8874 
   8875     const operand_ty = sema.typeOf(operand);
   8876     switch (operand_ty.zigTypeTag()) {
   8877         .ComptimeFloat, .Float, .ComptimeInt => {},
   8878         else => return sema.fail(
   8879             block,
   8880             operand_src,
   8881             "expected float type, found '{}'",
   8882             .{operand_ty.fmt(sema.mod)},
   8883         ),
   8884     }
   8885 
   8886     if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| {
   8887         return sema.addConstant(dest_ty, try operand_val.floatCast(sema.arena, dest_ty, target));
   8888     }
   8889     if (dest_is_comptime_float) {
   8890         return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_float'", .{});
   8891     }
   8892     const src_bits = operand_ty.floatBits(target);
   8893     const dst_bits = dest_ty.floatBits(target);
   8894     if (dst_bits >= src_bits) {
   8895         return sema.coerce(block, dest_ty, operand, operand_src);
   8896     }
   8897     try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
   8898     return block.addTyOp(.fptrunc, dest_ty, operand);
   8899 }
   8900 
   8901 fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8902     const tracy = trace(@src());
   8903     defer tracy.end();
   8904 
   8905     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8906     const src = inst_data.src();
   8907     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   8908     const array = try sema.resolveInst(extra.lhs);
   8909     const elem_index = try sema.resolveInst(extra.rhs);
   8910     return sema.elemVal(block, src, array, elem_index, src);
   8911 }
   8912 
   8913 fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8914     const tracy = trace(@src());
   8915     defer tracy.end();
   8916 
   8917     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8918     const src = inst_data.src();
   8919     const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
   8920     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   8921     const array = try sema.resolveInst(extra.lhs);
   8922     const elem_index = try sema.resolveInst(extra.rhs);
   8923     return sema.elemVal(block, src, array, elem_index, elem_index_src);
   8924 }
   8925 
   8926 fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8927     const tracy = trace(@src());
   8928     defer tracy.end();
   8929 
   8930     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8931     const src = inst_data.src();
   8932     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   8933     const array_ptr = try sema.resolveInst(extra.lhs);
   8934     const elem_index = try sema.resolveInst(extra.rhs);
   8935     return sema.elemPtr(block, src, array_ptr, elem_index, src, false);
   8936 }
   8937 
   8938 fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8939     const tracy = trace(@src());
   8940     defer tracy.end();
   8941 
   8942     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8943     const src = inst_data.src();
   8944     const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
   8945     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   8946     const array_ptr = try sema.resolveInst(extra.lhs);
   8947     const elem_index = try sema.resolveInst(extra.rhs);
   8948     return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false);
   8949 }
   8950 
   8951 fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8952     const tracy = trace(@src());
   8953     defer tracy.end();
   8954 
   8955     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8956     const src = inst_data.src();
   8957     const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;
   8958     const array_ptr = try sema.resolveInst(extra.ptr);
   8959     const elem_index = try sema.addIntUnsigned(Type.usize, extra.index);
   8960     return sema.elemPtr(block, src, array_ptr, elem_index, src, true);
   8961 }
   8962 
   8963 fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8964     const tracy = trace(@src());
   8965     defer tracy.end();
   8966 
   8967     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8968     const src = inst_data.src();
   8969     const extra = sema.code.extraData(Zir.Inst.SliceStart, inst_data.payload_index).data;
   8970     const array_ptr = try sema.resolveInst(extra.lhs);
   8971     const start = try sema.resolveInst(extra.start);
   8972 
   8973     return sema.analyzeSlice(block, src, array_ptr, start, .none, .none, .unneeded);
   8974 }
   8975 
   8976 fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8977     const tracy = trace(@src());
   8978     defer tracy.end();
   8979 
   8980     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8981     const src = inst_data.src();
   8982     const extra = sema.code.extraData(Zir.Inst.SliceEnd, inst_data.payload_index).data;
   8983     const array_ptr = try sema.resolveInst(extra.lhs);
   8984     const start = try sema.resolveInst(extra.start);
   8985     const end = try sema.resolveInst(extra.end);
   8986 
   8987     return sema.analyzeSlice(block, src, array_ptr, start, end, .none, .unneeded);
   8988 }
   8989 
   8990 fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8991     const tracy = trace(@src());
   8992     defer tracy.end();
   8993 
   8994     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8995     const src = inst_data.src();
   8996     const sentinel_src: LazySrcLoc = .{ .node_offset_slice_sentinel = inst_data.src_node };
   8997     const extra = sema.code.extraData(Zir.Inst.SliceSentinel, inst_data.payload_index).data;
   8998     const array_ptr = try sema.resolveInst(extra.lhs);
   8999     const start = try sema.resolveInst(extra.start);
   9000     const end = try sema.resolveInst(extra.end);
   9001     const sentinel = try sema.resolveInst(extra.sentinel);
   9002 
   9003     return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src);
   9004 }
   9005 
   9006 fn zirSwitchCapture(
   9007     sema: *Sema,
   9008     block: *Block,
   9009     inst: Zir.Inst.Index,
   9010     is_multi: bool,
   9011     is_ref: bool,
   9012 ) CompileError!Air.Inst.Ref {
   9013     const tracy = trace(@src());
   9014     defer tracy.end();
   9015 
   9016     const zir_datas = sema.code.instructions.items(.data);
   9017     const capture_info = zir_datas[inst].switch_capture;
   9018     const switch_info = zir_datas[capture_info.switch_inst].pl_node;
   9019     const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index);
   9020     const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_info.src_node };
   9021     const operand_is_ref = switch_extra.data.bits.is_ref;
   9022     const cond_inst = Zir.refToIndex(switch_extra.data.operand).?;
   9023     const cond_info = sema.code.instructions.items(.data)[cond_inst].un_node;
   9024     const operand_ptr = try sema.resolveInst(cond_info.operand);
   9025     const operand_ptr_ty = sema.typeOf(operand_ptr);
   9026     const operand_ty = if (operand_is_ref) operand_ptr_ty.childType() else operand_ptr_ty;
   9027 
   9028     const operand = if (operand_is_ref)
   9029         try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src)
   9030     else
   9031         operand_ptr;
   9032 
   9033     if (capture_info.prong_index == std.math.maxInt(@TypeOf(capture_info.prong_index))) {
   9034         // It is the else/`_` prong.
   9035         if (is_ref) {
   9036             assert(operand_is_ref);
   9037             return operand_ptr;
   9038         }
   9039 
   9040         switch (operand_ty.zigTypeTag()) {
   9041             .ErrorSet => if (block.switch_else_err_ty) |some| {
   9042                 return sema.bitCast(block, some, operand, operand_src);
   9043             } else {
   9044                 try block.addUnreachable(operand_src, false);
   9045                 return Air.Inst.Ref.unreachable_value;
   9046             },
   9047             else => return operand,
   9048         }
   9049     }
   9050 
   9051     const items = if (is_multi)
   9052         switch_extra.data.getMultiProng(sema.code, switch_extra.end, capture_info.prong_index).items
   9053     else
   9054         &[_]Zir.Inst.Ref{
   9055             switch_extra.data.getScalarProng(sema.code, switch_extra.end, capture_info.prong_index).item,
   9056         };
   9057 
   9058     switch (operand_ty.zigTypeTag()) {
   9059         .Union => {
   9060             const union_obj = operand_ty.cast(Type.Payload.Union).?.data;
   9061             const first_item = try sema.resolveInst(items[0]);
   9062             // Previous switch validation ensured this will succeed
   9063             const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, undefined) catch unreachable;
   9064 
   9065             const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, sema.mod).?);
   9066             const first_field = union_obj.fields.values()[first_field_index];
   9067 
   9068             for (items[1..]) |item, i| {
   9069                 const item_ref = try sema.resolveInst(item);
   9070                 // Previous switch validation ensured this will succeed
   9071                 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, undefined) catch unreachable;
   9072 
   9073                 const field_index = operand_ty.unionTagFieldIndex(item_val, sema.mod).?;
   9074                 const field = union_obj.fields.values()[field_index];
   9075                 if (!field.ty.eql(first_field.ty, sema.mod)) {
   9076                     const msg = msg: {
   9077                         const raw_capture_src = Module.SwitchProngSrc{ .multi_capture = capture_info.prong_index };
   9078                         const capture_src = raw_capture_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first);
   9079 
   9080                         const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{});
   9081                         errdefer msg.destroy(sema.gpa);
   9082 
   9083                         const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 0 } };
   9084                         const first_item_src = raw_first_item_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first);
   9085                         const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 1 + @intCast(u32, i) } };
   9086                         const item_src = raw_item_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first);
   9087                         try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(sema.mod)});
   9088                         try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(sema.mod)});
   9089                         break :msg msg;
   9090                     };
   9091                     return sema.failWithOwnedErrorMsg(msg);
   9092                 }
   9093             }
   9094 
   9095             if (is_ref) {
   9096                 assert(operand_is_ref);
   9097 
   9098                 const field_ty_ptr = try Type.ptr(sema.arena, sema.mod, .{
   9099                     .pointee_type = first_field.ty,
   9100                     .@"addrspace" = .generic,
   9101                     .mutable = operand_ptr_ty.ptrIsMutable(),
   9102                 });
   9103 
   9104                 if (try sema.resolveDefinedValue(block, operand_src, operand_ptr)) |op_ptr_val| {
   9105                     return sema.addConstant(
   9106                         field_ty_ptr,
   9107                         try Value.Tag.field_ptr.create(sema.arena, .{
   9108                             .container_ptr = op_ptr_val,
   9109                             .container_ty = operand_ty,
   9110                             .field_index = first_field_index,
   9111                         }),
   9112                     );
   9113                 }
   9114                 try sema.requireRuntimeBlock(block, operand_src, null);
   9115                 return block.addStructFieldPtr(operand_ptr, first_field_index, field_ty_ptr);
   9116             }
   9117 
   9118             if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| {
   9119                 return sema.addConstant(
   9120                     first_field.ty,
   9121                     operand_val.castTag(.@"union").?.data.val,
   9122                 );
   9123             }
   9124             try sema.requireRuntimeBlock(block, operand_src, null);
   9125             return block.addStructFieldVal(operand, first_field_index, first_field.ty);
   9126         },
   9127         .ErrorSet => {
   9128             if (is_multi) {
   9129                 var names: Module.ErrorSet.NameMap = .{};
   9130                 try names.ensureUnusedCapacity(sema.arena, items.len);
   9131                 for (items) |item| {
   9132                     const item_ref = try sema.resolveInst(item);
   9133                     // Previous switch validation ensured this will succeed
   9134                     const item_val = sema.resolveConstValue(block, .unneeded, item_ref, undefined) catch unreachable;
   9135                     names.putAssumeCapacityNoClobber(
   9136                         item_val.getError().?,
   9137                         {},
   9138                     );
   9139                 }
   9140                 // names must be sorted
   9141                 Module.ErrorSet.sortNames(&names);
   9142                 const else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names);
   9143 
   9144                 return sema.bitCast(block, else_error_ty, operand, operand_src);
   9145             } else {
   9146                 const item_ref = try sema.resolveInst(items[0]);
   9147                 // Previous switch validation ensured this will succeed
   9148                 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, undefined) catch unreachable;
   9149 
   9150                 const item_ty = try Type.Tag.error_set_single.create(sema.arena, item_val.getError().?);
   9151                 return sema.bitCast(block, item_ty, operand, operand_src);
   9152             }
   9153         },
   9154         else => {
   9155             // In this case the capture value is just the passed-through value of the
   9156             // switch condition.
   9157             if (is_ref) {
   9158                 assert(operand_is_ref);
   9159                 return operand_ptr;
   9160             } else {
   9161                 return operand;
   9162             }
   9163         },
   9164     }
   9165 }
   9166 
   9167 fn zirSwitchCond(
   9168     sema: *Sema,
   9169     block: *Block,
   9170     inst: Zir.Inst.Index,
   9171     is_ref: bool,
   9172 ) CompileError!Air.Inst.Ref {
   9173     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   9174     const src = inst_data.src();
   9175     const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node };
   9176     const operand_ptr = try sema.resolveInst(inst_data.operand);
   9177     const operand = if (is_ref)
   9178         try sema.analyzeLoad(block, src, operand_ptr, operand_src)
   9179     else
   9180         operand_ptr;
   9181     const operand_ty = sema.typeOf(operand);
   9182 
   9183     switch (operand_ty.zigTypeTag()) {
   9184         .Type,
   9185         .Void,
   9186         .Bool,
   9187         .Int,
   9188         .Float,
   9189         .ComptimeFloat,
   9190         .ComptimeInt,
   9191         .EnumLiteral,
   9192         .Pointer,
   9193         .Fn,
   9194         .ErrorSet,
   9195         .Enum,
   9196         => {
   9197             if (operand_ty.isSlice()) {
   9198                 return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)});
   9199             }
   9200             if ((try sema.typeHasOnePossibleValue(block, operand_src, operand_ty))) |opv| {
   9201                 return sema.addConstant(operand_ty, opv);
   9202             }
   9203             return operand;
   9204         },
   9205 
   9206         .Union => {
   9207             const union_ty = try sema.resolveTypeFields(block, operand_src, operand_ty);
   9208             const enum_ty = union_ty.unionTagType() orelse {
   9209                 const msg = msg: {
   9210                     const msg = try sema.errMsg(block, src, "switch on union with no attached enum", .{});
   9211                     errdefer msg.destroy(sema.gpa);
   9212                     if (union_ty.declSrcLocOrNull(sema.mod)) |union_src| {
   9213                         try sema.mod.errNoteNonLazy(union_src, msg, "consider 'union(enum)' here", .{});
   9214                     }
   9215                     break :msg msg;
   9216                 };
   9217                 return sema.failWithOwnedErrorMsg(msg);
   9218             };
   9219             return sema.unionToTag(block, enum_ty, operand, src);
   9220         },
   9221 
   9222         .ErrorUnion,
   9223         .NoReturn,
   9224         .Array,
   9225         .Struct,
   9226         .Undefined,
   9227         .Null,
   9228         .Optional,
   9229         .BoundFn,
   9230         .Opaque,
   9231         .Vector,
   9232         .Frame,
   9233         .AnyFrame,
   9234         => return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)}),
   9235     }
   9236 }
   9237 
   9238 const SwitchErrorSet = std.StringHashMap(Module.SwitchProngSrc);
   9239 
   9240 fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   9241     const tracy = trace(@src());
   9242     defer tracy.end();
   9243 
   9244     const gpa = sema.gpa;
   9245     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   9246     const src = inst_data.src();
   9247     const src_node_offset = inst_data.src_node;
   9248     const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };
   9249     const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset };
   9250     const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);
   9251 
   9252     const operand = try sema.resolveInst(extra.data.operand);
   9253 
   9254     var header_extra_index: usize = extra.end;
   9255 
   9256     const scalar_cases_len = extra.data.bits.scalar_cases_len;
   9257     const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: {
   9258         const multi_cases_len = sema.code.extra[header_extra_index];
   9259         header_extra_index += 1;
   9260         break :blk multi_cases_len;
   9261     } else 0;
   9262 
   9263     const special_prong = extra.data.bits.specialProng();
   9264     const special: struct { body: []const Zir.Inst.Index, end: usize } = switch (special_prong) {
   9265         .none => .{ .body = &.{}, .end = header_extra_index },
   9266         .under, .@"else" => blk: {
   9267             const body_len = sema.code.extra[header_extra_index];
   9268             const extra_body_start = header_extra_index + 1;
   9269             break :blk .{
   9270                 .body = sema.code.extra[extra_body_start..][0..body_len],
   9271                 .end = extra_body_start + body_len,
   9272             };
   9273         },
   9274     };
   9275 
   9276     const maybe_union_ty = blk: {
   9277         const zir_data = sema.code.instructions.items(.data);
   9278         const cond_index = Zir.refToIndex(extra.data.operand).?;
   9279         const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable;
   9280         break :blk sema.typeOf(raw_operand);
   9281     };
   9282     const union_originally = maybe_union_ty.zigTypeTag() == .Union;
   9283     var seen_union_fields: []?Module.SwitchProngSrc = &.{};
   9284     defer gpa.free(seen_union_fields);
   9285 
   9286     var empty_enum = false;
   9287 
   9288     const operand_ty = sema.typeOf(operand);
   9289     const err_set = operand_ty.zigTypeTag() == .ErrorSet;
   9290 
   9291     var else_error_ty: ?Type = null;
   9292 
   9293     // Validate usage of '_' prongs.
   9294     if (special_prong == .under and (!operand_ty.isNonexhaustiveEnum() or union_originally)) {
   9295         const msg = msg: {
   9296             const msg = try sema.errMsg(
   9297                 block,
   9298                 src,
   9299                 "'_' prong only allowed when switching on non-exhaustive enums",
   9300                 .{},
   9301             );
   9302             errdefer msg.destroy(gpa);
   9303             try sema.errNote(
   9304                 block,
   9305                 special_prong_src,
   9306                 msg,
   9307                 "'_' prong here",
   9308                 .{},
   9309             );
   9310             break :msg msg;
   9311         };
   9312         return sema.failWithOwnedErrorMsg(msg);
   9313     }
   9314 
   9315     const target = sema.mod.getTarget();
   9316 
   9317     // Validate for duplicate items, missing else prong, and invalid range.
   9318     switch (operand_ty.zigTypeTag()) {
   9319         .Union => unreachable, // handled in zirSwitchCond
   9320         .Enum => {
   9321             var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount());
   9322             empty_enum = seen_fields.len == 0 and !operand_ty.isNonexhaustiveEnum();
   9323             defer if (!union_originally) gpa.free(seen_fields);
   9324             if (union_originally) seen_union_fields = seen_fields;
   9325             mem.set(?Module.SwitchProngSrc, seen_fields, null);
   9326 
   9327             // This is used for non-exhaustive enum values that do not correspond to any tags.
   9328             var range_set = RangeSet.init(gpa, sema.mod);
   9329             defer range_set.deinit();
   9330 
   9331             var extra_index: usize = special.end;
   9332             {
   9333                 var scalar_i: u32 = 0;
   9334                 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   9335                     const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   9336                     extra_index += 1;
   9337                     const body_len = sema.code.extra[extra_index];
   9338                     extra_index += 1;
   9339                     extra_index += body_len;
   9340 
   9341                     try sema.validateSwitchItemEnum(
   9342                         block,
   9343                         seen_fields,
   9344                         &range_set,
   9345                         item_ref,
   9346                         src_node_offset,
   9347                         .{ .scalar = scalar_i },
   9348                     );
   9349                 }
   9350             }
   9351             {
   9352                 var multi_i: u32 = 0;
   9353                 while (multi_i < multi_cases_len) : (multi_i += 1) {
   9354                     const items_len = sema.code.extra[extra_index];
   9355                     extra_index += 1;
   9356                     const ranges_len = sema.code.extra[extra_index];
   9357                     extra_index += 1;
   9358                     const body_len = sema.code.extra[extra_index];
   9359                     extra_index += 1;
   9360                     const items = sema.code.refSlice(extra_index, items_len);
   9361                     extra_index += items_len + body_len;
   9362 
   9363                     for (items) |item_ref, item_i| {
   9364                         try sema.validateSwitchItemEnum(
   9365                             block,
   9366                             seen_fields,
   9367                             &range_set,
   9368                             item_ref,
   9369                             src_node_offset,
   9370                             .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
   9371                         );
   9372                     }
   9373 
   9374                     try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
   9375                 }
   9376             }
   9377             const all_tags_handled = for (seen_fields) |seen_src| {
   9378                 if (seen_src == null) break false;
   9379             } else true;
   9380 
   9381             if (special_prong == .@"else") {
   9382                 if (all_tags_handled and !operand_ty.isNonexhaustiveEnum()) return sema.fail(
   9383                     block,
   9384                     special_prong_src,
   9385                     "unreachable else prong; all cases already handled",
   9386                     .{},
   9387                 );
   9388             } else if (!all_tags_handled) {
   9389                 const msg = msg: {
   9390                     const msg = try sema.errMsg(
   9391                         block,
   9392                         src,
   9393                         "switch must handle all possibilities",
   9394                         .{},
   9395                     );
   9396                     errdefer msg.destroy(sema.gpa);
   9397                     for (seen_fields) |seen_src, i| {
   9398                         if (seen_src != null) continue;
   9399 
   9400                         const field_name = operand_ty.enumFieldName(i);
   9401                         try sema.addFieldErrNote(
   9402                             operand_ty,
   9403                             i,
   9404                             msg,
   9405                             "unhandled enumeration value: '{s}'",
   9406                             .{field_name},
   9407                         );
   9408                     }
   9409                     try sema.mod.errNoteNonLazy(
   9410                         operand_ty.declSrcLoc(sema.mod),
   9411                         msg,
   9412                         "enum '{}' declared here",
   9413                         .{operand_ty.fmt(sema.mod)},
   9414                     );
   9415                     break :msg msg;
   9416                 };
   9417                 return sema.failWithOwnedErrorMsg(msg);
   9418             } else if (special_prong == .none and operand_ty.isNonexhaustiveEnum() and !union_originally) {
   9419                 return sema.fail(
   9420                     block,
   9421                     src,
   9422                     "switch on non-exhaustive enum must include 'else' or '_' prong",
   9423                     .{},
   9424                 );
   9425             }
   9426         },
   9427         .ErrorSet => {
   9428             var seen_errors = SwitchErrorSet.init(gpa);
   9429             defer seen_errors.deinit();
   9430 
   9431             var extra_index: usize = special.end;
   9432             {
   9433                 var scalar_i: u32 = 0;
   9434                 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   9435                     const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   9436                     extra_index += 1;
   9437                     const body_len = sema.code.extra[extra_index];
   9438                     extra_index += 1;
   9439                     extra_index += body_len;
   9440 
   9441                     try sema.validateSwitchItemError(
   9442                         block,
   9443                         &seen_errors,
   9444                         item_ref,
   9445                         src_node_offset,
   9446                         .{ .scalar = scalar_i },
   9447                     );
   9448                 }
   9449             }
   9450             {
   9451                 var multi_i: u32 = 0;
   9452                 while (multi_i < multi_cases_len) : (multi_i += 1) {
   9453                     const items_len = sema.code.extra[extra_index];
   9454                     extra_index += 1;
   9455                     const ranges_len = sema.code.extra[extra_index];
   9456                     extra_index += 1;
   9457                     const body_len = sema.code.extra[extra_index];
   9458                     extra_index += 1;
   9459                     const items = sema.code.refSlice(extra_index, items_len);
   9460                     extra_index += items_len + body_len;
   9461 
   9462                     for (items) |item_ref, item_i| {
   9463                         try sema.validateSwitchItemError(
   9464                             block,
   9465                             &seen_errors,
   9466                             item_ref,
   9467                             src_node_offset,
   9468                             .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
   9469                         );
   9470                     }
   9471 
   9472                     try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
   9473                 }
   9474             }
   9475 
   9476             try sema.resolveInferredErrorSetTy(block, src, operand_ty);
   9477 
   9478             if (operand_ty.isAnyError()) {
   9479                 if (special_prong != .@"else") {
   9480                     return sema.fail(
   9481                         block,
   9482                         src,
   9483                         "else prong required when switching on type 'anyerror'",
   9484                         .{},
   9485                     );
   9486                 }
   9487                 else_error_ty = Type.@"anyerror";
   9488             } else else_validation: {
   9489                 var maybe_msg: ?*Module.ErrorMsg = null;
   9490                 errdefer if (maybe_msg) |msg| msg.destroy(sema.gpa);
   9491 
   9492                 for (operand_ty.errorSetNames()) |error_name| {
   9493                     if (!seen_errors.contains(error_name) and special_prong != .@"else") {
   9494                         const msg = maybe_msg orelse blk: {
   9495                             maybe_msg = try sema.errMsg(
   9496                                 block,
   9497                                 src,
   9498                                 "switch must handle all possibilities",
   9499                                 .{},
   9500                             );
   9501                             break :blk maybe_msg.?;
   9502                         };
   9503 
   9504                         try sema.errNote(
   9505                             block,
   9506                             src,
   9507                             msg,
   9508                             "unhandled error value: 'error.{s}'",
   9509                             .{error_name},
   9510                         );
   9511                     }
   9512                 }
   9513 
   9514                 if (maybe_msg) |msg| {
   9515                     maybe_msg = null;
   9516                     try sema.addDeclaredHereNote(msg, operand_ty);
   9517                     return sema.failWithOwnedErrorMsg(msg);
   9518                 }
   9519 
   9520                 if (special_prong == .@"else" and seen_errors.count() == operand_ty.errorSetNames().len) {
   9521                     // In order to enable common patterns for generic code allow simple else bodies
   9522                     // else => unreachable,
   9523                     // else => return,
   9524                     // else => |e| return e,
   9525                     // even if all the possible errors were already handled.
   9526                     const tags = sema.code.instructions.items(.tag);
   9527                     for (special.body) |else_inst| switch (tags[else_inst]) {
   9528                         .dbg_block_begin,
   9529                         .dbg_block_end,
   9530                         .dbg_stmt,
   9531                         .dbg_var_val,
   9532                         .switch_capture,
   9533                         .ret_type,
   9534                         .as_node,
   9535                         .ret_node,
   9536                         .@"unreachable",
   9537                         .@"defer",
   9538                         .defer_err_code,
   9539                         .err_union_code,
   9540                         .ret_err_value_code,
   9541                         .is_non_err,
   9542                         .condbr,
   9543                         => {},
   9544                         else => break,
   9545                     } else break :else_validation;
   9546 
   9547                     return sema.fail(
   9548                         block,
   9549                         special_prong_src,
   9550                         "unreachable else prong; all cases already handled",
   9551                         .{},
   9552                     );
   9553                 }
   9554 
   9555                 const error_names = operand_ty.errorSetNames();
   9556                 var names: Module.ErrorSet.NameMap = .{};
   9557                 try names.ensureUnusedCapacity(sema.arena, error_names.len);
   9558                 for (error_names) |error_name| {
   9559                     if (seen_errors.contains(error_name)) continue;
   9560 
   9561                     names.putAssumeCapacityNoClobber(error_name, {});
   9562                 }
   9563 
   9564                 // names must be sorted
   9565                 Module.ErrorSet.sortNames(&names);
   9566                 else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names);
   9567             }
   9568         },
   9569         .Int, .ComptimeInt => {
   9570             var range_set = RangeSet.init(gpa, sema.mod);
   9571             defer range_set.deinit();
   9572 
   9573             var extra_index: usize = special.end;
   9574             {
   9575                 var scalar_i: u32 = 0;
   9576                 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   9577                     const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   9578                     extra_index += 1;
   9579                     const body_len = sema.code.extra[extra_index];
   9580                     extra_index += 1;
   9581                     extra_index += body_len;
   9582 
   9583                     try sema.validateSwitchItem(
   9584                         block,
   9585                         &range_set,
   9586                         item_ref,
   9587                         operand_ty,
   9588                         src_node_offset,
   9589                         .{ .scalar = scalar_i },
   9590                     );
   9591                 }
   9592             }
   9593             {
   9594                 var multi_i: u32 = 0;
   9595                 while (multi_i < multi_cases_len) : (multi_i += 1) {
   9596                     const items_len = sema.code.extra[extra_index];
   9597                     extra_index += 1;
   9598                     const ranges_len = sema.code.extra[extra_index];
   9599                     extra_index += 1;
   9600                     const body_len = sema.code.extra[extra_index];
   9601                     extra_index += 1;
   9602                     const items = sema.code.refSlice(extra_index, items_len);
   9603                     extra_index += items_len;
   9604 
   9605                     for (items) |item_ref, item_i| {
   9606                         try sema.validateSwitchItem(
   9607                             block,
   9608                             &range_set,
   9609                             item_ref,
   9610                             operand_ty,
   9611                             src_node_offset,
   9612                             .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
   9613                         );
   9614                     }
   9615 
   9616                     var range_i: u32 = 0;
   9617                     while (range_i < ranges_len) : (range_i += 1) {
   9618                         const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   9619                         extra_index += 1;
   9620                         const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   9621                         extra_index += 1;
   9622 
   9623                         try sema.validateSwitchRange(
   9624                             block,
   9625                             &range_set,
   9626                             item_first,
   9627                             item_last,
   9628                             operand_ty,
   9629                             src_node_offset,
   9630                             .{ .range = .{ .prong = multi_i, .item = range_i } },
   9631                         );
   9632                     }
   9633 
   9634                     extra_index += body_len;
   9635                 }
   9636             }
   9637 
   9638             check_range: {
   9639                 if (operand_ty.zigTypeTag() == .Int) {
   9640                     var arena = std.heap.ArenaAllocator.init(gpa);
   9641                     defer arena.deinit();
   9642 
   9643                     const min_int = try operand_ty.minInt(arena.allocator(), target);
   9644                     const max_int = try operand_ty.maxInt(arena.allocator(), target);
   9645                     if (try range_set.spans(min_int, max_int, operand_ty)) {
   9646                         if (special_prong == .@"else") {
   9647                             return sema.fail(
   9648                                 block,
   9649                                 special_prong_src,
   9650                                 "unreachable else prong; all cases already handled",
   9651                                 .{},
   9652                             );
   9653                         }
   9654                         break :check_range;
   9655                     }
   9656                 }
   9657                 if (special_prong != .@"else") {
   9658                     return sema.fail(
   9659                         block,
   9660                         src,
   9661                         "switch must handle all possibilities",
   9662                         .{},
   9663                     );
   9664                 }
   9665             }
   9666         },
   9667         .Bool => {
   9668             var true_count: u8 = 0;
   9669             var false_count: u8 = 0;
   9670 
   9671             var extra_index: usize = special.end;
   9672             {
   9673                 var scalar_i: u32 = 0;
   9674                 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   9675                     const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   9676                     extra_index += 1;
   9677                     const body_len = sema.code.extra[extra_index];
   9678                     extra_index += 1;
   9679                     extra_index += body_len;
   9680 
   9681                     try sema.validateSwitchItemBool(
   9682                         block,
   9683                         &true_count,
   9684                         &false_count,
   9685                         item_ref,
   9686                         src_node_offset,
   9687                         .{ .scalar = scalar_i },
   9688                     );
   9689                 }
   9690             }
   9691             {
   9692                 var multi_i: u32 = 0;
   9693                 while (multi_i < multi_cases_len) : (multi_i += 1) {
   9694                     const items_len = sema.code.extra[extra_index];
   9695                     extra_index += 1;
   9696                     const ranges_len = sema.code.extra[extra_index];
   9697                     extra_index += 1;
   9698                     const body_len = sema.code.extra[extra_index];
   9699                     extra_index += 1;
   9700                     const items = sema.code.refSlice(extra_index, items_len);
   9701                     extra_index += items_len + body_len;
   9702 
   9703                     for (items) |item_ref, item_i| {
   9704                         try sema.validateSwitchItemBool(
   9705                             block,
   9706                             &true_count,
   9707                             &false_count,
   9708                             item_ref,
   9709                             src_node_offset,
   9710                             .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
   9711                         );
   9712                     }
   9713 
   9714                     try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
   9715                 }
   9716             }
   9717             switch (special_prong) {
   9718                 .@"else" => {
   9719                     if (true_count + false_count == 2) {
   9720                         return sema.fail(
   9721                             block,
   9722                             special_prong_src,
   9723                             "unreachable else prong; all cases already handled",
   9724                             .{},
   9725                         );
   9726                     }
   9727                 },
   9728                 .under, .none => {
   9729                     if (true_count + false_count < 2) {
   9730                         return sema.fail(
   9731                             block,
   9732                             src,
   9733                             "switch must handle all possibilities",
   9734                             .{},
   9735                         );
   9736                     }
   9737                 },
   9738             }
   9739         },
   9740         .EnumLiteral, .Void, .Fn, .Pointer, .Type => {
   9741             if (special_prong != .@"else") {
   9742                 return sema.fail(
   9743                     block,
   9744                     src,
   9745                     "else prong required when switching on type '{}'",
   9746                     .{operand_ty.fmt(sema.mod)},
   9747                 );
   9748             }
   9749 
   9750             var seen_values = ValueSrcMap.initContext(gpa, .{
   9751                 .ty = operand_ty,
   9752                 .mod = sema.mod,
   9753             });
   9754             defer seen_values.deinit();
   9755 
   9756             var extra_index: usize = special.end;
   9757             {
   9758                 var scalar_i: u32 = 0;
   9759                 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   9760                     const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   9761                     extra_index += 1;
   9762                     const body_len = sema.code.extra[extra_index];
   9763                     extra_index += 1;
   9764                     extra_index += body_len;
   9765 
   9766                     try sema.validateSwitchItemSparse(
   9767                         block,
   9768                         &seen_values,
   9769                         item_ref,
   9770                         src_node_offset,
   9771                         .{ .scalar = scalar_i },
   9772                     );
   9773                 }
   9774             }
   9775             {
   9776                 var multi_i: u32 = 0;
   9777                 while (multi_i < multi_cases_len) : (multi_i += 1) {
   9778                     const items_len = sema.code.extra[extra_index];
   9779                     extra_index += 1;
   9780                     const ranges_len = sema.code.extra[extra_index];
   9781                     extra_index += 1;
   9782                     const body_len = sema.code.extra[extra_index];
   9783                     extra_index += 1;
   9784                     const items = sema.code.refSlice(extra_index, items_len);
   9785                     extra_index += items_len + body_len;
   9786 
   9787                     for (items) |item_ref, item_i| {
   9788                         try sema.validateSwitchItemSparse(
   9789                             block,
   9790                             &seen_values,
   9791                             item_ref,
   9792                             src_node_offset,
   9793                             .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
   9794                         );
   9795                     }
   9796 
   9797                     try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
   9798                 }
   9799             }
   9800         },
   9801 
   9802         .ErrorUnion,
   9803         .NoReturn,
   9804         .Array,
   9805         .Struct,
   9806         .Undefined,
   9807         .Null,
   9808         .Optional,
   9809         .BoundFn,
   9810         .Opaque,
   9811         .Vector,
   9812         .Frame,
   9813         .AnyFrame,
   9814         .ComptimeFloat,
   9815         .Float,
   9816         => return sema.fail(block, operand_src, "invalid switch operand type '{}'", .{
   9817             operand_ty.fmt(sema.mod),
   9818         }),
   9819     }
   9820 
   9821     const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
   9822     try sema.air_instructions.append(gpa, .{
   9823         .tag = .block,
   9824         .data = undefined,
   9825     });
   9826     var label: Block.Label = .{
   9827         .zir_block = inst,
   9828         .merges = .{
   9829             .results = .{},
   9830             .br_list = .{},
   9831             .block_inst = block_inst,
   9832         },
   9833     };
   9834 
   9835     var child_block: Block = .{
   9836         .parent = block,
   9837         .sema = sema,
   9838         .src_decl = block.src_decl,
   9839         .namespace = block.namespace,
   9840         .wip_capture_scope = block.wip_capture_scope,
   9841         .instructions = .{},
   9842         .label = &label,
   9843         .inlining = block.inlining,
   9844         .is_comptime = block.is_comptime,
   9845         .switch_else_err_ty = else_error_ty,
   9846         .runtime_cond = block.runtime_cond,
   9847         .runtime_loop = block.runtime_loop,
   9848         .runtime_index = block.runtime_index,
   9849     };
   9850     const merges = &child_block.label.?.merges;
   9851     defer child_block.instructions.deinit(gpa);
   9852     defer merges.results.deinit(gpa);
   9853     defer merges.br_list.deinit(gpa);
   9854 
   9855     if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| {
   9856         var extra_index: usize = special.end;
   9857         {
   9858             var scalar_i: usize = 0;
   9859             while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   9860                 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   9861                 extra_index += 1;
   9862                 const body_len = sema.code.extra[extra_index];
   9863                 extra_index += 1;
   9864                 const body = sema.code.extra[extra_index..][0..body_len];
   9865                 extra_index += body_len;
   9866 
   9867                 const item = try sema.resolveInst(item_ref);
   9868                 // Validation above ensured these will succeed.
   9869                 const item_val = sema.resolveConstValue(&child_block, .unneeded, item, undefined) catch unreachable;
   9870                 if (operand_val.eql(item_val, operand_ty, sema.mod)) {
   9871                     if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
   9872                     return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
   9873                 }
   9874             }
   9875         }
   9876         {
   9877             var multi_i: usize = 0;
   9878             while (multi_i < multi_cases_len) : (multi_i += 1) {
   9879                 const items_len = sema.code.extra[extra_index];
   9880                 extra_index += 1;
   9881                 const ranges_len = sema.code.extra[extra_index];
   9882                 extra_index += 1;
   9883                 const body_len = sema.code.extra[extra_index];
   9884                 extra_index += 1;
   9885                 const items = sema.code.refSlice(extra_index, items_len);
   9886                 extra_index += items_len;
   9887                 const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..body_len];
   9888 
   9889                 for (items) |item_ref| {
   9890                     const item = try sema.resolveInst(item_ref);
   9891                     // Validation above ensured these will succeed.
   9892                     const item_val = sema.resolveConstValue(&child_block, .unneeded, item, undefined) catch unreachable;
   9893                     if (operand_val.eql(item_val, operand_ty, sema.mod)) {
   9894                         if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
   9895                         return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
   9896                     }
   9897                 }
   9898 
   9899                 var range_i: usize = 0;
   9900                 while (range_i < ranges_len) : (range_i += 1) {
   9901                     const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   9902                     extra_index += 1;
   9903                     const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   9904                     extra_index += 1;
   9905 
   9906                     // Validation above ensured these will succeed.
   9907                     const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, undefined) catch unreachable;
   9908                     const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, undefined) catch unreachable;
   9909                     if ((try sema.compare(block, src, operand_val, .gte, first_tv.val, operand_ty)) and
   9910                         (try sema.compare(block, src, operand_val, .lte, last_tv.val, operand_ty)))
   9911                     {
   9912                         if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
   9913                         return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
   9914                     }
   9915                 }
   9916 
   9917                 extra_index += body_len;
   9918             }
   9919         }
   9920         if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);
   9921         return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
   9922     }
   9923 
   9924     if (scalar_cases_len + multi_cases_len == 0) {
   9925         if (empty_enum) {
   9926             return Air.Inst.Ref.void_value;
   9927         }
   9928         if (special_prong == .none) {
   9929             return sema.fail(block, src, "switch must handle all possibilities", .{});
   9930         }
   9931         if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) {
   9932             return Air.Inst.Ref.unreachable_value;
   9933         }
   9934         return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
   9935     }
   9936 
   9937     try sema.requireRuntimeBlock(block, src, operand_src);
   9938 
   9939     const estimated_cases_extra = (scalar_cases_len + multi_cases_len) *
   9940         @typeInfo(Air.SwitchBr.Case).Struct.fields.len + 2;
   9941     var cases_extra = try std.ArrayListUnmanaged(u32).initCapacity(gpa, estimated_cases_extra);
   9942     defer cases_extra.deinit(gpa);
   9943 
   9944     var case_block = child_block.makeSubBlock();
   9945     case_block.runtime_loop = null;
   9946     case_block.runtime_cond = operand_src;
   9947     case_block.runtime_index.increment();
   9948     defer case_block.instructions.deinit(gpa);
   9949 
   9950     var extra_index: usize = special.end;
   9951 
   9952     var scalar_i: usize = 0;
   9953     while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   9954         const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   9955         extra_index += 1;
   9956         const body_len = sema.code.extra[extra_index];
   9957         extra_index += 1;
   9958         const body = sema.code.extra[extra_index..][0..body_len];
   9959         extra_index += body_len;
   9960 
   9961         var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
   9962         defer wip_captures.deinit();
   9963 
   9964         case_block.instructions.shrinkRetainingCapacity(0);
   9965         case_block.wip_capture_scope = wip_captures.scope;
   9966 
   9967         const item = try sema.resolveInst(item_ref);
   9968         // `item` is already guaranteed to be constant known.
   9969 
   9970         const analyze_body = if (union_originally) blk: {
   9971             const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable;
   9972             const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod);
   9973             break :blk field_ty.zigTypeTag() != .NoReturn;
   9974         } else true;
   9975 
   9976         if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
   9977             // nothing to do here
   9978         } else if (analyze_body) {
   9979             _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
   9980                 error.ComptimeBreak => {
   9981                     const zir_datas = sema.code.instructions.items(.data);
   9982                     const break_data = zir_datas[sema.comptime_break_inst].@"break";
   9983                     try sema.addRuntimeBreak(&case_block, .{
   9984                         .block_inst = break_data.block_inst,
   9985                         .operand = break_data.operand,
   9986                         .inst = sema.comptime_break_inst,
   9987                     });
   9988                 },
   9989                 else => |e| return e,
   9990             };
   9991         } else {
   9992             _ = try case_block.addNoOp(.unreach);
   9993         }
   9994 
   9995         try wip_captures.finalize();
   9996 
   9997         try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
   9998         cases_extra.appendAssumeCapacity(1); // items_len
   9999         cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
  10000         cases_extra.appendAssumeCapacity(@enumToInt(item));
  10001         cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
  10002     }
  10003 
  10004     var is_first = true;
  10005     var prev_cond_br: Air.Inst.Index = undefined;
  10006     var first_else_body: []const Air.Inst.Index = &.{};
  10007     defer gpa.free(first_else_body);
  10008     var prev_then_body: []const Air.Inst.Index = &.{};
  10009     defer gpa.free(prev_then_body);
  10010 
  10011     var cases_len = scalar_cases_len;
  10012     var multi_i: usize = 0;
  10013     while (multi_i < multi_cases_len) : (multi_i += 1) {
  10014         const items_len = sema.code.extra[extra_index];
  10015         extra_index += 1;
  10016         const ranges_len = sema.code.extra[extra_index];
  10017         extra_index += 1;
  10018         const body_len = sema.code.extra[extra_index];
  10019         extra_index += 1;
  10020         const items = sema.code.refSlice(extra_index, items_len);
  10021         extra_index += items_len;
  10022 
  10023         case_block.instructions.shrinkRetainingCapacity(0);
  10024         case_block.wip_capture_scope = child_block.wip_capture_scope;
  10025 
  10026         var any_ok: Air.Inst.Ref = .none;
  10027 
  10028         // If there are any ranges, we have to put all the items into the
  10029         // else prong. Otherwise, we can take advantage of multiple items
  10030         // mapping to the same body.
  10031         if (ranges_len == 0) {
  10032             cases_len += 1;
  10033 
  10034             const analyze_body = if (union_originally)
  10035                 for (items) |item_ref| {
  10036                     const item = try sema.resolveInst(item_ref);
  10037                     const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable;
  10038                     const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod);
  10039                     if (field_ty.zigTypeTag() != .NoReturn) break true;
  10040                 } else false
  10041             else
  10042                 true;
  10043 
  10044             const body = sema.code.extra[extra_index..][0..body_len];
  10045             extra_index += body_len;
  10046             if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
  10047                 // nothing to do here
  10048             } else if (analyze_body) {
  10049                 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
  10050                     error.ComptimeBreak => {
  10051                         const zir_datas = sema.code.instructions.items(.data);
  10052                         const break_data = zir_datas[sema.comptime_break_inst].@"break";
  10053                         try sema.addRuntimeBreak(&case_block, .{
  10054                             .block_inst = break_data.block_inst,
  10055                             .operand = break_data.operand,
  10056                             .inst = sema.comptime_break_inst,
  10057                         });
  10058                     },
  10059                     else => |e| return e,
  10060                 };
  10061             } else {
  10062                 _ = try case_block.addNoOp(.unreach);
  10063             }
  10064 
  10065             try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len +
  10066                 case_block.instructions.items.len);
  10067 
  10068             cases_extra.appendAssumeCapacity(@intCast(u32, items.len));
  10069             cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
  10070 
  10071             for (items) |item_ref| {
  10072                 const item = try sema.resolveInst(item_ref);
  10073                 cases_extra.appendAssumeCapacity(@enumToInt(item));
  10074             }
  10075 
  10076             cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
  10077         } else {
  10078             for (items) |item_ref| {
  10079                 const item = try sema.resolveInst(item_ref);
  10080                 const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item);
  10081                 if (any_ok != .none) {
  10082                     any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok);
  10083                 } else {
  10084                     any_ok = cmp_ok;
  10085                 }
  10086             }
  10087 
  10088             var range_i: usize = 0;
  10089             while (range_i < ranges_len) : (range_i += 1) {
  10090                 const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  10091                 extra_index += 1;
  10092                 const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  10093                 extra_index += 1;
  10094 
  10095                 const item_first = try sema.resolveInst(first_ref);
  10096                 const item_last = try sema.resolveInst(last_ref);
  10097 
  10098                 // operand >= first and operand <= last
  10099                 const range_first_ok = try case_block.addBinOp(
  10100                     if (case_block.float_mode == .Optimized) .cmp_gte_optimized else .cmp_gte,
  10101                     operand,
  10102                     item_first,
  10103                 );
  10104                 const range_last_ok = try case_block.addBinOp(
  10105                     if (case_block.float_mode == .Optimized) .cmp_lte_optimized else .cmp_lte,
  10106                     operand,
  10107                     item_last,
  10108                 );
  10109                 const range_ok = try case_block.addBinOp(
  10110                     .bool_and,
  10111                     range_first_ok,
  10112                     range_last_ok,
  10113                 );
  10114                 if (any_ok != .none) {
  10115                     any_ok = try case_block.addBinOp(.bool_or, any_ok, range_ok);
  10116                 } else {
  10117                     any_ok = range_ok;
  10118                 }
  10119             }
  10120 
  10121             const new_cond_br = try case_block.addInstAsIndex(.{ .tag = .cond_br, .data = .{
  10122                 .pl_op = .{
  10123                     .operand = any_ok,
  10124                     .payload = undefined,
  10125                 },
  10126             } });
  10127             var cond_body = case_block.instructions.toOwnedSlice(gpa);
  10128             defer gpa.free(cond_body);
  10129 
  10130             var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
  10131             defer wip_captures.deinit();
  10132 
  10133             case_block.instructions.shrinkRetainingCapacity(0);
  10134             case_block.wip_capture_scope = wip_captures.scope;
  10135 
  10136             const body = sema.code.extra[extra_index..][0..body_len];
  10137             extra_index += body_len;
  10138             if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
  10139                 // nothing to do here
  10140             } else {
  10141                 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
  10142                     error.ComptimeBreak => {
  10143                         const zir_datas = sema.code.instructions.items(.data);
  10144                         const break_data = zir_datas[sema.comptime_break_inst].@"break";
  10145                         try sema.addRuntimeBreak(&case_block, .{
  10146                             .block_inst = break_data.block_inst,
  10147                             .operand = break_data.operand,
  10148                             .inst = sema.comptime_break_inst,
  10149                         });
  10150                     },
  10151                     else => |e| return e,
  10152                 };
  10153             }
  10154 
  10155             try wip_captures.finalize();
  10156 
  10157             if (is_first) {
  10158                 is_first = false;
  10159                 first_else_body = cond_body;
  10160                 cond_body = &.{};
  10161             } else {
  10162                 try sema.air_extra.ensureUnusedCapacity(
  10163                     gpa,
  10164                     @typeInfo(Air.CondBr).Struct.fields.len + prev_then_body.len + cond_body.len,
  10165                 );
  10166 
  10167                 sema.air_instructions.items(.data)[prev_cond_br].pl_op.payload =
  10168                     sema.addExtraAssumeCapacity(Air.CondBr{
  10169                     .then_body_len = @intCast(u32, prev_then_body.len),
  10170                     .else_body_len = @intCast(u32, cond_body.len),
  10171                 });
  10172                 sema.air_extra.appendSliceAssumeCapacity(prev_then_body);
  10173                 sema.air_extra.appendSliceAssumeCapacity(cond_body);
  10174             }
  10175             gpa.free(prev_then_body);
  10176             prev_then_body = case_block.instructions.toOwnedSlice(gpa);
  10177             prev_cond_br = new_cond_br;
  10178         }
  10179     }
  10180 
  10181     var final_else_body: []const Air.Inst.Index = &.{};
  10182     if (special.body.len != 0 or !is_first or case_block.wantSafety()) {
  10183         var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
  10184         defer wip_captures.deinit();
  10185 
  10186         case_block.instructions.shrinkRetainingCapacity(0);
  10187         case_block.wip_capture_scope = wip_captures.scope;
  10188 
  10189         const analyze_body = if (union_originally)
  10190             for (seen_union_fields) |seen_field, index| {
  10191                 if (seen_field != null) continue;
  10192                 const union_obj = maybe_union_ty.cast(Type.Payload.Union).?.data;
  10193                 const field_ty = union_obj.fields.values()[index].ty;
  10194                 if (field_ty.zigTypeTag() != .NoReturn) break true;
  10195             } else false
  10196         else
  10197             true;
  10198         if (special.body.len != 0 and err_set and
  10199             try sema.maybeErrorUnwrap(&case_block, special.body, operand))
  10200         {
  10201             // nothing to do here
  10202         } else if (special.body.len != 0 and analyze_body) {
  10203             _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) {
  10204                 error.ComptimeBreak => {
  10205                     const zir_datas = sema.code.instructions.items(.data);
  10206                     const break_data = zir_datas[sema.comptime_break_inst].@"break";
  10207                     try sema.addRuntimeBreak(&case_block, .{
  10208                         .block_inst = break_data.block_inst,
  10209                         .operand = break_data.operand,
  10210                         .inst = sema.comptime_break_inst,
  10211                     });
  10212                 },
  10213                 else => |e| return e,
  10214             };
  10215         } else {
  10216             // We still need a terminator in this block, but we have proven
  10217             // that it is unreachable.
  10218             if (case_block.wantSafety()) {
  10219                 _ = try sema.safetyPanic(&case_block, src, .corrupt_switch);
  10220             } else {
  10221                 _ = try case_block.addNoOp(.unreach);
  10222             }
  10223         }
  10224 
  10225         try wip_captures.finalize();
  10226 
  10227         if (is_first) {
  10228             final_else_body = case_block.instructions.items;
  10229         } else {
  10230             try sema.air_extra.ensureUnusedCapacity(gpa, prev_then_body.len +
  10231                 @typeInfo(Air.CondBr).Struct.fields.len + case_block.instructions.items.len);
  10232 
  10233             sema.air_instructions.items(.data)[prev_cond_br].pl_op.payload =
  10234                 sema.addExtraAssumeCapacity(Air.CondBr{
  10235                 .then_body_len = @intCast(u32, prev_then_body.len),
  10236                 .else_body_len = @intCast(u32, case_block.instructions.items.len),
  10237             });
  10238             sema.air_extra.appendSliceAssumeCapacity(prev_then_body);
  10239             sema.air_extra.appendSliceAssumeCapacity(case_block.instructions.items);
  10240             final_else_body = first_else_body;
  10241         }
  10242     }
  10243 
  10244     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr).Struct.fields.len +
  10245         cases_extra.items.len + final_else_body.len);
  10246 
  10247     _ = try child_block.addInst(.{ .tag = .switch_br, .data = .{ .pl_op = .{
  10248         .operand = operand,
  10249         .payload = sema.addExtraAssumeCapacity(Air.SwitchBr{
  10250             .cases_len = @intCast(u32, cases_len),
  10251             .else_body_len = @intCast(u32, final_else_body.len),
  10252         }),
  10253     } } });
  10254     sema.air_extra.appendSliceAssumeCapacity(cases_extra.items);
  10255     sema.air_extra.appendSliceAssumeCapacity(final_else_body);
  10256 
  10257     return sema.analyzeBlockBody(block, src, &child_block, merges);
  10258 }
  10259 
  10260 fn resolveSwitchItemVal(
  10261     sema: *Sema,
  10262     block: *Block,
  10263     item_ref: Zir.Inst.Ref,
  10264     switch_node_offset: i32,
  10265     switch_prong_src: Module.SwitchProngSrc,
  10266     range_expand: Module.SwitchProngSrc.RangeExpand,
  10267 ) CompileError!TypedValue {
  10268     const item = try sema.resolveInst(item_ref);
  10269     const item_ty = sema.typeOf(item);
  10270     // Constructing a LazySrcLoc is costly because we only have the switch AST node.
  10271     // Only if we know for sure we need to report a compile error do we resolve the
  10272     // full source locations.
  10273     if (sema.resolveConstValue(block, .unneeded, item, undefined)) |val| {
  10274         return TypedValue{ .ty = item_ty, .val = val };
  10275     } else |err| switch (err) {
  10276         error.NeededSourceLocation => {
  10277             const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_node_offset, range_expand);
  10278             return TypedValue{
  10279                 .ty = item_ty,
  10280                 .val = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime known"),
  10281             };
  10282         },
  10283         else => |e| return e,
  10284     }
  10285 }
  10286 
  10287 fn validateSwitchRange(
  10288     sema: *Sema,
  10289     block: *Block,
  10290     range_set: *RangeSet,
  10291     first_ref: Zir.Inst.Ref,
  10292     last_ref: Zir.Inst.Ref,
  10293     operand_ty: Type,
  10294     src_node_offset: i32,
  10295     switch_prong_src: Module.SwitchProngSrc,
  10296 ) CompileError!void {
  10297     const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val;
  10298     const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val;
  10299     if (first_val.compare(.gt, last_val, operand_ty, sema.mod)) {
  10300         const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), src_node_offset, .first);
  10301         return sema.fail(block, src, "range start value is greater than the end value", .{});
  10302     }
  10303     const maybe_prev_src = try range_set.add(first_val, last_val, operand_ty, switch_prong_src);
  10304     return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
  10305 }
  10306 
  10307 fn validateSwitchItem(
  10308     sema: *Sema,
  10309     block: *Block,
  10310     range_set: *RangeSet,
  10311     item_ref: Zir.Inst.Ref,
  10312     operand_ty: Type,
  10313     src_node_offset: i32,
  10314     switch_prong_src: Module.SwitchProngSrc,
  10315 ) CompileError!void {
  10316     const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
  10317     const maybe_prev_src = try range_set.add(item_val, item_val, operand_ty, switch_prong_src);
  10318     return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
  10319 }
  10320 
  10321 fn validateSwitchItemEnum(
  10322     sema: *Sema,
  10323     block: *Block,
  10324     seen_fields: []?Module.SwitchProngSrc,
  10325     range_set: *RangeSet,
  10326     item_ref: Zir.Inst.Ref,
  10327     src_node_offset: i32,
  10328     switch_prong_src: Module.SwitchProngSrc,
  10329 ) CompileError!void {
  10330     const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
  10331     const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val, sema.mod) orelse {
  10332         const maybe_prev_src = try range_set.add(item_tv.val, item_tv.val, item_tv.ty, switch_prong_src);
  10333         return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
  10334     };
  10335     const maybe_prev_src = seen_fields[field_index];
  10336     seen_fields[field_index] = switch_prong_src;
  10337     return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
  10338 }
  10339 
  10340 fn validateSwitchItemError(
  10341     sema: *Sema,
  10342     block: *Block,
  10343     seen_errors: *SwitchErrorSet,
  10344     item_ref: Zir.Inst.Ref,
  10345     src_node_offset: i32,
  10346     switch_prong_src: Module.SwitchProngSrc,
  10347 ) CompileError!void {
  10348     const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
  10349     // TODO: Do i need to typecheck here?
  10350     const error_name = item_tv.val.castTag(.@"error").?.data.name;
  10351     const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev|
  10352         prev.value
  10353     else
  10354         null;
  10355     return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
  10356 }
  10357 
  10358 fn validateSwitchDupe(
  10359     sema: *Sema,
  10360     block: *Block,
  10361     maybe_prev_src: ?Module.SwitchProngSrc,
  10362     switch_prong_src: Module.SwitchProngSrc,
  10363     src_node_offset: i32,
  10364 ) CompileError!void {
  10365     const prev_prong_src = maybe_prev_src orelse return;
  10366     const gpa = sema.gpa;
  10367     const block_src_decl = sema.mod.declPtr(block.src_decl);
  10368     const src = switch_prong_src.resolve(gpa, block_src_decl, src_node_offset, .none);
  10369     const prev_src = prev_prong_src.resolve(gpa, block_src_decl, src_node_offset, .none);
  10370     const msg = msg: {
  10371         const msg = try sema.errMsg(
  10372             block,
  10373             src,
  10374             "duplicate switch value",
  10375             .{},
  10376         );
  10377         errdefer msg.destroy(sema.gpa);
  10378         try sema.errNote(
  10379             block,
  10380             prev_src,
  10381             msg,
  10382             "previous value here",
  10383             .{},
  10384         );
  10385         break :msg msg;
  10386     };
  10387     return sema.failWithOwnedErrorMsg(msg);
  10388 }
  10389 
  10390 fn validateSwitchItemBool(
  10391     sema: *Sema,
  10392     block: *Block,
  10393     true_count: *u8,
  10394     false_count: *u8,
  10395     item_ref: Zir.Inst.Ref,
  10396     src_node_offset: i32,
  10397     switch_prong_src: Module.SwitchProngSrc,
  10398 ) CompileError!void {
  10399     const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
  10400     if (item_val.toBool()) {
  10401         true_count.* += 1;
  10402     } else {
  10403         false_count.* += 1;
  10404     }
  10405     if (true_count.* + false_count.* > 2) {
  10406         const block_src_decl = sema.mod.declPtr(block.src_decl);
  10407         const src = switch_prong_src.resolve(sema.gpa, block_src_decl, src_node_offset, .none);
  10408         return sema.fail(block, src, "duplicate switch value", .{});
  10409     }
  10410 }
  10411 
  10412 const ValueSrcMap = std.HashMap(Value, Module.SwitchProngSrc, Value.HashContext, std.hash_map.default_max_load_percentage);
  10413 
  10414 fn validateSwitchItemSparse(
  10415     sema: *Sema,
  10416     block: *Block,
  10417     seen_values: *ValueSrcMap,
  10418     item_ref: Zir.Inst.Ref,
  10419     src_node_offset: i32,
  10420     switch_prong_src: Module.SwitchProngSrc,
  10421 ) CompileError!void {
  10422     const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
  10423     const kv = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return;
  10424     return sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset);
  10425 }
  10426 
  10427 fn validateSwitchNoRange(
  10428     sema: *Sema,
  10429     block: *Block,
  10430     ranges_len: u32,
  10431     operand_ty: Type,
  10432     src_node_offset: i32,
  10433 ) CompileError!void {
  10434     if (ranges_len == 0)
  10435         return;
  10436 
  10437     const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };
  10438     const range_src: LazySrcLoc = .{ .node_offset_switch_range = src_node_offset };
  10439 
  10440     const msg = msg: {
  10441         const msg = try sema.errMsg(
  10442             block,
  10443             operand_src,
  10444             "ranges not allowed when switching on type '{}'",
  10445             .{operand_ty.fmt(sema.mod)},
  10446         );
  10447         errdefer msg.destroy(sema.gpa);
  10448         try sema.errNote(
  10449             block,
  10450             range_src,
  10451             msg,
  10452             "range here",
  10453             .{},
  10454         );
  10455         break :msg msg;
  10456     };
  10457     return sema.failWithOwnedErrorMsg(msg);
  10458 }
  10459 
  10460 fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !bool {
  10461     const this_feature_is_implemented_in_the_backend =
  10462         sema.mod.comp.bin_file.options.use_llvm;
  10463 
  10464     if (!this_feature_is_implemented_in_the_backend) return false;
  10465 
  10466     const tags = sema.code.instructions.items(.tag);
  10467     for (body) |inst| {
  10468         switch (tags[inst]) {
  10469             .dbg_block_begin,
  10470             .dbg_block_end,
  10471             .dbg_stmt,
  10472             .@"unreachable",
  10473             .str,
  10474             .as_node,
  10475             .panic,
  10476             .field_val,
  10477             => {},
  10478             else => return false,
  10479         }
  10480     }
  10481 
  10482     for (body) |inst| {
  10483         const air_inst = switch (tags[inst]) {
  10484             .dbg_block_begin,
  10485             .dbg_block_end,
  10486             => continue,
  10487             .dbg_stmt => {
  10488                 try sema.zirDbgStmt(block, inst);
  10489                 continue;
  10490             },
  10491             .str => try sema.zirStr(block, inst),
  10492             .as_node => try sema.zirAsNode(block, inst),
  10493             .field_val => try sema.zirFieldVal(block, inst),
  10494             .@"unreachable" => {
  10495                 const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable";
  10496                 const src = inst_data.src();
  10497 
  10498                 const panic_fn = try sema.getBuiltin(block, src, "panicUnwrapError");
  10499                 const err_return_trace = try sema.getErrorReturnTrace(block, src);
  10500                 const args: [2]Air.Inst.Ref = .{ err_return_trace, operand };
  10501                 _ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, &args, null);
  10502                 return true;
  10503             },
  10504             .panic => {
  10505                 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  10506                 const src = inst_data.src();
  10507                 const msg_inst = try sema.resolveInst(inst_data.operand);
  10508 
  10509                 const panic_fn = try sema.getBuiltin(block, src, "panic");
  10510                 const err_return_trace = try sema.getErrorReturnTrace(block, src);
  10511                 const args: [3]Air.Inst.Ref = .{ msg_inst, err_return_trace, .null_value };
  10512                 _ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, &args, null);
  10513                 return true;
  10514             },
  10515             else => unreachable,
  10516         };
  10517         if (sema.typeOf(air_inst).isNoReturn())
  10518             return true;
  10519         try sema.inst_map.put(sema.gpa, inst, air_inst);
  10520     }
  10521     unreachable;
  10522 }
  10523 
  10524 fn maybeErrorUnwrapCondbr(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, cond: Zir.Inst.Ref, cond_src: LazySrcLoc) !void {
  10525     const index = Zir.refToIndex(cond) orelse return;
  10526     if (sema.code.instructions.items(.tag)[index] != .is_non_err) return;
  10527 
  10528     const err_inst_data = sema.code.instructions.items(.data)[index].un_node;
  10529     const err_operand = try sema.resolveInst(err_inst_data.operand);
  10530     const operand_ty = sema.typeOf(err_operand);
  10531     if (operand_ty.zigTypeTag() == .ErrorSet) {
  10532         try sema.maybeErrorUnwrapComptime(block, body, err_operand);
  10533         return;
  10534     }
  10535     if (try sema.resolveDefinedValue(block, cond_src, err_operand)) |val| {
  10536         if (val.getError() == null) return;
  10537         try sema.maybeErrorUnwrapComptime(block, body, err_operand);
  10538     }
  10539 }
  10540 
  10541 fn maybeErrorUnwrapComptime(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !void {
  10542     const tags = sema.code.instructions.items(.tag);
  10543     const inst = for (body) |inst| {
  10544         switch (tags[inst]) {
  10545             .dbg_block_begin,
  10546             .dbg_block_end,
  10547             .dbg_stmt,
  10548             => {},
  10549             .@"unreachable" => break inst,
  10550             else => return,
  10551         }
  10552     } else return;
  10553     const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable";
  10554     const src = inst_data.src();
  10555 
  10556     if (try sema.resolveDefinedValue(block, src, operand)) |val| {
  10557         if (val.getError()) |name| {
  10558             return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
  10559         }
  10560     }
  10561 }
  10562 
  10563 fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  10564     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  10565     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  10566     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  10567     const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  10568     const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs);
  10569     const field_name = try sema.resolveConstString(block, name_src, extra.rhs, "field name must be comptime known");
  10570     const ty = try sema.resolveTypeFields(block, ty_src, unresolved_ty);
  10571 
  10572     const has_field = hf: {
  10573         if (ty.isSlice()) {
  10574             if (mem.eql(u8, field_name, "ptr")) break :hf true;
  10575             if (mem.eql(u8, field_name, "len")) break :hf true;
  10576             break :hf false;
  10577         }
  10578         if (ty.castTag(.anon_struct)) |pl| {
  10579             break :hf for (pl.data.names) |name| {
  10580                 if (mem.eql(u8, name, field_name)) break true;
  10581             } else false;
  10582         }
  10583         if (ty.isTuple()) {
  10584             const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch break :hf false;
  10585             break :hf field_index < ty.structFieldCount();
  10586         }
  10587         break :hf switch (ty.zigTypeTag()) {
  10588             .Struct => ty.structFields().contains(field_name),
  10589             .Union => ty.unionFields().contains(field_name),
  10590             .Enum => ty.enumFields().contains(field_name),
  10591             .Array => mem.eql(u8, field_name, "len"),
  10592             else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{
  10593                 ty.fmt(sema.mod),
  10594             }),
  10595         };
  10596     };
  10597     if (has_field) {
  10598         return Air.Inst.Ref.bool_true;
  10599     } else {
  10600         return Air.Inst.Ref.bool_false;
  10601     }
  10602 }
  10603 
  10604 fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  10605     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  10606     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  10607     const src = inst_data.src();
  10608     const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  10609     const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  10610     const container_type = try sema.resolveType(block, lhs_src, extra.lhs);
  10611     const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "decl name must be comptime known");
  10612 
  10613     try checkNamespaceType(sema, block, lhs_src, container_type);
  10614 
  10615     const namespace = container_type.getNamespace() orelse return Air.Inst.Ref.bool_false;
  10616     if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| {
  10617         const decl = sema.mod.declPtr(decl_index);
  10618         if (decl.is_pub or decl.getFileScope() == block.getFileScope()) {
  10619             return Air.Inst.Ref.bool_true;
  10620         }
  10621     }
  10622     return Air.Inst.Ref.bool_false;
  10623 }
  10624 
  10625 fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  10626     const tracy = trace(@src());
  10627     defer tracy.end();
  10628 
  10629     const mod = sema.mod;
  10630     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
  10631     const operand_src = inst_data.src();
  10632     const operand = inst_data.get(sema.code);
  10633 
  10634     const result = mod.importFile(block.getFileScope(), operand) catch |err| switch (err) {
  10635         error.ImportOutsidePkgPath => {
  10636             return sema.fail(block, operand_src, "import of file outside package path: '{s}'", .{operand});
  10637         },
  10638         error.PackageNotFound => {
  10639             const cur_pkg = block.getFileScope().pkg;
  10640             const parent = if (cur_pkg == sema.mod.main_pkg or cur_pkg == sema.mod.root_pkg)
  10641                 "root"
  10642             else if (cur_pkg.parent) |parent| blk: {
  10643                 var it = parent.table.iterator();
  10644                 while (it.next()) |pkg| {
  10645                     if (pkg.value_ptr.* == cur_pkg) {
  10646                         break :blk pkg.key_ptr.*;
  10647                     }
  10648                 }
  10649                 unreachable;
  10650             } else {
  10651                 return sema.fail(block, operand_src, "no package named '{s}' available", .{operand});
  10652             };
  10653             return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, parent });
  10654         },
  10655         else => {
  10656             // TODO: these errors are file system errors; make sure an update() will
  10657             // retry this and not cache the file system error, which may be transient.
  10658             return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
  10659         },
  10660     };
  10661     try mod.semaFile(result.file);
  10662     const file_root_decl_index = result.file.root_decl.unwrap().?;
  10663     const file_root_decl = mod.declPtr(file_root_decl_index);
  10664     try mod.declareDeclDependency(sema.owner_decl_index, file_root_decl_index);
  10665     return sema.addConstant(file_root_decl.ty, file_root_decl.val);
  10666 }
  10667 
  10668 fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  10669     const tracy = trace(@src());
  10670     defer tracy.end();
  10671 
  10672     const mod = sema.mod;
  10673     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  10674     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  10675     const name = try sema.resolveConstString(block, operand_src, inst_data.operand, "file path name must be comptime known");
  10676 
  10677     const embed_file = mod.embedFile(block.getFileScope(), name) catch |err| switch (err) {
  10678         error.ImportOutsidePkgPath => {
  10679             return sema.fail(block, operand_src, "embed of file outside package path: '{s}'", .{name});
  10680         },
  10681         else => {
  10682             // TODO: these errors are file system errors; make sure an update() will
  10683             // retry this and not cache the file system error, which may be transient.
  10684             return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ name, @errorName(err) });
  10685         },
  10686     };
  10687 
  10688     var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
  10689     defer anon_decl.deinit();
  10690 
  10691     const bytes_including_null = embed_file.bytes[0 .. embed_file.bytes.len + 1];
  10692 
  10693     // TODO instead of using `Value.Tag.bytes`, create a new value tag for pointing at
  10694     // a `*Module.EmbedFile`. The purpose of this would be:
  10695     // - If only the length is read and the bytes are not inspected by comptime code,
  10696     //   there can be an optimization where the codegen backend does a copy_file_range
  10697     //   into the final binary, and never loads the data into memory.
  10698     // - When a Decl is destroyed, it can free the `*Module.EmbedFile`.
  10699     embed_file.owner_decl = try anon_decl.finish(
  10700         try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), embed_file.bytes.len),
  10701         try Value.Tag.bytes.create(anon_decl.arena(), bytes_including_null),
  10702         0, // default alignment
  10703     );
  10704 
  10705     return sema.analyzeDeclRef(embed_file.owner_decl);
  10706 }
  10707 
  10708 fn zirRetErrValueCode(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  10709     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
  10710     const err_name = inst_data.get(sema.code);
  10711 
  10712     // Return the error code from the function.
  10713     const kv = try sema.mod.getErrorValue(err_name);
  10714     const result_inst = try sema.addConstant(
  10715         try Type.Tag.error_set_single.create(sema.arena, kv.key),
  10716         try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }),
  10717     );
  10718     return result_inst;
  10719 }
  10720 
  10721 fn zirShl(
  10722     sema: *Sema,
  10723     block: *Block,
  10724     inst: Zir.Inst.Index,
  10725     air_tag: Air.Inst.Tag,
  10726 ) CompileError!Air.Inst.Ref {
  10727     const tracy = trace(@src());
  10728     defer tracy.end();
  10729 
  10730     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  10731     const src = inst_data.src();
  10732     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  10733     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  10734     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  10735     const lhs = try sema.resolveInst(extra.lhs);
  10736     const rhs = try sema.resolveInst(extra.rhs);
  10737     const lhs_ty = sema.typeOf(lhs);
  10738     const rhs_ty = sema.typeOf(rhs);
  10739     const target = sema.mod.getTarget();
  10740     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  10741 
  10742     const scalar_ty = lhs_ty.scalarType();
  10743     const scalar_rhs_ty = rhs_ty.scalarType();
  10744 
  10745     // TODO coerce rhs if air_tag is not shl_sat
  10746     const rhs_is_comptime_int = try sema.checkIntType(block, rhs_src, scalar_rhs_ty);
  10747 
  10748     const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);
  10749     const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs);
  10750 
  10751     if (maybe_rhs_val) |rhs_val| {
  10752         if (rhs_val.isUndef()) {
  10753             return sema.addConstUndef(sema.typeOf(lhs));
  10754         }
  10755         // If rhs is 0, return lhs without doing any calculations.
  10756         if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  10757             return lhs;
  10758         }
  10759         if (scalar_ty.zigTypeTag() != .ComptimeInt and air_tag != .shl_sat) {
  10760             var bits_payload = Value.Payload.U64{
  10761                 .base = .{ .tag = .int_u64 },
  10762                 .data = scalar_ty.intInfo(target).bits,
  10763             };
  10764             const bit_value = Value.initPayload(&bits_payload.base);
  10765             if (rhs_ty.zigTypeTag() == .Vector) {
  10766                 var i: usize = 0;
  10767                 while (i < rhs_ty.vectorLen()) : (i += 1) {
  10768                     if (rhs_val.indexVectorlike(i).compareHetero(.gte, bit_value, target)) {
  10769                         return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{
  10770                             rhs_val.indexVectorlike(i).fmtValue(scalar_ty, sema.mod),
  10771                             i,
  10772                             scalar_ty.fmt(sema.mod),
  10773                         });
  10774                     }
  10775                 }
  10776             } else if (rhs_val.compareHetero(.gte, bit_value, target)) {
  10777                 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{
  10778                     rhs_val.fmtValue(scalar_ty, sema.mod),
  10779                     scalar_ty.fmt(sema.mod),
  10780                 });
  10781             }
  10782         }
  10783     }
  10784 
  10785     const runtime_src = if (maybe_lhs_val) |lhs_val| rs: {
  10786         if (lhs_val.isUndef()) return sema.addConstUndef(lhs_ty);
  10787         const rhs_val = maybe_rhs_val orelse {
  10788             if (scalar_ty.zigTypeTag() == .ComptimeInt) {
  10789                 return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be a comptime known", .{});
  10790             }
  10791             break :rs rhs_src;
  10792         };
  10793 
  10794         const val = switch (air_tag) {
  10795             .shl_exact => val: {
  10796                 const shifted = try lhs_val.shlWithOverflow(rhs_val, lhs_ty, sema.arena, target);
  10797                 if (scalar_ty.zigTypeTag() == .ComptimeInt) {
  10798                     break :val shifted.wrapped_result;
  10799                 }
  10800                 if (shifted.overflowed.compareWithZero(.eq)) {
  10801                     break :val shifted.wrapped_result;
  10802                 }
  10803                 return sema.fail(block, src, "operation caused overflow", .{});
  10804             },
  10805 
  10806             .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt)
  10807                 try lhs_val.shl(rhs_val, lhs_ty, sema.arena, target)
  10808             else
  10809                 try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, target),
  10810 
  10811             .shl => if (scalar_ty.zigTypeTag() == .ComptimeInt)
  10812                 try lhs_val.shl(rhs_val, lhs_ty, sema.arena, target)
  10813             else
  10814                 try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, target),
  10815 
  10816             else => unreachable,
  10817         };
  10818 
  10819         return sema.addConstant(lhs_ty, val);
  10820     } else lhs_src;
  10821 
  10822     const new_rhs = if (air_tag == .shl_sat) rhs: {
  10823         // Limit the RHS type for saturating shl to be an integer as small as the LHS.
  10824         if (rhs_is_comptime_int or
  10825             scalar_rhs_ty.intInfo(target).bits > scalar_ty.intInfo(target).bits)
  10826         {
  10827             const max_int = try sema.addConstant(
  10828                 lhs_ty,
  10829                 try lhs_ty.maxInt(sema.arena, target),
  10830             );
  10831             const rhs_limited = try sema.analyzeMinMax(block, rhs_src, rhs, max_int, .min, rhs_src, rhs_src);
  10832             break :rhs try sema.intCast(block, src, lhs_ty, rhs_src, rhs_limited, rhs_src, false);
  10833         } else {
  10834             break :rhs rhs;
  10835         }
  10836     } else rhs;
  10837 
  10838     try sema.requireRuntimeBlock(block, src, runtime_src);
  10839     if (block.wantSafety()) {
  10840         const bit_count = scalar_ty.intInfo(target).bits;
  10841         if (!std.math.isPowerOfTwo(bit_count)) {
  10842             const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count);
  10843 
  10844             const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
  10845                 const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val));
  10846                 const lt = try block.addCmpVector(rhs, bit_count_inst, .lt, try sema.addType(rhs_ty));
  10847                 break :ok try block.addInst(.{
  10848                     .tag = .reduce,
  10849                     .data = .{ .reduce = .{
  10850                         .operand = lt,
  10851                         .operation = .And,
  10852                     } },
  10853                 });
  10854             } else ok: {
  10855                 const bit_count_inst = try sema.addConstant(rhs_ty, bit_count_val);
  10856                 break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst);
  10857             };
  10858             try sema.addSafetyCheck(block, ok, .shift_rhs_too_big);
  10859         }
  10860 
  10861         if (air_tag == .shl_exact) {
  10862             const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty);
  10863             const op_ov = try block.addInst(.{
  10864                 .tag = .shl_with_overflow,
  10865                 .data = .{ .ty_pl = .{
  10866                     .ty = try sema.addType(op_ov_tuple_ty),
  10867                     .payload = try sema.addExtra(Air.Bin{
  10868                         .lhs = lhs,
  10869                         .rhs = rhs,
  10870                     }),
  10871                 } },
  10872             });
  10873             const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
  10874             const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector)
  10875                 try block.addInst(.{
  10876                     .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
  10877                     .data = .{ .reduce = .{
  10878                         .operand = ov_bit,
  10879                         .operation = .Or,
  10880                     } },
  10881                 })
  10882             else
  10883                 ov_bit;
  10884             const zero_ov = try sema.addConstant(Type.@"u1", Value.zero);
  10885             const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
  10886 
  10887             try sema.addSafetyCheck(block, no_ov, .shl_overflow);
  10888             return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
  10889         }
  10890     }
  10891     return block.addBinOp(air_tag, lhs, new_rhs);
  10892 }
  10893 
  10894 fn zirShr(
  10895     sema: *Sema,
  10896     block: *Block,
  10897     inst: Zir.Inst.Index,
  10898     air_tag: Air.Inst.Tag,
  10899 ) CompileError!Air.Inst.Ref {
  10900     const tracy = trace(@src());
  10901     defer tracy.end();
  10902 
  10903     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  10904     const src = inst_data.src();
  10905     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  10906     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  10907     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  10908     const lhs = try sema.resolveInst(extra.lhs);
  10909     const rhs = try sema.resolveInst(extra.rhs);
  10910     const lhs_ty = sema.typeOf(lhs);
  10911     const rhs_ty = sema.typeOf(rhs);
  10912     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  10913     const target = sema.mod.getTarget();
  10914     const scalar_ty = lhs_ty.scalarType();
  10915 
  10916     const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);
  10917     const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs);
  10918 
  10919     const runtime_src = if (maybe_rhs_val) |rhs_val| rs: {
  10920         if (rhs_val.isUndef()) {
  10921             return sema.addConstUndef(lhs_ty);
  10922         }
  10923         // If rhs is 0, return lhs without doing any calculations.
  10924         if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  10925             return lhs;
  10926         }
  10927         if (scalar_ty.zigTypeTag() != .ComptimeInt) {
  10928             var bits_payload = Value.Payload.U64{
  10929                 .base = .{ .tag = .int_u64 },
  10930                 .data = scalar_ty.intInfo(target).bits,
  10931             };
  10932             const bit_value = Value.initPayload(&bits_payload.base);
  10933             if (rhs_ty.zigTypeTag() == .Vector) {
  10934                 var i: usize = 0;
  10935                 while (i < rhs_ty.vectorLen()) : (i += 1) {
  10936                     if (rhs_val.indexVectorlike(i).compareHetero(.gte, bit_value, target)) {
  10937                         return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{
  10938                             rhs_val.indexVectorlike(i).fmtValue(scalar_ty, sema.mod),
  10939                             i,
  10940                             scalar_ty.fmt(sema.mod),
  10941                         });
  10942                     }
  10943                 }
  10944             } else if (rhs_val.compareHetero(.gte, bit_value, target)) {
  10945                 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{
  10946                     rhs_val.fmtValue(scalar_ty, sema.mod),
  10947                     scalar_ty.fmt(sema.mod),
  10948                 });
  10949             }
  10950         }
  10951         if (maybe_lhs_val) |lhs_val| {
  10952             if (lhs_val.isUndef()) {
  10953                 return sema.addConstUndef(lhs_ty);
  10954             }
  10955             if (air_tag == .shr_exact) {
  10956                 // Detect if any ones would be shifted out.
  10957                 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, target);
  10958                 if (!(try truncated.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
  10959                     return sema.fail(block, src, "exact shift shifted out 1 bits", .{});
  10960                 }
  10961             }
  10962             const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, target);
  10963             return sema.addConstant(lhs_ty, val);
  10964         } else {
  10965             break :rs lhs_src;
  10966         }
  10967     } else rhs_src;
  10968 
  10969     if (maybe_rhs_val == null and scalar_ty.zigTypeTag() == .ComptimeInt) {
  10970         return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be a comptime known", .{});
  10971     }
  10972 
  10973     try sema.requireRuntimeBlock(block, src, runtime_src);
  10974     const result = try block.addBinOp(air_tag, lhs, rhs);
  10975     if (block.wantSafety()) {
  10976         const bit_count = scalar_ty.intInfo(target).bits;
  10977         if (!std.math.isPowerOfTwo(bit_count)) {
  10978             const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count);
  10979 
  10980             const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
  10981                 const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val));
  10982                 const lt = try block.addCmpVector(rhs, bit_count_inst, .lt, try sema.addType(rhs_ty));
  10983                 break :ok try block.addInst(.{
  10984                     .tag = .reduce,
  10985                     .data = .{ .reduce = .{
  10986                         .operand = lt,
  10987                         .operation = .And,
  10988                     } },
  10989                 });
  10990             } else ok: {
  10991                 const bit_count_inst = try sema.addConstant(rhs_ty, bit_count_val);
  10992                 break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst);
  10993             };
  10994             try sema.addSafetyCheck(block, ok, .shift_rhs_too_big);
  10995         }
  10996 
  10997         if (air_tag == .shr_exact) {
  10998             const back = try block.addBinOp(.shl, result, rhs);
  10999 
  11000             const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
  11001                 const eql = try block.addCmpVector(lhs, back, .eq, try sema.addType(rhs_ty));
  11002                 break :ok try block.addInst(.{
  11003                     .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
  11004                     .data = .{ .reduce = .{
  11005                         .operand = eql,
  11006                         .operation = .And,
  11007                     } },
  11008                 });
  11009             } else try block.addBinOp(.cmp_eq, lhs, back);
  11010             try sema.addSafetyCheck(block, ok, .shr_overflow);
  11011         }
  11012     }
  11013     return result;
  11014 }
  11015 
  11016 fn zirBitwise(
  11017     sema: *Sema,
  11018     block: *Block,
  11019     inst: Zir.Inst.Index,
  11020     air_tag: Air.Inst.Tag,
  11021 ) CompileError!Air.Inst.Ref {
  11022     const tracy = trace(@src());
  11023     defer tracy.end();
  11024 
  11025     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  11026     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  11027     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  11028     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  11029     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  11030     const lhs = try sema.resolveInst(extra.lhs);
  11031     const rhs = try sema.resolveInst(extra.rhs);
  11032     const lhs_ty = sema.typeOf(lhs);
  11033     const rhs_ty = sema.typeOf(rhs);
  11034     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  11035 
  11036     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  11037     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
  11038     const scalar_type = resolved_type.scalarType();
  11039     const scalar_tag = scalar_type.zigTypeTag();
  11040 
  11041     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  11042     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  11043 
  11044     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  11045     const target = sema.mod.getTarget();
  11046 
  11047     if (!is_int) {
  11048         return sema.fail(block, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) });
  11049     }
  11050 
  11051     const runtime_src = runtime: {
  11052         // TODO: ask the linker what kind of relocations are available, and
  11053         // in some cases emit a Value that means "this decl's address AND'd with this operand".
  11054         if (try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs)) |lhs_val| {
  11055             if (try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs)) |rhs_val| {
  11056                 const result_val = switch (air_tag) {
  11057                     .bit_and => try lhs_val.bitwiseAnd(rhs_val, resolved_type, sema.arena, target),
  11058                     .bit_or => try lhs_val.bitwiseOr(rhs_val, resolved_type, sema.arena, target),
  11059                     .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena, target),
  11060                     else => unreachable,
  11061                 };
  11062                 return sema.addConstant(resolved_type, result_val);
  11063             } else {
  11064                 break :runtime rhs_src;
  11065             }
  11066         } else {
  11067             break :runtime lhs_src;
  11068         }
  11069     };
  11070 
  11071     try sema.requireRuntimeBlock(block, src, runtime_src);
  11072     return block.addBinOp(air_tag, casted_lhs, casted_rhs);
  11073 }
  11074 
  11075 fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  11076     const tracy = trace(@src());
  11077     defer tracy.end();
  11078 
  11079     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  11080     const src = inst_data.src();
  11081     const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
  11082 
  11083     const operand = try sema.resolveInst(inst_data.operand);
  11084     const operand_type = sema.typeOf(operand);
  11085     const scalar_type = operand_type.scalarType();
  11086     const target = sema.mod.getTarget();
  11087 
  11088     if (scalar_type.zigTypeTag() != .Int) {
  11089         return sema.fail(block, src, "unable to perform binary not operation on type '{}'", .{
  11090             operand_type.fmt(sema.mod),
  11091         });
  11092     }
  11093 
  11094     if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
  11095         if (val.isUndef()) {
  11096             return sema.addConstUndef(operand_type);
  11097         } else if (operand_type.zigTypeTag() == .Vector) {
  11098             const vec_len = try sema.usizeCast(block, operand_src, operand_type.vectorLen());
  11099             var elem_val_buf: Value.ElemValueBuffer = undefined;
  11100             const elems = try sema.arena.alloc(Value, vec_len);
  11101             for (elems) |*elem, i| {
  11102                 const elem_val = val.elemValueBuffer(sema.mod, i, &elem_val_buf);
  11103                 elem.* = try elem_val.bitwiseNot(scalar_type, sema.arena, target);
  11104             }
  11105             return sema.addConstant(
  11106                 operand_type,
  11107                 try Value.Tag.aggregate.create(sema.arena, elems),
  11108             );
  11109         } else {
  11110             const result_val = try val.bitwiseNot(operand_type, sema.arena, target);
  11111             return sema.addConstant(operand_type, result_val);
  11112         }
  11113     }
  11114 
  11115     try sema.requireRuntimeBlock(block, src, null);
  11116     return block.addTyOp(.not, operand_type, operand);
  11117 }
  11118 
  11119 fn analyzeTupleCat(
  11120     sema: *Sema,
  11121     block: *Block,
  11122     src_node: i32,
  11123     lhs: Air.Inst.Ref,
  11124     rhs: Air.Inst.Ref,
  11125 ) CompileError!Air.Inst.Ref {
  11126     const lhs_ty = sema.typeOf(lhs);
  11127     const rhs_ty = sema.typeOf(rhs);
  11128     const src = LazySrcLoc.nodeOffset(src_node);
  11129     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node };
  11130     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node };
  11131 
  11132     const lhs_tuple = lhs_ty.tupleFields();
  11133     const rhs_tuple = rhs_ty.tupleFields();
  11134     const dest_fields = lhs_tuple.types.len + rhs_tuple.types.len;
  11135 
  11136     if (dest_fields == 0) {
  11137         return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value));
  11138     }
  11139     const final_len = try sema.usizeCast(block, rhs_src, dest_fields);
  11140 
  11141     const types = try sema.arena.alloc(Type, final_len);
  11142     const values = try sema.arena.alloc(Value, final_len);
  11143 
  11144     const opt_runtime_src = rs: {
  11145         var runtime_src: ?LazySrcLoc = null;
  11146         for (lhs_tuple.types) |ty, i| {
  11147             types[i] = ty;
  11148             values[i] = lhs_tuple.values[i];
  11149             const operand_src = lhs_src; // TODO better source location
  11150             if (values[i].tag() == .unreachable_value) {
  11151                 runtime_src = operand_src;
  11152             }
  11153         }
  11154         const offset = lhs_tuple.types.len;
  11155         for (rhs_tuple.types) |ty, i| {
  11156             types[i + offset] = ty;
  11157             values[i + offset] = rhs_tuple.values[i];
  11158             const operand_src = rhs_src; // TODO better source location
  11159             if (rhs_tuple.values[i].tag() == .unreachable_value) {
  11160                 runtime_src = operand_src;
  11161             }
  11162         }
  11163         break :rs runtime_src;
  11164     };
  11165 
  11166     const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{
  11167         .types = types,
  11168         .values = values,
  11169     });
  11170 
  11171     const runtime_src = opt_runtime_src orelse {
  11172         const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);
  11173         return sema.addConstant(tuple_ty, tuple_val);
  11174     };
  11175 
  11176     try sema.requireRuntimeBlock(block, src, runtime_src);
  11177 
  11178     const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len);
  11179     for (lhs_tuple.types) |_, i| {
  11180         const operand_src = lhs_src; // TODO better source location
  11181         element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, lhs, @intCast(u32, i), lhs_ty);
  11182     }
  11183     const offset = lhs_tuple.types.len;
  11184     for (rhs_tuple.types) |_, i| {
  11185         const operand_src = rhs_src; // TODO better source location
  11186         element_refs[i + offset] =
  11187             try sema.tupleFieldValByIndex(block, operand_src, rhs, @intCast(u32, i), rhs_ty);
  11188     }
  11189 
  11190     return block.addAggregateInit(tuple_ty, element_refs);
  11191 }
  11192 
  11193 fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  11194     const tracy = trace(@src());
  11195     defer tracy.end();
  11196 
  11197     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  11198     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  11199     const lhs = try sema.resolveInst(extra.lhs);
  11200     const rhs = try sema.resolveInst(extra.rhs);
  11201     const lhs_ty = sema.typeOf(lhs);
  11202     const rhs_ty = sema.typeOf(rhs);
  11203     const src = inst_data.src();
  11204 
  11205     if (lhs_ty.isTuple() and rhs_ty.isTuple()) {
  11206         return sema.analyzeTupleCat(block, inst_data.src_node, lhs, rhs);
  11207     }
  11208 
  11209     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  11210     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  11211 
  11212     const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs);
  11213     const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs);
  11214 
  11215     const resolved_elem_ty = t: {
  11216         var trash_block = block.makeSubBlock();
  11217         trash_block.is_comptime = false;
  11218         defer trash_block.instructions.deinit(sema.gpa);
  11219 
  11220         const instructions = [_]Air.Inst.Ref{
  11221             try trash_block.addBitCast(lhs_info.elem_type, .void_value),
  11222             try trash_block.addBitCast(rhs_info.elem_type, .void_value),
  11223         };
  11224         break :t try sema.resolvePeerTypes(block, src, &instructions, .{
  11225             .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
  11226         });
  11227     };
  11228 
  11229     // When there is a sentinel mismatch, no sentinel on the result.
  11230     // Otherwise, use the sentinel value provided by either operand,
  11231     // coercing it to the peer-resolved element type.
  11232     const res_sent_val: ?Value = s: {
  11233         if (lhs_info.sentinel) |lhs_sent_val| {
  11234             const lhs_sent = try sema.addConstant(lhs_info.elem_type, lhs_sent_val);
  11235             if (rhs_info.sentinel) |rhs_sent_val| {
  11236                 const rhs_sent = try sema.addConstant(rhs_info.elem_type, rhs_sent_val);
  11237                 const lhs_sent_casted = try sema.coerce(block, resolved_elem_ty, lhs_sent, lhs_src);
  11238                 const rhs_sent_casted = try sema.coerce(block, resolved_elem_ty, rhs_sent, rhs_src);
  11239                 const lhs_sent_casted_val = try sema.resolveConstValue(block, lhs_src, lhs_sent_casted, "array sentinel value must be comptime known");
  11240                 const rhs_sent_casted_val = try sema.resolveConstValue(block, rhs_src, rhs_sent_casted, "array sentinel value must be comptime known");
  11241                 if (try sema.valuesEqual(block, src, lhs_sent_casted_val, rhs_sent_casted_val, resolved_elem_ty)) {
  11242                     break :s lhs_sent_casted_val;
  11243                 } else {
  11244                     break :s null;
  11245                 }
  11246             } else {
  11247                 const lhs_sent_casted = try sema.coerce(block, resolved_elem_ty, lhs_sent, lhs_src);
  11248                 const lhs_sent_casted_val = try sema.resolveConstValue(block, lhs_src, lhs_sent_casted, "array sentinel value must be comptime known");
  11249                 break :s lhs_sent_casted_val;
  11250             }
  11251         } else {
  11252             if (rhs_info.sentinel) |rhs_sent_val| {
  11253                 const rhs_sent = try sema.addConstant(rhs_info.elem_type, rhs_sent_val);
  11254                 const rhs_sent_casted = try sema.coerce(block, resolved_elem_ty, rhs_sent, rhs_src);
  11255                 const rhs_sent_casted_val = try sema.resolveConstValue(block, rhs_src, rhs_sent_casted, "array sentinel value must be comptime known");
  11256                 break :s rhs_sent_casted_val;
  11257             } else {
  11258                 break :s null;
  11259             }
  11260         }
  11261     };
  11262 
  11263     const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);
  11264     const rhs_len = try sema.usizeCast(block, lhs_src, rhs_info.len);
  11265     const result_len = std.math.add(usize, lhs_len, rhs_len) catch |err| switch (err) {
  11266         error.Overflow => return sema.fail(
  11267             block,
  11268             src,
  11269             "concatenating arrays of length {d} and {d} produces an array too large for this compiler implementation to handle",
  11270             .{ lhs_len, rhs_len },
  11271         ),
  11272     };
  11273 
  11274     const result_ty = try Type.array(sema.arena, result_len, res_sent_val, resolved_elem_ty, sema.mod);
  11275     const ptr_addrspace = p: {
  11276         if (lhs_ty.zigTypeTag() == .Pointer) break :p lhs_ty.ptrAddressSpace();
  11277         if (rhs_ty.zigTypeTag() == .Pointer) break :p rhs_ty.ptrAddressSpace();
  11278         break :p null;
  11279     };
  11280 
  11281     const runtime_src = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| rs: {
  11282         if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| {
  11283             const lhs_sub_val = if (lhs_ty.isSinglePointer())
  11284                 (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).?
  11285             else
  11286                 lhs_val;
  11287 
  11288             const rhs_sub_val = if (rhs_ty.isSinglePointer())
  11289                 (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).?
  11290             else
  11291                 rhs_val;
  11292 
  11293             const final_len_including_sent = result_len + @boolToInt(res_sent_val != null);
  11294             const element_vals = try sema.arena.alloc(Value, final_len_including_sent);
  11295             var elem_i: usize = 0;
  11296             while (elem_i < lhs_len) : (elem_i += 1) {
  11297                 element_vals[elem_i] = try lhs_sub_val.elemValue(sema.mod, sema.arena, elem_i);
  11298             }
  11299             while (elem_i < result_len) : (elem_i += 1) {
  11300                 element_vals[elem_i] = try rhs_sub_val.elemValue(sema.mod, sema.arena, elem_i - lhs_len);
  11301             }
  11302             if (res_sent_val) |sent_val| {
  11303                 element_vals[result_len] = sent_val;
  11304             }
  11305             const val = try Value.Tag.aggregate.create(sema.arena, element_vals);
  11306             return sema.addConstantMaybeRef(block, src, result_ty, val, ptr_addrspace != null);
  11307         } else break :rs rhs_src;
  11308     } else lhs_src;
  11309 
  11310     try sema.requireRuntimeBlock(block, src, runtime_src);
  11311 
  11312     if (ptr_addrspace) |ptr_as| {
  11313         const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
  11314             .pointee_type = result_ty,
  11315             .@"addrspace" = ptr_as,
  11316         });
  11317         const alloc = try block.addTy(.alloc, alloc_ty);
  11318         const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
  11319             .pointee_type = resolved_elem_ty,
  11320             .@"addrspace" = ptr_as,
  11321         });
  11322 
  11323         var elem_i: usize = 0;
  11324         while (elem_i < lhs_len) : (elem_i += 1) {
  11325             const elem_index = try sema.addIntUnsigned(Type.usize, elem_i);
  11326             const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
  11327             const init = try sema.elemVal(block, lhs_src, lhs, elem_index, src);
  11328             try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
  11329         }
  11330         while (elem_i < result_len) : (elem_i += 1) {
  11331             const elem_index = try sema.addIntUnsigned(Type.usize, elem_i);
  11332             const rhs_index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len);
  11333             const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
  11334             const init = try sema.elemVal(block, rhs_src, rhs, rhs_index, src);
  11335             try sema.storePtr2(block, src, elem_ptr, src, init, rhs_src, .store);
  11336         }
  11337         if (res_sent_val) |sent_val| {
  11338             const elem_index = try sema.addIntUnsigned(Type.usize, result_len);
  11339             const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
  11340             const init = try sema.addConstant(lhs_info.elem_type, sent_val);
  11341             try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
  11342         }
  11343 
  11344         return alloc;
  11345     }
  11346 
  11347     const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len);
  11348     {
  11349         var elem_i: usize = 0;
  11350         while (elem_i < lhs_len) : (elem_i += 1) {
  11351             const index = try sema.addIntUnsigned(Type.usize, elem_i);
  11352             const init = try sema.elemVal(block, lhs_src, lhs, index, src);
  11353             element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, lhs_src);
  11354         }
  11355         while (elem_i < result_len) : (elem_i += 1) {
  11356             const index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len);
  11357             const init = try sema.elemVal(block, rhs_src, rhs, index, src);
  11358             element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, rhs_src);
  11359         }
  11360     }
  11361 
  11362     return block.addAggregateInit(result_ty, element_refs);
  11363 }
  11364 
  11365 fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref) !Type.ArrayInfo {
  11366     const operand_ty = sema.typeOf(operand);
  11367     switch (operand_ty.zigTypeTag()) {
  11368         .Array => return operand_ty.arrayInfo(),
  11369         .Pointer => {
  11370             const ptr_info = operand_ty.ptrInfo().data;
  11371             switch (ptr_info.size) {
  11372                 // TODO: in the Many case here this should only work if the type
  11373                 // has a sentinel, and this code should compute the length based
  11374                 // on the sentinel value.
  11375                 .Slice, .Many => {
  11376                     const val = try sema.resolveConstValue(block, src, operand, "slice value being concatenated must be comptime known");
  11377                     return Type.ArrayInfo{
  11378                         .elem_type = ptr_info.pointee_type,
  11379                         .sentinel = ptr_info.sentinel,
  11380                         .len = val.sliceLen(sema.mod),
  11381                     };
  11382                 },
  11383                 .One => {
  11384                     if (ptr_info.pointee_type.zigTypeTag() == .Array) {
  11385                         return ptr_info.pointee_type.arrayInfo();
  11386                     }
  11387                 },
  11388                 .C => {},
  11389             }
  11390         },
  11391         else => {},
  11392     }
  11393     return sema.fail(block, src, "expected indexable; found '{}'", .{operand_ty.fmt(sema.mod)});
  11394 }
  11395 
  11396 fn analyzeTupleMul(
  11397     sema: *Sema,
  11398     block: *Block,
  11399     src_node: i32,
  11400     operand: Air.Inst.Ref,
  11401     factor: u64,
  11402 ) CompileError!Air.Inst.Ref {
  11403     const operand_ty = sema.typeOf(operand);
  11404     const operand_tuple = operand_ty.tupleFields();
  11405     const src = LazySrcLoc.nodeOffset(src_node);
  11406     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node };
  11407     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node };
  11408 
  11409     const tuple_len = operand_tuple.types.len;
  11410     const final_len_u64 = std.math.mul(u64, tuple_len, factor) catch
  11411         return sema.fail(block, rhs_src, "operation results in overflow", .{});
  11412 
  11413     if (final_len_u64 == 0) {
  11414         return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value));
  11415     }
  11416     const final_len = try sema.usizeCast(block, rhs_src, final_len_u64);
  11417 
  11418     const types = try sema.arena.alloc(Type, final_len);
  11419     const values = try sema.arena.alloc(Value, final_len);
  11420 
  11421     const opt_runtime_src = rs: {
  11422         var runtime_src: ?LazySrcLoc = null;
  11423         for (operand_tuple.types) |ty, i| {
  11424             types[i] = ty;
  11425             values[i] = operand_tuple.values[i];
  11426             const operand_src = lhs_src; // TODO better source location
  11427             if (values[i].tag() == .unreachable_value) {
  11428                 runtime_src = operand_src;
  11429             }
  11430         }
  11431         var i: usize = 1;
  11432         while (i < factor) : (i += 1) {
  11433             mem.copy(Type, types[tuple_len * i ..], operand_tuple.types);
  11434             mem.copy(Value, values[tuple_len * i ..], operand_tuple.values);
  11435         }
  11436         break :rs runtime_src;
  11437     };
  11438 
  11439     const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{
  11440         .types = types,
  11441         .values = values,
  11442     });
  11443 
  11444     const runtime_src = opt_runtime_src orelse {
  11445         const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);
  11446         return sema.addConstant(tuple_ty, tuple_val);
  11447     };
  11448 
  11449     try sema.requireRuntimeBlock(block, src, runtime_src);
  11450 
  11451     const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len);
  11452     for (operand_tuple.types) |_, i| {
  11453         const operand_src = lhs_src; // TODO better source location
  11454         element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, operand, @intCast(u32, i), operand_ty);
  11455     }
  11456     var i: usize = 1;
  11457     while (i < factor) : (i += 1) {
  11458         mem.copy(Air.Inst.Ref, element_refs[tuple_len * i ..], element_refs[0..tuple_len]);
  11459     }
  11460 
  11461     return block.addAggregateInit(tuple_ty, element_refs);
  11462 }
  11463 
  11464 fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  11465     const tracy = trace(@src());
  11466     defer tracy.end();
  11467 
  11468     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  11469     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  11470     const lhs = try sema.resolveInst(extra.lhs);
  11471     const lhs_ty = sema.typeOf(lhs);
  11472     const src: LazySrcLoc = inst_data.src();
  11473     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  11474     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  11475 
  11476     // In `**` rhs must be comptime-known, but lhs can be runtime-known
  11477     const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, "array multiplication factor must be comptime known");
  11478 
  11479     if (lhs_ty.isTuple()) {
  11480         return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor);
  11481     }
  11482 
  11483     const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs);
  11484 
  11485     const result_len_u64 = std.math.mul(u64, lhs_info.len, factor) catch
  11486         return sema.fail(block, rhs_src, "operation results in overflow", .{});
  11487     const result_len = try sema.usizeCast(block, src, result_len_u64);
  11488 
  11489     const result_ty = try Type.array(sema.arena, result_len, lhs_info.sentinel, lhs_info.elem_type, sema.mod);
  11490 
  11491     const ptr_addrspace = if (lhs_ty.zigTypeTag() == .Pointer) lhs_ty.ptrAddressSpace() else null;
  11492     const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);
  11493 
  11494     if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| {
  11495         const final_len_including_sent = result_len + @boolToInt(lhs_info.sentinel != null);
  11496 
  11497         const lhs_sub_val = if (lhs_ty.isSinglePointer())
  11498             (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).?
  11499         else
  11500             lhs_val;
  11501 
  11502         const val = v: {
  11503             // Optimization for the common pattern of a single element repeated N times, such
  11504             // as zero-filling a byte array.
  11505             if (lhs_len == 1) {
  11506                 const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, 0);
  11507                 break :v try Value.Tag.repeated.create(sema.arena, elem_val);
  11508             }
  11509 
  11510             const element_vals = try sema.arena.alloc(Value, final_len_including_sent);
  11511             var elem_i: usize = 0;
  11512             while (elem_i < result_len) {
  11513                 var lhs_i: usize = 0;
  11514                 while (lhs_i < lhs_len) : (lhs_i += 1) {
  11515                     const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, lhs_i);
  11516                     element_vals[elem_i] = elem_val;
  11517                     elem_i += 1;
  11518                 }
  11519             }
  11520             if (lhs_info.sentinel) |sent_val| {
  11521                 element_vals[result_len] = sent_val;
  11522             }
  11523             break :v try Value.Tag.aggregate.create(sema.arena, element_vals);
  11524         };
  11525         return sema.addConstantMaybeRef(block, src, result_ty, val, ptr_addrspace != null);
  11526     }
  11527 
  11528     try sema.requireRuntimeBlock(block, src, lhs_src);
  11529 
  11530     if (ptr_addrspace) |ptr_as| {
  11531         const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
  11532             .pointee_type = result_ty,
  11533             .@"addrspace" = ptr_as,
  11534         });
  11535         const alloc = try block.addTy(.alloc, alloc_ty);
  11536         const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
  11537             .pointee_type = lhs_info.elem_type,
  11538             .@"addrspace" = ptr_as,
  11539         });
  11540 
  11541         var elem_i: usize = 0;
  11542         while (elem_i < result_len) {
  11543             var lhs_i: usize = 0;
  11544             while (lhs_i < lhs_len) : (lhs_i += 1) {
  11545                 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i);
  11546                 elem_i += 1;
  11547                 const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i);
  11548                 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
  11549                 const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src);
  11550                 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
  11551             }
  11552         }
  11553         if (lhs_info.sentinel) |sent_val| {
  11554             const elem_index = try sema.addIntUnsigned(Type.usize, result_len);
  11555             const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
  11556             const init = try sema.addConstant(lhs_info.elem_type, sent_val);
  11557             try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
  11558         }
  11559 
  11560         return alloc;
  11561     }
  11562 
  11563     const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len);
  11564     var elem_i: usize = 0;
  11565     while (elem_i < result_len) {
  11566         var lhs_i: usize = 0;
  11567         while (lhs_i < lhs_len) : (lhs_i += 1) {
  11568             const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i);
  11569             const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src);
  11570             element_refs[elem_i] = init;
  11571             elem_i += 1;
  11572         }
  11573     }
  11574 
  11575     return block.addAggregateInit(result_ty, element_refs);
  11576 }
  11577 
  11578 fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  11579     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  11580     const src = inst_data.src();
  11581     const lhs_src = src;
  11582     const rhs_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
  11583 
  11584     const rhs = try sema.resolveInst(inst_data.operand);
  11585     const rhs_ty = sema.typeOf(rhs);
  11586     const rhs_scalar_ty = rhs_ty.scalarType();
  11587 
  11588     if (rhs_scalar_ty.isUnsignedInt() or switch (rhs_scalar_ty.zigTypeTag()) {
  11589         .Int, .ComptimeInt, .Float, .ComptimeFloat => false,
  11590         else => true,
  11591     }) {
  11592         return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)});
  11593     }
  11594 
  11595     if (rhs_scalar_ty.isAnyFloat()) {
  11596         // We handle float negation here to ensure negative zero is represented in the bits.
  11597         if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
  11598             if (rhs_val.isUndef()) return sema.addConstUndef(rhs_ty);
  11599             const target = sema.mod.getTarget();
  11600             return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, target));
  11601         }
  11602         try sema.requireRuntimeBlock(block, src, null);
  11603         return block.addUnOp(if (block.float_mode == .Optimized) .neg_optimized else .neg, rhs);
  11604     }
  11605 
  11606     const lhs = if (rhs_ty.zigTypeTag() == .Vector)
  11607         try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero))
  11608     else
  11609         try sema.resolveInst(.zero);
  11610 
  11611     return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src);
  11612 }
  11613 
  11614 fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  11615     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  11616     const src = inst_data.src();
  11617     const lhs_src = src;
  11618     const rhs_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
  11619 
  11620     const rhs = try sema.resolveInst(inst_data.operand);
  11621     const rhs_ty = sema.typeOf(rhs);
  11622     const rhs_scalar_ty = rhs_ty.scalarType();
  11623 
  11624     switch (rhs_scalar_ty.zigTypeTag()) {
  11625         .Int, .ComptimeInt, .Float, .ComptimeFloat => {},
  11626         else => return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)}),
  11627     }
  11628 
  11629     const lhs = if (rhs_ty.zigTypeTag() == .Vector)
  11630         try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero))
  11631     else
  11632         try sema.resolveInst(.zero);
  11633 
  11634     return sema.analyzeArithmetic(block, .subwrap, lhs, rhs, src, lhs_src, rhs_src);
  11635 }
  11636 
  11637 fn zirArithmetic(
  11638     sema: *Sema,
  11639     block: *Block,
  11640     inst: Zir.Inst.Index,
  11641     zir_tag: Zir.Inst.Tag,
  11642 ) CompileError!Air.Inst.Ref {
  11643     const tracy = trace(@src());
  11644     defer tracy.end();
  11645 
  11646     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  11647     sema.src = .{ .node_offset_bin_op = inst_data.src_node };
  11648     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  11649     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  11650     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  11651     const lhs = try sema.resolveInst(extra.lhs);
  11652     const rhs = try sema.resolveInst(extra.rhs);
  11653 
  11654     return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src);
  11655 }
  11656 
  11657 fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  11658     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  11659     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  11660     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  11661     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  11662     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  11663     const lhs = try sema.resolveInst(extra.lhs);
  11664     const rhs = try sema.resolveInst(extra.rhs);
  11665     const lhs_ty = sema.typeOf(lhs);
  11666     const rhs_ty = sema.typeOf(rhs);
  11667     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
  11668     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
  11669     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  11670     try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .div);
  11671 
  11672     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  11673     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  11674         .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
  11675     });
  11676 
  11677     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  11678     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  11679 
  11680     const lhs_scalar_ty = lhs_ty.scalarType();
  11681     const rhs_scalar_ty = rhs_ty.scalarType();
  11682     const scalar_tag = resolved_type.scalarType().zigTypeTag();
  11683 
  11684     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  11685 
  11686     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div);
  11687 
  11688     const mod = sema.mod;
  11689     const target = mod.getTarget();
  11690     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs);
  11691     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs);
  11692 
  11693     if ((lhs_ty.zigTypeTag() == .ComptimeFloat and rhs_ty.zigTypeTag() == .ComptimeInt) or
  11694         (lhs_ty.zigTypeTag() == .ComptimeInt and rhs_ty.zigTypeTag() == .ComptimeFloat))
  11695     {
  11696         // If it makes a difference whether we coerce to ints or floats before doing the division, error.
  11697         // If lhs % rhs is 0, it doesn't matter.
  11698         const lhs_val = maybe_lhs_val orelse unreachable;
  11699         const rhs_val = maybe_rhs_val orelse unreachable;
  11700         const rem = lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target) catch unreachable;
  11701         if (rem.compareWithZero(.neq)) {
  11702             return sema.fail(block, src, "ambiguous coercion of division operands '{s}' and '{s}'; non-zero remainder '{}'", .{
  11703                 @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()), rem.fmtValue(resolved_type, sema.mod),
  11704             });
  11705         }
  11706     }
  11707 
  11708     // TODO: emit compile error when .div is used on integers and there would be an
  11709     // ambiguous result between div_floor and div_trunc.
  11710 
  11711     // For integers:
  11712     // If the lhs is zero, then zero is returned regardless of rhs.
  11713     // If the rhs is zero, compile error for division by zero.
  11714     // If the rhs is undefined, compile error because there is a possible
  11715     // value (zero) for which the division would be illegal behavior.
  11716     // If the lhs is undefined:
  11717     //   * if lhs type is signed:
  11718     //     * if rhs is comptime-known and not -1, result is undefined
  11719     //     * if rhs is -1 or runtime-known, compile error because there is a
  11720     //        possible value (-min_int / -1)  for which division would be
  11721     //        illegal behavior.
  11722     //   * if lhs type is unsigned, undef is returned regardless of rhs.
  11723     //
  11724     // For floats:
  11725     // If the rhs is zero:
  11726     //  * comptime_float: compile error for division by zero.
  11727     //  * other float type:
  11728     //    * if the lhs is zero: QNaN
  11729     //    * otherwise: +Inf or -Inf depending on lhs sign
  11730     // If the rhs is undefined:
  11731     //  * comptime_float: compile error because there is a possible
  11732     //    value (zero) for which the division would be illegal behavior.
  11733     //  * other float type: result is undefined
  11734     // If the lhs is undefined, result is undefined.
  11735     switch (scalar_tag) {
  11736         .Int, .ComptimeInt, .ComptimeFloat => {
  11737             if (maybe_lhs_val) |lhs_val| {
  11738                 if (!lhs_val.isUndef()) {
  11739                     if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  11740                         return sema.addConstant(resolved_type, Value.zero);
  11741                     }
  11742                 }
  11743             }
  11744             if (maybe_rhs_val) |rhs_val| {
  11745                 if (rhs_val.isUndef()) {
  11746                     return sema.failWithUseOfUndef(block, rhs_src);
  11747                 }
  11748                 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  11749                     return sema.failWithDivideByZero(block, rhs_src);
  11750                 }
  11751                 // TODO: if the RHS is one, return the LHS directly
  11752             }
  11753         },
  11754         else => {},
  11755     }
  11756 
  11757     const runtime_src = rs: {
  11758         if (maybe_lhs_val) |lhs_val| {
  11759             if (lhs_val.isUndef()) {
  11760                 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
  11761                     if (maybe_rhs_val) |rhs_val| {
  11762                         if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) {
  11763                             return sema.addConstUndef(resolved_type);
  11764                         }
  11765                     }
  11766                     return sema.failWithUseOfUndef(block, rhs_src);
  11767                 }
  11768                 return sema.addConstUndef(resolved_type);
  11769             }
  11770 
  11771             if (maybe_rhs_val) |rhs_val| {
  11772                 if (is_int) {
  11773                     return sema.addConstant(
  11774                         resolved_type,
  11775                         try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target),
  11776                     );
  11777                 } else {
  11778                     return sema.addConstant(
  11779                         resolved_type,
  11780                         try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target),
  11781                     );
  11782                 }
  11783             } else {
  11784                 break :rs rhs_src;
  11785             }
  11786         } else {
  11787             break :rs lhs_src;
  11788         }
  11789     };
  11790 
  11791     try sema.requireRuntimeBlock(block, src, runtime_src);
  11792 
  11793     if (block.wantSafety()) {
  11794         try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
  11795         try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
  11796     }
  11797 
  11798     const air_tag = if (is_int) blk: {
  11799         if (lhs_ty.isSignedInt() or rhs_ty.isSignedInt()) {
  11800             return sema.fail(block, src, "division with '{s}' and '{s}': signed integers must use @divTrunc, @divFloor, or @divExact", .{ @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()) });
  11801         }
  11802         break :blk Air.Inst.Tag.div_trunc;
  11803     } else switch (block.float_mode) {
  11804         .Optimized => Air.Inst.Tag.div_float_optimized,
  11805         .Strict => Air.Inst.Tag.div_float,
  11806     };
  11807     return block.addBinOp(air_tag, casted_lhs, casted_rhs);
  11808 }
  11809 
  11810 fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  11811     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  11812     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  11813     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  11814     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  11815     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  11816     const lhs = try sema.resolveInst(extra.lhs);
  11817     const rhs = try sema.resolveInst(extra.rhs);
  11818     const lhs_ty = sema.typeOf(lhs);
  11819     const rhs_ty = sema.typeOf(rhs);
  11820     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
  11821     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
  11822     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  11823     try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .div_exact);
  11824 
  11825     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  11826     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  11827         .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
  11828     });
  11829 
  11830     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  11831     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  11832 
  11833     const lhs_scalar_ty = lhs_ty.scalarType();
  11834     const scalar_tag = resolved_type.scalarType().zigTypeTag();
  11835 
  11836     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  11837 
  11838     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_exact);
  11839 
  11840     const mod = sema.mod;
  11841     const target = mod.getTarget();
  11842     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs);
  11843     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs);
  11844 
  11845     const runtime_src = rs: {
  11846         // For integers:
  11847         // If the lhs is zero, then zero is returned regardless of rhs.
  11848         // If the rhs is zero, compile error for division by zero.
  11849         // If the rhs is undefined, compile error because there is a possible
  11850         // value (zero) for which the division would be illegal behavior.
  11851         // If the lhs is undefined, compile error because there is a possible
  11852         // value for which the division would result in a remainder.
  11853         // TODO: emit runtime safety for if there is a remainder
  11854         // TODO: emit runtime safety for division by zero
  11855         //
  11856         // For floats:
  11857         // If the rhs is zero, compile error for division by zero.
  11858         // If the rhs is undefined, compile error because there is a possible
  11859         // value (zero) for which the division would be illegal behavior.
  11860         // If the lhs is undefined, compile error because there is a possible
  11861         // value for which the division would result in a remainder.
  11862         if (maybe_lhs_val) |lhs_val| {
  11863             if (lhs_val.isUndef()) {
  11864                 return sema.failWithUseOfUndef(block, rhs_src);
  11865             } else {
  11866                 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  11867                     return sema.addConstant(resolved_type, Value.zero);
  11868                 }
  11869             }
  11870         }
  11871         if (maybe_rhs_val) |rhs_val| {
  11872             if (rhs_val.isUndef()) {
  11873                 return sema.failWithUseOfUndef(block, rhs_src);
  11874             }
  11875             if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  11876                 return sema.failWithDivideByZero(block, rhs_src);
  11877             }
  11878             // TODO: if the RHS is one, return the LHS directly
  11879         }
  11880         if (maybe_lhs_val) |lhs_val| {
  11881             if (maybe_rhs_val) |rhs_val| {
  11882                 if (is_int) {
  11883                     const modulus_val = try lhs_val.intMod(rhs_val, resolved_type, sema.arena, target);
  11884                     if (modulus_val.compareWithZero(.neq)) {
  11885                         return sema.fail(block, src, "exact division produced remainder", .{});
  11886                     }
  11887                     return sema.addConstant(
  11888                         resolved_type,
  11889                         try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target),
  11890                     );
  11891                 } else {
  11892                     const modulus_val = try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target);
  11893                     if (modulus_val.compareWithZero(.neq)) {
  11894                         return sema.fail(block, src, "exact division produced remainder", .{});
  11895                     }
  11896                     return sema.addConstant(
  11897                         resolved_type,
  11898                         try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target),
  11899                     );
  11900                 }
  11901             } else break :rs rhs_src;
  11902         } else break :rs lhs_src;
  11903     };
  11904 
  11905     try sema.requireRuntimeBlock(block, src, runtime_src);
  11906 
  11907     // Depending on whether safety is enabled, we will have a slightly different strategy
  11908     // here. The `div_exact` AIR instruction causes undefined behavior if a remainder
  11909     // is produced, so in the safety check case, it cannot be used. Instead we do a
  11910     // div_trunc and check for remainder.
  11911 
  11912     if (block.wantSafety()) {
  11913         try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
  11914         try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
  11915 
  11916         const result = try block.addBinOp(.div_trunc, casted_lhs, casted_rhs);
  11917         const ok = if (!is_int) ok: {
  11918             const floored = try block.addUnOp(.floor, result);
  11919 
  11920             if (resolved_type.zigTypeTag() == .Vector) {
  11921                 const eql = try block.addCmpVector(result, floored, .eq, try sema.addType(resolved_type));
  11922                 break :ok try block.addInst(.{
  11923                     .tag = switch (block.float_mode) {
  11924                         .Strict => .reduce,
  11925                         .Optimized => .reduce_optimized,
  11926                     },
  11927                     .data = .{ .reduce = .{
  11928                         .operand = eql,
  11929                         .operation = .And,
  11930                     } },
  11931                 });
  11932             } else {
  11933                 const is_in_range = try block.addBinOp(switch (block.float_mode) {
  11934                     .Strict => .cmp_eq,
  11935                     .Optimized => .cmp_eq_optimized,
  11936                 }, result, floored);
  11937                 break :ok is_in_range;
  11938             }
  11939         } else ok: {
  11940             const remainder = try block.addBinOp(.rem, casted_lhs, casted_rhs);
  11941 
  11942             if (resolved_type.zigTypeTag() == .Vector) {
  11943                 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
  11944                 const zero = try sema.addConstant(resolved_type, zero_val);
  11945                 const eql = try block.addCmpVector(remainder, zero, .eq, try sema.addType(resolved_type));
  11946                 break :ok try block.addInst(.{
  11947                     .tag = .reduce,
  11948                     .data = .{ .reduce = .{
  11949                         .operand = eql,
  11950                         .operation = .And,
  11951                     } },
  11952                 });
  11953             } else {
  11954                 const zero = try sema.addConstant(resolved_type, Value.zero);
  11955                 const is_in_range = try block.addBinOp(.cmp_eq, remainder, zero);
  11956                 break :ok is_in_range;
  11957             }
  11958         };
  11959         try sema.addSafetyCheck(block, ok, .exact_division_remainder);
  11960         return result;
  11961     }
  11962 
  11963     return block.addBinOp(airTag(block, is_int, .div_exact, .div_exact_optimized), casted_lhs, casted_rhs);
  11964 }
  11965 
  11966 fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  11967     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  11968     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  11969     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  11970     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  11971     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  11972     const lhs = try sema.resolveInst(extra.lhs);
  11973     const rhs = try sema.resolveInst(extra.rhs);
  11974     const lhs_ty = sema.typeOf(lhs);
  11975     const rhs_ty = sema.typeOf(rhs);
  11976     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
  11977     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
  11978     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  11979     try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .div_floor);
  11980 
  11981     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  11982     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  11983         .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
  11984     });
  11985 
  11986     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  11987     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  11988 
  11989     const lhs_scalar_ty = lhs_ty.scalarType();
  11990     const rhs_scalar_ty = rhs_ty.scalarType();
  11991     const scalar_tag = resolved_type.scalarType().zigTypeTag();
  11992 
  11993     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  11994 
  11995     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_floor);
  11996 
  11997     const mod = sema.mod;
  11998     const target = mod.getTarget();
  11999     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs);
  12000     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs);
  12001 
  12002     const runtime_src = rs: {
  12003         // For integers:
  12004         // If the lhs is zero, then zero is returned regardless of rhs.
  12005         // If the rhs is zero, compile error for division by zero.
  12006         // If the rhs is undefined, compile error because there is a possible
  12007         // value (zero) for which the division would be illegal behavior.
  12008         // If the lhs is undefined:
  12009         //   * if lhs type is signed:
  12010         //     * if rhs is comptime-known and not -1, result is undefined
  12011         //     * if rhs is -1 or runtime-known, compile error because there is a
  12012         //        possible value (-min_int / -1)  for which division would be
  12013         //        illegal behavior.
  12014         //   * if lhs type is unsigned, undef is returned regardless of rhs.
  12015         // TODO: emit runtime safety for division by zero
  12016         //
  12017         // For floats:
  12018         // If the rhs is zero, compile error for division by zero.
  12019         // If the rhs is undefined, compile error because there is a possible
  12020         // value (zero) for which the division would be illegal behavior.
  12021         // If the lhs is undefined, result is undefined.
  12022         if (maybe_lhs_val) |lhs_val| {
  12023             if (!lhs_val.isUndef()) {
  12024                 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12025                     return sema.addConstant(resolved_type, Value.zero);
  12026                 }
  12027             }
  12028         }
  12029         if (maybe_rhs_val) |rhs_val| {
  12030             if (rhs_val.isUndef()) {
  12031                 return sema.failWithUseOfUndef(block, rhs_src);
  12032             }
  12033             if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12034                 return sema.failWithDivideByZero(block, rhs_src);
  12035             }
  12036             // TODO: if the RHS is one, return the LHS directly
  12037         }
  12038         if (maybe_lhs_val) |lhs_val| {
  12039             if (lhs_val.isUndef()) {
  12040                 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
  12041                     if (maybe_rhs_val) |rhs_val| {
  12042                         if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) {
  12043                             return sema.addConstUndef(resolved_type);
  12044                         }
  12045                     }
  12046                     return sema.failWithUseOfUndef(block, rhs_src);
  12047                 }
  12048                 return sema.addConstUndef(resolved_type);
  12049             }
  12050 
  12051             if (maybe_rhs_val) |rhs_val| {
  12052                 if (is_int) {
  12053                     return sema.addConstant(
  12054                         resolved_type,
  12055                         try lhs_val.intDivFloor(rhs_val, resolved_type, sema.arena, target),
  12056                     );
  12057                 } else {
  12058                     return sema.addConstant(
  12059                         resolved_type,
  12060                         try lhs_val.floatDivFloor(rhs_val, resolved_type, sema.arena, target),
  12061                     );
  12062                 }
  12063             } else break :rs rhs_src;
  12064         } else break :rs lhs_src;
  12065     };
  12066 
  12067     try sema.requireRuntimeBlock(block, src, runtime_src);
  12068 
  12069     if (block.wantSafety()) {
  12070         try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
  12071         try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
  12072     }
  12073 
  12074     return block.addBinOp(airTag(block, is_int, .div_floor, .div_floor_optimized), casted_lhs, casted_rhs);
  12075 }
  12076 
  12077 fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  12078     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  12079     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  12080     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  12081     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  12082     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  12083     const lhs = try sema.resolveInst(extra.lhs);
  12084     const rhs = try sema.resolveInst(extra.rhs);
  12085     const lhs_ty = sema.typeOf(lhs);
  12086     const rhs_ty = sema.typeOf(rhs);
  12087     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
  12088     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
  12089     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  12090     try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .div_trunc);
  12091 
  12092     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  12093     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  12094         .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
  12095     });
  12096 
  12097     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  12098     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  12099 
  12100     const lhs_scalar_ty = lhs_ty.scalarType();
  12101     const rhs_scalar_ty = rhs_ty.scalarType();
  12102     const scalar_tag = resolved_type.scalarType().zigTypeTag();
  12103 
  12104     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  12105 
  12106     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_trunc);
  12107 
  12108     const mod = sema.mod;
  12109     const target = mod.getTarget();
  12110     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs);
  12111     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs);
  12112 
  12113     const runtime_src = rs: {
  12114         // For integers:
  12115         // If the lhs is zero, then zero is returned regardless of rhs.
  12116         // If the rhs is zero, compile error for division by zero.
  12117         // If the rhs is undefined, compile error because there is a possible
  12118         // value (zero) for which the division would be illegal behavior.
  12119         // If the lhs is undefined:
  12120         //   * if lhs type is signed:
  12121         //     * if rhs is comptime-known and not -1, result is undefined
  12122         //     * if rhs is -1 or runtime-known, compile error because there is a
  12123         //        possible value (-min_int / -1)  for which division would be
  12124         //        illegal behavior.
  12125         //   * if lhs type is unsigned, undef is returned regardless of rhs.
  12126         // TODO: emit runtime safety for division by zero
  12127         //
  12128         // For floats:
  12129         // If the rhs is zero, compile error for division by zero.
  12130         // If the rhs is undefined, compile error because there is a possible
  12131         // value (zero) for which the division would be illegal behavior.
  12132         // If the lhs is undefined, result is undefined.
  12133         if (maybe_lhs_val) |lhs_val| {
  12134             if (!lhs_val.isUndef()) {
  12135                 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12136                     return sema.addConstant(resolved_type, Value.zero);
  12137                 }
  12138             }
  12139         }
  12140         if (maybe_rhs_val) |rhs_val| {
  12141             if (rhs_val.isUndef()) {
  12142                 return sema.failWithUseOfUndef(block, rhs_src);
  12143             }
  12144             if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12145                 return sema.failWithDivideByZero(block, rhs_src);
  12146             }
  12147         }
  12148         if (maybe_lhs_val) |lhs_val| {
  12149             if (lhs_val.isUndef()) {
  12150                 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
  12151                     if (maybe_rhs_val) |rhs_val| {
  12152                         if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) {
  12153                             return sema.addConstUndef(resolved_type);
  12154                         }
  12155                     }
  12156                     return sema.failWithUseOfUndef(block, rhs_src);
  12157                 }
  12158                 return sema.addConstUndef(resolved_type);
  12159             }
  12160 
  12161             if (maybe_rhs_val) |rhs_val| {
  12162                 if (is_int) {
  12163                     return sema.addConstant(
  12164                         resolved_type,
  12165                         try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target),
  12166                     );
  12167                 } else {
  12168                     return sema.addConstant(
  12169                         resolved_type,
  12170                         try lhs_val.floatDivTrunc(rhs_val, resolved_type, sema.arena, target),
  12171                     );
  12172                 }
  12173             } else break :rs rhs_src;
  12174         } else break :rs lhs_src;
  12175     };
  12176 
  12177     try sema.requireRuntimeBlock(block, src, runtime_src);
  12178 
  12179     if (block.wantSafety()) {
  12180         try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
  12181         try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
  12182     }
  12183 
  12184     return block.addBinOp(airTag(block, is_int, .div_trunc, .div_trunc_optimized), casted_lhs, casted_rhs);
  12185 }
  12186 
  12187 fn addDivIntOverflowSafety(
  12188     sema: *Sema,
  12189     block: *Block,
  12190     resolved_type: Type,
  12191     lhs_scalar_ty: Type,
  12192     maybe_lhs_val: ?Value,
  12193     maybe_rhs_val: ?Value,
  12194     casted_lhs: Air.Inst.Ref,
  12195     casted_rhs: Air.Inst.Ref,
  12196     is_int: bool,
  12197 ) CompileError!void {
  12198     if (!is_int) return;
  12199 
  12200     // If the LHS is unsigned, it cannot cause overflow.
  12201     if (!lhs_scalar_ty.isSignedInt()) return;
  12202 
  12203     const mod = sema.mod;
  12204     const target = mod.getTarget();
  12205 
  12206     // If the LHS is widened to a larger integer type, no overflow is possible.
  12207     if (lhs_scalar_ty.intInfo(target).bits < resolved_type.intInfo(target).bits) {
  12208         return;
  12209     }
  12210 
  12211     const min_int = try resolved_type.minInt(sema.arena, target);
  12212     const neg_one_scalar = try Value.Tag.int_i64.create(sema.arena, -1);
  12213     const neg_one = if (resolved_type.zigTypeTag() == .Vector)
  12214         try Value.Tag.repeated.create(sema.arena, neg_one_scalar)
  12215     else
  12216         neg_one_scalar;
  12217 
  12218     // If the LHS is comptime-known to be not equal to the min int,
  12219     // no overflow is possible.
  12220     if (maybe_lhs_val) |lhs_val| {
  12221         if (!lhs_val.compare(.eq, min_int, resolved_type, mod)) return;
  12222     }
  12223 
  12224     // If the RHS is comptime-known to not be equal to -1, no overflow is possible.
  12225     if (maybe_rhs_val) |rhs_val| {
  12226         if (!rhs_val.compare(.eq, neg_one, resolved_type, mod)) return;
  12227     }
  12228 
  12229     var ok: Air.Inst.Ref = .none;
  12230     if (resolved_type.zigTypeTag() == .Vector) {
  12231         const vector_ty_ref = try sema.addType(resolved_type);
  12232         if (maybe_lhs_val == null) {
  12233             const min_int_ref = try sema.addConstant(resolved_type, min_int);
  12234             ok = try block.addCmpVector(casted_lhs, min_int_ref, .neq, vector_ty_ref);
  12235         }
  12236         if (maybe_rhs_val == null) {
  12237             const neg_one_ref = try sema.addConstant(resolved_type, neg_one);
  12238             const rhs_ok = try block.addCmpVector(casted_rhs, neg_one_ref, .neq, vector_ty_ref);
  12239             if (ok == .none) {
  12240                 ok = rhs_ok;
  12241             } else {
  12242                 ok = try block.addBinOp(.bool_or, ok, rhs_ok);
  12243             }
  12244         }
  12245         assert(ok != .none);
  12246         ok = try block.addInst(.{
  12247             .tag = .reduce,
  12248             .data = .{ .reduce = .{
  12249                 .operand = ok,
  12250                 .operation = .And,
  12251             } },
  12252         });
  12253     } else {
  12254         if (maybe_lhs_val == null) {
  12255             const min_int_ref = try sema.addConstant(resolved_type, min_int);
  12256             ok = try block.addBinOp(.cmp_neq, casted_lhs, min_int_ref);
  12257         }
  12258         if (maybe_rhs_val == null) {
  12259             const neg_one_ref = try sema.addConstant(resolved_type, neg_one);
  12260             const rhs_ok = try block.addBinOp(.cmp_neq, casted_rhs, neg_one_ref);
  12261             if (ok == .none) {
  12262                 ok = rhs_ok;
  12263             } else {
  12264                 ok = try block.addBinOp(.bool_or, ok, rhs_ok);
  12265             }
  12266         }
  12267         assert(ok != .none);
  12268     }
  12269     try sema.addSafetyCheck(block, ok, .integer_overflow);
  12270 }
  12271 
  12272 fn addDivByZeroSafety(
  12273     sema: *Sema,
  12274     block: *Block,
  12275     resolved_type: Type,
  12276     maybe_rhs_val: ?Value,
  12277     casted_rhs: Air.Inst.Ref,
  12278     is_int: bool,
  12279 ) CompileError!void {
  12280     // Strict IEEE floats have well-defined division by zero.
  12281     if (!is_int and block.float_mode == .Strict) return;
  12282 
  12283     // If rhs was comptime-known to be zero a compile error would have been
  12284     // emitted above.
  12285     if (maybe_rhs_val != null) return;
  12286 
  12287     const ok = if (resolved_type.zigTypeTag() == .Vector) ok: {
  12288         const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
  12289         const zero = try sema.addConstant(resolved_type, zero_val);
  12290         const ok = try block.addCmpVector(casted_rhs, zero, .neq, try sema.addType(resolved_type));
  12291         break :ok try block.addInst(.{
  12292             .tag = if (is_int) .reduce else .reduce_optimized,
  12293             .data = .{ .reduce = .{
  12294                 .operand = ok,
  12295                 .operation = .And,
  12296             } },
  12297         });
  12298     } else ok: {
  12299         const zero = try sema.addConstant(resolved_type, Value.zero);
  12300         break :ok try block.addBinOp(if (is_int) .cmp_neq else .cmp_neq_optimized, casted_rhs, zero);
  12301     };
  12302     try sema.addSafetyCheck(block, ok, .divide_by_zero);
  12303 }
  12304 
  12305 fn airTag(block: *Block, is_int: bool, normal: Air.Inst.Tag, optimized: Air.Inst.Tag) Air.Inst.Tag {
  12306     if (is_int) return normal;
  12307     return switch (block.float_mode) {
  12308         .Strict => normal,
  12309         .Optimized => optimized,
  12310     };
  12311 }
  12312 
  12313 fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  12314     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  12315     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  12316     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  12317     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  12318     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  12319     const lhs = try sema.resolveInst(extra.lhs);
  12320     const rhs = try sema.resolveInst(extra.rhs);
  12321     const lhs_ty = sema.typeOf(lhs);
  12322     const rhs_ty = sema.typeOf(rhs);
  12323     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
  12324     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
  12325     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  12326     try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .mod_rem);
  12327 
  12328     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  12329     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  12330         .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
  12331     });
  12332 
  12333     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  12334     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  12335 
  12336     const lhs_scalar_ty = lhs_ty.scalarType();
  12337     const rhs_scalar_ty = rhs_ty.scalarType();
  12338     const scalar_tag = resolved_type.scalarType().zigTypeTag();
  12339 
  12340     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  12341 
  12342     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod_rem);
  12343 
  12344     const mod = sema.mod;
  12345     const target = mod.getTarget();
  12346     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs);
  12347     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs);
  12348 
  12349     const runtime_src = rs: {
  12350         // For integers:
  12351         // Either operand being undef is a compile error because there exists
  12352         // a possible value (TODO what is it?) that would invoke illegal behavior.
  12353         // TODO: can lhs undef be handled better?
  12354         //
  12355         // For floats:
  12356         // If the rhs is zero, compile error for division by zero.
  12357         // If the rhs is undefined, compile error because there is a possible
  12358         // value (zero) for which the division would be illegal behavior.
  12359         // If the lhs is undefined, result is undefined.
  12360         //
  12361         // For either one: if the result would be different between @mod and @rem,
  12362         // then emit a compile error saying you have to pick one.
  12363         if (is_int) {
  12364             if (maybe_lhs_val) |lhs_val| {
  12365                 if (lhs_val.isUndef()) {
  12366                     return sema.failWithUseOfUndef(block, lhs_src);
  12367                 }
  12368                 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12369                     return sema.addConstant(resolved_type, Value.zero);
  12370                 }
  12371             } else if (lhs_scalar_ty.isSignedInt()) {
  12372                 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
  12373             }
  12374             if (maybe_rhs_val) |rhs_val| {
  12375                 if (rhs_val.isUndef()) {
  12376                     return sema.failWithUseOfUndef(block, rhs_src);
  12377                 }
  12378                 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12379                     return sema.failWithDivideByZero(block, rhs_src);
  12380                 }
  12381                 if (maybe_lhs_val) |lhs_val| {
  12382                     const rem_result = try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src);
  12383                     // If this answer could possibly be different by doing `intMod`,
  12384                     // we must emit a compile error. Otherwise, it's OK.
  12385                     if ((try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) != (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) and
  12386                         !(try rem_result.compareWithZeroAdvanced(.eq, sema.kit(block, src))))
  12387                     {
  12388                         const bad_src = if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))
  12389                             lhs_src
  12390                         else
  12391                             rhs_src;
  12392                         return sema.failWithModRemNegative(block, bad_src, lhs_ty, rhs_ty);
  12393                     }
  12394                     if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) {
  12395                         // Negative
  12396                         return sema.addConstant(resolved_type, Value.zero);
  12397                     }
  12398                     return sema.addConstant(resolved_type, rem_result);
  12399                 }
  12400                 break :rs lhs_src;
  12401             } else if (rhs_scalar_ty.isSignedInt()) {
  12402                 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
  12403             } else {
  12404                 break :rs rhs_src;
  12405             }
  12406         }
  12407         // float operands
  12408         if (maybe_rhs_val) |rhs_val| {
  12409             if (rhs_val.isUndef()) {
  12410                 return sema.failWithUseOfUndef(block, rhs_src);
  12411             }
  12412             if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12413                 return sema.failWithDivideByZero(block, rhs_src);
  12414             }
  12415             if (try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) {
  12416                 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
  12417             }
  12418             if (maybe_lhs_val) |lhs_val| {
  12419                 if (lhs_val.isUndef() or (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))) {
  12420                     return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
  12421                 }
  12422                 return sema.addConstant(
  12423                     resolved_type,
  12424                     try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
  12425                 );
  12426             } else {
  12427                 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
  12428             }
  12429         } else {
  12430             return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
  12431         }
  12432     };
  12433 
  12434     try sema.requireRuntimeBlock(block, src, runtime_src);
  12435 
  12436     if (block.wantSafety()) {
  12437         try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
  12438     }
  12439 
  12440     const air_tag = airTag(block, is_int, .rem, .rem_optimized);
  12441     return block.addBinOp(air_tag, casted_lhs, casted_rhs);
  12442 }
  12443 
  12444 fn intRem(
  12445     sema: *Sema,
  12446     block: *Block,
  12447     ty: Type,
  12448     lhs: Value,
  12449     lhs_src: LazySrcLoc,
  12450     rhs: Value,
  12451     rhs_src: LazySrcLoc,
  12452 ) CompileError!Value {
  12453     if (ty.zigTypeTag() == .Vector) {
  12454         const result_data = try sema.arena.alloc(Value, ty.vectorLen());
  12455         for (result_data) |*scalar, i| {
  12456             scalar.* = try sema.intRemScalar(block, lhs.indexVectorlike(i), lhs_src, rhs.indexVectorlike(i), rhs_src);
  12457         }
  12458         return Value.Tag.aggregate.create(sema.arena, result_data);
  12459     }
  12460     return sema.intRemScalar(block, lhs, lhs_src, rhs, rhs_src);
  12461 }
  12462 
  12463 fn intRemScalar(
  12464     sema: *Sema,
  12465     block: *Block,
  12466     lhs: Value,
  12467     lhs_src: LazySrcLoc,
  12468     rhs: Value,
  12469     rhs_src: LazySrcLoc,
  12470 ) CompileError!Value {
  12471     const target = sema.mod.getTarget();
  12472     // TODO is this a performance issue? maybe we should try the operation without
  12473     // resorting to BigInt first.
  12474     var lhs_space: Value.BigIntSpace = undefined;
  12475     var rhs_space: Value.BigIntSpace = undefined;
  12476     const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, lhs_src));
  12477     const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, rhs_src));
  12478     const limbs_q = try sema.arena.alloc(
  12479         math.big.Limb,
  12480         lhs_bigint.limbs.len,
  12481     );
  12482     const limbs_r = try sema.arena.alloc(
  12483         math.big.Limb,
  12484         // TODO: consider reworking Sema to re-use Values rather than
  12485         // always producing new Value objects.
  12486         rhs_bigint.limbs.len,
  12487     );
  12488     const limbs_buffer = try sema.arena.alloc(
  12489         math.big.Limb,
  12490         math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
  12491     );
  12492     var result_q = math.big.int.Mutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
  12493     var result_r = math.big.int.Mutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
  12494     result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
  12495     return Value.fromBigInt(sema.arena, result_r.toConst());
  12496 }
  12497 
  12498 fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  12499     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  12500     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  12501     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  12502     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  12503     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  12504     const lhs = try sema.resolveInst(extra.lhs);
  12505     const rhs = try sema.resolveInst(extra.rhs);
  12506     const lhs_ty = sema.typeOf(lhs);
  12507     const rhs_ty = sema.typeOf(rhs);
  12508     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
  12509     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
  12510     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  12511     try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .mod);
  12512 
  12513     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  12514     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  12515         .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
  12516     });
  12517 
  12518     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  12519     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  12520 
  12521     const scalar_tag = resolved_type.scalarType().zigTypeTag();
  12522 
  12523     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  12524 
  12525     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod);
  12526 
  12527     const mod = sema.mod;
  12528     const target = mod.getTarget();
  12529     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs);
  12530     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs);
  12531 
  12532     const runtime_src = rs: {
  12533         // For integers:
  12534         // Either operand being undef is a compile error because there exists
  12535         // a possible value (TODO what is it?) that would invoke illegal behavior.
  12536         // TODO: can lhs zero be handled better?
  12537         // TODO: can lhs undef be handled better?
  12538         //
  12539         // For floats:
  12540         // If the rhs is zero, compile error for division by zero.
  12541         // If the rhs is undefined, compile error because there is a possible
  12542         // value (zero) for which the division would be illegal behavior.
  12543         // If the lhs is undefined, result is undefined.
  12544         if (is_int) {
  12545             if (maybe_lhs_val) |lhs_val| {
  12546                 if (lhs_val.isUndef()) {
  12547                     return sema.failWithUseOfUndef(block, lhs_src);
  12548                 }
  12549             }
  12550             if (maybe_rhs_val) |rhs_val| {
  12551                 if (rhs_val.isUndef()) {
  12552                     return sema.failWithUseOfUndef(block, rhs_src);
  12553                 }
  12554                 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12555                     return sema.failWithDivideByZero(block, rhs_src);
  12556                 }
  12557                 if (maybe_lhs_val) |lhs_val| {
  12558                     return sema.addConstant(
  12559                         resolved_type,
  12560                         try lhs_val.intMod(rhs_val, resolved_type, sema.arena, target),
  12561                     );
  12562                 }
  12563                 break :rs lhs_src;
  12564             } else {
  12565                 break :rs rhs_src;
  12566             }
  12567         }
  12568         // float operands
  12569         if (maybe_rhs_val) |rhs_val| {
  12570             if (rhs_val.isUndef()) {
  12571                 return sema.failWithUseOfUndef(block, rhs_src);
  12572             }
  12573             if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12574                 return sema.failWithDivideByZero(block, rhs_src);
  12575             }
  12576         }
  12577         if (maybe_lhs_val) |lhs_val| {
  12578             if (lhs_val.isUndef()) {
  12579                 return sema.addConstUndef(resolved_type);
  12580             }
  12581             if (maybe_rhs_val) |rhs_val| {
  12582                 return sema.addConstant(
  12583                     resolved_type,
  12584                     try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target),
  12585                 );
  12586             } else break :rs rhs_src;
  12587         } else break :rs lhs_src;
  12588     };
  12589 
  12590     try sema.requireRuntimeBlock(block, src, runtime_src);
  12591 
  12592     if (block.wantSafety()) {
  12593         try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
  12594     }
  12595 
  12596     const air_tag = airTag(block, is_int, .mod, .mod_optimized);
  12597     return block.addBinOp(air_tag, casted_lhs, casted_rhs);
  12598 }
  12599 
  12600 fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  12601     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  12602     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  12603     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  12604     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  12605     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  12606     const lhs = try sema.resolveInst(extra.lhs);
  12607     const rhs = try sema.resolveInst(extra.rhs);
  12608     const lhs_ty = sema.typeOf(lhs);
  12609     const rhs_ty = sema.typeOf(rhs);
  12610     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
  12611     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
  12612     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  12613     try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .rem);
  12614 
  12615     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  12616     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  12617         .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
  12618     });
  12619 
  12620     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  12621     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  12622 
  12623     const scalar_tag = resolved_type.scalarType().zigTypeTag();
  12624 
  12625     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  12626 
  12627     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .rem);
  12628 
  12629     const mod = sema.mod;
  12630     const target = mod.getTarget();
  12631     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs);
  12632     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs);
  12633 
  12634     const runtime_src = rs: {
  12635         // For integers:
  12636         // Either operand being undef is a compile error because there exists
  12637         // a possible value (TODO what is it?) that would invoke illegal behavior.
  12638         // TODO: can lhs zero be handled better?
  12639         // TODO: can lhs undef be handled better?
  12640         //
  12641         // For floats:
  12642         // If the rhs is zero, compile error for division by zero.
  12643         // If the rhs is undefined, compile error because there is a possible
  12644         // value (zero) for which the division would be illegal behavior.
  12645         // If the lhs is undefined, result is undefined.
  12646         if (is_int) {
  12647             if (maybe_lhs_val) |lhs_val| {
  12648                 if (lhs_val.isUndef()) {
  12649                     return sema.failWithUseOfUndef(block, lhs_src);
  12650                 }
  12651             }
  12652             if (maybe_rhs_val) |rhs_val| {
  12653                 if (rhs_val.isUndef()) {
  12654                     return sema.failWithUseOfUndef(block, rhs_src);
  12655                 }
  12656                 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12657                     return sema.failWithDivideByZero(block, rhs_src);
  12658                 }
  12659                 if (maybe_lhs_val) |lhs_val| {
  12660                     return sema.addConstant(
  12661                         resolved_type,
  12662                         try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src),
  12663                     );
  12664                 }
  12665                 break :rs lhs_src;
  12666             } else {
  12667                 break :rs rhs_src;
  12668             }
  12669         }
  12670         // float operands
  12671         if (maybe_rhs_val) |rhs_val| {
  12672             if (rhs_val.isUndef()) {
  12673                 return sema.failWithUseOfUndef(block, rhs_src);
  12674             }
  12675             if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12676                 return sema.failWithDivideByZero(block, rhs_src);
  12677             }
  12678         }
  12679         if (maybe_lhs_val) |lhs_val| {
  12680             if (lhs_val.isUndef()) {
  12681                 return sema.addConstUndef(resolved_type);
  12682             }
  12683             if (maybe_rhs_val) |rhs_val| {
  12684                 return sema.addConstant(
  12685                     resolved_type,
  12686                     try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
  12687                 );
  12688             } else break :rs rhs_src;
  12689         } else break :rs lhs_src;
  12690     };
  12691 
  12692     try sema.requireRuntimeBlock(block, src, runtime_src);
  12693 
  12694     if (block.wantSafety()) {
  12695         try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
  12696     }
  12697 
  12698     const air_tag = airTag(block, is_int, .rem, .rem_optimized);
  12699     return block.addBinOp(air_tag, casted_lhs, casted_rhs);
  12700 }
  12701 
  12702 fn zirOverflowArithmetic(
  12703     sema: *Sema,
  12704     block: *Block,
  12705     extended: Zir.Inst.Extended.InstData,
  12706     zir_tag: Zir.Inst.Extended,
  12707 ) CompileError!Air.Inst.Ref {
  12708     const tracy = trace(@src());
  12709     defer tracy.end();
  12710 
  12711     const extra = sema.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data;
  12712     const src = LazySrcLoc.nodeOffset(extra.node);
  12713 
  12714     const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  12715     const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  12716     const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node };
  12717 
  12718     const lhs = try sema.resolveInst(extra.lhs);
  12719     const rhs = try sema.resolveInst(extra.rhs);
  12720     const ptr = try sema.resolveInst(extra.ptr);
  12721 
  12722     const lhs_ty = sema.typeOf(lhs);
  12723     const rhs_ty = sema.typeOf(rhs);
  12724     const mod = sema.mod;
  12725     const target = mod.getTarget();
  12726 
  12727     // Note, the types of lhs/rhs (also for shifting)/ptr are already correct as ensured by astgen.
  12728     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  12729     const dest_ty = lhs_ty;
  12730     if (dest_ty.scalarType().zigTypeTag() != .Int) {
  12731         return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(mod)});
  12732     }
  12733 
  12734     const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);
  12735     const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs);
  12736 
  12737     const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty);
  12738     const ov_ty = tuple_ty.tupleFields().types[1];
  12739     // TODO: Remove and use `ov_ty` instead.
  12740     //       This is a temporary type used until overflow arithmetic properly returns `u1` instead of `bool`.
  12741     const overflowed_ty = if (dest_ty.zigTypeTag() == .Vector) try Type.vector(sema.arena, dest_ty.vectorLen(), Type.@"bool") else Type.@"bool";
  12742 
  12743     const result: struct {
  12744         /// TODO: Rename to `overflow_bit` and make of type `u1`.
  12745         overflowed: Air.Inst.Ref,
  12746         wrapped: Air.Inst.Ref,
  12747     } = result: {
  12748         switch (zir_tag) {
  12749             .add_with_overflow => {
  12750                 // If either of the arguments is zero, `false` is returned and the other is stored
  12751                 // to the result, even if it is undefined..
  12752                 // Otherwise, if either of the argument is undefined, undefined is returned.
  12753                 if (maybe_lhs_val) |lhs_val| {
  12754                     if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
  12755                         break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
  12756                     }
  12757                 }
  12758                 if (maybe_rhs_val) |rhs_val| {
  12759                     if (!rhs_val.isUndef() and (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
  12760                         break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
  12761                     }
  12762                 }
  12763                 if (maybe_lhs_val) |lhs_val| {
  12764                     if (maybe_rhs_val) |rhs_val| {
  12765                         if (lhs_val.isUndef() or rhs_val.isUndef()) {
  12766                             break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
  12767                         }
  12768 
  12769                         const result = try sema.intAddWithOverflow(block, src, lhs_val, rhs_val, dest_ty);
  12770                         const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);
  12771                         const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
  12772                         break :result .{ .overflowed = overflowed, .wrapped = wrapped };
  12773                     }
  12774                 }
  12775             },
  12776             .sub_with_overflow => {
  12777                 // If the rhs is zero, then the result is lhs and no overflow occured.
  12778                 // Otherwise, if either result is undefined, both results are undefined.
  12779                 if (maybe_rhs_val) |rhs_val| {
  12780                     if (rhs_val.isUndef()) {
  12781                         break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
  12782                     } else if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12783                         break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
  12784                     } else if (maybe_lhs_val) |lhs_val| {
  12785                         if (lhs_val.isUndef()) {
  12786                             break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
  12787                         }
  12788 
  12789                         const result = try sema.intSubWithOverflow(block, src, lhs_val, rhs_val, dest_ty);
  12790                         const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);
  12791                         const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
  12792                         break :result .{ .overflowed = overflowed, .wrapped = wrapped };
  12793                     }
  12794                 }
  12795             },
  12796             .mul_with_overflow => {
  12797                 // If either of the arguments is zero, the result is zero and no overflow occured.
  12798                 // If either of the arguments is one, the result is the other and no overflow occured.
  12799                 // Otherwise, if either of the arguments is undefined, both results are undefined.
  12800                 if (maybe_lhs_val) |lhs_val| {
  12801                     if (!lhs_val.isUndef()) {
  12802                         if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12803                             break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
  12804                         } else if (try sema.compare(block, src, lhs_val, .eq, Value.one, dest_ty)) {
  12805                             break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
  12806                         }
  12807                     }
  12808                 }
  12809 
  12810                 if (maybe_rhs_val) |rhs_val| {
  12811                     if (!rhs_val.isUndef()) {
  12812                         if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12813                             break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
  12814                         } else if (try sema.compare(block, src, rhs_val, .eq, Value.one, dest_ty)) {
  12815                             break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
  12816                         }
  12817                     }
  12818                 }
  12819 
  12820                 if (maybe_lhs_val) |lhs_val| {
  12821                     if (maybe_rhs_val) |rhs_val| {
  12822                         if (lhs_val.isUndef() or rhs_val.isUndef()) {
  12823                             break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
  12824                         }
  12825 
  12826                         const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, target);
  12827                         const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);
  12828                         const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
  12829                         break :result .{ .overflowed = overflowed, .wrapped = wrapped };
  12830                     }
  12831                 }
  12832             },
  12833             .shl_with_overflow => {
  12834                 // If lhs is zero, the result is zero and no overflow occurred.
  12835                 // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred.
  12836                 // Oterhwise if either of the arguments is undefined, both results are undefined.
  12837                 if (maybe_lhs_val) |lhs_val| {
  12838                     if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
  12839                         break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
  12840                     }
  12841                 }
  12842                 if (maybe_rhs_val) |rhs_val| {
  12843                     if (!rhs_val.isUndef() and (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
  12844                         break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
  12845                     }
  12846                 }
  12847                 if (maybe_lhs_val) |lhs_val| {
  12848                     if (maybe_rhs_val) |rhs_val| {
  12849                         if (lhs_val.isUndef() or rhs_val.isUndef()) {
  12850                             break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
  12851                         }
  12852 
  12853                         const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, target);
  12854                         const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);
  12855                         const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
  12856                         break :result .{ .overflowed = overflowed, .wrapped = wrapped };
  12857                     }
  12858                 }
  12859             },
  12860             else => unreachable,
  12861         }
  12862 
  12863         const air_tag: Air.Inst.Tag = switch (zir_tag) {
  12864             .add_with_overflow => .add_with_overflow,
  12865             .mul_with_overflow => .mul_with_overflow,
  12866             .sub_with_overflow => .sub_with_overflow,
  12867             .shl_with_overflow => .shl_with_overflow,
  12868             else => unreachable,
  12869         };
  12870 
  12871         const runtime_src = if (maybe_lhs_val == null) lhs_src else rhs_src;
  12872         try sema.requireRuntimeBlock(block, src, runtime_src);
  12873 
  12874         const tuple = try block.addInst(.{
  12875             .tag = air_tag,
  12876             .data = .{ .ty_pl = .{
  12877                 .ty = try block.sema.addType(tuple_ty),
  12878                 .payload = try block.sema.addExtra(Air.Bin{
  12879                     .lhs = lhs,
  12880                     .rhs = rhs,
  12881                 }),
  12882             } },
  12883         });
  12884 
  12885         const wrapped = try sema.tupleFieldValByIndex(block, src, tuple, 0, tuple_ty);
  12886         try sema.storePtr2(block, src, ptr, ptr_src, wrapped, src, .store);
  12887 
  12888         const overflow_bit = try sema.tupleFieldValByIndex(block, src, tuple, 1, tuple_ty);
  12889         const zero_ov_val = if (dest_ty.zigTypeTag() == .Vector) try Value.Tag.repeated.create(sema.arena, Value.zero) else Value.zero;
  12890         const zero_ov = try sema.addConstant(ov_ty, zero_ov_val);
  12891 
  12892         const overflowed_inst = if (dest_ty.zigTypeTag() == .Vector)
  12893             block.addCmpVector(overflow_bit, .zero, .neq, try sema.addType(ov_ty))
  12894         else
  12895             block.addBinOp(.cmp_neq, overflow_bit, zero_ov);
  12896         return overflowed_inst;
  12897     };
  12898 
  12899     try sema.storePtr2(block, src, ptr, ptr_src, result.wrapped, src, .store);
  12900     return result.overflowed;
  12901 }
  12902 
  12903 fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type {
  12904     const ov_ty = if (ty.zigTypeTag() == .Vector) try Type.vector(sema.arena, ty.vectorLen(), Type.@"u1") else Type.@"u1";
  12905 
  12906     const types = try sema.arena.alloc(Type, 2);
  12907     const values = try sema.arena.alloc(Value, 2);
  12908     const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{
  12909         .types = types,
  12910         .values = values,
  12911     });
  12912 
  12913     types[0] = ty;
  12914     types[1] = ov_ty;
  12915     values[0] = Value.initTag(.unreachable_value);
  12916     values[1] = Value.initTag(.unreachable_value);
  12917 
  12918     return tuple_ty;
  12919 }
  12920 
  12921 fn analyzeArithmetic(
  12922     sema: *Sema,
  12923     block: *Block,
  12924     /// TODO performance investigation: make this comptime?
  12925     zir_tag: Zir.Inst.Tag,
  12926     lhs: Air.Inst.Ref,
  12927     rhs: Air.Inst.Ref,
  12928     src: LazySrcLoc,
  12929     lhs_src: LazySrcLoc,
  12930     rhs_src: LazySrcLoc,
  12931 ) CompileError!Air.Inst.Ref {
  12932     const lhs_ty = sema.typeOf(lhs);
  12933     const rhs_ty = sema.typeOf(rhs);
  12934     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
  12935     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
  12936     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  12937 
  12938     if (lhs_zig_ty_tag == .Pointer) switch (lhs_ty.ptrSize()) {
  12939         .One, .Slice => {},
  12940         .Many, .C => {
  12941             const air_tag: Air.Inst.Tag = switch (zir_tag) {
  12942                 .add => .ptr_add,
  12943                 .sub => .ptr_sub,
  12944                 else => return sema.fail(
  12945                     block,
  12946                     src,
  12947                     "invalid pointer arithmetic operand: '{s}''",
  12948                     .{@tagName(zir_tag)},
  12949                 ),
  12950             };
  12951             return analyzePtrArithmetic(sema, block, src, lhs, rhs, air_tag, lhs_src, rhs_src);
  12952         },
  12953     };
  12954 
  12955     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  12956     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  12957         .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
  12958     });
  12959 
  12960     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  12961     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  12962 
  12963     const scalar_tag = resolved_type.scalarType().zigTypeTag();
  12964 
  12965     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  12966 
  12967     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, zir_tag);
  12968 
  12969     const mod = sema.mod;
  12970     const target = mod.getTarget();
  12971     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs);
  12972     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs);
  12973     const rs: struct { src: LazySrcLoc, air_tag: Air.Inst.Tag } = rs: {
  12974         switch (zir_tag) {
  12975             .add => {
  12976                 // For integers:
  12977                 // If either of the operands are zero, then the other operand is
  12978                 // returned, even if it is undefined.
  12979                 // If either of the operands are undefined, it's a compile error
  12980                 // because there is a possible value for which the addition would
  12981                 // overflow (max_int), causing illegal behavior.
  12982                 // For floats: either operand being undef makes the result undef.
  12983                 if (maybe_lhs_val) |lhs_val| {
  12984                     if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
  12985                         return casted_rhs;
  12986                     }
  12987                 }
  12988                 if (maybe_rhs_val) |rhs_val| {
  12989                     if (rhs_val.isUndef()) {
  12990                         if (is_int) {
  12991                             return sema.failWithUseOfUndef(block, rhs_src);
  12992                         } else {
  12993                             return sema.addConstUndef(resolved_type);
  12994                         }
  12995                     }
  12996                     if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  12997                         return casted_lhs;
  12998                     }
  12999                 }
  13000                 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .add_optimized else .add;
  13001                 if (maybe_lhs_val) |lhs_val| {
  13002                     if (lhs_val.isUndef()) {
  13003                         if (is_int) {
  13004                             return sema.failWithUseOfUndef(block, lhs_src);
  13005                         } else {
  13006                             return sema.addConstUndef(resolved_type);
  13007                         }
  13008                     }
  13009                     if (maybe_rhs_val) |rhs_val| {
  13010                         if (is_int) {
  13011                             const sum = try sema.intAdd(block, src, lhs_val, rhs_val, resolved_type);
  13012                             var vector_index: usize = undefined;
  13013                             if (!(try sema.intFitsInType(block, src, sum, resolved_type, &vector_index))) {
  13014                                 return sema.failWithIntegerOverflow(block, src, resolved_type, sum, vector_index);
  13015                             }
  13016                             return sema.addConstant(resolved_type, sum);
  13017                         } else {
  13018                             return sema.addConstant(
  13019                                 resolved_type,
  13020                                 try sema.floatAdd(lhs_val, rhs_val, resolved_type),
  13021                             );
  13022                         }
  13023                     } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
  13024                 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
  13025             },
  13026             .addwrap => {
  13027                 // Integers only; floats are checked above.
  13028                 // If either of the operands are zero, the other operand is returned.
  13029                 // If either of the operands are undefined, the result is undefined.
  13030                 if (maybe_lhs_val) |lhs_val| {
  13031                     if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
  13032                         return casted_rhs;
  13033                     }
  13034                 }
  13035                 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .addwrap_optimized else .addwrap;
  13036                 if (maybe_rhs_val) |rhs_val| {
  13037                     if (rhs_val.isUndef()) {
  13038                         return sema.addConstUndef(resolved_type);
  13039                     }
  13040                     if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  13041                         return casted_lhs;
  13042                     }
  13043                     if (maybe_lhs_val) |lhs_val| {
  13044                         return sema.addConstant(
  13045                             resolved_type,
  13046                             try sema.numberAddWrap(block, src, lhs_val, rhs_val, resolved_type),
  13047                         );
  13048                     } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
  13049                 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
  13050             },
  13051             .add_sat => {
  13052                 // Integers only; floats are checked above.
  13053                 // If either of the operands are zero, then the other operand is returned.
  13054                 // If either of the operands are undefined, the result is undefined.
  13055                 if (maybe_lhs_val) |lhs_val| {
  13056                     if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
  13057                         return casted_rhs;
  13058                     }
  13059                 }
  13060                 if (maybe_rhs_val) |rhs_val| {
  13061                     if (rhs_val.isUndef()) {
  13062                         return sema.addConstUndef(resolved_type);
  13063                     }
  13064                     if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  13065                         return casted_lhs;
  13066                     }
  13067                     if (maybe_lhs_val) |lhs_val| {
  13068                         const val = if (scalar_tag == .ComptimeInt)
  13069                             try sema.intAdd(block, src, lhs_val, rhs_val, resolved_type)
  13070                         else
  13071                             try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, target);
  13072 
  13073                         return sema.addConstant(resolved_type, val);
  13074                     } else break :rs .{ .src = lhs_src, .air_tag = .add_sat };
  13075                 } else break :rs .{ .src = rhs_src, .air_tag = .add_sat };
  13076             },
  13077             .sub => {
  13078                 // For integers:
  13079                 // If the rhs is zero, then the other operand is
  13080                 // returned, even if it is undefined.
  13081                 // If either of the operands are undefined, it's a compile error
  13082                 // because there is a possible value for which the subtraction would
  13083                 // overflow, causing illegal behavior.
  13084                 // For floats: either operand being undef makes the result undef.
  13085                 if (maybe_rhs_val) |rhs_val| {
  13086                     if (rhs_val.isUndef()) {
  13087                         if (is_int) {
  13088                             return sema.failWithUseOfUndef(block, rhs_src);
  13089                         } else {
  13090                             return sema.addConstUndef(resolved_type);
  13091                         }
  13092                     }
  13093                     if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  13094                         return casted_lhs;
  13095                     }
  13096                 }
  13097                 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .sub_optimized else .sub;
  13098                 if (maybe_lhs_val) |lhs_val| {
  13099                     if (lhs_val.isUndef()) {
  13100                         if (is_int) {
  13101                             return sema.failWithUseOfUndef(block, lhs_src);
  13102                         } else {
  13103                             return sema.addConstUndef(resolved_type);
  13104                         }
  13105                     }
  13106                     if (maybe_rhs_val) |rhs_val| {
  13107                         if (is_int) {
  13108                             const diff = try sema.intSub(block, src, lhs_val, rhs_val, resolved_type);
  13109                             var vector_index: usize = undefined;
  13110                             if (!(try sema.intFitsInType(block, src, diff, resolved_type, &vector_index))) {
  13111                                 return sema.failWithIntegerOverflow(block, src, resolved_type, diff, vector_index);
  13112                             }
  13113                             return sema.addConstant(resolved_type, diff);
  13114                         } else {
  13115                             return sema.addConstant(
  13116                                 resolved_type,
  13117                                 try sema.floatSub(lhs_val, rhs_val, resolved_type),
  13118                             );
  13119                         }
  13120                     } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
  13121                 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
  13122             },
  13123             .subwrap => {
  13124                 // Integers only; floats are checked above.
  13125                 // If the RHS is zero, then the other operand is returned, even if it is undefined.
  13126                 // If either of the operands are undefined, the result is undefined.
  13127                 if (maybe_rhs_val) |rhs_val| {
  13128                     if (rhs_val.isUndef()) {
  13129                         return sema.addConstUndef(resolved_type);
  13130                     }
  13131                     if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  13132                         return casted_lhs;
  13133                     }
  13134                 }
  13135                 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .subwrap_optimized else .subwrap;
  13136                 if (maybe_lhs_val) |lhs_val| {
  13137                     if (lhs_val.isUndef()) {
  13138                         return sema.addConstUndef(resolved_type);
  13139                     }
  13140                     if (maybe_rhs_val) |rhs_val| {
  13141                         return sema.addConstant(
  13142                             resolved_type,
  13143                             try sema.numberSubWrap(block, src, lhs_val, rhs_val, resolved_type),
  13144                         );
  13145                     } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
  13146                 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
  13147             },
  13148             .sub_sat => {
  13149                 // Integers only; floats are checked above.
  13150                 // If the RHS is zero, result is LHS.
  13151                 // If either of the operands are undefined, result is undefined.
  13152                 if (maybe_rhs_val) |rhs_val| {
  13153                     if (rhs_val.isUndef()) {
  13154                         return sema.addConstUndef(resolved_type);
  13155                     }
  13156                     if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  13157                         return casted_lhs;
  13158                     }
  13159                 }
  13160                 if (maybe_lhs_val) |lhs_val| {
  13161                     if (lhs_val.isUndef()) {
  13162                         return sema.addConstUndef(resolved_type);
  13163                     }
  13164                     if (maybe_rhs_val) |rhs_val| {
  13165                         const val = if (scalar_tag == .ComptimeInt)
  13166                             try sema.intSub(block, src, lhs_val, rhs_val, resolved_type)
  13167                         else
  13168                             try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, target);
  13169 
  13170                         return sema.addConstant(resolved_type, val);
  13171                     } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat };
  13172                 } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat };
  13173             },
  13174             .mul => {
  13175                 // For integers:
  13176                 // If either of the operands are zero, the result is zero.
  13177                 // If either of the operands are one, the result is the other
  13178                 // operand, even if it is undefined.
  13179                 // If either of the operands are undefined, it's a compile error
  13180                 // because there is a possible value for which the addition would
  13181                 // overflow (max_int), causing illegal behavior.
  13182                 // For floats: either operand being undef makes the result undef.
  13183                 if (maybe_lhs_val) |lhs_val| {
  13184                     if (!lhs_val.isUndef()) {
  13185                         if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  13186                             return sema.addConstant(resolved_type, Value.zero);
  13187                         }
  13188                         if (try sema.compare(block, src, lhs_val, .eq, Value.one, resolved_type)) {
  13189                             return casted_rhs;
  13190                         }
  13191                     }
  13192                 }
  13193                 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mul_optimized else .mul;
  13194                 if (maybe_rhs_val) |rhs_val| {
  13195                     if (rhs_val.isUndef()) {
  13196                         if (is_int) {
  13197                             return sema.failWithUseOfUndef(block, rhs_src);
  13198                         } else {
  13199                             return sema.addConstUndef(resolved_type);
  13200                         }
  13201                     }
  13202                     if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  13203                         return sema.addConstant(resolved_type, Value.zero);
  13204                     }
  13205                     if (try sema.compare(block, src, rhs_val, .eq, Value.one, resolved_type)) {
  13206                         return casted_lhs;
  13207                     }
  13208                     if (maybe_lhs_val) |lhs_val| {
  13209                         if (lhs_val.isUndef()) {
  13210                             if (is_int) {
  13211                                 return sema.failWithUseOfUndef(block, lhs_src);
  13212                             } else {
  13213                                 return sema.addConstUndef(resolved_type);
  13214                             }
  13215                         }
  13216                         if (is_int) {
  13217                             const product = try lhs_val.intMul(rhs_val, resolved_type, sema.arena, target);
  13218                             var vector_index: usize = undefined;
  13219                             if (!(try sema.intFitsInType(block, src, product, resolved_type, &vector_index))) {
  13220                                 return sema.failWithIntegerOverflow(block, src, resolved_type, product, vector_index);
  13221                             }
  13222                             return sema.addConstant(resolved_type, product);
  13223                         } else {
  13224                             return sema.addConstant(
  13225                                 resolved_type,
  13226                                 try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, target),
  13227                             );
  13228                         }
  13229                     } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
  13230                 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
  13231             },
  13232             .mulwrap => {
  13233                 // Integers only; floats are handled above.
  13234                 // If either of the operands are zero, result is zero.
  13235                 // If either of the operands are one, result is the other operand.
  13236                 // If either of the operands are undefined, result is undefined.
  13237                 if (maybe_lhs_val) |lhs_val| {
  13238                     if (!lhs_val.isUndef()) {
  13239                         if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  13240                             return sema.addConstant(resolved_type, Value.zero);
  13241                         }
  13242                         if (try sema.compare(block, src, lhs_val, .eq, Value.one, resolved_type)) {
  13243                             return casted_rhs;
  13244                         }
  13245                     }
  13246                 }
  13247                 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mulwrap_optimized else .mulwrap;
  13248                 if (maybe_rhs_val) |rhs_val| {
  13249                     if (rhs_val.isUndef()) {
  13250                         return sema.addConstUndef(resolved_type);
  13251                     }
  13252                     if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  13253                         return sema.addConstant(resolved_type, Value.zero);
  13254                     }
  13255                     if (try sema.compare(block, src, rhs_val, .eq, Value.one, resolved_type)) {
  13256                         return casted_lhs;
  13257                     }
  13258                     if (maybe_lhs_val) |lhs_val| {
  13259                         if (lhs_val.isUndef()) {
  13260                             return sema.addConstUndef(resolved_type);
  13261                         }
  13262                         return sema.addConstant(
  13263                             resolved_type,
  13264                             try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, target),
  13265                         );
  13266                     } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
  13267                 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
  13268             },
  13269             .mul_sat => {
  13270                 // Integers only; floats are checked above.
  13271                 // If either of the operands are zero, result is zero.
  13272                 // If either of the operands are one, result is the other operand.
  13273                 // If either of the operands are undefined, result is undefined.
  13274                 if (maybe_lhs_val) |lhs_val| {
  13275                     if (!lhs_val.isUndef()) {
  13276                         if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  13277                             return sema.addConstant(resolved_type, Value.zero);
  13278                         }
  13279                         if (try sema.compare(block, src, lhs_val, .eq, Value.one, resolved_type)) {
  13280                             return casted_rhs;
  13281                         }
  13282                     }
  13283                 }
  13284                 if (maybe_rhs_val) |rhs_val| {
  13285                     if (rhs_val.isUndef()) {
  13286                         return sema.addConstUndef(resolved_type);
  13287                     }
  13288                     if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
  13289                         return sema.addConstant(resolved_type, Value.zero);
  13290                     }
  13291                     if (try sema.compare(block, src, rhs_val, .eq, Value.one, resolved_type)) {
  13292                         return casted_lhs;
  13293                     }
  13294                     if (maybe_lhs_val) |lhs_val| {
  13295                         if (lhs_val.isUndef()) {
  13296                             return sema.addConstUndef(resolved_type);
  13297                         }
  13298 
  13299                         const val = if (scalar_tag == .ComptimeInt)
  13300                             try lhs_val.intMul(rhs_val, resolved_type, sema.arena, target)
  13301                         else
  13302                             try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, target);
  13303 
  13304                         return sema.addConstant(resolved_type, val);
  13305                     } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat };
  13306                 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat };
  13307             },
  13308             else => unreachable,
  13309         }
  13310     };
  13311 
  13312     try sema.requireRuntimeBlock(block, src, rs.src);
  13313     if (block.wantSafety()) {
  13314         if (scalar_tag == .Int) {
  13315             const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) {
  13316                 .add => .add_with_overflow,
  13317                 .sub => .sub_with_overflow,
  13318                 .mul => .mul_with_overflow,
  13319                 else => null,
  13320             };
  13321             if (maybe_op_ov) |op_ov_tag| {
  13322                 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(resolved_type);
  13323                 const op_ov = try block.addInst(.{
  13324                     .tag = op_ov_tag,
  13325                     .data = .{ .ty_pl = .{
  13326                         .ty = try sema.addType(op_ov_tuple_ty),
  13327                         .payload = try sema.addExtra(Air.Bin{
  13328                             .lhs = casted_lhs,
  13329                             .rhs = casted_rhs,
  13330                         }),
  13331                     } },
  13332                 });
  13333                 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
  13334                 const any_ov_bit = if (resolved_type.zigTypeTag() == .Vector)
  13335                     try block.addInst(.{
  13336                         .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
  13337                         .data = .{ .reduce = .{
  13338                             .operand = ov_bit,
  13339                             .operation = .Or,
  13340                         } },
  13341                     })
  13342                 else
  13343                     ov_bit;
  13344                 const zero_ov = try sema.addConstant(Type.@"u1", Value.zero);
  13345                 const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
  13346 
  13347                 try sema.addSafetyCheck(block, no_ov, .integer_overflow);
  13348                 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
  13349             }
  13350         }
  13351     }
  13352     return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs);
  13353 }
  13354 
  13355 fn analyzePtrArithmetic(
  13356     sema: *Sema,
  13357     block: *Block,
  13358     op_src: LazySrcLoc,
  13359     ptr: Air.Inst.Ref,
  13360     uncasted_offset: Air.Inst.Ref,
  13361     air_tag: Air.Inst.Tag,
  13362     ptr_src: LazySrcLoc,
  13363     offset_src: LazySrcLoc,
  13364 ) CompileError!Air.Inst.Ref {
  13365     // TODO if the operand is comptime-known to be negative, or is a negative int,
  13366     // coerce to isize instead of usize.
  13367     const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src);
  13368     const target = sema.mod.getTarget();
  13369     const opt_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, ptr);
  13370     const opt_off_val = try sema.resolveDefinedValue(block, offset_src, offset);
  13371     const ptr_ty = sema.typeOf(ptr);
  13372     const ptr_info = ptr_ty.ptrInfo().data;
  13373     const elem_ty = if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Array)
  13374         ptr_info.pointee_type.childType()
  13375     else
  13376         ptr_info.pointee_type;
  13377 
  13378     const new_ptr_ty = t: {
  13379         // Calculate the new pointer alignment.
  13380         // This code is duplicated in `elemPtrType`.
  13381         if (ptr_info.@"align" == 0) {
  13382             // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness.
  13383             break :t ptr_ty;
  13384         }
  13385         // If the addend is not a comptime-known value we can still count on
  13386         // it being a multiple of the type size.
  13387         const elem_size = elem_ty.abiSize(target);
  13388         const addend = if (opt_off_val) |off_val| a: {
  13389             const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(target));
  13390             break :a elem_size * off_int;
  13391         } else elem_size;
  13392 
  13393         // The resulting pointer is aligned to the lcd between the offset (an
  13394         // arbitrary number) and the alignment factor (always a power of two,
  13395         // non zero).
  13396         const new_align = @as(u32, 1) << @intCast(u5, @ctz(addend | ptr_info.@"align"));
  13397 
  13398         break :t try Type.ptr(sema.arena, sema.mod, .{
  13399             .pointee_type = ptr_info.pointee_type,
  13400             .sentinel = ptr_info.sentinel,
  13401             .@"align" = new_align,
  13402             .@"addrspace" = ptr_info.@"addrspace",
  13403             .mutable = ptr_info.mutable,
  13404             .@"allowzero" = ptr_info.@"allowzero",
  13405             .@"volatile" = ptr_info.@"volatile",
  13406             .size = ptr_info.size,
  13407         });
  13408     };
  13409 
  13410     const runtime_src = rs: {
  13411         if (opt_ptr_val) |ptr_val| {
  13412             if (opt_off_val) |offset_val| {
  13413                 if (ptr_val.isUndef()) return sema.addConstUndef(new_ptr_ty);
  13414 
  13415                 const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(target));
  13416                 if (offset_int == 0) return ptr;
  13417                 if (try ptr_val.getUnsignedIntAdvanced(target, sema.kit(block, ptr_src))) |addr| {
  13418                     const elem_size = elem_ty.abiSize(target);
  13419                     const new_addr = switch (air_tag) {
  13420                         .ptr_add => addr + elem_size * offset_int,
  13421                         .ptr_sub => addr - elem_size * offset_int,
  13422                         else => unreachable,
  13423                     };
  13424                     const new_ptr_val = try Value.Tag.int_u64.create(sema.arena, new_addr);
  13425                     return sema.addConstant(new_ptr_ty, new_ptr_val);
  13426                 }
  13427                 if (air_tag == .ptr_sub) {
  13428                     return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{});
  13429                 }
  13430                 const new_ptr_val = try ptr_val.elemPtr(ptr_ty, sema.arena, offset_int, sema.mod);
  13431                 return sema.addConstant(new_ptr_ty, new_ptr_val);
  13432             } else break :rs offset_src;
  13433         } else break :rs ptr_src;
  13434     };
  13435 
  13436     try sema.requireRuntimeBlock(block, op_src, runtime_src);
  13437     return block.addInst(.{
  13438         .tag = air_tag,
  13439         .data = .{ .ty_pl = .{
  13440             .ty = try sema.addType(new_ptr_ty),
  13441             .payload = try sema.addExtra(Air.Bin{
  13442                 .lhs = ptr,
  13443                 .rhs = offset,
  13444             }),
  13445         } },
  13446     });
  13447 }
  13448 
  13449 fn zirLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  13450     const tracy = trace(@src());
  13451     defer tracy.end();
  13452 
  13453     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  13454     const src = inst_data.src();
  13455     const ptr_src = src; // TODO better source location
  13456     const ptr = try sema.resolveInst(inst_data.operand);
  13457     return sema.analyzeLoad(block, src, ptr, ptr_src);
  13458 }
  13459 
  13460 fn zirAsm(
  13461     sema: *Sema,
  13462     block: *Block,
  13463     extended: Zir.Inst.Extended.InstData,
  13464 ) CompileError!Air.Inst.Ref {
  13465     const tracy = trace(@src());
  13466     defer tracy.end();
  13467 
  13468     const extra = sema.code.extraData(Zir.Inst.Asm, extended.operand);
  13469     const src = LazySrcLoc.nodeOffset(extra.data.src_node);
  13470     const ret_ty_src: LazySrcLoc = .{ .node_offset_asm_ret_ty = extra.data.src_node };
  13471     const outputs_len = @truncate(u5, extended.small);
  13472     const inputs_len = @truncate(u5, extended.small >> 5);
  13473     const clobbers_len = @truncate(u5, extended.small >> 10);
  13474     const is_volatile = @truncate(u1, extended.small >> 15) != 0;
  13475     const is_global_assembly = sema.func == null;
  13476 
  13477     if (extra.data.asm_source == 0) {
  13478         // This can move to become an AstGen error after inline assembly improvements land
  13479         // and stage1 code matches stage2 code.
  13480         return sema.fail(block, src, "assembly code must use string literal syntax", .{});
  13481     }
  13482 
  13483     const asm_source = sema.code.nullTerminatedString(extra.data.asm_source);
  13484 
  13485     if (is_global_assembly) {
  13486         if (outputs_len != 0) {
  13487             return sema.fail(block, src, "module-level assembly does not support outputs", .{});
  13488         }
  13489         if (inputs_len != 0) {
  13490             return sema.fail(block, src, "module-level assembly does not support inputs", .{});
  13491         }
  13492         if (clobbers_len != 0) {
  13493             return sema.fail(block, src, "module-level assembly does not support clobbers", .{});
  13494         }
  13495         if (is_volatile) {
  13496             return sema.fail(block, src, "volatile keyword is redundant on module-level assembly", .{});
  13497         }
  13498         try sema.mod.addGlobalAssembly(sema.owner_decl_index, asm_source);
  13499         return Air.Inst.Ref.void_value;
  13500     }
  13501 
  13502     if (block.is_comptime) {
  13503         try sema.requireRuntimeBlock(block, src, null);
  13504     }
  13505 
  13506     var extra_i = extra.end;
  13507     var output_type_bits = extra.data.output_type_bits;
  13508     var needed_capacity: usize = @typeInfo(Air.Asm).Struct.fields.len + outputs_len + inputs_len;
  13509 
  13510     const ConstraintName = struct { c: []const u8, n: []const u8 };
  13511     const out_args = try sema.arena.alloc(Air.Inst.Ref, outputs_len);
  13512     const outputs = try sema.arena.alloc(ConstraintName, outputs_len);
  13513     var expr_ty = Air.Inst.Ref.void_type;
  13514 
  13515     for (out_args) |*arg, out_i| {
  13516         const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i);
  13517         extra_i = output.end;
  13518 
  13519         const is_type = @truncate(u1, output_type_bits) != 0;
  13520         output_type_bits >>= 1;
  13521 
  13522         if (is_type) {
  13523             // Indicate the output is the asm instruction return value.
  13524             arg.* = .none;
  13525             const out_ty = try sema.resolveType(block, ret_ty_src, output.data.operand);
  13526             try sema.queueFullTypeResolution(out_ty);
  13527             expr_ty = try sema.addType(out_ty);
  13528         } else {
  13529             arg.* = try sema.resolveInst(output.data.operand);
  13530         }
  13531 
  13532         const constraint = sema.code.nullTerminatedString(output.data.constraint);
  13533         const name = sema.code.nullTerminatedString(output.data.name);
  13534         needed_capacity += (constraint.len + name.len + (2 + 3)) / 4;
  13535 
  13536         outputs[out_i] = .{ .c = constraint, .n = name };
  13537     }
  13538 
  13539     const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len);
  13540     const inputs = try sema.arena.alloc(ConstraintName, inputs_len);
  13541 
  13542     for (args) |*arg, arg_i| {
  13543         const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i);
  13544         extra_i = input.end;
  13545 
  13546         const uncasted_arg = try sema.resolveInst(input.data.operand);
  13547         const uncasted_arg_ty = sema.typeOf(uncasted_arg);
  13548         switch (uncasted_arg_ty.zigTypeTag()) {
  13549             .ComptimeInt => arg.* = try sema.coerce(block, Type.initTag(.usize), uncasted_arg, src),
  13550             .ComptimeFloat => arg.* = try sema.coerce(block, Type.initTag(.f64), uncasted_arg, src),
  13551             else => {
  13552                 arg.* = uncasted_arg;
  13553                 try sema.queueFullTypeResolution(uncasted_arg_ty);
  13554             },
  13555         }
  13556 
  13557         const constraint = sema.code.nullTerminatedString(input.data.constraint);
  13558         const name = sema.code.nullTerminatedString(input.data.name);
  13559         needed_capacity += (constraint.len + name.len + (2 + 3)) / 4;
  13560         inputs[arg_i] = .{ .c = constraint, .n = name };
  13561     }
  13562 
  13563     const clobbers = try sema.arena.alloc([]const u8, clobbers_len);
  13564     for (clobbers) |*name| {
  13565         name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
  13566         extra_i += 1;
  13567 
  13568         needed_capacity += name.*.len / 4 + 1;
  13569     }
  13570 
  13571     needed_capacity += (asm_source.len + 3) / 4;
  13572 
  13573     const gpa = sema.gpa;
  13574     try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity);
  13575     const asm_air = try block.addInst(.{
  13576         .tag = .assembly,
  13577         .data = .{ .ty_pl = .{
  13578             .ty = expr_ty,
  13579             .payload = sema.addExtraAssumeCapacity(Air.Asm{
  13580                 .source_len = @intCast(u32, asm_source.len),
  13581                 .outputs_len = outputs_len,
  13582                 .inputs_len = @intCast(u32, args.len),
  13583                 .flags = (@as(u32, @boolToInt(is_volatile)) << 31) | @intCast(u32, clobbers.len),
  13584             }),
  13585         } },
  13586     });
  13587     sema.appendRefsAssumeCapacity(out_args);
  13588     sema.appendRefsAssumeCapacity(args);
  13589     for (outputs) |o| {
  13590         const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
  13591         mem.copy(u8, buffer, o.c);
  13592         buffer[o.c.len] = 0;
  13593         mem.copy(u8, buffer[o.c.len + 1 ..], o.n);
  13594         buffer[o.c.len + 1 + o.n.len] = 0;
  13595         sema.air_extra.items.len += (o.c.len + o.n.len + (2 + 3)) / 4;
  13596     }
  13597     for (inputs) |input| {
  13598         const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
  13599         mem.copy(u8, buffer, input.c);
  13600         buffer[input.c.len] = 0;
  13601         mem.copy(u8, buffer[input.c.len + 1 ..], input.n);
  13602         buffer[input.c.len + 1 + input.n.len] = 0;
  13603         sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4;
  13604     }
  13605     for (clobbers) |clobber| {
  13606         const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
  13607         mem.copy(u8, buffer, clobber);
  13608         buffer[clobber.len] = 0;
  13609         sema.air_extra.items.len += clobber.len / 4 + 1;
  13610     }
  13611     {
  13612         const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
  13613         mem.copy(u8, buffer, asm_source);
  13614         sema.air_extra.items.len += (asm_source.len + 3) / 4;
  13615     }
  13616     return asm_air;
  13617 }
  13618 
  13619 /// Only called for equality operators. See also `zirCmp`.
  13620 fn zirCmpEq(
  13621     sema: *Sema,
  13622     block: *Block,
  13623     inst: Zir.Inst.Index,
  13624     op: std.math.CompareOperator,
  13625     air_tag: Air.Inst.Tag,
  13626 ) CompileError!Air.Inst.Ref {
  13627     const tracy = trace(@src());
  13628     defer tracy.end();
  13629 
  13630     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  13631     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  13632     const src: LazySrcLoc = inst_data.src();
  13633     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  13634     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  13635     const lhs = try sema.resolveInst(extra.lhs);
  13636     const rhs = try sema.resolveInst(extra.rhs);
  13637 
  13638     const lhs_ty = sema.typeOf(lhs);
  13639     const rhs_ty = sema.typeOf(rhs);
  13640     const lhs_ty_tag = lhs_ty.zigTypeTag();
  13641     const rhs_ty_tag = rhs_ty.zigTypeTag();
  13642     if (lhs_ty_tag == .Null and rhs_ty_tag == .Null) {
  13643         // null == null, null != null
  13644         if (op == .eq) {
  13645             return Air.Inst.Ref.bool_true;
  13646         } else {
  13647             return Air.Inst.Ref.bool_false;
  13648         }
  13649     }
  13650 
  13651     // comparing null with optionals
  13652     if (lhs_ty_tag == .Null and (rhs_ty_tag == .Optional or rhs_ty.isCPtr())) {
  13653         return sema.analyzeIsNull(block, src, rhs, op == .neq);
  13654     }
  13655     if (rhs_ty_tag == .Null and (lhs_ty_tag == .Optional or lhs_ty.isCPtr())) {
  13656         return sema.analyzeIsNull(block, src, lhs, op == .neq);
  13657     }
  13658 
  13659     if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {
  13660         const non_null_type = if (lhs_ty_tag == .Null) rhs_ty else lhs_ty;
  13661         return sema.fail(block, src, "comparison of '{}' with null", .{non_null_type.fmt(sema.mod)});
  13662     }
  13663 
  13664     if (lhs_ty_tag == .Union and (rhs_ty_tag == .EnumLiteral or rhs_ty_tag == .Enum)) {
  13665         return sema.analyzeCmpUnionTag(block, src, lhs, lhs_src, rhs, rhs_src, op);
  13666     }
  13667     if (rhs_ty_tag == .Union and (lhs_ty_tag == .EnumLiteral or lhs_ty_tag == .Enum)) {
  13668         return sema.analyzeCmpUnionTag(block, src, rhs, rhs_src, lhs, lhs_src, op);
  13669     }
  13670 
  13671     if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {
  13672         const runtime_src: LazySrcLoc = src: {
  13673             if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lval| {
  13674                 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rval| {
  13675                     if (lval.isUndef() or rval.isUndef()) {
  13676                         return sema.addConstUndef(Type.bool);
  13677                     }
  13678                     // TODO optimisation opportunity: evaluate if mem.eql is faster with the names,
  13679                     // or calling to Module.getErrorValue to get the values and then compare them is
  13680                     // faster.
  13681                     const lhs_name = lval.castTag(.@"error").?.data.name;
  13682                     const rhs_name = rval.castTag(.@"error").?.data.name;
  13683                     if (mem.eql(u8, lhs_name, rhs_name) == (op == .eq)) {
  13684                         return Air.Inst.Ref.bool_true;
  13685                     } else {
  13686                         return Air.Inst.Ref.bool_false;
  13687                     }
  13688                 } else {
  13689                     break :src rhs_src;
  13690                 }
  13691             } else {
  13692                 break :src lhs_src;
  13693             }
  13694         };
  13695         try sema.requireRuntimeBlock(block, src, runtime_src);
  13696         return block.addBinOp(air_tag, lhs, rhs);
  13697     }
  13698     if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {
  13699         const lhs_as_type = try sema.analyzeAsType(block, lhs_src, lhs);
  13700         const rhs_as_type = try sema.analyzeAsType(block, rhs_src, rhs);
  13701         if (lhs_as_type.eql(rhs_as_type, sema.mod) == (op == .eq)) {
  13702             return Air.Inst.Ref.bool_true;
  13703         } else {
  13704             return Air.Inst.Ref.bool_false;
  13705         }
  13706     }
  13707     return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, true);
  13708 }
  13709 
  13710 fn analyzeCmpUnionTag(
  13711     sema: *Sema,
  13712     block: *Block,
  13713     src: LazySrcLoc,
  13714     un: Air.Inst.Ref,
  13715     un_src: LazySrcLoc,
  13716     tag: Air.Inst.Ref,
  13717     tag_src: LazySrcLoc,
  13718     op: std.math.CompareOperator,
  13719 ) CompileError!Air.Inst.Ref {
  13720     const union_ty = try sema.resolveTypeFields(block, un_src, sema.typeOf(un));
  13721     const union_tag_ty = union_ty.unionTagType() orelse {
  13722         const msg = msg: {
  13723             const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
  13724             errdefer msg.destroy(sema.gpa);
  13725             try sema.mod.errNoteNonLazy(union_ty.declSrcLoc(sema.mod), msg, "union '{}' is not a tagged union", .{union_ty.fmt(sema.mod)});
  13726             break :msg msg;
  13727         };
  13728         return sema.failWithOwnedErrorMsg(msg);
  13729     };
  13730     // Coerce both the union and the tag to the union's tag type, and then execute the
  13731     // enum comparison codepath.
  13732     const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src);
  13733     const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src);
  13734 
  13735     if (try sema.resolveMaybeUndefVal(block, tag_src, coerced_tag)) |enum_val| {
  13736         if (enum_val.isUndef()) return sema.addConstUndef(Type.bool);
  13737         const field_ty = union_ty.unionFieldType(enum_val, sema.mod);
  13738         if (field_ty.zigTypeTag() == .NoReturn) {
  13739             return Air.Inst.Ref.bool_false;
  13740         }
  13741     }
  13742 
  13743     return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src);
  13744 }
  13745 
  13746 /// Only called for non-equality operators. See also `zirCmpEq`.
  13747 fn zirCmp(
  13748     sema: *Sema,
  13749     block: *Block,
  13750     inst: Zir.Inst.Index,
  13751     op: std.math.CompareOperator,
  13752 ) CompileError!Air.Inst.Ref {
  13753     const tracy = trace(@src());
  13754     defer tracy.end();
  13755 
  13756     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  13757     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  13758     const src: LazySrcLoc = inst_data.src();
  13759     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  13760     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  13761     const lhs = try sema.resolveInst(extra.lhs);
  13762     const rhs = try sema.resolveInst(extra.rhs);
  13763     return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, false);
  13764 }
  13765 
  13766 fn analyzeCmp(
  13767     sema: *Sema,
  13768     block: *Block,
  13769     src: LazySrcLoc,
  13770     lhs: Air.Inst.Ref,
  13771     rhs: Air.Inst.Ref,
  13772     op: std.math.CompareOperator,
  13773     lhs_src: LazySrcLoc,
  13774     rhs_src: LazySrcLoc,
  13775     is_equality_cmp: bool,
  13776 ) CompileError!Air.Inst.Ref {
  13777     const lhs_ty = sema.typeOf(lhs);
  13778     const rhs_ty = sema.typeOf(rhs);
  13779     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  13780 
  13781     if (lhs_ty.zigTypeTag() == .Vector and rhs_ty.zigTypeTag() == .Vector) {
  13782         return sema.cmpVector(block, src, lhs, rhs, op, lhs_src, rhs_src);
  13783     }
  13784     if (lhs_ty.isNumeric() and rhs_ty.isNumeric()) {
  13785         // This operation allows any combination of integer and float types, regardless of the
  13786         // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for
  13787         // numeric types.
  13788         return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src);
  13789     }
  13790     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  13791     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
  13792     if (!resolved_type.isSelfComparable(is_equality_cmp)) {
  13793         return sema.fail(block, src, "operator {s} not allowed for type '{}'", .{
  13794             compareOperatorName(op), resolved_type.fmt(sema.mod),
  13795         });
  13796     }
  13797     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  13798     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  13799     return sema.cmpSelf(block, src, casted_lhs, casted_rhs, op, lhs_src, rhs_src);
  13800 }
  13801 
  13802 fn compareOperatorName(comp: std.math.CompareOperator) []const u8 {
  13803     return switch (comp) {
  13804         .lt => "<",
  13805         .lte => "<=",
  13806         .eq => "==",
  13807         .gte => ">=",
  13808         .gt => ">",
  13809         .neq => "!=",
  13810     };
  13811 }
  13812 
  13813 fn cmpSelf(
  13814     sema: *Sema,
  13815     block: *Block,
  13816     src: LazySrcLoc,
  13817     casted_lhs: Air.Inst.Ref,
  13818     casted_rhs: Air.Inst.Ref,
  13819     op: std.math.CompareOperator,
  13820     lhs_src: LazySrcLoc,
  13821     rhs_src: LazySrcLoc,
  13822 ) CompileError!Air.Inst.Ref {
  13823     const resolved_type = sema.typeOf(casted_lhs);
  13824     const runtime_src: LazySrcLoc = src: {
  13825         if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
  13826             if (lhs_val.isUndef()) return sema.addConstUndef(Type.bool);
  13827             if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
  13828                 if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool);
  13829 
  13830                 if (resolved_type.zigTypeTag() == .Vector) {
  13831                     const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.@"bool");
  13832                     const cmp_val = try sema.compareVector(block, lhs_src, lhs_val, op, rhs_val, resolved_type);
  13833                     return sema.addConstant(result_ty, cmp_val);
  13834                 }
  13835 
  13836                 if (try sema.compare(block, lhs_src, lhs_val, op, rhs_val, resolved_type)) {
  13837                     return Air.Inst.Ref.bool_true;
  13838                 } else {
  13839                     return Air.Inst.Ref.bool_false;
  13840                 }
  13841             } else {
  13842                 if (resolved_type.zigTypeTag() == .Bool) {
  13843                     // We can lower bool eq/neq more efficiently.
  13844                     return sema.runtimeBoolCmp(block, src, op, casted_rhs, lhs_val.toBool(), rhs_src);
  13845                 }
  13846                 break :src rhs_src;
  13847             }
  13848         } else {
  13849             // For bools, we still check the other operand, because we can lower
  13850             // bool eq/neq more efficiently.
  13851             if (resolved_type.zigTypeTag() == .Bool) {
  13852                 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
  13853                     if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool);
  13854                     return sema.runtimeBoolCmp(block, src, op, casted_lhs, rhs_val.toBool(), lhs_src);
  13855                 }
  13856             }
  13857             break :src lhs_src;
  13858         }
  13859     };
  13860     try sema.requireRuntimeBlock(block, src, runtime_src);
  13861     if (resolved_type.zigTypeTag() == .Vector) {
  13862         const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.@"bool");
  13863         const result_ty_ref = try sema.addType(result_ty);
  13864         return block.addCmpVector(casted_lhs, casted_rhs, op, result_ty_ref);
  13865     }
  13866     const tag = Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized);
  13867     return block.addBinOp(tag, casted_lhs, casted_rhs);
  13868 }
  13869 
  13870 /// cmp_eq (x, false) => not(x)
  13871 /// cmp_eq (x, true ) => x
  13872 /// cmp_neq(x, false) => x
  13873 /// cmp_neq(x, true ) => not(x)
  13874 fn runtimeBoolCmp(
  13875     sema: *Sema,
  13876     block: *Block,
  13877     src: LazySrcLoc,
  13878     op: std.math.CompareOperator,
  13879     lhs: Air.Inst.Ref,
  13880     rhs: bool,
  13881     runtime_src: LazySrcLoc,
  13882 ) CompileError!Air.Inst.Ref {
  13883     if ((op == .neq) == rhs) {
  13884         try sema.requireRuntimeBlock(block, src, runtime_src);
  13885         return block.addTyOp(.not, Type.bool, lhs);
  13886     } else {
  13887         return lhs;
  13888     }
  13889 }
  13890 
  13891 fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  13892     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  13893     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  13894     const ty = try sema.resolveType(block, operand_src, inst_data.operand);
  13895     switch (ty.zigTypeTag()) {
  13896         .Fn,
  13897         .NoReturn,
  13898         .Undefined,
  13899         .Null,
  13900         .BoundFn,
  13901         .Opaque,
  13902         => return sema.fail(block, operand_src, "no size available for type '{}'", .{ty.fmt(sema.mod)}),
  13903 
  13904         .Type,
  13905         .EnumLiteral,
  13906         .ComptimeFloat,
  13907         .ComptimeInt,
  13908         .Void,
  13909         => return sema.addIntUnsigned(Type.comptime_int, 0),
  13910 
  13911         .Bool,
  13912         .Int,
  13913         .Float,
  13914         .Pointer,
  13915         .Array,
  13916         .Struct,
  13917         .Optional,
  13918         .ErrorUnion,
  13919         .ErrorSet,
  13920         .Enum,
  13921         .Union,
  13922         .Vector,
  13923         .Frame,
  13924         .AnyFrame,
  13925         => {},
  13926     }
  13927     const target = sema.mod.getTarget();
  13928     const val = try ty.lazyAbiSize(target, sema.arena);
  13929     if (val.tag() == .lazy_size) {
  13930         try sema.queueFullTypeResolution(ty);
  13931     }
  13932     return sema.addConstant(Type.comptime_int, val);
  13933 }
  13934 
  13935 fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  13936     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  13937     const src = inst_data.src();
  13938     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  13939     const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand);
  13940     const target = sema.mod.getTarget();
  13941     const bit_size = try operand_ty.bitSizeAdvanced(target, sema.kit(block, src));
  13942     return sema.addIntUnsigned(Type.comptime_int, bit_size);
  13943 }
  13944 
  13945 fn zirThis(
  13946     sema: *Sema,
  13947     block: *Block,
  13948     extended: Zir.Inst.Extended.InstData,
  13949 ) CompileError!Air.Inst.Ref {
  13950     const this_decl_index = block.namespace.getDeclIndex();
  13951     const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
  13952     return sema.analyzeDeclVal(block, src, this_decl_index);
  13953 }
  13954 
  13955 fn zirClosureCapture(
  13956     sema: *Sema,
  13957     block: *Block,
  13958     inst: Zir.Inst.Index,
  13959 ) CompileError!void {
  13960     // TODO: Compile error when closed over values are modified
  13961     const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
  13962     const src = inst_data.src();
  13963     // Closures are not necessarily constant values. For example, the
  13964     // code might do something like this:
  13965     // fn foo(x: anytype) void { const S = struct {field: @TypeOf(x)}; }
  13966     // ...in which case the closure_capture instruction has access to a runtime
  13967     // value only. In such case we preserve the type and use a dummy runtime value.
  13968     const operand = try sema.resolveInst(inst_data.operand);
  13969     const val = (try sema.resolveMaybeUndefValAllowVariables(block, src, operand)) orelse
  13970         Value.initTag(.generic_poison);
  13971 
  13972     try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, .{
  13973         .ty = try sema.typeOf(operand).copy(sema.perm_arena),
  13974         .val = try val.copy(sema.perm_arena),
  13975     });
  13976 }
  13977 
  13978 fn zirClosureGet(
  13979     sema: *Sema,
  13980     block: *Block,
  13981     inst: Zir.Inst.Index,
  13982 ) CompileError!Air.Inst.Ref {
  13983     // TODO CLOSURE: Test this with inline functions
  13984     const inst_data = sema.code.instructions.items(.data)[inst].inst_node;
  13985     var scope: *CaptureScope = sema.mod.declPtr(block.src_decl).src_scope.?;
  13986     // Note: The target closure must be in this scope list.
  13987     // If it's not here, the zir is invalid, or the list is broken.
  13988     const tv = while (true) {
  13989         // Note: We don't need to add a dependency here, because
  13990         // decls always depend on their lexical parents.
  13991 
  13992         // Fail this decl if a scope it depended on failed.
  13993         if (scope.failed()) {
  13994             if (sema.owner_func) |owner_func| {
  13995                 owner_func.state = .dependency_failure;
  13996             } else {
  13997                 sema.owner_decl.analysis = .dependency_failure;
  13998             }
  13999             return error.AnalysisFail;
  14000         }
  14001         if (scope.captures.getPtr(inst_data.inst)) |tv| {
  14002             break tv;
  14003         }
  14004         scope = scope.parent.?;
  14005     } else unreachable;
  14006 
  14007     if (tv.val.tag() == .generic_poison and !block.is_typeof and !block.is_comptime and sema.func != null) {
  14008         const msg = msg: {
  14009             const name = name: {
  14010                 const file = sema.owner_decl.getFileScope();
  14011                 const tree = file.getTree(sema.mod.gpa) catch |err| {
  14012                     // In this case we emit a warning + a less precise source location.
  14013                     log.warn("unable to load {s}: {s}", .{
  14014                         file.sub_file_path, @errorName(err),
  14015                     });
  14016                     break :name null;
  14017                 };
  14018                 const node = sema.owner_decl.relativeToNodeIndex(inst_data.src_node);
  14019                 const token = tree.nodes.items(.main_token)[node];
  14020                 break :name tree.tokenSlice(token);
  14021             };
  14022 
  14023             const msg = if (name) |some|
  14024                 try sema.errMsg(block, inst_data.src(), "'{s}' not accessible from inner function", .{some})
  14025             else
  14026                 try sema.errMsg(block, inst_data.src(), "variable not accessible from inner function", .{});
  14027             errdefer msg.destroy(sema.gpa);
  14028 
  14029             try sema.errNote(block, LazySrcLoc.nodeOffset(0), msg, "crossed function definition here", .{});
  14030 
  14031             // TODO add "declared here" note
  14032             break :msg msg;
  14033         };
  14034         return sema.failWithOwnedErrorMsg(msg);
  14035     }
  14036 
  14037     return sema.addConstant(tv.ty, tv.val);
  14038 }
  14039 
  14040 fn zirRetAddr(
  14041     sema: *Sema,
  14042     block: *Block,
  14043     extended: Zir.Inst.Extended.InstData,
  14044 ) CompileError!Air.Inst.Ref {
  14045     const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
  14046     try sema.requireRuntimeBlock(block, src, null);
  14047     return try block.addNoOp(.ret_addr);
  14048 }
  14049 
  14050 fn zirFrameAddress(
  14051     sema: *Sema,
  14052     block: *Block,
  14053     extended: Zir.Inst.Extended.InstData,
  14054 ) CompileError!Air.Inst.Ref {
  14055     const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
  14056     try sema.requireRuntimeBlock(block, src, null);
  14057     return try block.addNoOp(.frame_addr);
  14058 }
  14059 
  14060 fn zirBuiltinSrc(
  14061     sema: *Sema,
  14062     block: *Block,
  14063     extended: Zir.Inst.Extended.InstData,
  14064 ) CompileError!Air.Inst.Ref {
  14065     const tracy = trace(@src());
  14066     defer tracy.end();
  14067 
  14068     const extra = sema.code.extraData(Zir.Inst.Src, extended.operand).data;
  14069     const src = LazySrcLoc.nodeOffset(extra.node);
  14070     const func = sema.func orelse return sema.fail(block, src, "@src outside function", .{});
  14071     const fn_owner_decl = sema.mod.declPtr(func.owner_decl);
  14072 
  14073     const func_name_val = blk: {
  14074         var anon_decl = try block.startAnonDecl(src);
  14075         defer anon_decl.deinit();
  14076         const name = std.mem.span(fn_owner_decl.name);
  14077         const bytes = try anon_decl.arena().dupe(u8, name[0 .. name.len + 1]);
  14078         const new_decl = try anon_decl.finish(
  14079             try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len - 1),
  14080             try Value.Tag.bytes.create(anon_decl.arena(), bytes),
  14081             0, // default alignment
  14082         );
  14083         break :blk try Value.Tag.decl_ref.create(sema.arena, new_decl);
  14084     };
  14085 
  14086     const file_name_val = blk: {
  14087         var anon_decl = try block.startAnonDecl(src);
  14088         defer anon_decl.deinit();
  14089         const relative_path = try fn_owner_decl.getFileScope().fullPath(sema.arena);
  14090         const absolute_path = std.fs.realpathAlloc(sema.arena, relative_path) catch |err| {
  14091             return sema.fail(block, src, "failed to get absolute path of file '{s}': {s}", .{ relative_path, @errorName(err) });
  14092         };
  14093         const aboslute_duped = try anon_decl.arena().dupeZ(u8, absolute_path);
  14094         const new_decl = try anon_decl.finish(
  14095             try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), aboslute_duped.len),
  14096             try Value.Tag.bytes.create(anon_decl.arena(), aboslute_duped[0 .. aboslute_duped.len + 1]),
  14097             0, // default alignment
  14098         );
  14099         break :blk try Value.Tag.decl_ref.create(sema.arena, new_decl);
  14100     };
  14101 
  14102     const field_values = try sema.arena.alloc(Value, 4);
  14103     // file: [:0]const u8,
  14104     field_values[0] = file_name_val;
  14105     // fn_name: [:0]const u8,
  14106     field_values[1] = func_name_val;
  14107     // line: u32
  14108     field_values[2] = try Value.Tag.runtime_int.create(sema.arena, extra.line + 1);
  14109     // column: u32,
  14110     field_values[3] = try Value.Tag.int_u64.create(sema.arena, extra.column + 1);
  14111 
  14112     return sema.addConstant(
  14113         try sema.getBuiltinType(block, src, "SourceLocation"),
  14114         try Value.Tag.aggregate.create(sema.arena, field_values),
  14115     );
  14116 }
  14117 
  14118 fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  14119     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  14120     const src = inst_data.src();
  14121     const ty = try sema.resolveType(block, src, inst_data.operand);
  14122     const type_info_ty = try sema.getBuiltinType(block, src, "Type");
  14123     const target = sema.mod.getTarget();
  14124 
  14125     switch (ty.zigTypeTag()) {
  14126         .Type => return sema.addConstant(
  14127             type_info_ty,
  14128             try Value.Tag.@"union".create(sema.arena, .{
  14129                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Type)),
  14130                 .val = Value.@"void",
  14131             }),
  14132         ),
  14133         .Void => return sema.addConstant(
  14134             type_info_ty,
  14135             try Value.Tag.@"union".create(sema.arena, .{
  14136                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Void)),
  14137                 .val = Value.@"void",
  14138             }),
  14139         ),
  14140         .Bool => return sema.addConstant(
  14141             type_info_ty,
  14142             try Value.Tag.@"union".create(sema.arena, .{
  14143                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Bool)),
  14144                 .val = Value.@"void",
  14145             }),
  14146         ),
  14147         .NoReturn => return sema.addConstant(
  14148             type_info_ty,
  14149             try Value.Tag.@"union".create(sema.arena, .{
  14150                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.NoReturn)),
  14151                 .val = Value.@"void",
  14152             }),
  14153         ),
  14154         .ComptimeFloat => return sema.addConstant(
  14155             type_info_ty,
  14156             try Value.Tag.@"union".create(sema.arena, .{
  14157                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ComptimeFloat)),
  14158                 .val = Value.@"void",
  14159             }),
  14160         ),
  14161         .ComptimeInt => return sema.addConstant(
  14162             type_info_ty,
  14163             try Value.Tag.@"union".create(sema.arena, .{
  14164                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ComptimeInt)),
  14165                 .val = Value.@"void",
  14166             }),
  14167         ),
  14168         .Undefined => return sema.addConstant(
  14169             type_info_ty,
  14170             try Value.Tag.@"union".create(sema.arena, .{
  14171                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Undefined)),
  14172                 .val = Value.@"void",
  14173             }),
  14174         ),
  14175         .Null => return sema.addConstant(
  14176             type_info_ty,
  14177             try Value.Tag.@"union".create(sema.arena, .{
  14178                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Null)),
  14179                 .val = Value.@"void",
  14180             }),
  14181         ),
  14182         .EnumLiteral => return sema.addConstant(
  14183             type_info_ty,
  14184             try Value.Tag.@"union".create(sema.arena, .{
  14185                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.EnumLiteral)),
  14186                 .val = Value.@"void",
  14187             }),
  14188         ),
  14189         .Fn => {
  14190             // TODO: look into memoizing this result.
  14191             const info = ty.fnInfo();
  14192 
  14193             var params_anon_decl = try block.startAnonDecl(src);
  14194             defer params_anon_decl.deinit();
  14195 
  14196             const param_vals = try params_anon_decl.arena().alloc(Value, info.param_types.len);
  14197             for (param_vals) |*param_val, i| {
  14198                 const param_ty = info.param_types[i];
  14199                 const is_generic = param_ty.tag() == .generic_poison;
  14200                 const param_ty_val = if (is_generic)
  14201                     Value.@"null"
  14202                 else
  14203                     try Value.Tag.opt_payload.create(
  14204                         params_anon_decl.arena(),
  14205                         try Value.Tag.ty.create(params_anon_decl.arena(), try param_ty.copy(params_anon_decl.arena())),
  14206                     );
  14207 
  14208                 const param_fields = try params_anon_decl.arena().create([3]Value);
  14209                 param_fields.* = .{
  14210                     // is_generic: bool,
  14211                     Value.makeBool(is_generic),
  14212                     // is_noalias: bool,
  14213                     Value.@"false", // TODO
  14214                     // arg_type: ?type,
  14215                     param_ty_val,
  14216                 };
  14217                 param_val.* = try Value.Tag.aggregate.create(params_anon_decl.arena(), param_fields);
  14218             }
  14219 
  14220             const args_val = v: {
  14221                 const fn_info_decl_index = (try sema.namespaceLookup(
  14222                     block,
  14223                     src,
  14224                     type_info_ty.getNamespace().?,
  14225                     "Fn",
  14226                 )).?;
  14227                 try sema.mod.declareDeclDependency(sema.owner_decl_index, fn_info_decl_index);
  14228                 try sema.ensureDeclAnalyzed(fn_info_decl_index);
  14229                 const fn_info_decl = sema.mod.declPtr(fn_info_decl_index);
  14230                 var fn_ty_buffer: Value.ToTypeBuffer = undefined;
  14231                 const fn_ty = fn_info_decl.val.toType(&fn_ty_buffer);
  14232                 const param_info_decl_index = (try sema.namespaceLookup(
  14233                     block,
  14234                     src,
  14235                     fn_ty.getNamespace().?,
  14236                     "Param",
  14237                 )).?;
  14238                 try sema.mod.declareDeclDependency(sema.owner_decl_index, param_info_decl_index);
  14239                 try sema.ensureDeclAnalyzed(param_info_decl_index);
  14240                 const param_info_decl = sema.mod.declPtr(param_info_decl_index);
  14241                 var param_buffer: Value.ToTypeBuffer = undefined;
  14242                 const param_ty = param_info_decl.val.toType(&param_buffer);
  14243                 const new_decl = try params_anon_decl.finish(
  14244                     try Type.Tag.array.create(params_anon_decl.arena(), .{
  14245                         .len = param_vals.len,
  14246                         .elem_type = try param_ty.copy(params_anon_decl.arena()),
  14247                     }),
  14248                     try Value.Tag.aggregate.create(
  14249                         params_anon_decl.arena(),
  14250                         param_vals,
  14251                     ),
  14252                     0, // default alignment
  14253                 );
  14254                 break :v try Value.Tag.slice.create(sema.arena, .{
  14255                     .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl),
  14256                     .len = try Value.Tag.int_u64.create(sema.arena, param_vals.len),
  14257                 });
  14258             };
  14259 
  14260             const ret_ty_opt = if (info.return_type.tag() != .generic_poison)
  14261                 try Value.Tag.opt_payload.create(
  14262                     sema.arena,
  14263                     try Value.Tag.ty.create(sema.arena, info.return_type),
  14264                 )
  14265             else
  14266                 Value.@"null";
  14267 
  14268             const field_values = try sema.arena.create([6]Value);
  14269             field_values.* = .{
  14270                 // calling_convention: CallingConvention,
  14271                 try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.cc)),
  14272                 // alignment: comptime_int,
  14273                 try Value.Tag.int_u64.create(sema.arena, ty.abiAlignment(target)),
  14274                 // is_generic: bool,
  14275                 Value.makeBool(info.is_generic),
  14276                 // is_var_args: bool,
  14277                 Value.makeBool(info.is_var_args),
  14278                 // return_type: ?type,
  14279                 ret_ty_opt,
  14280                 // args: []const Fn.Param,
  14281                 args_val,
  14282             };
  14283 
  14284             return sema.addConstant(
  14285                 type_info_ty,
  14286                 try Value.Tag.@"union".create(sema.arena, .{
  14287                     .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Fn)),
  14288                     .val = try Value.Tag.aggregate.create(sema.arena, field_values),
  14289                 }),
  14290             );
  14291         },
  14292         .Int => {
  14293             const info = ty.intInfo(target);
  14294             const field_values = try sema.arena.alloc(Value, 2);
  14295             // signedness: Signedness,
  14296             field_values[0] = try Value.Tag.enum_field_index.create(
  14297                 sema.arena,
  14298                 @enumToInt(info.signedness),
  14299             );
  14300             // bits: comptime_int,
  14301             field_values[1] = try Value.Tag.int_u64.create(sema.arena, info.bits);
  14302 
  14303             return sema.addConstant(
  14304                 type_info_ty,
  14305                 try Value.Tag.@"union".create(sema.arena, .{
  14306                     .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Int)),
  14307                     .val = try Value.Tag.aggregate.create(sema.arena, field_values),
  14308                 }),
  14309             );
  14310         },
  14311         .Float => {
  14312             const field_values = try sema.arena.alloc(Value, 1);
  14313             // bits: comptime_int,
  14314             field_values[0] = try Value.Tag.int_u64.create(sema.arena, ty.bitSize(target));
  14315 
  14316             return sema.addConstant(
  14317                 type_info_ty,
  14318                 try Value.Tag.@"union".create(sema.arena, .{
  14319                     .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Float)),
  14320                     .val = try Value.Tag.aggregate.create(sema.arena, field_values),
  14321                 }),
  14322             );
  14323         },
  14324         .Pointer => {
  14325             const info = ty.ptrInfo().data;
  14326             const alignment = if (info.@"align" != 0)
  14327                 try Value.Tag.int_u64.create(sema.arena, info.@"align")
  14328             else
  14329                 try info.pointee_type.lazyAbiAlignment(target, sema.arena);
  14330 
  14331             const field_values = try sema.arena.create([8]Value);
  14332             field_values.* = .{
  14333                 // size: Size,
  14334                 try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.size)),
  14335                 // is_const: bool,
  14336                 Value.makeBool(!info.mutable),
  14337                 // is_volatile: bool,
  14338                 Value.makeBool(info.@"volatile"),
  14339                 // alignment: comptime_int,
  14340                 alignment,
  14341                 // address_space: AddressSpace
  14342                 try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.@"addrspace")),
  14343                 // child: type,
  14344                 try Value.Tag.ty.create(sema.arena, info.pointee_type),
  14345                 // is_allowzero: bool,
  14346                 Value.makeBool(info.@"allowzero"),
  14347                 // sentinel: ?*const anyopaque,
  14348                 try sema.optRefValue(block, src, info.pointee_type, info.sentinel),
  14349             };
  14350 
  14351             return sema.addConstant(
  14352                 type_info_ty,
  14353                 try Value.Tag.@"union".create(sema.arena, .{
  14354                     .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Pointer)),
  14355                     .val = try Value.Tag.aggregate.create(sema.arena, field_values),
  14356                 }),
  14357             );
  14358         },
  14359         .Array => {
  14360             const info = ty.arrayInfo();
  14361             const field_values = try sema.arena.alloc(Value, 3);
  14362             // len: comptime_int,
  14363             field_values[0] = try Value.Tag.int_u64.create(sema.arena, info.len);
  14364             // child: type,
  14365             field_values[1] = try Value.Tag.ty.create(sema.arena, info.elem_type);
  14366             // sentinel: ?*const anyopaque,
  14367             field_values[2] = try sema.optRefValue(block, src, info.elem_type, info.sentinel);
  14368 
  14369             return sema.addConstant(
  14370                 type_info_ty,
  14371                 try Value.Tag.@"union".create(sema.arena, .{
  14372                     .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Array)),
  14373                     .val = try Value.Tag.aggregate.create(sema.arena, field_values),
  14374                 }),
  14375             );
  14376         },
  14377         .Vector => {
  14378             const info = ty.arrayInfo();
  14379             const field_values = try sema.arena.alloc(Value, 2);
  14380             // len: comptime_int,
  14381             field_values[0] = try Value.Tag.int_u64.create(sema.arena, info.len);
  14382             // child: type,
  14383             field_values[1] = try Value.Tag.ty.create(sema.arena, info.elem_type);
  14384 
  14385             return sema.addConstant(
  14386                 type_info_ty,
  14387                 try Value.Tag.@"union".create(sema.arena, .{
  14388                     .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Vector)),
  14389                     .val = try Value.Tag.aggregate.create(sema.arena, field_values),
  14390                 }),
  14391             );
  14392         },
  14393         .Optional => {
  14394             const field_values = try sema.arena.alloc(Value, 1);
  14395             // child: type,
  14396             field_values[0] = try Value.Tag.ty.create(sema.arena, try ty.optionalChildAlloc(sema.arena));
  14397 
  14398             return sema.addConstant(
  14399                 type_info_ty,
  14400                 try Value.Tag.@"union".create(sema.arena, .{
  14401                     .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Optional)),
  14402                     .val = try Value.Tag.aggregate.create(sema.arena, field_values),
  14403                 }),
  14404             );
  14405         },
  14406         .ErrorSet => {
  14407             var fields_anon_decl = try block.startAnonDecl(src);
  14408             defer fields_anon_decl.deinit();
  14409 
  14410             // Get the Error type
  14411             const error_field_ty = t: {
  14412                 const set_field_ty_decl_index = (try sema.namespaceLookup(
  14413                     block,
  14414                     src,
  14415                     type_info_ty.getNamespace().?,
  14416                     "Error",
  14417                 )).?;
  14418                 try sema.mod.declareDeclDependency(sema.owner_decl_index, set_field_ty_decl_index);
  14419                 try sema.ensureDeclAnalyzed(set_field_ty_decl_index);
  14420                 const set_field_ty_decl = sema.mod.declPtr(set_field_ty_decl_index);
  14421                 var buffer: Value.ToTypeBuffer = undefined;
  14422                 break :t try set_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena());
  14423             };
  14424 
  14425             try sema.queueFullTypeResolution(try error_field_ty.copy(sema.arena));
  14426 
  14427             // If the error set is inferred it must be resolved at this point
  14428             try sema.resolveInferredErrorSetTy(block, src, ty);
  14429 
  14430             // Build our list of Error values
  14431             // Optional value is only null if anyerror
  14432             // Value can be zero-length slice otherwise
  14433             const error_field_vals: ?[]Value = if (ty.isAnyError()) null else blk: {
  14434                 const names = ty.errorSetNames();
  14435                 const vals = try fields_anon_decl.arena().alloc(Value, names.len);
  14436                 for (vals) |*field_val, i| {
  14437                     const name = names[i];
  14438                     const name_val = v: {
  14439                         var anon_decl = try block.startAnonDecl(src);
  14440                         defer anon_decl.deinit();
  14441                         const bytes = try anon_decl.arena().dupeZ(u8, name);
  14442                         const new_decl = try anon_decl.finish(
  14443                             try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
  14444                             try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
  14445                             0, // default alignment
  14446                         );
  14447                         break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl);
  14448                     };
  14449 
  14450                     const error_field_fields = try fields_anon_decl.arena().create([1]Value);
  14451                     error_field_fields.* = .{
  14452                         // name: []const u8,
  14453                         name_val,
  14454                     };
  14455 
  14456                     field_val.* = try Value.Tag.aggregate.create(
  14457                         fields_anon_decl.arena(),
  14458                         error_field_fields,
  14459                     );
  14460                 }
  14461 
  14462                 break :blk vals;
  14463             };
  14464 
  14465             // Build our ?[]const Error value
  14466             const errors_val = if (error_field_vals) |vals| v: {
  14467                 const new_decl = try fields_anon_decl.finish(
  14468                     try Type.Tag.array.create(fields_anon_decl.arena(), .{
  14469                         .len = vals.len,
  14470                         .elem_type = error_field_ty,
  14471                     }),
  14472                     try Value.Tag.aggregate.create(
  14473                         fields_anon_decl.arena(),
  14474                         vals,
  14475                     ),
  14476                     0, // default alignment
  14477                 );
  14478 
  14479                 const new_decl_val = try Value.Tag.decl_ref.create(sema.arena, new_decl);
  14480                 const slice_val = try Value.Tag.slice.create(sema.arena, .{
  14481                     .ptr = new_decl_val,
  14482                     .len = try Value.Tag.int_u64.create(sema.arena, vals.len),
  14483                 });
  14484                 break :v try Value.Tag.opt_payload.create(sema.arena, slice_val);
  14485             } else Value.@"null";
  14486 
  14487             // Construct Type{ .ErrorSet = errors_val }
  14488             return sema.addConstant(
  14489                 type_info_ty,
  14490                 try Value.Tag.@"union".create(sema.arena, .{
  14491                     .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ErrorSet)),
  14492                     .val = errors_val,
  14493                 }),
  14494             );
  14495         },
  14496         .ErrorUnion => {
  14497             const field_values = try sema.arena.alloc(Value, 2);
  14498             // error_set: type,
  14499             field_values[0] = try Value.Tag.ty.create(sema.arena, ty.errorUnionSet());
  14500             // payload: type,
  14501             field_values[1] = try Value.Tag.ty.create(sema.arena, ty.errorUnionPayload());
  14502 
  14503             return sema.addConstant(
  14504                 type_info_ty,
  14505                 try Value.Tag.@"union".create(sema.arena, .{
  14506                     .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ErrorUnion)),
  14507                     .val = try Value.Tag.aggregate.create(sema.arena, field_values),
  14508                 }),
  14509             );
  14510         },
  14511         .Enum => {
  14512             // TODO: look into memoizing this result.
  14513             var int_tag_type_buffer: Type.Payload.Bits = undefined;
  14514             const int_tag_ty = try ty.intTagType(&int_tag_type_buffer).copy(sema.arena);
  14515 
  14516             const is_exhaustive = Value.makeBool(!ty.isNonexhaustiveEnum());
  14517 
  14518             var fields_anon_decl = try block.startAnonDecl(src);
  14519             defer fields_anon_decl.deinit();
  14520 
  14521             const enum_field_ty = t: {
  14522                 const enum_field_ty_decl_index = (try sema.namespaceLookup(
  14523                     block,
  14524                     src,
  14525                     type_info_ty.getNamespace().?,
  14526                     "EnumField",
  14527                 )).?;
  14528                 try sema.mod.declareDeclDependency(sema.owner_decl_index, enum_field_ty_decl_index);
  14529                 try sema.ensureDeclAnalyzed(enum_field_ty_decl_index);
  14530                 const enum_field_ty_decl = sema.mod.declPtr(enum_field_ty_decl_index);
  14531                 var buffer: Value.ToTypeBuffer = undefined;
  14532                 break :t try enum_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena());
  14533             };
  14534 
  14535             const enum_fields = ty.enumFields();
  14536             const enum_field_vals = try fields_anon_decl.arena().alloc(Value, enum_fields.count());
  14537 
  14538             for (enum_field_vals) |*field_val, i| {
  14539                 var tag_val_payload: Value.Payload.U32 = .{
  14540                     .base = .{ .tag = .enum_field_index },
  14541                     .data = @intCast(u32, i),
  14542                 };
  14543                 const tag_val = Value.initPayload(&tag_val_payload.base);
  14544 
  14545                 var buffer: Value.Payload.U64 = undefined;
  14546                 const int_val = try tag_val.enumToInt(ty, &buffer).copy(fields_anon_decl.arena());
  14547 
  14548                 const name = enum_fields.keys()[i];
  14549                 const name_val = v: {
  14550                     var anon_decl = try block.startAnonDecl(src);
  14551                     defer anon_decl.deinit();
  14552                     const bytes = try anon_decl.arena().dupeZ(u8, name);
  14553                     const new_decl = try anon_decl.finish(
  14554                         try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
  14555                         try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
  14556                         0, // default alignment
  14557                     );
  14558                     break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl);
  14559                 };
  14560 
  14561                 const enum_field_fields = try fields_anon_decl.arena().create([2]Value);
  14562                 enum_field_fields.* = .{
  14563                     // name: []const u8,
  14564                     name_val,
  14565                     // value: comptime_int,
  14566                     int_val,
  14567                 };
  14568                 field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), enum_field_fields);
  14569             }
  14570 
  14571             const fields_val = v: {
  14572                 const new_decl = try fields_anon_decl.finish(
  14573                     try Type.Tag.array.create(fields_anon_decl.arena(), .{
  14574                         .len = enum_field_vals.len,
  14575                         .elem_type = enum_field_ty,
  14576                     }),
  14577                     try Value.Tag.aggregate.create(
  14578                         fields_anon_decl.arena(),
  14579                         enum_field_vals,
  14580                     ),
  14581                     0, // default alignment
  14582                 );
  14583                 break :v try Value.Tag.decl_ref.create(sema.arena, new_decl);
  14584             };
  14585 
  14586             const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespace());
  14587 
  14588             const field_values = try sema.arena.create([5]Value);
  14589             field_values.* = .{
  14590                 // layout: ContainerLayout,
  14591                 try Value.Tag.enum_field_index.create(
  14592                     sema.arena,
  14593                     @enumToInt(std.builtin.Type.ContainerLayout.Auto),
  14594                 ),
  14595 
  14596                 // tag_type: type,
  14597                 try Value.Tag.ty.create(sema.arena, int_tag_ty),
  14598                 // fields: []const EnumField,
  14599                 fields_val,
  14600                 // decls: []const Declaration,
  14601                 decls_val,
  14602                 // is_exhaustive: bool,
  14603                 is_exhaustive,
  14604             };
  14605 
  14606             return sema.addConstant(
  14607                 type_info_ty,
  14608                 try Value.Tag.@"union".create(sema.arena, .{
  14609                     .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Enum)),
  14610                     .val = try Value.Tag.aggregate.create(sema.arena, field_values),
  14611                 }),
  14612             );
  14613         },
  14614         .Union => {
  14615             // TODO: look into memoizing this result.
  14616 
  14617             var fields_anon_decl = try block.startAnonDecl(src);
  14618             defer fields_anon_decl.deinit();
  14619 
  14620             const union_field_ty = t: {
  14621                 const union_field_ty_decl_index = (try sema.namespaceLookup(
  14622                     block,
  14623                     src,
  14624                     type_info_ty.getNamespace().?,
  14625                     "UnionField",
  14626                 )).?;
  14627                 try sema.mod.declareDeclDependency(sema.owner_decl_index, union_field_ty_decl_index);
  14628                 try sema.ensureDeclAnalyzed(union_field_ty_decl_index);
  14629                 const union_field_ty_decl = sema.mod.declPtr(union_field_ty_decl_index);
  14630                 var buffer: Value.ToTypeBuffer = undefined;
  14631                 break :t try union_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena());
  14632             };
  14633 
  14634             const union_ty = try sema.resolveTypeFields(block, src, ty);
  14635             try sema.resolveTypeLayout(block, src, ty); // Getting alignment requires type layout
  14636             const layout = union_ty.containerLayout();
  14637 
  14638             const union_fields = union_ty.unionFields();
  14639             const union_field_vals = try fields_anon_decl.arena().alloc(Value, union_fields.count());
  14640 
  14641             for (union_field_vals) |*field_val, i| {
  14642                 const field = union_fields.values()[i];
  14643                 const name = union_fields.keys()[i];
  14644                 const name_val = v: {
  14645                     var anon_decl = try block.startAnonDecl(src);
  14646                     defer anon_decl.deinit();
  14647                     const bytes = try anon_decl.arena().dupeZ(u8, name);
  14648                     const new_decl = try anon_decl.finish(
  14649                         try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
  14650                         try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
  14651                         0, // default alignment
  14652                     );
  14653                     break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl);
  14654                 };
  14655 
  14656                 const union_field_fields = try fields_anon_decl.arena().create([3]Value);
  14657                 const alignment = switch (layout) {
  14658                     .Auto, .Extern => try sema.unionFieldAlignment(block, src, field),
  14659                     .Packed => 0,
  14660                 };
  14661 
  14662                 union_field_fields.* = .{
  14663                     // name: []const u8,
  14664                     name_val,
  14665                     // field_type: type,
  14666                     try Value.Tag.ty.create(fields_anon_decl.arena(), field.ty),
  14667                     // alignment: comptime_int,
  14668                     try Value.Tag.int_u64.create(fields_anon_decl.arena(), alignment),
  14669                 };
  14670                 field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), union_field_fields);
  14671             }
  14672 
  14673             const fields_val = v: {
  14674                 const new_decl = try fields_anon_decl.finish(
  14675                     try Type.Tag.array.create(fields_anon_decl.arena(), .{
  14676                         .len = union_field_vals.len,
  14677                         .elem_type = union_field_ty,
  14678                     }),
  14679                     try Value.Tag.aggregate.create(
  14680                         fields_anon_decl.arena(),
  14681                         try fields_anon_decl.arena().dupe(Value, union_field_vals),
  14682                     ),
  14683                     0, // default alignment
  14684                 );
  14685                 break :v try Value.Tag.slice.create(sema.arena, .{
  14686                     .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl),
  14687                     .len = try Value.Tag.int_u64.create(sema.arena, union_field_vals.len),
  14688                 });
  14689             };
  14690 
  14691             const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespace());
  14692 
  14693             const enum_tag_ty_val = if (union_ty.unionTagType()) |tag_ty| v: {
  14694                 const ty_val = try Value.Tag.ty.create(sema.arena, tag_ty);
  14695                 break :v try Value.Tag.opt_payload.create(sema.arena, ty_val);
  14696             } else Value.@"null";
  14697 
  14698             const field_values = try sema.arena.create([4]Value);
  14699             field_values.* = .{
  14700                 // layout: ContainerLayout,
  14701                 try Value.Tag.enum_field_index.create(
  14702                     sema.arena,
  14703                     @enumToInt(layout),
  14704                 ),
  14705 
  14706                 // tag_type: ?type,
  14707                 enum_tag_ty_val,
  14708                 // fields: []const UnionField,
  14709                 fields_val,
  14710                 // decls: []const Declaration,
  14711                 decls_val,
  14712             };
  14713 
  14714             return sema.addConstant(
  14715                 type_info_ty,
  14716                 try Value.Tag.@"union".create(sema.arena, .{
  14717                     .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Union)),
  14718                     .val = try Value.Tag.aggregate.create(sema.arena, field_values),
  14719                 }),
  14720             );
  14721         },
  14722         .Struct => {
  14723             // TODO: look into memoizing this result.
  14724 
  14725             var fields_anon_decl = try block.startAnonDecl(src);
  14726             defer fields_anon_decl.deinit();
  14727 
  14728             const struct_field_ty = t: {
  14729                 const struct_field_ty_decl_index = (try sema.namespaceLookup(
  14730                     block,
  14731                     src,
  14732                     type_info_ty.getNamespace().?,
  14733                     "StructField",
  14734                 )).?;
  14735                 try sema.mod.declareDeclDependency(sema.owner_decl_index, struct_field_ty_decl_index);
  14736                 try sema.ensureDeclAnalyzed(struct_field_ty_decl_index);
  14737                 const struct_field_ty_decl = sema.mod.declPtr(struct_field_ty_decl_index);
  14738                 var buffer: Value.ToTypeBuffer = undefined;
  14739                 break :t try struct_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena());
  14740             };
  14741             const struct_ty = try sema.resolveTypeFields(block, src, ty);
  14742             try sema.resolveTypeLayout(block, src, ty); // Getting alignment requires type layout
  14743             const layout = struct_ty.containerLayout();
  14744 
  14745             const struct_field_vals = fv: {
  14746                 if (struct_ty.isTupleOrAnonStruct()) {
  14747                     const tuple = struct_ty.tupleFields();
  14748                     const field_types = tuple.types;
  14749                     const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len);
  14750                     for (struct_field_vals) |*struct_field_val, i| {
  14751                         const field_ty = field_types[i];
  14752                         const name_val = v: {
  14753                             var anon_decl = try block.startAnonDecl(src);
  14754                             defer anon_decl.deinit();
  14755                             const bytes = if (struct_ty.castTag(.anon_struct)) |payload|
  14756                                 try anon_decl.arena().dupeZ(u8, payload.data.names[i])
  14757                             else
  14758                                 try std.fmt.allocPrintZ(anon_decl.arena(), "{d}", .{i});
  14759                             const new_decl = try anon_decl.finish(
  14760                                 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
  14761                                 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
  14762                                 0, // default alignment
  14763                             );
  14764                             break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{
  14765                                 .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl),
  14766                                 .len = try Value.Tag.int_u64.create(fields_anon_decl.arena(), bytes.len),
  14767                             });
  14768                         };
  14769 
  14770                         const struct_field_fields = try fields_anon_decl.arena().create([5]Value);
  14771                         const field_val = tuple.values[i];
  14772                         const is_comptime = field_val.tag() != .unreachable_value;
  14773                         const opt_default_val = if (is_comptime) field_val else null;
  14774                         const default_val_ptr = try sema.optRefValue(block, src, field_ty, opt_default_val);
  14775                         struct_field_fields.* = .{
  14776                             // name: []const u8,
  14777                             name_val,
  14778                             // field_type: type,
  14779                             try Value.Tag.ty.create(fields_anon_decl.arena(), field_ty),
  14780                             // default_value: ?*const anyopaque,
  14781                             try default_val_ptr.copy(fields_anon_decl.arena()),
  14782                             // is_comptime: bool,
  14783                             Value.makeBool(is_comptime),
  14784                             // alignment: comptime_int,
  14785                             try field_ty.lazyAbiAlignment(target, fields_anon_decl.arena()),
  14786                         };
  14787                         struct_field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), struct_field_fields);
  14788                     }
  14789                     break :fv struct_field_vals;
  14790                 }
  14791                 const struct_fields = struct_ty.structFields();
  14792                 const struct_field_vals = try fields_anon_decl.arena().alloc(Value, struct_fields.count());
  14793 
  14794                 for (struct_field_vals) |*field_val, i| {
  14795                     const field = struct_fields.values()[i];
  14796                     const name = struct_fields.keys()[i];
  14797                     const name_val = v: {
  14798                         var anon_decl = try block.startAnonDecl(src);
  14799                         defer anon_decl.deinit();
  14800                         const bytes = try anon_decl.arena().dupeZ(u8, name);
  14801                         const new_decl = try anon_decl.finish(
  14802                             try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
  14803                             try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
  14804                             0, // default alignment
  14805                         );
  14806                         break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{
  14807                             .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl),
  14808                             .len = try Value.Tag.int_u64.create(fields_anon_decl.arena(), bytes.len),
  14809                         });
  14810                     };
  14811 
  14812                     const struct_field_fields = try fields_anon_decl.arena().create([5]Value);
  14813                     const opt_default_val = if (field.default_val.tag() == .unreachable_value)
  14814                         null
  14815                     else
  14816                         field.default_val;
  14817                     const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val);
  14818                     const alignment = field.alignment(target, layout);
  14819 
  14820                     struct_field_fields.* = .{
  14821                         // name: []const u8,
  14822                         name_val,
  14823                         // field_type: type,
  14824                         try Value.Tag.ty.create(fields_anon_decl.arena(), field.ty),
  14825                         // default_value: ?*const anyopaque,
  14826                         try default_val_ptr.copy(fields_anon_decl.arena()),
  14827                         // is_comptime: bool,
  14828                         Value.makeBool(field.is_comptime),
  14829                         // alignment: comptime_int,
  14830                         try Value.Tag.int_u64.create(fields_anon_decl.arena(), alignment),
  14831                     };
  14832                     field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), struct_field_fields);
  14833                 }
  14834                 break :fv struct_field_vals;
  14835             };
  14836 
  14837             const fields_val = v: {
  14838                 const new_decl = try fields_anon_decl.finish(
  14839                     try Type.Tag.array.create(fields_anon_decl.arena(), .{
  14840                         .len = struct_field_vals.len,
  14841                         .elem_type = struct_field_ty,
  14842                     }),
  14843                     try Value.Tag.aggregate.create(
  14844                         fields_anon_decl.arena(),
  14845                         try fields_anon_decl.arena().dupe(Value, struct_field_vals),
  14846                     ),
  14847                     0, // default alignment
  14848                 );
  14849                 break :v try Value.Tag.slice.create(sema.arena, .{
  14850                     .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl),
  14851                     .len = try Value.Tag.int_u64.create(sema.arena, struct_field_vals.len),
  14852                 });
  14853             };
  14854 
  14855             const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespace());
  14856 
  14857             const backing_integer_val = blk: {
  14858                 if (layout == .Packed) {
  14859                     const struct_obj = struct_ty.castTag(.@"struct").?.data;
  14860                     assert(struct_obj.haveLayout());
  14861                     assert(struct_obj.backing_int_ty.isInt());
  14862                     const backing_int_ty_val = try Value.Tag.ty.create(sema.arena, struct_obj.backing_int_ty);
  14863                     break :blk try Value.Tag.opt_payload.create(sema.arena, backing_int_ty_val);
  14864                 } else {
  14865                     break :blk Value.initTag(.null_value);
  14866                 }
  14867             };
  14868 
  14869             const field_values = try sema.arena.create([5]Value);
  14870             field_values.* = .{
  14871                 // layout: ContainerLayout,
  14872                 try Value.Tag.enum_field_index.create(
  14873                     sema.arena,
  14874                     @enumToInt(layout),
  14875                 ),
  14876                 // backing_integer: ?type,
  14877                 backing_integer_val,
  14878                 // fields: []const StructField,
  14879                 fields_val,
  14880                 // decls: []const Declaration,
  14881                 decls_val,
  14882                 // is_tuple: bool,
  14883                 Value.makeBool(struct_ty.isTuple()),
  14884             };
  14885 
  14886             return sema.addConstant(
  14887                 type_info_ty,
  14888                 try Value.Tag.@"union".create(sema.arena, .{
  14889                     .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Struct)),
  14890                     .val = try Value.Tag.aggregate.create(sema.arena, field_values),
  14891                 }),
  14892             );
  14893         },
  14894         .Opaque => {
  14895             // TODO: look into memoizing this result.
  14896 
  14897             const opaque_ty = try sema.resolveTypeFields(block, src, ty);
  14898             const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespace());
  14899 
  14900             const field_values = try sema.arena.create([1]Value);
  14901             field_values.* = .{
  14902                 // decls: []const Declaration,
  14903                 decls_val,
  14904             };
  14905 
  14906             return sema.addConstant(
  14907                 type_info_ty,
  14908                 try Value.Tag.@"union".create(sema.arena, .{
  14909                     .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Opaque)),
  14910                     .val = try Value.Tag.aggregate.create(sema.arena, field_values),
  14911                 }),
  14912             );
  14913         },
  14914         .BoundFn => @panic("TODO remove this type from the language and compiler"),
  14915         .Frame => return sema.failWithUseOfAsync(block, src),
  14916         .AnyFrame => return sema.failWithUseOfAsync(block, src),
  14917     }
  14918 }
  14919 
  14920 fn typeInfoDecls(
  14921     sema: *Sema,
  14922     block: *Block,
  14923     src: LazySrcLoc,
  14924     type_info_ty: Type,
  14925     opt_namespace: ?*Module.Namespace,
  14926 ) CompileError!Value {
  14927     var decls_anon_decl = try block.startAnonDecl(src);
  14928     defer decls_anon_decl.deinit();
  14929 
  14930     const declaration_ty = t: {
  14931         const declaration_ty_decl_index = (try sema.namespaceLookup(
  14932             block,
  14933             src,
  14934             type_info_ty.getNamespace().?,
  14935             "Declaration",
  14936         )).?;
  14937         try sema.mod.declareDeclDependency(sema.owner_decl_index, declaration_ty_decl_index);
  14938         try sema.ensureDeclAnalyzed(declaration_ty_decl_index);
  14939         const declaration_ty_decl = sema.mod.declPtr(declaration_ty_decl_index);
  14940         var buffer: Value.ToTypeBuffer = undefined;
  14941         break :t try declaration_ty_decl.val.toType(&buffer).copy(decls_anon_decl.arena());
  14942     };
  14943     try sema.queueFullTypeResolution(try declaration_ty.copy(sema.arena));
  14944 
  14945     const decls_len = if (opt_namespace) |ns| ns.decls.count() else 0;
  14946     const decls_vals = try decls_anon_decl.arena().alloc(Value, decls_len);
  14947     for (decls_vals) |*decls_val, i| {
  14948         const decl_index = opt_namespace.?.decls.keys()[i];
  14949         const decl = sema.mod.declPtr(decl_index);
  14950         const name_val = v: {
  14951             var anon_decl = try block.startAnonDecl(src);
  14952             defer anon_decl.deinit();
  14953             const bytes = try anon_decl.arena().dupeZ(u8, mem.sliceTo(decl.name, 0));
  14954             const new_decl = try anon_decl.finish(
  14955                 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
  14956                 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
  14957                 0, // default alignment
  14958             );
  14959             break :v try Value.Tag.slice.create(decls_anon_decl.arena(), .{
  14960                 .ptr = try Value.Tag.decl_ref.create(decls_anon_decl.arena(), new_decl),
  14961                 .len = try Value.Tag.int_u64.create(decls_anon_decl.arena(), bytes.len),
  14962             });
  14963         };
  14964 
  14965         const fields = try decls_anon_decl.arena().create([2]Value);
  14966         fields.* = .{
  14967             //name: []const u8,
  14968             name_val,
  14969             //is_pub: bool,
  14970             Value.makeBool(decl.is_pub),
  14971         };
  14972         decls_val.* = try Value.Tag.aggregate.create(decls_anon_decl.arena(), fields);
  14973     }
  14974 
  14975     const new_decl = try decls_anon_decl.finish(
  14976         try Type.Tag.array.create(decls_anon_decl.arena(), .{
  14977             .len = decls_vals.len,
  14978             .elem_type = declaration_ty,
  14979         }),
  14980         try Value.Tag.aggregate.create(
  14981             decls_anon_decl.arena(),
  14982             try decls_anon_decl.arena().dupe(Value, decls_vals),
  14983         ),
  14984         0, // default alignment
  14985     );
  14986     return try Value.Tag.slice.create(sema.arena, .{
  14987         .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl),
  14988         .len = try Value.Tag.int_u64.create(sema.arena, decls_vals.len),
  14989     });
  14990 }
  14991 
  14992 fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  14993     _ = block;
  14994     const zir_datas = sema.code.instructions.items(.data);
  14995     const inst_data = zir_datas[inst].un_node;
  14996     const operand = try sema.resolveInst(inst_data.operand);
  14997     const operand_ty = sema.typeOf(operand);
  14998     return sema.addType(operand_ty);
  14999 }
  15000 
  15001 fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  15002     const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
  15003     const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index);
  15004     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
  15005 
  15006     var child_block: Block = .{
  15007         .parent = block,
  15008         .sema = sema,
  15009         .src_decl = block.src_decl,
  15010         .namespace = block.namespace,
  15011         .wip_capture_scope = block.wip_capture_scope,
  15012         .instructions = .{},
  15013         .inlining = block.inlining,
  15014         .is_comptime = false,
  15015         .is_typeof = true,
  15016         .want_safety = false,
  15017     };
  15018     defer child_block.instructions.deinit(sema.gpa);
  15019 
  15020     const operand = try sema.resolveBody(&child_block, body, inst);
  15021     const operand_ty = sema.typeOf(operand);
  15022     if (operand_ty.tag() == .generic_poison) return error.GenericPoison;
  15023     return sema.addType(operand_ty);
  15024 }
  15025 
  15026 fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  15027     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15028     const src = inst_data.src();
  15029     const operand = try sema.resolveInst(inst_data.operand);
  15030     const operand_ty = sema.typeOf(operand);
  15031     const res_ty = try sema.log2IntType(block, operand_ty, src);
  15032     return sema.addType(res_ty);
  15033 }
  15034 
  15035 fn zirLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  15036     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15037     const src = inst_data.src();
  15038     const operand = try sema.resolveType(block, src, inst_data.operand);
  15039     const res_ty = try sema.log2IntType(block, operand, src);
  15040     return sema.addType(res_ty);
  15041 }
  15042 
  15043 fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) CompileError!Type {
  15044     switch (operand.zigTypeTag()) {
  15045         .ComptimeInt => return Type.@"comptime_int",
  15046         .Int => {
  15047             const bits = operand.bitSize(sema.mod.getTarget());
  15048             const count = if (bits == 0)
  15049                 0
  15050             else blk: {
  15051                 var count: u16 = 0;
  15052                 var s = bits - 1;
  15053                 while (s != 0) : (s >>= 1) {
  15054                     count += 1;
  15055                 }
  15056                 break :blk count;
  15057             };
  15058             return Module.makeIntType(sema.arena, .unsigned, count);
  15059         },
  15060         .Vector => {
  15061             const elem_ty = operand.elemType2();
  15062             const log2_elem_ty = try sema.log2IntType(block, elem_ty, src);
  15063             return Type.Tag.vector.create(sema.arena, .{
  15064                 .len = operand.vectorLen(),
  15065                 .elem_type = log2_elem_ty,
  15066             });
  15067         },
  15068         else => {},
  15069     }
  15070     return sema.fail(
  15071         block,
  15072         src,
  15073         "bit shifting operation expected integer type, found '{}'",
  15074         .{operand.fmt(sema.mod)},
  15075     );
  15076 }
  15077 
  15078 fn zirTypeofPeer(
  15079     sema: *Sema,
  15080     block: *Block,
  15081     extended: Zir.Inst.Extended.InstData,
  15082 ) CompileError!Air.Inst.Ref {
  15083     const tracy = trace(@src());
  15084     defer tracy.end();
  15085 
  15086     const extra = sema.code.extraData(Zir.Inst.TypeOfPeer, extended.operand);
  15087     const src = LazySrcLoc.nodeOffset(extra.data.src_node);
  15088     const body = sema.code.extra[extra.data.body_index..][0..extra.data.body_len];
  15089 
  15090     var child_block: Block = .{
  15091         .parent = block,
  15092         .sema = sema,
  15093         .src_decl = block.src_decl,
  15094         .namespace = block.namespace,
  15095         .wip_capture_scope = block.wip_capture_scope,
  15096         .instructions = .{},
  15097         .inlining = block.inlining,
  15098         .is_comptime = false,
  15099         .is_typeof = true,
  15100         .runtime_cond = block.runtime_cond,
  15101         .runtime_loop = block.runtime_loop,
  15102         .runtime_index = block.runtime_index,
  15103     };
  15104     defer child_block.instructions.deinit(sema.gpa);
  15105     // Ignore the result, we only care about the instructions in `args`.
  15106     _ = try sema.analyzeBodyBreak(&child_block, body);
  15107 
  15108     const args = sema.code.refSlice(extra.end, extended.small);
  15109 
  15110     const inst_list = try sema.gpa.alloc(Air.Inst.Ref, args.len);
  15111     defer sema.gpa.free(inst_list);
  15112 
  15113     for (args) |arg_ref, i| {
  15114         inst_list[i] = try sema.resolveInst(arg_ref);
  15115     }
  15116 
  15117     const result_type = try sema.resolvePeerTypes(block, src, inst_list, .{ .typeof_builtin_call_node_offset = extra.data.src_node });
  15118     return sema.addType(result_type);
  15119 }
  15120 
  15121 fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  15122     const tracy = trace(@src());
  15123     defer tracy.end();
  15124 
  15125     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15126     const src = inst_data.src();
  15127     const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
  15128     const uncasted_operand = try sema.resolveInst(inst_data.operand);
  15129 
  15130     const operand = try sema.coerce(block, Type.bool, uncasted_operand, operand_src);
  15131     if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
  15132         return if (val.isUndef())
  15133             sema.addConstUndef(Type.bool)
  15134         else if (val.toBool())
  15135             Air.Inst.Ref.bool_false
  15136         else
  15137             Air.Inst.Ref.bool_true;
  15138     }
  15139     try sema.requireRuntimeBlock(block, src, null);
  15140     return block.addTyOp(.not, Type.bool, operand);
  15141 }
  15142 
  15143 fn zirBoolBr(
  15144     sema: *Sema,
  15145     parent_block: *Block,
  15146     inst: Zir.Inst.Index,
  15147     is_bool_or: bool,
  15148 ) CompileError!Air.Inst.Ref {
  15149     const tracy = trace(@src());
  15150     defer tracy.end();
  15151 
  15152     const datas = sema.code.instructions.items(.data);
  15153     const inst_data = datas[inst].bool_br;
  15154     const lhs = try sema.resolveInst(inst_data.lhs);
  15155     const lhs_src = sema.src;
  15156     const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
  15157     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
  15158     const gpa = sema.gpa;
  15159 
  15160     if (try sema.resolveDefinedValue(parent_block, lhs_src, lhs)) |lhs_val| {
  15161         if (lhs_val.toBool() == is_bool_or) {
  15162             if (is_bool_or) {
  15163                 return Air.Inst.Ref.bool_true;
  15164             } else {
  15165                 return Air.Inst.Ref.bool_false;
  15166             }
  15167         }
  15168         // comptime-known left-hand side. No need for a block here; the result
  15169         // is simply the rhs expression. Here we rely on there only being 1
  15170         // break instruction (`break_inline`).
  15171         return sema.resolveBody(parent_block, body, inst);
  15172     }
  15173 
  15174     const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
  15175     try sema.air_instructions.append(gpa, .{
  15176         .tag = .block,
  15177         .data = .{ .ty_pl = .{
  15178             .ty = .bool_type,
  15179             .payload = undefined,
  15180         } },
  15181     });
  15182 
  15183     var child_block = parent_block.makeSubBlock();
  15184     child_block.runtime_loop = null;
  15185     child_block.runtime_cond = lhs_src;
  15186     child_block.runtime_index.increment();
  15187     defer child_block.instructions.deinit(gpa);
  15188 
  15189     var then_block = child_block.makeSubBlock();
  15190     defer then_block.instructions.deinit(gpa);
  15191 
  15192     var else_block = child_block.makeSubBlock();
  15193     defer else_block.instructions.deinit(gpa);
  15194 
  15195     const lhs_block = if (is_bool_or) &then_block else &else_block;
  15196     const rhs_block = if (is_bool_or) &else_block else &then_block;
  15197 
  15198     const lhs_result: Air.Inst.Ref = if (is_bool_or) .bool_true else .bool_false;
  15199     _ = try lhs_block.addBr(block_inst, lhs_result);
  15200 
  15201     const rhs_result = try sema.resolveBody(rhs_block, body, inst);
  15202     _ = try rhs_block.addBr(block_inst, rhs_result);
  15203 
  15204     return finishCondBr(sema, parent_block, &child_block, &then_block, &else_block, lhs, block_inst);
  15205 }
  15206 
  15207 fn finishCondBr(
  15208     sema: *Sema,
  15209     parent_block: *Block,
  15210     child_block: *Block,
  15211     then_block: *Block,
  15212     else_block: *Block,
  15213     cond: Air.Inst.Ref,
  15214     block_inst: Air.Inst.Index,
  15215 ) !Air.Inst.Ref {
  15216     const gpa = sema.gpa;
  15217 
  15218     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
  15219         then_block.instructions.items.len + else_block.instructions.items.len +
  15220         @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1);
  15221 
  15222     const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{
  15223         .then_body_len = @intCast(u32, then_block.instructions.items.len),
  15224         .else_body_len = @intCast(u32, else_block.instructions.items.len),
  15225     });
  15226     sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items);
  15227     sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items);
  15228 
  15229     _ = try child_block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{
  15230         .operand = cond,
  15231         .payload = cond_br_payload,
  15232     } } });
  15233 
  15234     sema.air_instructions.items(.data)[block_inst].ty_pl.payload = sema.addExtraAssumeCapacity(
  15235         Air.Block{ .body_len = @intCast(u32, child_block.instructions.items.len) },
  15236     );
  15237     sema.air_extra.appendSliceAssumeCapacity(child_block.instructions.items);
  15238 
  15239     try parent_block.instructions.append(gpa, block_inst);
  15240     return Air.indexToRef(block_inst);
  15241 }
  15242 
  15243 fn zirIsNonNull(
  15244     sema: *Sema,
  15245     block: *Block,
  15246     inst: Zir.Inst.Index,
  15247 ) CompileError!Air.Inst.Ref {
  15248     const tracy = trace(@src());
  15249     defer tracy.end();
  15250 
  15251     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15252     const src = inst_data.src();
  15253     const operand = try sema.resolveInst(inst_data.operand);
  15254     return sema.analyzeIsNull(block, src, operand, true);
  15255 }
  15256 
  15257 fn zirIsNonNullPtr(
  15258     sema: *Sema,
  15259     block: *Block,
  15260     inst: Zir.Inst.Index,
  15261 ) CompileError!Air.Inst.Ref {
  15262     const tracy = trace(@src());
  15263     defer tracy.end();
  15264 
  15265     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15266     const src = inst_data.src();
  15267     const ptr = try sema.resolveInst(inst_data.operand);
  15268     if ((try sema.resolveMaybeUndefVal(block, src, ptr)) == null) {
  15269         return block.addUnOp(.is_non_null_ptr, ptr);
  15270     }
  15271     const loaded = try sema.analyzeLoad(block, src, ptr, src);
  15272     return sema.analyzeIsNull(block, src, loaded, true);
  15273 }
  15274 
  15275 fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  15276     const tracy = trace(@src());
  15277     defer tracy.end();
  15278 
  15279     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15280     const operand = try sema.resolveInst(inst_data.operand);
  15281     return sema.analyzeIsNonErr(block, inst_data.src(), operand);
  15282 }
  15283 
  15284 fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  15285     const tracy = trace(@src());
  15286     defer tracy.end();
  15287 
  15288     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15289     const src = inst_data.src();
  15290     const ptr = try sema.resolveInst(inst_data.operand);
  15291     const loaded = try sema.analyzeLoad(block, src, ptr, src);
  15292     return sema.analyzeIsNonErr(block, src, loaded);
  15293 }
  15294 
  15295 fn zirCondbr(
  15296     sema: *Sema,
  15297     parent_block: *Block,
  15298     inst: Zir.Inst.Index,
  15299 ) CompileError!Zir.Inst.Index {
  15300     const tracy = trace(@src());
  15301     defer tracy.end();
  15302 
  15303     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  15304     const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
  15305     const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
  15306 
  15307     const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
  15308     const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
  15309 
  15310     const uncasted_cond = try sema.resolveInst(extra.data.condition);
  15311     const cond = try sema.coerce(parent_block, Type.bool, uncasted_cond, cond_src);
  15312 
  15313     if (try sema.resolveDefinedValue(parent_block, cond_src, cond)) |cond_val| {
  15314         const body = if (cond_val.toBool()) then_body else else_body;
  15315 
  15316         try sema.maybeErrorUnwrapCondbr(parent_block, body, extra.data.condition, cond_src);
  15317         // We use `analyzeBodyInner` since we want to propagate any possible
  15318         // `error.ComptimeBreak` to the caller.
  15319         return sema.analyzeBodyInner(parent_block, body);
  15320     }
  15321 
  15322     const gpa = sema.gpa;
  15323 
  15324     // We'll re-use the sub block to save on memory bandwidth, and yank out the
  15325     // instructions array in between using it for the then block and else block.
  15326     var sub_block = parent_block.makeSubBlock();
  15327     sub_block.runtime_loop = null;
  15328     sub_block.runtime_cond = cond_src;
  15329     sub_block.runtime_index.increment();
  15330     defer sub_block.instructions.deinit(gpa);
  15331 
  15332     _ = sema.analyzeBodyInner(&sub_block, then_body) catch |err| switch (err) {
  15333         error.ComptimeBreak => {
  15334             const zir_datas = sema.code.instructions.items(.data);
  15335             const break_data = zir_datas[sema.comptime_break_inst].@"break";
  15336             try sema.addRuntimeBreak(&sub_block, .{
  15337                 .block_inst = break_data.block_inst,
  15338                 .operand = break_data.operand,
  15339                 .inst = sema.comptime_break_inst,
  15340             });
  15341         },
  15342         else => |e| return e,
  15343     };
  15344     const true_instructions = sub_block.instructions.toOwnedSlice(gpa);
  15345     defer gpa.free(true_instructions);
  15346 
  15347     const err_cond = blk: {
  15348         const index = Zir.refToIndex(extra.data.condition) orelse break :blk null;
  15349         if (sema.code.instructions.items(.tag)[index] != .is_non_err) break :blk null;
  15350 
  15351         const err_inst_data = sema.code.instructions.items(.data)[index].un_node;
  15352         const err_operand = try sema.resolveInst(err_inst_data.operand);
  15353         const operand_ty = sema.typeOf(err_operand);
  15354         assert(operand_ty.zigTypeTag() == .ErrorUnion);
  15355         const result_ty = operand_ty.errorUnionSet();
  15356         break :blk try sub_block.addTyOp(.unwrap_errunion_err, result_ty, err_operand);
  15357     };
  15358 
  15359     if (err_cond != null and try sema.maybeErrorUnwrap(&sub_block, else_body, err_cond.?)) {
  15360         // nothing to do
  15361     } else {
  15362         _ = sema.analyzeBodyInner(&sub_block, else_body) catch |err| switch (err) {
  15363             error.ComptimeBreak => {
  15364                 const zir_datas = sema.code.instructions.items(.data);
  15365                 const break_data = zir_datas[sema.comptime_break_inst].@"break";
  15366                 try sema.addRuntimeBreak(&sub_block, .{
  15367                     .block_inst = break_data.block_inst,
  15368                     .operand = break_data.operand,
  15369                     .inst = sema.comptime_break_inst,
  15370                 });
  15371             },
  15372             else => |e| return e,
  15373         };
  15374     }
  15375     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
  15376         true_instructions.len + sub_block.instructions.items.len);
  15377     _ = try parent_block.addInst(.{
  15378         .tag = .cond_br,
  15379         .data = .{ .pl_op = .{
  15380             .operand = cond,
  15381             .payload = sema.addExtraAssumeCapacity(Air.CondBr{
  15382                 .then_body_len = @intCast(u32, true_instructions.len),
  15383                 .else_body_len = @intCast(u32, sub_block.instructions.items.len),
  15384             }),
  15385         } },
  15386     });
  15387     sema.air_extra.appendSliceAssumeCapacity(true_instructions);
  15388     sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items);
  15389     return always_noreturn;
  15390 }
  15391 
  15392 fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Ref {
  15393     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  15394     const src = inst_data.src();
  15395     const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  15396     const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
  15397     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
  15398     const err_union = try sema.resolveInst(extra.data.operand);
  15399     const err_union_ty = sema.typeOf(err_union);
  15400     if (err_union_ty.zigTypeTag() != .ErrorUnion) {
  15401         return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{
  15402             err_union_ty.fmt(sema.mod),
  15403         });
  15404     }
  15405     const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
  15406     if (is_non_err != .none) {
  15407         const is_non_err_val = (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)).?;
  15408         if (is_non_err_val.toBool()) {
  15409             return sema.analyzeErrUnionPayload(parent_block, src, err_union_ty, err_union, operand_src, false);
  15410         }
  15411         // We can analyze the body directly in the parent block because we know there are
  15412         // no breaks from the body possible, and that the body is noreturn.
  15413         return sema.resolveBody(parent_block, body, inst);
  15414     }
  15415 
  15416     var sub_block = parent_block.makeSubBlock();
  15417     defer sub_block.instructions.deinit(sema.gpa);
  15418 
  15419     // This body is guaranteed to end with noreturn and has no breaks.
  15420     _ = try sema.analyzeBodyInner(&sub_block, body);
  15421 
  15422     try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Try).Struct.fields.len +
  15423         sub_block.instructions.items.len);
  15424     const try_inst = try parent_block.addInst(.{
  15425         .tag = .@"try",
  15426         .data = .{ .pl_op = .{
  15427             .operand = err_union,
  15428             .payload = sema.addExtraAssumeCapacity(Air.Try{
  15429                 .body_len = @intCast(u32, sub_block.instructions.items.len),
  15430             }),
  15431         } },
  15432     });
  15433     sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items);
  15434     return try_inst;
  15435 }
  15436 
  15437 fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Ref {
  15438     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  15439     const src = inst_data.src();
  15440     const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  15441     const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
  15442     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
  15443     const operand = try sema.resolveInst(extra.data.operand);
  15444     const err_union = try sema.analyzeLoad(parent_block, src, operand, operand_src);
  15445     const err_union_ty = sema.typeOf(err_union);
  15446     if (err_union_ty.zigTypeTag() != .ErrorUnion) {
  15447         return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{
  15448             err_union_ty.fmt(sema.mod),
  15449         });
  15450     }
  15451     const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
  15452     if (is_non_err != .none) {
  15453         const is_non_err_val = (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)).?;
  15454         if (is_non_err_val.toBool()) {
  15455             return sema.analyzeErrUnionPayloadPtr(parent_block, src, operand, false, false);
  15456         }
  15457         // We can analyze the body directly in the parent block because we know there are
  15458         // no breaks from the body possible, and that the body is noreturn.
  15459         return sema.resolveBody(parent_block, body, inst);
  15460     }
  15461 
  15462     var sub_block = parent_block.makeSubBlock();
  15463     defer sub_block.instructions.deinit(sema.gpa);
  15464 
  15465     // This body is guaranteed to end with noreturn and has no breaks.
  15466     _ = try sema.analyzeBodyInner(&sub_block, body);
  15467 
  15468     const operand_ty = sema.typeOf(operand);
  15469     const ptr_info = operand_ty.ptrInfo().data;
  15470     const res_ty = try Type.ptr(sema.arena, sema.mod, .{
  15471         .pointee_type = err_union_ty.errorUnionPayload(),
  15472         .@"addrspace" = ptr_info.@"addrspace",
  15473         .mutable = ptr_info.mutable,
  15474         .@"allowzero" = ptr_info.@"allowzero",
  15475         .@"volatile" = ptr_info.@"volatile",
  15476     });
  15477     const res_ty_ref = try sema.addType(res_ty);
  15478     try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.TryPtr).Struct.fields.len +
  15479         sub_block.instructions.items.len);
  15480     const try_inst = try parent_block.addInst(.{
  15481         .tag = .try_ptr,
  15482         .data = .{ .ty_pl = .{
  15483             .ty = res_ty_ref,
  15484             .payload = sema.addExtraAssumeCapacity(Air.TryPtr{
  15485                 .ptr = operand,
  15486                 .body_len = @intCast(u32, sub_block.instructions.items.len),
  15487             }),
  15488         } },
  15489     });
  15490     sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items);
  15491     return try_inst;
  15492 }
  15493 
  15494 // A `break` statement is inside a runtime condition, but trying to
  15495 // break from an inline loop. In such case we must convert it to
  15496 // a runtime break.
  15497 fn addRuntimeBreak(sema: *Sema, child_block: *Block, break_data: BreakData) !void {
  15498     const gop = try sema.inst_map.getOrPut(sema.gpa, break_data.block_inst);
  15499     const labeled_block = if (!gop.found_existing) blk: {
  15500         try sema.post_hoc_blocks.ensureUnusedCapacity(sema.gpa, 1);
  15501 
  15502         const new_block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
  15503         gop.value_ptr.* = Air.indexToRef(new_block_inst);
  15504         try sema.air_instructions.append(sema.gpa, .{
  15505             .tag = .block,
  15506             .data = undefined,
  15507         });
  15508         const labeled_block = try sema.gpa.create(LabeledBlock);
  15509         labeled_block.* = .{
  15510             .label = .{
  15511                 .zir_block = break_data.block_inst,
  15512                 .merges = .{
  15513                     .results = .{},
  15514                     .br_list = .{},
  15515                     .block_inst = new_block_inst,
  15516                 },
  15517             },
  15518             .block = .{
  15519                 .parent = child_block,
  15520                 .sema = sema,
  15521                 .src_decl = child_block.src_decl,
  15522                 .namespace = child_block.namespace,
  15523                 .wip_capture_scope = child_block.wip_capture_scope,
  15524                 .instructions = .{},
  15525                 .label = &labeled_block.label,
  15526                 .inlining = child_block.inlining,
  15527                 .is_comptime = child_block.is_comptime,
  15528             },
  15529         };
  15530         sema.post_hoc_blocks.putAssumeCapacityNoClobber(new_block_inst, labeled_block);
  15531         break :blk labeled_block;
  15532     } else blk: {
  15533         const new_block_inst = Air.refToIndex(gop.value_ptr.*).?;
  15534         const labeled_block = sema.post_hoc_blocks.get(new_block_inst).?;
  15535         break :blk labeled_block;
  15536     };
  15537 
  15538     const operand = try sema.resolveInst(break_data.operand);
  15539     const br_ref = try child_block.addBr(labeled_block.label.merges.block_inst, operand);
  15540     try labeled_block.label.merges.results.append(sema.gpa, operand);
  15541     try labeled_block.label.merges.br_list.append(sema.gpa, Air.refToIndex(br_ref).?);
  15542     labeled_block.block.runtime_index.increment();
  15543     if (labeled_block.block.runtime_cond == null and labeled_block.block.runtime_loop == null) {
  15544         labeled_block.block.runtime_cond = child_block.runtime_cond orelse child_block.runtime_loop;
  15545         labeled_block.block.runtime_loop = child_block.runtime_loop;
  15546     }
  15547 }
  15548 
  15549 fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
  15550     const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable";
  15551     const src = inst_data.src();
  15552 
  15553     if (block.is_comptime or inst_data.force_comptime) {
  15554         return sema.fail(block, src, "reached unreachable code", .{});
  15555     }
  15556     try sema.requireFunctionBlock(block, src);
  15557     // TODO Add compile error for @optimizeFor occurring too late in a scope.
  15558     try block.addUnreachable(src, true);
  15559     return always_noreturn;
  15560 }
  15561 
  15562 fn zirRetErrValue(
  15563     sema: *Sema,
  15564     block: *Block,
  15565     inst: Zir.Inst.Index,
  15566 ) CompileError!Zir.Inst.Index {
  15567     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
  15568     const err_name = inst_data.get(sema.code);
  15569     const src = inst_data.src();
  15570 
  15571     // Return the error code from the function.
  15572     const kv = try sema.mod.getErrorValue(err_name);
  15573     const result_inst = try sema.addConstant(
  15574         try Type.Tag.error_set_single.create(sema.arena, kv.key),
  15575         try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }),
  15576     );
  15577     return sema.analyzeRet(block, result_inst, src);
  15578 }
  15579 
  15580 fn zirRetTok(
  15581     sema: *Sema,
  15582     block: *Block,
  15583     inst: Zir.Inst.Index,
  15584 ) CompileError!Zir.Inst.Index {
  15585     const tracy = trace(@src());
  15586     defer tracy.end();
  15587 
  15588     const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
  15589     const operand = try sema.resolveInst(inst_data.operand);
  15590     const src = inst_data.src();
  15591 
  15592     return sema.analyzeRet(block, operand, src);
  15593 }
  15594 
  15595 fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
  15596     const tracy = trace(@src());
  15597     defer tracy.end();
  15598 
  15599     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15600     const operand = try sema.resolveInst(inst_data.operand);
  15601     const src = inst_data.src();
  15602 
  15603     return sema.analyzeRet(block, operand, src);
  15604 }
  15605 
  15606 fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
  15607     const tracy = trace(@src());
  15608     defer tracy.end();
  15609 
  15610     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15611     const src = inst_data.src();
  15612     const ret_ptr = try sema.resolveInst(inst_data.operand);
  15613 
  15614     if (block.is_comptime or block.inlining != null) {
  15615         const operand = try sema.analyzeLoad(block, src, ret_ptr, src);
  15616         return sema.analyzeRet(block, operand, src);
  15617     }
  15618 
  15619     if (sema.wantErrorReturnTracing()) {
  15620         const is_non_err = try sema.analyzePtrIsNonErr(block, src, ret_ptr);
  15621         return retWithErrTracing(sema, block, src, is_non_err, .ret_load, ret_ptr);
  15622     }
  15623 
  15624     _ = try block.addUnOp(.ret_load, ret_ptr);
  15625     return always_noreturn;
  15626 }
  15627 
  15628 fn retWithErrTracing(
  15629     sema: *Sema,
  15630     block: *Block,
  15631     src: LazySrcLoc,
  15632     is_non_err: Air.Inst.Ref,
  15633     ret_tag: Air.Inst.Tag,
  15634     operand: Air.Inst.Ref,
  15635 ) CompileError!Zir.Inst.Index {
  15636     const need_check = switch (is_non_err) {
  15637         .bool_true => {
  15638             _ = try block.addUnOp(ret_tag, operand);
  15639             return always_noreturn;
  15640         },
  15641         .bool_false => false,
  15642         else => true,
  15643     };
  15644     const gpa = sema.gpa;
  15645     const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
  15646     const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
  15647     const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty);
  15648     const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
  15649     const return_err_fn = try sema.getBuiltin(block, src, "returnError");
  15650     const args: [1]Air.Inst.Ref = .{err_return_trace};
  15651 
  15652     if (!need_check) {
  15653         _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args, null);
  15654         _ = try block.addUnOp(ret_tag, operand);
  15655         return always_noreturn;
  15656     }
  15657 
  15658     var then_block = block.makeSubBlock();
  15659     defer then_block.instructions.deinit(gpa);
  15660     _ = try then_block.addUnOp(ret_tag, operand);
  15661 
  15662     var else_block = block.makeSubBlock();
  15663     defer else_block.instructions.deinit(gpa);
  15664     _ = try sema.analyzeCall(&else_block, return_err_fn, src, src, .never_inline, false, &args, null);
  15665     _ = try else_block.addUnOp(ret_tag, operand);
  15666 
  15667     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
  15668         then_block.instructions.items.len + else_block.instructions.items.len +
  15669         @typeInfo(Air.Block).Struct.fields.len + 1);
  15670 
  15671     const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{
  15672         .then_body_len = @intCast(u32, then_block.instructions.items.len),
  15673         .else_body_len = @intCast(u32, else_block.instructions.items.len),
  15674     });
  15675     sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items);
  15676     sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items);
  15677 
  15678     _ = try block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{
  15679         .operand = is_non_err,
  15680         .payload = cond_br_payload,
  15681     } } });
  15682 
  15683     return always_noreturn;
  15684 }
  15685 
  15686 fn wantErrorReturnTracing(sema: *Sema) bool {
  15687     // TODO implement this feature in all the backends and then delete this check.
  15688     const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;
  15689 
  15690     return sema.fn_ret_ty.isError() and
  15691         sema.mod.comp.bin_file.options.error_return_tracing and
  15692         backend_supports_error_return_tracing;
  15693 }
  15694 
  15695 fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void {
  15696     assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion);
  15697 
  15698     if (sema.fn_ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| {
  15699         const op_ty = sema.typeOf(uncasted_operand);
  15700         switch (op_ty.zigTypeTag()) {
  15701             .ErrorSet => {
  15702                 try payload.data.addErrorSet(sema.gpa, op_ty);
  15703             },
  15704             .ErrorUnion => {
  15705                 try payload.data.addErrorSet(sema.gpa, op_ty.errorUnionSet());
  15706             },
  15707             else => {},
  15708         }
  15709     }
  15710 }
  15711 
  15712 fn analyzeRet(
  15713     sema: *Sema,
  15714     block: *Block,
  15715     uncasted_operand: Air.Inst.Ref,
  15716     src: LazySrcLoc,
  15717 ) CompileError!Zir.Inst.Index {
  15718     // Special case for returning an error to an inferred error set; we need to
  15719     // add the error tag to the inferred error set of the in-scope function, so
  15720     // that the coercion below works correctly.
  15721     if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) {
  15722         try sema.addToInferredErrorSet(uncasted_operand);
  15723     }
  15724     const operand = sema.coerceExtra(block, sema.fn_ret_ty, uncasted_operand, src, .{ .is_ret = true }) catch |err| switch (err) {
  15725         error.NotCoercible => unreachable,
  15726         else => |e| return e,
  15727     };
  15728 
  15729     if (block.inlining) |inlining| {
  15730         if (block.is_comptime) {
  15731             inlining.comptime_result = operand;
  15732             return error.ComptimeReturn;
  15733         }
  15734         // We are inlining a function call; rewrite the `ret` as a `break`.
  15735         try inlining.merges.results.append(sema.gpa, operand);
  15736         _ = try block.addBr(inlining.merges.block_inst, operand);
  15737         return always_noreturn;
  15738     }
  15739 
  15740     try sema.resolveTypeLayout(block, src, sema.fn_ret_ty);
  15741 
  15742     if (sema.wantErrorReturnTracing()) {
  15743         // Avoid adding a frame to the error return trace in case the value is comptime-known
  15744         // to be not an error.
  15745         const is_non_err = try sema.analyzeIsNonErr(block, src, operand);
  15746         return retWithErrTracing(sema, block, src, is_non_err, .ret, operand);
  15747     }
  15748 
  15749     _ = try block.addUnOp(.ret, operand);
  15750     return always_noreturn;
  15751 }
  15752 
  15753 fn floatOpAllowed(tag: Zir.Inst.Tag) bool {
  15754     // extend this swich as additional operators are implemented
  15755     return switch (tag) {
  15756         .add, .sub, .mul, .div, .div_exact, .div_trunc, .div_floor, .mod, .rem, .mod_rem => true,
  15757         else => false,
  15758     };
  15759 }
  15760 
  15761 fn zirOverflowArithmeticPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  15762     const tracy = trace(@src());
  15763     defer tracy.end();
  15764 
  15765     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15766     const elem_ty_src = inst_data.src();
  15767     const elem_type = try sema.resolveType(block, elem_ty_src, inst_data.operand);
  15768     const ty = try Type.ptr(sema.arena, sema.mod, .{
  15769         .pointee_type = elem_type,
  15770         .@"addrspace" = .generic,
  15771         .mutable = true,
  15772         .@"allowzero" = false,
  15773         .@"volatile" = false,
  15774         .size = .One,
  15775     });
  15776     return sema.addType(ty);
  15777 }
  15778 
  15779 fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  15780     const tracy = trace(@src());
  15781     defer tracy.end();
  15782 
  15783     const inst_data = sema.code.instructions.items(.data)[inst].ptr_type;
  15784     const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index);
  15785     const elem_ty_src: LazySrcLoc = .{ .node_offset_ptr_elem = extra.data.src_node };
  15786     const sentinel_src: LazySrcLoc = .{ .node_offset_ptr_sentinel = extra.data.src_node };
  15787     const align_src: LazySrcLoc = .{ .node_offset_ptr_align = extra.data.src_node };
  15788     const addrspace_src: LazySrcLoc = .{ .node_offset_ptr_addrspace = extra.data.src_node };
  15789     const bitoffset_src: LazySrcLoc = .{ .node_offset_ptr_bitoffset = extra.data.src_node };
  15790     const hostsize_src: LazySrcLoc = .{ .node_offset_ptr_hostsize = extra.data.src_node };
  15791 
  15792     const unresolved_elem_ty = try sema.resolveType(block, elem_ty_src, extra.data.elem_type);
  15793     const target = sema.mod.getTarget();
  15794 
  15795     var extra_i = extra.end;
  15796 
  15797     const sentinel = if (inst_data.flags.has_sentinel) blk: {
  15798         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
  15799         extra_i += 1;
  15800         break :blk (try sema.resolveInstConst(block, sentinel_src, ref, "pointer sentinel value must be comptime known")).val;
  15801     } else null;
  15802 
  15803     const abi_align: u32 = if (inst_data.flags.has_align) blk: {
  15804         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
  15805         extra_i += 1;
  15806         const coerced = try sema.coerce(block, Type.u32, try sema.resolveInst(ref), align_src);
  15807         const val = try sema.resolveConstValue(block, align_src, coerced, "pointer alignment must be comptime known");
  15808         // Check if this happens to be the lazy alignment of our element type, in
  15809         // which case we can make this 0 without resolving it.
  15810         if (val.castTag(.lazy_align)) |payload| {
  15811             if (payload.data.eql(unresolved_elem_ty, sema.mod)) {
  15812                 break :blk 0;
  15813             }
  15814         }
  15815         const abi_align = @intCast(u32, (try val.getUnsignedIntAdvanced(target, sema.kit(block, align_src))).?);
  15816         try sema.validateAlign(block, align_src, abi_align);
  15817         break :blk abi_align;
  15818     } else 0;
  15819 
  15820     const address_space = if (inst_data.flags.has_addrspace) blk: {
  15821         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
  15822         extra_i += 1;
  15823         break :blk try sema.analyzeAddrspace(block, addrspace_src, ref, .pointer);
  15824     } else .generic;
  15825 
  15826     const bit_offset = if (inst_data.flags.has_bit_range) blk: {
  15827         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
  15828         extra_i += 1;
  15829         const bit_offset = try sema.resolveInt(block, bitoffset_src, ref, Type.u16, "pointer bit-offset must be comptime known");
  15830         break :blk @intCast(u16, bit_offset);
  15831     } else 0;
  15832 
  15833     const host_size: u16 = if (inst_data.flags.has_bit_range) blk: {
  15834         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
  15835         extra_i += 1;
  15836         const host_size = try sema.resolveInt(block, hostsize_src, ref, Type.u16, "pointer host size must be comptime known");
  15837         break :blk @intCast(u16, host_size);
  15838     } else 0;
  15839 
  15840     if (host_size != 0 and bit_offset >= host_size * 8) {
  15841         return sema.fail(block, bitoffset_src, "bit offset starts after end of host integer", .{});
  15842     }
  15843 
  15844     const elem_ty = if (abi_align == 0)
  15845         unresolved_elem_ty
  15846     else t: {
  15847         const elem_ty = try sema.resolveTypeFields(block, elem_ty_src, unresolved_elem_ty);
  15848         try sema.resolveTypeLayout(block, elem_ty_src, elem_ty);
  15849         break :t elem_ty;
  15850     };
  15851 
  15852     if (elem_ty.zigTypeTag() == .NoReturn) {
  15853         return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{});
  15854     } else if (elem_ty.zigTypeTag() == .Fn) {
  15855         if (inst_data.size != .One) {
  15856             return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{});
  15857         }
  15858         const fn_align = elem_ty.fnInfo().alignment;
  15859         if (inst_data.flags.has_align and abi_align != 0 and fn_align != 0 and
  15860             abi_align != fn_align)
  15861         {
  15862             return sema.fail(block, align_src, "function pointer alignment disagrees with function alignment", .{});
  15863         }
  15864     } else if (inst_data.size == .Many and elem_ty.zigTypeTag() == .Opaque) {
  15865         return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{});
  15866     } else if (inst_data.size == .C) {
  15867         if (!try sema.validateExternType(block, elem_ty_src, elem_ty, .other)) {
  15868             const msg = msg: {
  15869                 const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)});
  15870                 errdefer msg.destroy(sema.gpa);
  15871 
  15872                 const src_decl = sema.mod.declPtr(block.src_decl);
  15873                 try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src.toSrcLoc(src_decl), elem_ty, .other);
  15874 
  15875                 try sema.addDeclaredHereNote(msg, elem_ty);
  15876                 break :msg msg;
  15877             };
  15878             return sema.failWithOwnedErrorMsg(msg);
  15879         }
  15880         if (elem_ty.zigTypeTag() == .Opaque) {
  15881             return sema.fail(block, elem_ty_src, "C pointers cannot point to opaque types", .{});
  15882         }
  15883     }
  15884 
  15885     const ty = try Type.ptr(sema.arena, sema.mod, .{
  15886         .pointee_type = elem_ty,
  15887         .sentinel = sentinel,
  15888         .@"align" = abi_align,
  15889         .@"addrspace" = address_space,
  15890         .bit_offset = bit_offset,
  15891         .host_size = host_size,
  15892         .mutable = inst_data.flags.is_mutable,
  15893         .@"allowzero" = inst_data.flags.is_allowzero,
  15894         .@"volatile" = inst_data.flags.is_volatile,
  15895         .size = inst_data.size,
  15896     });
  15897     return sema.addType(ty);
  15898 }
  15899 
  15900 fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  15901     const tracy = trace(@src());
  15902     defer tracy.end();
  15903 
  15904     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15905     const src = inst_data.src();
  15906     const obj_ty = try sema.resolveType(block, src, inst_data.operand);
  15907 
  15908     switch (obj_ty.zigTypeTag()) {
  15909         .Struct => return sema.structInitEmpty(block, obj_ty, src, src),
  15910         .Array, .Vector => return sema.arrayInitEmpty(block, src, obj_ty),
  15911         .Void => return sema.addConstant(obj_ty, Value.void),
  15912         .Union => return sema.fail(block, src, "union initializer must initialize one field", .{}),
  15913         else => return sema.failWithArrayInitNotSupported(block, src, obj_ty),
  15914     }
  15915 }
  15916 
  15917 fn structInitEmpty(
  15918     sema: *Sema,
  15919     block: *Block,
  15920     obj_ty: Type,
  15921     dest_src: LazySrcLoc,
  15922     init_src: LazySrcLoc,
  15923 ) CompileError!Air.Inst.Ref {
  15924     const gpa = sema.gpa;
  15925     // This logic must be synchronized with that in `zirStructInit`.
  15926     const struct_ty = try sema.resolveTypeFields(block, dest_src, obj_ty);
  15927 
  15928     // The init values to use for the struct instance.
  15929     const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount());
  15930     defer gpa.free(field_inits);
  15931     mem.set(Air.Inst.Ref, field_inits, .none);
  15932 
  15933     return sema.finishStructInit(block, init_src, dest_src, field_inits, struct_ty, false);
  15934 }
  15935 
  15936 fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) CompileError!Air.Inst.Ref {
  15937     const arr_len = obj_ty.arrayLen();
  15938     if (arr_len != 0) {
  15939         if (obj_ty.zigTypeTag() == .Array) {
  15940             return sema.fail(block, src, "expected {d} array elements; found 0", .{arr_len});
  15941         } else {
  15942             return sema.fail(block, src, "expected {d} vector elements; found 0", .{arr_len});
  15943         }
  15944     }
  15945     if (obj_ty.sentinel()) |sentinel| {
  15946         const val = try Value.Tag.empty_array_sentinel.create(sema.arena, sentinel);
  15947         return sema.addConstant(obj_ty, val);
  15948     } else {
  15949         return sema.addConstant(obj_ty, Value.initTag(.empty_array));
  15950     }
  15951 }
  15952 
  15953 fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  15954     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  15955     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  15956     const field_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  15957     const init_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  15958     const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
  15959     const union_ty = try sema.resolveType(block, ty_src, extra.union_type);
  15960     const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "name of field being initialized must be comptime known");
  15961     const init = try sema.resolveInst(extra.init);
  15962     return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src);
  15963 }
  15964 
  15965 fn unionInit(
  15966     sema: *Sema,
  15967     block: *Block,
  15968     uncasted_init: Air.Inst.Ref,
  15969     init_src: LazySrcLoc,
  15970     union_ty: Type,
  15971     union_ty_src: LazySrcLoc,
  15972     field_name: []const u8,
  15973     field_src: LazySrcLoc,
  15974 ) CompileError!Air.Inst.Ref {
  15975     const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
  15976     const field = union_ty.unionFields().values()[field_index];
  15977     const init = try sema.coerce(block, field.ty, uncasted_init, init_src);
  15978 
  15979     if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {
  15980         const tag_ty = union_ty.unionTagTypeHypothetical();
  15981         const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
  15982         const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
  15983         return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{
  15984             .tag = tag_val,
  15985             .val = init_val,
  15986         }));
  15987     }
  15988 
  15989     try sema.requireRuntimeBlock(block, init_src, null);
  15990     _ = union_ty_src;
  15991     try sema.queueFullTypeResolution(union_ty);
  15992     return block.addUnionInit(union_ty, field_index, init);
  15993 }
  15994 
  15995 fn zirStructInit(
  15996     sema: *Sema,
  15997     block: *Block,
  15998     inst: Zir.Inst.Index,
  15999     is_ref: bool,
  16000 ) CompileError!Air.Inst.Ref {
  16001     const gpa = sema.gpa;
  16002     const zir_datas = sema.code.instructions.items(.data);
  16003     const inst_data = zir_datas[inst].pl_node;
  16004     const extra = sema.code.extraData(Zir.Inst.StructInit, inst_data.payload_index);
  16005     const src = inst_data.src();
  16006 
  16007     const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data;
  16008     const first_field_type_data = zir_datas[first_item.field_type].pl_node;
  16009     const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data;
  16010     const resolved_ty = try sema.resolveType(block, src, first_field_type_extra.container_type);
  16011     try sema.resolveTypeLayout(block, src, resolved_ty);
  16012 
  16013     if (resolved_ty.zigTypeTag() == .Struct) {
  16014         // This logic must be synchronized with that in `zirStructInitEmpty`.
  16015 
  16016         // Maps field index to field_type index of where it was already initialized.
  16017         // For making sure all fields are accounted for and no fields are duplicated.
  16018         const found_fields = try gpa.alloc(Zir.Inst.Index, resolved_ty.structFieldCount());
  16019         defer gpa.free(found_fields);
  16020 
  16021         // The init values to use for the struct instance.
  16022         const field_inits = try gpa.alloc(Air.Inst.Ref, resolved_ty.structFieldCount());
  16023         defer gpa.free(field_inits);
  16024         mem.set(Air.Inst.Ref, field_inits, .none);
  16025 
  16026         var field_i: u32 = 0;
  16027         var extra_index = extra.end;
  16028 
  16029         const is_packed = resolved_ty.containerLayout() == .Packed;
  16030         while (field_i < extra.data.fields_len) : (field_i += 1) {
  16031             const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index);
  16032             extra_index = item.end;
  16033 
  16034             const field_type_data = zir_datas[item.data.field_type].pl_node;
  16035             const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };
  16036             const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
  16037             const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
  16038             const field_index = if (resolved_ty.isTuple())
  16039                 try sema.tupleFieldIndex(block, resolved_ty, field_name, field_src)
  16040             else
  16041                 try sema.structFieldIndex(block, resolved_ty, field_name, field_src);
  16042             if (field_inits[field_index] != .none) {
  16043                 const other_field_type = found_fields[field_index];
  16044                 const other_field_type_data = zir_datas[other_field_type].pl_node;
  16045                 const other_field_src: LazySrcLoc = .{ .node_offset_initializer = other_field_type_data.src_node };
  16046                 const msg = msg: {
  16047                     const msg = try sema.errMsg(block, field_src, "duplicate field", .{});
  16048                     errdefer msg.destroy(gpa);
  16049                     try sema.errNote(block, other_field_src, msg, "other field here", .{});
  16050                     break :msg msg;
  16051                 };
  16052                 return sema.failWithOwnedErrorMsg(msg);
  16053             }
  16054             found_fields[field_index] = item.data.field_type;
  16055             field_inits[field_index] = try sema.resolveInst(item.data.init);
  16056             if (!is_packed) if (resolved_ty.structFieldValueComptime(field_index)) |default_value| {
  16057                 const init_val = (try sema.resolveMaybeUndefVal(block, field_src, field_inits[field_index])) orelse {
  16058                     return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime known");
  16059                 };
  16060 
  16061                 if (!init_val.eql(default_value, resolved_ty.structFieldType(field_index), sema.mod)) {
  16062                     return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index);
  16063                 }
  16064             };
  16065         }
  16066 
  16067         return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref);
  16068     } else if (resolved_ty.zigTypeTag() == .Union) {
  16069         if (extra.data.fields_len != 1) {
  16070             return sema.fail(block, src, "union initialization expects exactly one field", .{});
  16071         }
  16072 
  16073         const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end);
  16074 
  16075         const field_type_data = zir_datas[item.data.field_type].pl_node;
  16076         const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };
  16077         const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
  16078         const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
  16079         const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
  16080         const tag_ty = resolved_ty.unionTagTypeHypothetical();
  16081         const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
  16082         const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
  16083 
  16084         const init_inst = try sema.resolveInst(item.data.init);
  16085         if (try sema.resolveMaybeUndefVal(block, field_src, init_inst)) |val| {
  16086             return sema.addConstantMaybeRef(
  16087                 block,
  16088                 src,
  16089                 resolved_ty,
  16090                 try Value.Tag.@"union".create(sema.arena, .{ .tag = tag_val, .val = val }),
  16091                 is_ref,
  16092             );
  16093         }
  16094 
  16095         if (is_ref) {
  16096             const target = sema.mod.getTarget();
  16097             const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
  16098                 .pointee_type = resolved_ty,
  16099                 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  16100             });
  16101             const alloc = try block.addTy(.alloc, alloc_ty);
  16102             const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true);
  16103             try sema.storePtr(block, src, field_ptr, init_inst);
  16104             const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(), tag_val);
  16105             _ = try block.addBinOp(.set_union_tag, alloc, new_tag);
  16106             return alloc;
  16107         }
  16108 
  16109         try sema.requireRuntimeBlock(block, src, null);
  16110         try sema.queueFullTypeResolution(resolved_ty);
  16111         return block.addUnionInit(resolved_ty, field_index, init_inst);
  16112     } else if (resolved_ty.isAnonStruct()) {
  16113         return sema.fail(block, src, "TODO anon struct init validation", .{});
  16114     }
  16115     unreachable;
  16116 }
  16117 
  16118 fn finishStructInit(
  16119     sema: *Sema,
  16120     block: *Block,
  16121     init_src: LazySrcLoc,
  16122     dest_src: LazySrcLoc,
  16123     field_inits: []Air.Inst.Ref,
  16124     struct_ty: Type,
  16125     is_ref: bool,
  16126 ) CompileError!Air.Inst.Ref {
  16127     const gpa = sema.gpa;
  16128 
  16129     var root_msg: ?*Module.ErrorMsg = null;
  16130     errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
  16131 
  16132     if (struct_ty.isAnonStruct()) {
  16133         const struct_obj = struct_ty.castTag(.anon_struct).?.data;
  16134         for (struct_obj.values) |default_val, i| {
  16135             if (field_inits[i] != .none) continue;
  16136 
  16137             if (default_val.tag() == .unreachable_value) {
  16138                 const field_name = struct_obj.names[i];
  16139                 const template = "missing struct field: {s}";
  16140                 const args = .{field_name};
  16141                 if (root_msg) |msg| {
  16142                     try sema.errNote(block, init_src, msg, template, args);
  16143                 } else {
  16144                     root_msg = try sema.errMsg(block, init_src, template, args);
  16145                 }
  16146             } else {
  16147                 field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val);
  16148             }
  16149         }
  16150     } else if (struct_ty.isTuple()) {
  16151         const struct_obj = struct_ty.castTag(.tuple).?.data;
  16152         for (struct_obj.values) |default_val, i| {
  16153             if (field_inits[i] != .none) continue;
  16154 
  16155             if (default_val.tag() == .unreachable_value) {
  16156                 const template = "missing tuple field with index {d}";
  16157                 if (root_msg) |msg| {
  16158                     try sema.errNote(block, init_src, msg, template, .{i});
  16159                 } else {
  16160                     root_msg = try sema.errMsg(block, init_src, template, .{i});
  16161                 }
  16162             } else {
  16163                 field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val);
  16164             }
  16165         }
  16166     } else {
  16167         const struct_obj = struct_ty.castTag(.@"struct").?.data;
  16168         for (struct_obj.fields.values()) |field, i| {
  16169             if (field_inits[i] != .none) continue;
  16170 
  16171             if (field.default_val.tag() == .unreachable_value) {
  16172                 const field_name = struct_obj.fields.keys()[i];
  16173                 const template = "missing struct field: {s}";
  16174                 const args = .{field_name};
  16175                 if (root_msg) |msg| {
  16176                     try sema.errNote(block, init_src, msg, template, args);
  16177                 } else {
  16178                     root_msg = try sema.errMsg(block, init_src, template, args);
  16179                 }
  16180             } else {
  16181                 field_inits[i] = try sema.addConstant(field.ty, field.default_val);
  16182             }
  16183         }
  16184     }
  16185 
  16186     if (root_msg) |msg| {
  16187         root_msg = null;
  16188         if (struct_ty.castTag(.@"struct")) |struct_obj| {
  16189             const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
  16190             defer gpa.free(fqn);
  16191             try sema.mod.errNoteNonLazy(
  16192                 struct_obj.data.srcLoc(sema.mod),
  16193                 msg,
  16194                 "struct '{s}' declared here",
  16195                 .{fqn},
  16196             );
  16197         }
  16198         return sema.failWithOwnedErrorMsg(msg);
  16199     }
  16200 
  16201     const is_comptime = for (field_inits) |field_init| {
  16202         if (!(try sema.isComptimeKnown(block, dest_src, field_init))) {
  16203             break false;
  16204         }
  16205     } else true;
  16206 
  16207     if (is_comptime) {
  16208         const values = try sema.arena.alloc(Value, field_inits.len);
  16209         for (field_inits) |field_init, i| {
  16210             values[i] = (sema.resolveMaybeUndefVal(block, dest_src, field_init) catch unreachable).?;
  16211         }
  16212         const struct_val = try Value.Tag.aggregate.create(sema.arena, values);
  16213         return sema.addConstantMaybeRef(block, dest_src, struct_ty, struct_val, is_ref);
  16214     }
  16215 
  16216     if (is_ref) {
  16217         try sema.resolveStructLayout(block, dest_src, struct_ty);
  16218         const target = sema.mod.getTarget();
  16219         const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
  16220             .pointee_type = struct_ty,
  16221             .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  16222         });
  16223         const alloc = try block.addTy(.alloc, alloc_ty);
  16224         for (field_inits) |field_init, i_usize| {
  16225             const i = @intCast(u32, i_usize);
  16226             const field_src = dest_src;
  16227             const field_ptr = try sema.structFieldPtrByIndex(block, dest_src, alloc, i, field_src, struct_ty, true);
  16228             try sema.storePtr(block, dest_src, field_ptr, field_init);
  16229         }
  16230 
  16231         return alloc;
  16232     }
  16233 
  16234     try sema.requireRuntimeBlock(block, dest_src, null);
  16235     try sema.queueFullTypeResolution(struct_ty);
  16236     return block.addAggregateInit(struct_ty, field_inits);
  16237 }
  16238 
  16239 fn zirStructInitAnon(
  16240     sema: *Sema,
  16241     block: *Block,
  16242     inst: Zir.Inst.Index,
  16243     is_ref: bool,
  16244 ) CompileError!Air.Inst.Ref {
  16245     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  16246     const src = inst_data.src();
  16247     const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);
  16248     const types = try sema.arena.alloc(Type, extra.data.fields_len);
  16249     const values = try sema.arena.alloc(Value, types.len);
  16250     var fields = std.StringArrayHashMapUnmanaged(u32){};
  16251     defer fields.deinit(sema.gpa);
  16252     try fields.ensureUnusedCapacity(sema.gpa, types.len);
  16253 
  16254     const opt_runtime_index = rs: {
  16255         var runtime_index: ?usize = null;
  16256         var extra_index = extra.end;
  16257         for (types) |*field_ty, i| {
  16258             const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
  16259             extra_index = item.end;
  16260 
  16261             const name = sema.code.nullTerminatedString(item.data.field_name);
  16262             const gop = fields.getOrPutAssumeCapacity(name);
  16263             if (gop.found_existing) {
  16264                 const msg = msg: {
  16265                     const decl = sema.mod.declPtr(block.src_decl);
  16266                     const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i);
  16267                     const msg = try sema.errMsg(block, field_src, "duplicate field", .{});
  16268                     errdefer msg.destroy(sema.gpa);
  16269 
  16270                     const prev_source = Module.initSrc(src.node_offset.x, sema.gpa, decl, gop.value_ptr.*);
  16271                     try sema.errNote(block, prev_source, msg, "other field here", .{});
  16272                     break :msg msg;
  16273                 };
  16274                 return sema.failWithOwnedErrorMsg(msg);
  16275             }
  16276             gop.value_ptr.* = @intCast(u32, i);
  16277 
  16278             const init = try sema.resolveInst(item.data.init);
  16279             field_ty.* = sema.typeOf(init);
  16280             if (types[i].zigTypeTag() == .Opaque) {
  16281                 const msg = msg: {
  16282                     const decl = sema.mod.declPtr(block.src_decl);
  16283                     const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i);
  16284                     const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
  16285                     errdefer msg.destroy(sema.gpa);
  16286 
  16287                     try sema.addDeclaredHereNote(msg, types[i]);
  16288                     break :msg msg;
  16289                 };
  16290                 return sema.failWithOwnedErrorMsg(msg);
  16291             }
  16292             const init_src = src; // TODO better source location
  16293             if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {
  16294                 values[i] = init_val;
  16295             } else {
  16296                 values[i] = Value.initTag(.unreachable_value);
  16297                 runtime_index = i;
  16298             }
  16299         }
  16300         break :rs runtime_index;
  16301     };
  16302 
  16303     const tuple_ty = try Type.Tag.anon_struct.create(sema.arena, .{
  16304         .names = try sema.arena.dupe([]const u8, fields.keys()),
  16305         .types = types,
  16306         .values = values,
  16307     });
  16308 
  16309     const runtime_index = opt_runtime_index orelse {
  16310         const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);
  16311         return sema.addConstantMaybeRef(block, src, tuple_ty, tuple_val, is_ref);
  16312     };
  16313 
  16314     sema.requireRuntimeBlock(block, src, .unneeded) catch |err| switch (err) {
  16315         error.NeededSourceLocation => {
  16316             const decl = sema.mod.declPtr(block.src_decl);
  16317             const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, runtime_index);
  16318             try sema.requireRuntimeBlock(block, src, field_src);
  16319             return error.AnalysisFail;
  16320         },
  16321         else => |e| return e,
  16322     };
  16323 
  16324     if (is_ref) {
  16325         const target = sema.mod.getTarget();
  16326         const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
  16327             .pointee_type = tuple_ty,
  16328             .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  16329         });
  16330         const alloc = try block.addTy(.alloc, alloc_ty);
  16331         var extra_index = extra.end;
  16332         for (types) |field_ty, i_usize| {
  16333             const i = @intCast(u32, i_usize);
  16334             const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
  16335             extra_index = item.end;
  16336 
  16337             const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
  16338                 .mutable = true,
  16339                 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  16340                 .pointee_type = field_ty,
  16341             });
  16342             if (values[i].tag() == .unreachable_value) {
  16343                 const init = try sema.resolveInst(item.data.init);
  16344                 const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty);
  16345                 _ = try block.addBinOp(.store, field_ptr, init);
  16346             }
  16347         }
  16348 
  16349         return alloc;
  16350     }
  16351 
  16352     const element_refs = try sema.arena.alloc(Air.Inst.Ref, types.len);
  16353     var extra_index = extra.end;
  16354     for (types) |_, i| {
  16355         const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
  16356         extra_index = item.end;
  16357         element_refs[i] = try sema.resolveInst(item.data.init);
  16358     }
  16359 
  16360     return block.addAggregateInit(tuple_ty, element_refs);
  16361 }
  16362 
  16363 fn zirArrayInit(
  16364     sema: *Sema,
  16365     block: *Block,
  16366     inst: Zir.Inst.Index,
  16367     is_ref: bool,
  16368 ) CompileError!Air.Inst.Ref {
  16369     const gpa = sema.gpa;
  16370     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  16371     const src = inst_data.src();
  16372 
  16373     const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
  16374     const args = sema.code.refSlice(extra.end, extra.data.operands_len);
  16375     assert(args.len >= 2); // array_ty + at least one element
  16376 
  16377     const array_ty = try sema.resolveType(block, src, args[0]);
  16378     const sentinel_val = array_ty.sentinel();
  16379 
  16380     const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @boolToInt(sentinel_val != null));
  16381     defer gpa.free(resolved_args);
  16382     for (args[1..]) |arg, i| {
  16383         const resolved_arg = try sema.resolveInst(arg);
  16384         const arg_src = src; // TODO better source location
  16385         const elem_ty = if (array_ty.zigTypeTag() == .Struct)
  16386             array_ty.tupleFields().types[i]
  16387         else
  16388             array_ty.elemType2();
  16389         resolved_args[i] = try sema.coerce(block, elem_ty, resolved_arg, arg_src);
  16390     }
  16391 
  16392     if (sentinel_val) |some| {
  16393         resolved_args[resolved_args.len - 1] = try sema.addConstant(array_ty.elemType2(), some);
  16394     }
  16395 
  16396     const opt_runtime_src: ?LazySrcLoc = for (resolved_args) |arg| {
  16397         const arg_src = src; // TODO better source location
  16398         const comptime_known = try sema.isComptimeKnown(block, arg_src, arg);
  16399         if (!comptime_known) break arg_src;
  16400     } else null;
  16401 
  16402     const runtime_src = opt_runtime_src orelse {
  16403         const elem_vals = try sema.arena.alloc(Value, resolved_args.len);
  16404 
  16405         for (resolved_args) |arg, i| {
  16406             // We checked that all args are comptime above.
  16407             elem_vals[i] = (sema.resolveMaybeUndefVal(block, src, arg) catch unreachable).?;
  16408         }
  16409 
  16410         const array_val = try Value.Tag.aggregate.create(sema.arena, elem_vals);
  16411         return sema.addConstantMaybeRef(block, src, array_ty, array_val, is_ref);
  16412     };
  16413 
  16414     try sema.requireRuntimeBlock(block, src, runtime_src);
  16415     try sema.queueFullTypeResolution(array_ty);
  16416 
  16417     if (is_ref) {
  16418         const target = sema.mod.getTarget();
  16419         const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
  16420             .pointee_type = array_ty,
  16421             .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  16422         });
  16423         const alloc = try block.addTy(.alloc, alloc_ty);
  16424 
  16425         if (array_ty.isTuple()) {
  16426             const types = array_ty.tupleFields().types;
  16427             for (resolved_args) |arg, i| {
  16428                 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
  16429                     .mutable = true,
  16430                     .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  16431                     .pointee_type = types[i],
  16432                 });
  16433                 const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);
  16434 
  16435                 const index = try sema.addIntUnsigned(Type.usize, i);
  16436                 const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref);
  16437                 _ = try block.addBinOp(.store, elem_ptr, arg);
  16438             }
  16439             return alloc;
  16440         }
  16441 
  16442         const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
  16443             .mutable = true,
  16444             .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  16445             .pointee_type = array_ty.elemType2(),
  16446         });
  16447         const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);
  16448 
  16449         for (resolved_args) |arg, i| {
  16450             const index = try sema.addIntUnsigned(Type.usize, i);
  16451             const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref);
  16452             _ = try block.addBinOp(.store, elem_ptr, arg);
  16453         }
  16454         return alloc;
  16455     }
  16456 
  16457     return block.addAggregateInit(array_ty, resolved_args);
  16458 }
  16459 
  16460 fn zirArrayInitAnon(
  16461     sema: *Sema,
  16462     block: *Block,
  16463     inst: Zir.Inst.Index,
  16464     is_ref: bool,
  16465 ) CompileError!Air.Inst.Ref {
  16466     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  16467     const src = inst_data.src();
  16468     const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
  16469     const operands = sema.code.refSlice(extra.end, extra.data.operands_len);
  16470 
  16471     const types = try sema.arena.alloc(Type, operands.len);
  16472     const values = try sema.arena.alloc(Value, operands.len);
  16473 
  16474     const opt_runtime_src = rs: {
  16475         var runtime_src: ?LazySrcLoc = null;
  16476         for (operands) |operand, i| {
  16477             const operand_src = src; // TODO better source location
  16478             const elem = try sema.resolveInst(operand);
  16479             types[i] = sema.typeOf(elem);
  16480             if (types[i].zigTypeTag() == .Opaque) {
  16481                 const msg = msg: {
  16482                     const msg = try sema.errMsg(block, operand_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
  16483                     errdefer msg.destroy(sema.gpa);
  16484 
  16485                     try sema.addDeclaredHereNote(msg, types[i]);
  16486                     break :msg msg;
  16487                 };
  16488                 return sema.failWithOwnedErrorMsg(msg);
  16489             }
  16490             if (try sema.resolveMaybeUndefVal(block, operand_src, elem)) |val| {
  16491                 values[i] = val;
  16492             } else {
  16493                 values[i] = Value.initTag(.unreachable_value);
  16494                 runtime_src = operand_src;
  16495             }
  16496         }
  16497         break :rs runtime_src;
  16498     };
  16499 
  16500     const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{
  16501         .types = types,
  16502         .values = values,
  16503     });
  16504 
  16505     const runtime_src = opt_runtime_src orelse {
  16506         const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);
  16507         return sema.addConstantMaybeRef(block, src, tuple_ty, tuple_val, is_ref);
  16508     };
  16509 
  16510     try sema.requireRuntimeBlock(block, src, runtime_src);
  16511 
  16512     if (is_ref) {
  16513         const target = sema.mod.getTarget();
  16514         const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
  16515             .pointee_type = tuple_ty,
  16516             .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  16517         });
  16518         const alloc = try block.addTy(.alloc, alloc_ty);
  16519         for (operands) |operand, i_usize| {
  16520             const i = @intCast(u32, i_usize);
  16521             const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
  16522                 .mutable = true,
  16523                 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  16524                 .pointee_type = types[i],
  16525             });
  16526             if (values[i].tag() == .unreachable_value) {
  16527                 const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty);
  16528                 _ = try block.addBinOp(.store, field_ptr, try sema.resolveInst(operand));
  16529             }
  16530         }
  16531 
  16532         return alloc;
  16533     }
  16534 
  16535     const element_refs = try sema.arena.alloc(Air.Inst.Ref, operands.len);
  16536     for (operands) |operand, i| {
  16537         element_refs[i] = try sema.resolveInst(operand);
  16538     }
  16539 
  16540     return block.addAggregateInit(tuple_ty, element_refs);
  16541 }
  16542 
  16543 fn addConstantMaybeRef(
  16544     sema: *Sema,
  16545     block: *Block,
  16546     src: LazySrcLoc,
  16547     ty: Type,
  16548     val: Value,
  16549     is_ref: bool,
  16550 ) !Air.Inst.Ref {
  16551     if (!is_ref) return sema.addConstant(ty, val);
  16552 
  16553     var anon_decl = try block.startAnonDecl(src);
  16554     defer anon_decl.deinit();
  16555     const decl = try anon_decl.finish(
  16556         try ty.copy(anon_decl.arena()),
  16557         try val.copy(anon_decl.arena()),
  16558         0, // default alignment
  16559     );
  16560     return sema.analyzeDeclRef(decl);
  16561 }
  16562 
  16563 fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  16564     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  16565     const extra = sema.code.extraData(Zir.Inst.FieldTypeRef, inst_data.payload_index).data;
  16566     const ty_src = inst_data.src();
  16567     const field_src = inst_data.src();
  16568     const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);
  16569     const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "field name must be comptime known");
  16570     return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
  16571 }
  16572 
  16573 fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  16574     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  16575     const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
  16576     const ty_src = inst_data.src();
  16577     const field_src = inst_data.src();
  16578     const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);
  16579     if (aggregate_ty.tag() == .var_args_param) return sema.addType(aggregate_ty);
  16580     const field_name = sema.code.nullTerminatedString(extra.name_start);
  16581     return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
  16582 }
  16583 
  16584 fn fieldType(
  16585     sema: *Sema,
  16586     block: *Block,
  16587     aggregate_ty: Type,
  16588     field_name: []const u8,
  16589     field_src: LazySrcLoc,
  16590     ty_src: LazySrcLoc,
  16591 ) CompileError!Air.Inst.Ref {
  16592     var cur_ty = aggregate_ty;
  16593     while (true) {
  16594         const resolved_ty = try sema.resolveTypeFields(block, ty_src, cur_ty);
  16595         cur_ty = resolved_ty;
  16596         switch (cur_ty.zigTypeTag()) {
  16597             .Struct => {
  16598                 if (cur_ty.isAnonStruct()) {
  16599                     const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src);
  16600                     return sema.addType(cur_ty.tupleFields().types[field_index]);
  16601                 }
  16602                 const struct_obj = cur_ty.castTag(.@"struct").?.data;
  16603                 const field = struct_obj.fields.get(field_name) orelse
  16604                     return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
  16605                 return sema.addType(field.ty);
  16606             },
  16607             .Union => {
  16608                 const union_obj = cur_ty.cast(Type.Payload.Union).?.data;
  16609                 const field = union_obj.fields.get(field_name) orelse
  16610                     return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
  16611                 return sema.addType(field.ty);
  16612             },
  16613             .Optional => {
  16614                 if (cur_ty.castTag(.optional)) |some| {
  16615                     // Struct/array init through optional requires the child type to not be a pointer.
  16616                     // If the child of .optional is a pointer it'll error on the next loop.
  16617                     cur_ty = some.data;
  16618                     continue;
  16619                 }
  16620             },
  16621             .ErrorUnion => {
  16622                 cur_ty = cur_ty.errorUnionPayload();
  16623                 continue;
  16624             },
  16625             else => {},
  16626         }
  16627         return sema.fail(block, ty_src, "expected struct or union; found '{}'", .{
  16628             resolved_ty.fmt(sema.mod),
  16629         });
  16630     }
  16631 }
  16632 
  16633 fn zirErrorReturnTrace(
  16634     sema: *Sema,
  16635     block: *Block,
  16636     extended: Zir.Inst.Extended.InstData,
  16637 ) CompileError!Air.Inst.Ref {
  16638     const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
  16639     return sema.getErrorReturnTrace(block, src);
  16640 }
  16641 
  16642 fn getErrorReturnTrace(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError!Air.Inst.Ref {
  16643     const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
  16644     const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
  16645     const opt_ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty);
  16646 
  16647     // TODO implement this feature in all the backends and then delete this check.
  16648     const backend_supports_error_return_tracing =
  16649         sema.mod.comp.bin_file.options.use_llvm;
  16650 
  16651     if (sema.owner_func != null and
  16652         sema.owner_func.?.calls_or_awaits_errorable_fn and
  16653         sema.mod.comp.bin_file.options.error_return_tracing and
  16654         backend_supports_error_return_tracing)
  16655     {
  16656         return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
  16657     }
  16658     return sema.addConstant(opt_ptr_stack_trace_ty, Value.@"null");
  16659 }
  16660 
  16661 fn zirFrame(
  16662     sema: *Sema,
  16663     block: *Block,
  16664     extended: Zir.Inst.Extended.InstData,
  16665 ) CompileError!Air.Inst.Ref {
  16666     const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
  16667     return sema.failWithUseOfAsync(block, src);
  16668 }
  16669 
  16670 fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  16671     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  16672     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  16673     const ty = try sema.resolveType(block, operand_src, inst_data.operand);
  16674     if (ty.isNoReturn()) {
  16675         return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.mod)});
  16676     }
  16677     const target = sema.mod.getTarget();
  16678     const val = try ty.lazyAbiAlignment(target, sema.arena);
  16679     if (val.tag() == .lazy_align) {
  16680         try sema.queueFullTypeResolution(ty);
  16681     }
  16682     return sema.addConstant(Type.comptime_int, val);
  16683 }
  16684 
  16685 fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  16686     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  16687     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  16688     const operand = try sema.resolveInst(inst_data.operand);
  16689     if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
  16690         if (val.isUndef()) return sema.addConstUndef(Type.initTag(.u1));
  16691         const bool_ints = [2]Air.Inst.Ref{ .zero, .one };
  16692         return bool_ints[@boolToInt(val.toBool())];
  16693     }
  16694     return block.addUnOp(.bool_to_int, operand);
  16695 }
  16696 
  16697 fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  16698     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  16699     const src = inst_data.src();
  16700     _ = src;
  16701     const operand = try sema.resolveInst(inst_data.operand);
  16702     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  16703 
  16704     if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {
  16705         const bytes = val.castTag(.@"error").?.data.name;
  16706         return sema.addStrLit(block, bytes);
  16707     }
  16708 
  16709     // Similar to zirTagName, we have special AIR instruction for the error name in case an optimimzation pass
  16710     // might be able to resolve the result at compile time.
  16711     return block.addUnOp(.error_name, operand);
  16712 }
  16713 
  16714 fn zirUnaryMath(
  16715     sema: *Sema,
  16716     block: *Block,
  16717     inst: Zir.Inst.Index,
  16718     air_tag: Air.Inst.Tag,
  16719     comptime eval: fn (Value, Type, Allocator, std.Target) Allocator.Error!Value,
  16720 ) CompileError!Air.Inst.Ref {
  16721     const tracy = trace(@src());
  16722     defer tracy.end();
  16723 
  16724     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  16725     const operand = try sema.resolveInst(inst_data.operand);
  16726     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  16727     const operand_ty = sema.typeOf(operand);
  16728     const target = sema.mod.getTarget();
  16729 
  16730     switch (operand_ty.zigTypeTag()) {
  16731         .ComptimeFloat, .Float => {},
  16732         .Vector => {
  16733             const scalar_ty = operand_ty.scalarType();
  16734             switch (scalar_ty.zigTypeTag()) {
  16735                 .ComptimeFloat, .Float => {},
  16736                 else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{scalar_ty.fmt(sema.mod)}),
  16737             }
  16738         },
  16739         else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{operand_ty.fmt(sema.mod)}),
  16740     }
  16741 
  16742     switch (operand_ty.zigTypeTag()) {
  16743         .Vector => {
  16744             const scalar_ty = operand_ty.scalarType();
  16745             const vec_len = operand_ty.vectorLen();
  16746             const result_ty = try Type.vector(sema.arena, vec_len, scalar_ty);
  16747             if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
  16748                 if (val.isUndef())
  16749                     return sema.addConstUndef(result_ty);
  16750 
  16751                 var elem_buf: Value.ElemValueBuffer = undefined;
  16752                 const elems = try sema.arena.alloc(Value, vec_len);
  16753                 for (elems) |*elem, i| {
  16754                     const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf);
  16755                     elem.* = try eval(elem_val, scalar_ty, sema.arena, target);
  16756                 }
  16757                 return sema.addConstant(
  16758                     result_ty,
  16759                     try Value.Tag.aggregate.create(sema.arena, elems),
  16760                 );
  16761             }
  16762 
  16763             try sema.requireRuntimeBlock(block, operand_src, null);
  16764             return block.addUnOp(air_tag, operand);
  16765         },
  16766         .ComptimeFloat, .Float => {
  16767             if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| {
  16768                 if (operand_val.isUndef())
  16769                     return sema.addConstUndef(operand_ty);
  16770                 const result_val = try eval(operand_val, operand_ty, sema.arena, target);
  16771                 return sema.addConstant(operand_ty, result_val);
  16772             }
  16773 
  16774             try sema.requireRuntimeBlock(block, operand_src, null);
  16775             return block.addUnOp(air_tag, operand);
  16776         },
  16777         else => unreachable,
  16778     }
  16779 }
  16780 
  16781 fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  16782     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  16783     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  16784     const src = inst_data.src();
  16785     const operand = try sema.resolveInst(inst_data.operand);
  16786     const operand_ty = sema.typeOf(operand);
  16787     const mod = sema.mod;
  16788 
  16789     try sema.resolveTypeLayout(block, operand_src, operand_ty);
  16790     const enum_ty = switch (operand_ty.zigTypeTag()) {
  16791         .EnumLiteral => {
  16792             const val = try sema.resolveConstValue(block, .unneeded, operand, undefined);
  16793             const bytes = val.castTag(.enum_literal).?.data;
  16794             return sema.addStrLit(block, bytes);
  16795         },
  16796         .Enum => operand_ty,
  16797         .Union => operand_ty.unionTagType() orelse {
  16798             const msg = msg: {
  16799                 const msg = try sema.errMsg(block, src, "union '{}' is untagged", .{
  16800                     operand_ty.fmt(sema.mod),
  16801                 });
  16802                 errdefer msg.destroy(sema.gpa);
  16803                 try sema.addDeclaredHereNote(msg, operand_ty);
  16804                 break :msg msg;
  16805             };
  16806             return sema.failWithOwnedErrorMsg(msg);
  16807         },
  16808         else => return sema.fail(block, operand_src, "expected enum or union; found '{}'", .{
  16809             operand_ty.fmt(mod),
  16810         }),
  16811     };
  16812     const enum_decl_index = enum_ty.getOwnerDecl();
  16813     const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src);
  16814     if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| {
  16815         const field_index = enum_ty.enumTagFieldIndex(val, mod) orelse {
  16816             const enum_decl = mod.declPtr(enum_decl_index);
  16817             const msg = msg: {
  16818                 const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{s}'", .{
  16819                     val.fmtValue(enum_ty, sema.mod), enum_decl.name,
  16820                 });
  16821                 errdefer msg.destroy(sema.gpa);
  16822                 try mod.errNoteNonLazy(enum_decl.srcLoc(), msg, "declared here", .{});
  16823                 break :msg msg;
  16824             };
  16825             return sema.failWithOwnedErrorMsg(msg);
  16826         };
  16827         const field_name = enum_ty.enumFieldName(field_index);
  16828         return sema.addStrLit(block, field_name);
  16829     }
  16830     try sema.requireRuntimeBlock(block, src, operand_src);
  16831     if (block.wantSafety() and sema.mod.comp.bin_file.options.use_llvm) {
  16832         const ok = try block.addUnOp(.is_named_enum_value, casted_operand);
  16833         try sema.addSafetyCheck(block, ok, .invalid_enum_value);
  16834     }
  16835     // In case the value is runtime-known, we have an AIR instruction for this instead
  16836     // of trying to lower it in Sema because an optimization pass may result in the operand
  16837     // being comptime-known, which would let us elide the `tag_name` AIR instruction.
  16838     return block.addUnOp(.tag_name, casted_operand);
  16839 }
  16840 
  16841 fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  16842     const mod = sema.mod;
  16843     const name_strategy = @intToEnum(Zir.Inst.NameStrategy, extended.small);
  16844     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  16845     const src = LazySrcLoc.nodeOffset(extra.node);
  16846     const type_info_ty = try sema.resolveBuiltinTypeFields(block, src, "Type");
  16847     const uncasted_operand = try sema.resolveInst(extra.operand);
  16848     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  16849     const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src);
  16850     const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime known");
  16851     const union_val = val.cast(Value.Payload.Union).?.data;
  16852     const target = mod.getTarget();
  16853     const tag_index = type_info_ty.unionTagFieldIndex(union_val.tag, mod).?;
  16854     if (union_val.val.anyUndef()) return sema.failWithUseOfUndef(block, src);
  16855     switch (@intToEnum(std.builtin.TypeId, tag_index)) {
  16856         .Type => return Air.Inst.Ref.type_type,
  16857         .Void => return Air.Inst.Ref.void_type,
  16858         .Bool => return Air.Inst.Ref.bool_type,
  16859         .NoReturn => return Air.Inst.Ref.noreturn_type,
  16860         .ComptimeFloat => return Air.Inst.Ref.comptime_float_type,
  16861         .ComptimeInt => return Air.Inst.Ref.comptime_int_type,
  16862         .Undefined => return Air.Inst.Ref.undefined_type,
  16863         .Null => return Air.Inst.Ref.null_type,
  16864         .AnyFrame => return sema.failWithUseOfAsync(block, src),
  16865         .EnumLiteral => return Air.Inst.Ref.enum_literal_type,
  16866         .Int => {
  16867             const struct_val = union_val.val.castTag(.aggregate).?.data;
  16868             // TODO use reflection instead of magic numbers here
  16869             const signedness_val = struct_val[0];
  16870             const bits_val = struct_val[1];
  16871 
  16872             const signedness = signedness_val.toEnum(std.builtin.Signedness);
  16873             const bits = @intCast(u16, bits_val.toUnsignedInt(target));
  16874             const ty = switch (signedness) {
  16875                 .signed => try Type.Tag.int_signed.create(sema.arena, bits),
  16876                 .unsigned => try Type.Tag.int_unsigned.create(sema.arena, bits),
  16877             };
  16878             return sema.addType(ty);
  16879         },
  16880         .Vector => {
  16881             const struct_val = union_val.val.castTag(.aggregate).?.data;
  16882             // TODO use reflection instead of magic numbers here
  16883             const len_val = struct_val[0];
  16884             const child_val = struct_val[1];
  16885 
  16886             const len = len_val.toUnsignedInt(target);
  16887             var buffer: Value.ToTypeBuffer = undefined;
  16888             const child_ty = child_val.toType(&buffer);
  16889 
  16890             try sema.checkVectorElemType(block, src, child_ty);
  16891 
  16892             const ty = try Type.vector(sema.arena, len, try child_ty.copy(sema.arena));
  16893             return sema.addType(ty);
  16894         },
  16895         .Float => {
  16896             const struct_val = union_val.val.castTag(.aggregate).?.data;
  16897             // TODO use reflection instead of magic numbers here
  16898             // bits: comptime_int,
  16899             const bits_val = struct_val[0];
  16900 
  16901             const bits = @intCast(u16, bits_val.toUnsignedInt(target));
  16902             const ty = switch (bits) {
  16903                 16 => Type.@"f16",
  16904                 32 => Type.@"f32",
  16905                 64 => Type.@"f64",
  16906                 80 => Type.@"f80",
  16907                 128 => Type.@"f128",
  16908                 else => return sema.fail(block, src, "{}-bit float unsupported", .{bits}),
  16909             };
  16910             return sema.addType(ty);
  16911         },
  16912         .Pointer => {
  16913             const struct_val = union_val.val.castTag(.aggregate).?.data;
  16914             // TODO use reflection instead of magic numbers here
  16915             const size_val = struct_val[0];
  16916             const is_const_val = struct_val[1];
  16917             const is_volatile_val = struct_val[2];
  16918             const alignment_val = struct_val[3];
  16919             const address_space_val = struct_val[4];
  16920             const child_val = struct_val[5];
  16921             const is_allowzero_val = struct_val[6];
  16922             const sentinel_val = struct_val[7];
  16923 
  16924             if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) {
  16925                 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
  16926             }
  16927             const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?);
  16928 
  16929             var buffer: Value.ToTypeBuffer = undefined;
  16930             const unresolved_elem_ty = child_val.toType(&buffer);
  16931             const elem_ty = if (abi_align == 0)
  16932                 unresolved_elem_ty
  16933             else t: {
  16934                 const elem_ty = try sema.resolveTypeFields(block, src, unresolved_elem_ty);
  16935                 try sema.resolveTypeLayout(block, src, elem_ty);
  16936                 break :t elem_ty;
  16937             };
  16938 
  16939             const ptr_size = size_val.toEnum(std.builtin.Type.Pointer.Size);
  16940 
  16941             var actual_sentinel: ?Value = null;
  16942             if (!sentinel_val.isNull()) {
  16943                 if (ptr_size == .One or ptr_size == .C) {
  16944                     return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{});
  16945                 }
  16946                 const sentinel_ptr_val = sentinel_val.castTag(.opt_payload).?.data;
  16947                 const ptr_ty = try Type.ptr(sema.arena, mod, .{
  16948                     .@"addrspace" = .generic,
  16949                     .pointee_type = try elem_ty.copy(sema.arena),
  16950                 });
  16951                 actual_sentinel = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?;
  16952             }
  16953 
  16954             if (elem_ty.zigTypeTag() == .NoReturn) {
  16955                 return sema.fail(block, src, "pointer to noreturn not allowed", .{});
  16956             } else if (elem_ty.zigTypeTag() == .Fn) {
  16957                 if (ptr_size != .One) {
  16958                     return sema.fail(block, src, "function pointers must be single pointers", .{});
  16959                 }
  16960                 const fn_align = elem_ty.fnInfo().alignment;
  16961                 if (abi_align != 0 and fn_align != 0 and
  16962                     abi_align != fn_align)
  16963                 {
  16964                     return sema.fail(block, src, "function pointer alignment disagrees with function alignment", .{});
  16965                 }
  16966             } else if (ptr_size == .Many and elem_ty.zigTypeTag() == .Opaque) {
  16967                 return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{});
  16968             } else if (ptr_size == .C) {
  16969                 if (!try sema.validateExternType(block, src, elem_ty, .other)) {
  16970                     const msg = msg: {
  16971                         const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)});
  16972                         errdefer msg.destroy(sema.gpa);
  16973 
  16974                         const src_decl = sema.mod.declPtr(block.src_decl);
  16975                         try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), elem_ty, .other);
  16976 
  16977                         try sema.addDeclaredHereNote(msg, elem_ty);
  16978                         break :msg msg;
  16979                     };
  16980                     return sema.failWithOwnedErrorMsg(msg);
  16981                 }
  16982                 if (elem_ty.zigTypeTag() == .Opaque) {
  16983                     return sema.fail(block, src, "C pointers cannot point to opaque types", .{});
  16984                 }
  16985             }
  16986 
  16987             const ty = try Type.ptr(sema.arena, mod, .{
  16988                 .size = ptr_size,
  16989                 .mutable = !is_const_val.toBool(),
  16990                 .@"volatile" = is_volatile_val.toBool(),
  16991                 .@"align" = abi_align,
  16992                 .@"addrspace" = address_space_val.toEnum(std.builtin.AddressSpace),
  16993                 .pointee_type = try elem_ty.copy(sema.arena),
  16994                 .@"allowzero" = is_allowzero_val.toBool(),
  16995                 .sentinel = actual_sentinel,
  16996             });
  16997             return sema.addType(ty);
  16998         },
  16999         .Array => {
  17000             const struct_val = union_val.val.castTag(.aggregate).?.data;
  17001             // TODO use reflection instead of magic numbers here
  17002             // len: comptime_int,
  17003             const len_val = struct_val[0];
  17004             // child: type,
  17005             const child_val = struct_val[1];
  17006             // sentinel: ?*const anyopaque,
  17007             const sentinel_val = struct_val[2];
  17008 
  17009             const len = len_val.toUnsignedInt(target);
  17010             var buffer: Value.ToTypeBuffer = undefined;
  17011             const child_ty = try child_val.toType(&buffer).copy(sema.arena);
  17012             const sentinel = if (sentinel_val.castTag(.opt_payload)) |p| blk: {
  17013                 const ptr_ty = try Type.ptr(sema.arena, mod, .{
  17014                     .@"addrspace" = .generic,
  17015                     .pointee_type = child_ty,
  17016                 });
  17017                 break :blk (try sema.pointerDeref(block, src, p.data, ptr_ty)).?;
  17018             } else null;
  17019 
  17020             const ty = try Type.array(sema.arena, len, sentinel, child_ty, sema.mod);
  17021             return sema.addType(ty);
  17022         },
  17023         .Optional => {
  17024             const struct_val = union_val.val.castTag(.aggregate).?.data;
  17025             // TODO use reflection instead of magic numbers here
  17026             // child: type,
  17027             const child_val = struct_val[0];
  17028 
  17029             var buffer: Value.ToTypeBuffer = undefined;
  17030             const child_ty = try child_val.toType(&buffer).copy(sema.arena);
  17031 
  17032             const ty = try Type.optional(sema.arena, child_ty);
  17033             return sema.addType(ty);
  17034         },
  17035         .ErrorUnion => {
  17036             const struct_val = union_val.val.castTag(.aggregate).?.data;
  17037             // TODO use reflection instead of magic numbers here
  17038             // error_set: type,
  17039             const error_set_val = struct_val[0];
  17040             // payload: type,
  17041             const payload_val = struct_val[1];
  17042 
  17043             var buffer: Value.ToTypeBuffer = undefined;
  17044             const error_set_ty = try error_set_val.toType(&buffer).copy(sema.arena);
  17045             const payload_ty = try payload_val.toType(&buffer).copy(sema.arena);
  17046 
  17047             if (error_set_ty.zigTypeTag() != .ErrorSet) {
  17048                 return sema.fail(block, src, "Type.ErrorUnion.error_set must be an error set type", .{});
  17049             }
  17050 
  17051             const ty = try Type.Tag.error_union.create(sema.arena, .{
  17052                 .error_set = error_set_ty,
  17053                 .payload = payload_ty,
  17054             });
  17055             return sema.addType(ty);
  17056         },
  17057         .ErrorSet => {
  17058             const payload_val = union_val.val.optionalValue() orelse
  17059                 return sema.addType(Type.initTag(.anyerror));
  17060             const slice_val = payload_val.castTag(.slice).?.data;
  17061 
  17062             const len = try sema.usizeCast(block, src, slice_val.len.toUnsignedInt(mod.getTarget()));
  17063             var names: Module.ErrorSet.NameMap = .{};
  17064             try names.ensureUnusedCapacity(sema.arena, len);
  17065             var i: usize = 0;
  17066             while (i < len) : (i += 1) {
  17067                 var buf: Value.ElemValueBuffer = undefined;
  17068                 const elem_val = slice_val.ptr.elemValueBuffer(mod, i, &buf);
  17069                 const struct_val = elem_val.castTag(.aggregate).?.data;
  17070                 // TODO use reflection instead of magic numbers here
  17071                 // error_set: type,
  17072                 const name_val = struct_val[0];
  17073                 const name_str = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, sema.mod);
  17074 
  17075                 const kv = try mod.getErrorValue(name_str);
  17076                 const gop = names.getOrPutAssumeCapacity(kv.key);
  17077                 if (gop.found_existing) {
  17078                     return sema.fail(block, src, "duplicate error '{s}'", .{name_str});
  17079                 }
  17080             }
  17081 
  17082             // names must be sorted
  17083             Module.ErrorSet.sortNames(&names);
  17084             const ty = try Type.Tag.error_set_merged.create(sema.arena, names);
  17085             return sema.addType(ty);
  17086         },
  17087         .Struct => {
  17088             // TODO use reflection instead of magic numbers here
  17089             const struct_val = union_val.val.castTag(.aggregate).?.data;
  17090             // layout: containerlayout,
  17091             const layout_val = struct_val[0];
  17092             // backing_int: ?type,
  17093             const backing_int_val = struct_val[1];
  17094             // fields: []const enumfield,
  17095             const fields_val = struct_val[2];
  17096             // decls: []const declaration,
  17097             const decls_val = struct_val[3];
  17098             // is_tuple: bool,
  17099             const is_tuple_val = struct_val[4];
  17100             assert(struct_val.len == 5);
  17101 
  17102             const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout);
  17103 
  17104             // Decls
  17105             if (decls_val.sliceLen(mod) > 0) {
  17106                 return sema.fail(block, src, "reified structs must have no decls", .{});
  17107             }
  17108 
  17109             if (layout != .Packed and !backing_int_val.isNull()) {
  17110                 return sema.fail(block, src, "non-packed struct does not support backing integer type", .{});
  17111             }
  17112 
  17113             return if (is_tuple_val.toBool())
  17114                 try sema.reifyTuple(block, src, fields_val)
  17115             else
  17116                 try sema.reifyStruct(block, inst, src, layout, backing_int_val, fields_val, name_strategy);
  17117         },
  17118         .Enum => {
  17119             const struct_val: []const Value = union_val.val.castTag(.aggregate).?.data;
  17120             // TODO use reflection instead of magic numbers here
  17121             // layout: ContainerLayout,
  17122             const layout_val = struct_val[0];
  17123             // tag_type: type,
  17124             const tag_type_val = struct_val[1];
  17125             // fields: []const EnumField,
  17126             const fields_val = struct_val[2];
  17127             // decls: []const Declaration,
  17128             const decls_val = struct_val[3];
  17129             // is_exhaustive: bool,
  17130             const is_exhaustive_val = struct_val[4];
  17131 
  17132             // enum layout is always auto
  17133             const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout);
  17134             if (layout != .Auto) {
  17135                 return sema.fail(block, src, "reified enums must have a layout .Auto", .{});
  17136             }
  17137 
  17138             // Decls
  17139             if (decls_val.sliceLen(mod) > 0) {
  17140                 return sema.fail(block, src, "reified enums must have no decls", .{});
  17141             }
  17142 
  17143             const gpa = sema.gpa;
  17144             var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
  17145             errdefer new_decl_arena.deinit();
  17146             const new_decl_arena_allocator = new_decl_arena.allocator();
  17147 
  17148             // Define our empty enum decl
  17149             const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull);
  17150             const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumFull);
  17151             enum_ty_payload.* = .{
  17152                 .base = .{
  17153                     .tag = if (!is_exhaustive_val.toBool())
  17154                         .enum_nonexhaustive
  17155                     else
  17156                         .enum_full,
  17157                 },
  17158                 .data = enum_obj,
  17159             };
  17160             const enum_ty = Type.initPayload(&enum_ty_payload.base);
  17161             const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
  17162             const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
  17163                 .ty = Type.type,
  17164                 .val = enum_val,
  17165             }, name_strategy, "enum", inst);
  17166             const new_decl = mod.declPtr(new_decl_index);
  17167             new_decl.owns_tv = true;
  17168             errdefer mod.abortAnonDecl(new_decl_index);
  17169 
  17170             enum_obj.* = .{
  17171                 .owner_decl = new_decl_index,
  17172                 .tag_ty = Type.@"null",
  17173                 .tag_ty_inferred = false,
  17174                 .fields = .{},
  17175                 .values = .{},
  17176                 .namespace = .{
  17177                     .parent = block.namespace,
  17178                     .ty = enum_ty,
  17179                     .file_scope = block.getFileScope(),
  17180                 },
  17181             };
  17182 
  17183             // Enum tag type
  17184             var buffer: Value.ToTypeBuffer = undefined;
  17185             const int_tag_ty = try tag_type_val.toType(&buffer).copy(new_decl_arena_allocator);
  17186 
  17187             if (int_tag_ty.zigTypeTag() != .Int) {
  17188                 return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{});
  17189             }
  17190             enum_obj.tag_ty = int_tag_ty;
  17191 
  17192             // Fields
  17193             const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
  17194             try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
  17195             try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
  17196                 .ty = enum_obj.tag_ty,
  17197                 .mod = mod,
  17198             });
  17199 
  17200             var i: usize = 0;
  17201             while (i < fields_len) : (i += 1) {
  17202                 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
  17203                 const field_struct_val: []const Value = elem_val.castTag(.aggregate).?.data;
  17204                 // TODO use reflection instead of magic numbers here
  17205                 // name: []const u8
  17206                 const name_val = field_struct_val[0];
  17207                 // value: comptime_int
  17208                 const value_val = field_struct_val[1];
  17209 
  17210                 const field_name = try name_val.toAllocatedBytes(
  17211                     Type.initTag(.const_slice_u8),
  17212                     new_decl_arena_allocator,
  17213                     sema.mod,
  17214                 );
  17215 
  17216                 if (!try sema.intFitsInType(block, src, value_val, enum_obj.tag_ty, null)) {
  17217                     // TODO: better source location
  17218                     return sema.fail(block, src, "field '{s}' with enumeration value '{}' is too large for backing int type '{}'", .{
  17219                         field_name,
  17220                         value_val.fmtValue(Type.@"comptime_int", mod),
  17221                         enum_obj.tag_ty.fmt(mod),
  17222                     });
  17223                 }
  17224 
  17225                 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);
  17226                 if (gop.found_existing) {
  17227                     // TODO: better source location
  17228                     return sema.fail(block, src, "duplicate enum tag {s}", .{field_name});
  17229                 }
  17230 
  17231                 const copied_tag_val = try value_val.copy(new_decl_arena_allocator);
  17232                 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{
  17233                     .ty = enum_obj.tag_ty,
  17234                     .mod = mod,
  17235                 });
  17236             }
  17237 
  17238             try new_decl.finalizeNewArena(&new_decl_arena);
  17239             return sema.analyzeDeclVal(block, src, new_decl_index);
  17240         },
  17241         .Opaque => {
  17242             const struct_val = union_val.val.castTag(.aggregate).?.data;
  17243             // decls: []const Declaration,
  17244             const decls_val = struct_val[0];
  17245 
  17246             // Decls
  17247             if (decls_val.sliceLen(mod) > 0) {
  17248                 return sema.fail(block, src, "reified opaque must have no decls", .{});
  17249             }
  17250 
  17251             var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
  17252             errdefer new_decl_arena.deinit();
  17253             const new_decl_arena_allocator = new_decl_arena.allocator();
  17254 
  17255             const opaque_obj = try new_decl_arena_allocator.create(Module.Opaque);
  17256             const opaque_ty_payload = try new_decl_arena_allocator.create(Type.Payload.Opaque);
  17257             opaque_ty_payload.* = .{
  17258                 .base = .{ .tag = .@"opaque" },
  17259                 .data = opaque_obj,
  17260             };
  17261             const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
  17262             const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty);
  17263             const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
  17264                 .ty = Type.type,
  17265                 .val = opaque_val,
  17266             }, name_strategy, "opaque", inst);
  17267             const new_decl = mod.declPtr(new_decl_index);
  17268             new_decl.owns_tv = true;
  17269             errdefer mod.abortAnonDecl(new_decl_index);
  17270 
  17271             opaque_obj.* = .{
  17272                 .owner_decl = new_decl_index,
  17273                 .namespace = .{
  17274                     .parent = block.namespace,
  17275                     .ty = opaque_ty,
  17276                     .file_scope = block.getFileScope(),
  17277                 },
  17278             };
  17279 
  17280             try new_decl.finalizeNewArena(&new_decl_arena);
  17281             return sema.analyzeDeclVal(block, src, new_decl_index);
  17282         },
  17283         .Union => {
  17284             // TODO use reflection instead of magic numbers here
  17285             const struct_val = union_val.val.castTag(.aggregate).?.data;
  17286             // layout: containerlayout,
  17287             const layout_val = struct_val[0];
  17288             // tag_type: ?type,
  17289             const tag_type_val = struct_val[1];
  17290             // fields: []const enumfield,
  17291             const fields_val = struct_val[2];
  17292             // decls: []const declaration,
  17293             const decls_val = struct_val[3];
  17294 
  17295             // Decls
  17296             if (decls_val.sliceLen(mod) > 0) {
  17297                 return sema.fail(block, src, "reified unions must have no decls", .{});
  17298             }
  17299             const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout);
  17300 
  17301             var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
  17302             errdefer new_decl_arena.deinit();
  17303             const new_decl_arena_allocator = new_decl_arena.allocator();
  17304 
  17305             const union_obj = try new_decl_arena_allocator.create(Module.Union);
  17306             const type_tag = if (!tag_type_val.isNull())
  17307                 Type.Tag.union_tagged
  17308             else if (layout != .Auto)
  17309                 Type.Tag.@"union"
  17310             else switch (block.sema.mod.optimizeMode()) {
  17311                 .Debug, .ReleaseSafe => Type.Tag.union_safety_tagged,
  17312                 .ReleaseFast, .ReleaseSmall => Type.Tag.@"union",
  17313             };
  17314             const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);
  17315             union_payload.* = .{
  17316                 .base = .{ .tag = type_tag },
  17317                 .data = union_obj,
  17318             };
  17319             const union_ty = Type.initPayload(&union_payload.base);
  17320             const new_union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
  17321             const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
  17322                 .ty = Type.type,
  17323                 .val = new_union_val,
  17324             }, name_strategy, "union", inst);
  17325             const new_decl = mod.declPtr(new_decl_index);
  17326             new_decl.owns_tv = true;
  17327             errdefer mod.abortAnonDecl(new_decl_index);
  17328             union_obj.* = .{
  17329                 .owner_decl = new_decl_index,
  17330                 .tag_ty = Type.initTag(.@"null"),
  17331                 .fields = .{},
  17332                 .zir_index = inst,
  17333                 .layout = layout,
  17334                 .status = .have_field_types,
  17335                 .namespace = .{
  17336                     .parent = block.namespace,
  17337                     .ty = union_ty,
  17338                     .file_scope = block.getFileScope(),
  17339                 },
  17340             };
  17341 
  17342             // Tag type
  17343             var tag_ty_field_names: ?Module.EnumFull.NameMap = null;
  17344             var enum_field_names: ?*Module.EnumNumbered.NameMap = null;
  17345             const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
  17346             if (tag_type_val.optionalValue()) |payload_val| {
  17347                 var buffer: Value.ToTypeBuffer = undefined;
  17348                 union_obj.tag_ty = try payload_val.toType(&buffer).copy(new_decl_arena_allocator);
  17349 
  17350                 if (union_obj.tag_ty.zigTypeTag() != .Enum) {
  17351                     return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{});
  17352                 }
  17353                 tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena);
  17354             } else {
  17355                 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, fields_len, null);
  17356                 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
  17357             }
  17358 
  17359             // Fields
  17360             try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
  17361 
  17362             var i: usize = 0;
  17363             while (i < fields_len) : (i += 1) {
  17364                 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
  17365                 const field_struct_val = elem_val.castTag(.aggregate).?.data;
  17366                 // TODO use reflection instead of magic numbers here
  17367                 // name: []const u8
  17368                 const name_val = field_struct_val[0];
  17369                 // field_type: type,
  17370                 const field_type_val = field_struct_val[1];
  17371                 // alignment: comptime_int,
  17372                 const alignment_val = field_struct_val[2];
  17373 
  17374                 const field_name = try name_val.toAllocatedBytes(
  17375                     Type.initTag(.const_slice_u8),
  17376                     new_decl_arena_allocator,
  17377                     sema.mod,
  17378                 );
  17379 
  17380                 if (enum_field_names) |set| {
  17381                     set.putAssumeCapacity(field_name, {});
  17382                 }
  17383 
  17384                 if (tag_ty_field_names) |*names| {
  17385                     const enum_has_field = names.orderedRemove(field_name);
  17386                     if (!enum_has_field) {
  17387                         const msg = msg: {
  17388                             const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
  17389                             errdefer msg.destroy(sema.gpa);
  17390                             try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
  17391                             break :msg msg;
  17392                         };
  17393                         return sema.failWithOwnedErrorMsg(msg);
  17394                     }
  17395                 }
  17396 
  17397                 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
  17398                 if (gop.found_existing) {
  17399                     // TODO: better source location
  17400                     return sema.fail(block, src, "duplicate union field {s}", .{field_name});
  17401                 }
  17402 
  17403                 var buffer: Value.ToTypeBuffer = undefined;
  17404                 gop.value_ptr.* = .{
  17405                     .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator),
  17406                     .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)),
  17407                 };
  17408             }
  17409 
  17410             if (tag_ty_field_names) |names| {
  17411                 if (names.count() > 0) {
  17412                     const msg = msg: {
  17413                         const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{});
  17414                         errdefer msg.destroy(sema.gpa);
  17415 
  17416                         const enum_ty = union_obj.tag_ty;
  17417                         for (names.keys()) |field_name| {
  17418                             const field_index = enum_ty.enumFieldIndex(field_name).?;
  17419                             try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name});
  17420                         }
  17421                         try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
  17422                         break :msg msg;
  17423                     };
  17424                     return sema.failWithOwnedErrorMsg(msg);
  17425                 }
  17426             }
  17427 
  17428             try new_decl.finalizeNewArena(&new_decl_arena);
  17429             return sema.analyzeDeclVal(block, src, new_decl_index);
  17430         },
  17431         .Fn => {
  17432             const struct_val = union_val.val.castTag(.aggregate).?.data;
  17433             // TODO use reflection instead of magic numbers here
  17434             // calling_convention: CallingConvention,
  17435             const cc = struct_val[0].toEnum(std.builtin.CallingConvention);
  17436             // alignment: comptime_int,
  17437             const alignment_val = struct_val[1];
  17438             // is_generic: bool,
  17439             const is_generic = struct_val[2].toBool();
  17440             // is_var_args: bool,
  17441             const is_var_args = struct_val[3].toBool();
  17442             // return_type: ?type,
  17443             const return_type_val = struct_val[4];
  17444             // args: []const Param,
  17445             const args_val = struct_val[5];
  17446 
  17447             if (is_generic) {
  17448                 return sema.fail(block, src, "Type.Fn.is_generic must be false for @Type", .{});
  17449             }
  17450 
  17451             if (is_var_args and cc != .C) {
  17452                 return sema.fail(block, src, "varargs functions must have C calling convention", .{});
  17453             }
  17454 
  17455             const alignment = alignment: {
  17456                 if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) {
  17457                     return sema.fail(block, src, "alignment must fit in 'u32'", .{});
  17458                 }
  17459                 const alignment = @intCast(u29, alignment_val.toUnsignedInt(target));
  17460                 if (alignment == target_util.defaultFunctionAlignment(target)) {
  17461                     break :alignment 0;
  17462                 } else {
  17463                     break :alignment alignment;
  17464                 }
  17465             };
  17466             var buf: Value.ToTypeBuffer = undefined;
  17467 
  17468             const args_slice_val = args_val.castTag(.slice).?.data;
  17469             const args_len = try sema.usizeCast(block, src, args_slice_val.len.toUnsignedInt(mod.getTarget()));
  17470             var param_types = try sema.arena.alloc(Type, args_len);
  17471             var comptime_params = try sema.arena.alloc(bool, args_len);
  17472             var noalias_bits: u32 = 0;
  17473             var i: usize = 0;
  17474             while (i < args_len) : (i += 1) {
  17475                 var arg_buf: Value.ElemValueBuffer = undefined;
  17476                 const arg = args_slice_val.ptr.elemValueBuffer(mod, i, &arg_buf);
  17477                 const arg_val = arg.castTag(.aggregate).?.data;
  17478                 // TODO use reflection instead of magic numbers here
  17479                 // is_generic: bool,
  17480                 const arg_is_generic = arg_val[0].toBool();
  17481                 // is_noalias: bool,
  17482                 const arg_is_noalias = arg_val[1].toBool();
  17483                 // arg_type: ?type,
  17484                 const param_type_val = arg_val[2];
  17485 
  17486                 if (arg_is_generic) {
  17487                     return sema.fail(block, src, "Type.Fn.Param.is_generic must be false for @Type", .{});
  17488                 }
  17489 
  17490                 if (arg_is_noalias) {
  17491                     noalias_bits = @as(u32, 1) << (std.math.cast(u5, i) orelse
  17492                         return sema.fail(block, src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{}));
  17493                 }
  17494 
  17495                 const param_type = param_type_val.optionalValue() orelse
  17496                     return sema.fail(block, src, "Type.Fn.Param.arg_type must be non-null for @Type", .{});
  17497 
  17498                 param_types[i] = try param_type.toType(&buf).copy(sema.arena);
  17499             }
  17500 
  17501             const return_type = return_type_val.optionalValue() orelse
  17502                 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
  17503 
  17504             var fn_info = Type.Payload.Function.Data{
  17505                 .param_types = param_types,
  17506                 .comptime_params = comptime_params.ptr,
  17507                 .noalias_bits = noalias_bits,
  17508                 .return_type = try return_type.toType(&buf).copy(sema.arena),
  17509                 .alignment = alignment,
  17510                 .cc = cc,
  17511                 .is_var_args = is_var_args,
  17512                 .is_generic = false,
  17513                 .align_is_generic = false,
  17514                 .cc_is_generic = false,
  17515                 .section_is_generic = false,
  17516                 .addrspace_is_generic = false,
  17517             };
  17518 
  17519             const ty = try Type.Tag.function.create(sema.arena, fn_info);
  17520             return sema.addType(ty);
  17521         },
  17522         .BoundFn => @panic("TODO delete BoundFn from the language"),
  17523         .Frame => return sema.failWithUseOfAsync(block, src),
  17524     }
  17525 }
  17526 
  17527 fn reifyTuple(
  17528     sema: *Sema,
  17529     block: *Block,
  17530     src: LazySrcLoc,
  17531     fields_val: Value,
  17532 ) CompileError!Air.Inst.Ref {
  17533     const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(sema.mod));
  17534     if (fields_len == 0) return sema.addType(Type.initTag(.empty_struct_literal));
  17535 
  17536     const types = try sema.arena.alloc(Type, fields_len);
  17537     const values = try sema.arena.alloc(Value, fields_len);
  17538 
  17539     var used_fields: std.AutoArrayHashMapUnmanaged(u32, void) = .{};
  17540     defer used_fields.deinit(sema.gpa);
  17541     try used_fields.ensureTotalCapacity(sema.gpa, fields_len);
  17542 
  17543     var i: usize = 0;
  17544     while (i < fields_len) : (i += 1) {
  17545         const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
  17546         const field_struct_val = elem_val.castTag(.aggregate).?.data;
  17547         // TODO use reflection instead of magic numbers here
  17548         // name: []const u8
  17549         const name_val = field_struct_val[0];
  17550         // field_type: type,
  17551         const field_type_val = field_struct_val[1];
  17552         //default_value: ?*const anyopaque,
  17553         const default_value_val = field_struct_val[2];
  17554 
  17555         const field_name = try name_val.toAllocatedBytes(
  17556             Type.initTag(.const_slice_u8),
  17557             sema.arena,
  17558             sema.mod,
  17559         );
  17560 
  17561         const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch |err| {
  17562             return sema.fail(
  17563                 block,
  17564                 src,
  17565                 "tuple cannot have non-numeric field '{s}': {}",
  17566                 .{ field_name, err },
  17567             );
  17568         };
  17569 
  17570         if (field_index >= fields_len) {
  17571             return sema.fail(
  17572                 block,
  17573                 src,
  17574                 "tuple field {} exceeds tuple field count",
  17575                 .{field_index},
  17576             );
  17577         }
  17578 
  17579         const gop = used_fields.getOrPutAssumeCapacity(field_index);
  17580         if (gop.found_existing) {
  17581             // TODO: better source location
  17582             return sema.fail(block, src, "duplicate tuple field {}", .{field_index});
  17583         }
  17584 
  17585         const default_val = if (default_value_val.optionalValue()) |opt_val| blk: {
  17586             const payload_val = if (opt_val.pointerDecl()) |opt_decl|
  17587                 sema.mod.declPtr(opt_decl).val
  17588             else
  17589                 opt_val;
  17590             break :blk try payload_val.copy(sema.arena);
  17591         } else Value.initTag(.unreachable_value);
  17592 
  17593         var buffer: Value.ToTypeBuffer = undefined;
  17594         types[field_index] = try field_type_val.toType(&buffer).copy(sema.arena);
  17595         values[field_index] = default_val;
  17596     }
  17597 
  17598     const ty = try Type.Tag.tuple.create(sema.arena, .{
  17599         .types = types,
  17600         .values = values,
  17601     });
  17602     return sema.addType(ty);
  17603 }
  17604 
  17605 fn reifyStruct(
  17606     sema: *Sema,
  17607     block: *Block,
  17608     inst: Zir.Inst.Index,
  17609     src: LazySrcLoc,
  17610     layout: std.builtin.Type.ContainerLayout,
  17611     backing_int_val: Value,
  17612     fields_val: Value,
  17613     name_strategy: Zir.Inst.NameStrategy,
  17614 ) CompileError!Air.Inst.Ref {
  17615     var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
  17616     errdefer new_decl_arena.deinit();
  17617     const new_decl_arena_allocator = new_decl_arena.allocator();
  17618 
  17619     const struct_obj = try new_decl_arena_allocator.create(Module.Struct);
  17620     const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
  17621     const new_struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty);
  17622     const mod = sema.mod;
  17623     const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
  17624         .ty = Type.type,
  17625         .val = new_struct_val,
  17626     }, name_strategy, "struct", inst);
  17627     const new_decl = mod.declPtr(new_decl_index);
  17628     new_decl.owns_tv = true;
  17629     errdefer mod.abortAnonDecl(new_decl_index);
  17630     struct_obj.* = .{
  17631         .owner_decl = new_decl_index,
  17632         .fields = .{},
  17633         .zir_index = inst,
  17634         .layout = layout,
  17635         .status = .have_field_types,
  17636         .known_non_opv = false,
  17637         .namespace = .{
  17638             .parent = block.namespace,
  17639             .ty = struct_ty,
  17640             .file_scope = block.getFileScope(),
  17641         },
  17642     };
  17643 
  17644     const target = mod.getTarget();
  17645 
  17646     // Fields
  17647     const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
  17648     try struct_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
  17649     var i: usize = 0;
  17650     while (i < fields_len) : (i += 1) {
  17651         const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
  17652         const field_struct_val = elem_val.castTag(.aggregate).?.data;
  17653         // TODO use reflection instead of magic numbers here
  17654         // name: []const u8
  17655         const name_val = field_struct_val[0];
  17656         // field_type: type,
  17657         const field_type_val = field_struct_val[1];
  17658         //default_value: ?*const anyopaque,
  17659         const default_value_val = field_struct_val[2];
  17660         // is_comptime: bool,
  17661         const is_comptime_val = field_struct_val[3];
  17662         // alignment: comptime_int,
  17663         const alignment_val = field_struct_val[4];
  17664 
  17665         if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) {
  17666             return sema.fail(block, src, "alignment must fit in 'u32'", .{});
  17667         }
  17668         const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?);
  17669 
  17670         const field_name = try name_val.toAllocatedBytes(
  17671             Type.initTag(.const_slice_u8),
  17672             new_decl_arena_allocator,
  17673             mod,
  17674         );
  17675 
  17676         const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
  17677         if (gop.found_existing) {
  17678             // TODO: better source location
  17679             return sema.fail(block, src, "duplicate struct field {s}", .{field_name});
  17680         }
  17681 
  17682         const default_val = if (default_value_val.optionalValue()) |opt_val| blk: {
  17683             const payload_val = if (opt_val.pointerDecl()) |opt_decl|
  17684                 mod.declPtr(opt_decl).val
  17685             else
  17686                 opt_val;
  17687             break :blk try payload_val.copy(new_decl_arena_allocator);
  17688         } else Value.initTag(.unreachable_value);
  17689 
  17690         var buffer: Value.ToTypeBuffer = undefined;
  17691         gop.value_ptr.* = .{
  17692             .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator),
  17693             .abi_align = abi_align,
  17694             .default_val = default_val,
  17695             .is_comptime = is_comptime_val.toBool(),
  17696             .offset = undefined,
  17697         };
  17698     }
  17699 
  17700     if (layout == .Packed) {
  17701         struct_obj.status = .layout_wip;
  17702 
  17703         for (struct_obj.fields.values()) |field, index| {
  17704             sema.resolveTypeLayout(block, src, field.ty) catch |err| switch (err) {
  17705                 error.AnalysisFail => {
  17706                     const msg = sema.err orelse return err;
  17707                     try sema.addFieldErrNote(struct_ty, index, msg, "while checking this field", .{});
  17708                     return err;
  17709                 },
  17710                 else => return err,
  17711             };
  17712         }
  17713 
  17714         var fields_bit_sum: u64 = 0;
  17715         for (struct_obj.fields.values()) |field| {
  17716             fields_bit_sum += field.ty.bitSize(target);
  17717         }
  17718 
  17719         if (backing_int_val.optionalValue()) |payload| {
  17720             var buf: Value.ToTypeBuffer = undefined;
  17721             const backing_int_ty = payload.toType(&buf);
  17722             try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum);
  17723             struct_obj.backing_int_ty = try backing_int_ty.copy(new_decl_arena_allocator);
  17724         } else {
  17725             var buf: Type.Payload.Bits = .{
  17726                 .base = .{ .tag = .int_unsigned },
  17727                 .data = @intCast(u16, fields_bit_sum),
  17728             };
  17729             struct_obj.backing_int_ty = try Type.initPayload(&buf.base).copy(new_decl_arena_allocator);
  17730         }
  17731 
  17732         struct_obj.status = .have_layout;
  17733     }
  17734 
  17735     try new_decl.finalizeNewArena(&new_decl_arena);
  17736     return sema.analyzeDeclVal(block, src, new_decl_index);
  17737 }
  17738 
  17739 fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17740     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  17741     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  17742     const ty = try sema.resolveType(block, ty_src, inst_data.operand);
  17743 
  17744     var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
  17745     defer anon_decl.deinit();
  17746 
  17747     const bytes = try ty.nameAllocArena(anon_decl.arena(), sema.mod);
  17748 
  17749     const new_decl = try anon_decl.finish(
  17750         try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
  17751         try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
  17752         0, // default alignment
  17753     );
  17754 
  17755     return sema.analyzeDeclRef(new_decl);
  17756 }
  17757 
  17758 fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17759     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  17760     const src = inst_data.src();
  17761     return sema.failWithUseOfAsync(block, src);
  17762 }
  17763 
  17764 fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17765     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  17766     const src = inst_data.src();
  17767     return sema.failWithUseOfAsync(block, src);
  17768 }
  17769 
  17770 fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17771     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  17772     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  17773     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  17774     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  17775     const dest_ty = try sema.resolveType(block, ty_src, extra.lhs);
  17776     const operand = try sema.resolveInst(extra.rhs);
  17777     const operand_ty = sema.typeOf(operand);
  17778 
  17779     _ = try sema.checkIntType(block, ty_src, dest_ty);
  17780     try sema.checkFloatType(block, operand_src, operand_ty);
  17781 
  17782     if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
  17783         const result_val = try sema.floatToInt(block, operand_src, val, operand_ty, dest_ty);
  17784         return sema.addConstant(dest_ty, result_val);
  17785     } else if (dest_ty.zigTypeTag() == .ComptimeInt) {
  17786         return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_int' must be comptime known");
  17787     }
  17788 
  17789     try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
  17790     const result = try block.addTyOp(if (block.float_mode == .Optimized) .float_to_int_optimized else .float_to_int, dest_ty, operand);
  17791     if (block.wantSafety()) {
  17792         const back = try block.addTyOp(.int_to_float, operand_ty, result);
  17793         const diff = try block.addBinOp(.sub, operand, back);
  17794         const ok_pos = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_lt_optimized else .cmp_lt, diff, try sema.addConstant(operand_ty, Value.one));
  17795         const ok_neg = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_gt_optimized else .cmp_gt, diff, try sema.addConstant(operand_ty, Value.negative_one));
  17796         const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg);
  17797         try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds);
  17798     }
  17799     return result;
  17800 }
  17801 
  17802 fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17803     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  17804     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  17805     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  17806     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  17807     const dest_ty = try sema.resolveType(block, ty_src, extra.lhs);
  17808     const operand = try sema.resolveInst(extra.rhs);
  17809     const operand_ty = sema.typeOf(operand);
  17810 
  17811     try sema.checkFloatType(block, ty_src, dest_ty);
  17812     _ = try sema.checkIntType(block, operand_src, operand_ty);
  17813 
  17814     if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
  17815         const target = sema.mod.getTarget();
  17816         const result_val = try val.intToFloatAdvanced(sema.arena, operand_ty, dest_ty, target, sema.kit(block, operand_src));
  17817         return sema.addConstant(dest_ty, result_val);
  17818     } else if (dest_ty.zigTypeTag() == .ComptimeFloat) {
  17819         return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_float' must be comptime known");
  17820     }
  17821 
  17822     try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
  17823     return block.addTyOp(.int_to_float, dest_ty, operand);
  17824 }
  17825 
  17826 fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17827     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  17828     const src = inst_data.src();
  17829 
  17830     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  17831 
  17832     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  17833     const operand_res = try sema.resolveInst(extra.rhs);
  17834     const operand_coerced = try sema.coerce(block, Type.usize, operand_res, operand_src);
  17835 
  17836     const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  17837     const ptr_ty = try sema.resolveType(block, src, extra.lhs);
  17838     const elem_ty = ptr_ty.elemType2();
  17839     try sema.checkPtrType(block, type_src, ptr_ty);
  17840     const target = sema.mod.getTarget();
  17841     const ptr_align = try ptr_ty.ptrAlignmentAdvanced(target, sema.kit(block, src));
  17842 
  17843     if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| {
  17844         const addr = val.toUnsignedInt(target);
  17845         if (!ptr_ty.isAllowzeroPtr() and addr == 0)
  17846             return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)});
  17847         if (addr != 0 and addr % ptr_align != 0)
  17848             return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)});
  17849 
  17850         const val_payload = try sema.arena.create(Value.Payload.U64);
  17851         val_payload.* = .{
  17852             .base = .{ .tag = .int_u64 },
  17853             .data = addr,
  17854         };
  17855         return sema.addConstant(ptr_ty, Value.initPayload(&val_payload.base));
  17856     }
  17857 
  17858     try sema.requireRuntimeBlock(block, src, operand_src);
  17859     if (block.wantSafety() and try sema.typeHasRuntimeBits(block, sema.src, elem_ty)) {
  17860         if (!ptr_ty.isAllowzeroPtr()) {
  17861             const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
  17862             try sema.addSafetyCheck(block, is_non_zero, .cast_to_null);
  17863         }
  17864 
  17865         if (ptr_align > 1) {
  17866             const val_payload = try sema.arena.create(Value.Payload.U64);
  17867             val_payload.* = .{
  17868                 .base = .{ .tag = .int_u64 },
  17869                 .data = ptr_align - 1,
  17870             };
  17871             const align_minus_1 = try sema.addConstant(
  17872                 Type.usize,
  17873                 Value.initPayload(&val_payload.base),
  17874             );
  17875             const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);
  17876             const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
  17877             try sema.addSafetyCheck(block, is_aligned, .incorrect_alignment);
  17878         }
  17879     }
  17880     return block.addBitCast(ptr_ty, operand_coerced);
  17881 }
  17882 
  17883 fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
  17884     const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
  17885     const src = LazySrcLoc.nodeOffset(extra.node);
  17886     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  17887     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  17888     const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
  17889     const operand = try sema.resolveInst(extra.rhs);
  17890     const operand_ty = sema.typeOf(operand);
  17891     try sema.checkErrorSetType(block, dest_ty_src, dest_ty);
  17892     try sema.checkErrorSetType(block, operand_src, operand_ty);
  17893 
  17894     // operand must be defined since it can be an invalid error value
  17895     const maybe_operand_val = try sema.resolveDefinedValue(block, operand_src, operand);
  17896 
  17897     if (disjoint: {
  17898         // Try avoiding resolving inferred error sets if we can
  17899         if (!dest_ty.isAnyError() and dest_ty.errorSetNames().len == 0) break :disjoint true;
  17900         if (!operand_ty.isAnyError() and operand_ty.errorSetNames().len == 0) break :disjoint true;
  17901         if (dest_ty.isAnyError()) break :disjoint false;
  17902         if (operand_ty.isAnyError()) break :disjoint false;
  17903         for (dest_ty.errorSetNames()) |dest_err_name|
  17904             if (operand_ty.errorSetHasField(dest_err_name))
  17905                 break :disjoint false;
  17906 
  17907         if (dest_ty.tag() != .error_set_inferred and operand_ty.tag() != .error_set_inferred)
  17908             break :disjoint true;
  17909 
  17910         try sema.resolveInferredErrorSetTy(block, dest_ty_src, dest_ty);
  17911         try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty);
  17912         for (dest_ty.errorSetNames()) |dest_err_name|
  17913             if (operand_ty.errorSetHasField(dest_err_name))
  17914                 break :disjoint false;
  17915 
  17916         break :disjoint true;
  17917     }) {
  17918         const msg = msg: {
  17919             const msg = try sema.errMsg(
  17920                 block,
  17921                 src,
  17922                 "error sets '{}' and '{}' have no common errors",
  17923                 .{ operand_ty.fmt(sema.mod), dest_ty.fmt(sema.mod) },
  17924             );
  17925             errdefer msg.destroy(sema.gpa);
  17926             try sema.addDeclaredHereNote(msg, operand_ty);
  17927             try sema.addDeclaredHereNote(msg, dest_ty);
  17928             break :msg msg;
  17929         };
  17930         return sema.failWithOwnedErrorMsg(msg);
  17931     }
  17932 
  17933     if (maybe_operand_val) |val| {
  17934         if (!dest_ty.isAnyError()) {
  17935             const error_name = val.castTag(.@"error").?.data.name;
  17936             if (!dest_ty.errorSetHasField(error_name)) {
  17937                 const msg = msg: {
  17938                     const msg = try sema.errMsg(
  17939                         block,
  17940                         src,
  17941                         "'error.{s}' not a member of error set '{}'",
  17942                         .{ error_name, dest_ty.fmt(sema.mod) },
  17943                     );
  17944                     errdefer msg.destroy(sema.gpa);
  17945                     try sema.addDeclaredHereNote(msg, dest_ty);
  17946                     break :msg msg;
  17947                 };
  17948                 return sema.failWithOwnedErrorMsg(msg);
  17949             }
  17950         }
  17951 
  17952         return sema.addConstant(dest_ty, val);
  17953     }
  17954 
  17955     try sema.requireRuntimeBlock(block, src, operand_src);
  17956     if (block.wantSafety() and !dest_ty.isAnyError() and sema.mod.comp.bin_file.options.use_llvm) {
  17957         const err_int_inst = try block.addBitCast(Type.err_int, operand);
  17958         const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst);
  17959         try sema.addSafetyCheck(block, ok, .invalid_error_code);
  17960     }
  17961     return block.addBitCast(dest_ty, operand);
  17962 }
  17963 
  17964 fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17965     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  17966     const src = inst_data.src();
  17967     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  17968     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  17969     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  17970     const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
  17971     const operand = try sema.resolveInst(extra.rhs);
  17972     const operand_ty = sema.typeOf(operand);
  17973     const target = sema.mod.getTarget();
  17974 
  17975     try sema.checkPtrType(block, dest_ty_src, dest_ty);
  17976     try sema.checkPtrOperand(block, operand_src, operand_ty);
  17977 
  17978     const operand_info = operand_ty.ptrInfo().data;
  17979     const dest_info = dest_ty.ptrInfo().data;
  17980     if (!operand_info.mutable and dest_info.mutable) {
  17981         return sema.fail(block, src, "cast discards const qualifier", .{});
  17982     }
  17983     if (operand_info.@"volatile" and !dest_info.@"volatile") {
  17984         return sema.fail(block, src, "cast discards volatile qualifier", .{});
  17985     }
  17986 
  17987     const dest_is_slice = dest_ty.isSlice();
  17988     const operand_is_slice = operand_ty.isSlice();
  17989     if (dest_is_slice and !operand_is_slice) {
  17990         return sema.fail(block, dest_ty_src, "illegal pointer cast to slice", .{});
  17991     }
  17992     const ptr = if (operand_is_slice and !dest_is_slice)
  17993         try sema.analyzeSlicePtr(block, operand_src, operand, operand_ty)
  17994     else
  17995         operand;
  17996 
  17997     const dest_elem_ty = dest_ty.elemType2();
  17998     try sema.resolveTypeLayout(block, dest_ty_src, dest_elem_ty);
  17999     const dest_align = dest_ty.ptrAlignment(target);
  18000 
  18001     const operand_elem_ty = operand_ty.elemType2();
  18002     try sema.resolveTypeLayout(block, operand_src, operand_elem_ty);
  18003     const operand_align = operand_ty.ptrAlignment(target);
  18004 
  18005     // If the destination is less aligned than the source, preserve the source alignment
  18006     const aligned_dest_ty = if (operand_align <= dest_align) dest_ty else blk: {
  18007         // Unwrap the pointer (or pointer-like optional) type, set alignment, and re-wrap into result
  18008         if (dest_ty.zigTypeTag() == .Optional) {
  18009             var buf: Type.Payload.ElemType = undefined;
  18010             var dest_ptr_info = dest_ty.optionalChild(&buf).ptrInfo().data;
  18011             dest_ptr_info.@"align" = operand_align;
  18012             break :blk try Type.optional(sema.arena, try Type.ptr(sema.arena, sema.mod, dest_ptr_info));
  18013         } else {
  18014             var dest_ptr_info = dest_ty.ptrInfo().data;
  18015             dest_ptr_info.@"align" = operand_align;
  18016             break :blk try Type.ptr(sema.arena, sema.mod, dest_ptr_info);
  18017         }
  18018     };
  18019 
  18020     if (dest_is_slice) {
  18021         const operand_elem_size = operand_elem_ty.abiSize(target);
  18022         const dest_elem_size = dest_elem_ty.abiSize(target);
  18023         if (operand_elem_size != dest_elem_size) {
  18024             // note that this is not implemented in stage1 so we should probably wait
  18025             // until that codebase is replaced before implementing this in stage2.
  18026             return sema.fail(block, dest_ty_src, "TODO: implement @ptrCast between slices changing the length", .{});
  18027         }
  18028     }
  18029 
  18030     if (dest_align > operand_align) {
  18031         const msg = msg: {
  18032             const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});
  18033             errdefer msg.destroy(sema.gpa);
  18034 
  18035             try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{
  18036                 operand_ty.fmt(sema.mod), operand_align,
  18037             });
  18038             try sema.errNote(block, dest_ty_src, msg, "'{}' has alignment '{d}'", .{
  18039                 dest_ty.fmt(sema.mod), dest_align,
  18040             });
  18041             break :msg msg;
  18042         };
  18043         return sema.failWithOwnedErrorMsg(msg);
  18044     }
  18045 
  18046     if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| {
  18047         if (!dest_ty.ptrAllowsZero() and operand_val.isUndef()) {
  18048             return sema.failWithUseOfUndef(block, operand_src);
  18049         }
  18050         if (!dest_ty.ptrAllowsZero() and operand_val.isNull()) {
  18051             return sema.fail(block, operand_src, "null pointer casted to type {}", .{dest_ty.fmt(sema.mod)});
  18052         }
  18053         return sema.addConstant(aligned_dest_ty, operand_val);
  18054     }
  18055 
  18056     try sema.requireRuntimeBlock(block, src, null);
  18057     if (block.wantSafety() and operand_ty.ptrAllowsZero() and !dest_ty.ptrAllowsZero() and
  18058         try sema.typeHasRuntimeBits(block, sema.src, dest_ty.elemType2()))
  18059     {
  18060         const ptr_int = try block.addUnOp(.ptrtoint, ptr);
  18061         const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize);
  18062         const ok = if (operand_is_slice) ok: {
  18063             const len = try sema.analyzeSliceLen(block, operand_src, operand);
  18064             const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
  18065             break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);
  18066         } else is_non_zero;
  18067         try sema.addSafetyCheck(block, ok, .cast_to_null);
  18068     }
  18069 
  18070     return block.addBitCast(aligned_dest_ty, ptr);
  18071 }
  18072 
  18073 fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  18074     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  18075     const src = inst_data.src();
  18076     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  18077     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  18078     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  18079     const dest_scalar_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
  18080     const operand = try sema.resolveInst(extra.rhs);
  18081     const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_scalar_ty);
  18082     const operand_ty = sema.typeOf(operand);
  18083     const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
  18084     const is_vector = operand_ty.zigTypeTag() == .Vector;
  18085     const dest_ty = if (is_vector)
  18086         try Type.vector(sema.arena, operand_ty.vectorLen(), dest_scalar_ty)
  18087     else
  18088         dest_scalar_ty;
  18089 
  18090     if (dest_is_comptime_int) {
  18091         return sema.coerce(block, dest_ty, operand, operand_src);
  18092     }
  18093 
  18094     const target = sema.mod.getTarget();
  18095     const dest_info = dest_scalar_ty.intInfo(target);
  18096 
  18097     if (try sema.typeHasOnePossibleValue(block, dest_ty_src, dest_ty)) |val| {
  18098         return sema.addConstant(dest_ty, val);
  18099     }
  18100 
  18101     if (operand_scalar_ty.zigTypeTag() != .ComptimeInt) {
  18102         const operand_info = operand_ty.intInfo(target);
  18103         if (try sema.typeHasOnePossibleValue(block, operand_src, operand_ty)) |val| {
  18104             return sema.addConstant(operand_ty, val);
  18105         }
  18106 
  18107         if (operand_info.signedness != dest_info.signedness) {
  18108             return sema.fail(block, operand_src, "expected {s} integer type, found '{}'", .{
  18109                 @tagName(dest_info.signedness), operand_ty.fmt(sema.mod),
  18110             });
  18111         }
  18112         if (operand_info.bits < dest_info.bits) {
  18113             const msg = msg: {
  18114                 const msg = try sema.errMsg(
  18115                     block,
  18116                     src,
  18117                     "destination type '{}' has more bits than source type '{}'",
  18118                     .{ dest_ty.fmt(sema.mod), operand_ty.fmt(sema.mod) },
  18119                 );
  18120                 errdefer msg.destroy(sema.gpa);
  18121                 try sema.errNote(block, dest_ty_src, msg, "destination type has {d} bits", .{
  18122                     dest_info.bits,
  18123                 });
  18124                 try sema.errNote(block, operand_src, msg, "operand type has {d} bits", .{
  18125                     operand_info.bits,
  18126                 });
  18127                 break :msg msg;
  18128             };
  18129             return sema.failWithOwnedErrorMsg(msg);
  18130         }
  18131     }
  18132 
  18133     if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
  18134         if (val.isUndef()) return sema.addConstUndef(dest_ty);
  18135         if (!is_vector) {
  18136             return sema.addConstant(
  18137                 dest_ty,
  18138                 try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits, target),
  18139             );
  18140         }
  18141         var elem_buf: Value.ElemValueBuffer = undefined;
  18142         const elems = try sema.arena.alloc(Value, operand_ty.vectorLen());
  18143         for (elems) |*elem, i| {
  18144             const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf);
  18145             elem.* = try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits, target);
  18146         }
  18147         return sema.addConstant(
  18148             dest_ty,
  18149             try Value.Tag.aggregate.create(sema.arena, elems),
  18150         );
  18151     }
  18152 
  18153     try sema.requireRuntimeBlock(block, src, operand_src);
  18154     return block.addTyOp(.trunc, dest_ty, operand);
  18155 }
  18156 
  18157 fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  18158     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  18159     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  18160     const align_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  18161     const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  18162     const dest_align = try sema.resolveAlign(block, align_src, extra.lhs);
  18163     const ptr = try sema.resolveInst(extra.rhs);
  18164     const ptr_ty = sema.typeOf(ptr);
  18165 
  18166     try sema.checkPtrOperand(block, ptr_src, ptr_ty);
  18167 
  18168     var ptr_info = ptr_ty.ptrInfo().data;
  18169     ptr_info.@"align" = dest_align;
  18170     var dest_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
  18171     if (ptr_ty.zigTypeTag() == .Optional) {
  18172         dest_ty = try Type.Tag.optional.create(sema.arena, dest_ty);
  18173     }
  18174 
  18175     if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |val| {
  18176         if (try val.getUnsignedIntAdvanced(sema.mod.getTarget(), null)) |addr| {
  18177             if (addr % dest_align != 0) {
  18178                 return sema.fail(block, ptr_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align });
  18179             }
  18180         }
  18181         return sema.addConstant(dest_ty, val);
  18182     }
  18183 
  18184     try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
  18185     if (block.wantSafety() and dest_align > 1 and
  18186         try sema.typeHasRuntimeBits(block, sema.src, ptr_info.pointee_type))
  18187     {
  18188         const val_payload = try sema.arena.create(Value.Payload.U64);
  18189         val_payload.* = .{
  18190             .base = .{ .tag = .int_u64 },
  18191             .data = dest_align - 1,
  18192         };
  18193         const align_minus_1 = try sema.addConstant(
  18194             Type.usize,
  18195             Value.initPayload(&val_payload.base),
  18196         );
  18197         const actual_ptr = if (ptr_ty.isSlice())
  18198             try sema.analyzeSlicePtr(block, ptr_src, ptr, ptr_ty)
  18199         else
  18200             ptr;
  18201         const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr);
  18202         const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);
  18203         const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
  18204         const ok = if (ptr_ty.isSlice()) ok: {
  18205             const len = try sema.analyzeSliceLen(block, ptr_src, ptr);
  18206             const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
  18207             break :ok try block.addBinOp(.bit_or, len_zero, is_aligned);
  18208         } else is_aligned;
  18209         try sema.addSafetyCheck(block, ok, .incorrect_alignment);
  18210     }
  18211     return sema.bitCast(block, dest_ty, ptr, ptr_src);
  18212 }
  18213 
  18214 fn zirBitCount(
  18215     sema: *Sema,
  18216     block: *Block,
  18217     inst: Zir.Inst.Index,
  18218     air_tag: Air.Inst.Tag,
  18219     comptime comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64,
  18220 ) CompileError!Air.Inst.Ref {
  18221     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  18222     const src = inst_data.src();
  18223     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  18224     const operand = try sema.resolveInst(inst_data.operand);
  18225     const operand_ty = sema.typeOf(operand);
  18226     _ = try checkIntOrVector(sema, block, operand, operand_src);
  18227     const target = sema.mod.getTarget();
  18228     const bits = operand_ty.intInfo(target).bits;
  18229 
  18230     if (try sema.typeHasOnePossibleValue(block, operand_src, operand_ty)) |val| {
  18231         return sema.addConstant(operand_ty, val);
  18232     }
  18233 
  18234     const result_scalar_ty = try Type.smallestUnsignedInt(sema.arena, bits);
  18235     switch (operand_ty.zigTypeTag()) {
  18236         .Vector => {
  18237             const vec_len = operand_ty.vectorLen();
  18238             const result_ty = try Type.vector(sema.arena, vec_len, result_scalar_ty);
  18239             if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
  18240                 if (val.isUndef()) return sema.addConstUndef(result_ty);
  18241 
  18242                 var elem_buf: Value.ElemValueBuffer = undefined;
  18243                 const elems = try sema.arena.alloc(Value, vec_len);
  18244                 const scalar_ty = operand_ty.scalarType();
  18245                 for (elems) |*elem, i| {
  18246                     const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf);
  18247                     const count = comptimeOp(elem_val, scalar_ty, target);
  18248                     elem.* = try Value.Tag.int_u64.create(sema.arena, count);
  18249                 }
  18250                 return sema.addConstant(
  18251                     result_ty,
  18252                     try Value.Tag.aggregate.create(sema.arena, elems),
  18253                 );
  18254             } else {
  18255                 try sema.requireRuntimeBlock(block, src, operand_src);
  18256                 return block.addTyOp(air_tag, result_ty, operand);
  18257             }
  18258         },
  18259         .Int => {
  18260             if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
  18261                 if (val.isUndef()) return sema.addConstUndef(result_scalar_ty);
  18262                 return sema.addIntUnsigned(result_scalar_ty, comptimeOp(val, operand_ty, target));
  18263             } else {
  18264                 try sema.requireRuntimeBlock(block, src, operand_src);
  18265                 return block.addTyOp(air_tag, result_scalar_ty, operand);
  18266             }
  18267         },
  18268         else => unreachable,
  18269     }
  18270 }
  18271 
  18272 fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  18273     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  18274     const src = inst_data.src();
  18275     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  18276     const operand = try sema.resolveInst(inst_data.operand);
  18277     const operand_ty = sema.typeOf(operand);
  18278     const scalar_ty = try sema.checkIntOrVector(block, operand, operand_src);
  18279     const target = sema.mod.getTarget();
  18280     const bits = scalar_ty.intInfo(target).bits;
  18281     if (bits % 8 != 0) {
  18282         return sema.fail(
  18283             block,
  18284             operand_src,
  18285             "@byteSwap requires the number of bits to be evenly divisible by 8, but {} has {} bits",
  18286             .{ scalar_ty.fmt(sema.mod), bits },
  18287         );
  18288     }
  18289 
  18290     if (try sema.typeHasOnePossibleValue(block, operand_src, operand_ty)) |val| {
  18291         return sema.addConstant(operand_ty, val);
  18292     }
  18293 
  18294     switch (operand_ty.zigTypeTag()) {
  18295         .Int => {
  18296             const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
  18297                 if (val.isUndef()) return sema.addConstUndef(operand_ty);
  18298                 const result_val = try val.byteSwap(operand_ty, target, sema.arena);
  18299                 return sema.addConstant(operand_ty, result_val);
  18300             } else operand_src;
  18301 
  18302             try sema.requireRuntimeBlock(block, src, runtime_src);
  18303             return block.addTyOp(.byte_swap, operand_ty, operand);
  18304         },
  18305         .Vector => {
  18306             const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
  18307                 if (val.isUndef())
  18308                     return sema.addConstUndef(operand_ty);
  18309 
  18310                 const vec_len = operand_ty.vectorLen();
  18311                 var elem_buf: Value.ElemValueBuffer = undefined;
  18312                 const elems = try sema.arena.alloc(Value, vec_len);
  18313                 for (elems) |*elem, i| {
  18314                     const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf);
  18315                     elem.* = try elem_val.byteSwap(operand_ty, target, sema.arena);
  18316                 }
  18317                 return sema.addConstant(
  18318                     operand_ty,
  18319                     try Value.Tag.aggregate.create(sema.arena, elems),
  18320                 );
  18321             } else operand_src;
  18322 
  18323             try sema.requireRuntimeBlock(block, src, runtime_src);
  18324             return block.addTyOp(.byte_swap, operand_ty, operand);
  18325         },
  18326         else => unreachable,
  18327     }
  18328 }
  18329 
  18330 fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  18331     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  18332     const src = inst_data.src();
  18333     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  18334     const operand = try sema.resolveInst(inst_data.operand);
  18335     const operand_ty = sema.typeOf(operand);
  18336     _ = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
  18337 
  18338     if (try sema.typeHasOnePossibleValue(block, operand_src, operand_ty)) |val| {
  18339         return sema.addConstant(operand_ty, val);
  18340     }
  18341 
  18342     const target = sema.mod.getTarget();
  18343     switch (operand_ty.zigTypeTag()) {
  18344         .Int, .ComptimeInt => {
  18345             const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
  18346                 if (val.isUndef()) return sema.addConstUndef(operand_ty);
  18347                 const result_val = try val.bitReverse(operand_ty, target, sema.arena);
  18348                 return sema.addConstant(operand_ty, result_val);
  18349             } else operand_src;
  18350 
  18351             try sema.requireRuntimeBlock(block, src, runtime_src);
  18352             return block.addTyOp(.bit_reverse, operand_ty, operand);
  18353         },
  18354         .Vector => {
  18355             const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
  18356                 if (val.isUndef())
  18357                     return sema.addConstUndef(operand_ty);
  18358 
  18359                 const vec_len = operand_ty.vectorLen();
  18360                 var elem_buf: Value.ElemValueBuffer = undefined;
  18361                 const elems = try sema.arena.alloc(Value, vec_len);
  18362                 for (elems) |*elem, i| {
  18363                     const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf);
  18364                     elem.* = try elem_val.bitReverse(operand_ty, target, sema.arena);
  18365                 }
  18366                 return sema.addConstant(
  18367                     operand_ty,
  18368                     try Value.Tag.aggregate.create(sema.arena, elems),
  18369                 );
  18370             } else operand_src;
  18371 
  18372             try sema.requireRuntimeBlock(block, src, runtime_src);
  18373             return block.addTyOp(.bit_reverse, operand_ty, operand);
  18374         },
  18375         else => unreachable,
  18376     }
  18377 }
  18378 
  18379 fn zirBitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  18380     const offset = try bitOffsetOf(sema, block, inst);
  18381     return sema.addIntUnsigned(Type.comptime_int, offset);
  18382 }
  18383 
  18384 fn zirOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  18385     const offset = try bitOffsetOf(sema, block, inst);
  18386     // TODO reminder to make this a compile error for packed structs
  18387     return sema.addIntUnsigned(Type.comptime_int, offset / 8);
  18388 }
  18389 
  18390 fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u64 {
  18391     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  18392     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  18393     sema.src = src;
  18394     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  18395     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  18396     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  18397 
  18398     const ty = try sema.resolveType(block, lhs_src, extra.lhs);
  18399     const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "name of field must be comptime known");
  18400     const target = sema.mod.getTarget();
  18401 
  18402     try sema.resolveTypeLayout(block, lhs_src, ty);
  18403     switch (ty.zigTypeTag()) {
  18404         .Struct => {},
  18405         else => {
  18406             const msg = msg: {
  18407                 const msg = try sema.errMsg(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(sema.mod)});
  18408                 errdefer msg.destroy(sema.gpa);
  18409                 try sema.addDeclaredHereNote(msg, ty);
  18410                 break :msg msg;
  18411             };
  18412             return sema.failWithOwnedErrorMsg(msg);
  18413         },
  18414     }
  18415 
  18416     const field_index = if (ty.isTuple()) blk: {
  18417         if (mem.eql(u8, field_name, "len")) {
  18418             return sema.fail(block, src, "no offset available for 'len' field of tuple", .{});
  18419         }
  18420         break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src);
  18421     } else try sema.structFieldIndex(block, ty, field_name, rhs_src);
  18422 
  18423     switch (ty.containerLayout()) {
  18424         .Packed => {
  18425             var bit_sum: u64 = 0;
  18426             const fields = ty.structFields();
  18427             for (fields.values()) |field, i| {
  18428                 if (i == field_index) {
  18429                     return bit_sum;
  18430                 }
  18431                 bit_sum += field.ty.bitSize(target);
  18432             } else unreachable;
  18433         },
  18434         else => return ty.structFieldOffset(field_index, target) * 8,
  18435     }
  18436 }
  18437 
  18438 fn checkNamespaceType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void {
  18439     switch (ty.zigTypeTag()) {
  18440         .Struct, .Enum, .Union, .Opaque => return,
  18441         else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{}'", .{ty.fmt(sema.mod)}),
  18442     }
  18443 }
  18444 
  18445 /// Returns `true` if the type was a comptime_int.
  18446 fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
  18447     switch (try ty.zigTypeTagOrPoison()) {
  18448         .ComptimeInt => return true,
  18449         .Int => return false,
  18450         else => return sema.fail(block, src, "expected integer type, found '{}'", .{ty.fmt(sema.mod)}),
  18451     }
  18452 }
  18453 
  18454 fn checkInvalidPtrArithmetic(
  18455     sema: *Sema,
  18456     block: *Block,
  18457     src: LazySrcLoc,
  18458     ty: Type,
  18459     zir_tag: Zir.Inst.Tag,
  18460 ) CompileError!void {
  18461     switch (try ty.zigTypeTagOrPoison()) {
  18462         .Pointer => switch (ty.ptrSize()) {
  18463             .One, .Slice => return,
  18464             .Many, .C => return sema.fail(
  18465                 block,
  18466                 src,
  18467                 "invalid pointer arithmetic operand: '{s}''",
  18468                 .{@tagName(zir_tag)},
  18469             ),
  18470         },
  18471         else => return,
  18472     }
  18473 }
  18474 
  18475 fn checkArithmeticOp(
  18476     sema: *Sema,
  18477     block: *Block,
  18478     src: LazySrcLoc,
  18479     scalar_tag: std.builtin.TypeId,
  18480     lhs_zig_ty_tag: std.builtin.TypeId,
  18481     rhs_zig_ty_tag: std.builtin.TypeId,
  18482     zir_tag: Zir.Inst.Tag,
  18483 ) CompileError!void {
  18484     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  18485     const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;
  18486 
  18487     if (!is_int and !(is_float and floatOpAllowed(zir_tag))) {
  18488         return sema.fail(block, src, "invalid operands to binary expression: '{s}' and '{s}'", .{
  18489             @tagName(lhs_zig_ty_tag), @tagName(rhs_zig_ty_tag),
  18490         });
  18491     }
  18492 }
  18493 
  18494 fn checkPtrOperand(
  18495     sema: *Sema,
  18496     block: *Block,
  18497     ty_src: LazySrcLoc,
  18498     ty: Type,
  18499 ) CompileError!void {
  18500     switch (ty.zigTypeTag()) {
  18501         .Pointer => return,
  18502         .Fn => {
  18503             const msg = msg: {
  18504                 const msg = try sema.errMsg(
  18505                     block,
  18506                     ty_src,
  18507                     "expected pointer, found '{}'",
  18508                     .{ty.fmt(sema.mod)},
  18509                 );
  18510                 errdefer msg.destroy(sema.gpa);
  18511 
  18512                 try sema.errNote(block, ty_src, msg, "use '&' to obtain a function pointer", .{});
  18513 
  18514                 break :msg msg;
  18515             };
  18516             return sema.failWithOwnedErrorMsg(msg);
  18517         },
  18518         .Optional => if (ty.isPtrLikeOptional()) return,
  18519         else => {},
  18520     }
  18521     return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(sema.mod)});
  18522 }
  18523 
  18524 fn checkPtrType(
  18525     sema: *Sema,
  18526     block: *Block,
  18527     ty_src: LazySrcLoc,
  18528     ty: Type,
  18529 ) CompileError!void {
  18530     switch (ty.zigTypeTag()) {
  18531         .Pointer => return,
  18532         .Fn => {
  18533             const msg = msg: {
  18534                 const msg = try sema.errMsg(
  18535                     block,
  18536                     ty_src,
  18537                     "expected pointer type, found '{}'",
  18538                     .{ty.fmt(sema.mod)},
  18539                 );
  18540                 errdefer msg.destroy(sema.gpa);
  18541 
  18542                 try sema.errNote(block, ty_src, msg, "use '*const ' to make a function pointer type", .{});
  18543 
  18544                 break :msg msg;
  18545             };
  18546             return sema.failWithOwnedErrorMsg(msg);
  18547         },
  18548         .Optional => if (ty.isPtrLikeOptional()) return,
  18549         else => {},
  18550     }
  18551     return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(sema.mod)});
  18552 }
  18553 
  18554 fn checkVectorElemType(
  18555     sema: *Sema,
  18556     block: *Block,
  18557     ty_src: LazySrcLoc,
  18558     ty: Type,
  18559 ) CompileError!void {
  18560     switch (ty.zigTypeTag()) {
  18561         .Int, .Float, .Bool => return,
  18562         else => if (ty.isPtrAtRuntime()) return,
  18563     }
  18564     return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{}'", .{ty.fmt(sema.mod)});
  18565 }
  18566 
  18567 fn checkFloatType(
  18568     sema: *Sema,
  18569     block: *Block,
  18570     ty_src: LazySrcLoc,
  18571     ty: Type,
  18572 ) CompileError!void {
  18573     switch (ty.zigTypeTag()) {
  18574         .ComptimeInt, .ComptimeFloat, .Float => {},
  18575         else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty.fmt(sema.mod)}),
  18576     }
  18577 }
  18578 
  18579 fn checkNumericType(
  18580     sema: *Sema,
  18581     block: *Block,
  18582     ty_src: LazySrcLoc,
  18583     ty: Type,
  18584 ) CompileError!void {
  18585     switch (ty.zigTypeTag()) {
  18586         .ComptimeFloat, .Float, .ComptimeInt, .Int => {},
  18587         .Vector => switch (ty.childType().zigTypeTag()) {
  18588             .ComptimeFloat, .Float, .ComptimeInt, .Int => {},
  18589             else => |t| return sema.fail(block, ty_src, "expected number, found '{}'", .{t}),
  18590         },
  18591         else => return sema.fail(block, ty_src, "expected number, found '{}'", .{ty.fmt(sema.mod)}),
  18592     }
  18593 }
  18594 
  18595 /// Returns the casted pointer.
  18596 fn checkAtomicPtrOperand(
  18597     sema: *Sema,
  18598     block: *Block,
  18599     elem_ty: Type,
  18600     elem_ty_src: LazySrcLoc,
  18601     ptr: Air.Inst.Ref,
  18602     ptr_src: LazySrcLoc,
  18603     ptr_const: bool,
  18604 ) CompileError!Air.Inst.Ref {
  18605     const target = sema.mod.getTarget();
  18606     var diag: target_util.AtomicPtrAlignmentDiagnostics = .{};
  18607     const alignment = target_util.atomicPtrAlignment(target, elem_ty, &diag) catch |err| switch (err) {
  18608         error.FloatTooBig => return sema.fail(
  18609             block,
  18610             elem_ty_src,
  18611             "expected {d}-bit float type or smaller; found {d}-bit float type",
  18612             .{ diag.max_bits, diag.bits },
  18613         ),
  18614         error.IntTooBig => return sema.fail(
  18615             block,
  18616             elem_ty_src,
  18617             "expected {d}-bit integer type or smaller; found {d}-bit integer type",
  18618             .{ diag.max_bits, diag.bits },
  18619         ),
  18620         error.BadType => return sema.fail(
  18621             block,
  18622             elem_ty_src,
  18623             "expected bool, integer, float, enum, or pointer type; found '{}'",
  18624             .{elem_ty.fmt(sema.mod)},
  18625         ),
  18626     };
  18627 
  18628     var wanted_ptr_data: Type.Payload.Pointer.Data = .{
  18629         .pointee_type = elem_ty,
  18630         .@"align" = alignment,
  18631         .@"addrspace" = .generic,
  18632         .mutable = !ptr_const,
  18633     };
  18634 
  18635     const ptr_ty = sema.typeOf(ptr);
  18636     const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison()) {
  18637         .Pointer => ptr_ty.ptrInfo().data,
  18638         else => {
  18639             const wanted_ptr_ty = try Type.ptr(sema.arena, sema.mod, wanted_ptr_data);
  18640             _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
  18641             unreachable;
  18642         },
  18643     };
  18644 
  18645     wanted_ptr_data.@"addrspace" = ptr_data.@"addrspace";
  18646     wanted_ptr_data.@"allowzero" = ptr_data.@"allowzero";
  18647     wanted_ptr_data.@"volatile" = ptr_data.@"volatile";
  18648 
  18649     const wanted_ptr_ty = try Type.ptr(sema.arena, sema.mod, wanted_ptr_data);
  18650     const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
  18651 
  18652     return casted_ptr;
  18653 }
  18654 
  18655 fn checkPtrIsNotComptimeMutable(
  18656     sema: *Sema,
  18657     block: *Block,
  18658     ptr_val: Value,
  18659     ptr_src: LazySrcLoc,
  18660     operand_src: LazySrcLoc,
  18661 ) CompileError!void {
  18662     _ = operand_src;
  18663     if (ptr_val.isComptimeMutablePtr()) {
  18664         return sema.fail(block, ptr_src, "cannot store runtime value in compile time variable", .{});
  18665     }
  18666 }
  18667 
  18668 fn checkComptimeVarStore(
  18669     sema: *Sema,
  18670     block: *Block,
  18671     src: LazySrcLoc,
  18672     decl_ref_mut: Value.Payload.DeclRefMut.Data,
  18673 ) CompileError!void {
  18674     if (@enumToInt(decl_ref_mut.runtime_index) < @enumToInt(block.runtime_index)) {
  18675         if (block.runtime_cond) |cond_src| {
  18676             const msg = msg: {
  18677                 const msg = try sema.errMsg(block, src, "store to comptime variable depends on runtime condition", .{});
  18678                 errdefer msg.destroy(sema.gpa);
  18679                 try sema.errNote(block, cond_src, msg, "runtime condition here", .{});
  18680                 break :msg msg;
  18681             };
  18682             return sema.failWithOwnedErrorMsg(msg);
  18683         }
  18684         if (block.runtime_loop) |loop_src| {
  18685             const msg = msg: {
  18686                 const msg = try sema.errMsg(block, src, "cannot store to comptime variable in non-inline loop", .{});
  18687                 errdefer msg.destroy(sema.gpa);
  18688                 try sema.errNote(block, loop_src, msg, "non-inline loop here", .{});
  18689                 break :msg msg;
  18690             };
  18691             return sema.failWithOwnedErrorMsg(msg);
  18692         }
  18693         unreachable;
  18694     }
  18695 }
  18696 
  18697 fn checkIntOrVector(
  18698     sema: *Sema,
  18699     block: *Block,
  18700     operand: Air.Inst.Ref,
  18701     operand_src: LazySrcLoc,
  18702 ) CompileError!Type {
  18703     const operand_ty = sema.typeOf(operand);
  18704     switch (try operand_ty.zigTypeTagOrPoison()) {
  18705         .Int => return operand_ty,
  18706         .Vector => {
  18707             const elem_ty = operand_ty.childType();
  18708             switch (try elem_ty.zigTypeTagOrPoison()) {
  18709                 .Int => return elem_ty,
  18710                 else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{
  18711                     elem_ty.fmt(sema.mod),
  18712                 }),
  18713             }
  18714         },
  18715         else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{
  18716             operand_ty.fmt(sema.mod),
  18717         }),
  18718     }
  18719 }
  18720 
  18721 fn checkIntOrVectorAllowComptime(
  18722     sema: *Sema,
  18723     block: *Block,
  18724     operand_ty: Type,
  18725     operand_src: LazySrcLoc,
  18726 ) CompileError!Type {
  18727     switch (try operand_ty.zigTypeTagOrPoison()) {
  18728         .Int, .ComptimeInt => return operand_ty,
  18729         .Vector => {
  18730             const elem_ty = operand_ty.childType();
  18731             switch (try elem_ty.zigTypeTagOrPoison()) {
  18732                 .Int, .ComptimeInt => return elem_ty,
  18733                 else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{
  18734                     elem_ty.fmt(sema.mod),
  18735                 }),
  18736             }
  18737         },
  18738         else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{
  18739             operand_ty.fmt(sema.mod),
  18740         }),
  18741     }
  18742 }
  18743 
  18744 fn checkErrorSetType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void {
  18745     switch (ty.zigTypeTag()) {
  18746         .ErrorSet => return,
  18747         else => return sema.fail(block, src, "expected error set type, found '{}'", .{ty.fmt(sema.mod)}),
  18748     }
  18749 }
  18750 
  18751 const SimdBinOp = struct {
  18752     len: ?usize,
  18753     /// Coerced to `result_ty`.
  18754     lhs: Air.Inst.Ref,
  18755     /// Coerced to `result_ty`.
  18756     rhs: Air.Inst.Ref,
  18757     lhs_val: ?Value,
  18758     rhs_val: ?Value,
  18759     /// Only different than `scalar_ty` when it is a vector operation.
  18760     result_ty: Type,
  18761     scalar_ty: Type,
  18762 };
  18763 
  18764 fn checkSimdBinOp(
  18765     sema: *Sema,
  18766     block: *Block,
  18767     src: LazySrcLoc,
  18768     uncasted_lhs: Air.Inst.Ref,
  18769     uncasted_rhs: Air.Inst.Ref,
  18770     lhs_src: LazySrcLoc,
  18771     rhs_src: LazySrcLoc,
  18772 ) CompileError!SimdBinOp {
  18773     const lhs_ty = sema.typeOf(uncasted_lhs);
  18774     const rhs_ty = sema.typeOf(uncasted_rhs);
  18775 
  18776     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  18777     var vec_len: ?usize = if (lhs_ty.zigTypeTag() == .Vector) lhs_ty.vectorLen() else null;
  18778     const result_ty = try sema.resolvePeerTypes(block, src, &.{ uncasted_lhs, uncasted_rhs }, .{
  18779         .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
  18780     });
  18781     const lhs = try sema.coerce(block, result_ty, uncasted_lhs, lhs_src);
  18782     const rhs = try sema.coerce(block, result_ty, uncasted_rhs, rhs_src);
  18783 
  18784     return SimdBinOp{
  18785         .len = vec_len,
  18786         .lhs = lhs,
  18787         .rhs = rhs,
  18788         .lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs),
  18789         .rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs),
  18790         .result_ty = result_ty,
  18791         .scalar_ty = result_ty.scalarType(),
  18792     };
  18793 }
  18794 
  18795 fn checkVectorizableBinaryOperands(
  18796     sema: *Sema,
  18797     block: *Block,
  18798     src: LazySrcLoc,
  18799     lhs_ty: Type,
  18800     rhs_ty: Type,
  18801     lhs_src: LazySrcLoc,
  18802     rhs_src: LazySrcLoc,
  18803 ) CompileError!void {
  18804     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
  18805     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
  18806     if (lhs_zig_ty_tag != .Vector and rhs_zig_ty_tag != .Vector) return;
  18807 
  18808     const lhs_is_vector = switch (lhs_zig_ty_tag) {
  18809         .Vector, .Array => true,
  18810         else => false,
  18811     };
  18812     const rhs_is_vector = switch (rhs_zig_ty_tag) {
  18813         .Vector, .Array => true,
  18814         else => false,
  18815     };
  18816 
  18817     if (lhs_is_vector and rhs_is_vector) {
  18818         const lhs_len = lhs_ty.arrayLen();
  18819         const rhs_len = rhs_ty.arrayLen();
  18820         if (lhs_len != rhs_len) {
  18821             const msg = msg: {
  18822                 const msg = try sema.errMsg(block, src, "vector length mismatch", .{});
  18823                 errdefer msg.destroy(sema.gpa);
  18824                 try sema.errNote(block, lhs_src, msg, "length {d} here", .{lhs_len});
  18825                 try sema.errNote(block, rhs_src, msg, "length {d} here", .{rhs_len});
  18826                 break :msg msg;
  18827             };
  18828             return sema.failWithOwnedErrorMsg(msg);
  18829         }
  18830     } else {
  18831         const msg = msg: {
  18832             const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: '{}' and '{}'", .{
  18833                 lhs_ty.fmt(sema.mod), rhs_ty.fmt(sema.mod),
  18834             });
  18835             errdefer msg.destroy(sema.gpa);
  18836             if (lhs_is_vector) {
  18837                 try sema.errNote(block, lhs_src, msg, "vector here", .{});
  18838                 try sema.errNote(block, rhs_src, msg, "scalar here", .{});
  18839             } else {
  18840                 try sema.errNote(block, lhs_src, msg, "scalar here", .{});
  18841                 try sema.errNote(block, rhs_src, msg, "vector here", .{});
  18842             }
  18843             break :msg msg;
  18844         };
  18845         return sema.failWithOwnedErrorMsg(msg);
  18846     }
  18847 }
  18848 
  18849 fn maybeOptionsSrc(sema: *Sema, block: *Block, base_src: LazySrcLoc, wanted: []const u8) LazySrcLoc {
  18850     if (base_src == .unneeded) return .unneeded;
  18851     return Module.optionsSrc(sema.gpa, sema.mod.declPtr(block.src_decl), base_src, wanted);
  18852 }
  18853 
  18854 fn resolveExportOptions(
  18855     sema: *Sema,
  18856     block: *Block,
  18857     src: LazySrcLoc,
  18858     zir_ref: Zir.Inst.Ref,
  18859 ) CompileError!std.builtin.ExportOptions {
  18860     const export_options_ty = try sema.getBuiltinType(block, src, "ExportOptions");
  18861     const air_ref = try sema.resolveInst(zir_ref);
  18862     const options = try sema.coerce(block, export_options_ty, air_ref, src);
  18863 
  18864     const name_src = sema.maybeOptionsSrc(block, src, "name");
  18865     const linkage_src = sema.maybeOptionsSrc(block, src, "linkage");
  18866     const section_src = sema.maybeOptionsSrc(block, src, "section");
  18867     const visibility_src = sema.maybeOptionsSrc(block, src, "visibility");
  18868 
  18869     const name_operand = try sema.fieldVal(block, src, options, "name", name_src);
  18870     const name_val = try sema.resolveConstValue(block, name_src, name_operand, "name of exported value must be comptime known");
  18871     const name_ty = Type.initTag(.const_slice_u8);
  18872     const name = try name_val.toAllocatedBytes(name_ty, sema.arena, sema.mod);
  18873 
  18874     const linkage_operand = try sema.fieldVal(block, src, options, "linkage", linkage_src);
  18875     const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_operand, "linkage of exported value must be comptime known");
  18876     const linkage = linkage_val.toEnum(std.builtin.GlobalLinkage);
  18877 
  18878     const section = try sema.fieldVal(block, src, options, "section", section_src);
  18879     const section_val = try sema.resolveConstValue(block, section_src, section, "linksection of exported value must be comptime known");
  18880 
  18881     const visibility_operand = try sema.fieldVal(block, src, options, "visibility", visibility_src);
  18882     const visibility_val = try sema.resolveConstValue(block, visibility_src, visibility_operand, "visibility of exported value must be comptime known");
  18883     const visibility = visibility_val.toEnum(std.builtin.SymbolVisibility);
  18884 
  18885     if (name.len < 1) {
  18886         return sema.fail(block, name_src, "exported symbol name cannot be empty", .{});
  18887     }
  18888 
  18889     if (visibility != .default and linkage == .Internal) {
  18890         return sema.fail(block, visibility_src, "symbol '{s}' exported with internal linkage has non-default visibility {s}", .{
  18891             name, @tagName(visibility),
  18892         });
  18893     }
  18894 
  18895     if (!section_val.isNull()) {
  18896         return sema.fail(block, section_src, "TODO: implement exporting with linksection", .{});
  18897     }
  18898 
  18899     return std.builtin.ExportOptions{
  18900         .name = name,
  18901         .linkage = linkage,
  18902         .section = null, // TODO
  18903         .visibility = visibility,
  18904     };
  18905 }
  18906 
  18907 fn resolveBuiltinEnum(
  18908     sema: *Sema,
  18909     block: *Block,
  18910     src: LazySrcLoc,
  18911     zir_ref: Zir.Inst.Ref,
  18912     comptime name: []const u8,
  18913     reason: []const u8,
  18914 ) CompileError!@field(std.builtin, name) {
  18915     const ty = try sema.getBuiltinType(block, src, name);
  18916     const air_ref = try sema.resolveInst(zir_ref);
  18917     const coerced = try sema.coerce(block, ty, air_ref, src);
  18918     const val = try sema.resolveConstValue(block, src, coerced, reason);
  18919     return val.toEnum(@field(std.builtin, name));
  18920 }
  18921 
  18922 fn resolveAtomicOrder(
  18923     sema: *Sema,
  18924     block: *Block,
  18925     src: LazySrcLoc,
  18926     zir_ref: Zir.Inst.Ref,
  18927     reason: []const u8,
  18928 ) CompileError!std.builtin.AtomicOrder {
  18929     return resolveBuiltinEnum(sema, block, src, zir_ref, "AtomicOrder", reason);
  18930 }
  18931 
  18932 fn resolveAtomicRmwOp(
  18933     sema: *Sema,
  18934     block: *Block,
  18935     src: LazySrcLoc,
  18936     zir_ref: Zir.Inst.Ref,
  18937 ) CompileError!std.builtin.AtomicRmwOp {
  18938     return resolveBuiltinEnum(sema, block, src, zir_ref, "AtomicRmwOp", "@atomicRmW operation must be comptime known");
  18939 }
  18940 
  18941 fn zirCmpxchg(
  18942     sema: *Sema,
  18943     block: *Block,
  18944     extended: Zir.Inst.Extended.InstData,
  18945 ) CompileError!Air.Inst.Ref {
  18946     const extra = sema.code.extraData(Zir.Inst.Cmpxchg, extended.operand).data;
  18947     const air_tag: Air.Inst.Tag = switch (extended.small) {
  18948         0 => .cmpxchg_weak,
  18949         1 => .cmpxchg_strong,
  18950         else => unreachable,
  18951     };
  18952     const src = LazySrcLoc.nodeOffset(extra.node);
  18953     // zig fmt: off
  18954     const elem_ty_src      : LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  18955     const ptr_src          : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  18956     const expected_src     : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node };
  18957     const new_value_src    : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = extra.node };
  18958     const success_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg4 = extra.node };
  18959     const failure_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg5 = extra.node };
  18960     // zig fmt: on
  18961     const expected_value = try sema.resolveInst(extra.expected_value);
  18962     const elem_ty = sema.typeOf(expected_value);
  18963     if (elem_ty.zigTypeTag() == .Float) {
  18964         return sema.fail(
  18965             block,
  18966             elem_ty_src,
  18967             "expected bool, integer, enum, or pointer type; found '{}'",
  18968             .{elem_ty.fmt(sema.mod)},
  18969         );
  18970     }
  18971     const uncasted_ptr = try sema.resolveInst(extra.ptr);
  18972     const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
  18973     const new_value = try sema.coerce(block, elem_ty, try sema.resolveInst(extra.new_value), new_value_src);
  18974     const success_order = try sema.resolveAtomicOrder(block, success_order_src, extra.success_order, "atomic order of cmpxchg success must be comptime known");
  18975     const failure_order = try sema.resolveAtomicOrder(block, failure_order_src, extra.failure_order, "atomic order of cmpxchg failure must be comptime known");
  18976 
  18977     if (@enumToInt(success_order) < @enumToInt(std.builtin.AtomicOrder.Monotonic)) {
  18978         return sema.fail(block, success_order_src, "success atomic ordering must be Monotonic or stricter", .{});
  18979     }
  18980     if (@enumToInt(failure_order) < @enumToInt(std.builtin.AtomicOrder.Monotonic)) {
  18981         return sema.fail(block, failure_order_src, "failure atomic ordering must be Monotonic or stricter", .{});
  18982     }
  18983     if (@enumToInt(failure_order) > @enumToInt(success_order)) {
  18984         return sema.fail(block, failure_order_src, "failure atomic ordering must be no stricter than success", .{});
  18985     }
  18986     if (failure_order == .Release or failure_order == .AcqRel) {
  18987         return sema.fail(block, failure_order_src, "failure atomic ordering must not be Release or AcqRel", .{});
  18988     }
  18989 
  18990     const result_ty = try Type.optional(sema.arena, elem_ty);
  18991 
  18992     // special case zero bit types
  18993     if ((try sema.typeHasOnePossibleValue(block, elem_ty_src, elem_ty)) != null) {
  18994         return sema.addConstant(result_ty, Value.@"null");
  18995     }
  18996 
  18997     const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
  18998         if (try sema.resolveMaybeUndefVal(block, expected_src, expected_value)) |expected_val| {
  18999             if (try sema.resolveMaybeUndefVal(block, new_value_src, new_value)) |new_val| {
  19000                 if (expected_val.isUndef() or new_val.isUndef()) {
  19001                     // TODO: this should probably cause the memory stored at the pointer
  19002                     // to become undef as well
  19003                     return sema.addConstUndef(result_ty);
  19004                 }
  19005                 const ptr_ty = sema.typeOf(ptr);
  19006                 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;
  19007                 const result_val = if (stored_val.eql(expected_val, elem_ty, sema.mod)) blk: {
  19008                     try sema.storePtr(block, src, ptr, new_value);
  19009                     break :blk Value.@"null";
  19010                 } else try Value.Tag.opt_payload.create(sema.arena, stored_val);
  19011 
  19012                 return sema.addConstant(result_ty, result_val);
  19013             } else break :rs new_value_src;
  19014         } else break :rs expected_src;
  19015     } else ptr_src;
  19016 
  19017     const flags: u32 = @as(u32, @enumToInt(success_order)) |
  19018         (@as(u32, @enumToInt(failure_order)) << 3);
  19019 
  19020     try sema.requireRuntimeBlock(block, src, runtime_src);
  19021     return block.addInst(.{
  19022         .tag = air_tag,
  19023         .data = .{ .ty_pl = .{
  19024             .ty = try sema.addType(result_ty),
  19025             .payload = try sema.addExtra(Air.Cmpxchg{
  19026                 .ptr = ptr,
  19027                 .expected_value = expected_value,
  19028                 .new_value = new_value,
  19029                 .flags = flags,
  19030             }),
  19031         } },
  19032     });
  19033 }
  19034 
  19035 fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  19036     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  19037     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  19038     const len_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  19039     const scalar_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  19040     const len = @intCast(u32, try sema.resolveInt(block, len_src, extra.lhs, Type.u32, "vector splat destination length must be comptime known"));
  19041     const scalar = try sema.resolveInst(extra.rhs);
  19042     const scalar_ty = sema.typeOf(scalar);
  19043     try sema.checkVectorElemType(block, scalar_src, scalar_ty);
  19044     const vector_ty = try Type.Tag.vector.create(sema.arena, .{
  19045         .len = len,
  19046         .elem_type = scalar_ty,
  19047     });
  19048     if (try sema.resolveMaybeUndefVal(block, scalar_src, scalar)) |scalar_val| {
  19049         if (scalar_val.isUndef()) return sema.addConstUndef(vector_ty);
  19050 
  19051         return sema.addConstant(
  19052             vector_ty,
  19053             try Value.Tag.repeated.create(sema.arena, scalar_val),
  19054         );
  19055     }
  19056 
  19057     try sema.requireRuntimeBlock(block, inst_data.src(), scalar_src);
  19058     return block.addTyOp(.splat, vector_ty, scalar);
  19059 }
  19060 
  19061 fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  19062     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  19063     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  19064     const op_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  19065     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  19066     const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, "ReduceOp", "@reduce operation must be comptime known");
  19067     const operand = try sema.resolveInst(extra.rhs);
  19068     const operand_ty = sema.typeOf(operand);
  19069     const target = sema.mod.getTarget();
  19070 
  19071     if (operand_ty.zigTypeTag() != .Vector) {
  19072         return sema.fail(block, operand_src, "expected vector, found '{}'", .{operand_ty.fmt(sema.mod)});
  19073     }
  19074 
  19075     const scalar_ty = operand_ty.childType();
  19076 
  19077     // Type-check depending on operation.
  19078     switch (operation) {
  19079         .And, .Or, .Xor => switch (scalar_ty.zigTypeTag()) {
  19080             .Int, .Bool => {},
  19081             else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found '{}'", .{
  19082                 @tagName(operation), operand_ty.fmt(sema.mod),
  19083             }),
  19084         },
  19085         .Min, .Max, .Add, .Mul => switch (scalar_ty.zigTypeTag()) {
  19086             .Int, .Float => {},
  19087             else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found '{}'", .{
  19088                 @tagName(operation), operand_ty.fmt(sema.mod),
  19089             }),
  19090         },
  19091     }
  19092 
  19093     const vec_len = operand_ty.vectorLen();
  19094     if (vec_len == 0) {
  19095         // TODO re-evaluate if we should introduce a "neutral value" for some operations,
  19096         // e.g. zero for add and one for mul.
  19097         return sema.fail(block, operand_src, "@reduce operation requires a vector with nonzero length", .{});
  19098     }
  19099 
  19100     if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| {
  19101         if (operand_val.isUndef()) return sema.addConstUndef(scalar_ty);
  19102 
  19103         var accum: Value = try operand_val.elemValue(sema.mod, sema.arena, 0);
  19104         var elem_buf: Value.ElemValueBuffer = undefined;
  19105         var i: u32 = 1;
  19106         while (i < vec_len) : (i += 1) {
  19107             const elem_val = operand_val.elemValueBuffer(sema.mod, i, &elem_buf);
  19108             switch (operation) {
  19109                 .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena, target),
  19110                 .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena, target),
  19111                 .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena, target),
  19112                 .Min => accum = accum.numberMin(elem_val, target),
  19113                 .Max => accum = accum.numberMax(elem_val, target),
  19114                 .Add => accum = try sema.numberAddWrap(block, operand_src, accum, elem_val, scalar_ty),
  19115                 .Mul => accum = try accum.numberMulWrap(elem_val, scalar_ty, sema.arena, target),
  19116             }
  19117         }
  19118         return sema.addConstant(scalar_ty, accum);
  19119     }
  19120 
  19121     try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
  19122     return block.addInst(.{
  19123         .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
  19124         .data = .{ .reduce = .{
  19125             .operand = operand,
  19126             .operation = operation,
  19127         } },
  19128     });
  19129 }
  19130 
  19131 fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  19132     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  19133     const extra = sema.code.extraData(Zir.Inst.Shuffle, inst_data.payload_index).data;
  19134     const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  19135     const mask_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
  19136 
  19137     const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
  19138     try sema.checkVectorElemType(block, elem_ty_src, elem_ty);
  19139     var a = try sema.resolveInst(extra.a);
  19140     var b = try sema.resolveInst(extra.b);
  19141     var mask = try sema.resolveInst(extra.mask);
  19142     var mask_ty = sema.typeOf(mask);
  19143 
  19144     const mask_len = switch (sema.typeOf(mask).zigTypeTag()) {
  19145         .Array, .Vector => sema.typeOf(mask).arrayLen(),
  19146         else => return sema.fail(block, mask_src, "expected vector or array, found '{}'", .{sema.typeOf(mask).fmt(sema.mod)}),
  19147     };
  19148     mask_ty = try Type.Tag.vector.create(sema.arena, .{
  19149         .len = mask_len,
  19150         .elem_type = Type.@"i32",
  19151     });
  19152     mask = try sema.coerce(block, mask_ty, mask, mask_src);
  19153     const mask_val = try sema.resolveConstMaybeUndefVal(block, mask_src, mask, "shuffle mask must be comptime known");
  19154     return sema.analyzeShuffle(block, inst_data.src_node, elem_ty, a, b, mask_val, @intCast(u32, mask_len));
  19155 }
  19156 
  19157 fn analyzeShuffle(
  19158     sema: *Sema,
  19159     block: *Block,
  19160     src_node: i32,
  19161     elem_ty: Type,
  19162     a_arg: Air.Inst.Ref,
  19163     b_arg: Air.Inst.Ref,
  19164     mask: Value,
  19165     mask_len: u32,
  19166 ) CompileError!Air.Inst.Ref {
  19167     const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = src_node };
  19168     const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = src_node };
  19169     const mask_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = src_node };
  19170     var a = a_arg;
  19171     var b = b_arg;
  19172 
  19173     const res_ty = try Type.Tag.vector.create(sema.arena, .{
  19174         .len = mask_len,
  19175         .elem_type = elem_ty,
  19176     });
  19177 
  19178     var maybe_a_len = switch (sema.typeOf(a).zigTypeTag()) {
  19179         .Array, .Vector => sema.typeOf(a).arrayLen(),
  19180         .Undefined => null,
  19181         else => return sema.fail(block, a_src, "expected vector or array with element type '{}', found '{}'", .{
  19182             elem_ty.fmt(sema.mod),
  19183             sema.typeOf(a).fmt(sema.mod),
  19184         }),
  19185     };
  19186     var maybe_b_len = switch (sema.typeOf(b).zigTypeTag()) {
  19187         .Array, .Vector => sema.typeOf(b).arrayLen(),
  19188         .Undefined => null,
  19189         else => return sema.fail(block, b_src, "expected vector or array with element type '{}', found '{}'", .{
  19190             elem_ty.fmt(sema.mod),
  19191             sema.typeOf(b).fmt(sema.mod),
  19192         }),
  19193     };
  19194     if (maybe_a_len == null and maybe_b_len == null) {
  19195         return sema.addConstUndef(res_ty);
  19196     }
  19197     const a_len = maybe_a_len orelse maybe_b_len.?;
  19198     const b_len = maybe_b_len orelse a_len;
  19199 
  19200     const a_ty = try Type.Tag.vector.create(sema.arena, .{
  19201         .len = a_len,
  19202         .elem_type = elem_ty,
  19203     });
  19204     const b_ty = try Type.Tag.vector.create(sema.arena, .{
  19205         .len = b_len,
  19206         .elem_type = elem_ty,
  19207     });
  19208 
  19209     if (maybe_a_len == null) a = try sema.addConstUndef(a_ty);
  19210     if (maybe_b_len == null) b = try sema.addConstUndef(b_ty);
  19211 
  19212     const operand_info = [2]std.meta.Tuple(&.{ u64, LazySrcLoc, Type }){
  19213         .{ a_len, a_src, a_ty },
  19214         .{ b_len, b_src, b_ty },
  19215     };
  19216 
  19217     var i: usize = 0;
  19218     while (i < mask_len) : (i += 1) {
  19219         var buf: Value.ElemValueBuffer = undefined;
  19220         const elem = mask.elemValueBuffer(sema.mod, i, &buf);
  19221         if (elem.isUndef()) continue;
  19222         const int = elem.toSignedInt();
  19223         var unsigned: u32 = undefined;
  19224         var chosen: u32 = undefined;
  19225         if (int >= 0) {
  19226             unsigned = @intCast(u32, int);
  19227             chosen = 0;
  19228         } else {
  19229             unsigned = @intCast(u32, ~int);
  19230             chosen = 1;
  19231         }
  19232         if (unsigned >= operand_info[chosen][0]) {
  19233             const msg = msg: {
  19234                 const msg = try sema.errMsg(block, mask_src, "mask index '{d}' has out-of-bounds selection", .{i});
  19235                 errdefer msg.destroy(sema.gpa);
  19236 
  19237                 try sema.errNote(block, operand_info[chosen][1], msg, "selected index '{d}' out of bounds of '{}'", .{
  19238                     unsigned,
  19239                     operand_info[chosen][2].fmt(sema.mod),
  19240                 });
  19241 
  19242                 if (chosen == 0) {
  19243                     try sema.errNote(block, b_src, msg, "selections from the second vector are specified with negative numbers", .{});
  19244                 }
  19245 
  19246                 break :msg msg;
  19247             };
  19248             return sema.failWithOwnedErrorMsg(msg);
  19249         }
  19250     }
  19251 
  19252     if (try sema.resolveMaybeUndefVal(block, a_src, a)) |a_val| {
  19253         if (try sema.resolveMaybeUndefVal(block, b_src, b)) |b_val| {
  19254             const values = try sema.arena.alloc(Value, mask_len);
  19255 
  19256             i = 0;
  19257             while (i < mask_len) : (i += 1) {
  19258                 var buf: Value.ElemValueBuffer = undefined;
  19259                 const mask_elem_val = mask.elemValueBuffer(sema.mod, i, &buf);
  19260                 if (mask_elem_val.isUndef()) {
  19261                     values[i] = Value.undef;
  19262                     continue;
  19263                 }
  19264                 const int = mask_elem_val.toSignedInt();
  19265                 const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int);
  19266                 if (int >= 0) {
  19267                     values[i] = try a_val.elemValue(sema.mod, sema.arena, unsigned);
  19268                 } else {
  19269                     values[i] = try b_val.elemValue(sema.mod, sema.arena, unsigned);
  19270                 }
  19271             }
  19272             const res_val = try Value.Tag.aggregate.create(sema.arena, values);
  19273             return sema.addConstant(res_ty, res_val);
  19274         }
  19275     }
  19276 
  19277     // All static analysis passed, and not comptime.
  19278     // For runtime codegen, vectors a and b must be the same length. Here we
  19279     // recursively @shuffle the smaller vector to append undefined elements
  19280     // to it up to the length of the longer vector. This recursion terminates
  19281     // in 1 call because these calls to analyzeShuffle guarantee a_len == b_len.
  19282     if (a_len != b_len) {
  19283         const min_len = std.math.min(a_len, b_len);
  19284         const max_src = if (a_len > b_len) a_src else b_src;
  19285         const max_len = try sema.usizeCast(block, max_src, std.math.max(a_len, b_len));
  19286 
  19287         const expand_mask_values = try sema.arena.alloc(Value, max_len);
  19288         i = 0;
  19289         while (i < min_len) : (i += 1) {
  19290             expand_mask_values[i] = try Value.Tag.int_u64.create(sema.arena, i);
  19291         }
  19292         while (i < max_len) : (i += 1) {
  19293             expand_mask_values[i] = Value.negative_one;
  19294         }
  19295         const expand_mask = try Value.Tag.aggregate.create(sema.arena, expand_mask_values);
  19296 
  19297         if (a_len < b_len) {
  19298             const undef = try sema.addConstUndef(a_ty);
  19299             a = try sema.analyzeShuffle(block, src_node, elem_ty, a, undef, expand_mask, @intCast(u32, max_len));
  19300         } else {
  19301             const undef = try sema.addConstUndef(b_ty);
  19302             b = try sema.analyzeShuffle(block, src_node, elem_ty, b, undef, expand_mask, @intCast(u32, max_len));
  19303         }
  19304     }
  19305 
  19306     const mask_index = @intCast(u32, sema.air_values.items.len);
  19307     try sema.air_values.append(sema.gpa, mask);
  19308     return block.addInst(.{
  19309         .tag = .shuffle,
  19310         .data = .{ .ty_pl = .{
  19311             .ty = try sema.addType(res_ty),
  19312             .payload = try block.sema.addExtra(Air.Shuffle{
  19313                 .a = a,
  19314                 .b = b,
  19315                 .mask = mask_index,
  19316                 .mask_len = mask_len,
  19317             }),
  19318         } },
  19319     });
  19320 }
  19321 
  19322 fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
  19323     const extra = sema.code.extraData(Zir.Inst.Select, extended.operand).data;
  19324 
  19325     const src = LazySrcLoc.nodeOffset(extra.node);
  19326     const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  19327     const pred_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  19328     const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node };
  19329     const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = extra.node };
  19330 
  19331     const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
  19332     try sema.checkVectorElemType(block, elem_ty_src, elem_ty);
  19333     const pred_uncoerced = try sema.resolveInst(extra.pred);
  19334     const pred_ty = sema.typeOf(pred_uncoerced);
  19335 
  19336     const vec_len_u64 = switch (try pred_ty.zigTypeTagOrPoison()) {
  19337         .Vector, .Array => pred_ty.arrayLen(),
  19338         else => return sema.fail(block, pred_src, "expected vector or array, found '{}'", .{pred_ty.fmt(sema.mod)}),
  19339     };
  19340     const vec_len = try sema.usizeCast(block, pred_src, vec_len_u64);
  19341 
  19342     const bool_vec_ty = try Type.vector(sema.arena, vec_len, Type.bool);
  19343     const pred = try sema.coerce(block, bool_vec_ty, pred_uncoerced, pred_src);
  19344 
  19345     const vec_ty = try Type.vector(sema.arena, vec_len, elem_ty);
  19346     const a = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.a), a_src);
  19347     const b = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.b), b_src);
  19348 
  19349     const maybe_pred = try sema.resolveMaybeUndefVal(block, pred_src, pred);
  19350     const maybe_a = try sema.resolveMaybeUndefVal(block, a_src, a);
  19351     const maybe_b = try sema.resolveMaybeUndefVal(block, b_src, b);
  19352 
  19353     const runtime_src = if (maybe_pred) |pred_val| rs: {
  19354         if (pred_val.isUndef()) return sema.addConstUndef(vec_ty);
  19355 
  19356         if (maybe_a) |a_val| {
  19357             if (a_val.isUndef()) return sema.addConstUndef(vec_ty);
  19358 
  19359             if (maybe_b) |b_val| {
  19360                 if (b_val.isUndef()) return sema.addConstUndef(vec_ty);
  19361 
  19362                 var buf: Value.ElemValueBuffer = undefined;
  19363                 const elems = try sema.gpa.alloc(Value, vec_len);
  19364                 for (elems) |*elem, i| {
  19365                     const pred_elem_val = pred_val.elemValueBuffer(sema.mod, i, &buf);
  19366                     const should_choose_a = pred_elem_val.toBool();
  19367                     if (should_choose_a) {
  19368                         elem.* = a_val.elemValueBuffer(sema.mod, i, &buf);
  19369                     } else {
  19370                         elem.* = b_val.elemValueBuffer(sema.mod, i, &buf);
  19371                     }
  19372                 }
  19373 
  19374                 return sema.addConstant(
  19375                     vec_ty,
  19376                     try Value.Tag.aggregate.create(sema.arena, elems),
  19377                 );
  19378             } else {
  19379                 break :rs b_src;
  19380             }
  19381         } else {
  19382             if (maybe_b) |b_val| {
  19383                 if (b_val.isUndef()) return sema.addConstUndef(vec_ty);
  19384             }
  19385             break :rs a_src;
  19386         }
  19387     } else rs: {
  19388         if (maybe_a) |a_val| {
  19389             if (a_val.isUndef()) return sema.addConstUndef(vec_ty);
  19390         }
  19391         if (maybe_b) |b_val| {
  19392             if (b_val.isUndef()) return sema.addConstUndef(vec_ty);
  19393         }
  19394         break :rs pred_src;
  19395     };
  19396 
  19397     try sema.requireRuntimeBlock(block, src, runtime_src);
  19398     return block.addInst(.{
  19399         .tag = .select,
  19400         .data = .{ .pl_op = .{
  19401             .operand = pred,
  19402             .payload = try block.sema.addExtra(Air.Bin{
  19403                 .lhs = a,
  19404                 .rhs = b,
  19405             }),
  19406         } },
  19407     });
  19408 }
  19409 
  19410 fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  19411     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  19412     const extra = sema.code.extraData(Zir.Inst.AtomicLoad, inst_data.payload_index).data;
  19413     // zig fmt: off
  19414     const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  19415     const ptr_src    : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  19416     const order_src  : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  19417     // zig fmt: on
  19418     const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
  19419     const uncasted_ptr = try sema.resolveInst(extra.ptr);
  19420     const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true);
  19421     const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicLoad must be comptime known");
  19422 
  19423     switch (order) {
  19424         .Release, .AcqRel => {
  19425             return sema.fail(
  19426                 block,
  19427                 order_src,
  19428                 "@atomicLoad atomic ordering must not be Release or AcqRel",
  19429                 .{},
  19430             );
  19431         },
  19432         else => {},
  19433     }
  19434 
  19435     if (try sema.typeHasOnePossibleValue(block, elem_ty_src, elem_ty)) |val| {
  19436         return sema.addConstant(elem_ty, val);
  19437     }
  19438 
  19439     if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
  19440         if (try sema.pointerDeref(block, ptr_src, ptr_val, sema.typeOf(ptr))) |elem_val| {
  19441             return sema.addConstant(elem_ty, elem_val);
  19442         }
  19443     }
  19444 
  19445     try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
  19446     return block.addInst(.{
  19447         .tag = .atomic_load,
  19448         .data = .{ .atomic_load = .{
  19449             .ptr = ptr,
  19450             .order = order,
  19451         } },
  19452     });
  19453 }
  19454 
  19455 fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  19456     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  19457     const extra = sema.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data;
  19458     const src = inst_data.src();
  19459     // zig fmt: off
  19460     const elem_ty_src   : LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  19461     const ptr_src       : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  19462     const op_src        : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  19463     const operand_src   : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
  19464     const order_src     : LazySrcLoc = .{ .node_offset_builtin_call_arg4 = inst_data.src_node };
  19465     // zig fmt: on
  19466     const operand = try sema.resolveInst(extra.operand);
  19467     const elem_ty = sema.typeOf(operand);
  19468     const uncasted_ptr = try sema.resolveInst(extra.ptr);
  19469     const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
  19470     const op = try sema.resolveAtomicRmwOp(block, op_src, extra.operation);
  19471 
  19472     switch (elem_ty.zigTypeTag()) {
  19473         .Enum => if (op != .Xchg) {
  19474             return sema.fail(block, op_src, "@atomicRmw with enum only allowed with .Xchg", .{});
  19475         },
  19476         .Bool => if (op != .Xchg) {
  19477             return sema.fail(block, op_src, "@atomicRmw with bool only allowed with .Xchg", .{});
  19478         },
  19479         .Float => switch (op) {
  19480             .Xchg, .Add, .Sub => {},
  19481             else => return sema.fail(block, op_src, "@atomicRmw with float only allowed with .Xchg, .Add, and .Sub", .{}),
  19482         },
  19483         else => {},
  19484     }
  19485     const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicRmW must be comptime known");
  19486 
  19487     if (order == .Unordered) {
  19488         return sema.fail(block, order_src, "@atomicRmw atomic ordering must not be Unordered", .{});
  19489     }
  19490 
  19491     // special case zero bit types
  19492     if (try sema.typeHasOnePossibleValue(block, elem_ty_src, elem_ty)) |val| {
  19493         return sema.addConstant(elem_ty, val);
  19494     }
  19495 
  19496     const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
  19497         const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand);
  19498         const operand_val = maybe_operand_val orelse {
  19499             try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);
  19500             break :rs operand_src;
  19501         };
  19502         if (ptr_val.isComptimeMutablePtr()) {
  19503             const target = sema.mod.getTarget();
  19504             const ptr_ty = sema.typeOf(ptr);
  19505             const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;
  19506             const new_val = switch (op) {
  19507                 // zig fmt: off
  19508                 .Xchg => operand_val,
  19509                 .Add  => try sema.numberAddWrap(block, src, stored_val, operand_val, elem_ty),
  19510                 .Sub  => try sema.numberSubWrap(block, src, stored_val, operand_val, elem_ty),
  19511                 .And  => try                   stored_val.bitwiseAnd   (operand_val, elem_ty, sema.arena, target),
  19512                 .Nand => try                   stored_val.bitwiseNand  (operand_val, elem_ty, sema.arena, target),
  19513                 .Or   => try                   stored_val.bitwiseOr    (operand_val, elem_ty, sema.arena, target),
  19514                 .Xor  => try                   stored_val.bitwiseXor   (operand_val, elem_ty, sema.arena, target),
  19515                 .Max  =>                       stored_val.numberMax    (operand_val,                      target),
  19516                 .Min  =>                       stored_val.numberMin    (operand_val,                      target),
  19517                 // zig fmt: on
  19518             };
  19519             try sema.storePtrVal(block, src, ptr_val, new_val, elem_ty);
  19520             return sema.addConstant(elem_ty, stored_val);
  19521         } else break :rs ptr_src;
  19522     } else ptr_src;
  19523 
  19524     const flags: u32 = @as(u32, @enumToInt(order)) | (@as(u32, @enumToInt(op)) << 3);
  19525 
  19526     try sema.requireRuntimeBlock(block, src, runtime_src);
  19527     return block.addInst(.{
  19528         .tag = .atomic_rmw,
  19529         .data = .{ .pl_op = .{
  19530             .operand = ptr,
  19531             .payload = try sema.addExtra(Air.AtomicRmw{
  19532                 .operand = operand,
  19533                 .flags = flags,
  19534             }),
  19535         } },
  19536     });
  19537 }
  19538 
  19539 fn zirAtomicStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
  19540     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  19541     const extra = sema.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data;
  19542     const src = inst_data.src();
  19543     // zig fmt: off
  19544     const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  19545     const ptr_src       : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  19546     const operand_src   : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  19547     const order_src     : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
  19548     // zig fmt: on
  19549     const operand = try sema.resolveInst(extra.operand);
  19550     const elem_ty = sema.typeOf(operand);
  19551     const uncasted_ptr = try sema.resolveInst(extra.ptr);
  19552     const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
  19553     const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicStore must be comptime known");
  19554 
  19555     const air_tag: Air.Inst.Tag = switch (order) {
  19556         .Acquire, .AcqRel => {
  19557             return sema.fail(
  19558                 block,
  19559                 order_src,
  19560                 "@atomicStore atomic ordering must not be Acquire or AcqRel",
  19561                 .{},
  19562             );
  19563         },
  19564         .Unordered => .atomic_store_unordered,
  19565         .Monotonic => .atomic_store_monotonic,
  19566         .Release => .atomic_store_release,
  19567         .SeqCst => .atomic_store_seq_cst,
  19568     };
  19569 
  19570     return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag);
  19571 }
  19572 
  19573 fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  19574     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  19575     const extra = sema.code.extraData(Zir.Inst.MulAdd, inst_data.payload_index).data;
  19576     const src = inst_data.src();
  19577 
  19578     const mulend1_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  19579     const mulend2_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  19580     const addend_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
  19581 
  19582     const addend = try sema.resolveInst(extra.addend);
  19583     const ty = sema.typeOf(addend);
  19584     const mulend1 = try sema.coerce(block, ty, try sema.resolveInst(extra.mulend1), mulend1_src);
  19585     const mulend2 = try sema.coerce(block, ty, try sema.resolveInst(extra.mulend2), mulend2_src);
  19586 
  19587     const target = sema.mod.getTarget();
  19588 
  19589     const maybe_mulend1 = try sema.resolveMaybeUndefVal(block, mulend1_src, mulend1);
  19590     const maybe_mulend2 = try sema.resolveMaybeUndefVal(block, mulend2_src, mulend2);
  19591     const maybe_addend = try sema.resolveMaybeUndefVal(block, addend_src, addend);
  19592 
  19593     switch (ty.zigTypeTag()) {
  19594         .ComptimeFloat, .Float, .Vector => {},
  19595         else => return sema.fail(block, src, "expected vector of floats or float type, found '{}'", .{ty.fmt(sema.mod)}),
  19596     }
  19597 
  19598     const runtime_src = if (maybe_mulend1) |mulend1_val| rs: {
  19599         if (maybe_mulend2) |mulend2_val| {
  19600             if (mulend2_val.isUndef()) return sema.addConstUndef(ty);
  19601 
  19602             if (maybe_addend) |addend_val| {
  19603                 if (addend_val.isUndef()) return sema.addConstUndef(ty);
  19604                 const result_val = try Value.mulAdd(ty, mulend1_val, mulend2_val, addend_val, sema.arena, target);
  19605                 return sema.addConstant(ty, result_val);
  19606             } else {
  19607                 break :rs addend_src;
  19608             }
  19609         } else {
  19610             if (maybe_addend) |addend_val| {
  19611                 if (addend_val.isUndef()) return sema.addConstUndef(ty);
  19612             }
  19613             break :rs mulend2_src;
  19614         }
  19615     } else rs: {
  19616         if (maybe_mulend2) |mulend2_val| {
  19617             if (mulend2_val.isUndef()) return sema.addConstUndef(ty);
  19618         }
  19619         if (maybe_addend) |addend_val| {
  19620             if (addend_val.isUndef()) return sema.addConstUndef(ty);
  19621         }
  19622         break :rs mulend1_src;
  19623     };
  19624 
  19625     try sema.requireRuntimeBlock(block, src, runtime_src);
  19626     return block.addInst(.{
  19627         .tag = .mul_add,
  19628         .data = .{ .pl_op = .{
  19629             .operand = addend,
  19630             .payload = try sema.addExtra(Air.Bin{
  19631                 .lhs = mulend1,
  19632                 .rhs = mulend2,
  19633             }),
  19634         } },
  19635     });
  19636 }
  19637 
  19638 fn resolveCallOptions(
  19639     sema: *Sema,
  19640     block: *Block,
  19641     src: LazySrcLoc,
  19642     zir_ref: Zir.Inst.Ref,
  19643     is_comptime: bool,
  19644     is_nosuspend: bool,
  19645     func: Air.Inst.Ref,
  19646     func_src: LazySrcLoc,
  19647 ) CompileError!std.builtin.CallOptions.Modifier {
  19648     const call_options_ty = try sema.getBuiltinType(block, src, "CallOptions");
  19649     const air_ref = try sema.resolveInst(zir_ref);
  19650     const options = try sema.coerce(block, call_options_ty, air_ref, src);
  19651 
  19652     const modifier_src = sema.maybeOptionsSrc(block, src, "modifier");
  19653     const stack_src = sema.maybeOptionsSrc(block, src, "stack");
  19654 
  19655     const modifier = try sema.fieldVal(block, src, options, "modifier", modifier_src);
  19656     const modifier_val = try sema.resolveConstValue(block, modifier_src, modifier, "call modifier must be comptime known");
  19657     const wanted_modifier = modifier_val.toEnum(std.builtin.CallOptions.Modifier);
  19658 
  19659     const stack = try sema.fieldVal(block, src, options, "stack", stack_src);
  19660     const stack_val = try sema.resolveConstValue(block, stack_src, stack, "call stack value must be comptime known");
  19661 
  19662     if (!stack_val.isNull()) {
  19663         return sema.fail(block, stack_src, "TODO: implement @call with stack", .{});
  19664     }
  19665 
  19666     switch (wanted_modifier) {
  19667         // These can be upgraded to comptime or nosuspend calls.
  19668         .auto, .never_tail, .no_async => {
  19669             if (is_comptime) {
  19670                 if (wanted_modifier == .never_tail) {
  19671                     return sema.fail(block, modifier_src, "unable to perform 'never_tail' call at compile-time", .{});
  19672                 }
  19673                 return .compile_time;
  19674             }
  19675             if (is_nosuspend) {
  19676                 return .no_async;
  19677             }
  19678             return wanted_modifier;
  19679         },
  19680         // These can be upgraded to comptime. nosuspend bit can be safely ignored.
  19681         .always_inline, .compile_time => {
  19682             _ = (try sema.resolveDefinedValue(block, func_src, func)) orelse {
  19683                 return sema.fail(block, func_src, "modifier '{s}' requires a comptime-known function", .{@tagName(wanted_modifier)});
  19684             };
  19685 
  19686             if (is_comptime) {
  19687                 return .compile_time;
  19688             }
  19689             return wanted_modifier;
  19690         },
  19691         .always_tail => {
  19692             if (is_comptime) {
  19693                 return .compile_time;
  19694             }
  19695             return wanted_modifier;
  19696         },
  19697         .async_kw => {
  19698             if (is_nosuspend) {
  19699                 return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{});
  19700             }
  19701             if (is_comptime) {
  19702                 return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used in combination with comptime function call", .{});
  19703             }
  19704             return wanted_modifier;
  19705         },
  19706         .never_inline => {
  19707             if (is_comptime) {
  19708                 return sema.fail(block, modifier_src, "unable to perform 'never_inline' call at compile-time", .{});
  19709             }
  19710             return wanted_modifier;
  19711         },
  19712     }
  19713 }
  19714 
  19715 fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  19716     const tracy = trace(@src());
  19717     defer tracy.end();
  19718 
  19719     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  19720     const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  19721     const func_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  19722     const args_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  19723     const call_src = inst_data.src();
  19724 
  19725     const extra = sema.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data;
  19726     var func = try sema.resolveInst(extra.callee);
  19727     const modifier = sema.resolveCallOptions(
  19728         block,
  19729         .unneeded,
  19730         extra.options,
  19731         extra.flags.is_comptime,
  19732         extra.flags.is_nosuspend,
  19733         func,
  19734         func_src,
  19735     ) catch |err| switch (err) {
  19736         error.NeededSourceLocation => {
  19737             _ = try sema.resolveCallOptions(
  19738                 block,
  19739                 options_src,
  19740                 extra.options,
  19741                 extra.flags.is_comptime,
  19742                 extra.flags.is_nosuspend,
  19743                 func,
  19744                 func_src,
  19745             );
  19746             return error.AnalysisFail;
  19747         },
  19748         else => |e| return e,
  19749     };
  19750     const args = try sema.resolveInst(extra.args);
  19751 
  19752     const args_ty = sema.typeOf(args);
  19753     if (!args_ty.isTuple() and args_ty.tag() != .empty_struct_literal) {
  19754         return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(sema.mod)});
  19755     }
  19756 
  19757     var resolved_args: []Air.Inst.Ref = undefined;
  19758 
  19759     // Desugar bound functions here
  19760     var bound_arg_src: ?LazySrcLoc = null;
  19761     if (sema.typeOf(func).tag() == .bound_fn) {
  19762         bound_arg_src = func_src;
  19763         const bound_func = try sema.resolveValue(block, .unneeded, func, undefined);
  19764         const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
  19765         func = bound_data.func_inst;
  19766         resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount() + 1);
  19767         resolved_args[0] = bound_data.arg0_inst;
  19768         for (resolved_args[1..]) |*resolved, i| {
  19769             resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
  19770         }
  19771     } else {
  19772         resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount());
  19773         for (resolved_args) |*resolved, i| {
  19774             resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
  19775         }
  19776     }
  19777     const ensure_result_used = extra.flags.ensure_result_used;
  19778     return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src);
  19779 }
  19780 
  19781 fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  19782     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  19783     const extra = sema.code.extraData(Zir.Inst.FieldParentPtr, inst_data.payload_index).data;
  19784     const src = inst_data.src();
  19785     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  19786     const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  19787     const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  19788 
  19789     const struct_ty = try sema.resolveType(block, ty_src, extra.parent_type);
  19790     const field_name = try sema.resolveConstString(block, name_src, extra.field_name, "field name must be comptime known");
  19791     const field_ptr = try sema.resolveInst(extra.field_ptr);
  19792     const field_ptr_ty = sema.typeOf(field_ptr);
  19793 
  19794     if (struct_ty.zigTypeTag() != .Struct) {
  19795         return sema.fail(block, ty_src, "expected struct type, found '{}'", .{struct_ty.fmt(sema.mod)});
  19796     }
  19797     try sema.resolveTypeLayout(block, ty_src, struct_ty);
  19798 
  19799     const field_index = if (struct_ty.isTuple()) blk: {
  19800         if (mem.eql(u8, field_name, "len")) {
  19801             return sema.fail(block, src, "cannot get @fieldParentPtr of 'len' field of tuple", .{});
  19802         }
  19803         break :blk try sema.tupleFieldIndex(block, struct_ty, field_name, name_src);
  19804     } else try sema.structFieldIndex(block, struct_ty, field_name, name_src);
  19805 
  19806     try sema.checkPtrOperand(block, ptr_src, field_ptr_ty);
  19807     const field_ptr_ty_info = field_ptr_ty.ptrInfo().data;
  19808 
  19809     var ptr_ty_data: Type.Payload.Pointer.Data = .{
  19810         .pointee_type = struct_ty.structFieldType(field_index),
  19811         .mutable = field_ptr_ty_info.mutable,
  19812         .@"addrspace" = field_ptr_ty_info.@"addrspace",
  19813     };
  19814 
  19815     if (struct_ty.containerLayout() == .Packed) {
  19816         return sema.fail(block, src, "TODO handle packed structs with @fieldParentPtr", .{});
  19817     } else {
  19818         ptr_ty_data.@"align" = if (struct_ty.castTag(.@"struct")) |struct_obj| b: {
  19819             break :b struct_obj.data.fields.values()[field_index].abi_align;
  19820         } else 0;
  19821     }
  19822 
  19823     const actual_field_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);
  19824     const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, ptr_src);
  19825 
  19826     ptr_ty_data.pointee_type = struct_ty;
  19827     const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);
  19828 
  19829     if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {
  19830         const payload = field_ptr_val.castTag(.field_ptr) orelse {
  19831             return sema.fail(block, ptr_src, "pointer value not based on parent struct", .{});
  19832         };
  19833         if (payload.data.field_index != field_index) {
  19834             const msg = msg: {
  19835                 const msg = try sema.errMsg(
  19836                     block,
  19837                     src,
  19838                     "field '{s}' has index '{d}' but pointer value is index '{d}' of struct '{}'",
  19839                     .{
  19840                         field_name,
  19841                         field_index,
  19842                         payload.data.field_index,
  19843                         struct_ty.fmt(sema.mod),
  19844                     },
  19845                 );
  19846                 errdefer msg.destroy(sema.gpa);
  19847                 try sema.addDeclaredHereNote(msg, struct_ty);
  19848                 break :msg msg;
  19849             };
  19850             return sema.failWithOwnedErrorMsg(msg);
  19851         }
  19852         return sema.addConstant(result_ptr, payload.data.container_ptr);
  19853     }
  19854 
  19855     try sema.requireRuntimeBlock(block, src, ptr_src);
  19856     return block.addInst(.{
  19857         .tag = .field_parent_ptr,
  19858         .data = .{ .ty_pl = .{
  19859             .ty = try sema.addType(result_ptr),
  19860             .payload = try block.sema.addExtra(Air.FieldParentPtr{
  19861                 .field_ptr = casted_field_ptr,
  19862                 .field_index = @intCast(u32, field_index),
  19863             }),
  19864         } },
  19865     });
  19866 }
  19867 
  19868 fn zirMinMax(
  19869     sema: *Sema,
  19870     block: *Block,
  19871     inst: Zir.Inst.Index,
  19872     comptime air_tag: Air.Inst.Tag,
  19873 ) CompileError!Air.Inst.Ref {
  19874     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  19875     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  19876     const src = inst_data.src();
  19877     const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  19878     const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  19879     const lhs = try sema.resolveInst(extra.lhs);
  19880     const rhs = try sema.resolveInst(extra.rhs);
  19881     try sema.checkNumericType(block, lhs_src, sema.typeOf(lhs));
  19882     try sema.checkNumericType(block, rhs_src, sema.typeOf(rhs));
  19883     return sema.analyzeMinMax(block, src, lhs, rhs, air_tag, lhs_src, rhs_src);
  19884 }
  19885 
  19886 fn analyzeMinMax(
  19887     sema: *Sema,
  19888     block: *Block,
  19889     src: LazySrcLoc,
  19890     lhs: Air.Inst.Ref,
  19891     rhs: Air.Inst.Ref,
  19892     comptime air_tag: Air.Inst.Tag,
  19893     lhs_src: LazySrcLoc,
  19894     rhs_src: LazySrcLoc,
  19895 ) CompileError!Air.Inst.Ref {
  19896     const simd_op = try sema.checkSimdBinOp(block, src, lhs, rhs, lhs_src, rhs_src);
  19897 
  19898     // TODO @maximum(max_int, undefined) should return max_int
  19899 
  19900     const runtime_src = if (simd_op.lhs_val) |lhs_val| rs: {
  19901         if (lhs_val.isUndef()) return sema.addConstUndef(simd_op.result_ty);
  19902 
  19903         const rhs_val = simd_op.rhs_val orelse break :rs rhs_src;
  19904 
  19905         if (rhs_val.isUndef()) return sema.addConstUndef(simd_op.result_ty);
  19906 
  19907         const opFunc = switch (air_tag) {
  19908             .min => Value.numberMin,
  19909             .max => Value.numberMax,
  19910             else => unreachable,
  19911         };
  19912         const target = sema.mod.getTarget();
  19913         const vec_len = simd_op.len orelse {
  19914             const result_val = opFunc(lhs_val, rhs_val, target);
  19915             return sema.addConstant(simd_op.result_ty, result_val);
  19916         };
  19917         var lhs_buf: Value.ElemValueBuffer = undefined;
  19918         var rhs_buf: Value.ElemValueBuffer = undefined;
  19919         const elems = try sema.arena.alloc(Value, vec_len);
  19920         for (elems) |*elem, i| {
  19921             const lhs_elem_val = lhs_val.elemValueBuffer(sema.mod, i, &lhs_buf);
  19922             const rhs_elem_val = rhs_val.elemValueBuffer(sema.mod, i, &rhs_buf);
  19923             elem.* = opFunc(lhs_elem_val, rhs_elem_val, target);
  19924         }
  19925         return sema.addConstant(
  19926             simd_op.result_ty,
  19927             try Value.Tag.aggregate.create(sema.arena, elems),
  19928         );
  19929     } else rs: {
  19930         if (simd_op.rhs_val) |rhs_val| {
  19931             if (rhs_val.isUndef()) return sema.addConstUndef(simd_op.result_ty);
  19932         }
  19933         break :rs lhs_src;
  19934     };
  19935 
  19936     try sema.requireRuntimeBlock(block, src, runtime_src);
  19937     return block.addBinOp(air_tag, simd_op.lhs, simd_op.rhs);
  19938 }
  19939 
  19940 fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
  19941     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  19942     const extra = sema.code.extraData(Zir.Inst.Memcpy, inst_data.payload_index).data;
  19943     const src = inst_data.src();
  19944     const dest_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  19945     const src_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  19946     const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  19947     const uncasted_dest_ptr = try sema.resolveInst(extra.dest);
  19948 
  19949     // TODO AstGen's coerced_ty cannot handle volatile here
  19950     var dest_ptr_info = Type.initTag(.manyptr_u8).ptrInfo().data;
  19951     dest_ptr_info.@"volatile" = sema.typeOf(uncasted_dest_ptr).isVolatilePtr();
  19952     const dest_ptr_ty = try Type.ptr(sema.arena, sema.mod, dest_ptr_info);
  19953     const dest_ptr = try sema.coerce(block, dest_ptr_ty, uncasted_dest_ptr, dest_src);
  19954 
  19955     const uncasted_src_ptr = try sema.resolveInst(extra.source);
  19956     var src_ptr_info = Type.initTag(.manyptr_const_u8).ptrInfo().data;
  19957     src_ptr_info.@"volatile" = sema.typeOf(uncasted_src_ptr).isVolatilePtr();
  19958     const src_ptr_ty = try Type.ptr(sema.arena, sema.mod, src_ptr_info);
  19959     const src_ptr = try sema.coerce(block, src_ptr_ty, uncasted_src_ptr, src_src);
  19960     const len = try sema.coerce(block, Type.usize, try sema.resolveInst(extra.byte_count), len_src);
  19961 
  19962     const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: {
  19963         if (!dest_ptr_val.isComptimeMutablePtr()) break :rs dest_src;
  19964         if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |src_ptr_val| {
  19965             if (!src_ptr_val.isComptimeMutablePtr()) break :rs src_src;
  19966             if (try sema.resolveDefinedValue(block, len_src, len)) |len_val| {
  19967                 _ = len_val;
  19968                 return sema.fail(block, src, "TODO: Sema.zirMemcpy at comptime", .{});
  19969             } else break :rs len_src;
  19970         } else break :rs src_src;
  19971     } else dest_src;
  19972 
  19973     try sema.requireRuntimeBlock(block, src, runtime_src);
  19974     _ = try block.addInst(.{
  19975         .tag = .memcpy,
  19976         .data = .{ .pl_op = .{
  19977             .operand = dest_ptr,
  19978             .payload = try sema.addExtra(Air.Bin{
  19979                 .lhs = src_ptr,
  19980                 .rhs = len,
  19981             }),
  19982         } },
  19983     });
  19984 }
  19985 
  19986 fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
  19987     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  19988     const extra = sema.code.extraData(Zir.Inst.Memset, inst_data.payload_index).data;
  19989     const src = inst_data.src();
  19990     const dest_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  19991     const value_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  19992     const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  19993     const uncasted_dest_ptr = try sema.resolveInst(extra.dest);
  19994 
  19995     // TODO AstGen's coerced_ty cannot handle volatile here
  19996     var ptr_info = Type.initTag(.manyptr_u8).ptrInfo().data;
  19997     ptr_info.@"volatile" = sema.typeOf(uncasted_dest_ptr).isVolatilePtr();
  19998     const dest_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
  19999     const dest_ptr = try sema.coerce(block, dest_ptr_ty, uncasted_dest_ptr, dest_src);
  20000 
  20001     const value = try sema.coerce(block, Type.u8, try sema.resolveInst(extra.byte), value_src);
  20002     const len = try sema.coerce(block, Type.usize, try sema.resolveInst(extra.byte_count), len_src);
  20003 
  20004     const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: {
  20005         if (!ptr_val.isComptimeMutablePtr()) break :rs dest_src;
  20006         if (try sema.resolveDefinedValue(block, len_src, len)) |len_val| {
  20007             if (try sema.resolveMaybeUndefVal(block, value_src, value)) |val| {
  20008                 _ = len_val;
  20009                 _ = val;
  20010                 return sema.fail(block, src, "TODO: Sema.zirMemset at comptime", .{});
  20011             } else break :rs value_src;
  20012         } else break :rs len_src;
  20013     } else dest_src;
  20014 
  20015     try sema.requireRuntimeBlock(block, src, runtime_src);
  20016     _ = try block.addInst(.{
  20017         .tag = .memset,
  20018         .data = .{ .pl_op = .{
  20019             .operand = dest_ptr,
  20020             .payload = try sema.addExtra(Air.Bin{
  20021                 .lhs = value,
  20022                 .rhs = len,
  20023             }),
  20024         } },
  20025     });
  20026 }
  20027 
  20028 fn zirBuiltinAsyncCall(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
  20029     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  20030     const src = LazySrcLoc.nodeOffset(extra.node);
  20031     return sema.failWithUseOfAsync(block, src);
  20032 }
  20033 
  20034 fn zirResume(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20035     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  20036     const src = inst_data.src();
  20037     return sema.failWithUseOfAsync(block, src);
  20038 }
  20039 
  20040 fn zirAwait(
  20041     sema: *Sema,
  20042     block: *Block,
  20043     inst: Zir.Inst.Index,
  20044 ) CompileError!Air.Inst.Ref {
  20045     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  20046     const src = inst_data.src();
  20047 
  20048     return sema.failWithUseOfAsync(block, src);
  20049 }
  20050 
  20051 fn zirAwaitNosuspend(
  20052     sema: *Sema,
  20053     block: *Block,
  20054     extended: Zir.Inst.Extended.InstData,
  20055 ) CompileError!Air.Inst.Ref {
  20056     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  20057     const src = LazySrcLoc.nodeOffset(extra.node);
  20058 
  20059     return sema.failWithUseOfAsync(block, src);
  20060 }
  20061 
  20062 fn zirVarExtended(
  20063     sema: *Sema,
  20064     block: *Block,
  20065     extended: Zir.Inst.Extended.InstData,
  20066 ) CompileError!Air.Inst.Ref {
  20067     const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand);
  20068     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 };
  20069     const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 };
  20070     const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small);
  20071 
  20072     var extra_index: usize = extra.end;
  20073 
  20074     const lib_name: ?[]const u8 = if (small.has_lib_name) blk: {
  20075         const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]);
  20076         extra_index += 1;
  20077         break :blk lib_name;
  20078     } else null;
  20079 
  20080     // ZIR supports encoding this information but it is not used; the information
  20081     // is encoded via the Decl entry.
  20082     assert(!small.has_align);
  20083 
  20084     const uncasted_init: Air.Inst.Ref = if (small.has_init) blk: {
  20085         const init_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  20086         extra_index += 1;
  20087         break :blk try sema.resolveInst(init_ref);
  20088     } else .none;
  20089 
  20090     const have_ty = extra.data.var_type != .none;
  20091     const var_ty = if (have_ty)
  20092         try sema.resolveType(block, ty_src, extra.data.var_type)
  20093     else
  20094         sema.typeOf(uncasted_init);
  20095 
  20096     const init_val = if (uncasted_init != .none) blk: {
  20097         const init = if (have_ty)
  20098             try sema.coerce(block, var_ty, uncasted_init, init_src)
  20099         else
  20100             uncasted_init;
  20101 
  20102         break :blk (try sema.resolveMaybeUndefVal(block, init_src, init)) orelse
  20103             return sema.failWithNeededComptime(block, init_src, "container level variable initializers must be comptime known");
  20104     } else Value.initTag(.unreachable_value);
  20105 
  20106     try sema.validateVarType(block, ty_src, var_ty, small.is_extern);
  20107 
  20108     const new_var = try sema.gpa.create(Module.Var);
  20109     errdefer sema.gpa.destroy(new_var);
  20110 
  20111     log.debug("created variable {*} owner_decl: {*} ({s})", .{
  20112         new_var, sema.owner_decl, sema.owner_decl.name,
  20113     });
  20114 
  20115     new_var.* = .{
  20116         .owner_decl = sema.owner_decl_index,
  20117         .init = init_val,
  20118         .is_extern = small.is_extern,
  20119         .is_mutable = true, // TODO get rid of this unused field
  20120         .is_threadlocal = small.is_threadlocal,
  20121         .is_weak_linkage = false,
  20122         .lib_name = null,
  20123     };
  20124 
  20125     if (lib_name) |lname| {
  20126         new_var.lib_name = try sema.handleExternLibName(block, ty_src, lname);
  20127     }
  20128 
  20129     const result = try sema.addConstant(
  20130         var_ty,
  20131         try Value.Tag.variable.create(sema.arena, new_var),
  20132     );
  20133     return result;
  20134 }
  20135 
  20136 fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20137     const tracy = trace(@src());
  20138     defer tracy.end();
  20139 
  20140     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  20141     const extra = sema.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
  20142     const target = sema.mod.getTarget();
  20143 
  20144     const align_src: LazySrcLoc = .{ .node_offset_fn_type_align = inst_data.src_node };
  20145     const addrspace_src: LazySrcLoc = .{ .node_offset_fn_type_addrspace = inst_data.src_node };
  20146     const section_src: LazySrcLoc = .{ .node_offset_fn_type_section = inst_data.src_node };
  20147     const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node };
  20148     const ret_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = inst_data.src_node };
  20149     const has_body = extra.data.body_len != 0;
  20150 
  20151     var extra_index: usize = extra.end;
  20152 
  20153     const lib_name: ?[]const u8 = if (extra.data.bits.has_lib_name) blk: {
  20154         const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]);
  20155         extra_index += 1;
  20156         break :blk lib_name;
  20157     } else null;
  20158 
  20159     if (has_body and
  20160         (extra.data.bits.has_align_body or extra.data.bits.has_align_ref) and
  20161         !target_util.supportsFunctionAlignment(target))
  20162     {
  20163         return sema.fail(block, align_src, "target does not support function alignment", .{});
  20164     }
  20165 
  20166     const @"align": ?u32 = if (extra.data.bits.has_align_body) blk: {
  20167         const body_len = sema.code.extra[extra_index];
  20168         extra_index += 1;
  20169         const body = sema.code.extra[extra_index..][0..body_len];
  20170         extra_index += body.len;
  20171 
  20172         const val = try sema.resolveGenericBody(block, align_src, body, inst, Type.u29, "alignment must be comptime known");
  20173         if (val.tag() == .generic_poison) {
  20174             break :blk null;
  20175         }
  20176         const alignment = @intCast(u32, val.toUnsignedInt(target));
  20177         try sema.validateAlign(block, align_src, alignment);
  20178         if (alignment == target_util.defaultFunctionAlignment(target)) {
  20179             break :blk 0;
  20180         } else {
  20181             break :blk alignment;
  20182         }
  20183     } else if (extra.data.bits.has_align_ref) blk: {
  20184         const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  20185         extra_index += 1;
  20186         const align_tv = sema.resolveInstConst(block, align_src, align_ref, "alignment must be comptime known") catch |err| switch (err) {
  20187             error.GenericPoison => {
  20188                 break :blk null;
  20189             },
  20190             else => |e| return e,
  20191         };
  20192         const alignment = @intCast(u32, align_tv.val.toUnsignedInt(target));
  20193         try sema.validateAlign(block, align_src, alignment);
  20194         if (alignment == target_util.defaultFunctionAlignment(target)) {
  20195             break :blk 0;
  20196         } else {
  20197             break :blk alignment;
  20198         }
  20199     } else 0;
  20200 
  20201     const @"addrspace": ?std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: {
  20202         const body_len = sema.code.extra[extra_index];
  20203         extra_index += 1;
  20204         const body = sema.code.extra[extra_index..][0..body_len];
  20205         extra_index += body.len;
  20206 
  20207         const addrspace_ty = try sema.getBuiltinType(block, addrspace_src, "AddressSpace");
  20208         const val = try sema.resolveGenericBody(block, addrspace_src, body, inst, addrspace_ty, "addrespace must be comptime known");
  20209         if (val.tag() == .generic_poison) {
  20210             break :blk null;
  20211         }
  20212         break :blk val.toEnum(std.builtin.AddressSpace);
  20213     } else if (extra.data.bits.has_addrspace_ref) blk: {
  20214         const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  20215         extra_index += 1;
  20216         const addrspace_tv = sema.resolveInstConst(block, addrspace_src, addrspace_ref, "addrespace must be comptime known") catch |err| switch (err) {
  20217             error.GenericPoison => {
  20218                 break :blk null;
  20219             },
  20220             else => |e| return e,
  20221         };
  20222         break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace);
  20223     } else target_util.defaultAddressSpace(target, .function);
  20224 
  20225     const @"linksection": FuncLinkSection = if (extra.data.bits.has_section_body) blk: {
  20226         const body_len = sema.code.extra[extra_index];
  20227         extra_index += 1;
  20228         const body = sema.code.extra[extra_index..][0..body_len];
  20229         extra_index += body.len;
  20230 
  20231         const val = try sema.resolveGenericBody(block, section_src, body, inst, Type.initTag(.const_slice_u8), "linksection must be comptime known");
  20232         if (val.tag() == .generic_poison) {
  20233             break :blk FuncLinkSection{ .generic = {} };
  20234         }
  20235         return sema.fail(block, section_src, "TODO implement linksection on functions", .{});
  20236     } else if (extra.data.bits.has_section_ref) blk: {
  20237         const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  20238         extra_index += 1;
  20239         const section_tv = sema.resolveInstConst(block, section_src, section_ref, "linksection must be comptime known") catch |err| switch (err) {
  20240             error.GenericPoison => {
  20241                 break :blk FuncLinkSection{ .generic = {} };
  20242             },
  20243             else => |e| return e,
  20244         };
  20245         _ = section_tv;
  20246         return sema.fail(block, section_src, "TODO implement linksection on functions", .{});
  20247     } else FuncLinkSection{ .default = {} };
  20248 
  20249     const cc: ?std.builtin.CallingConvention = if (extra.data.bits.has_cc_body) blk: {
  20250         const body_len = sema.code.extra[extra_index];
  20251         extra_index += 1;
  20252         const body = sema.code.extra[extra_index..][0..body_len];
  20253         extra_index += body.len;
  20254 
  20255         const cc_ty = try sema.getBuiltinType(block, addrspace_src, "CallingConvention");
  20256         const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty, "calling convention must be comptime known");
  20257         if (val.tag() == .generic_poison) {
  20258             break :blk null;
  20259         }
  20260         break :blk val.toEnum(std.builtin.CallingConvention);
  20261     } else if (extra.data.bits.has_cc_ref) blk: {
  20262         const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  20263         extra_index += 1;
  20264         const cc_tv = sema.resolveInstConst(block, cc_src, cc_ref, "calling convention must be comptime known") catch |err| switch (err) {
  20265             error.GenericPoison => {
  20266                 break :blk null;
  20267             },
  20268             else => |e| return e,
  20269         };
  20270         break :blk cc_tv.val.toEnum(std.builtin.CallingConvention);
  20271     } else std.builtin.CallingConvention.Unspecified;
  20272 
  20273     const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: {
  20274         const body_len = sema.code.extra[extra_index];
  20275         extra_index += 1;
  20276         const body = sema.code.extra[extra_index..][0..body_len];
  20277         extra_index += body.len;
  20278 
  20279         const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type, "return type must be comptime known");
  20280         var buffer: Value.ToTypeBuffer = undefined;
  20281         const ty = try val.toType(&buffer).copy(sema.arena);
  20282         break :blk ty;
  20283     } else if (extra.data.bits.has_ret_ty_ref) blk: {
  20284         const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  20285         extra_index += 1;
  20286         const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref, "return type must be comptime known") catch |err| switch (err) {
  20287             error.GenericPoison => {
  20288                 break :blk Type.initTag(.generic_poison);
  20289             },
  20290             else => |e| return e,
  20291         };
  20292         var buffer: Value.ToTypeBuffer = undefined;
  20293         const ty = try ret_ty_tv.val.toType(&buffer).copy(sema.arena);
  20294         break :blk ty;
  20295     } else Type.void;
  20296 
  20297     const noalias_bits: u32 = if (extra.data.bits.has_any_noalias) blk: {
  20298         const x = sema.code.extra[extra_index];
  20299         extra_index += 1;
  20300         break :blk x;
  20301     } else 0;
  20302 
  20303     var src_locs: Zir.Inst.Func.SrcLocs = undefined;
  20304     if (has_body) {
  20305         extra_index += extra.data.body_len;
  20306         src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
  20307     }
  20308 
  20309     const is_var_args = extra.data.bits.is_var_args;
  20310     const is_inferred_error = extra.data.bits.is_inferred_error;
  20311     const is_extern = extra.data.bits.is_extern;
  20312     const is_noinline = extra.data.bits.is_noinline;
  20313 
  20314     return sema.funcCommon(
  20315         block,
  20316         inst_data.src_node,
  20317         inst,
  20318         @"align",
  20319         @"addrspace",
  20320         @"linksection",
  20321         cc,
  20322         ret_ty,
  20323         is_var_args,
  20324         is_inferred_error,
  20325         is_extern,
  20326         has_body,
  20327         src_locs,
  20328         lib_name,
  20329         noalias_bits,
  20330         is_noinline,
  20331     );
  20332 }
  20333 
  20334 fn zirCUndef(
  20335     sema: *Sema,
  20336     block: *Block,
  20337     extended: Zir.Inst.Extended.InstData,
  20338 ) CompileError!Air.Inst.Ref {
  20339     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  20340     const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  20341 
  20342     const name = try sema.resolveConstString(block, src, extra.operand, "name of macro being undefined must be comptime known");
  20343     try block.c_import_buf.?.writer().print("#undefine {s}\n", .{name});
  20344     return Air.Inst.Ref.void_value;
  20345 }
  20346 
  20347 fn zirCInclude(
  20348     sema: *Sema,
  20349     block: *Block,
  20350     extended: Zir.Inst.Extended.InstData,
  20351 ) CompileError!Air.Inst.Ref {
  20352     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  20353     const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  20354 
  20355     const name = try sema.resolveConstString(block, src, extra.operand, "path being included must be comptime known");
  20356     try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name});
  20357     return Air.Inst.Ref.void_value;
  20358 }
  20359 
  20360 fn zirCDefine(
  20361     sema: *Sema,
  20362     block: *Block,
  20363     extended: Zir.Inst.Extended.InstData,
  20364 ) CompileError!Air.Inst.Ref {
  20365     const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
  20366     const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  20367     const val_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  20368 
  20369     const name = try sema.resolveConstString(block, name_src, extra.lhs, "name of macro being undefined must be comptime known");
  20370     const rhs = try sema.resolveInst(extra.rhs);
  20371     if (sema.typeOf(rhs).zigTypeTag() != .Void) {
  20372         const value = try sema.resolveConstString(block, val_src, extra.rhs, "value of macro being undefined must be comptime known");
  20373         try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value });
  20374     } else {
  20375         try block.c_import_buf.?.writer().print("#define {s}\n", .{name});
  20376     }
  20377     return Air.Inst.Ref.void_value;
  20378 }
  20379 
  20380 fn zirWasmMemorySize(
  20381     sema: *Sema,
  20382     block: *Block,
  20383     extended: Zir.Inst.Extended.InstData,
  20384 ) CompileError!Air.Inst.Ref {
  20385     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  20386     const index_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  20387     const builtin_src = LazySrcLoc.nodeOffset(extra.node);
  20388     const target = sema.mod.getTarget();
  20389     if (!target.isWasm()) {
  20390         return sema.fail(block, builtin_src, "builtin @wasmMemorySize is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)});
  20391     }
  20392 
  20393     const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.operand, Type.u32, "wasm memory size index must be comptime known"));
  20394     try sema.requireRuntimeBlock(block, builtin_src, null);
  20395     return block.addInst(.{
  20396         .tag = .wasm_memory_size,
  20397         .data = .{ .pl_op = .{
  20398             .operand = .none,
  20399             .payload = index,
  20400         } },
  20401     });
  20402 }
  20403 
  20404 fn zirWasmMemoryGrow(
  20405     sema: *Sema,
  20406     block: *Block,
  20407     extended: Zir.Inst.Extended.InstData,
  20408 ) CompileError!Air.Inst.Ref {
  20409     const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
  20410     const builtin_src = LazySrcLoc.nodeOffset(extra.node);
  20411     const index_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  20412     const delta_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  20413     const target = sema.mod.getTarget();
  20414     if (!target.isWasm()) {
  20415         return sema.fail(block, builtin_src, "builtin @wasmMemoryGrow is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)});
  20416     }
  20417 
  20418     const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.lhs, Type.u32, "wasm memory size index must be comptime known"));
  20419     const delta = try sema.coerce(block, Type.u32, try sema.resolveInst(extra.rhs), delta_src);
  20420 
  20421     try sema.requireRuntimeBlock(block, builtin_src, null);
  20422     return block.addInst(.{
  20423         .tag = .wasm_memory_grow,
  20424         .data = .{ .pl_op = .{
  20425             .operand = delta,
  20426             .payload = index,
  20427         } },
  20428     });
  20429 }
  20430 
  20431 fn resolvePrefetchOptions(
  20432     sema: *Sema,
  20433     block: *Block,
  20434     src: LazySrcLoc,
  20435     zir_ref: Zir.Inst.Ref,
  20436 ) CompileError!std.builtin.PrefetchOptions {
  20437     const options_ty = try sema.getBuiltinType(block, src, "PrefetchOptions");
  20438     const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src);
  20439     const target = sema.mod.getTarget();
  20440 
  20441     const rw_src = sema.maybeOptionsSrc(block, src, "rw");
  20442     const locality_src = sema.maybeOptionsSrc(block, src, "locality");
  20443     const cache_src = sema.maybeOptionsSrc(block, src, "cache");
  20444 
  20445     const rw = try sema.fieldVal(block, src, options, "rw", rw_src);
  20446     const rw_val = try sema.resolveConstValue(block, rw_src, rw, "prefetch read/write must be comptime known");
  20447 
  20448     const locality = try sema.fieldVal(block, src, options, "locality", locality_src);
  20449     const locality_val = try sema.resolveConstValue(block, locality_src, locality, "prefetch locality must be comptime known");
  20450 
  20451     const cache = try sema.fieldVal(block, src, options, "cache", cache_src);
  20452     const cache_val = try sema.resolveConstValue(block, cache_src, cache, "prefetch cache must be comptime known");
  20453 
  20454     return std.builtin.PrefetchOptions{
  20455         .rw = rw_val.toEnum(std.builtin.PrefetchOptions.Rw),
  20456         .locality = @intCast(u2, locality_val.toUnsignedInt(target)),
  20457         .cache = cache_val.toEnum(std.builtin.PrefetchOptions.Cache),
  20458     };
  20459 }
  20460 
  20461 fn zirPrefetch(
  20462     sema: *Sema,
  20463     block: *Block,
  20464     extended: Zir.Inst.Extended.InstData,
  20465 ) CompileError!Air.Inst.Ref {
  20466     const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
  20467     const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  20468     const opts_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  20469     const ptr = try sema.resolveInst(extra.lhs);
  20470     try sema.checkPtrOperand(block, ptr_src, sema.typeOf(ptr));
  20471 
  20472     const options = sema.resolvePrefetchOptions(block, .unneeded, extra.rhs) catch |err| switch (err) {
  20473         error.NeededSourceLocation => {
  20474             _ = try sema.resolvePrefetchOptions(block, opts_src, extra.rhs);
  20475             return error.AnalysisFail;
  20476         },
  20477         else => |e| return e,
  20478     };
  20479 
  20480     if (!block.is_comptime) {
  20481         _ = try block.addInst(.{
  20482             .tag = .prefetch,
  20483             .data = .{ .prefetch = .{
  20484                 .ptr = ptr,
  20485                 .rw = options.rw,
  20486                 .locality = options.locality,
  20487                 .cache = options.cache,
  20488             } },
  20489         });
  20490     }
  20491 
  20492     return Air.Inst.Ref.void_value;
  20493 }
  20494 
  20495 fn resolveExternOptions(
  20496     sema: *Sema,
  20497     block: *Block,
  20498     src: LazySrcLoc,
  20499     zir_ref: Zir.Inst.Ref,
  20500 ) CompileError!std.builtin.ExternOptions {
  20501     const options_inst = try sema.resolveInst(zir_ref);
  20502     const extern_options_ty = try sema.getBuiltinType(block, src, "ExternOptions");
  20503     const options = try sema.coerce(block, extern_options_ty, options_inst, src);
  20504     const mod = sema.mod;
  20505 
  20506     const name_src = sema.maybeOptionsSrc(block, src, "name");
  20507     const library_src = sema.maybeOptionsSrc(block, src, "library");
  20508     const linkage_src = sema.maybeOptionsSrc(block, src, "linkage");
  20509     const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local");
  20510 
  20511     const name_ref = try sema.fieldVal(block, src, options, "name", name_src);
  20512     const name_val = try sema.resolveConstValue(block, name_src, name_ref, "name of the extern symbol must be comptime known");
  20513     const name = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, mod);
  20514 
  20515     const library_name_inst = try sema.fieldVal(block, src, options, "library_name", library_src);
  20516     const library_name_val = try sema.resolveConstValue(block, library_src, library_name_inst, "library in which extern symbol is must be comptime known");
  20517 
  20518     const linkage_ref = try sema.fieldVal(block, src, options, "linkage", linkage_src);
  20519     const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_ref, "linkage of the extern symbol must be comptime known");
  20520     const linkage = linkage_val.toEnum(std.builtin.GlobalLinkage);
  20521 
  20522     const is_thread_local = try sema.fieldVal(block, src, options, "is_thread_local", thread_local_src);
  20523     const is_thread_local_val = try sema.resolveConstValue(block, thread_local_src, is_thread_local, "threadlocality of the extern symbol must be comptime known");
  20524 
  20525     const library_name = if (!library_name_val.isNull()) blk: {
  20526         const payload = library_name_val.castTag(.opt_payload).?.data;
  20527         const library_name = try payload.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, mod);
  20528         if (library_name.len == 0) {
  20529             return sema.fail(block, library_src, "library name name cannot be empty", .{});
  20530         }
  20531         break :blk try sema.handleExternLibName(block, library_src, library_name);
  20532     } else null;
  20533 
  20534     if (name.len == 0) {
  20535         return sema.fail(block, name_src, "extern symbol name cannot be empty", .{});
  20536     }
  20537 
  20538     if (linkage != .Weak and linkage != .Strong) {
  20539         return sema.fail(block, linkage_src, "extern symbol must use strong or weak linkage", .{});
  20540     }
  20541 
  20542     return std.builtin.ExternOptions{
  20543         .name = name,
  20544         .library_name = library_name,
  20545         .linkage = linkage,
  20546         .is_thread_local = is_thread_local_val.toBool(),
  20547     };
  20548 }
  20549 
  20550 fn zirBuiltinExtern(
  20551     sema: *Sema,
  20552     block: *Block,
  20553     extended: Zir.Inst.Extended.InstData,
  20554 ) CompileError!Air.Inst.Ref {
  20555     const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
  20556     const src = LazySrcLoc.nodeOffset(extra.node);
  20557     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  20558     const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  20559 
  20560     var ty = try sema.resolveType(block, ty_src, extra.lhs);
  20561     if (!ty.isPtrAtRuntime()) {
  20562         return sema.fail(block, ty_src, "expected (optional) pointer", .{});
  20563     }
  20564 
  20565     const options = sema.resolveExternOptions(block, .unneeded, extra.rhs) catch |err| switch (err) {
  20566         error.NeededSourceLocation => {
  20567             _ = try sema.resolveExternOptions(block, options_src, extra.rhs);
  20568             return error.AnalysisFail;
  20569         },
  20570         else => |e| return e,
  20571     };
  20572 
  20573     if (options.linkage == .Weak and !ty.ptrAllowsZero()) {
  20574         ty = try Type.optional(sema.arena, ty);
  20575     }
  20576 
  20577     // TODO check duplicate extern
  20578 
  20579     const new_decl_index = try sema.mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, null);
  20580     errdefer sema.mod.destroyDecl(new_decl_index);
  20581     const new_decl = sema.mod.declPtr(new_decl_index);
  20582     new_decl.name = try sema.gpa.dupeZ(u8, options.name);
  20583 
  20584     var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
  20585     errdefer new_decl_arena.deinit();
  20586     const new_decl_arena_allocator = new_decl_arena.allocator();
  20587 
  20588     const new_var = try new_decl_arena_allocator.create(Module.Var);
  20589     errdefer new_decl_arena_allocator.destroy(new_var);
  20590 
  20591     new_var.* = .{
  20592         .owner_decl = sema.owner_decl_index,
  20593         .init = Value.initTag(.unreachable_value),
  20594         .is_extern = true,
  20595         .is_mutable = false, // TODO get rid of this unused field
  20596         .is_threadlocal = options.is_thread_local,
  20597         .is_weak_linkage = options.linkage == .Weak,
  20598         .lib_name = null,
  20599     };
  20600 
  20601     new_decl.src_line = sema.owner_decl.src_line;
  20602     new_decl.ty = try ty.copy(new_decl_arena_allocator);
  20603     new_decl.val = try Value.Tag.variable.create(new_decl_arena_allocator, new_var);
  20604     new_decl.@"align" = 0;
  20605     new_decl.@"linksection" = null;
  20606     new_decl.has_tv = true;
  20607     new_decl.analysis = .complete;
  20608     new_decl.generation = sema.mod.generation;
  20609 
  20610     const arena_state = try new_decl_arena_allocator.create(std.heap.ArenaAllocator.State);
  20611     arena_state.* = new_decl_arena.state;
  20612     new_decl.value_arena = arena_state;
  20613 
  20614     const ref = try sema.analyzeDeclRef(new_decl_index);
  20615     try sema.requireRuntimeBlock(block, src, null);
  20616     return block.addBitCast(ty, ref);
  20617 }
  20618 
  20619 /// Asserts that the block is not comptime.
  20620 fn requireFunctionBlock(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
  20621     assert(!block.is_comptime);
  20622     if (sema.func == null and !block.is_typeof and !block.is_coerce_result_ptr) {
  20623         return sema.fail(block, src, "instruction illegal outside function body", .{});
  20624     }
  20625 }
  20626 
  20627 fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: ?LazySrcLoc) !void {
  20628     if (block.is_comptime) {
  20629         const msg = msg: {
  20630             const msg = try sema.errMsg(block, src, "unable to evaluate comptime expression", .{});
  20631             errdefer msg.destroy(sema.gpa);
  20632 
  20633             if (runtime_src) |some| {
  20634                 try sema.errNote(block, some, msg, "operation is runtime due to this operand", .{});
  20635             }
  20636             break :msg msg;
  20637         };
  20638         return sema.failWithOwnedErrorMsg(msg);
  20639     }
  20640     try sema.requireFunctionBlock(block, src);
  20641 }
  20642 
  20643 /// Emit a compile error if type cannot be used for a runtime variable.
  20644 fn validateVarType(
  20645     sema: *Sema,
  20646     block: *Block,
  20647     src: LazySrcLoc,
  20648     var_ty: Type,
  20649     is_extern: bool,
  20650 ) CompileError!void {
  20651     if (try sema.validateRunTimeType(block, src, var_ty, is_extern)) return;
  20652 
  20653     const mod = sema.mod;
  20654 
  20655     const msg = msg: {
  20656         const msg = try sema.errMsg(block, src, "variable of type '{}' must be const or comptime", .{var_ty.fmt(mod)});
  20657         errdefer msg.destroy(sema.gpa);
  20658 
  20659         const src_decl = mod.declPtr(block.src_decl);
  20660         try sema.explainWhyTypeIsComptime(block, src, msg, src.toSrcLoc(src_decl), var_ty);
  20661         if (var_ty.zigTypeTag() == .ComptimeInt or var_ty.zigTypeTag() == .ComptimeFloat) {
  20662             try sema.errNote(block, src, msg, "to modify this variable at runtime, it must be given an explicit fixed-size number type", .{});
  20663         }
  20664 
  20665         break :msg msg;
  20666     };
  20667     return sema.failWithOwnedErrorMsg(msg);
  20668 }
  20669 
  20670 fn validateRunTimeType(
  20671     sema: *Sema,
  20672     block: *Block,
  20673     src: LazySrcLoc,
  20674     var_ty: Type,
  20675     is_extern: bool,
  20676 ) CompileError!bool {
  20677     var ty = var_ty;
  20678     while (true) switch (ty.zigTypeTag()) {
  20679         .Bool,
  20680         .Int,
  20681         .Float,
  20682         .ErrorSet,
  20683         .Frame,
  20684         .AnyFrame,
  20685         .Void,
  20686         => return true,
  20687 
  20688         .Enum => return !(try sema.typeRequiresComptime(ty)),
  20689 
  20690         .BoundFn,
  20691         .ComptimeFloat,
  20692         .ComptimeInt,
  20693         .EnumLiteral,
  20694         .NoReturn,
  20695         .Type,
  20696         .Undefined,
  20697         .Null,
  20698         .Fn,
  20699         => return false,
  20700 
  20701         .Pointer => {
  20702             const elem_ty = ty.childType();
  20703             switch (elem_ty.zigTypeTag()) {
  20704                 .Opaque => return true,
  20705                 .Fn => return elem_ty.isFnOrHasRuntimeBits(),
  20706                 else => ty = elem_ty,
  20707             }
  20708         },
  20709         .Opaque => return is_extern,
  20710 
  20711         .Optional => {
  20712             var buf: Type.Payload.ElemType = undefined;
  20713             const child_ty = ty.optionalChild(&buf);
  20714             return validateRunTimeType(sema, block, src, child_ty, is_extern);
  20715         },
  20716         .Array, .Vector => ty = ty.elemType(),
  20717 
  20718         .ErrorUnion => ty = ty.errorUnionPayload(),
  20719 
  20720         .Struct, .Union => {
  20721             const resolved_ty = try sema.resolveTypeFields(block, src, ty);
  20722             const needs_comptime = try sema.typeRequiresComptime(resolved_ty);
  20723             return !needs_comptime;
  20724         },
  20725     };
  20726 }
  20727 
  20728 const TypeSet = std.HashMapUnmanaged(Type, void, Type.HashContext64, std.hash_map.default_max_load_percentage);
  20729 
  20730 fn explainWhyTypeIsComptime(
  20731     sema: *Sema,
  20732     block: *Block,
  20733     src: LazySrcLoc,
  20734     msg: *Module.ErrorMsg,
  20735     src_loc: Module.SrcLoc,
  20736     ty: Type,
  20737 ) CompileError!void {
  20738     var type_set = TypeSet{};
  20739     defer type_set.deinit(sema.gpa);
  20740 
  20741     try sema.resolveTypeFully(block, src, ty);
  20742     return sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty, &type_set);
  20743 }
  20744 
  20745 fn explainWhyTypeIsComptimeInner(
  20746     sema: *Sema,
  20747     block: *Block,
  20748     src: LazySrcLoc,
  20749     msg: *Module.ErrorMsg,
  20750     src_loc: Module.SrcLoc,
  20751     ty: Type,
  20752     type_set: *TypeSet,
  20753 ) CompileError!void {
  20754     const mod = sema.mod;
  20755     switch (ty.zigTypeTag()) {
  20756         .Bool,
  20757         .Int,
  20758         .Float,
  20759         .ErrorSet,
  20760         .Enum,
  20761         .Frame,
  20762         .AnyFrame,
  20763         .Void,
  20764         => return,
  20765 
  20766         .Fn => {
  20767             try mod.errNoteNonLazy(src_loc, msg, "use '*const {}' for a function pointer type", .{
  20768                 ty.fmt(sema.mod),
  20769             });
  20770         },
  20771 
  20772         .Type => {
  20773             try mod.errNoteNonLazy(src_loc, msg, "types are not available at runtime", .{});
  20774         },
  20775 
  20776         .BoundFn,
  20777         .ComptimeFloat,
  20778         .ComptimeInt,
  20779         .EnumLiteral,
  20780         .NoReturn,
  20781         .Undefined,
  20782         .Null,
  20783         => return,
  20784 
  20785         .Opaque => {
  20786             try mod.errNoteNonLazy(src_loc, msg, "opaque type '{}' has undefined size", .{ty.fmt(sema.mod)});
  20787         },
  20788 
  20789         .Array, .Vector => {
  20790             try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.elemType(), type_set);
  20791         },
  20792         .Pointer => {
  20793             const elem_ty = ty.elemType2();
  20794             if (elem_ty.zigTypeTag() == .Fn) {
  20795                 const fn_info = elem_ty.fnInfo();
  20796                 if (fn_info.is_generic) {
  20797                     try mod.errNoteNonLazy(src_loc, msg, "function is generic", .{});
  20798                 }
  20799                 switch (fn_info.cc) {
  20800                     .Inline => try mod.errNoteNonLazy(src_loc, msg, "function has inline calling convention", .{}),
  20801                     else => {},
  20802                 }
  20803                 if (fn_info.return_type.comptimeOnly()) {
  20804                     try mod.errNoteNonLazy(src_loc, msg, "function has a comptime-only return type", .{});
  20805                 }
  20806                 return;
  20807             }
  20808             try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.elemType(), type_set);
  20809         },
  20810 
  20811         .Optional => {
  20812             var buf: Type.Payload.ElemType = undefined;
  20813             try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.optionalChild(&buf), type_set);
  20814         },
  20815         .ErrorUnion => {
  20816             try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.errorUnionPayload(), type_set);
  20817         },
  20818 
  20819         .Struct => {
  20820             if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return;
  20821 
  20822             if (ty.castTag(.@"struct")) |payload| {
  20823                 const struct_obj = payload.data;
  20824                 for (struct_obj.fields.values()) |field, i| {
  20825                     const field_src_loc = struct_obj.fieldSrcLoc(sema.mod, .{
  20826                         .index = i,
  20827                         .range = .type,
  20828                     });
  20829 
  20830                     if (try sema.typeRequiresComptime(field.ty)) {
  20831                         try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{});
  20832                         try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set);
  20833                     }
  20834                 }
  20835             }
  20836             // TODO tuples
  20837         },
  20838 
  20839         .Union => {
  20840             if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return;
  20841 
  20842             if (ty.cast(Type.Payload.Union)) |payload| {
  20843                 const union_obj = payload.data;
  20844                 for (union_obj.fields.values()) |field, i| {
  20845                     const field_src_loc = union_obj.fieldSrcLoc(sema.mod, .{
  20846                         .index = i,
  20847                         .range = .type,
  20848                     });
  20849 
  20850                     if (try sema.typeRequiresComptime(field.ty)) {
  20851                         try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{});
  20852                         try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set);
  20853                     }
  20854                 }
  20855             }
  20856         },
  20857     }
  20858 }
  20859 
  20860 const ExternPosition = enum {
  20861     ret_ty,
  20862     param_ty,
  20863     union_field,
  20864     other,
  20865 };
  20866 
  20867 /// Returns true if `ty` is allowed in extern types.
  20868 /// Does *NOT* require `ty` to be resolved in any way.
  20869 /// Calls `resolveTypeLayout` for packed containers.
  20870 fn validateExternType(
  20871     sema: *Sema,
  20872     block: *Block,
  20873     src: LazySrcLoc,
  20874     ty: Type,
  20875     position: ExternPosition,
  20876 ) !bool {
  20877     switch (ty.zigTypeTag()) {
  20878         .Type,
  20879         .ComptimeFloat,
  20880         .ComptimeInt,
  20881         .EnumLiteral,
  20882         .Undefined,
  20883         .Null,
  20884         .ErrorUnion,
  20885         .ErrorSet,
  20886         .BoundFn,
  20887         .Frame,
  20888         => return false,
  20889         .Void => return position == .union_field or position == .ret_ty,
  20890         .NoReturn => return position == .ret_ty,
  20891         .Opaque,
  20892         .Bool,
  20893         .Float,
  20894         .AnyFrame,
  20895         => return true,
  20896         .Pointer => return !ty.isSlice(),
  20897         .Int => switch (ty.intInfo(sema.mod.getTarget()).bits) {
  20898             8, 16, 32, 64, 128 => return true,
  20899             else => return false,
  20900         },
  20901         .Fn => return !Type.fnCallingConventionAllowsZigTypes(ty.fnCallingConvention()),
  20902         .Enum => {
  20903             var buf: Type.Payload.Bits = undefined;
  20904             return sema.validateExternType(block, src, ty.intTagType(&buf), position);
  20905         },
  20906         .Struct, .Union => switch (ty.containerLayout()) {
  20907             .Extern => return true,
  20908             .Packed => {
  20909                 const target = sema.mod.getTarget();
  20910                 const bit_size = try ty.bitSizeAdvanced(target, sema.kit(block, src));
  20911                 switch (bit_size) {
  20912                     8, 16, 32, 64, 128 => return true,
  20913                     else => return false,
  20914                 }
  20915             },
  20916             .Auto => return false,
  20917         },
  20918         .Array => {
  20919             if (position == .ret_ty or position == .param_ty) return false;
  20920             return sema.validateExternType(block, src, ty.elemType2(), .other);
  20921         },
  20922         .Vector => return sema.validateExternType(block, src, ty.elemType2(), .other),
  20923         .Optional => return ty.isPtrLikeOptional(),
  20924     }
  20925 }
  20926 
  20927 fn explainWhyTypeIsNotExtern(
  20928     sema: *Sema,
  20929     msg: *Module.ErrorMsg,
  20930     src_loc: Module.SrcLoc,
  20931     ty: Type,
  20932     position: ExternPosition,
  20933 ) CompileError!void {
  20934     const mod = sema.mod;
  20935     switch (ty.zigTypeTag()) {
  20936         .Opaque,
  20937         .Bool,
  20938         .Float,
  20939         .AnyFrame,
  20940         => return,
  20941 
  20942         .Type,
  20943         .ComptimeFloat,
  20944         .ComptimeInt,
  20945         .EnumLiteral,
  20946         .Undefined,
  20947         .Null,
  20948         .ErrorUnion,
  20949         .ErrorSet,
  20950         .BoundFn,
  20951         .Frame,
  20952         => return,
  20953 
  20954         .Pointer => try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{}),
  20955         .Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}),
  20956         .NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
  20957         .Int => if (ty.intInfo(sema.mod.getTarget()).bits > 128) {
  20958             try mod.errNoteNonLazy(src_loc, msg, "only integers with less than 128 bits are extern compatible", .{});
  20959         } else {
  20960             try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{});
  20961         },
  20962         .Fn => switch (ty.fnCallingConvention()) {
  20963             .Unspecified => try mod.errNoteNonLazy(src_loc, msg, "extern function must specify calling convention", .{}),
  20964             .Async => try mod.errNoteNonLazy(src_loc, msg, "async function cannot be extern", .{}),
  20965             .Inline => try mod.errNoteNonLazy(src_loc, msg, "inline function cannot be extern", .{}),
  20966             else => return,
  20967         },
  20968         .Enum => {
  20969             var buf: Type.Payload.Bits = undefined;
  20970             const tag_ty = ty.intTagType(&buf);
  20971             try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)});
  20972             try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position);
  20973         },
  20974         .Struct => try mod.errNoteNonLazy(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}),
  20975         .Union => try mod.errNoteNonLazy(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}),
  20976         .Array => {
  20977             if (position == .ret_ty) {
  20978                 return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a return type", .{});
  20979             } else if (position == .param_ty) {
  20980                 return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a parameter type", .{});
  20981             }
  20982             try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(), position);
  20983         },
  20984         .Vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(), position),
  20985         .Optional => try mod.errNoteNonLazy(src_loc, msg, "only pointer like optionals are extern compatible", .{}),
  20986     }
  20987 }
  20988 
  20989 /// Returns true if `ty` is allowed in packed types.
  20990 /// Does *NOT* require `ty` to be resolved in any way.
  20991 fn validatePackedType(ty: Type) bool {
  20992     switch (ty.zigTypeTag()) {
  20993         .Type,
  20994         .ComptimeFloat,
  20995         .ComptimeInt,
  20996         .EnumLiteral,
  20997         .Undefined,
  20998         .Null,
  20999         .ErrorUnion,
  21000         .ErrorSet,
  21001         .BoundFn,
  21002         .Frame,
  21003         .NoReturn,
  21004         .Opaque,
  21005         .AnyFrame,
  21006         .Fn,
  21007         .Array,
  21008         => return false,
  21009         .Optional => return ty.isPtrLikeOptional(),
  21010         .Void,
  21011         .Bool,
  21012         .Float,
  21013         .Int,
  21014         .Vector,
  21015         .Enum,
  21016         => return true,
  21017         .Pointer => return !ty.isSlice(),
  21018         .Struct, .Union => return ty.containerLayout() == .Packed,
  21019     }
  21020 }
  21021 
  21022 fn explainWhyTypeIsNotPacked(
  21023     sema: *Sema,
  21024     msg: *Module.ErrorMsg,
  21025     src_loc: Module.SrcLoc,
  21026     ty: Type,
  21027 ) CompileError!void {
  21028     const mod = sema.mod;
  21029     switch (ty.zigTypeTag()) {
  21030         .Void,
  21031         .Bool,
  21032         .Float,
  21033         .Int,
  21034         .Vector,
  21035         .Enum,
  21036         => return,
  21037         .Type,
  21038         .ComptimeFloat,
  21039         .ComptimeInt,
  21040         .EnumLiteral,
  21041         .Undefined,
  21042         .Null,
  21043         .BoundFn,
  21044         .Frame,
  21045         .NoReturn,
  21046         .Opaque,
  21047         .ErrorUnion,
  21048         .ErrorSet,
  21049         .AnyFrame,
  21050         .Optional,
  21051         .Array,
  21052         => try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{}),
  21053         .Pointer => try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{}),
  21054         .Fn => {
  21055             try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{});
  21056             try mod.errNoteNonLazy(src_loc, msg, "use '*const ' to make a function pointer type", .{});
  21057         },
  21058         .Struct => try mod.errNoteNonLazy(src_loc, msg, "only packed structs layout are allowed in packed types", .{}),
  21059         .Union => try mod.errNoteNonLazy(src_loc, msg, "only packed unions layout are allowed in packed types", .{}),
  21060     }
  21061 }
  21062 
  21063 pub const PanicId = enum {
  21064     unreach,
  21065     unwrap_null,
  21066     cast_to_null,
  21067     incorrect_alignment,
  21068     invalid_error_code,
  21069     cast_truncated_data,
  21070     negative_to_unsigned,
  21071     integer_overflow,
  21072     shl_overflow,
  21073     shr_overflow,
  21074     divide_by_zero,
  21075     exact_division_remainder,
  21076     /// TODO make this call `std.builtin.panicInactiveUnionField`.
  21077     inactive_union_field,
  21078     integer_part_out_of_bounds,
  21079     corrupt_switch,
  21080     shift_rhs_too_big,
  21081     invalid_enum_value,
  21082 };
  21083 
  21084 fn addSafetyCheck(
  21085     sema: *Sema,
  21086     parent_block: *Block,
  21087     ok: Air.Inst.Ref,
  21088     panic_id: PanicId,
  21089 ) !void {
  21090     const gpa = sema.gpa;
  21091 
  21092     var fail_block: Block = .{
  21093         .parent = parent_block,
  21094         .sema = sema,
  21095         .src_decl = parent_block.src_decl,
  21096         .namespace = parent_block.namespace,
  21097         .wip_capture_scope = parent_block.wip_capture_scope,
  21098         .instructions = .{},
  21099         .inlining = parent_block.inlining,
  21100         .is_comptime = parent_block.is_comptime,
  21101     };
  21102 
  21103     defer fail_block.instructions.deinit(gpa);
  21104 
  21105     // This function doesn't actually need a src location but if
  21106     // the panic function interface ever changes passing `.unneeded` here
  21107     // will cause confusing panics.
  21108     const src = sema.src;
  21109     _ = try sema.safetyPanic(&fail_block, src, panic_id);
  21110 
  21111     try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
  21112 }
  21113 
  21114 fn addSafetyCheckExtra(
  21115     sema: *Sema,
  21116     parent_block: *Block,
  21117     ok: Air.Inst.Ref,
  21118     fail_block: *Block,
  21119 ) !void {
  21120     const gpa = sema.gpa;
  21121 
  21122     try parent_block.instructions.ensureUnusedCapacity(gpa, 1);
  21123 
  21124     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
  21125         1 + // The main block only needs space for the cond_br.
  21126         @typeInfo(Air.CondBr).Struct.fields.len +
  21127         1 + // The ok branch of the cond_br only needs space for the br.
  21128         fail_block.instructions.items.len);
  21129 
  21130     try sema.air_instructions.ensureUnusedCapacity(gpa, 3);
  21131     const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
  21132     const cond_br_inst = block_inst + 1;
  21133     const br_inst = cond_br_inst + 1;
  21134     sema.air_instructions.appendAssumeCapacity(.{
  21135         .tag = .block,
  21136         .data = .{ .ty_pl = .{
  21137             .ty = .void_type,
  21138             .payload = sema.addExtraAssumeCapacity(Air.Block{
  21139                 .body_len = 1,
  21140             }),
  21141         } },
  21142     });
  21143     sema.air_extra.appendAssumeCapacity(cond_br_inst);
  21144 
  21145     sema.air_instructions.appendAssumeCapacity(.{
  21146         .tag = .cond_br,
  21147         .data = .{ .pl_op = .{
  21148             .operand = ok,
  21149             .payload = sema.addExtraAssumeCapacity(Air.CondBr{
  21150                 .then_body_len = 1,
  21151                 .else_body_len = @intCast(u32, fail_block.instructions.items.len),
  21152             }),
  21153         } },
  21154     });
  21155     sema.air_extra.appendAssumeCapacity(br_inst);
  21156     sema.air_extra.appendSliceAssumeCapacity(fail_block.instructions.items);
  21157 
  21158     sema.air_instructions.appendAssumeCapacity(.{
  21159         .tag = .br,
  21160         .data = .{ .br = .{
  21161             .block_inst = block_inst,
  21162             .operand = .void_value,
  21163         } },
  21164     });
  21165 
  21166     parent_block.instructions.appendAssumeCapacity(block_inst);
  21167 }
  21168 
  21169 fn panicWithMsg(
  21170     sema: *Sema,
  21171     block: *Block,
  21172     src: LazySrcLoc,
  21173     msg_inst: Air.Inst.Ref,
  21174 ) !Zir.Inst.Index {
  21175     const mod = sema.mod;
  21176     const arena = sema.arena;
  21177 
  21178     const this_feature_is_implemented_in_the_backend =
  21179         mod.comp.bin_file.options.target.ofmt == .c or
  21180         mod.comp.bin_file.options.use_llvm;
  21181     if (!this_feature_is_implemented_in_the_backend) {
  21182         // TODO implement this feature in all the backends and then delete this branch
  21183         _ = try block.addNoOp(.breakpoint);
  21184         _ = try block.addNoOp(.unreach);
  21185         return always_noreturn;
  21186     }
  21187     const panic_fn = try sema.getBuiltin(block, src, "panic");
  21188     const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
  21189     const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
  21190     const target = mod.getTarget();
  21191     const ptr_stack_trace_ty = try Type.ptr(arena, mod, .{
  21192         .pointee_type = stack_trace_ty,
  21193         .@"addrspace" = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic
  21194     });
  21195     const null_stack_trace = try sema.addConstant(
  21196         try Type.optional(arena, ptr_stack_trace_ty),
  21197         Value.@"null",
  21198     );
  21199     const args: [3]Air.Inst.Ref = .{ msg_inst, null_stack_trace, .null_value };
  21200     _ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, &args, null);
  21201     return always_noreturn;
  21202 }
  21203 
  21204 fn panicUnwrapError(
  21205     sema: *Sema,
  21206     parent_block: *Block,
  21207     src: LazySrcLoc,
  21208     operand: Air.Inst.Ref,
  21209     unwrap_err_tag: Air.Inst.Tag,
  21210     is_non_err_tag: Air.Inst.Tag,
  21211 ) !void {
  21212     const ok = try parent_block.addUnOp(is_non_err_tag, operand);
  21213     const gpa = sema.gpa;
  21214 
  21215     var fail_block: Block = .{
  21216         .parent = parent_block,
  21217         .sema = sema,
  21218         .src_decl = parent_block.src_decl,
  21219         .namespace = parent_block.namespace,
  21220         .wip_capture_scope = parent_block.wip_capture_scope,
  21221         .instructions = .{},
  21222         .inlining = parent_block.inlining,
  21223         .is_comptime = parent_block.is_comptime,
  21224     };
  21225 
  21226     defer fail_block.instructions.deinit(gpa);
  21227 
  21228     {
  21229         const this_feature_is_implemented_in_the_backend =
  21230             sema.mod.comp.bin_file.options.use_llvm;
  21231 
  21232         if (!this_feature_is_implemented_in_the_backend) {
  21233             // TODO implement this feature in all the backends and then delete this branch
  21234             _ = try fail_block.addNoOp(.breakpoint);
  21235             _ = try fail_block.addNoOp(.unreach);
  21236         } else {
  21237             const panic_fn = try sema.getBuiltin(&fail_block, src, "panicUnwrapError");
  21238             const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand);
  21239             const err_return_trace = try sema.getErrorReturnTrace(&fail_block, src);
  21240             const args: [2]Air.Inst.Ref = .{ err_return_trace, err };
  21241             _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args, null);
  21242         }
  21243     }
  21244     try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
  21245 }
  21246 
  21247 fn panicIndexOutOfBounds(
  21248     sema: *Sema,
  21249     parent_block: *Block,
  21250     src: LazySrcLoc,
  21251     index: Air.Inst.Ref,
  21252     len: Air.Inst.Ref,
  21253     cmp_op: Air.Inst.Tag,
  21254 ) !void {
  21255     const ok = try parent_block.addBinOp(cmp_op, index, len);
  21256     const gpa = sema.gpa;
  21257 
  21258     var fail_block: Block = .{
  21259         .parent = parent_block,
  21260         .sema = sema,
  21261         .src_decl = parent_block.src_decl,
  21262         .namespace = parent_block.namespace,
  21263         .wip_capture_scope = parent_block.wip_capture_scope,
  21264         .instructions = .{},
  21265         .inlining = parent_block.inlining,
  21266         .is_comptime = parent_block.is_comptime,
  21267     };
  21268 
  21269     defer fail_block.instructions.deinit(gpa);
  21270 
  21271     {
  21272         const this_feature_is_implemented_in_the_backend =
  21273             sema.mod.comp.bin_file.options.use_llvm;
  21274 
  21275         if (!this_feature_is_implemented_in_the_backend) {
  21276             // TODO implement this feature in all the backends and then delete this branch
  21277             _ = try fail_block.addNoOp(.breakpoint);
  21278             _ = try fail_block.addNoOp(.unreach);
  21279         } else {
  21280             const panic_fn = try sema.getBuiltin(&fail_block, src, "panicOutOfBounds");
  21281             const args: [2]Air.Inst.Ref = .{ index, len };
  21282             _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args, null);
  21283         }
  21284     }
  21285     try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
  21286 }
  21287 
  21288 fn panicSentinelMismatch(
  21289     sema: *Sema,
  21290     parent_block: *Block,
  21291     src: LazySrcLoc,
  21292     maybe_sentinel: ?Value,
  21293     sentinel_ty: Type,
  21294     ptr: Air.Inst.Ref,
  21295     sentinel_index: Air.Inst.Ref,
  21296 ) !void {
  21297     const expected_sentinel_val = maybe_sentinel orelse return;
  21298     const expected_sentinel = try sema.addConstant(sentinel_ty, expected_sentinel_val);
  21299 
  21300     const ptr_ty = sema.typeOf(ptr);
  21301     const actual_sentinel = if (ptr_ty.isSlice())
  21302         try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index)
  21303     else blk: {
  21304         const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null);
  21305         const sentinel_ptr = try parent_block.addPtrElemPtr(ptr, sentinel_index, elem_ptr_ty);
  21306         break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr);
  21307     };
  21308 
  21309     const ok = if (sentinel_ty.zigTypeTag() == .Vector) ok: {
  21310         const eql =
  21311             try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq, try sema.addType(sentinel_ty));
  21312         break :ok try parent_block.addInst(.{
  21313             .tag = .reduce,
  21314             .data = .{ .reduce = .{
  21315                 .operand = eql,
  21316                 .operation = .And,
  21317             } },
  21318         });
  21319     } else if (sentinel_ty.isSelfComparable(true))
  21320         try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel)
  21321     else {
  21322         const panic_fn = try sema.getBuiltin(parent_block, src, "checkNonScalarSentinel");
  21323         const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel };
  21324         _ = try sema.analyzeCall(parent_block, panic_fn, src, src, .auto, false, &args, null);
  21325         return;
  21326     };
  21327     const gpa = sema.gpa;
  21328 
  21329     var fail_block: Block = .{
  21330         .parent = parent_block,
  21331         .sema = sema,
  21332         .src_decl = parent_block.src_decl,
  21333         .namespace = parent_block.namespace,
  21334         .wip_capture_scope = parent_block.wip_capture_scope,
  21335         .instructions = .{},
  21336         .inlining = parent_block.inlining,
  21337         .is_comptime = parent_block.is_comptime,
  21338     };
  21339 
  21340     defer fail_block.instructions.deinit(gpa);
  21341 
  21342     {
  21343         const this_feature_is_implemented_in_the_backend =
  21344             sema.mod.comp.bin_file.options.use_llvm;
  21345 
  21346         if (!this_feature_is_implemented_in_the_backend) {
  21347             // TODO implement this feature in all the backends and then delete this branch
  21348             _ = try fail_block.addNoOp(.breakpoint);
  21349             _ = try fail_block.addNoOp(.unreach);
  21350         } else {
  21351             const panic_fn = try sema.getBuiltin(&fail_block, src, "panicSentinelMismatch");
  21352             const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel };
  21353             _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args, null);
  21354         }
  21355     }
  21356     try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
  21357 }
  21358 
  21359 fn safetyPanic(
  21360     sema: *Sema,
  21361     block: *Block,
  21362     src: LazySrcLoc,
  21363     panic_id: PanicId,
  21364 ) CompileError!Zir.Inst.Index {
  21365     const msg = switch (panic_id) {
  21366         .unreach => "reached unreachable code",
  21367         .unwrap_null => "attempt to use null value",
  21368         .cast_to_null => "cast causes pointer to be null",
  21369         .incorrect_alignment => "incorrect alignment",
  21370         .invalid_error_code => "invalid error code",
  21371         .cast_truncated_data => "integer cast truncated bits",
  21372         .negative_to_unsigned => "attempt to cast negative value to unsigned integer",
  21373         .integer_overflow => "integer overflow",
  21374         .shl_overflow => "left shift overflowed bits",
  21375         .shr_overflow => "right shift overflowed bits",
  21376         .divide_by_zero => "division by zero",
  21377         .exact_division_remainder => "exact division produced remainder",
  21378         .inactive_union_field => "access of inactive union field",
  21379         .integer_part_out_of_bounds => "integer part of floating point value out of bounds",
  21380         .corrupt_switch => "switch on corrupt value",
  21381         .shift_rhs_too_big => "shift amount is greater than the type size",
  21382         .invalid_enum_value => "invalid enum value",
  21383     };
  21384 
  21385     const msg_inst = msg_inst: {
  21386         // TODO instead of making a new decl for every panic in the entire compilation,
  21387         // introduce the concept of a reference-counted decl for these
  21388         var anon_decl = try block.startAnonDecl(src);
  21389         defer anon_decl.deinit();
  21390         break :msg_inst try sema.analyzeDeclRef(try anon_decl.finish(
  21391             try Type.Tag.array_u8.create(anon_decl.arena(), msg.len),
  21392             try Value.Tag.bytes.create(anon_decl.arena(), msg),
  21393             0, // default alignment
  21394         ));
  21395     };
  21396 
  21397     const casted_msg_inst = try sema.coerce(block, Type.initTag(.const_slice_u8), msg_inst, src);
  21398     return sema.panicWithMsg(block, src, casted_msg_inst);
  21399 }
  21400 
  21401 fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
  21402     sema.branch_count += 1;
  21403     if (sema.branch_count > sema.branch_quota) {
  21404         const msg = try sema.errMsg(
  21405             block,
  21406             src,
  21407             "evaluation exceeded {d} backwards branches",
  21408             .{sema.branch_quota},
  21409         );
  21410         try sema.errNote(
  21411             block,
  21412             src,
  21413             msg,
  21414             "use @setEvalBranchQuota() to raise the branch limit from {d}",
  21415             .{sema.branch_quota},
  21416         );
  21417         return sema.failWithOwnedErrorMsg(msg);
  21418     }
  21419 }
  21420 
  21421 fn fieldVal(
  21422     sema: *Sema,
  21423     block: *Block,
  21424     src: LazySrcLoc,
  21425     object: Air.Inst.Ref,
  21426     field_name: []const u8,
  21427     field_name_src: LazySrcLoc,
  21428 ) CompileError!Air.Inst.Ref {
  21429     // When editing this function, note that there is corresponding logic to be edited
  21430     // in `fieldPtr`. This function takes a value and returns a value.
  21431 
  21432     const arena = sema.arena;
  21433     const object_src = src; // TODO better source location
  21434     const object_ty = sema.typeOf(object);
  21435 
  21436     // Zig allows dereferencing a single pointer during field lookup. Note that
  21437     // we don't actually need to generate the dereference some field lookups, like the
  21438     // length of arrays and other comptime operations.
  21439     const is_pointer_to = object_ty.isSinglePointer();
  21440 
  21441     const inner_ty = if (is_pointer_to)
  21442         object_ty.childType()
  21443     else
  21444         object_ty;
  21445 
  21446     switch (inner_ty.zigTypeTag()) {
  21447         .Array => {
  21448             if (mem.eql(u8, field_name, "len")) {
  21449                 return sema.addConstant(
  21450                     Type.usize,
  21451                     try Value.Tag.int_u64.create(arena, inner_ty.arrayLen()),
  21452                 );
  21453             } else {
  21454                 return sema.fail(
  21455                     block,
  21456                     field_name_src,
  21457                     "no member named '{s}' in '{}'",
  21458                     .{ field_name, object_ty.fmt(sema.mod) },
  21459                 );
  21460             }
  21461         },
  21462         .Pointer => {
  21463             const ptr_info = inner_ty.ptrInfo().data;
  21464             if (ptr_info.size == .Slice) {
  21465                 if (mem.eql(u8, field_name, "ptr")) {
  21466                     const slice = if (is_pointer_to)
  21467                         try sema.analyzeLoad(block, src, object, object_src)
  21468                     else
  21469                         object;
  21470                     return sema.analyzeSlicePtr(block, object_src, slice, inner_ty);
  21471                 } else if (mem.eql(u8, field_name, "len")) {
  21472                     const slice = if (is_pointer_to)
  21473                         try sema.analyzeLoad(block, src, object, object_src)
  21474                     else
  21475                         object;
  21476                     return sema.analyzeSliceLen(block, src, slice);
  21477                 } else {
  21478                     return sema.fail(
  21479                         block,
  21480                         field_name_src,
  21481                         "no member named '{s}' in '{}'",
  21482                         .{ field_name, object_ty.fmt(sema.mod) },
  21483                     );
  21484                 }
  21485             } else if (ptr_info.pointee_type.zigTypeTag() == .Array) {
  21486                 if (mem.eql(u8, field_name, "len")) {
  21487                     return sema.addConstant(
  21488                         Type.usize,
  21489                         try Value.Tag.int_u64.create(arena, ptr_info.pointee_type.arrayLen()),
  21490                     );
  21491                 } else {
  21492                     return sema.fail(
  21493                         block,
  21494                         field_name_src,
  21495                         "no member named '{s}' in '{}'",
  21496                         .{ field_name, ptr_info.pointee_type.fmt(sema.mod) },
  21497                     );
  21498                 }
  21499             }
  21500         },
  21501         .Type => {
  21502             const dereffed_type = if (is_pointer_to)
  21503                 try sema.analyzeLoad(block, src, object, object_src)
  21504             else
  21505                 object;
  21506 
  21507             const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?;
  21508             var to_type_buffer: Value.ToTypeBuffer = undefined;
  21509             const child_type = val.toType(&to_type_buffer);
  21510 
  21511             switch (try child_type.zigTypeTagOrPoison()) {
  21512                 .ErrorSet => {
  21513                     const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {
  21514                         if (payload.data.names.getEntry(field_name)) |entry| {
  21515                             break :blk entry.key_ptr.*;
  21516                         }
  21517                         const msg = msg: {
  21518                             const msg = try sema.errMsg(block, src, "no error named '{s}' in '{}'", .{
  21519                                 field_name, child_type.fmt(sema.mod),
  21520                             });
  21521                             errdefer msg.destroy(sema.gpa);
  21522                             try sema.addDeclaredHereNote(msg, child_type);
  21523                             break :msg msg;
  21524                         };
  21525                         return sema.failWithOwnedErrorMsg(msg);
  21526                     } else (try sema.mod.getErrorValue(field_name)).key;
  21527 
  21528                     return sema.addConstant(
  21529                         try child_type.copy(arena),
  21530                         try Value.Tag.@"error".create(arena, .{ .name = name }),
  21531                     );
  21532                 },
  21533                 .Union => {
  21534                     const union_ty = try sema.resolveTypeFields(block, src, child_type);
  21535 
  21536                     if (union_ty.getNamespace()) |namespace| {
  21537                         if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| {
  21538                             return inst;
  21539                         }
  21540                     }
  21541                     if (union_ty.unionTagType()) |enum_ty| {
  21542                         if (enum_ty.enumFieldIndex(field_name)) |field_index_usize| {
  21543                             const field_index = @intCast(u32, field_index_usize);
  21544                             return sema.addConstant(
  21545                                 enum_ty,
  21546                                 try Value.Tag.enum_field_index.create(sema.arena, field_index),
  21547                             );
  21548                         }
  21549                     }
  21550                     return sema.failWithBadMemberAccess(block, union_ty, field_name_src, field_name);
  21551                 },
  21552                 .Enum => {
  21553                     if (child_type.getNamespace()) |namespace| {
  21554                         if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| {
  21555                             return inst;
  21556                         }
  21557                     }
  21558                     const field_index_usize = child_type.enumFieldIndex(field_name) orelse
  21559                         return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
  21560                     const field_index = @intCast(u32, field_index_usize);
  21561                     const enum_val = try Value.Tag.enum_field_index.create(arena, field_index);
  21562                     return sema.addConstant(try child_type.copy(arena), enum_val);
  21563                 },
  21564                 .Struct, .Opaque => {
  21565                     if (child_type.getNamespace()) |namespace| {
  21566                         if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| {
  21567                             return inst;
  21568                         }
  21569                     }
  21570                     return sema.failWithBadMemberAccess(block, child_type, src, field_name);
  21571                 },
  21572                 else => {
  21573                     const msg = msg: {
  21574                         const msg = try sema.errMsg(block, src, "type '{}' has no members", .{child_type.fmt(sema.mod)});
  21575                         errdefer msg.destroy(sema.gpa);
  21576                         if (child_type.isSlice()) try sema.errNote(block, src, msg, "slice values have 'len' and 'ptr' members", .{});
  21577                         if (child_type.zigTypeTag() == .Array) try sema.errNote(block, src, msg, "array values have 'len' member", .{});
  21578                         break :msg msg;
  21579                     };
  21580                     return sema.failWithOwnedErrorMsg(msg);
  21581                 },
  21582             }
  21583         },
  21584         .Struct => if (is_pointer_to) {
  21585             // Avoid loading the entire struct by fetching a pointer and loading that
  21586             const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false);
  21587             return sema.analyzeLoad(block, src, field_ptr, object_src);
  21588         } else {
  21589             return sema.structFieldVal(block, src, object, field_name, field_name_src, inner_ty);
  21590         },
  21591         .Union => if (is_pointer_to) {
  21592             // Avoid loading the entire union by fetching a pointer and loading that
  21593             const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false);
  21594             return sema.analyzeLoad(block, src, field_ptr, object_src);
  21595         } else {
  21596             return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty);
  21597         },
  21598         else => {},
  21599     }
  21600     return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
  21601 }
  21602 
  21603 fn fieldPtr(
  21604     sema: *Sema,
  21605     block: *Block,
  21606     src: LazySrcLoc,
  21607     object_ptr: Air.Inst.Ref,
  21608     field_name: []const u8,
  21609     field_name_src: LazySrcLoc,
  21610     initializing: bool,
  21611 ) CompileError!Air.Inst.Ref {
  21612     // When editing this function, note that there is corresponding logic to be edited
  21613     // in `fieldVal`. This function takes a pointer and returns a pointer.
  21614 
  21615     const object_ptr_src = src; // TODO better source location
  21616     const object_ptr_ty = sema.typeOf(object_ptr);
  21617     const object_ty = switch (object_ptr_ty.zigTypeTag()) {
  21618         .Pointer => object_ptr_ty.elemType(),
  21619         else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty.fmt(sema.mod)}),
  21620     };
  21621 
  21622     // Zig allows dereferencing a single pointer during field lookup. Note that
  21623     // we don't actually need to generate the dereference some field lookups, like the
  21624     // length of arrays and other comptime operations.
  21625     const is_pointer_to = object_ty.isSinglePointer();
  21626 
  21627     const inner_ty = if (is_pointer_to)
  21628         object_ty.childType()
  21629     else
  21630         object_ty;
  21631 
  21632     switch (inner_ty.zigTypeTag()) {
  21633         .Array => {
  21634             if (mem.eql(u8, field_name, "len")) {
  21635                 var anon_decl = try block.startAnonDecl(src);
  21636                 defer anon_decl.deinit();
  21637                 return sema.analyzeDeclRef(try anon_decl.finish(
  21638                     Type.usize,
  21639                     try Value.Tag.int_u64.create(anon_decl.arena(), inner_ty.arrayLen()),
  21640                     0, // default alignment
  21641                 ));
  21642             } else {
  21643                 return sema.fail(
  21644                     block,
  21645                     field_name_src,
  21646                     "no member named '{s}' in '{}'",
  21647                     .{ field_name, object_ty.fmt(sema.mod) },
  21648                 );
  21649             }
  21650         },
  21651         .Pointer => if (inner_ty.isSlice()) {
  21652             const inner_ptr = if (is_pointer_to)
  21653                 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
  21654             else
  21655                 object_ptr;
  21656 
  21657             if (mem.eql(u8, field_name, "ptr")) {
  21658                 const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer);
  21659                 const slice_ptr_ty = inner_ty.slicePtrFieldType(buf);
  21660 
  21661                 const result_ty = try Type.ptr(sema.arena, sema.mod, .{
  21662                     .pointee_type = slice_ptr_ty,
  21663                     .mutable = object_ptr_ty.ptrIsMutable(),
  21664                     .@"addrspace" = object_ptr_ty.ptrAddressSpace(),
  21665                 });
  21666 
  21667                 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
  21668                     return sema.addConstant(
  21669                         result_ty,
  21670                         try Value.Tag.field_ptr.create(sema.arena, .{
  21671                             .container_ptr = val,
  21672                             .container_ty = inner_ty,
  21673                             .field_index = Value.Payload.Slice.ptr_index,
  21674                         }),
  21675                     );
  21676                 }
  21677                 try sema.requireRuntimeBlock(block, src, null);
  21678 
  21679                 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
  21680             } else if (mem.eql(u8, field_name, "len")) {
  21681                 const result_ty = try Type.ptr(sema.arena, sema.mod, .{
  21682                     .pointee_type = Type.usize,
  21683                     .mutable = object_ptr_ty.ptrIsMutable(),
  21684                     .@"addrspace" = object_ptr_ty.ptrAddressSpace(),
  21685                 });
  21686 
  21687                 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
  21688                     return sema.addConstant(
  21689                         result_ty,
  21690                         try Value.Tag.field_ptr.create(sema.arena, .{
  21691                             .container_ptr = val,
  21692                             .container_ty = inner_ty,
  21693                             .field_index = Value.Payload.Slice.len_index,
  21694                         }),
  21695                     );
  21696                 }
  21697                 try sema.requireRuntimeBlock(block, src, null);
  21698 
  21699                 return block.addTyOp(.ptr_slice_len_ptr, result_ty, inner_ptr);
  21700             } else {
  21701                 return sema.fail(
  21702                     block,
  21703                     field_name_src,
  21704                     "no member named '{s}' in '{}'",
  21705                     .{ field_name, object_ty.fmt(sema.mod) },
  21706                 );
  21707             }
  21708         },
  21709         .Type => {
  21710             _ = try sema.resolveConstValue(block, .unneeded, object_ptr, undefined);
  21711             const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src);
  21712             const inner = if (is_pointer_to)
  21713                 try sema.analyzeLoad(block, src, result, object_ptr_src)
  21714             else
  21715                 result;
  21716 
  21717             const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?;
  21718             var to_type_buffer: Value.ToTypeBuffer = undefined;
  21719             const child_type = val.toType(&to_type_buffer);
  21720 
  21721             switch (child_type.zigTypeTag()) {
  21722                 .ErrorSet => {
  21723                     // TODO resolve inferred error sets
  21724                     const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {
  21725                         if (payload.data.names.getEntry(field_name)) |entry| {
  21726                             break :blk entry.key_ptr.*;
  21727                         }
  21728                         return sema.fail(block, src, "no error named '{s}' in '{}'", .{
  21729                             field_name, child_type.fmt(sema.mod),
  21730                         });
  21731                     } else (try sema.mod.getErrorValue(field_name)).key;
  21732 
  21733                     var anon_decl = try block.startAnonDecl(src);
  21734                     defer anon_decl.deinit();
  21735                     return sema.analyzeDeclRef(try anon_decl.finish(
  21736                         try child_type.copy(anon_decl.arena()),
  21737                         try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }),
  21738                         0, // default alignment
  21739                     ));
  21740                 },
  21741                 .Union => {
  21742                     if (child_type.getNamespace()) |namespace| {
  21743                         if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
  21744                             return inst;
  21745                         }
  21746                     }
  21747                     if (child_type.unionTagType()) |enum_ty| {
  21748                         if (enum_ty.enumFieldIndex(field_name)) |field_index| {
  21749                             const field_index_u32 = @intCast(u32, field_index);
  21750                             var anon_decl = try block.startAnonDecl(src);
  21751                             defer anon_decl.deinit();
  21752                             return sema.analyzeDeclRef(try anon_decl.finish(
  21753                                 try enum_ty.copy(anon_decl.arena()),
  21754                                 try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),
  21755                                 0, // default alignment
  21756                             ));
  21757                         }
  21758                     }
  21759                     return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
  21760                 },
  21761                 .Enum => {
  21762                     if (child_type.getNamespace()) |namespace| {
  21763                         if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
  21764                             return inst;
  21765                         }
  21766                     }
  21767                     const field_index = child_type.enumFieldIndex(field_name) orelse {
  21768                         return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
  21769                     };
  21770                     const field_index_u32 = @intCast(u32, field_index);
  21771                     var anon_decl = try block.startAnonDecl(src);
  21772                     defer anon_decl.deinit();
  21773                     return sema.analyzeDeclRef(try anon_decl.finish(
  21774                         try child_type.copy(anon_decl.arena()),
  21775                         try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),
  21776                         0, // default alignment
  21777                     ));
  21778                 },
  21779                 .Struct, .Opaque => {
  21780                     if (child_type.getNamespace()) |namespace| {
  21781                         if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
  21782                             return inst;
  21783                         }
  21784                     }
  21785                     return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
  21786                 },
  21787                 else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(sema.mod)}),
  21788             }
  21789         },
  21790         .Struct => {
  21791             const inner_ptr = if (is_pointer_to)
  21792                 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
  21793             else
  21794                 object_ptr;
  21795             return sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);
  21796         },
  21797         .Union => {
  21798             const inner_ptr = if (is_pointer_to)
  21799                 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
  21800             else
  21801                 object_ptr;
  21802             return sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);
  21803         },
  21804         else => {},
  21805     }
  21806     return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
  21807 }
  21808 
  21809 fn fieldCallBind(
  21810     sema: *Sema,
  21811     block: *Block,
  21812     src: LazySrcLoc,
  21813     raw_ptr: Air.Inst.Ref,
  21814     field_name: []const u8,
  21815     field_name_src: LazySrcLoc,
  21816 ) CompileError!Air.Inst.Ref {
  21817     // When editing this function, note that there is corresponding logic to be edited
  21818     // in `fieldVal`. This function takes a pointer and returns a pointer.
  21819 
  21820     const raw_ptr_src = src; // TODO better source location
  21821     const raw_ptr_ty = sema.typeOf(raw_ptr);
  21822     const inner_ty = if (raw_ptr_ty.zigTypeTag() == .Pointer and (raw_ptr_ty.ptrSize() == .One or raw_ptr_ty.ptrSize() == .C))
  21823         raw_ptr_ty.childType()
  21824     else
  21825         return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(sema.mod)});
  21826 
  21827     // Optionally dereference a second pointer to get the concrete type.
  21828     const is_double_ptr = inner_ty.zigTypeTag() == .Pointer and inner_ty.ptrSize() == .One;
  21829     const concrete_ty = if (is_double_ptr) inner_ty.childType() else inner_ty;
  21830     const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty;
  21831     const object_ptr = if (is_double_ptr)
  21832         try sema.analyzeLoad(block, src, raw_ptr, src)
  21833     else
  21834         raw_ptr;
  21835 
  21836     const arena = sema.arena;
  21837     find_field: {
  21838         switch (concrete_ty.zigTypeTag()) {
  21839             .Struct => {
  21840                 const struct_ty = try sema.resolveTypeFields(block, src, concrete_ty);
  21841                 if (struct_ty.castTag(.@"struct")) |struct_obj| {
  21842                     const field_index_usize = struct_obj.data.fields.getIndex(field_name) orelse
  21843                         break :find_field;
  21844                     const field_index = @intCast(u32, field_index_usize);
  21845                     const field = struct_obj.data.fields.values()[field_index];
  21846 
  21847                     return finishFieldCallBind(sema, block, src, ptr_ty, field.ty, field_index, object_ptr);
  21848                 } else if (struct_ty.isTuple()) {
  21849                     if (mem.eql(u8, field_name, "len")) {
  21850                         return sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount());
  21851                     }
  21852                     if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {
  21853                         if (field_index >= struct_ty.structFieldCount()) break :find_field;
  21854                         return finishFieldCallBind(sema, block, src, ptr_ty, struct_ty.structFieldType(field_index), field_index, object_ptr);
  21855                     } else |_| {}
  21856                 } else {
  21857                     const max = struct_ty.structFieldCount();
  21858                     var i: u32 = 0;
  21859                     while (i < max) : (i += 1) {
  21860                         if (mem.eql(u8, struct_ty.structFieldName(i), field_name)) {
  21861                             return finishFieldCallBind(sema, block, src, ptr_ty, struct_ty.structFieldType(i), i, object_ptr);
  21862                         }
  21863                     }
  21864                 }
  21865             },
  21866             .Union => {
  21867                 const union_ty = try sema.resolveTypeFields(block, src, concrete_ty);
  21868                 const fields = union_ty.unionFields();
  21869                 const field_index_usize = fields.getIndex(field_name) orelse break :find_field;
  21870                 const field_index = @intCast(u32, field_index_usize);
  21871                 const field = fields.values()[field_index];
  21872 
  21873                 return finishFieldCallBind(sema, block, src, ptr_ty, field.ty, field_index, object_ptr);
  21874             },
  21875             .Type => {
  21876                 const namespace = try sema.analyzeLoad(block, src, object_ptr, src);
  21877                 return sema.fieldVal(block, src, namespace, field_name, field_name_src);
  21878             },
  21879             else => {},
  21880         }
  21881     }
  21882 
  21883     // If we get here, we need to look for a decl in the struct type instead.
  21884     switch (concrete_ty.zigTypeTag()) {
  21885         .Struct, .Opaque, .Union, .Enum => {
  21886             if (concrete_ty.getNamespace()) |namespace| {
  21887                 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
  21888                     const decl_val = try sema.analyzeLoad(block, src, inst, src);
  21889                     const decl_type = sema.typeOf(decl_val);
  21890                     if (decl_type.zigTypeTag() == .Fn and
  21891                         decl_type.fnParamLen() >= 1)
  21892                     {
  21893                         const first_param_type = decl_type.fnParamType(0);
  21894                         const first_param_tag = first_param_type.tag();
  21895                         // zig fmt: off
  21896                         if (first_param_tag == .var_args_param or
  21897                             first_param_tag == .generic_poison or (
  21898                                 first_param_type.zigTypeTag() == .Pointer and
  21899                                 (first_param_type.ptrSize() == .One or
  21900                                 first_param_type.ptrSize() == .C) and
  21901                                 first_param_type.childType().eql(concrete_ty, sema.mod)))
  21902                         {
  21903                             // zig fmt: on
  21904                             // TODO: bound fn calls on rvalues should probably
  21905                             // generate a by-value argument somehow.
  21906                             const ty = Type.Tag.bound_fn.init();
  21907                             const value = try Value.Tag.bound_fn.create(arena, .{
  21908                                 .func_inst = decl_val,
  21909                                 .arg0_inst = object_ptr,
  21910                             });
  21911                             return sema.addConstant(ty, value);
  21912                         } else if (first_param_type.eql(concrete_ty, sema.mod)) {
  21913                             var deref = try sema.analyzeLoad(block, src, object_ptr, src);
  21914                             const ty = Type.Tag.bound_fn.init();
  21915                             const value = try Value.Tag.bound_fn.create(arena, .{
  21916                                 .func_inst = decl_val,
  21917                                 .arg0_inst = deref,
  21918                             });
  21919                             return sema.addConstant(ty, value);
  21920                         }
  21921                     }
  21922                 }
  21923             }
  21924         },
  21925         else => {},
  21926     }
  21927 
  21928     const msg = msg: {
  21929         const msg = try sema.errMsg(block, src, "no field or member function named '{s}' in '{}'", .{ field_name, concrete_ty.fmt(sema.mod) });
  21930         errdefer msg.destroy(sema.gpa);
  21931         try sema.addDeclaredHereNote(msg, concrete_ty);
  21932         break :msg msg;
  21933     };
  21934     return sema.failWithOwnedErrorMsg(msg);
  21935 }
  21936 
  21937 fn finishFieldCallBind(
  21938     sema: *Sema,
  21939     block: *Block,
  21940     src: LazySrcLoc,
  21941     ptr_ty: Type,
  21942     field_ty: Type,
  21943     field_index: u32,
  21944     object_ptr: Air.Inst.Ref,
  21945 ) CompileError!Air.Inst.Ref {
  21946     const arena = sema.arena;
  21947     const ptr_field_ty = try Type.ptr(arena, sema.mod, .{
  21948         .pointee_type = field_ty,
  21949         .mutable = ptr_ty.ptrIsMutable(),
  21950         .@"addrspace" = ptr_ty.ptrAddressSpace(),
  21951     });
  21952 
  21953     const container_ty = ptr_ty.childType();
  21954     if (container_ty.zigTypeTag() == .Struct) {
  21955         if (container_ty.structFieldValueComptime(field_index)) |default_val| {
  21956             return sema.addConstant(field_ty, default_val);
  21957         }
  21958     }
  21959 
  21960     if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| {
  21961         const pointer = try sema.addConstant(
  21962             ptr_field_ty,
  21963             try Value.Tag.field_ptr.create(arena, .{
  21964                 .container_ptr = struct_ptr_val,
  21965                 .container_ty = container_ty,
  21966                 .field_index = field_index,
  21967             }),
  21968         );
  21969         return sema.analyzeLoad(block, src, pointer, src);
  21970     }
  21971 
  21972     try sema.requireRuntimeBlock(block, src, null);
  21973     const ptr_inst = try block.addStructFieldPtr(object_ptr, field_index, ptr_field_ty);
  21974     return sema.analyzeLoad(block, src, ptr_inst, src);
  21975 }
  21976 
  21977 fn namespaceLookup(
  21978     sema: *Sema,
  21979     block: *Block,
  21980     src: LazySrcLoc,
  21981     namespace: *Namespace,
  21982     decl_name: []const u8,
  21983 ) CompileError!?Decl.Index {
  21984     const gpa = sema.gpa;
  21985     if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| {
  21986         const decl = sema.mod.declPtr(decl_index);
  21987         if (!decl.is_pub and decl.getFileScope() != block.getFileScope()) {
  21988             const msg = msg: {
  21989                 const msg = try sema.errMsg(block, src, "'{s}' is not marked 'pub'", .{
  21990                     decl_name,
  21991                 });
  21992                 errdefer msg.destroy(gpa);
  21993                 try sema.mod.errNoteNonLazy(decl.srcLoc(), msg, "declared here", .{});
  21994                 break :msg msg;
  21995             };
  21996             return sema.failWithOwnedErrorMsg(msg);
  21997         }
  21998         return decl_index;
  21999     }
  22000     return null;
  22001 }
  22002 
  22003 fn namespaceLookupRef(
  22004     sema: *Sema,
  22005     block: *Block,
  22006     src: LazySrcLoc,
  22007     namespace: *Namespace,
  22008     decl_name: []const u8,
  22009 ) CompileError!?Air.Inst.Ref {
  22010     const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;
  22011     try sema.addReferencedBy(block, src, decl);
  22012     return try sema.analyzeDeclRef(decl);
  22013 }
  22014 
  22015 fn namespaceLookupVal(
  22016     sema: *Sema,
  22017     block: *Block,
  22018     src: LazySrcLoc,
  22019     namespace: *Namespace,
  22020     decl_name: []const u8,
  22021 ) CompileError!?Air.Inst.Ref {
  22022     const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;
  22023     return try sema.analyzeDeclVal(block, src, decl);
  22024 }
  22025 
  22026 fn structFieldPtr(
  22027     sema: *Sema,
  22028     block: *Block,
  22029     src: LazySrcLoc,
  22030     struct_ptr: Air.Inst.Ref,
  22031     field_name: []const u8,
  22032     field_name_src: LazySrcLoc,
  22033     unresolved_struct_ty: Type,
  22034     initializing: bool,
  22035 ) CompileError!Air.Inst.Ref {
  22036     assert(unresolved_struct_ty.zigTypeTag() == .Struct);
  22037 
  22038     const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty);
  22039     try sema.resolveStructLayout(block, src, struct_ty);
  22040 
  22041     if (struct_ty.isTuple()) {
  22042         if (mem.eql(u8, field_name, "len")) {
  22043             const len_inst = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount());
  22044             return sema.analyzeRef(block, src, len_inst);
  22045         }
  22046         const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src);
  22047         return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing);
  22048     } else if (struct_ty.isAnonStruct()) {
  22049         const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src);
  22050         return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing);
  22051     }
  22052 
  22053     const struct_obj = struct_ty.castTag(.@"struct").?.data;
  22054 
  22055     const field_index_big = struct_obj.fields.getIndex(field_name) orelse
  22056         return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
  22057     const field_index = @intCast(u32, field_index_big);
  22058 
  22059     return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, field_name_src, struct_ty, initializing);
  22060 }
  22061 
  22062 fn structFieldPtrByIndex(
  22063     sema: *Sema,
  22064     block: *Block,
  22065     src: LazySrcLoc,
  22066     struct_ptr: Air.Inst.Ref,
  22067     field_index: u32,
  22068     field_src: LazySrcLoc,
  22069     struct_ty: Type,
  22070     initializing: bool,
  22071 ) CompileError!Air.Inst.Ref {
  22072     if (struct_ty.isAnonStruct()) {
  22073         return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing);
  22074     }
  22075 
  22076     const struct_obj = struct_ty.castTag(.@"struct").?.data;
  22077     const field = struct_obj.fields.values()[field_index];
  22078     const struct_ptr_ty = sema.typeOf(struct_ptr);
  22079     const struct_ptr_ty_info = struct_ptr_ty.ptrInfo().data;
  22080 
  22081     var ptr_ty_data: Type.Payload.Pointer.Data = .{
  22082         .pointee_type = field.ty,
  22083         .mutable = struct_ptr_ty_info.mutable,
  22084         .@"volatile" = struct_ptr_ty_info.@"volatile",
  22085         .@"addrspace" = struct_ptr_ty_info.@"addrspace",
  22086     };
  22087 
  22088     const target = sema.mod.getTarget();
  22089 
  22090     if (struct_obj.layout == .Packed) {
  22091         comptime assert(Type.packed_struct_layout_version == 2);
  22092 
  22093         var running_bits: u16 = 0;
  22094         for (struct_obj.fields.values()) |f, i| {
  22095             if (!(try sema.typeHasRuntimeBits(block, field_src, f.ty))) continue;
  22096 
  22097             if (i == field_index) {
  22098                 ptr_ty_data.bit_offset = running_bits;
  22099             }
  22100             running_bits += @intCast(u16, f.ty.bitSize(target));
  22101         }
  22102         ptr_ty_data.host_size = (running_bits + 7) / 8;
  22103 
  22104         // If this is a packed struct embedded in another one, we need to offset
  22105         // the bits against each other.
  22106         if (struct_ptr_ty_info.host_size != 0) {
  22107             ptr_ty_data.host_size = struct_ptr_ty_info.host_size;
  22108             ptr_ty_data.bit_offset += struct_ptr_ty_info.bit_offset;
  22109         }
  22110 
  22111         const parent_align = if (struct_ptr_ty_info.@"align" != 0)
  22112             struct_ptr_ty_info.@"align"
  22113         else
  22114             struct_ptr_ty_info.pointee_type.abiAlignment(target);
  22115         ptr_ty_data.@"align" = parent_align;
  22116 
  22117         // If the field happens to be byte-aligned, simplify the pointer type.
  22118         // The pointee type bit size must match its ABI byte size so that loads and stores
  22119         // do not interfere with the surrounding packed bits.
  22120         // We do not attempt this with big-endian targets yet because of nested
  22121         // structs and floats. I need to double-check the desired behavior for big endian
  22122         // targets before adding the necessary complications to this code. This will not
  22123         // cause miscompilations; it only means the field pointer uses bit masking when it
  22124         // might not be strictly necessary.
  22125         if (parent_align != 0 and ptr_ty_data.bit_offset % 8 == 0 and
  22126             target.cpu.arch.endian() == .Little)
  22127         {
  22128             const elem_size_bytes = ptr_ty_data.pointee_type.abiSize(target);
  22129             const elem_size_bits = ptr_ty_data.pointee_type.bitSize(target);
  22130             if (elem_size_bytes * 8 == elem_size_bits) {
  22131                 const byte_offset = ptr_ty_data.bit_offset / 8;
  22132                 const new_align = @as(u32, 1) << @intCast(u5, @ctz(byte_offset | parent_align));
  22133                 ptr_ty_data.bit_offset = 0;
  22134                 ptr_ty_data.host_size = 0;
  22135                 ptr_ty_data.@"align" = new_align;
  22136             }
  22137         }
  22138     } else {
  22139         ptr_ty_data.@"align" = field.abi_align;
  22140     }
  22141 
  22142     const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);
  22143 
  22144     if (field.is_comptime) {
  22145         const val = try Value.Tag.comptime_field_ptr.create(sema.arena, .{
  22146             .field_ty = try field.ty.copy(sema.arena),
  22147             .field_val = try field.default_val.copy(sema.arena),
  22148         });
  22149         return sema.addConstant(ptr_field_ty, val);
  22150     }
  22151 
  22152     if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
  22153         return sema.addConstant(
  22154             ptr_field_ty,
  22155             try Value.Tag.field_ptr.create(sema.arena, .{
  22156                 .container_ptr = struct_ptr_val,
  22157                 .container_ty = struct_ptr_ty.childType(),
  22158                 .field_index = field_index,
  22159             }),
  22160         );
  22161     }
  22162 
  22163     try sema.requireRuntimeBlock(block, src, null);
  22164     return block.addStructFieldPtr(struct_ptr, field_index, ptr_field_ty);
  22165 }
  22166 
  22167 fn structFieldVal(
  22168     sema: *Sema,
  22169     block: *Block,
  22170     src: LazySrcLoc,
  22171     struct_byval: Air.Inst.Ref,
  22172     field_name: []const u8,
  22173     field_name_src: LazySrcLoc,
  22174     unresolved_struct_ty: Type,
  22175 ) CompileError!Air.Inst.Ref {
  22176     assert(unresolved_struct_ty.zigTypeTag() == .Struct);
  22177 
  22178     const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty);
  22179     switch (struct_ty.tag()) {
  22180         .tuple, .empty_struct_literal => return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty),
  22181         .anon_struct => {
  22182             const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src);
  22183             return tupleFieldValByIndex(sema, block, src, struct_byval, field_index, struct_ty);
  22184         },
  22185         .@"struct" => {
  22186             const struct_obj = struct_ty.castTag(.@"struct").?.data;
  22187 
  22188             const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
  22189                 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
  22190             const field_index = @intCast(u32, field_index_usize);
  22191             const field = struct_obj.fields.values()[field_index];
  22192 
  22193             if (field.is_comptime) {
  22194                 return sema.addConstant(field.ty, field.default_val);
  22195             }
  22196 
  22197             if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| {
  22198                 if (struct_val.isUndef()) return sema.addConstUndef(field.ty);
  22199                 if ((try sema.typeHasOnePossibleValue(block, src, field.ty))) |opv| {
  22200                     return sema.addConstant(field.ty, opv);
  22201                 }
  22202 
  22203                 const field_values = struct_val.castTag(.aggregate).?.data;
  22204                 return sema.addConstant(field.ty, field_values[field_index]);
  22205             }
  22206 
  22207             try sema.requireRuntimeBlock(block, src, null);
  22208             return block.addStructFieldVal(struct_byval, field_index, field.ty);
  22209         },
  22210         else => unreachable,
  22211     }
  22212 }
  22213 
  22214 fn tupleFieldVal(
  22215     sema: *Sema,
  22216     block: *Block,
  22217     src: LazySrcLoc,
  22218     tuple_byval: Air.Inst.Ref,
  22219     field_name: []const u8,
  22220     field_name_src: LazySrcLoc,
  22221     tuple_ty: Type,
  22222 ) CompileError!Air.Inst.Ref {
  22223     if (mem.eql(u8, field_name, "len")) {
  22224         return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount());
  22225     }
  22226     const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_name_src);
  22227     return tupleFieldValByIndex(sema, block, src, tuple_byval, field_index, tuple_ty);
  22228 }
  22229 
  22230 /// Asserts that `field_name` is not "len".
  22231 fn tupleFieldIndex(
  22232     sema: *Sema,
  22233     block: *Block,
  22234     tuple_ty: Type,
  22235     field_name: []const u8,
  22236     field_name_src: LazySrcLoc,
  22237 ) CompileError!u32 {
  22238     assert(!std.mem.eql(u8, field_name, "len"));
  22239     if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {
  22240         if (field_index < tuple_ty.structFieldCount()) return field_index;
  22241         return sema.fail(block, field_name_src, "index '{s}' out of bounds of tuple '{}'", .{
  22242             field_name, tuple_ty.fmt(sema.mod),
  22243         });
  22244     } else |_| {}
  22245 
  22246     return sema.fail(block, field_name_src, "no field named '{s}' in tuple '{}'", .{
  22247         field_name, tuple_ty.fmt(sema.mod),
  22248     });
  22249 }
  22250 
  22251 fn tupleFieldValByIndex(
  22252     sema: *Sema,
  22253     block: *Block,
  22254     src: LazySrcLoc,
  22255     tuple_byval: Air.Inst.Ref,
  22256     field_index: u32,
  22257     tuple_ty: Type,
  22258 ) CompileError!Air.Inst.Ref {
  22259     const tuple = tuple_ty.tupleFields();
  22260     const field_ty = tuple.types[field_index];
  22261 
  22262     if (tuple.values[field_index].tag() != .unreachable_value) {
  22263         return sema.addConstant(field_ty, tuple.values[field_index]);
  22264     }
  22265 
  22266     if (try sema.resolveMaybeUndefVal(block, src, tuple_byval)) |tuple_val| {
  22267         if (tuple_val.isUndef()) return sema.addConstUndef(field_ty);
  22268         if ((try sema.typeHasOnePossibleValue(block, src, field_ty))) |opv| {
  22269             return sema.addConstant(field_ty, opv);
  22270         }
  22271         const field_values = tuple_val.castTag(.aggregate).?.data;
  22272         return sema.addConstant(field_ty, field_values[field_index]);
  22273     }
  22274 
  22275     if (tuple_ty.structFieldValueComptime(field_index)) |default_val| {
  22276         return sema.addConstant(field_ty, default_val);
  22277     }
  22278 
  22279     try sema.requireRuntimeBlock(block, src, null);
  22280     return block.addStructFieldVal(tuple_byval, field_index, field_ty);
  22281 }
  22282 
  22283 fn unionFieldPtr(
  22284     sema: *Sema,
  22285     block: *Block,
  22286     src: LazySrcLoc,
  22287     union_ptr: Air.Inst.Ref,
  22288     field_name: []const u8,
  22289     field_name_src: LazySrcLoc,
  22290     unresolved_union_ty: Type,
  22291     initializing: bool,
  22292 ) CompileError!Air.Inst.Ref {
  22293     const arena = sema.arena;
  22294     assert(unresolved_union_ty.zigTypeTag() == .Union);
  22295 
  22296     const union_ptr_ty = sema.typeOf(union_ptr);
  22297     const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);
  22298     const union_obj = union_ty.cast(Type.Payload.Union).?.data;
  22299     const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
  22300     const field = union_obj.fields.values()[field_index];
  22301     const ptr_field_ty = try Type.ptr(arena, sema.mod, .{
  22302         .pointee_type = field.ty,
  22303         .mutable = union_ptr_ty.ptrIsMutable(),
  22304         .@"volatile" = union_ptr_ty.isVolatilePtr(),
  22305         .@"addrspace" = union_ptr_ty.ptrAddressSpace(),
  22306     });
  22307     const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);
  22308 
  22309     if (initializing and field.ty.zigTypeTag() == .NoReturn) {
  22310         const msg = msg: {
  22311             const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{});
  22312             errdefer msg.destroy(sema.gpa);
  22313 
  22314             try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name});
  22315             try sema.addDeclaredHereNote(msg, union_ty);
  22316             break :msg msg;
  22317         };
  22318         return sema.failWithOwnedErrorMsg(msg);
  22319     }
  22320 
  22321     if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {
  22322         switch (union_obj.layout) {
  22323             .Auto => if (!initializing) {
  22324                 const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse
  22325                     break :ct;
  22326                 if (union_val.isUndef()) {
  22327                     return sema.failWithUseOfUndef(block, src);
  22328                 }
  22329                 const tag_and_val = union_val.castTag(.@"union").?.data;
  22330                 var field_tag_buf: Value.Payload.U32 = .{
  22331                     .base = .{ .tag = .enum_field_index },
  22332                     .data = enum_field_index,
  22333                 };
  22334                 const field_tag = Value.initPayload(&field_tag_buf.base);
  22335                 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
  22336                 if (!tag_matches) {
  22337                     const msg = msg: {
  22338                         const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;
  22339                         const active_field_name = union_obj.tag_ty.enumFieldName(active_index);
  22340                         const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
  22341                         errdefer msg.destroy(sema.gpa);
  22342                         try sema.addDeclaredHereNote(msg, union_ty);
  22343                         break :msg msg;
  22344                     };
  22345                     return sema.failWithOwnedErrorMsg(msg);
  22346                 }
  22347             },
  22348             .Packed, .Extern => {},
  22349         }
  22350         return sema.addConstant(
  22351             ptr_field_ty,
  22352             try Value.Tag.field_ptr.create(arena, .{
  22353                 .container_ptr = union_ptr_val,
  22354                 .container_ty = union_ty,
  22355                 .field_index = field_index,
  22356             }),
  22357         );
  22358     }
  22359 
  22360     try sema.requireRuntimeBlock(block, src, null);
  22361     if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
  22362         union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
  22363     {
  22364         const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
  22365         const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
  22366         // TODO would it be better if get_union_tag supported pointers to unions?
  22367         const union_val = try block.addTyOp(.load, union_ty, union_ptr);
  22368         const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val);
  22369         const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
  22370         try sema.addSafetyCheck(block, ok, .inactive_union_field);
  22371     }
  22372     if (field.ty.zigTypeTag() == .NoReturn) {
  22373         _ = try block.addNoOp(.unreach);
  22374         return Air.Inst.Ref.unreachable_value;
  22375     }
  22376     return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);
  22377 }
  22378 
  22379 fn unionFieldVal(
  22380     sema: *Sema,
  22381     block: *Block,
  22382     src: LazySrcLoc,
  22383     union_byval: Air.Inst.Ref,
  22384     field_name: []const u8,
  22385     field_name_src: LazySrcLoc,
  22386     unresolved_union_ty: Type,
  22387 ) CompileError!Air.Inst.Ref {
  22388     assert(unresolved_union_ty.zigTypeTag() == .Union);
  22389 
  22390     const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);
  22391     const union_obj = union_ty.cast(Type.Payload.Union).?.data;
  22392     const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
  22393     const field = union_obj.fields.values()[field_index];
  22394     const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);
  22395 
  22396     if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| {
  22397         if (union_val.isUndef()) return sema.addConstUndef(field.ty);
  22398 
  22399         const tag_and_val = union_val.castTag(.@"union").?.data;
  22400         var field_tag_buf: Value.Payload.U32 = .{
  22401             .base = .{ .tag = .enum_field_index },
  22402             .data = enum_field_index,
  22403         };
  22404         const field_tag = Value.initPayload(&field_tag_buf.base);
  22405         const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
  22406         switch (union_obj.layout) {
  22407             .Auto => {
  22408                 if (tag_matches) {
  22409                     return sema.addConstant(field.ty, tag_and_val.val);
  22410                 } else {
  22411                     const msg = msg: {
  22412                         const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;
  22413                         const active_field_name = union_obj.tag_ty.enumFieldName(active_index);
  22414                         const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
  22415                         errdefer msg.destroy(sema.gpa);
  22416                         try sema.addDeclaredHereNote(msg, union_ty);
  22417                         break :msg msg;
  22418                     };
  22419                     return sema.failWithOwnedErrorMsg(msg);
  22420                 }
  22421             },
  22422             .Packed, .Extern => {
  22423                 if (tag_matches) {
  22424                     return sema.addConstant(field.ty, tag_and_val.val);
  22425                 } else {
  22426                     const old_ty = union_ty.unionFieldType(tag_and_val.tag, sema.mod);
  22427                     const new_val = try sema.bitCastVal(block, src, tag_and_val.val, old_ty, field.ty, 0);
  22428                     return sema.addConstant(field.ty, new_val);
  22429                 }
  22430             },
  22431         }
  22432     }
  22433 
  22434     try sema.requireRuntimeBlock(block, src, null);
  22435     if (union_obj.layout == .Auto and block.wantSafety() and
  22436         union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
  22437     {
  22438         const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
  22439         const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
  22440         const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval);
  22441         const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
  22442         try sema.addSafetyCheck(block, ok, .inactive_union_field);
  22443     }
  22444     if (field.ty.zigTypeTag() == .NoReturn) {
  22445         _ = try block.addNoOp(.unreach);
  22446         return Air.Inst.Ref.unreachable_value;
  22447     }
  22448     return block.addStructFieldVal(union_byval, field_index, field.ty);
  22449 }
  22450 
  22451 fn elemPtr(
  22452     sema: *Sema,
  22453     block: *Block,
  22454     src: LazySrcLoc,
  22455     indexable_ptr: Air.Inst.Ref,
  22456     elem_index: Air.Inst.Ref,
  22457     elem_index_src: LazySrcLoc,
  22458     init: bool,
  22459 ) CompileError!Air.Inst.Ref {
  22460     const indexable_ptr_src = src; // TODO better source location
  22461     const indexable_ptr_ty = sema.typeOf(indexable_ptr);
  22462     const target = sema.mod.getTarget();
  22463     const indexable_ty = switch (indexable_ptr_ty.zigTypeTag()) {
  22464         .Pointer => indexable_ptr_ty.elemType(),
  22465         else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(sema.mod)}),
  22466     };
  22467     if (!indexable_ty.isIndexable()) {
  22468         return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty.fmt(sema.mod)});
  22469     }
  22470 
  22471     switch (indexable_ty.zigTypeTag()) {
  22472         .Pointer => {
  22473             // In all below cases, we have to deref the ptr operand to get the actual indexable pointer.
  22474             const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src);
  22475             switch (indexable_ty.ptrSize()) {
  22476                 .Slice => return sema.elemPtrSlice(block, src, indexable_ptr_src, indexable, elem_index_src, elem_index),
  22477                 .Many, .C => {
  22478                     const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_ptr_src, indexable);
  22479                     const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
  22480                     const runtime_src = rs: {
  22481                         const ptr_val = maybe_ptr_val orelse break :rs indexable_ptr_src;
  22482                         const index_val = maybe_index_val orelse break :rs elem_index_src;
  22483                         const index = @intCast(usize, index_val.toUnsignedInt(target));
  22484                         const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, sema.mod);
  22485                         const result_ty = try sema.elemPtrType(indexable_ty, index);
  22486                         return sema.addConstant(result_ty, elem_ptr);
  22487                     };
  22488                     const result_ty = try sema.elemPtrType(indexable_ty, null);
  22489 
  22490                     try sema.requireRuntimeBlock(block, src, runtime_src);
  22491                     return block.addPtrElemPtr(indexable, elem_index, result_ty);
  22492                 },
  22493                 .One => {
  22494                     assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
  22495                     return sema.elemPtrArray(block, src, indexable_ptr_src, indexable, elem_index_src, elem_index, init);
  22496                 },
  22497             }
  22498         },
  22499         .Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init),
  22500         .Struct => {
  22501             // Tuple field access.
  22502             const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime known");
  22503             const index = @intCast(u32, index_val.toUnsignedInt(target));
  22504             return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init);
  22505         },
  22506         else => unreachable,
  22507     }
  22508 }
  22509 
  22510 fn elemVal(
  22511     sema: *Sema,
  22512     block: *Block,
  22513     src: LazySrcLoc,
  22514     indexable: Air.Inst.Ref,
  22515     elem_index_uncasted: Air.Inst.Ref,
  22516     elem_index_src: LazySrcLoc,
  22517 ) CompileError!Air.Inst.Ref {
  22518     const indexable_src = src; // TODO better source location
  22519     const indexable_ty = sema.typeOf(indexable);
  22520     const target = sema.mod.getTarget();
  22521 
  22522     if (!indexable_ty.isIndexable()) {
  22523         return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty.fmt(sema.mod)});
  22524     }
  22525 
  22526     // TODO in case of a vector of pointers, we need to detect whether the element
  22527     // index is a scalar or vector instead of unconditionally casting to usize.
  22528     const elem_index = try sema.coerce(block, Type.usize, elem_index_uncasted, elem_index_src);
  22529 
  22530     switch (indexable_ty.zigTypeTag()) {
  22531         .Pointer => switch (indexable_ty.ptrSize()) {
  22532             .Slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index),
  22533             .Many, .C => {
  22534                 const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable);
  22535                 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
  22536 
  22537                 const runtime_src = rs: {
  22538                     const indexable_val = maybe_indexable_val orelse break :rs indexable_src;
  22539                     const index_val = maybe_index_val orelse break :rs elem_index_src;
  22540                     const index = @intCast(usize, index_val.toUnsignedInt(target));
  22541                     const elem_ptr_val = try indexable_val.elemPtr(indexable_ty, sema.arena, index, sema.mod);
  22542                     if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, indexable_ty)) |elem_val| {
  22543                         return sema.addConstant(indexable_ty.elemType2(), elem_val);
  22544                     }
  22545                     break :rs indexable_src;
  22546                 };
  22547 
  22548                 try sema.requireRuntimeBlock(block, src, runtime_src);
  22549                 return block.addBinOp(.ptr_elem_val, indexable, elem_index);
  22550             },
  22551             .One => {
  22552                 assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
  22553                 const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false);
  22554                 return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src);
  22555             },
  22556         },
  22557         .Array => return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index),
  22558         .Vector => {
  22559             // TODO: If the index is a vector, the result should be a vector.
  22560             return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index);
  22561         },
  22562         .Struct => {
  22563             // Tuple field access.
  22564             const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime known");
  22565             const index = @intCast(u32, index_val.toUnsignedInt(target));
  22566             return tupleField(sema, block, indexable_src, indexable, elem_index_src, index);
  22567         },
  22568         else => unreachable,
  22569     }
  22570 }
  22571 
  22572 fn validateRuntimeElemAccess(
  22573     sema: *Sema,
  22574     block: *Block,
  22575     elem_index_src: LazySrcLoc,
  22576     elem_ty: Type,
  22577     parent_ty: Type,
  22578     parent_src: LazySrcLoc,
  22579 ) CompileError!void {
  22580     const valid_rt = try sema.validateRunTimeType(block, elem_index_src, elem_ty, false);
  22581     if (!valid_rt) {
  22582         const msg = msg: {
  22583             const msg = try sema.errMsg(
  22584                 block,
  22585                 elem_index_src,
  22586                 "values of type '{}' must be comptime known, but index value is runtime known",
  22587                 .{parent_ty.fmt(sema.mod)},
  22588             );
  22589             errdefer msg.destroy(sema.gpa);
  22590 
  22591             const src_decl = sema.mod.declPtr(block.src_decl);
  22592             try sema.explainWhyTypeIsComptime(block, elem_index_src, msg, parent_src.toSrcLoc(src_decl), parent_ty);
  22593 
  22594             break :msg msg;
  22595         };
  22596         return sema.failWithOwnedErrorMsg(msg);
  22597     }
  22598 }
  22599 
  22600 fn tupleFieldPtr(
  22601     sema: *Sema,
  22602     block: *Block,
  22603     tuple_ptr_src: LazySrcLoc,
  22604     tuple_ptr: Air.Inst.Ref,
  22605     field_index_src: LazySrcLoc,
  22606     field_index: u32,
  22607     init: bool,
  22608 ) CompileError!Air.Inst.Ref {
  22609     const tuple_ptr_ty = sema.typeOf(tuple_ptr);
  22610     const tuple_ty = tuple_ptr_ty.childType();
  22611     const tuple_fields = tuple_ty.tupleFields();
  22612 
  22613     if (tuple_fields.types.len == 0) {
  22614         return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{});
  22615     }
  22616 
  22617     if (field_index >= tuple_fields.types.len) {
  22618         return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{
  22619             field_index, tuple_fields.types.len,
  22620         });
  22621     }
  22622 
  22623     const field_ty = tuple_fields.types[field_index];
  22624     const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{
  22625         .pointee_type = field_ty,
  22626         .mutable = tuple_ptr_ty.ptrIsMutable(),
  22627         .@"volatile" = tuple_ptr_ty.isVolatilePtr(),
  22628         .@"addrspace" = tuple_ptr_ty.ptrAddressSpace(),
  22629     });
  22630 
  22631     if (tuple_ty.structFieldValueComptime(field_index)) |default_val| {
  22632         const val = try Value.Tag.comptime_field_ptr.create(sema.arena, .{
  22633             .field_ty = field_ty,
  22634             .field_val = default_val,
  22635         });
  22636         return sema.addConstant(ptr_field_ty, val);
  22637     }
  22638 
  22639     if (try sema.resolveMaybeUndefVal(block, tuple_ptr_src, tuple_ptr)) |tuple_ptr_val| {
  22640         return sema.addConstant(
  22641             ptr_field_ty,
  22642             try Value.Tag.field_ptr.create(sema.arena, .{
  22643                 .container_ptr = tuple_ptr_val,
  22644                 .container_ty = tuple_ty,
  22645                 .field_index = field_index,
  22646             }),
  22647         );
  22648     }
  22649 
  22650     if (!init) {
  22651         try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_ptr_src);
  22652     }
  22653 
  22654     try sema.requireRuntimeBlock(block, tuple_ptr_src, null);
  22655     return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty);
  22656 }
  22657 
  22658 fn tupleField(
  22659     sema: *Sema,
  22660     block: *Block,
  22661     tuple_src: LazySrcLoc,
  22662     tuple: Air.Inst.Ref,
  22663     field_index_src: LazySrcLoc,
  22664     field_index: u32,
  22665 ) CompileError!Air.Inst.Ref {
  22666     const tuple_ty = sema.typeOf(tuple);
  22667     const tuple_fields = tuple_ty.tupleFields();
  22668 
  22669     if (tuple_fields.types.len == 0) {
  22670         return sema.fail(block, tuple_src, "indexing into empty tuple is not allowed", .{});
  22671     }
  22672 
  22673     if (field_index >= tuple_fields.types.len) {
  22674         return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{
  22675             field_index, tuple_fields.types.len,
  22676         });
  22677     }
  22678 
  22679     const field_ty = tuple_fields.types[field_index];
  22680     const field_val = tuple_fields.values[field_index];
  22681 
  22682     if (field_val.tag() != .unreachable_value) {
  22683         return sema.addConstant(field_ty, field_val); // comptime field
  22684     }
  22685 
  22686     if (try sema.resolveMaybeUndefVal(block, tuple_src, tuple)) |tuple_val| {
  22687         if (tuple_val.isUndef()) return sema.addConstUndef(field_ty);
  22688         return sema.addConstant(field_ty, tuple_val.fieldValue(tuple_ty, field_index));
  22689     }
  22690 
  22691     try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
  22692 
  22693     try sema.requireRuntimeBlock(block, tuple_src, null);
  22694     return block.addStructFieldVal(tuple, field_index, field_ty);
  22695 }
  22696 
  22697 fn elemValArray(
  22698     sema: *Sema,
  22699     block: *Block,
  22700     src: LazySrcLoc,
  22701     array_src: LazySrcLoc,
  22702     array: Air.Inst.Ref,
  22703     elem_index_src: LazySrcLoc,
  22704     elem_index: Air.Inst.Ref,
  22705 ) CompileError!Air.Inst.Ref {
  22706     const array_ty = sema.typeOf(array);
  22707     const array_sent = array_ty.sentinel();
  22708     const array_len = array_ty.arrayLen();
  22709     const array_len_s = array_len + @boolToInt(array_sent != null);
  22710     const elem_ty = array_ty.childType();
  22711 
  22712     if (array_len_s == 0) {
  22713         return sema.fail(block, array_src, "indexing into empty array is not allowed", .{});
  22714     }
  22715 
  22716     const maybe_undef_array_val = try sema.resolveMaybeUndefVal(block, array_src, array);
  22717     // index must be defined since it can access out of bounds
  22718     const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
  22719     const target = sema.mod.getTarget();
  22720 
  22721     if (maybe_index_val) |index_val| {
  22722         const index = @intCast(usize, index_val.toUnsignedInt(target));
  22723         if (array_sent) |s| {
  22724             if (index == array_len) {
  22725                 return sema.addConstant(elem_ty, s);
  22726             }
  22727         }
  22728         if (index >= array_len_s) {
  22729             const sentinel_label: []const u8 = if (array_sent != null) " +1 (sentinel)" else "";
  22730             return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label });
  22731         }
  22732     }
  22733     if (maybe_undef_array_val) |array_val| {
  22734         if (array_val.isUndef()) {
  22735             return sema.addConstUndef(elem_ty);
  22736         }
  22737         if (maybe_index_val) |index_val| {
  22738             const index = @intCast(usize, index_val.toUnsignedInt(target));
  22739             const elem_val = try array_val.elemValue(sema.mod, sema.arena, index);
  22740             return sema.addConstant(elem_ty, elem_val);
  22741         }
  22742     }
  22743 
  22744     try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src);
  22745 
  22746     const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src;
  22747     try sema.requireRuntimeBlock(block, src, runtime_src);
  22748     if (block.wantSafety()) {
  22749         // Runtime check is only needed if unable to comptime check
  22750         if (maybe_index_val == null) {
  22751             const len_inst = try sema.addIntUnsigned(Type.usize, array_len);
  22752             const cmp_op: Air.Inst.Tag = if (array_sent != null) .cmp_lte else .cmp_lt;
  22753             try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op);
  22754         }
  22755     }
  22756     return block.addBinOp(.array_elem_val, array, elem_index);
  22757 }
  22758 
  22759 fn elemPtrArray(
  22760     sema: *Sema,
  22761     block: *Block,
  22762     src: LazySrcLoc,
  22763     array_ptr_src: LazySrcLoc,
  22764     array_ptr: Air.Inst.Ref,
  22765     elem_index_src: LazySrcLoc,
  22766     elem_index: Air.Inst.Ref,
  22767     init: bool,
  22768 ) CompileError!Air.Inst.Ref {
  22769     const target = sema.mod.getTarget();
  22770     const array_ptr_ty = sema.typeOf(array_ptr);
  22771     const array_ty = array_ptr_ty.childType();
  22772     const array_sent = array_ty.sentinel() != null;
  22773     const array_len = array_ty.arrayLen();
  22774     const array_len_s = array_len + @boolToInt(array_sent);
  22775 
  22776     if (array_len_s == 0) {
  22777         return sema.fail(block, array_ptr_src, "indexing into empty array is not allowed", .{});
  22778     }
  22779 
  22780     const maybe_undef_array_ptr_val = try sema.resolveMaybeUndefVal(block, array_ptr_src, array_ptr);
  22781     // The index must not be undefined since it can be out of bounds.
  22782     const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
  22783         const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(target));
  22784         if (index >= array_len_s) {
  22785             const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else "";
  22786             return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label });
  22787         }
  22788         break :o index;
  22789     } else null;
  22790 
  22791     const elem_ptr_ty = try sema.elemPtrType(array_ptr_ty, offset);
  22792 
  22793     if (maybe_undef_array_ptr_val) |array_ptr_val| {
  22794         if (array_ptr_val.isUndef()) {
  22795             return sema.addConstUndef(elem_ptr_ty);
  22796         }
  22797         if (offset) |index| {
  22798             const elem_ptr = try array_ptr_val.elemPtr(array_ptr_ty, sema.arena, index, sema.mod);
  22799             return sema.addConstant(elem_ptr_ty, elem_ptr);
  22800         }
  22801     }
  22802 
  22803     if (!init) {
  22804         try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(), array_ty, array_ptr_src);
  22805     }
  22806 
  22807     const runtime_src = if (maybe_undef_array_ptr_val != null) elem_index_src else array_ptr_src;
  22808     try sema.requireRuntimeBlock(block, src, runtime_src);
  22809 
  22810     // Runtime check is only needed if unable to comptime check.
  22811     if (block.wantSafety() and offset == null) {
  22812         const len_inst = try sema.addIntUnsigned(Type.usize, array_len);
  22813         const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt;
  22814         try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op);
  22815     }
  22816 
  22817     return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty);
  22818 }
  22819 
  22820 fn elemValSlice(
  22821     sema: *Sema,
  22822     block: *Block,
  22823     src: LazySrcLoc,
  22824     slice_src: LazySrcLoc,
  22825     slice: Air.Inst.Ref,
  22826     elem_index_src: LazySrcLoc,
  22827     elem_index: Air.Inst.Ref,
  22828 ) CompileError!Air.Inst.Ref {
  22829     const slice_ty = sema.typeOf(slice);
  22830     const slice_sent = slice_ty.sentinel() != null;
  22831     const elem_ty = slice_ty.elemType2();
  22832     var runtime_src = slice_src;
  22833 
  22834     // slice must be defined since it can dereferenced as null
  22835     const maybe_slice_val = try sema.resolveDefinedValue(block, slice_src, slice);
  22836     // index must be defined since it can index out of bounds
  22837     const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
  22838     const target = sema.mod.getTarget();
  22839 
  22840     if (maybe_slice_val) |slice_val| {
  22841         runtime_src = elem_index_src;
  22842         const slice_len = slice_val.sliceLen(sema.mod);
  22843         const slice_len_s = slice_len + @boolToInt(slice_sent);
  22844         if (slice_len_s == 0) {
  22845             return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
  22846         }
  22847         if (maybe_index_val) |index_val| {
  22848             const index = @intCast(usize, index_val.toUnsignedInt(target));
  22849             if (index >= slice_len_s) {
  22850                 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
  22851                 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
  22852             }
  22853             const elem_ptr_val = try slice_val.elemPtr(slice_ty, sema.arena, index, sema.mod);
  22854             if (try sema.pointerDeref(block, slice_src, elem_ptr_val, slice_ty)) |elem_val| {
  22855                 return sema.addConstant(elem_ty, elem_val);
  22856             }
  22857             runtime_src = slice_src;
  22858         }
  22859     }
  22860 
  22861     try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src);
  22862 
  22863     try sema.requireRuntimeBlock(block, src, runtime_src);
  22864     if (block.wantSafety()) {
  22865         const len_inst = if (maybe_slice_val) |slice_val|
  22866             try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod))
  22867         else
  22868             try block.addTyOp(.slice_len, Type.usize, slice);
  22869         const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
  22870         try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op);
  22871     }
  22872     try sema.queueFullTypeResolution(sema.typeOf(slice));
  22873     return block.addBinOp(.slice_elem_val, slice, elem_index);
  22874 }
  22875 
  22876 fn elemPtrSlice(
  22877     sema: *Sema,
  22878     block: *Block,
  22879     src: LazySrcLoc,
  22880     slice_src: LazySrcLoc,
  22881     slice: Air.Inst.Ref,
  22882     elem_index_src: LazySrcLoc,
  22883     elem_index: Air.Inst.Ref,
  22884 ) CompileError!Air.Inst.Ref {
  22885     const target = sema.mod.getTarget();
  22886     const slice_ty = sema.typeOf(slice);
  22887     const slice_sent = slice_ty.sentinel() != null;
  22888 
  22889     const maybe_undef_slice_val = try sema.resolveMaybeUndefVal(block, slice_src, slice);
  22890     // The index must not be undefined since it can be out of bounds.
  22891     const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
  22892         const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(target));
  22893         break :o index;
  22894     } else null;
  22895 
  22896     const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset);
  22897 
  22898     if (maybe_undef_slice_val) |slice_val| {
  22899         if (slice_val.isUndef()) {
  22900             return sema.addConstUndef(elem_ptr_ty);
  22901         }
  22902         const slice_len = slice_val.sliceLen(sema.mod);
  22903         const slice_len_s = slice_len + @boolToInt(slice_sent);
  22904         if (slice_len_s == 0) {
  22905             return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
  22906         }
  22907         if (offset) |index| {
  22908             if (index >= slice_len_s) {
  22909                 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
  22910                 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
  22911             }
  22912             const elem_ptr_val = try slice_val.elemPtr(slice_ty, sema.arena, index, sema.mod);
  22913             return sema.addConstant(elem_ptr_ty, elem_ptr_val);
  22914         }
  22915     }
  22916 
  22917     try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ptr_ty, slice_ty, slice_src);
  22918 
  22919     const runtime_src = if (maybe_undef_slice_val != null) elem_index_src else slice_src;
  22920     try sema.requireRuntimeBlock(block, src, runtime_src);
  22921     if (block.wantSafety()) {
  22922         const len_inst = len: {
  22923             if (maybe_undef_slice_val) |slice_val|
  22924                 if (!slice_val.isUndef())
  22925                     break :len try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod));
  22926             break :len try block.addTyOp(.slice_len, Type.usize, slice);
  22927         };
  22928         const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
  22929         try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op);
  22930     }
  22931     return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty);
  22932 }
  22933 
  22934 fn coerce(
  22935     sema: *Sema,
  22936     block: *Block,
  22937     dest_ty_unresolved: Type,
  22938     inst: Air.Inst.Ref,
  22939     inst_src: LazySrcLoc,
  22940 ) CompileError!Air.Inst.Ref {
  22941     return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, .{}) catch |err| switch (err) {
  22942         error.NotCoercible => unreachable,
  22943         else => |e| return e,
  22944     };
  22945 }
  22946 
  22947 const CoersionError = CompileError || error{
  22948     /// When coerce is called recursively, this error should be returned instead of using `fail`
  22949     /// to ensure correct types in compile errors.
  22950     NotCoercible,
  22951 };
  22952 
  22953 const CoerceOpts = struct {
  22954     /// Should coerceExtra emit error messages.
  22955     report_err: bool = true,
  22956     /// Ignored if `report_err == false`.
  22957     is_ret: bool = false,
  22958     /// Should coercion to comptime_int ermit an error message.
  22959     no_cast_to_comptime_int: bool = false,
  22960 };
  22961 
  22962 fn coerceExtra(
  22963     sema: *Sema,
  22964     block: *Block,
  22965     dest_ty_unresolved: Type,
  22966     inst: Air.Inst.Ref,
  22967     inst_src: LazySrcLoc,
  22968     opts: CoerceOpts,
  22969 ) CoersionError!Air.Inst.Ref {
  22970     switch (dest_ty_unresolved.tag()) {
  22971         .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src),
  22972         .generic_poison => return inst,
  22973         else => {},
  22974     }
  22975     const dest_ty_src = inst_src; // TODO better source location
  22976     const dest_ty = try sema.resolveTypeFields(block, dest_ty_src, dest_ty_unresolved);
  22977     const inst_ty = try sema.resolveTypeFields(block, inst_src, sema.typeOf(inst));
  22978     const target = sema.mod.getTarget();
  22979     // If the types are the same, we can return the operand.
  22980     if (dest_ty.eql(inst_ty, sema.mod))
  22981         return inst;
  22982 
  22983     const arena = sema.arena;
  22984     const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst);
  22985 
  22986     var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
  22987     if (in_memory_result == .ok) {
  22988         if (maybe_inst_val) |val| {
  22989             // Keep the comptime Value representation; take the new type.
  22990             return sema.addConstant(dest_ty, val);
  22991         }
  22992         try sema.requireRuntimeBlock(block, inst_src, null);
  22993         return block.addBitCast(dest_ty, inst);
  22994     }
  22995 
  22996     const is_undef = if (maybe_inst_val) |val| val.isUndef() else false;
  22997 
  22998     switch (dest_ty.zigTypeTag()) {
  22999         .Optional => optional: {
  23000             // undefined sets the optional bit also to undefined.
  23001             if (is_undef) {
  23002                 return sema.addConstUndef(dest_ty);
  23003             }
  23004 
  23005             // null to ?T
  23006             if (inst_ty.zigTypeTag() == .Null) {
  23007                 return sema.addConstant(dest_ty, Value.@"null");
  23008             }
  23009 
  23010             // cast from ?*T and ?[*]T to ?*anyopaque
  23011             // but don't do it if the source type is a double pointer
  23012             if (dest_ty.isPtrLikeOptional() and dest_ty.elemType2().tag() == .anyopaque and
  23013                 inst_ty.isPtrLikeOptional() and inst_ty.elemType2().zigTypeTag() != .Pointer)
  23014             {
  23015                 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional;
  23016                 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
  23017             }
  23018 
  23019             // T to ?T
  23020             const child_type = try dest_ty.optionalChildAlloc(sema.arena);
  23021             const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
  23022                 error.NotCoercible => {
  23023                     if (in_memory_result == .no_match) {
  23024                         // Try to give more useful notes
  23025                         in_memory_result = try sema.coerceInMemoryAllowed(block, child_type, inst_ty, false, target, dest_ty_src, inst_src);
  23026                     }
  23027                     break :optional;
  23028                 },
  23029                 else => |e| return e,
  23030             };
  23031             return try sema.wrapOptional(block, dest_ty, intermediate, inst_src);
  23032         },
  23033         .Pointer => pointer: {
  23034             const dest_info = dest_ty.ptrInfo().data;
  23035 
  23036             // Function body to function pointer.
  23037             if (inst_ty.zigTypeTag() == .Fn) {
  23038                 const fn_val = try sema.resolveConstValue(block, .unneeded, inst, undefined);
  23039                 const fn_decl = fn_val.pointerDecl().?;
  23040                 const inst_as_ptr = try sema.analyzeDeclRef(fn_decl);
  23041                 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);
  23042             }
  23043 
  23044             // *T to *[1]T
  23045             single_item: {
  23046                 if (dest_info.size != .One) break :single_item;
  23047                 if (!inst_ty.isSinglePointer()) break :single_item;
  23048                 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
  23049                 const ptr_elem_ty = inst_ty.childType();
  23050                 const array_ty = dest_info.pointee_type;
  23051                 if (array_ty.zigTypeTag() != .Array) break :single_item;
  23052                 const array_elem_ty = array_ty.childType();
  23053                 const dest_is_mut = dest_info.mutable;
  23054                 switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
  23055                     .ok => {},
  23056                     else => break :single_item,
  23057                 }
  23058                 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
  23059             }
  23060 
  23061             // Coercions where the source is a single pointer to an array.
  23062             src_array_ptr: {
  23063                 if (!inst_ty.isSinglePointer()) break :src_array_ptr;
  23064                 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
  23065                 const array_ty = inst_ty.childType();
  23066                 if (array_ty.zigTypeTag() != .Array) break :src_array_ptr;
  23067                 const array_elem_type = array_ty.childType();
  23068                 const dest_is_mut = dest_info.mutable;
  23069 
  23070                 const dst_elem_type = dest_info.pointee_type;
  23071                 const elem_res = try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src);
  23072                 switch (elem_res) {
  23073                     .ok => {},
  23074                     else => {
  23075                         in_memory_result = .{ .ptr_child = .{
  23076                             .child = try elem_res.dupe(sema.arena),
  23077                             .actual = array_elem_type,
  23078                             .wanted = dst_elem_type,
  23079                         } };
  23080                         break :src_array_ptr;
  23081                     },
  23082                 }
  23083 
  23084                 if (dest_info.sentinel) |dest_sent| {
  23085                     if (array_ty.sentinel()) |inst_sent| {
  23086                         if (!dest_sent.eql(inst_sent, dst_elem_type, sema.mod)) {
  23087                             in_memory_result = .{ .ptr_sentinel = .{
  23088                                 .actual = inst_sent,
  23089                                 .wanted = dest_sent,
  23090                                 .ty = dst_elem_type,
  23091                             } };
  23092                             break :src_array_ptr;
  23093                         }
  23094                     } else {
  23095                         in_memory_result = .{ .ptr_sentinel = .{
  23096                             .actual = Value.initTag(.unreachable_value),
  23097                             .wanted = dest_sent,
  23098                             .ty = dst_elem_type,
  23099                         } };
  23100                         break :src_array_ptr;
  23101                     }
  23102                 }
  23103 
  23104                 switch (dest_info.size) {
  23105                     .Slice => {
  23106                         // *[N]T to []T
  23107                         return sema.coerceArrayPtrToSlice(block, dest_ty, inst, inst_src);
  23108                     },
  23109                     .C => {
  23110                         // *[N]T to [*c]T
  23111                         return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
  23112                     },
  23113                     .Many => {
  23114                         // *[N]T to [*]T
  23115                         return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
  23116                     },
  23117                     .One => {},
  23118                 }
  23119             }
  23120 
  23121             // coercion from C pointer
  23122             if (inst_ty.isCPtr()) src_c_ptr: {
  23123                 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :src_c_ptr;
  23124                 // In this case we must add a safety check because the C pointer
  23125                 // could be null.
  23126                 const src_elem_ty = inst_ty.childType();
  23127                 const dest_is_mut = dest_info.mutable;
  23128                 const dst_elem_type = dest_info.pointee_type;
  23129                 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
  23130                     .ok => {},
  23131                     else => break :src_c_ptr,
  23132                 }
  23133                 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
  23134             }
  23135 
  23136             // cast from *T and [*]T to *anyopaque
  23137             // but don't do it if the source type is a double pointer
  23138             if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer and
  23139                 inst_ty.childType().zigTypeTag() != .Pointer and sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
  23140             {
  23141                 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
  23142             }
  23143 
  23144             switch (dest_info.size) {
  23145                 // coercion to C pointer
  23146                 .C => switch (inst_ty.zigTypeTag()) {
  23147                     .Null => {
  23148                         return sema.addConstant(dest_ty, Value.@"null");
  23149                     },
  23150                     .ComptimeInt => {
  23151                         const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
  23152                             error.NotCoercible => break :pointer,
  23153                             else => |e| return e,
  23154                         };
  23155                         return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
  23156                     },
  23157                     .Int => {
  23158                         const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) {
  23159                             .signed => Type.isize,
  23160                             .unsigned => Type.usize,
  23161                         };
  23162                         const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
  23163                             error.NotCoercible => {
  23164                                 // Try to give more useful notes
  23165                                 in_memory_result = try sema.coerceInMemoryAllowed(block, ptr_size_ty, inst_ty, false, target, dest_ty_src, inst_src);
  23166                                 break :pointer;
  23167                             },
  23168                             else => |e| return e,
  23169                         };
  23170                         return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
  23171                     },
  23172                     .Pointer => p: {
  23173                         if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p;
  23174                         const inst_info = inst_ty.ptrInfo().data;
  23175                         switch (try sema.coerceInMemoryAllowed(
  23176                             block,
  23177                             dest_info.pointee_type,
  23178                             inst_info.pointee_type,
  23179                             dest_info.mutable,
  23180                             target,
  23181                             dest_ty_src,
  23182                             inst_src,
  23183                         )) {
  23184                             .ok => {},
  23185                             else => break :p,
  23186                         }
  23187                         if (inst_info.size == .Slice) {
  23188                             if (dest_info.sentinel == null or inst_info.sentinel == null or
  23189                                 !dest_info.sentinel.?.eql(inst_info.sentinel.?, dest_info.pointee_type, sema.mod))
  23190                                 break :p;
  23191 
  23192                             const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty);
  23193                             return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src);
  23194                         }
  23195                         return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
  23196                     },
  23197                     else => {},
  23198                 },
  23199                 .One => switch (dest_info.pointee_type.zigTypeTag()) {
  23200                     .Union => {
  23201                         // pointer to anonymous struct to pointer to union
  23202                         if (inst_ty.isSinglePointer() and
  23203                             inst_ty.childType().isAnonStruct() and
  23204                             sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
  23205                         {
  23206                             return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
  23207                         }
  23208                     },
  23209                     .Struct => {
  23210                         // pointer to anonymous struct to pointer to struct
  23211                         if (inst_ty.isSinglePointer() and
  23212                             inst_ty.childType().isAnonStruct() and
  23213                             sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
  23214                         {
  23215                             return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
  23216                         }
  23217                     },
  23218                     .Array => {
  23219                         // pointer to tuple to pointer to array
  23220                         if (inst_ty.isSinglePointer() and
  23221                             inst_ty.childType().isTuple() and
  23222                             sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
  23223                         {
  23224                             return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
  23225                         }
  23226                     },
  23227                     else => {},
  23228                 },
  23229                 .Slice => {
  23230                     // pointer to tuple to slice
  23231                     if (inst_ty.isSinglePointer() and inst_ty.childType().isTuple() and dest_info.size == .Slice and
  23232                         sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
  23233                     {
  23234                         return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
  23235                     }
  23236 
  23237                     // empty tuple to zero-length slice
  23238                     // note that this allows coercing to a mutable slice.
  23239                     if (inst_ty.isSinglePointer() and
  23240                         inst_ty.childType().tag() == .empty_struct_literal and
  23241                         dest_info.size == .Slice)
  23242                     {
  23243                         const slice_val = try Value.Tag.slice.create(sema.arena, .{
  23244                             .ptr = Value.undef,
  23245                             .len = Value.zero,
  23246                         });
  23247                         return sema.addConstant(dest_ty, slice_val);
  23248                     }
  23249 
  23250                     if (inst_ty.zigTypeTag() == .Array) {
  23251                         return sema.fail(
  23252                             block,
  23253                             inst_src,
  23254                             "array literal requires address-of operator (&) to coerce to slice type '{}'",
  23255                             .{dest_ty.fmt(sema.mod)},
  23256                         );
  23257                     }
  23258                 },
  23259                 .Many => p: {
  23260                     if (!inst_ty.isSlice()) break :p;
  23261                     if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p;
  23262                     const inst_info = inst_ty.ptrInfo().data;
  23263 
  23264                     switch (try sema.coerceInMemoryAllowed(
  23265                         block,
  23266                         dest_info.pointee_type,
  23267                         inst_info.pointee_type,
  23268                         dest_info.mutable,
  23269                         target,
  23270                         dest_ty_src,
  23271                         inst_src,
  23272                     )) {
  23273                         .ok => {},
  23274                         else => break :p,
  23275                     }
  23276 
  23277                     if (dest_info.sentinel == null or inst_info.sentinel == null or
  23278                         !dest_info.sentinel.?.eql(inst_info.sentinel.?, dest_info.pointee_type, sema.mod))
  23279                         break :p;
  23280 
  23281                     const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty);
  23282                     return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src);
  23283                 },
  23284             }
  23285         },
  23286         .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {
  23287             .Float, .ComptimeFloat => float: {
  23288                 const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse {
  23289                     if (dest_ty.zigTypeTag() == .ComptimeInt) {
  23290                         if (!opts.report_err) return error.NotCoercible;
  23291                         return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime known");
  23292                     }
  23293                     break :float;
  23294                 };
  23295 
  23296                 if (val.floatHasFraction()) {
  23297                     return sema.fail(
  23298                         block,
  23299                         inst_src,
  23300                         "fractional component prevents float value '{}' from coercion to type '{}'",
  23301                         .{ val.fmtValue(inst_ty, sema.mod), dest_ty.fmt(sema.mod) },
  23302                     );
  23303                 }
  23304                 const result_val = try sema.floatToInt(block, inst_src, val, inst_ty, dest_ty);
  23305                 return try sema.addConstant(dest_ty, result_val);
  23306             },
  23307             .Int, .ComptimeInt => {
  23308                 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
  23309                     // comptime known integer to other number
  23310                     if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) {
  23311                         if (!opts.report_err) return error.NotCoercible;
  23312                         return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
  23313                     }
  23314                     return try sema.addConstant(dest_ty, val);
  23315                 }
  23316                 if (dest_ty.zigTypeTag() == .ComptimeInt) {
  23317                     if (!opts.report_err) return error.NotCoercible;
  23318                     if (opts.no_cast_to_comptime_int) return inst;
  23319                     return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime known");
  23320                 }
  23321 
  23322                 // integer widening
  23323                 const dst_info = dest_ty.intInfo(target);
  23324                 const src_info = inst_ty.intInfo(target);
  23325                 if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or
  23326                     // small enough unsigned ints can get casted to large enough signed ints
  23327                     (dst_info.signedness == .signed and dst_info.bits > src_info.bits))
  23328                 {
  23329                     try sema.requireRuntimeBlock(block, inst_src, null);
  23330                     return block.addTyOp(.intcast, dest_ty, inst);
  23331                 }
  23332             },
  23333             .Undefined => {
  23334                 return sema.addConstUndef(dest_ty);
  23335             },
  23336             else => {},
  23337         },
  23338         .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag()) {
  23339             .ComptimeFloat => {
  23340                 const val = try sema.resolveConstValue(block, .unneeded, inst, undefined);
  23341                 const result_val = try val.floatCast(sema.arena, dest_ty, target);
  23342                 return try sema.addConstant(dest_ty, result_val);
  23343             },
  23344             .Float => {
  23345                 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
  23346                     const result_val = try val.floatCast(sema.arena, dest_ty, target);
  23347                     if (!val.eql(result_val, dest_ty, sema.mod)) {
  23348                         return sema.fail(
  23349                             block,
  23350                             inst_src,
  23351                             "type '{}' cannot represent float value '{}'",
  23352                             .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) },
  23353                         );
  23354                     }
  23355                     return try sema.addConstant(dest_ty, result_val);
  23356                 } else if (dest_ty.zigTypeTag() == .ComptimeFloat) {
  23357                     if (!opts.report_err) return error.NotCoercible;
  23358                     return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime known");
  23359                 }
  23360 
  23361                 // float widening
  23362                 const src_bits = inst_ty.floatBits(target);
  23363                 const dst_bits = dest_ty.floatBits(target);
  23364                 if (dst_bits >= src_bits) {
  23365                     try sema.requireRuntimeBlock(block, inst_src, null);
  23366                     return block.addTyOp(.fpext, dest_ty, inst);
  23367                 }
  23368             },
  23369             .Int, .ComptimeInt => int: {
  23370                 const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse {
  23371                     if (dest_ty.zigTypeTag() == .ComptimeFloat) {
  23372                         if (!opts.report_err) return error.NotCoercible;
  23373                         return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime known");
  23374                     }
  23375                     break :int;
  23376                 };
  23377                 const result_val = try val.intToFloatAdvanced(sema.arena, inst_ty, dest_ty, target, sema.kit(block, inst_src));
  23378                 // TODO implement this compile error
  23379                 //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty);
  23380                 //if (!int_again_val.eql(val, inst_ty, mod)) {
  23381                 //    return sema.fail(
  23382                 //        block,
  23383                 //        inst_src,
  23384                 //        "type '{}' cannot represent integer value '{}'",
  23385                 //        .{ dest_ty.fmt(sema.mod), val },
  23386                 //    );
  23387                 //}
  23388                 return try sema.addConstant(dest_ty, result_val);
  23389             },
  23390             .Undefined => {
  23391                 return sema.addConstUndef(dest_ty);
  23392             },
  23393             else => {},
  23394         },
  23395         .Enum => switch (inst_ty.zigTypeTag()) {
  23396             .EnumLiteral => {
  23397                 // enum literal to enum
  23398                 const val = try sema.resolveConstValue(block, .unneeded, inst, undefined);
  23399                 const bytes = val.castTag(.enum_literal).?.data;
  23400                 const field_index = dest_ty.enumFieldIndex(bytes) orelse {
  23401                     const msg = msg: {
  23402                         const msg = try sema.errMsg(
  23403                             block,
  23404                             inst_src,
  23405                             "no field named '{s}' in enum '{}'",
  23406                             .{ bytes, dest_ty.fmt(sema.mod) },
  23407                         );
  23408                         errdefer msg.destroy(sema.gpa);
  23409                         try sema.addDeclaredHereNote(msg, dest_ty);
  23410                         break :msg msg;
  23411                     };
  23412                     return sema.failWithOwnedErrorMsg(msg);
  23413                 };
  23414                 return sema.addConstant(
  23415                     dest_ty,
  23416                     try Value.Tag.enum_field_index.create(arena, @intCast(u32, field_index)),
  23417                 );
  23418             },
  23419             .Union => blk: {
  23420                 // union to its own tag type
  23421                 const union_tag_ty = inst_ty.unionTagType() orelse break :blk;
  23422                 if (union_tag_ty.eql(dest_ty, sema.mod)) {
  23423                     return sema.unionToTag(block, dest_ty, inst, inst_src);
  23424                 }
  23425             },
  23426             .Undefined => {
  23427                 return sema.addConstUndef(dest_ty);
  23428             },
  23429             else => {},
  23430         },
  23431         .ErrorUnion => switch (inst_ty.zigTypeTag()) {
  23432             .ErrorUnion => eu: {
  23433                 if (maybe_inst_val) |inst_val| {
  23434                     switch (inst_val.tag()) {
  23435                         .undef => return sema.addConstUndef(dest_ty),
  23436                         .eu_payload => {
  23437                             const payload = try sema.addConstant(
  23438                                 inst_ty.errorUnionPayload(),
  23439                                 inst_val.castTag(.eu_payload).?.data,
  23440                             );
  23441                             return sema.wrapErrorUnionPayload(block, dest_ty, payload, inst_src) catch |err| switch (err) {
  23442                                 error.NotCoercible => break :eu,
  23443                                 else => |e| return e,
  23444                             };
  23445                         },
  23446                         else => {
  23447                             const error_set = try sema.addConstant(
  23448                                 inst_ty.errorUnionSet(),
  23449                                 inst_val,
  23450                             );
  23451                             return sema.wrapErrorUnionSet(block, dest_ty, error_set, inst_src);
  23452                         },
  23453                     }
  23454                 }
  23455             },
  23456             .ErrorSet => {
  23457                 // E to E!T
  23458                 return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);
  23459             },
  23460             .Undefined => {
  23461                 return sema.addConstUndef(dest_ty);
  23462             },
  23463             else => eu: {
  23464                 // T to E!T
  23465                 return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src) catch |err| switch (err) {
  23466                     error.NotCoercible => break :eu,
  23467                     else => |e| return e,
  23468                 };
  23469             },
  23470         },
  23471         .Union => switch (inst_ty.zigTypeTag()) {
  23472             .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src),
  23473             .Struct => {
  23474                 if (inst_ty.isAnonStruct()) {
  23475                     return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);
  23476                 }
  23477             },
  23478             .Undefined => {
  23479                 return sema.addConstUndef(dest_ty);
  23480             },
  23481             else => {},
  23482         },
  23483         .Array => switch (inst_ty.zigTypeTag()) {
  23484             .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
  23485             .Struct => {
  23486                 if (inst == .empty_struct) {
  23487                     return sema.arrayInitEmpty(block, inst_src, dest_ty);
  23488                 }
  23489                 if (inst_ty.isTuple()) {
  23490                     return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
  23491                 }
  23492             },
  23493             .Undefined => {
  23494                 return sema.addConstUndef(dest_ty);
  23495             },
  23496             else => {},
  23497         },
  23498         .Vector => switch (inst_ty.zigTypeTag()) {
  23499             .Array, .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
  23500             .Struct => {
  23501                 if (inst_ty.isTuple()) {
  23502                     return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
  23503                 }
  23504             },
  23505             .Undefined => {
  23506                 return sema.addConstUndef(dest_ty);
  23507             },
  23508             else => {},
  23509         },
  23510         .Struct => {
  23511             if (inst == .empty_struct) {
  23512                 return sema.structInitEmpty(block, dest_ty, dest_ty_src, inst_src);
  23513             }
  23514             if (inst_ty.isTupleOrAnonStruct()) {
  23515                 return sema.coerceTupleToStruct(block, dest_ty, dest_ty_src, inst, inst_src);
  23516             }
  23517         },
  23518         else => {},
  23519     }
  23520 
  23521     // undefined to anything. We do this after the big switch above so that
  23522     // special logic has a chance to run first, such as `*[N]T` to `[]T` which
  23523     // should initialize the length field of the slice.
  23524     if (is_undef) {
  23525         return sema.addConstUndef(dest_ty);
  23526     }
  23527 
  23528     if (!opts.report_err) return error.NotCoercible;
  23529 
  23530     if (opts.is_ret and dest_ty.zigTypeTag() == .NoReturn) {
  23531         const msg = msg: {
  23532             const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{});
  23533             errdefer msg.destroy(sema.gpa);
  23534 
  23535             const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
  23536             const src_decl = sema.mod.declPtr(sema.func.?.owner_decl);
  23537             try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "'noreturn' declared here", .{});
  23538             break :msg msg;
  23539         };
  23540         return sema.failWithOwnedErrorMsg(msg);
  23541     }
  23542 
  23543     const msg = msg: {
  23544         const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) });
  23545         errdefer msg.destroy(sema.gpa);
  23546 
  23547         // E!T to T
  23548         if (inst_ty.zigTypeTag() == .ErrorUnion and
  23549             (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
  23550         {
  23551             try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{});
  23552             try sema.errNote(block, inst_src, msg, "consider using `try`, `catch`, or `if`", .{});
  23553         }
  23554 
  23555         // ?T to T
  23556         var buf: Type.Payload.ElemType = undefined;
  23557         if (inst_ty.zigTypeTag() == .Optional and
  23558             (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(&buf), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
  23559         {
  23560             try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{});
  23561             try sema.errNote(block, inst_src, msg, "consider using `.?`, `orelse`, or `if`", .{});
  23562         }
  23563 
  23564         try in_memory_result.report(sema, block, inst_src, msg);
  23565 
  23566         // Add notes about function return type
  23567         if (opts.is_ret and sema.mod.test_functions.get(sema.func.?.owner_decl) == null) {
  23568             const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
  23569             const src_decl = sema.mod.declPtr(sema.func.?.owner_decl);
  23570             if (inst_ty.isError() and !dest_ty.isError()) {
  23571                 try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function cannot return an error", .{});
  23572             } else {
  23573                 try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function return type declared here", .{});
  23574             }
  23575         }
  23576 
  23577         // TODO maybe add "cannot store an error in type '{}'" note
  23578 
  23579         break :msg msg;
  23580     };
  23581     return sema.failWithOwnedErrorMsg(msg);
  23582 }
  23583 
  23584 const InMemoryCoercionResult = union(enum) {
  23585     ok,
  23586     no_match: Pair,
  23587     int_not_coercible: Int,
  23588     error_union_payload: PairAndChild,
  23589     array_len: IntPair,
  23590     array_sentinel: Sentinel,
  23591     array_elem: PairAndChild,
  23592     vector_len: IntPair,
  23593     vector_elem: PairAndChild,
  23594     optional_shape: Pair,
  23595     optional_child: PairAndChild,
  23596     from_anyerror,
  23597     missing_error: []const []const u8,
  23598     /// true if wanted is var args
  23599     fn_var_args: bool,
  23600     /// true if wanted is generic
  23601     fn_generic: bool,
  23602     fn_param_count: IntPair,
  23603     fn_param_noalias: IntPair,
  23604     fn_param_comptime: ComptimeParam,
  23605     fn_param: Param,
  23606     fn_cc: CC,
  23607     fn_return_type: PairAndChild,
  23608     ptr_child: PairAndChild,
  23609     ptr_addrspace: AddressSpace,
  23610     ptr_sentinel: Sentinel,
  23611     ptr_size: Size,
  23612     ptr_qualifiers: Qualifiers,
  23613     ptr_allowzero: Pair,
  23614     ptr_bit_range: BitRange,
  23615     ptr_alignment: IntPair,
  23616 
  23617     const Pair = struct {
  23618         actual: Type,
  23619         wanted: Type,
  23620     };
  23621 
  23622     const PairAndChild = struct {
  23623         child: *InMemoryCoercionResult,
  23624         actual: Type,
  23625         wanted: Type,
  23626     };
  23627 
  23628     const Param = struct {
  23629         child: *InMemoryCoercionResult,
  23630         actual: Type,
  23631         wanted: Type,
  23632         index: u64,
  23633     };
  23634 
  23635     const ComptimeParam = struct {
  23636         index: u64,
  23637         wanted: bool,
  23638     };
  23639 
  23640     const Sentinel = struct {
  23641         // unreachable_value indicates no sentinel
  23642         actual: Value,
  23643         wanted: Value,
  23644         ty: Type,
  23645     };
  23646 
  23647     const Int = struct {
  23648         actual_signedness: std.builtin.Signedness,
  23649         wanted_signedness: std.builtin.Signedness,
  23650         actual_bits: u16,
  23651         wanted_bits: u16,
  23652     };
  23653 
  23654     const IntPair = struct {
  23655         actual: u64,
  23656         wanted: u64,
  23657     };
  23658 
  23659     const Size = struct {
  23660         actual: std.builtin.Type.Pointer.Size,
  23661         wanted: std.builtin.Type.Pointer.Size,
  23662     };
  23663 
  23664     const Qualifiers = struct {
  23665         actual_const: bool,
  23666         wanted_const: bool,
  23667         actual_volatile: bool,
  23668         wanted_volatile: bool,
  23669     };
  23670 
  23671     const AddressSpace = struct {
  23672         actual: std.builtin.AddressSpace,
  23673         wanted: std.builtin.AddressSpace,
  23674     };
  23675 
  23676     const CC = struct {
  23677         actual: std.builtin.CallingConvention,
  23678         wanted: std.builtin.CallingConvention,
  23679     };
  23680 
  23681     const BitRange = struct {
  23682         actual_host: u16,
  23683         wanted_host: u16,
  23684         actual_offset: u16,
  23685         wanted_offset: u16,
  23686     };
  23687 
  23688     fn dupe(child: *const InMemoryCoercionResult, arena: Allocator) !*InMemoryCoercionResult {
  23689         const res = try arena.create(InMemoryCoercionResult);
  23690         res.* = child.*;
  23691         return res;
  23692     }
  23693 
  23694     fn report(res: *const InMemoryCoercionResult, sema: *Sema, block: *Block, src: LazySrcLoc, msg: *Module.ErrorMsg) !void {
  23695         var cur = res;
  23696         while (true) switch (cur.*) {
  23697             .ok => unreachable,
  23698             .no_match => |types| {
  23699                 try sema.addDeclaredHereNote(msg, types.wanted);
  23700                 try sema.addDeclaredHereNote(msg, types.actual);
  23701                 break;
  23702             },
  23703             .int_not_coercible => |int| {
  23704                 try sema.errNote(block, src, msg, "{s} {d}-bit int cannot represent all possible {s} {d}-bit values", .{
  23705                     @tagName(int.wanted_signedness), int.wanted_bits, @tagName(int.actual_signedness), int.actual_bits,
  23706                 });
  23707                 break;
  23708             },
  23709             .error_union_payload => |pair| {
  23710                 try sema.errNote(block, src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{
  23711                     pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
  23712                 });
  23713                 cur = pair.child;
  23714             },
  23715             .array_len => |lens| {
  23716                 try sema.errNote(block, src, msg, "array of length {d} cannot cast into an array of length {d}", .{
  23717                     lens.actual, lens.wanted,
  23718                 });
  23719                 break;
  23720             },
  23721             .array_sentinel => |sentinel| {
  23722                 if (sentinel.actual.tag() != .unreachable_value) {
  23723                     try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{
  23724                         sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
  23725                     });
  23726                 } else {
  23727                     try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{
  23728                         sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
  23729                     });
  23730                 }
  23731                 break;
  23732             },
  23733             .array_elem => |pair| {
  23734                 try sema.errNote(block, src, msg, "array element type '{}' cannot cast into array element type '{}'", .{
  23735                     pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
  23736                 });
  23737                 cur = pair.child;
  23738             },
  23739             .vector_len => |lens| {
  23740                 try sema.errNote(block, src, msg, "vector of length {d} cannot cast into a vector of length {d}", .{
  23741                     lens.actual, lens.wanted,
  23742                 });
  23743                 break;
  23744             },
  23745             .vector_elem => |pair| {
  23746                 try sema.errNote(block, src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{
  23747                     pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
  23748                 });
  23749                 cur = pair.child;
  23750             },
  23751             .optional_shape => |pair| {
  23752                 var buf_actual: Type.Payload.ElemType = undefined;
  23753                 var buf_wanted: Type.Payload.ElemType = undefined;
  23754                 try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{
  23755                     pair.actual.optionalChild(&buf_actual).fmt(sema.mod), pair.wanted.optionalChild(&buf_wanted).fmt(sema.mod),
  23756                 });
  23757                 break;
  23758             },
  23759             .optional_child => |pair| {
  23760                 try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{
  23761                     pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
  23762                 });
  23763                 cur = pair.child;
  23764             },
  23765             .from_anyerror => {
  23766                 try sema.errNote(block, src, msg, "global error set cannot cast into a smaller set", .{});
  23767                 break;
  23768             },
  23769             .missing_error => |missing_errors| {
  23770                 for (missing_errors) |err| {
  23771                     try sema.errNote(block, src, msg, "'error.{s}' not a member of destination error set", .{err});
  23772                 }
  23773                 break;
  23774             },
  23775             .fn_var_args => |wanted_var_args| {
  23776                 if (wanted_var_args) {
  23777                     try sema.errNote(block, src, msg, "non-variadic function cannot cast into a variadic function", .{});
  23778                 } else {
  23779                     try sema.errNote(block, src, msg, "variadic function cannot cast into a non-variadic function", .{});
  23780                 }
  23781                 break;
  23782             },
  23783             .fn_generic => |wanted_generic| {
  23784                 if (wanted_generic) {
  23785                     try sema.errNote(block, src, msg, "non-generic function cannot cast into a generic function", .{});
  23786                 } else {
  23787                     try sema.errNote(block, src, msg, "generic function cannot cast into a non-generic function", .{});
  23788                 }
  23789                 break;
  23790             },
  23791             .fn_param_count => |lens| {
  23792                 try sema.errNote(block, src, msg, "function with {d} parameters cannot cast into a function with {d} parameters", .{
  23793                     lens.actual, lens.wanted,
  23794                 });
  23795                 break;
  23796             },
  23797             .fn_param_noalias => |param| {
  23798                 var index: u6 = 0;
  23799                 var actual_noalias = false;
  23800                 while (true) : (index += 1) {
  23801                     const actual = @truncate(u1, param.actual >> index);
  23802                     const wanted = @truncate(u1, param.wanted >> index);
  23803                     if (actual != wanted) {
  23804                         actual_noalias = actual == 1;
  23805                         break;
  23806                     }
  23807                 }
  23808                 if (!actual_noalias) {
  23809                     try sema.errNote(block, src, msg, "regular parameter {d} cannot cast into a noalias parameter", .{index});
  23810                 } else {
  23811                     try sema.errNote(block, src, msg, "noalias parameter {d} cannot cast into a regular parameter", .{index});
  23812                 }
  23813                 break;
  23814             },
  23815             .fn_param_comptime => |param| {
  23816                 if (param.wanted) {
  23817                     try sema.errNote(block, src, msg, "non-comptime parameter {d} cannot cast into a comptime parameter", .{param.index});
  23818                 } else {
  23819                     try sema.errNote(block, src, msg, "comptime parameter {d} cannot cast into a non-comptime parameter", .{param.index});
  23820                 }
  23821                 break;
  23822             },
  23823             .fn_param => |param| {
  23824                 try sema.errNote(block, src, msg, "parameter {d} '{}' cannot cast into '{}'", .{
  23825                     param.index, param.actual.fmt(sema.mod), param.wanted.fmt(sema.mod),
  23826                 });
  23827                 cur = param.child;
  23828             },
  23829             .fn_cc => |cc| {
  23830                 try sema.errNote(block, src, msg, "calling convention {s} cannot cast into calling convention {s}", .{ @tagName(cc.actual), @tagName(cc.wanted) });
  23831                 break;
  23832             },
  23833             .fn_return_type => |pair| {
  23834                 try sema.errNote(block, src, msg, "return type '{}' cannot cast into return type '{}'", .{
  23835                     pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
  23836                 });
  23837                 cur = pair.child;
  23838             },
  23839             .ptr_child => |pair| {
  23840                 try sema.errNote(block, src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{
  23841                     pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
  23842                 });
  23843                 cur = pair.child;
  23844             },
  23845             .ptr_addrspace => |@"addrspace"| {
  23846                 try sema.errNote(block, src, msg, "address space '{s}' cannot cast into address space '{s}'", .{ @tagName(@"addrspace".actual), @tagName(@"addrspace".wanted) });
  23847                 break;
  23848             },
  23849             .ptr_sentinel => |sentinel| {
  23850                 if (sentinel.actual.tag() != .unreachable_value) {
  23851                     try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{
  23852                         sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
  23853                     });
  23854                 } else {
  23855                     try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{
  23856                         sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
  23857                     });
  23858                 }
  23859                 break;
  23860             },
  23861             .ptr_size => |size| {
  23862                 try sema.errNote(block, src, msg, "a {s} pointer cannot cast into a {s} pointer", .{ pointerSizeString(size.actual), pointerSizeString(size.wanted) });
  23863                 break;
  23864             },
  23865             .ptr_qualifiers => |qualifiers| {
  23866                 const ok_const = !qualifiers.actual_const or qualifiers.wanted_const;
  23867                 const ok_volatile = !qualifiers.actual_volatile or qualifiers.wanted_volatile;
  23868                 if (!ok_const) {
  23869                     try sema.errNote(block, src, msg, "cast discards const qualifier", .{});
  23870                 } else if (!ok_volatile) {
  23871                     try sema.errNote(block, src, msg, "cast discards volatile qualifier", .{});
  23872                 }
  23873                 break;
  23874             },
  23875             .ptr_allowzero => |pair| {
  23876                 const wanted_allow_zero = pair.wanted.ptrAllowsZero();
  23877                 const actual_allow_zero = pair.actual.ptrAllowsZero();
  23878                 if (actual_allow_zero and !wanted_allow_zero) {
  23879                     try sema.errNote(block, src, msg, "'{}' could have null values which are illegal in type '{}'", .{
  23880                         pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
  23881                     });
  23882                 } else {
  23883                     try sema.errNote(block, src, msg, "mutable '{}' allows illegal null values stored to type '{}'", .{
  23884                         pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
  23885                     });
  23886                 }
  23887                 break;
  23888             },
  23889             .ptr_bit_range => |bit_range| {
  23890                 if (bit_range.actual_host != bit_range.wanted_host) {
  23891                     try sema.errNote(block, src, msg, "pointer host size '{}' cannot cast into pointer host size '{}'", .{
  23892                         bit_range.actual_host, bit_range.wanted_host,
  23893                     });
  23894                 }
  23895                 if (bit_range.actual_offset != bit_range.wanted_offset) {
  23896                     try sema.errNote(block, src, msg, "pointer bit offset '{}' cannot cast into pointer bit offset '{}'", .{
  23897                         bit_range.actual_offset, bit_range.wanted_offset,
  23898                     });
  23899                 }
  23900                 break;
  23901             },
  23902             .ptr_alignment => |pair| {
  23903                 try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{
  23904                     pair.actual, pair.wanted,
  23905                 });
  23906                 break;
  23907             },
  23908         };
  23909     }
  23910 };
  23911 
  23912 fn pointerSizeString(size: std.builtin.Type.Pointer.Size) []const u8 {
  23913     return switch (size) {
  23914         .One => "single",
  23915         .Many => "many",
  23916         .C => "C",
  23917         .Slice => unreachable,
  23918     };
  23919 }
  23920 
  23921 /// If pointers have the same representation in runtime memory, a bitcast AIR instruction
  23922 /// may be used for the coercion.
  23923 /// * `const` attribute can be gained
  23924 /// * `volatile` attribute can be gained
  23925 /// * `allowzero` attribute can be gained (whether from explicit attribute, C pointer, or optional pointer) but only if !dest_is_mut
  23926 /// * alignment can be decreased
  23927 /// * bit offset attributes must match exactly
  23928 /// * `*`/`[*]` must match exactly, but `[*c]` matches either one
  23929 /// * sentinel-terminated pointers can coerce into `[*]`
  23930 fn coerceInMemoryAllowed(
  23931     sema: *Sema,
  23932     block: *Block,
  23933     dest_ty: Type,
  23934     src_ty: Type,
  23935     dest_is_mut: bool,
  23936     target: std.Target,
  23937     dest_src: LazySrcLoc,
  23938     src_src: LazySrcLoc,
  23939 ) CompileError!InMemoryCoercionResult {
  23940     if (dest_ty.eql(src_ty, sema.mod))
  23941         return .ok;
  23942 
  23943     // Differently-named integers with the same number of bits.
  23944     if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) {
  23945         const dest_info = dest_ty.intInfo(target);
  23946         const src_info = src_ty.intInfo(target);
  23947 
  23948         if (dest_info.signedness == src_info.signedness and
  23949             dest_info.bits == src_info.bits)
  23950         {
  23951             return .ok;
  23952         }
  23953 
  23954         if ((src_info.signedness == dest_info.signedness and dest_info.bits < src_info.bits) or
  23955             // small enough unsigned ints can get casted to large enough signed ints
  23956             (dest_info.signedness == .signed and (src_info.signedness == .unsigned or dest_info.bits <= src_info.bits)) or
  23957             (dest_info.signedness == .unsigned and src_info.signedness == .signed))
  23958         {
  23959             return InMemoryCoercionResult{ .int_not_coercible = .{
  23960                 .actual_signedness = src_info.signedness,
  23961                 .wanted_signedness = dest_info.signedness,
  23962                 .actual_bits = src_info.bits,
  23963                 .wanted_bits = dest_info.bits,
  23964             } };
  23965         }
  23966     }
  23967 
  23968     // Differently-named floats with the same number of bits.
  23969     if (dest_ty.zigTypeTag() == .Float and src_ty.zigTypeTag() == .Float) {
  23970         const dest_bits = dest_ty.floatBits(target);
  23971         const src_bits = src_ty.floatBits(target);
  23972         if (dest_bits == src_bits) {
  23973             return .ok;
  23974         }
  23975     }
  23976 
  23977     // Pointers / Pointer-like Optionals
  23978     var dest_buf: Type.Payload.ElemType = undefined;
  23979     var src_buf: Type.Payload.ElemType = undefined;
  23980     const maybe_dest_ptr_ty = try sema.typePtrOrOptionalPtrTy(block, dest_ty, &dest_buf, dest_src);
  23981     const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(block, src_ty, &src_buf, src_src);
  23982     if (maybe_dest_ptr_ty) |dest_ptr_ty| {
  23983         if (maybe_src_ptr_ty) |src_ptr_ty| {
  23984             return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target, dest_src, src_src);
  23985         }
  23986     }
  23987 
  23988     // Slices
  23989     if (dest_ty.isSlice() and src_ty.isSlice()) {
  23990         return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src);
  23991     }
  23992 
  23993     const dest_tag = dest_ty.zigTypeTag();
  23994     const src_tag = src_ty.zigTypeTag();
  23995 
  23996     // Functions
  23997     if (dest_tag == .Fn and src_tag == .Fn) {
  23998         return try sema.coerceInMemoryAllowedFns(block, dest_ty, src_ty, target, dest_src, src_src);
  23999     }
  24000 
  24001     // Error Unions
  24002     if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) {
  24003         const dest_payload = dest_ty.errorUnionPayload();
  24004         const src_payload = src_ty.errorUnionPayload();
  24005         const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src);
  24006         if (child != .ok) {
  24007             return InMemoryCoercionResult{ .error_union_payload = .{
  24008                 .child = try child.dupe(sema.arena),
  24009                 .actual = src_payload,
  24010                 .wanted = dest_payload,
  24011             } };
  24012         }
  24013         return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target, dest_src, src_src);
  24014     }
  24015 
  24016     // Error Sets
  24017     if (dest_tag == .ErrorSet and src_tag == .ErrorSet) {
  24018         return try sema.coerceInMemoryAllowedErrorSets(block, dest_ty, src_ty, dest_src, src_src);
  24019     }
  24020 
  24021     // Arrays
  24022     if (dest_tag == .Array and src_tag == .Array) {
  24023         const dest_info = dest_ty.arrayInfo();
  24024         const src_info = src_ty.arrayInfo();
  24025         if (dest_info.len != src_info.len) {
  24026             return InMemoryCoercionResult{ .array_len = .{
  24027                 .actual = src_info.len,
  24028                 .wanted = dest_info.len,
  24029             } };
  24030         }
  24031 
  24032         const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src);
  24033         if (child != .ok) {
  24034             return InMemoryCoercionResult{ .array_elem = .{
  24035                 .child = try child.dupe(sema.arena),
  24036                 .actual = src_info.elem_type,
  24037                 .wanted = dest_info.elem_type,
  24038             } };
  24039         }
  24040         const ok_sent = dest_info.sentinel == null or
  24041             (src_info.sentinel != null and
  24042             dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, sema.mod));
  24043         if (!ok_sent) {
  24044             return InMemoryCoercionResult{ .array_sentinel = .{
  24045                 .actual = src_info.sentinel orelse Value.initTag(.unreachable_value),
  24046                 .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value),
  24047                 .ty = dest_info.elem_type,
  24048             } };
  24049         }
  24050         return .ok;
  24051     }
  24052 
  24053     // Vectors
  24054     if (dest_tag == .Vector and src_tag == .Vector) {
  24055         const dest_len = dest_ty.vectorLen();
  24056         const src_len = src_ty.vectorLen();
  24057         if (dest_len != src_len) {
  24058             return InMemoryCoercionResult{ .vector_len = .{
  24059                 .actual = src_len,
  24060                 .wanted = dest_len,
  24061             } };
  24062         }
  24063 
  24064         const dest_elem_ty = dest_ty.scalarType();
  24065         const src_elem_ty = src_ty.scalarType();
  24066         const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src);
  24067         if (child != .ok) {
  24068             return InMemoryCoercionResult{ .vector_elem = .{
  24069                 .child = try child.dupe(sema.arena),
  24070                 .actual = src_elem_ty,
  24071                 .wanted = dest_elem_ty,
  24072             } };
  24073         }
  24074 
  24075         return .ok;
  24076     }
  24077 
  24078     // Optionals
  24079     if (dest_tag == .Optional and src_tag == .Optional) {
  24080         if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) {
  24081             return InMemoryCoercionResult{ .optional_shape = .{
  24082                 .actual = src_ty,
  24083                 .wanted = dest_ty,
  24084             } };
  24085         }
  24086         const dest_child_type = dest_ty.optionalChild(&dest_buf);
  24087         const src_child_type = src_ty.optionalChild(&src_buf);
  24088 
  24089         const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src);
  24090         if (child != .ok) {
  24091             return InMemoryCoercionResult{ .optional_child = .{
  24092                 .child = try child.dupe(sema.arena),
  24093                 .actual = try src_child_type.copy(sema.arena),
  24094                 .wanted = try dest_child_type.copy(sema.arena),
  24095             } };
  24096         }
  24097 
  24098         return .ok;
  24099     }
  24100 
  24101     return InMemoryCoercionResult{ .no_match = .{
  24102         .actual = dest_ty,
  24103         .wanted = src_ty,
  24104     } };
  24105 }
  24106 
  24107 fn coerceInMemoryAllowedErrorSets(
  24108     sema: *Sema,
  24109     block: *Block,
  24110     dest_ty: Type,
  24111     src_ty: Type,
  24112     dest_src: LazySrcLoc,
  24113     src_src: LazySrcLoc,
  24114 ) !InMemoryCoercionResult {
  24115     // Coercion to `anyerror`. Note that this check can return false negatives
  24116     // in case the error sets did not get resolved.
  24117     if (dest_ty.isAnyError()) {
  24118         return .ok;
  24119     }
  24120 
  24121     if (dest_ty.castTag(.error_set_inferred)) |dst_payload| {
  24122         const dst_ies = dst_payload.data;
  24123         // We will make an effort to return `ok` without resolving either error set, to
  24124         // avoid unnecessary "unable to resolve error set" dependency loop errors.
  24125         switch (src_ty.tag()) {
  24126             .error_set_inferred => {
  24127                 // If both are inferred error sets of functions, and
  24128                 // the dest includes the source function, the coercion is OK.
  24129                 // This check is important because it works without forcing a full resolution
  24130                 // of inferred error sets.
  24131                 const src_ies = src_ty.castTag(.error_set_inferred).?.data;
  24132 
  24133                 if (dst_ies.inferred_error_sets.contains(src_ies)) {
  24134                     return .ok;
  24135                 }
  24136             },
  24137             .error_set_single => {
  24138                 const name = src_ty.castTag(.error_set_single).?.data;
  24139                 if (dst_ies.errors.contains(name)) return .ok;
  24140             },
  24141             .error_set_merged => {
  24142                 const names = src_ty.castTag(.error_set_merged).?.data.keys();
  24143                 for (names) |name| {
  24144                     if (!dst_ies.errors.contains(name)) break;
  24145                 } else return .ok;
  24146             },
  24147             .error_set => {
  24148                 const names = src_ty.castTag(.error_set).?.data.names.keys();
  24149                 for (names) |name| {
  24150                     if (!dst_ies.errors.contains(name)) break;
  24151                 } else return .ok;
  24152             },
  24153             .anyerror => {},
  24154             else => unreachable,
  24155         }
  24156 
  24157         if (dst_ies.func == sema.owner_func) {
  24158             // We are trying to coerce an error set to the current function's
  24159             // inferred error set.
  24160             try dst_ies.addErrorSet(sema.gpa, src_ty);
  24161             return .ok;
  24162         }
  24163 
  24164         try sema.resolveInferredErrorSet(block, dest_src, dst_payload.data);
  24165         // isAnyError might have changed from a false negative to a true positive after resolution.
  24166         if (dest_ty.isAnyError()) {
  24167             return .ok;
  24168         }
  24169     }
  24170 
  24171     var missing_error_buf = std.ArrayList([]const u8).init(sema.gpa);
  24172     defer missing_error_buf.deinit();
  24173 
  24174     switch (src_ty.tag()) {
  24175         .error_set_inferred => {
  24176             const src_data = src_ty.castTag(.error_set_inferred).?.data;
  24177 
  24178             try sema.resolveInferredErrorSet(block, src_src, src_data);
  24179             // src anyerror status might have changed after the resolution.
  24180             if (src_ty.isAnyError()) {
  24181                 // dest_ty.isAnyError() == true is already checked for at this point.
  24182                 return .from_anyerror;
  24183             }
  24184 
  24185             for (src_data.errors.keys()) |key| {
  24186                 if (!dest_ty.errorSetHasField(key)) {
  24187                     try missing_error_buf.append(key);
  24188                 }
  24189             }
  24190 
  24191             if (missing_error_buf.items.len != 0) {
  24192                 return InMemoryCoercionResult{
  24193                     .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items),
  24194                 };
  24195             }
  24196 
  24197             return .ok;
  24198         },
  24199         .error_set_single => {
  24200             const name = src_ty.castTag(.error_set_single).?.data;
  24201             if (dest_ty.errorSetHasField(name)) {
  24202                 return .ok;
  24203             }
  24204             const list = try sema.arena.alloc([]const u8, 1);
  24205             list[0] = name;
  24206             return InMemoryCoercionResult{ .missing_error = list };
  24207         },
  24208         .error_set_merged => {
  24209             const names = src_ty.castTag(.error_set_merged).?.data.keys();
  24210             for (names) |name| {
  24211                 if (!dest_ty.errorSetHasField(name)) {
  24212                     try missing_error_buf.append(name);
  24213                 }
  24214             }
  24215 
  24216             if (missing_error_buf.items.len != 0) {
  24217                 return InMemoryCoercionResult{
  24218                     .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items),
  24219                 };
  24220             }
  24221 
  24222             return .ok;
  24223         },
  24224         .error_set => {
  24225             const names = src_ty.castTag(.error_set).?.data.names.keys();
  24226             for (names) |name| {
  24227                 if (!dest_ty.errorSetHasField(name)) {
  24228                     try missing_error_buf.append(name);
  24229                 }
  24230             }
  24231 
  24232             if (missing_error_buf.items.len != 0) {
  24233                 return InMemoryCoercionResult{
  24234                     .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items),
  24235                 };
  24236             }
  24237 
  24238             return .ok;
  24239         },
  24240         .anyerror => switch (dest_ty.tag()) {
  24241             .error_set_inferred => unreachable, // Caught by dest_ty.isAnyError() above.
  24242             .error_set_single, .error_set_merged, .error_set => return .from_anyerror,
  24243             .anyerror => unreachable, // Filtered out above.
  24244             else => unreachable,
  24245         },
  24246         else => unreachable,
  24247     }
  24248 
  24249     unreachable;
  24250 }
  24251 
  24252 fn coerceInMemoryAllowedFns(
  24253     sema: *Sema,
  24254     block: *Block,
  24255     dest_ty: Type,
  24256     src_ty: Type,
  24257     target: std.Target,
  24258     dest_src: LazySrcLoc,
  24259     src_src: LazySrcLoc,
  24260 ) !InMemoryCoercionResult {
  24261     const dest_info = dest_ty.fnInfo();
  24262     const src_info = src_ty.fnInfo();
  24263 
  24264     if (dest_info.is_var_args != src_info.is_var_args) {
  24265         return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args };
  24266     }
  24267 
  24268     if (dest_info.is_generic != src_info.is_generic) {
  24269         return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };
  24270     }
  24271 
  24272     if (dest_info.cc != src_info.cc) {
  24273         return InMemoryCoercionResult{ .fn_cc = .{
  24274             .actual = src_info.cc,
  24275             .wanted = dest_info.cc,
  24276         } };
  24277     }
  24278 
  24279     if (!src_info.return_type.isNoReturn()) {
  24280         const rt = try sema.coerceInMemoryAllowed(block, dest_info.return_type, src_info.return_type, false, target, dest_src, src_src);
  24281         if (rt != .ok) {
  24282             return InMemoryCoercionResult{ .fn_return_type = .{
  24283                 .child = try rt.dupe(sema.arena),
  24284                 .actual = src_info.return_type,
  24285                 .wanted = dest_info.return_type,
  24286             } };
  24287         }
  24288     }
  24289 
  24290     if (dest_info.param_types.len != src_info.param_types.len) {
  24291         return InMemoryCoercionResult{ .fn_param_count = .{
  24292             .actual = dest_info.param_types.len,
  24293             .wanted = dest_info.param_types.len,
  24294         } };
  24295     }
  24296 
  24297     if (dest_info.noalias_bits != src_info.noalias_bits) {
  24298         return InMemoryCoercionResult{ .fn_param_noalias = .{
  24299             .actual = src_info.noalias_bits,
  24300             .wanted = dest_info.noalias_bits,
  24301         } };
  24302     }
  24303 
  24304     for (dest_info.param_types) |dest_param_ty, i| {
  24305         const src_param_ty = src_info.param_types[i];
  24306 
  24307         if (dest_info.comptime_params[i] != src_info.comptime_params[i]) {
  24308             return InMemoryCoercionResult{ .fn_param_comptime = .{
  24309                 .index = i,
  24310                 .wanted = dest_info.comptime_params[i],
  24311             } };
  24312         }
  24313 
  24314         // Note: Cast direction is reversed here.
  24315         const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src);
  24316         if (param != .ok) {
  24317             return InMemoryCoercionResult{ .fn_param = .{
  24318                 .child = try param.dupe(sema.arena),
  24319                 .actual = src_param_ty,
  24320                 .wanted = dest_param_ty,
  24321                 .index = i,
  24322             } };
  24323         }
  24324     }
  24325 
  24326     return .ok;
  24327 }
  24328 
  24329 fn coerceInMemoryAllowedPtrs(
  24330     sema: *Sema,
  24331     block: *Block,
  24332     dest_ty: Type,
  24333     src_ty: Type,
  24334     dest_ptr_ty: Type,
  24335     src_ptr_ty: Type,
  24336     dest_is_mut: bool,
  24337     target: std.Target,
  24338     dest_src: LazySrcLoc,
  24339     src_src: LazySrcLoc,
  24340 ) !InMemoryCoercionResult {
  24341     const dest_info = dest_ptr_ty.ptrInfo().data;
  24342     const src_info = src_ptr_ty.ptrInfo().data;
  24343 
  24344     const ok_ptr_size = src_info.size == dest_info.size or
  24345         src_info.size == .C or dest_info.size == .C;
  24346     if (!ok_ptr_size) {
  24347         return InMemoryCoercionResult{ .ptr_size = .{
  24348             .actual = src_info.size,
  24349             .wanted = dest_info.size,
  24350         } };
  24351     }
  24352 
  24353     const ok_cv_qualifiers =
  24354         (src_info.mutable or !dest_info.mutable) and
  24355         (!src_info.@"volatile" or dest_info.@"volatile");
  24356 
  24357     if (!ok_cv_qualifiers) {
  24358         return InMemoryCoercionResult{ .ptr_qualifiers = .{
  24359             .actual_const = !src_info.mutable,
  24360             .wanted_const = !dest_info.mutable,
  24361             .actual_volatile = src_info.@"volatile",
  24362             .wanted_volatile = dest_info.@"volatile",
  24363         } };
  24364     }
  24365 
  24366     if (dest_info.@"addrspace" != src_info.@"addrspace") {
  24367         return InMemoryCoercionResult{ .ptr_addrspace = .{
  24368             .actual = src_info.@"addrspace",
  24369             .wanted = dest_info.@"addrspace",
  24370         } };
  24371     }
  24372 
  24373     const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src);
  24374     if (child != .ok) {
  24375         return InMemoryCoercionResult{ .ptr_child = .{
  24376             .child = try child.dupe(sema.arena),
  24377             .actual = src_info.pointee_type,
  24378             .wanted = dest_info.pointee_type,
  24379         } };
  24380     }
  24381 
  24382     const dest_allow_zero = dest_ty.ptrAllowsZero();
  24383     const src_allow_zero = src_ty.ptrAllowsZero();
  24384 
  24385     const ok_allows_zero = (dest_allow_zero and
  24386         (src_allow_zero or !dest_is_mut)) or
  24387         (!dest_allow_zero and !src_allow_zero);
  24388     if (!ok_allows_zero) {
  24389         return InMemoryCoercionResult{ .ptr_allowzero = .{
  24390             .actual = src_ty,
  24391             .wanted = dest_ty,
  24392         } };
  24393     }
  24394 
  24395     if (src_info.host_size != dest_info.host_size or
  24396         src_info.bit_offset != dest_info.bit_offset)
  24397     {
  24398         return InMemoryCoercionResult{ .ptr_bit_range = .{
  24399             .actual_host = src_info.host_size,
  24400             .wanted_host = dest_info.host_size,
  24401             .actual_offset = src_info.bit_offset,
  24402             .wanted_offset = dest_info.bit_offset,
  24403         } };
  24404     }
  24405 
  24406     const ok_sent = dest_info.sentinel == null or src_info.size == .C or
  24407         (src_info.sentinel != null and
  24408         dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod));
  24409     if (!ok_sent) {
  24410         return InMemoryCoercionResult{ .ptr_sentinel = .{
  24411             .actual = src_info.sentinel orelse Value.initTag(.unreachable_value),
  24412             .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value),
  24413             .ty = dest_info.pointee_type,
  24414         } };
  24415     }
  24416 
  24417     // If both pointers have alignment 0, it means they both want ABI alignment.
  24418     // In this case, if they share the same child type, no need to resolve
  24419     // pointee type alignment. Otherwise both pointee types must have their alignment
  24420     // resolved and we compare the alignment numerically.
  24421     alignment: {
  24422         if (src_info.@"align" == 0 and dest_info.@"align" == 0 and
  24423             dest_info.pointee_type.eql(src_info.pointee_type, sema.mod))
  24424         {
  24425             break :alignment;
  24426         }
  24427 
  24428         const src_align = if (src_info.@"align" != 0)
  24429             src_info.@"align"
  24430         else
  24431             src_info.pointee_type.abiAlignment(target);
  24432 
  24433         const dest_align = if (dest_info.@"align" != 0)
  24434             dest_info.@"align"
  24435         else
  24436             dest_info.pointee_type.abiAlignment(target);
  24437 
  24438         if (dest_align > src_align) {
  24439             return InMemoryCoercionResult{ .ptr_alignment = .{
  24440                 .actual = src_align,
  24441                 .wanted = dest_align,
  24442             } };
  24443         }
  24444 
  24445         break :alignment;
  24446     }
  24447 
  24448     return .ok;
  24449 }
  24450 
  24451 fn coerceVarArgParam(
  24452     sema: *Sema,
  24453     block: *Block,
  24454     inst: Air.Inst.Ref,
  24455     inst_src: LazySrcLoc,
  24456 ) !Air.Inst.Ref {
  24457     if (block.is_typeof) return inst;
  24458 
  24459     const coerced = switch (sema.typeOf(inst).zigTypeTag()) {
  24460         // TODO consider casting to c_int/f64 if they fit
  24461         .ComptimeInt, .ComptimeFloat => return sema.fail(
  24462             block,
  24463             inst_src,
  24464             "integer and float literals passed variadic function must be casted to a fixed-size number type",
  24465             .{},
  24466         ),
  24467         .Fn => blk: {
  24468             const fn_val = try sema.resolveConstValue(block, .unneeded, inst, undefined);
  24469             const fn_decl = fn_val.pointerDecl().?;
  24470             break :blk try sema.analyzeDeclRef(fn_decl);
  24471         },
  24472         .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}),
  24473         else => inst,
  24474     };
  24475 
  24476     const coerced_ty = sema.typeOf(coerced);
  24477     if (!try sema.validateExternType(block, inst_src, coerced_ty, .other)) {
  24478         const msg = msg: {
  24479             const msg = try sema.errMsg(block, inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(sema.mod)});
  24480             errdefer msg.destroy(sema.gpa);
  24481 
  24482             const src_decl = sema.mod.declPtr(block.src_decl);
  24483             try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl), coerced_ty, .other);
  24484 
  24485             try sema.addDeclaredHereNote(msg, coerced_ty);
  24486             break :msg msg;
  24487         };
  24488         return sema.failWithOwnedErrorMsg(msg);
  24489     }
  24490     return coerced;
  24491 }
  24492 
  24493 // TODO migrate callsites to use storePtr2 instead.
  24494 fn storePtr(
  24495     sema: *Sema,
  24496     block: *Block,
  24497     src: LazySrcLoc,
  24498     ptr: Air.Inst.Ref,
  24499     uncasted_operand: Air.Inst.Ref,
  24500 ) CompileError!void {
  24501     return sema.storePtr2(block, src, ptr, src, uncasted_operand, src, .store);
  24502 }
  24503 
  24504 fn storePtr2(
  24505     sema: *Sema,
  24506     block: *Block,
  24507     src: LazySrcLoc,
  24508     ptr: Air.Inst.Ref,
  24509     ptr_src: LazySrcLoc,
  24510     uncasted_operand: Air.Inst.Ref,
  24511     operand_src: LazySrcLoc,
  24512     air_tag: Air.Inst.Tag,
  24513 ) CompileError!void {
  24514     const ptr_ty = sema.typeOf(ptr);
  24515     if (ptr_ty.isConstPtr())
  24516         return sema.fail(block, ptr_src, "cannot assign to constant", .{});
  24517 
  24518     const elem_ty = ptr_ty.childType();
  24519 
  24520     // To generate better code for tuples, we detect a tuple operand here, and
  24521     // analyze field loads and stores directly. This avoids an extra allocation + memcpy
  24522     // which would occur if we used `coerce`.
  24523     // However, we avoid this mechanism if the destination element type is a tuple,
  24524     // because the regular store will be better for this case.
  24525     // If the destination type is a struct we don't want this mechanism to trigger, because
  24526     // this code does not handle tuple-to-struct coercion which requires dealing with missing
  24527     // fields.
  24528     const operand_ty = sema.typeOf(uncasted_operand);
  24529     if (operand_ty.isTuple() and elem_ty.zigTypeTag() == .Array) {
  24530         const tuple = operand_ty.tupleFields();
  24531         for (tuple.types) |_, i_usize| {
  24532             const i = @intCast(u32, i_usize);
  24533             const elem_src = operand_src; // TODO better source location
  24534             const elem = try tupleField(sema, block, operand_src, uncasted_operand, elem_src, i);
  24535             const elem_index = try sema.addIntUnsigned(Type.usize, i);
  24536             const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src, false);
  24537             try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store);
  24538         }
  24539         return;
  24540     }
  24541 
  24542     // TODO do the same thing for anon structs as for tuples above.
  24543     // However, beware of the need to handle missing/extra fields.
  24544 
  24545     const is_ret = air_tag == .ret_ptr;
  24546 
  24547     // Detect if we are storing an array operand to a bitcasted vector pointer.
  24548     // If so, we instead reach through the bitcasted pointer to the vector pointer,
  24549     // bitcast the array operand to a vector, and then lower this as a store of
  24550     // a vector value to a vector pointer. This generally results in better code,
  24551     // as well as working around an LLVM bug:
  24552     // https://github.com/ziglang/zig/issues/11154
  24553     if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| {
  24554         const vector_ty = sema.typeOf(vector_ptr).childType();
  24555         const vector = sema.coerceExtra(block, vector_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) {
  24556             error.NotCoercible => unreachable,
  24557             else => |e| return e,
  24558         };
  24559         try sema.storePtr2(block, src, vector_ptr, ptr_src, vector, operand_src, .store);
  24560         return;
  24561     }
  24562 
  24563     const operand = sema.coerceExtra(block, elem_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) {
  24564         error.NotCoercible => unreachable,
  24565         else => |e| return e,
  24566     };
  24567     const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand);
  24568 
  24569     const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
  24570         const operand_val = maybe_operand_val orelse {
  24571             try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);
  24572             break :rs operand_src;
  24573         };
  24574         if (ptr_val.isComptimeMutablePtr()) {
  24575             try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty);
  24576             return;
  24577         } else break :rs ptr_src;
  24578     } else ptr_src;
  24579 
  24580     // We do this after the possible comptime store above, for the case of field_ptr stores
  24581     // to unions because we want the comptime tag to be set, even if the field type is void.
  24582     if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)
  24583         return;
  24584 
  24585     if (air_tag == .bitcast) {
  24586         // `air_tag == .bitcast` is used as a special case for `zirCoerceResultPtr`
  24587         // to avoid calling `requireRuntimeBlock` for the dummy block.
  24588         _ = try block.addBinOp(.store, ptr, operand);
  24589         return;
  24590     }
  24591 
  24592     if (block.is_comptime) {
  24593         // TODO ideally this would tell why the block is comptime
  24594         return sema.fail(block, ptr_src, "cannot store to runtime value in comptime block", .{});
  24595     }
  24596 
  24597     try sema.requireRuntimeBlock(block, src, runtime_src);
  24598     try sema.queueFullTypeResolution(elem_ty);
  24599     if (is_ret) {
  24600         _ = try block.addBinOp(.store, ptr, operand);
  24601     } else {
  24602         _ = try block.addBinOp(air_tag, ptr, operand);
  24603     }
  24604 }
  24605 
  24606 /// Traverse an arbitrary number of bitcasted pointers and return the underyling vector
  24607 /// pointer. Only if the final element type matches the vector element type, and the
  24608 /// lengths match.
  24609 fn obtainBitCastedVectorPtr(sema: *Sema, ptr: Air.Inst.Ref) ?Air.Inst.Ref {
  24610     const array_ty = sema.typeOf(ptr).childType();
  24611     if (array_ty.zigTypeTag() != .Array) return null;
  24612     var ptr_inst = Air.refToIndex(ptr) orelse return null;
  24613     const air_datas = sema.air_instructions.items(.data);
  24614     const air_tags = sema.air_instructions.items(.tag);
  24615     const prev_ptr = while (air_tags[ptr_inst] == .bitcast) {
  24616         const prev_ptr = air_datas[ptr_inst].ty_op.operand;
  24617         const prev_ptr_ty = sema.typeOf(prev_ptr);
  24618         const prev_ptr_child_ty = switch (prev_ptr_ty.tag()) {
  24619             .single_mut_pointer => prev_ptr_ty.castTag(.single_mut_pointer).?.data,
  24620             .pointer => prev_ptr_ty.castTag(.pointer).?.data.pointee_type,
  24621             else => return null,
  24622         };
  24623         if (prev_ptr_child_ty.zigTypeTag() == .Vector) break prev_ptr;
  24624         ptr_inst = Air.refToIndex(prev_ptr) orelse return null;
  24625     } else return null;
  24626 
  24627     // We have a pointer-to-array and a pointer-to-vector. If the elements and
  24628     // lengths match, return the result.
  24629     const vector_ty = sema.typeOf(prev_ptr).childType();
  24630     if (array_ty.childType().eql(vector_ty.childType(), sema.mod) and
  24631         array_ty.arrayLen() == vector_ty.vectorLen())
  24632     {
  24633         return prev_ptr;
  24634     } else {
  24635         return null;
  24636     }
  24637 }
  24638 
  24639 /// Call when you have Value objects rather than Air instructions, and you want to
  24640 /// assert the store must be done at comptime.
  24641 fn storePtrVal(
  24642     sema: *Sema,
  24643     block: *Block,
  24644     src: LazySrcLoc,
  24645     ptr_val: Value,
  24646     operand_val: Value,
  24647     operand_ty: Type,
  24648 ) !void {
  24649     var mut_kit = try beginComptimePtrMutation(sema, block, src, ptr_val, operand_ty);
  24650     try sema.checkComptimeVarStore(block, src, mut_kit.decl_ref_mut);
  24651 
  24652     switch (mut_kit.pointee) {
  24653         .direct => |val_ptr| {
  24654             if (mut_kit.decl_ref_mut.runtime_index == .comptime_field_ptr) {
  24655                 if (!operand_val.eql(val_ptr.*, operand_ty, sema.mod)) {
  24656                     // TODO use failWithInvalidComptimeFieldStore
  24657                     return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{});
  24658                 }
  24659                 return;
  24660             }
  24661             const arena = mut_kit.beginArena(sema.mod);
  24662             defer mut_kit.finishArena(sema.mod);
  24663 
  24664             val_ptr.* = try operand_val.copy(arena);
  24665         },
  24666         .reinterpret => |reinterpret| {
  24667             const target = sema.mod.getTarget();
  24668             const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(target));
  24669             const buffer = try sema.gpa.alloc(u8, abi_size);
  24670             defer sema.gpa.free(buffer);
  24671             reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, sema.mod, buffer);
  24672             operand_val.writeToMemory(operand_ty, sema.mod, buffer[reinterpret.byte_offset..]);
  24673 
  24674             const arena = mut_kit.beginArena(sema.mod);
  24675             defer mut_kit.finishArena(sema.mod);
  24676 
  24677             reinterpret.val_ptr.* = try Value.readFromMemory(mut_kit.ty, sema.mod, buffer, arena);
  24678         },
  24679         .bad_decl_ty, .bad_ptr_ty => {
  24680             // TODO show the decl declaration site in a note and explain whether the decl
  24681             // or the pointer is the problematic type
  24682             return sema.fail(block, src, "comptime mutation of a reinterpreted pointer requires type '{}' to have a well-defined memory layout", .{mut_kit.ty.fmt(sema.mod)});
  24683         },
  24684     }
  24685 }
  24686 
  24687 const ComptimePtrMutationKit = struct {
  24688     decl_ref_mut: Value.Payload.DeclRefMut.Data,
  24689     pointee: union(enum) {
  24690         /// The pointer type matches the actual comptime Value so a direct
  24691         /// modification is possible.
  24692         direct: *Value,
  24693         /// The largest parent Value containing pointee and having a well-defined memory layout.
  24694         /// This is used for bitcasting, if direct dereferencing failed.
  24695         reinterpret: struct {
  24696             val_ptr: *Value,
  24697             byte_offset: usize,
  24698         },
  24699         /// If the root decl could not be used as parent, this means `ty` is the type that
  24700         /// caused that by not having a well-defined layout.
  24701         /// This one means the Decl that owns the value trying to be modified does not
  24702         /// have a well defined memory layout.
  24703         bad_decl_ty,
  24704         /// If the root decl could not be used as parent, this means `ty` is the type that
  24705         /// caused that by not having a well-defined layout.
  24706         /// This one means the pointer type that is being stored through does not
  24707         /// have a well defined memory layout.
  24708         bad_ptr_ty,
  24709     },
  24710     ty: Type,
  24711     decl_arena: std.heap.ArenaAllocator = undefined,
  24712 
  24713     fn beginArena(self: *ComptimePtrMutationKit, mod: *Module) Allocator {
  24714         const decl = mod.declPtr(self.decl_ref_mut.decl_index);
  24715         self.decl_arena = decl.value_arena.?.promote(mod.gpa);
  24716         return self.decl_arena.allocator();
  24717     }
  24718 
  24719     fn finishArena(self: *ComptimePtrMutationKit, mod: *Module) void {
  24720         const decl = mod.declPtr(self.decl_ref_mut.decl_index);
  24721         decl.value_arena.?.* = self.decl_arena.state;
  24722         self.decl_arena = undefined;
  24723     }
  24724 };
  24725 
  24726 fn beginComptimePtrMutation(
  24727     sema: *Sema,
  24728     block: *Block,
  24729     src: LazySrcLoc,
  24730     ptr_val: Value,
  24731     ptr_elem_ty: Type,
  24732 ) CompileError!ComptimePtrMutationKit {
  24733     const target = sema.mod.getTarget();
  24734     switch (ptr_val.tag()) {
  24735         .decl_ref_mut => {
  24736             const decl_ref_mut = ptr_val.castTag(.decl_ref_mut).?.data;
  24737             const decl = sema.mod.declPtr(decl_ref_mut.decl_index);
  24738             return beginComptimePtrMutationInner(sema, block, src, decl.ty, &decl.val, ptr_elem_ty, decl_ref_mut);
  24739         },
  24740         .comptime_field_ptr => {
  24741             const payload = ptr_val.castTag(.comptime_field_ptr).?.data;
  24742             const duped = try sema.arena.create(Value);
  24743             duped.* = payload.field_val;
  24744             return beginComptimePtrMutationInner(sema, block, src, payload.field_ty, duped, ptr_elem_ty, .{
  24745                 .decl_index = @intToEnum(Module.Decl.Index, 0),
  24746                 .runtime_index = .comptime_field_ptr,
  24747             });
  24748         },
  24749         .elem_ptr => {
  24750             const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
  24751             var parent = try beginComptimePtrMutation(sema, block, src, elem_ptr.array_ptr, elem_ptr.elem_ty);
  24752             switch (parent.pointee) {
  24753                 .direct => |val_ptr| switch (parent.ty.zigTypeTag()) {
  24754                     .Array, .Vector => {
  24755                         const check_len = parent.ty.arrayLenIncludingSentinel();
  24756                         if (elem_ptr.index >= check_len) {
  24757                             // TODO have the parent include the decl so we can say "declared here"
  24758                             return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{
  24759                                 elem_ptr.index, check_len,
  24760                             });
  24761                         }
  24762                         const elem_ty = parent.ty.childType();
  24763                         switch (val_ptr.tag()) {
  24764                             .undef => {
  24765                                 // An array has been initialized to undefined at comptime and now we
  24766                                 // are for the first time setting an element. We must change the representation
  24767                                 // of the array from `undef` to `array`.
  24768                                 const arena = parent.beginArena(sema.mod);
  24769                                 defer parent.finishArena(sema.mod);
  24770 
  24771                                 const array_len_including_sentinel =
  24772                                     try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel());
  24773                                 const elems = try arena.alloc(Value, array_len_including_sentinel);
  24774                                 mem.set(Value, elems, Value.undef);
  24775 
  24776                                 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
  24777 
  24778                                 return beginComptimePtrMutationInner(
  24779                                     sema,
  24780                                     block,
  24781                                     src,
  24782                                     elem_ty,
  24783                                     &elems[elem_ptr.index],
  24784                                     ptr_elem_ty,
  24785                                     parent.decl_ref_mut,
  24786                                 );
  24787                             },
  24788                             .bytes => {
  24789                                 // An array is memory-optimized to store a slice of bytes, but we are about
  24790                                 // to modify an individual field and the representation has to change.
  24791                                 // If we wanted to avoid this, there would need to be special detection
  24792                                 // elsewhere to identify when writing a value to an array element that is stored
  24793                                 // using the `bytes` tag, and handle it without making a call to this function.
  24794                                 const arena = parent.beginArena(sema.mod);
  24795                                 defer parent.finishArena(sema.mod);
  24796 
  24797                                 const bytes = val_ptr.castTag(.bytes).?.data;
  24798                                 const dest_len = parent.ty.arrayLenIncludingSentinel();
  24799                                 // bytes.len may be one greater than dest_len because of the case when
  24800                                 // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted.
  24801                                 assert(bytes.len >= dest_len);
  24802                                 const elems = try arena.alloc(Value, @intCast(usize, dest_len));
  24803                                 for (elems) |*elem, i| {
  24804                                     elem.* = try Value.Tag.int_u64.create(arena, bytes[i]);
  24805                                 }
  24806 
  24807                                 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
  24808 
  24809                                 return beginComptimePtrMutationInner(
  24810                                     sema,
  24811                                     block,
  24812                                     src,
  24813                                     elem_ty,
  24814                                     &elems[elem_ptr.index],
  24815                                     ptr_elem_ty,
  24816                                     parent.decl_ref_mut,
  24817                                 );
  24818                             },
  24819                             .str_lit => {
  24820                                 // An array is memory-optimized to store a slice of bytes, but we are about
  24821                                 // to modify an individual field and the representation has to change.
  24822                                 // If we wanted to avoid this, there would need to be special detection
  24823                                 // elsewhere to identify when writing a value to an array element that is stored
  24824                                 // using the `str_lit` tag, and handle it without making a call to this function.
  24825                                 const arena = parent.beginArena(sema.mod);
  24826                                 defer parent.finishArena(sema.mod);
  24827 
  24828                                 const str_lit = val_ptr.castTag(.str_lit).?.data;
  24829                                 const dest_len = parent.ty.arrayLenIncludingSentinel();
  24830                                 const bytes = sema.mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
  24831                                 const elems = try arena.alloc(Value, @intCast(usize, dest_len));
  24832                                 for (bytes) |byte, i| {
  24833                                     elems[i] = try Value.Tag.int_u64.create(arena, byte);
  24834                                 }
  24835                                 if (parent.ty.sentinel()) |sent_val| {
  24836                                     assert(elems.len == bytes.len + 1);
  24837                                     elems[bytes.len] = sent_val;
  24838                                 }
  24839 
  24840                                 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
  24841 
  24842                                 return beginComptimePtrMutationInner(
  24843                                     sema,
  24844                                     block,
  24845                                     src,
  24846                                     elem_ty,
  24847                                     &elems[elem_ptr.index],
  24848                                     ptr_elem_ty,
  24849                                     parent.decl_ref_mut,
  24850                                 );
  24851                             },
  24852                             .repeated => {
  24853                                 // An array is memory-optimized to store only a single element value, and
  24854                                 // that value is understood to be the same for the entire length of the array.
  24855                                 // However, now we want to modify an individual field and so the
  24856                                 // representation has to change.  If we wanted to avoid this, there would
  24857                                 // need to be special detection elsewhere to identify when writing a value to an
  24858                                 // array element that is stored using the `repeated` tag, and handle it
  24859                                 // without making a call to this function.
  24860                                 const arena = parent.beginArena(sema.mod);
  24861                                 defer parent.finishArena(sema.mod);
  24862 
  24863                                 const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena);
  24864                                 const array_len_including_sentinel =
  24865                                     try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel());
  24866                                 const elems = try arena.alloc(Value, array_len_including_sentinel);
  24867                                 if (elems.len > 0) elems[0] = repeated_val;
  24868                                 for (elems[1..]) |*elem| {
  24869                                     elem.* = try repeated_val.copy(arena);
  24870                                 }
  24871 
  24872                                 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
  24873 
  24874                                 return beginComptimePtrMutationInner(
  24875                                     sema,
  24876                                     block,
  24877                                     src,
  24878                                     elem_ty,
  24879                                     &elems[elem_ptr.index],
  24880                                     ptr_elem_ty,
  24881                                     parent.decl_ref_mut,
  24882                                 );
  24883                             },
  24884 
  24885                             .aggregate => return beginComptimePtrMutationInner(
  24886                                 sema,
  24887                                 block,
  24888                                 src,
  24889                                 elem_ty,
  24890                                 &val_ptr.castTag(.aggregate).?.data[elem_ptr.index],
  24891                                 ptr_elem_ty,
  24892                                 parent.decl_ref_mut,
  24893                             ),
  24894 
  24895                             .the_only_possible_value => {
  24896                                 const duped = try sema.arena.create(Value);
  24897                                 duped.* = Value.initTag(.the_only_possible_value);
  24898                                 return beginComptimePtrMutationInner(
  24899                                     sema,
  24900                                     block,
  24901                                     src,
  24902                                     elem_ty,
  24903                                     duped,
  24904                                     ptr_elem_ty,
  24905                                     parent.decl_ref_mut,
  24906                                 );
  24907                             },
  24908 
  24909                             else => unreachable,
  24910                         }
  24911                     },
  24912                     else => {
  24913                         if (elem_ptr.index != 0) {
  24914                             // TODO include a "declared here" note for the decl
  24915                             return sema.fail(block, src, "out of bounds comptime store of index {d}", .{
  24916                                 elem_ptr.index,
  24917                             });
  24918                         }
  24919                         return beginComptimePtrMutationInner(
  24920                             sema,
  24921                             block,
  24922                             src,
  24923                             parent.ty,
  24924                             val_ptr,
  24925                             ptr_elem_ty,
  24926                             parent.decl_ref_mut,
  24927                         );
  24928                     },
  24929                 },
  24930                 .reinterpret => |reinterpret| {
  24931                     if (!elem_ptr.elem_ty.hasWellDefinedLayout()) {
  24932                         // Even though the parent value type has well-defined memory layout, our
  24933                         // pointer type does not.
  24934                         return ComptimePtrMutationKit{
  24935                             .decl_ref_mut = parent.decl_ref_mut,
  24936                             .pointee = .bad_ptr_ty,
  24937                             .ty = elem_ptr.elem_ty,
  24938                         };
  24939                     }
  24940 
  24941                     const elem_abi_size_u64 = try sema.typeAbiSize(block, src, elem_ptr.elem_ty);
  24942                     const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
  24943                     return ComptimePtrMutationKit{
  24944                         .decl_ref_mut = parent.decl_ref_mut,
  24945                         .pointee = .{ .reinterpret = .{
  24946                             .val_ptr = reinterpret.val_ptr,
  24947                             .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_ptr.index,
  24948                         } },
  24949                         .ty = parent.ty,
  24950                     };
  24951                 },
  24952                 .bad_decl_ty, .bad_ptr_ty => return parent,
  24953             }
  24954         },
  24955         .field_ptr => {
  24956             const field_ptr = ptr_val.castTag(.field_ptr).?.data;
  24957             const field_index = @intCast(u32, field_ptr.field_index);
  24958 
  24959             var parent = try beginComptimePtrMutation(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty);
  24960             switch (parent.pointee) {
  24961                 .direct => |val_ptr| switch (val_ptr.tag()) {
  24962                     .undef => {
  24963                         // A struct or union has been initialized to undefined at comptime and now we
  24964                         // are for the first time setting a field. We must change the representation
  24965                         // of the struct/union from `undef` to `struct`/`union`.
  24966                         const arena = parent.beginArena(sema.mod);
  24967                         defer parent.finishArena(sema.mod);
  24968 
  24969                         switch (parent.ty.zigTypeTag()) {
  24970                             .Struct => {
  24971                                 const fields = try arena.alloc(Value, parent.ty.structFieldCount());
  24972                                 mem.set(Value, fields, Value.undef);
  24973 
  24974                                 val_ptr.* = try Value.Tag.aggregate.create(arena, fields);
  24975 
  24976                                 return beginComptimePtrMutationInner(
  24977                                     sema,
  24978                                     block,
  24979                                     src,
  24980                                     parent.ty.structFieldType(field_index),
  24981                                     &fields[field_index],
  24982                                     ptr_elem_ty,
  24983                                     parent.decl_ref_mut,
  24984                                 );
  24985                             },
  24986                             .Union => {
  24987                                 const payload = try arena.create(Value.Payload.Union);
  24988                                 payload.* = .{ .data = .{
  24989                                     .tag = try Value.Tag.enum_field_index.create(arena, field_index),
  24990                                     .val = Value.undef,
  24991                                 } };
  24992 
  24993                                 val_ptr.* = Value.initPayload(&payload.base);
  24994 
  24995                                 return beginComptimePtrMutationInner(
  24996                                     sema,
  24997                                     block,
  24998                                     src,
  24999                                     parent.ty.structFieldType(field_index),
  25000                                     &payload.data.val,
  25001                                     ptr_elem_ty,
  25002                                     parent.decl_ref_mut,
  25003                                 );
  25004                             },
  25005                             .Pointer => {
  25006                                 assert(parent.ty.isSlice());
  25007                                 val_ptr.* = try Value.Tag.slice.create(arena, .{
  25008                                     .ptr = Value.undef,
  25009                                     .len = Value.undef,
  25010                                 });
  25011 
  25012                                 switch (field_index) {
  25013                                     Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner(
  25014                                         sema,
  25015                                         block,
  25016                                         src,
  25017                                         parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
  25018                                         &val_ptr.castTag(.slice).?.data.ptr,
  25019                                         ptr_elem_ty,
  25020                                         parent.decl_ref_mut,
  25021                                     ),
  25022                                     Value.Payload.Slice.len_index => return beginComptimePtrMutationInner(
  25023                                         sema,
  25024                                         block,
  25025                                         src,
  25026                                         Type.usize,
  25027                                         &val_ptr.castTag(.slice).?.data.len,
  25028                                         ptr_elem_ty,
  25029                                         parent.decl_ref_mut,
  25030                                     ),
  25031 
  25032                                     else => unreachable,
  25033                                 }
  25034                             },
  25035                             else => unreachable,
  25036                         }
  25037                     },
  25038                     .aggregate => return beginComptimePtrMutationInner(
  25039                         sema,
  25040                         block,
  25041                         src,
  25042                         parent.ty.structFieldType(field_index),
  25043                         &val_ptr.castTag(.aggregate).?.data[field_index],
  25044                         ptr_elem_ty,
  25045                         parent.decl_ref_mut,
  25046                     ),
  25047 
  25048                     .@"union" => {
  25049                         // We need to set the active field of the union.
  25050                         const arena = parent.beginArena(sema.mod);
  25051                         defer parent.finishArena(sema.mod);
  25052 
  25053                         const payload = &val_ptr.castTag(.@"union").?.data;
  25054                         payload.tag = try Value.Tag.enum_field_index.create(arena, field_index);
  25055 
  25056                         return beginComptimePtrMutationInner(
  25057                             sema,
  25058                             block,
  25059                             src,
  25060                             parent.ty.structFieldType(field_index),
  25061                             &payload.val,
  25062                             ptr_elem_ty,
  25063                             parent.decl_ref_mut,
  25064                         );
  25065                     },
  25066                     .slice => switch (field_index) {
  25067                         Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner(
  25068                             sema,
  25069                             block,
  25070                             src,
  25071                             parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
  25072                             &val_ptr.castTag(.slice).?.data.ptr,
  25073                             ptr_elem_ty,
  25074                             parent.decl_ref_mut,
  25075                         ),
  25076 
  25077                         Value.Payload.Slice.len_index => return beginComptimePtrMutationInner(
  25078                             sema,
  25079                             block,
  25080                             src,
  25081                             Type.usize,
  25082                             &val_ptr.castTag(.slice).?.data.len,
  25083                             ptr_elem_ty,
  25084                             parent.decl_ref_mut,
  25085                         ),
  25086 
  25087                         else => unreachable,
  25088                     },
  25089 
  25090                     .empty_struct_value => {
  25091                         const duped = try sema.arena.create(Value);
  25092                         duped.* = Value.initTag(.the_only_possible_value);
  25093                         return beginComptimePtrMutationInner(
  25094                             sema,
  25095                             block,
  25096                             src,
  25097                             parent.ty.structFieldType(field_index),
  25098                             duped,
  25099                             ptr_elem_ty,
  25100                             parent.decl_ref_mut,
  25101                         );
  25102                     },
  25103 
  25104                     else => unreachable,
  25105                 },
  25106                 .reinterpret => |reinterpret| {
  25107                     const field_offset_u64 = field_ptr.container_ty.structFieldOffset(field_index, target);
  25108                     const field_offset = try sema.usizeCast(block, src, field_offset_u64);
  25109                     return ComptimePtrMutationKit{
  25110                         .decl_ref_mut = parent.decl_ref_mut,
  25111                         .pointee = .{ .reinterpret = .{
  25112                             .val_ptr = reinterpret.val_ptr,
  25113                             .byte_offset = reinterpret.byte_offset + field_offset,
  25114                         } },
  25115                         .ty = parent.ty,
  25116                     };
  25117                 },
  25118                 .bad_decl_ty, .bad_ptr_ty => return parent,
  25119             }
  25120         },
  25121         .eu_payload_ptr => {
  25122             const eu_ptr = ptr_val.castTag(.eu_payload_ptr).?.data;
  25123             var parent = try beginComptimePtrMutation(sema, block, src, eu_ptr.container_ptr, eu_ptr.container_ty);
  25124             switch (parent.pointee) {
  25125                 .direct => |val_ptr| {
  25126                     const payload_ty = parent.ty.errorUnionPayload();
  25127                     switch (val_ptr.tag()) {
  25128                         else => {
  25129                             // An error union has been initialized to undefined at comptime and now we
  25130                             // are for the first time setting the payload. We must change the
  25131                             // representation of the error union from `undef` to `opt_payload`.
  25132                             const arena = parent.beginArena(sema.mod);
  25133                             defer parent.finishArena(sema.mod);
  25134 
  25135                             const payload = try arena.create(Value.Payload.SubValue);
  25136                             payload.* = .{
  25137                                 .base = .{ .tag = .eu_payload },
  25138                                 .data = Value.undef,
  25139                             };
  25140 
  25141                             val_ptr.* = Value.initPayload(&payload.base);
  25142 
  25143                             return ComptimePtrMutationKit{
  25144                                 .decl_ref_mut = parent.decl_ref_mut,
  25145                                 .pointee = .{ .direct = &payload.data },
  25146                                 .ty = payload_ty,
  25147                             };
  25148                         },
  25149                         .eu_payload => return ComptimePtrMutationKit{
  25150                             .decl_ref_mut = parent.decl_ref_mut,
  25151                             .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data },
  25152                             .ty = payload_ty,
  25153                         },
  25154                     }
  25155                 },
  25156                 .bad_decl_ty, .bad_ptr_ty => return parent,
  25157                 // Even though the parent value type has well-defined memory layout, our
  25158                 // pointer type does not.
  25159                 .reinterpret => return ComptimePtrMutationKit{
  25160                     .decl_ref_mut = parent.decl_ref_mut,
  25161                     .pointee = .bad_ptr_ty,
  25162                     .ty = eu_ptr.container_ty,
  25163                 },
  25164             }
  25165         },
  25166         .opt_payload_ptr => {
  25167             const opt_ptr = if (ptr_val.castTag(.opt_payload_ptr)) |some| some.data else {
  25168                 return sema.beginComptimePtrMutation(block, src, ptr_val, try ptr_elem_ty.optionalChildAlloc(sema.arena));
  25169             };
  25170             var parent = try beginComptimePtrMutation(sema, block, src, opt_ptr.container_ptr, opt_ptr.container_ty);
  25171             switch (parent.pointee) {
  25172                 .direct => |val_ptr| {
  25173                     const payload_ty = try parent.ty.optionalChildAlloc(sema.arena);
  25174                     switch (val_ptr.tag()) {
  25175                         .undef, .null_value => {
  25176                             // An optional has been initialized to undefined at comptime and now we
  25177                             // are for the first time setting the payload. We must change the
  25178                             // representation of the optional from `undef` to `opt_payload`.
  25179                             const arena = parent.beginArena(sema.mod);
  25180                             defer parent.finishArena(sema.mod);
  25181 
  25182                             const payload = try arena.create(Value.Payload.SubValue);
  25183                             payload.* = .{
  25184                                 .base = .{ .tag = .opt_payload },
  25185                                 .data = Value.undef,
  25186                             };
  25187 
  25188                             val_ptr.* = Value.initPayload(&payload.base);
  25189 
  25190                             return ComptimePtrMutationKit{
  25191                                 .decl_ref_mut = parent.decl_ref_mut,
  25192                                 .pointee = .{ .direct = &payload.data },
  25193                                 .ty = payload_ty,
  25194                             };
  25195                         },
  25196                         .opt_payload => return ComptimePtrMutationKit{
  25197                             .decl_ref_mut = parent.decl_ref_mut,
  25198                             .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data },
  25199                             .ty = payload_ty,
  25200                         },
  25201 
  25202                         else => return ComptimePtrMutationKit{
  25203                             .decl_ref_mut = parent.decl_ref_mut,
  25204                             .pointee = .{ .direct = val_ptr },
  25205                             .ty = payload_ty,
  25206                         },
  25207                     }
  25208                 },
  25209                 .bad_decl_ty, .bad_ptr_ty => return parent,
  25210                 // Even though the parent value type has well-defined memory layout, our
  25211                 // pointer type does not.
  25212                 .reinterpret => return ComptimePtrMutationKit{
  25213                     .decl_ref_mut = parent.decl_ref_mut,
  25214                     .pointee = .bad_ptr_ty,
  25215                     .ty = opt_ptr.container_ty,
  25216                 },
  25217             }
  25218         },
  25219         .decl_ref => unreachable, // isComptimeMutablePtr() has been checked already
  25220         else => unreachable,
  25221     }
  25222 }
  25223 
  25224 fn beginComptimePtrMutationInner(
  25225     sema: *Sema,
  25226     block: *Block,
  25227     src: LazySrcLoc,
  25228     decl_ty: Type,
  25229     decl_val: *Value,
  25230     ptr_elem_ty: Type,
  25231     decl_ref_mut: Value.Payload.DeclRefMut.Data,
  25232 ) CompileError!ComptimePtrMutationKit {
  25233     const target = sema.mod.getTarget();
  25234     const coerce_ok = (try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_ty, true, target, src, src)) == .ok;
  25235     if (coerce_ok) {
  25236         return ComptimePtrMutationKit{
  25237             .decl_ref_mut = decl_ref_mut,
  25238             .pointee = .{ .direct = decl_val },
  25239             .ty = decl_ty,
  25240         };
  25241     }
  25242 
  25243     // Handle the case that the decl is an array and we're actually trying to point to an element.
  25244     if (decl_ty.isArrayOrVector()) {
  25245         const decl_elem_ty = decl_ty.childType();
  25246         if ((try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_elem_ty, true, target, src, src)) == .ok) {
  25247             return ComptimePtrMutationKit{
  25248                 .decl_ref_mut = decl_ref_mut,
  25249                 .pointee = .{ .direct = decl_val },
  25250                 .ty = decl_ty,
  25251             };
  25252         }
  25253     }
  25254 
  25255     if (!decl_ty.hasWellDefinedLayout()) {
  25256         return ComptimePtrMutationKit{
  25257             .decl_ref_mut = decl_ref_mut,
  25258             .pointee = .{ .bad_decl_ty = {} },
  25259             .ty = decl_ty,
  25260         };
  25261     }
  25262     if (!ptr_elem_ty.hasWellDefinedLayout()) {
  25263         return ComptimePtrMutationKit{
  25264             .decl_ref_mut = decl_ref_mut,
  25265             .pointee = .{ .bad_ptr_ty = {} },
  25266             .ty = ptr_elem_ty,
  25267         };
  25268     }
  25269     return ComptimePtrMutationKit{
  25270         .decl_ref_mut = decl_ref_mut,
  25271         .pointee = .{ .reinterpret = .{
  25272             .val_ptr = decl_val,
  25273             .byte_offset = 0,
  25274         } },
  25275         .ty = decl_ty,
  25276     };
  25277 }
  25278 
  25279 const TypedValueAndOffset = struct {
  25280     tv: TypedValue,
  25281     byte_offset: usize,
  25282 };
  25283 
  25284 const ComptimePtrLoadKit = struct {
  25285     /// The Value and Type corresponding to the pointee of the provided pointer.
  25286     /// If a direct dereference is not possible, this is null.
  25287     pointee: ?TypedValue,
  25288     /// The largest parent Value containing `pointee` and having a well-defined memory layout.
  25289     /// This is used for bitcasting, if direct dereferencing failed (i.e. `pointee` is null).
  25290     parent: ?TypedValueAndOffset,
  25291     /// Whether the `pointee` could be mutated by further
  25292     /// semantic analysis and a copy must be performed.
  25293     is_mutable: bool,
  25294     /// If the root decl could not be used as `parent`, this is the type that
  25295     /// caused that by not having a well-defined layout
  25296     ty_without_well_defined_layout: ?Type,
  25297 };
  25298 
  25299 const ComptimePtrLoadError = CompileError || error{
  25300     RuntimeLoad,
  25301 };
  25302 
  25303 /// If `maybe_array_ty` is provided, it will be used to directly dereference an
  25304 /// .elem_ptr of type T to a value of [N]T, if necessary.
  25305 fn beginComptimePtrLoad(
  25306     sema: *Sema,
  25307     block: *Block,
  25308     src: LazySrcLoc,
  25309     ptr_val: Value,
  25310     maybe_array_ty: ?Type,
  25311 ) ComptimePtrLoadError!ComptimePtrLoadKit {
  25312     const target = sema.mod.getTarget();
  25313     var deref: ComptimePtrLoadKit = switch (ptr_val.tag()) {
  25314         .decl_ref,
  25315         .decl_ref_mut,
  25316         => blk: {
  25317             const decl_index = switch (ptr_val.tag()) {
  25318                 .decl_ref => ptr_val.castTag(.decl_ref).?.data,
  25319                 .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl_index,
  25320                 else => unreachable,
  25321             };
  25322             const is_mutable = ptr_val.tag() == .decl_ref_mut;
  25323             const decl = sema.mod.declPtr(decl_index);
  25324             const decl_tv = try decl.typedValue();
  25325             if (decl_tv.val.tag() == .variable) return error.RuntimeLoad;
  25326 
  25327             const layout_defined = decl.ty.hasWellDefinedLayout();
  25328             break :blk ComptimePtrLoadKit{
  25329                 .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,
  25330                 .pointee = decl_tv,
  25331                 .is_mutable = is_mutable,
  25332                 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
  25333             };
  25334         },
  25335 
  25336         .elem_ptr => blk: {
  25337             const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
  25338             const elem_ty = elem_ptr.elem_ty;
  25339             var deref = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr, null);
  25340 
  25341             // This code assumes that elem_ptrs have been "flattened" in order for direct dereference
  25342             // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that
  25343             // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened"
  25344             if (elem_ptr.array_ptr.castTag(.elem_ptr)) |parent_elem_ptr| {
  25345                 assert(!(parent_elem_ptr.data.elem_ty.eql(elem_ty, sema.mod)));
  25346             }
  25347 
  25348             if (elem_ptr.index != 0) {
  25349                 if (elem_ty.hasWellDefinedLayout()) {
  25350                     if (deref.parent) |*parent| {
  25351                         // Update the byte offset (in-place)
  25352                         const elem_size = try sema.typeAbiSize(block, src, elem_ty);
  25353                         const offset = parent.byte_offset + elem_size * elem_ptr.index;
  25354                         parent.byte_offset = try sema.usizeCast(block, src, offset);
  25355                     }
  25356                 } else {
  25357                     deref.parent = null;
  25358                     deref.ty_without_well_defined_layout = elem_ty;
  25359                 }
  25360             }
  25361 
  25362             // If we're loading an elem_ptr that was derived from a different type
  25363             // than the true type of the underlying decl, we cannot deref directly
  25364             const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector()) x: {
  25365                 const deref_elem_ty = deref.pointee.?.ty.childType();
  25366                 break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or
  25367                     (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok;
  25368             } else false;
  25369             if (!ty_matches) {
  25370                 deref.pointee = null;
  25371                 break :blk deref;
  25372             }
  25373 
  25374             var array_tv = deref.pointee.?;
  25375             const check_len = array_tv.ty.arrayLenIncludingSentinel();
  25376             if (maybe_array_ty) |load_ty| {
  25377                 // It's possible that we're loading a [N]T, in which case we'd like to slice
  25378                 // the pointee array directly from our parent array.
  25379                 if (load_ty.isArrayOrVector() and load_ty.childType().eql(elem_ty, sema.mod)) {
  25380                     const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel());
  25381                     deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{
  25382                         .ty = try Type.array(sema.arena, N, null, elem_ty, sema.mod),
  25383                         .val = try array_tv.val.sliceArray(sema.mod, sema.arena, elem_ptr.index, elem_ptr.index + N),
  25384                     } else null;
  25385                     break :blk deref;
  25386                 }
  25387             }
  25388 
  25389             if (elem_ptr.index >= check_len) {
  25390                 deref.pointee = null;
  25391                 break :blk deref;
  25392             }
  25393             if (elem_ptr.index == check_len - 1) {
  25394                 if (array_tv.ty.sentinel()) |sent| {
  25395                     deref.pointee = TypedValue{
  25396                         .ty = elem_ty,
  25397                         .val = sent,
  25398                     };
  25399                     break :blk deref;
  25400                 }
  25401             }
  25402             deref.pointee = TypedValue{
  25403                 .ty = elem_ty,
  25404                 .val = try array_tv.val.elemValue(sema.mod, sema.arena, elem_ptr.index),
  25405             };
  25406             break :blk deref;
  25407         },
  25408 
  25409         .slice => blk: {
  25410             const slice = ptr_val.castTag(.slice).?.data;
  25411             break :blk try beginComptimePtrLoad(sema, block, src, slice.ptr, null);
  25412         },
  25413 
  25414         .field_ptr => blk: {
  25415             const field_ptr = ptr_val.castTag(.field_ptr).?.data;
  25416             const field_index = @intCast(u32, field_ptr.field_index);
  25417             var deref = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty);
  25418 
  25419             if (field_ptr.container_ty.hasWellDefinedLayout()) {
  25420                 const struct_ty = field_ptr.container_ty.castTag(.@"struct");
  25421                 if (struct_ty != null and struct_ty.?.data.layout == .Packed) {
  25422                     // packed structs are not byte addressable
  25423                     deref.parent = null;
  25424                 } else if (deref.parent) |*parent| {
  25425                     // Update the byte offset (in-place)
  25426                     try sema.resolveTypeLayout(block, src, field_ptr.container_ty);
  25427                     const field_offset = field_ptr.container_ty.structFieldOffset(field_index, target);
  25428                     parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset);
  25429                 }
  25430             } else {
  25431                 deref.parent = null;
  25432                 deref.ty_without_well_defined_layout = field_ptr.container_ty;
  25433             }
  25434 
  25435             const tv = deref.pointee orelse {
  25436                 deref.pointee = null;
  25437                 break :blk deref;
  25438             };
  25439             const coerce_in_mem_ok =
  25440                 (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
  25441                 (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok;
  25442             if (!coerce_in_mem_ok) {
  25443                 deref.pointee = null;
  25444                 break :blk deref;
  25445             }
  25446 
  25447             if (field_ptr.container_ty.isSlice()) {
  25448                 const slice_val = tv.val.castTag(.slice).?.data;
  25449                 deref.pointee = switch (field_index) {
  25450                     Value.Payload.Slice.ptr_index => TypedValue{
  25451                         .ty = field_ptr.container_ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
  25452                         .val = slice_val.ptr,
  25453                     },
  25454                     Value.Payload.Slice.len_index => TypedValue{
  25455                         .ty = Type.usize,
  25456                         .val = slice_val.len,
  25457                     },
  25458                     else => unreachable,
  25459                 };
  25460             } else {
  25461                 const field_ty = field_ptr.container_ty.structFieldType(field_index);
  25462                 deref.pointee = TypedValue{
  25463                     .ty = field_ty,
  25464                     .val = tv.val.fieldValue(tv.ty, field_index),
  25465                 };
  25466             }
  25467             break :blk deref;
  25468         },
  25469 
  25470         .comptime_field_ptr => blk: {
  25471             const comptime_field_ptr = ptr_val.castTag(.comptime_field_ptr).?.data;
  25472             break :blk ComptimePtrLoadKit{
  25473                 .parent = null,
  25474                 .pointee = .{ .ty = comptime_field_ptr.field_ty, .val = comptime_field_ptr.field_val },
  25475                 .is_mutable = false,
  25476                 .ty_without_well_defined_layout = comptime_field_ptr.field_ty,
  25477             };
  25478         },
  25479 
  25480         .opt_payload_ptr,
  25481         .eu_payload_ptr,
  25482         => blk: {
  25483             const payload_ptr = ptr_val.cast(Value.Payload.PayloadPtr).?.data;
  25484             const payload_ty = switch (ptr_val.tag()) {
  25485                 .eu_payload_ptr => payload_ptr.container_ty.errorUnionPayload(),
  25486                 .opt_payload_ptr => try payload_ptr.container_ty.optionalChildAlloc(sema.arena),
  25487                 else => unreachable,
  25488             };
  25489             var deref = try beginComptimePtrLoad(sema, block, src, payload_ptr.container_ptr, payload_ptr.container_ty);
  25490 
  25491             // eu_payload_ptr and opt_payload_ptr never have a well-defined layout
  25492             if (deref.parent != null) {
  25493                 deref.parent = null;
  25494                 deref.ty_without_well_defined_layout = payload_ptr.container_ty;
  25495             }
  25496 
  25497             if (deref.pointee) |*tv| {
  25498                 const coerce_in_mem_ok =
  25499                     (try sema.coerceInMemoryAllowed(block, payload_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
  25500                     (try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok;
  25501                 if (coerce_in_mem_ok) {
  25502                     const payload_val = switch (ptr_val.tag()) {
  25503                         .eu_payload_ptr => if (tv.val.castTag(.eu_payload)) |some| some.data else {
  25504                             return sema.fail(block, src, "attempt to unwrap error: {s}", .{tv.val.castTag(.@"error").?.data.name});
  25505                         },
  25506                         .opt_payload_ptr => if (tv.val.castTag(.opt_payload)) |some| some.data else opt: {
  25507                             if (tv.val.isNull()) return sema.fail(block, src, "attempt to use null value", .{});
  25508                             break :opt tv.val;
  25509                         },
  25510                         else => unreachable,
  25511                     };
  25512                     tv.* = TypedValue{ .ty = payload_ty, .val = payload_val };
  25513                     break :blk deref;
  25514                 }
  25515             }
  25516             deref.pointee = null;
  25517             break :blk deref;
  25518         },
  25519         .null_value => {
  25520             return sema.fail(block, src, "attempt to use null value", .{});
  25521         },
  25522 
  25523         .zero,
  25524         .one,
  25525         .int_u64,
  25526         .int_i64,
  25527         .int_big_positive,
  25528         .int_big_negative,
  25529         .variable,
  25530         .extern_fn,
  25531         .function,
  25532         => return error.RuntimeLoad,
  25533 
  25534         else => unreachable,
  25535     };
  25536 
  25537     if (deref.pointee) |tv| {
  25538         if (deref.parent == null and tv.ty.hasWellDefinedLayout()) {
  25539             deref.parent = .{ .tv = tv, .byte_offset = 0 };
  25540         }
  25541     }
  25542     return deref;
  25543 }
  25544 
  25545 fn bitCast(
  25546     sema: *Sema,
  25547     block: *Block,
  25548     dest_ty_unresolved: Type,
  25549     inst: Air.Inst.Ref,
  25550     inst_src: LazySrcLoc,
  25551 ) CompileError!Air.Inst.Ref {
  25552     const dest_ty = try sema.resolveTypeFields(block, inst_src, dest_ty_unresolved);
  25553     try sema.resolveTypeLayout(block, inst_src, dest_ty);
  25554 
  25555     const old_ty = try sema.resolveTypeFields(block, inst_src, sema.typeOf(inst));
  25556     try sema.resolveTypeLayout(block, inst_src, old_ty);
  25557 
  25558     const target = sema.mod.getTarget();
  25559     const dest_bits = dest_ty.bitSize(target);
  25560     const old_bits = old_ty.bitSize(target);
  25561 
  25562     if (old_bits != dest_bits) {
  25563         return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{}' has {d} bits but source type '{}' has {d} bits", .{
  25564             dest_ty.fmt(sema.mod),
  25565             dest_bits,
  25566             old_ty.fmt(sema.mod),
  25567             old_bits,
  25568         });
  25569     }
  25570 
  25571     if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
  25572         const result_val = try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0);
  25573         return sema.addConstant(dest_ty, result_val);
  25574     }
  25575     try sema.requireRuntimeBlock(block, inst_src, null);
  25576     return block.addBitCast(dest_ty, inst);
  25577 }
  25578 
  25579 fn bitCastVal(
  25580     sema: *Sema,
  25581     block: *Block,
  25582     src: LazySrcLoc,
  25583     val: Value,
  25584     old_ty: Type,
  25585     new_ty: Type,
  25586     buffer_offset: usize,
  25587 ) !Value {
  25588     const target = sema.mod.getTarget();
  25589     if (old_ty.eql(new_ty, sema.mod)) return val;
  25590 
  25591     // Some conversions have a bitwise definition that ignores in-memory layout,
  25592     // such as converting between f80 and u80.
  25593 
  25594     if (old_ty.eql(Type.f80, sema.mod) and new_ty.isAbiInt()) {
  25595         const float = val.toFloat(f80);
  25596         switch (new_ty.intInfo(target).signedness) {
  25597             .signed => {
  25598                 const int = @bitCast(i80, float);
  25599                 const limbs = try sema.arena.alloc(std.math.big.Limb, 2);
  25600                 const big_int = std.math.big.int.Mutable.init(limbs, int);
  25601                 return Value.fromBigInt(sema.arena, big_int.toConst());
  25602             },
  25603             .unsigned => {
  25604                 const int = @bitCast(u80, float);
  25605                 const limbs = try sema.arena.alloc(std.math.big.Limb, 2);
  25606                 const big_int = std.math.big.int.Mutable.init(limbs, int);
  25607                 return Value.fromBigInt(sema.arena, big_int.toConst());
  25608             },
  25609         }
  25610     }
  25611 
  25612     if (new_ty.eql(Type.f80, sema.mod) and old_ty.isAbiInt()) {
  25613         var bigint_space: Value.BigIntSpace = undefined;
  25614         var bigint = try val.toBigIntAdvanced(&bigint_space, target, sema.kit(block, src));
  25615         switch (old_ty.intInfo(target).signedness) {
  25616             .signed => {
  25617                 // This conversion cannot fail because we already checked bit size before
  25618                 // calling bitCastVal.
  25619                 const int = bigint.to(i80) catch unreachable;
  25620                 const float = @bitCast(f80, int);
  25621                 return Value.Tag.float_80.create(sema.arena, float);
  25622             },
  25623             .unsigned => {
  25624                 // This conversion cannot fail because we already checked bit size before
  25625                 // calling bitCastVal.
  25626                 const int = bigint.to(u80) catch unreachable;
  25627                 const float = @bitCast(f80, int);
  25628                 return Value.Tag.float_80.create(sema.arena, float);
  25629             },
  25630         }
  25631     }
  25632 
  25633     // For types with well-defined memory layouts, we serialize them a byte buffer,
  25634     // then deserialize to the new type.
  25635     const abi_size = try sema.usizeCast(block, src, old_ty.abiSize(target));
  25636     const buffer = try sema.gpa.alloc(u8, abi_size);
  25637     defer sema.gpa.free(buffer);
  25638     val.writeToMemory(old_ty, sema.mod, buffer);
  25639     return Value.readFromMemory(new_ty, sema.mod, buffer[buffer_offset..], sema.arena);
  25640 }
  25641 
  25642 fn coerceArrayPtrToSlice(
  25643     sema: *Sema,
  25644     block: *Block,
  25645     dest_ty: Type,
  25646     inst: Air.Inst.Ref,
  25647     inst_src: LazySrcLoc,
  25648 ) CompileError!Air.Inst.Ref {
  25649     if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
  25650         const ptr_array_ty = sema.typeOf(inst);
  25651         const array_ty = ptr_array_ty.childType();
  25652         const slice_val = try Value.Tag.slice.create(sema.arena, .{
  25653             .ptr = val,
  25654             .len = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()),
  25655         });
  25656         return sema.addConstant(dest_ty, slice_val);
  25657     }
  25658     try sema.requireRuntimeBlock(block, inst_src, null);
  25659     return block.addTyOp(.array_to_slice, dest_ty, inst);
  25660 }
  25661 
  25662 fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_result: *InMemoryCoercionResult) bool {
  25663     const dest_info = dest_ty.ptrInfo().data;
  25664     const inst_info = inst_ty.ptrInfo().data;
  25665     const len0 = (inst_info.pointee_type.zigTypeTag() == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel() == 0 or
  25666         (inst_info.pointee_type.arrayLen() == 0 and dest_info.sentinel == null and dest_info.size != .C and dest_info.size != .Many))) or
  25667         (inst_info.pointee_type.isTuple() and inst_info.pointee_type.tupleFields().types.len == 0);
  25668 
  25669     const ok_cv_qualifiers =
  25670         ((inst_info.mutable or !dest_info.mutable) or len0) and
  25671         (!inst_info.@"volatile" or dest_info.@"volatile");
  25672 
  25673     if (!ok_cv_qualifiers) {
  25674         in_memory_result.* = .{ .ptr_qualifiers = .{
  25675             .actual_const = !inst_info.mutable,
  25676             .wanted_const = !dest_info.mutable,
  25677             .actual_volatile = inst_info.@"volatile",
  25678             .wanted_volatile = dest_info.@"volatile",
  25679         } };
  25680         return false;
  25681     }
  25682     if (dest_info.@"addrspace" != inst_info.@"addrspace") {
  25683         in_memory_result.* = .{ .ptr_addrspace = .{
  25684             .actual = inst_info.@"addrspace",
  25685             .wanted = dest_info.@"addrspace",
  25686         } };
  25687         return false;
  25688     }
  25689     if (inst_info.@"align" == 0 and dest_info.@"align" == 0) return true;
  25690     if (len0) return true;
  25691     const target = sema.mod.getTarget();
  25692 
  25693     const inst_align = if (inst_info.@"align" != 0)
  25694         inst_info.@"align"
  25695     else
  25696         inst_info.pointee_type.abiAlignment(target);
  25697 
  25698     const dest_align = if (dest_info.@"align" != 0)
  25699         dest_info.@"align"
  25700     else
  25701         dest_info.pointee_type.abiAlignment(target);
  25702 
  25703     if (dest_align > inst_align) {
  25704         in_memory_result.* = .{ .ptr_alignment = .{
  25705             .actual = inst_align,
  25706             .wanted = dest_align,
  25707         } };
  25708         return false;
  25709     }
  25710     return true;
  25711 }
  25712 
  25713 fn coerceCompatiblePtrs(
  25714     sema: *Sema,
  25715     block: *Block,
  25716     dest_ty: Type,
  25717     inst: Air.Inst.Ref,
  25718     inst_src: LazySrcLoc,
  25719 ) !Air.Inst.Ref {
  25720     const inst_ty = sema.typeOf(inst);
  25721     if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
  25722         // The comptime Value representation is compatible with both types.
  25723         return sema.addConstant(dest_ty, val);
  25724     }
  25725     try sema.requireRuntimeBlock(block, inst_src, null);
  25726     const inst_allows_zero = (inst_ty.zigTypeTag() == .Pointer and inst_ty.ptrAllowsZero()) or true;
  25727     if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero() and
  25728         try sema.typeHasRuntimeBits(block, sema.src, dest_ty.elemType2()))
  25729     {
  25730         const actual_ptr = if (inst_ty.isSlice())
  25731             try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty)
  25732         else
  25733             inst;
  25734         const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr);
  25735         const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize);
  25736         const ok = if (inst_ty.isSlice()) ok: {
  25737             const len = try sema.analyzeSliceLen(block, inst_src, inst);
  25738             const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
  25739             break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);
  25740         } else is_non_zero;
  25741         try sema.addSafetyCheck(block, ok, .cast_to_null);
  25742     }
  25743     return sema.bitCast(block, dest_ty, inst, inst_src);
  25744 }
  25745 
  25746 fn coerceEnumToUnion(
  25747     sema: *Sema,
  25748     block: *Block,
  25749     union_ty: Type,
  25750     union_ty_src: LazySrcLoc,
  25751     inst: Air.Inst.Ref,
  25752     inst_src: LazySrcLoc,
  25753 ) !Air.Inst.Ref {
  25754     const inst_ty = sema.typeOf(inst);
  25755 
  25756     const tag_ty = union_ty.unionTagType() orelse {
  25757         const msg = msg: {
  25758             const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{
  25759                 union_ty.fmt(sema.mod), inst_ty.fmt(sema.mod),
  25760             });
  25761             errdefer msg.destroy(sema.gpa);
  25762             try sema.errNote(block, union_ty_src, msg, "cannot coerce enum to untagged union", .{});
  25763             try sema.addDeclaredHereNote(msg, union_ty);
  25764             break :msg msg;
  25765         };
  25766         return sema.failWithOwnedErrorMsg(msg);
  25767     };
  25768 
  25769     const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src);
  25770     if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| {
  25771         const field_index = union_ty.unionTagFieldIndex(val, sema.mod) orelse {
  25772             const msg = msg: {
  25773                 const msg = try sema.errMsg(block, inst_src, "union '{}' has no tag with value '{}'", .{
  25774                     union_ty.fmt(sema.mod), val.fmtValue(tag_ty, sema.mod),
  25775                 });
  25776                 errdefer msg.destroy(sema.gpa);
  25777                 try sema.addDeclaredHereNote(msg, union_ty);
  25778                 break :msg msg;
  25779             };
  25780             return sema.failWithOwnedErrorMsg(msg);
  25781         };
  25782 
  25783         const union_obj = union_ty.cast(Type.Payload.Union).?.data;
  25784         const field = union_obj.fields.values()[field_index];
  25785         const field_ty = try sema.resolveTypeFields(block, inst_src, field.ty);
  25786         if (field_ty.zigTypeTag() == .NoReturn) {
  25787             const msg = msg: {
  25788                 const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{});
  25789                 errdefer msg.destroy(sema.gpa);
  25790 
  25791                 const field_name = union_obj.fields.keys()[field_index];
  25792                 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name});
  25793                 try sema.addDeclaredHereNote(msg, union_ty);
  25794                 break :msg msg;
  25795             };
  25796             return sema.failWithOwnedErrorMsg(msg);
  25797         }
  25798         const opv = (try sema.typeHasOnePossibleValue(block, inst_src, field_ty)) orelse {
  25799             const msg = msg: {
  25800                 const field_name = union_obj.fields.keys()[field_index];
  25801                 const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{s}'", .{
  25802                     inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod), field_ty.fmt(sema.mod), field_name,
  25803                 });
  25804                 errdefer msg.destroy(sema.gpa);
  25805 
  25806                 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name});
  25807                 try sema.addDeclaredHereNote(msg, union_ty);
  25808                 break :msg msg;
  25809             };
  25810             return sema.failWithOwnedErrorMsg(msg);
  25811         };
  25812 
  25813         return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{
  25814             .tag = val,
  25815             .val = opv,
  25816         }));
  25817     }
  25818 
  25819     try sema.requireRuntimeBlock(block, inst_src, null);
  25820 
  25821     if (tag_ty.isNonexhaustiveEnum()) {
  25822         const msg = msg: {
  25823             const msg = try sema.errMsg(block, inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{
  25824                 union_ty.fmt(sema.mod),
  25825             });
  25826             errdefer msg.destroy(sema.gpa);
  25827             try sema.addDeclaredHereNote(msg, tag_ty);
  25828             break :msg msg;
  25829         };
  25830         return sema.failWithOwnedErrorMsg(msg);
  25831     }
  25832 
  25833     const union_obj = union_ty.cast(Type.Payload.Union).?.data;
  25834     {
  25835         var msg: ?*Module.ErrorMsg = null;
  25836         errdefer if (msg) |some| some.destroy(sema.gpa);
  25837 
  25838         for (union_obj.fields.values()) |field, i| {
  25839             if (field.ty.zigTypeTag() == .NoReturn) {
  25840                 const err_msg = msg orelse try sema.errMsg(
  25841                     block,
  25842                     inst_src,
  25843                     "runtime coercion from enum '{}' to union '{}' which has a 'noreturn' field",
  25844                     .{ tag_ty.fmt(sema.mod), union_ty.fmt(sema.mod) },
  25845                 );
  25846                 msg = err_msg;
  25847 
  25848                 try sema.addFieldErrNote(union_ty, i, err_msg, "'noreturn' field here", .{});
  25849             }
  25850         }
  25851         if (msg) |some| {
  25852             msg = null;
  25853             try sema.addDeclaredHereNote(some, union_ty);
  25854             return sema.failWithOwnedErrorMsg(some);
  25855         }
  25856     }
  25857 
  25858     // If the union has all fields 0 bits, the union value is just the enum value.
  25859     if (union_ty.unionHasAllZeroBitFieldTypes()) {
  25860         return block.addBitCast(union_ty, enum_tag);
  25861     }
  25862 
  25863     const msg = msg: {
  25864         const msg = try sema.errMsg(
  25865             block,
  25866             inst_src,
  25867             "runtime coercion from enum '{}' to union '{}' which has non-void fields",
  25868             .{ tag_ty.fmt(sema.mod), union_ty.fmt(sema.mod) },
  25869         );
  25870         errdefer msg.destroy(sema.gpa);
  25871 
  25872         var it = union_obj.fields.iterator();
  25873         var field_index: usize = 0;
  25874         while (it.next()) |field| : (field_index += 1) {
  25875             const field_name = field.key_ptr.*;
  25876             const field_ty = field.value_ptr.ty;
  25877             if (!field_ty.hasRuntimeBits()) continue;
  25878             try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) });
  25879         }
  25880         try sema.addDeclaredHereNote(msg, union_ty);
  25881         break :msg msg;
  25882     };
  25883     return sema.failWithOwnedErrorMsg(msg);
  25884 }
  25885 
  25886 fn coerceAnonStructToUnion(
  25887     sema: *Sema,
  25888     block: *Block,
  25889     union_ty: Type,
  25890     union_ty_src: LazySrcLoc,
  25891     inst: Air.Inst.Ref,
  25892     inst_src: LazySrcLoc,
  25893 ) !Air.Inst.Ref {
  25894     const inst_ty = sema.typeOf(inst);
  25895     const field_count = inst_ty.structFieldCount();
  25896     if (field_count != 1) {
  25897         const msg = msg: {
  25898             const msg = if (field_count > 1) try sema.errMsg(
  25899                 block,
  25900                 inst_src,
  25901                 "cannot initialize multiple union fields at once, unions can only have one active field",
  25902                 .{},
  25903             ) else try sema.errMsg(
  25904                 block,
  25905                 inst_src,
  25906                 "union initializer must initialize one field",
  25907                 .{},
  25908             );
  25909             errdefer msg.destroy(sema.gpa);
  25910 
  25911             // TODO add notes for where the anon struct was created to point out
  25912             // the extra fields.
  25913 
  25914             try sema.addDeclaredHereNote(msg, union_ty);
  25915             break :msg msg;
  25916         };
  25917         return sema.failWithOwnedErrorMsg(msg);
  25918     }
  25919 
  25920     const anon_struct = inst_ty.castTag(.anon_struct).?.data;
  25921     const field_name = anon_struct.names[0];
  25922     const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty);
  25923     return sema.unionInit(block, init, inst_src, union_ty, union_ty_src, field_name, inst_src);
  25924 }
  25925 
  25926 fn coerceAnonStructToUnionPtrs(
  25927     sema: *Sema,
  25928     block: *Block,
  25929     ptr_union_ty: Type,
  25930     union_ty_src: LazySrcLoc,
  25931     ptr_anon_struct: Air.Inst.Ref,
  25932     anon_struct_src: LazySrcLoc,
  25933 ) !Air.Inst.Ref {
  25934     const union_ty = ptr_union_ty.childType();
  25935     const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src);
  25936     const union_inst = try sema.coerceAnonStructToUnion(block, union_ty, union_ty_src, anon_struct, anon_struct_src);
  25937     return sema.analyzeRef(block, union_ty_src, union_inst);
  25938 }
  25939 
  25940 fn coerceAnonStructToStructPtrs(
  25941     sema: *Sema,
  25942     block: *Block,
  25943     ptr_struct_ty: Type,
  25944     struct_ty_src: LazySrcLoc,
  25945     ptr_anon_struct: Air.Inst.Ref,
  25946     anon_struct_src: LazySrcLoc,
  25947 ) !Air.Inst.Ref {
  25948     const struct_ty = ptr_struct_ty.childType();
  25949     const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src);
  25950     const struct_inst = try sema.coerceTupleToStruct(block, struct_ty, struct_ty_src, anon_struct, anon_struct_src);
  25951     return sema.analyzeRef(block, struct_ty_src, struct_inst);
  25952 }
  25953 
  25954 /// If the lengths match, coerces element-wise.
  25955 fn coerceArrayLike(
  25956     sema: *Sema,
  25957     block: *Block,
  25958     dest_ty: Type,
  25959     dest_ty_src: LazySrcLoc,
  25960     inst: Air.Inst.Ref,
  25961     inst_src: LazySrcLoc,
  25962 ) !Air.Inst.Ref {
  25963     const inst_ty = sema.typeOf(inst);
  25964     const inst_len = inst_ty.arrayLen();
  25965     const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen());
  25966     const target = sema.mod.getTarget();
  25967 
  25968     if (dest_len != inst_len) {
  25969         const msg = msg: {
  25970             const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{
  25971                 dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod),
  25972             });
  25973             errdefer msg.destroy(sema.gpa);
  25974             try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len});
  25975             try sema.errNote(block, inst_src, msg, "source has length {d}", .{inst_len});
  25976             break :msg msg;
  25977         };
  25978         return sema.failWithOwnedErrorMsg(msg);
  25979     }
  25980 
  25981     const dest_elem_ty = dest_ty.childType();
  25982     const inst_elem_ty = inst_ty.childType();
  25983     const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_elem_ty, inst_elem_ty, false, target, dest_ty_src, inst_src);
  25984     if (in_memory_result == .ok) {
  25985         if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |inst_val| {
  25986             // These types share the same comptime value representation.
  25987             return sema.addConstant(dest_ty, inst_val);
  25988         }
  25989         try sema.requireRuntimeBlock(block, inst_src, null);
  25990         return block.addBitCast(dest_ty, inst);
  25991     }
  25992 
  25993     const element_vals = try sema.arena.alloc(Value, dest_len);
  25994     const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_len);
  25995     var runtime_src: ?LazySrcLoc = null;
  25996 
  25997     for (element_vals) |*elem, i| {
  25998         const index_ref = try sema.addConstant(
  25999             Type.usize,
  26000             try Value.Tag.int_u64.create(sema.arena, i),
  26001         );
  26002         const src = inst_src; // TODO better source location
  26003         const elem_src = inst_src; // TODO better source location
  26004         const elem_ref = try sema.elemValArray(block, src, inst_src, inst, elem_src, index_ref);
  26005         const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src);
  26006         element_refs[i] = coerced;
  26007         if (runtime_src == null) {
  26008             if (try sema.resolveMaybeUndefVal(block, elem_src, coerced)) |elem_val| {
  26009                 elem.* = elem_val;
  26010             } else {
  26011                 runtime_src = elem_src;
  26012             }
  26013         }
  26014     }
  26015 
  26016     if (runtime_src) |rs| {
  26017         try sema.requireRuntimeBlock(block, inst_src, rs);
  26018         return block.addAggregateInit(dest_ty, element_refs);
  26019     }
  26020 
  26021     return sema.addConstant(
  26022         dest_ty,
  26023         try Value.Tag.aggregate.create(sema.arena, element_vals),
  26024     );
  26025 }
  26026 
  26027 /// If the lengths match, coerces element-wise.
  26028 fn coerceTupleToArray(
  26029     sema: *Sema,
  26030     block: *Block,
  26031     dest_ty: Type,
  26032     dest_ty_src: LazySrcLoc,
  26033     inst: Air.Inst.Ref,
  26034     inst_src: LazySrcLoc,
  26035 ) !Air.Inst.Ref {
  26036     const inst_ty = sema.typeOf(inst);
  26037     const inst_len = inst_ty.arrayLen();
  26038     const dest_len = dest_ty.arrayLen();
  26039 
  26040     if (dest_len != inst_len) {
  26041         const msg = msg: {
  26042             const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{
  26043                 dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod),
  26044             });
  26045             errdefer msg.destroy(sema.gpa);
  26046             try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len});
  26047             try sema.errNote(block, inst_src, msg, "source has length {d}", .{inst_len});
  26048             break :msg msg;
  26049         };
  26050         return sema.failWithOwnedErrorMsg(msg);
  26051     }
  26052 
  26053     const dest_elems = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLenIncludingSentinel());
  26054     const element_vals = try sema.arena.alloc(Value, dest_elems);
  26055     const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_elems);
  26056     const dest_elem_ty = dest_ty.childType();
  26057 
  26058     var runtime_src: ?LazySrcLoc = null;
  26059     for (element_vals) |*elem, i_usize| {
  26060         const i = @intCast(u32, i_usize);
  26061         if (i_usize == inst_len) {
  26062             elem.* = dest_ty.sentinel().?;
  26063             element_refs[i] = try sema.addConstant(dest_elem_ty, elem.*);
  26064             break;
  26065         }
  26066         const elem_src = inst_src; // TODO better source location
  26067         const elem_ref = try tupleField(sema, block, inst_src, inst, elem_src, i);
  26068         const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src);
  26069         element_refs[i] = coerced;
  26070         if (runtime_src == null) {
  26071             if (try sema.resolveMaybeUndefVal(block, elem_src, coerced)) |elem_val| {
  26072                 elem.* = elem_val;
  26073             } else {
  26074                 runtime_src = elem_src;
  26075             }
  26076         }
  26077     }
  26078 
  26079     if (runtime_src) |rs| {
  26080         try sema.requireRuntimeBlock(block, inst_src, rs);
  26081         return block.addAggregateInit(dest_ty, element_refs);
  26082     }
  26083 
  26084     return sema.addConstant(
  26085         dest_ty,
  26086         try Value.Tag.aggregate.create(sema.arena, element_vals),
  26087     );
  26088 }
  26089 
  26090 /// If the lengths match, coerces element-wise.
  26091 fn coerceTupleToSlicePtrs(
  26092     sema: *Sema,
  26093     block: *Block,
  26094     slice_ty: Type,
  26095     slice_ty_src: LazySrcLoc,
  26096     ptr_tuple: Air.Inst.Ref,
  26097     tuple_src: LazySrcLoc,
  26098 ) !Air.Inst.Ref {
  26099     const tuple_ty = sema.typeOf(ptr_tuple).childType();
  26100     const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src);
  26101     const slice_info = slice_ty.ptrInfo().data;
  26102     const array_ty = try Type.array(sema.arena, tuple_ty.structFieldCount(), slice_info.sentinel, slice_info.pointee_type, sema.mod);
  26103     const array_inst = try sema.coerceTupleToArray(block, array_ty, slice_ty_src, tuple, tuple_src);
  26104     if (slice_info.@"align" != 0) {
  26105         return sema.fail(block, slice_ty_src, "TODO: override the alignment of the array decl we create here", .{});
  26106     }
  26107     const ptr_array = try sema.analyzeRef(block, slice_ty_src, array_inst);
  26108     return sema.coerceArrayPtrToSlice(block, slice_ty, ptr_array, slice_ty_src);
  26109 }
  26110 
  26111 /// If the lengths match, coerces element-wise.
  26112 fn coerceTupleToArrayPtrs(
  26113     sema: *Sema,
  26114     block: *Block,
  26115     ptr_array_ty: Type,
  26116     array_ty_src: LazySrcLoc,
  26117     ptr_tuple: Air.Inst.Ref,
  26118     tuple_src: LazySrcLoc,
  26119 ) !Air.Inst.Ref {
  26120     const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src);
  26121     const ptr_info = ptr_array_ty.ptrInfo().data;
  26122     const array_ty = ptr_info.pointee_type;
  26123     const array_inst = try sema.coerceTupleToArray(block, array_ty, array_ty_src, tuple, tuple_src);
  26124     if (ptr_info.@"align" != 0) {
  26125         return sema.fail(block, array_ty_src, "TODO: override the alignment of the array decl we create here", .{});
  26126     }
  26127     const ptr_array = try sema.analyzeRef(block, array_ty_src, array_inst);
  26128     return ptr_array;
  26129 }
  26130 
  26131 /// Handles both tuples and anon struct literals. Coerces field-wise. Reports
  26132 /// errors for both extra fields and missing fields.
  26133 fn coerceTupleToStruct(
  26134     sema: *Sema,
  26135     block: *Block,
  26136     dest_ty: Type,
  26137     dest_ty_src: LazySrcLoc,
  26138     inst: Air.Inst.Ref,
  26139     inst_src: LazySrcLoc,
  26140 ) !Air.Inst.Ref {
  26141     const struct_ty = try sema.resolveTypeFields(block, dest_ty_src, dest_ty);
  26142 
  26143     if (struct_ty.isTupleOrAnonStruct()) {
  26144         return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src);
  26145     }
  26146 
  26147     const fields = struct_ty.structFields();
  26148     const field_vals = try sema.arena.alloc(Value, fields.count());
  26149     const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len);
  26150     mem.set(Air.Inst.Ref, field_refs, .none);
  26151 
  26152     const inst_ty = sema.typeOf(inst);
  26153     const tuple = inst_ty.tupleFields();
  26154     var runtime_src: ?LazySrcLoc = null;
  26155     for (tuple.types) |_, i_usize| {
  26156         const i = @intCast(u32, i_usize);
  26157         const field_src = inst_src; // TODO better source location
  26158         const field_name = if (inst_ty.castTag(.anon_struct)) |payload|
  26159             payload.data.names[i]
  26160         else
  26161             try std.fmt.allocPrint(sema.arena, "{d}", .{i});
  26162         const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
  26163         const field = fields.values()[field_index];
  26164         const elem_ref = try tupleField(sema, block, inst_src, inst, field_src, i);
  26165         const coerced = try sema.coerce(block, field.ty, elem_ref, field_src);
  26166         field_refs[field_index] = coerced;
  26167         if (field.is_comptime) {
  26168             const init_val = (try sema.resolveMaybeUndefVal(block, field_src, coerced)) orelse {
  26169                 return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime known");
  26170             };
  26171 
  26172             if (!init_val.eql(field.default_val, field.ty, sema.mod)) {
  26173                 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, i);
  26174             }
  26175         }
  26176         if (runtime_src == null) {
  26177             if (try sema.resolveMaybeUndefVal(block, field_src, coerced)) |field_val| {
  26178                 field_vals[field_index] = field_val;
  26179             } else {
  26180                 runtime_src = field_src;
  26181             }
  26182         }
  26183     }
  26184 
  26185     // Populate default field values and report errors for missing fields.
  26186     var root_msg: ?*Module.ErrorMsg = null;
  26187     errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
  26188 
  26189     for (field_refs) |*field_ref, i| {
  26190         if (field_ref.* != .none) continue;
  26191 
  26192         const field_name = fields.keys()[i];
  26193         const field = fields.values()[i];
  26194         const field_src = inst_src; // TODO better source location
  26195         if (field.default_val.tag() == .unreachable_value) {
  26196             const template = "missing struct field: {s}";
  26197             const args = .{field_name};
  26198             if (root_msg) |msg| {
  26199                 try sema.errNote(block, field_src, msg, template, args);
  26200             } else {
  26201                 root_msg = try sema.errMsg(block, field_src, template, args);
  26202             }
  26203             continue;
  26204         }
  26205         if (runtime_src == null) {
  26206             field_vals[i] = field.default_val;
  26207         } else {
  26208             field_ref.* = try sema.addConstant(field.ty, field.default_val);
  26209         }
  26210     }
  26211 
  26212     if (root_msg) |msg| {
  26213         root_msg = null;
  26214         try sema.addDeclaredHereNote(msg, struct_ty);
  26215         return sema.failWithOwnedErrorMsg(msg);
  26216     }
  26217 
  26218     if (runtime_src) |rs| {
  26219         try sema.requireRuntimeBlock(block, inst_src, rs);
  26220         return block.addAggregateInit(struct_ty, field_refs);
  26221     }
  26222 
  26223     return sema.addConstant(
  26224         struct_ty,
  26225         try Value.Tag.aggregate.create(sema.arena, field_vals),
  26226     );
  26227 }
  26228 
  26229 fn coerceTupleToTuple(
  26230     sema: *Sema,
  26231     block: *Block,
  26232     tuple_ty: Type,
  26233     inst: Air.Inst.Ref,
  26234     inst_src: LazySrcLoc,
  26235 ) !Air.Inst.Ref {
  26236     const field_count = tuple_ty.structFieldCount();
  26237     const field_vals = try sema.arena.alloc(Value, field_count);
  26238     const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len);
  26239     mem.set(Air.Inst.Ref, field_refs, .none);
  26240 
  26241     const inst_ty = sema.typeOf(inst);
  26242     const tuple = inst_ty.tupleFields();
  26243     var runtime_src: ?LazySrcLoc = null;
  26244     for (tuple.types) |_, i_usize| {
  26245         const i = @intCast(u32, i_usize);
  26246         const field_src = inst_src; // TODO better source location
  26247         const field_name = if (inst_ty.castTag(.anon_struct)) |payload|
  26248             payload.data.names[i]
  26249         else
  26250             try std.fmt.allocPrint(sema.arena, "{d}", .{i});
  26251 
  26252         if (mem.eql(u8, field_name, "len")) {
  26253             return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{});
  26254         }
  26255 
  26256         const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src);
  26257 
  26258         const field_ty = tuple_ty.structFieldType(i);
  26259         const default_val = tuple_ty.structFieldDefaultValue(i);
  26260         const elem_ref = try tupleField(sema, block, inst_src, inst, field_src, i);
  26261         const coerced = try sema.coerce(block, field_ty, elem_ref, field_src);
  26262         field_refs[field_index] = coerced;
  26263         if (default_val.tag() != .unreachable_value) {
  26264             const init_val = (try sema.resolveMaybeUndefVal(block, field_src, coerced)) orelse {
  26265                 return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime known");
  26266             };
  26267 
  26268             if (!init_val.eql(default_val, field_ty, sema.mod)) {
  26269                 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, i);
  26270             }
  26271         }
  26272         if (runtime_src == null) {
  26273             if (try sema.resolveMaybeUndefVal(block, field_src, coerced)) |field_val| {
  26274                 field_vals[field_index] = field_val;
  26275             } else {
  26276                 runtime_src = field_src;
  26277             }
  26278         }
  26279     }
  26280 
  26281     // Populate default field values and report errors for missing fields.
  26282     var root_msg: ?*Module.ErrorMsg = null;
  26283     errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
  26284 
  26285     for (field_refs) |*field_ref, i| {
  26286         if (field_ref.* != .none) continue;
  26287 
  26288         const default_val = tuple_ty.structFieldDefaultValue(i);
  26289         const field_ty = tuple_ty.structFieldType(i);
  26290 
  26291         const field_src = inst_src; // TODO better source location
  26292         if (default_val.tag() == .unreachable_value) {
  26293             if (tuple_ty.isTuple()) {
  26294                 const template = "missing tuple field: {d}";
  26295                 if (root_msg) |msg| {
  26296                     try sema.errNote(block, field_src, msg, template, .{i});
  26297                 } else {
  26298                     root_msg = try sema.errMsg(block, field_src, template, .{i});
  26299                 }
  26300                 continue;
  26301             }
  26302             const template = "missing struct field: {s}";
  26303             const args = .{tuple_ty.structFieldName(i)};
  26304             if (root_msg) |msg| {
  26305                 try sema.errNote(block, field_src, msg, template, args);
  26306             } else {
  26307                 root_msg = try sema.errMsg(block, field_src, template, args);
  26308             }
  26309             continue;
  26310         }
  26311         if (runtime_src == null) {
  26312             field_vals[i] = default_val;
  26313         } else {
  26314             field_ref.* = try sema.addConstant(field_ty, default_val);
  26315         }
  26316     }
  26317 
  26318     if (root_msg) |msg| {
  26319         root_msg = null;
  26320         try sema.addDeclaredHereNote(msg, tuple_ty);
  26321         return sema.failWithOwnedErrorMsg(msg);
  26322     }
  26323 
  26324     if (runtime_src) |rs| {
  26325         try sema.requireRuntimeBlock(block, inst_src, rs);
  26326         return block.addAggregateInit(tuple_ty, field_refs);
  26327     }
  26328 
  26329     return sema.addConstant(
  26330         tuple_ty,
  26331         try Value.Tag.aggregate.create(sema.arena, field_vals),
  26332     );
  26333 }
  26334 
  26335 fn analyzeDeclVal(
  26336     sema: *Sema,
  26337     block: *Block,
  26338     src: LazySrcLoc,
  26339     decl_index: Decl.Index,
  26340 ) CompileError!Air.Inst.Ref {
  26341     if (sema.decl_val_table.get(decl_index)) |result| {
  26342         return result;
  26343     }
  26344     try sema.addReferencedBy(block, src, decl_index);
  26345     const decl_ref = try sema.analyzeDeclRef(decl_index);
  26346     const result = try sema.analyzeLoad(block, src, decl_ref, src);
  26347     if (Air.refToIndex(result)) |index| {
  26348         if (sema.air_instructions.items(.tag)[index] == .constant and !block.is_typeof) {
  26349             try sema.decl_val_table.put(sema.gpa, decl_index, result);
  26350         }
  26351     }
  26352     return result;
  26353 }
  26354 
  26355 fn addReferencedBy(
  26356     sema: *Sema,
  26357     block: *Block,
  26358     src: LazySrcLoc,
  26359     decl_index: Decl.Index,
  26360 ) !void {
  26361     if (sema.mod.comp.reference_trace == @as(u32, 0)) return;
  26362     try sema.mod.reference_table.put(sema.gpa, decl_index, .{
  26363         .referencer = block.src_decl,
  26364         .src = src,
  26365     });
  26366 }
  26367 
  26368 fn ensureDeclAnalyzed(sema: *Sema, decl_index: Decl.Index) CompileError!void {
  26369     const decl = sema.mod.declPtr(decl_index);
  26370     if (decl.analysis == .in_progress) {
  26371         const msg = try Module.ErrorMsg.create(sema.gpa, decl.srcLoc(), "dependency loop detected", .{});
  26372         return sema.failWithOwnedErrorMsg(msg);
  26373     }
  26374 
  26375     sema.mod.ensureDeclAnalyzed(decl_index) catch |err| {
  26376         if (sema.owner_func) |owner_func| {
  26377             owner_func.state = .dependency_failure;
  26378         } else {
  26379             sema.owner_decl.analysis = .dependency_failure;
  26380         }
  26381         return err;
  26382     };
  26383 }
  26384 
  26385 fn ensureFuncBodyAnalyzed(sema: *Sema, func: *Module.Fn) CompileError!void {
  26386     sema.mod.ensureFuncBodyAnalyzed(func) catch |err| {
  26387         if (sema.owner_func) |owner_func| {
  26388             owner_func.state = .dependency_failure;
  26389         } else {
  26390             sema.owner_decl.analysis = .dependency_failure;
  26391         }
  26392         return err;
  26393     };
  26394 }
  26395 
  26396 fn refValue(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, val: Value) !Value {
  26397     var anon_decl = try block.startAnonDecl(src);
  26398     defer anon_decl.deinit();
  26399     const decl = try anon_decl.finish(
  26400         try ty.copy(anon_decl.arena()),
  26401         try val.copy(anon_decl.arena()),
  26402         0, // default alignment
  26403     );
  26404     try sema.mod.declareDeclDependency(sema.owner_decl_index, decl);
  26405     return try Value.Tag.decl_ref.create(sema.arena, decl);
  26406 }
  26407 
  26408 fn optRefValue(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, opt_val: ?Value) !Value {
  26409     const val = opt_val orelse return Value.@"null";
  26410     const ptr_val = try refValue(sema, block, src, ty, val);
  26411     const result = try Value.Tag.opt_payload.create(sema.arena, ptr_val);
  26412     return result;
  26413 }
  26414 
  26415 fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref {
  26416     try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index);
  26417     try sema.ensureDeclAnalyzed(decl_index);
  26418 
  26419     const decl = sema.mod.declPtr(decl_index);
  26420     const decl_tv = try decl.typedValue();
  26421     if (decl_tv.val.castTag(.variable)) |payload| {
  26422         const variable = payload.data;
  26423         const ty = try Type.ptr(sema.arena, sema.mod, .{
  26424             .pointee_type = decl_tv.ty,
  26425             .mutable = variable.is_mutable,
  26426             .@"addrspace" = decl.@"addrspace",
  26427             .@"align" = decl.@"align",
  26428         });
  26429         return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl_index));
  26430     }
  26431     return sema.addConstant(
  26432         try Type.ptr(sema.arena, sema.mod, .{
  26433             .pointee_type = decl_tv.ty,
  26434             .mutable = false,
  26435             .@"addrspace" = decl.@"addrspace",
  26436             .@"align" = decl.@"align",
  26437         }),
  26438         try Value.Tag.decl_ref.create(sema.arena, decl_index),
  26439     );
  26440 }
  26441 
  26442 fn analyzeRef(
  26443     sema: *Sema,
  26444     block: *Block,
  26445     src: LazySrcLoc,
  26446     operand: Air.Inst.Ref,
  26447 ) CompileError!Air.Inst.Ref {
  26448     const operand_ty = sema.typeOf(operand);
  26449 
  26450     if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {
  26451         var anon_decl = try block.startAnonDecl(src);
  26452         defer anon_decl.deinit();
  26453         return sema.analyzeDeclRef(try anon_decl.finish(
  26454             try operand_ty.copy(anon_decl.arena()),
  26455             try val.copy(anon_decl.arena()),
  26456             0, // default alignment
  26457         ));
  26458     }
  26459 
  26460     try sema.requireRuntimeBlock(block, src, null);
  26461     const address_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);
  26462     const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
  26463         .pointee_type = operand_ty,
  26464         .mutable = false,
  26465         .@"addrspace" = address_space,
  26466     });
  26467     const mut_ptr_type = try Type.ptr(sema.arena, sema.mod, .{
  26468         .pointee_type = operand_ty,
  26469         .@"addrspace" = address_space,
  26470     });
  26471     const alloc = try block.addTy(.alloc, mut_ptr_type);
  26472     try sema.storePtr(block, src, alloc, operand);
  26473 
  26474     // TODO: Replace with sema.coerce when that supports adding pointer constness.
  26475     return sema.bitCast(block, ptr_type, alloc, src);
  26476 }
  26477 
  26478 fn analyzeLoad(
  26479     sema: *Sema,
  26480     block: *Block,
  26481     src: LazySrcLoc,
  26482     ptr: Air.Inst.Ref,
  26483     ptr_src: LazySrcLoc,
  26484 ) CompileError!Air.Inst.Ref {
  26485     const ptr_ty = sema.typeOf(ptr);
  26486     const elem_ty = switch (ptr_ty.zigTypeTag()) {
  26487         .Pointer => ptr_ty.childType(),
  26488         else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}),
  26489     };
  26490 
  26491     if (try sema.typeHasOnePossibleValue(block, src, elem_ty)) |opv| {
  26492         return sema.addConstant(elem_ty, opv);
  26493     }
  26494 
  26495     if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
  26496         if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| {
  26497             return sema.addConstant(elem_ty, elem_val);
  26498         }
  26499         if (block.is_typeof) {
  26500             return sema.addConstUndef(elem_ty);
  26501         }
  26502     }
  26503 
  26504     if (block.is_comptime) {
  26505         // TODO ideally this would tell why the block is comptime
  26506         return sema.fail(block, ptr_src, "cannot load runtime value in comptime block", .{});
  26507     }
  26508 
  26509     try sema.requireFunctionBlock(block, src);
  26510     return block.addTyOp(.load, elem_ty, ptr);
  26511 }
  26512 
  26513 fn analyzeSlicePtr(
  26514     sema: *Sema,
  26515     block: *Block,
  26516     slice_src: LazySrcLoc,
  26517     slice: Air.Inst.Ref,
  26518     slice_ty: Type,
  26519 ) CompileError!Air.Inst.Ref {
  26520     const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer);
  26521     const result_ty = slice_ty.slicePtrFieldType(buf);
  26522     if (try sema.resolveMaybeUndefVal(block, slice_src, slice)) |val| {
  26523         if (val.isUndef()) return sema.addConstUndef(result_ty);
  26524         return sema.addConstant(result_ty, val.slicePtr());
  26525     }
  26526     try sema.requireRuntimeBlock(block, slice_src, null);
  26527     return block.addTyOp(.slice_ptr, result_ty, slice);
  26528 }
  26529 
  26530 fn analyzeSliceLen(
  26531     sema: *Sema,
  26532     block: *Block,
  26533     src: LazySrcLoc,
  26534     slice_inst: Air.Inst.Ref,
  26535 ) CompileError!Air.Inst.Ref {
  26536     if (try sema.resolveMaybeUndefVal(block, src, slice_inst)) |slice_val| {
  26537         if (slice_val.isUndef()) {
  26538             return sema.addConstUndef(Type.usize);
  26539         }
  26540         return sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod));
  26541     }
  26542     try sema.requireRuntimeBlock(block, src, null);
  26543     return block.addTyOp(.slice_len, Type.usize, slice_inst);
  26544 }
  26545 
  26546 fn analyzeIsNull(
  26547     sema: *Sema,
  26548     block: *Block,
  26549     src: LazySrcLoc,
  26550     operand: Air.Inst.Ref,
  26551     invert_logic: bool,
  26552 ) CompileError!Air.Inst.Ref {
  26553     const result_ty = Type.bool;
  26554     if (try sema.resolveMaybeUndefVal(block, src, operand)) |opt_val| {
  26555         if (opt_val.isUndef()) {
  26556             return sema.addConstUndef(result_ty);
  26557         }
  26558         const is_null = opt_val.isNull();
  26559         const bool_value = if (invert_logic) !is_null else is_null;
  26560         if (bool_value) {
  26561             return Air.Inst.Ref.bool_true;
  26562         } else {
  26563             return Air.Inst.Ref.bool_false;
  26564         }
  26565     }
  26566 
  26567     const operand_ty = sema.typeOf(operand);
  26568     var buf: Type.Payload.ElemType = undefined;
  26569     if (operand_ty.zigTypeTag() == .Optional and operand_ty.optionalChild(&buf).zigTypeTag() == .NoReturn) {
  26570         return Air.Inst.Ref.bool_true;
  26571     }
  26572     try sema.requireRuntimeBlock(block, src, null);
  26573     const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null;
  26574     return block.addUnOp(air_tag, operand);
  26575 }
  26576 
  26577 fn analyzePtrIsNonErrComptimeOnly(
  26578     sema: *Sema,
  26579     block: *Block,
  26580     src: LazySrcLoc,
  26581     operand: Air.Inst.Ref,
  26582 ) CompileError!Air.Inst.Ref {
  26583     const ptr_ty = sema.typeOf(operand);
  26584     assert(ptr_ty.zigTypeTag() == .Pointer);
  26585     const child_ty = ptr_ty.childType();
  26586 
  26587     const child_tag = child_ty.zigTypeTag();
  26588     if (child_tag != .ErrorSet and child_tag != .ErrorUnion) return Air.Inst.Ref.bool_true;
  26589     if (child_tag == .ErrorSet) return Air.Inst.Ref.bool_false;
  26590     assert(child_tag == .ErrorUnion);
  26591 
  26592     _ = block;
  26593     _ = src;
  26594 
  26595     return Air.Inst.Ref.none;
  26596 }
  26597 
  26598 fn analyzeIsNonErrComptimeOnly(
  26599     sema: *Sema,
  26600     block: *Block,
  26601     src: LazySrcLoc,
  26602     operand: Air.Inst.Ref,
  26603 ) CompileError!Air.Inst.Ref {
  26604     const operand_ty = sema.typeOf(operand);
  26605     const ot = operand_ty.zigTypeTag();
  26606     if (ot != .ErrorSet and ot != .ErrorUnion) return Air.Inst.Ref.bool_true;
  26607     if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;
  26608     assert(ot == .ErrorUnion);
  26609 
  26610     const payload_ty = operand_ty.errorUnionPayload();
  26611     if (payload_ty.zigTypeTag() == .NoReturn) {
  26612         return Air.Inst.Ref.bool_false;
  26613     }
  26614 
  26615     if (Air.refToIndex(operand)) |operand_inst| {
  26616         switch (sema.air_instructions.items(.tag)[operand_inst]) {
  26617             .wrap_errunion_payload => return Air.Inst.Ref.bool_true,
  26618             .wrap_errunion_err => return Air.Inst.Ref.bool_false,
  26619             else => {},
  26620         }
  26621     } else if (operand == .undef) {
  26622         return sema.addConstUndef(Type.bool);
  26623     } else {
  26624         // None of the ref tags can be errors.
  26625         return Air.Inst.Ref.bool_true;
  26626     }
  26627 
  26628     const maybe_operand_val = try sema.resolveMaybeUndefVal(block, src, operand);
  26629 
  26630     // exception if the error union error set is known to be empty,
  26631     // we allow the comparison but always make it comptime known.
  26632     const set_ty = operand_ty.errorUnionSet();
  26633     switch (set_ty.tag()) {
  26634         .anyerror => {},
  26635         .error_set_inferred => blk: {
  26636             // If the error set is empty, we must return a comptime true or false.
  26637             // However we want to avoid unnecessarily resolving an inferred error set
  26638             // in case it is already non-empty.
  26639             const ies = set_ty.castTag(.error_set_inferred).?.data;
  26640             if (ies.is_anyerror) break :blk;
  26641             if (ies.errors.count() != 0) break :blk;
  26642             if (maybe_operand_val == null) {
  26643                 // Try to avoid resolving inferred error set if possible.
  26644                 if (ies.errors.count() != 0) break :blk;
  26645                 if (ies.is_anyerror) break :blk;
  26646                 var it = ies.inferred_error_sets.keyIterator();
  26647                 while (it.next()) |other_error_set_ptr| {
  26648                     const other_ies: *Module.Fn.InferredErrorSet = other_error_set_ptr.*;
  26649                     if (ies == other_ies) continue;
  26650                     try sema.resolveInferredErrorSet(block, src, other_ies);
  26651                     if (other_ies.is_anyerror) {
  26652                         ies.is_anyerror = true;
  26653                         ies.is_resolved = true;
  26654                         break :blk;
  26655                     }
  26656 
  26657                     if (other_ies.errors.count() != 0) break :blk;
  26658                 }
  26659                 if (ies.func == sema.owner_func) {
  26660                     // We're checking the inferred errorset of the current function and none of
  26661                     // its child inferred error sets contained any errors meaning that any value
  26662                     // so far with this type can't contain errors either.
  26663                     return Air.Inst.Ref.bool_true;
  26664                 }
  26665                 try sema.resolveInferredErrorSet(block, src, ies);
  26666                 if (ies.is_anyerror) break :blk;
  26667                 if (ies.errors.count() == 0) return Air.Inst.Ref.bool_true;
  26668             }
  26669         },
  26670         else => if (set_ty.errorSetNames().len == 0) return Air.Inst.Ref.bool_true,
  26671     }
  26672 
  26673     if (maybe_operand_val) |err_union| {
  26674         if (err_union.isUndef()) {
  26675             return sema.addConstUndef(Type.bool);
  26676         }
  26677         if (err_union.getError() == null) {
  26678             return Air.Inst.Ref.bool_true;
  26679         } else {
  26680             return Air.Inst.Ref.bool_false;
  26681         }
  26682     }
  26683     return Air.Inst.Ref.none;
  26684 }
  26685 
  26686 fn analyzeIsNonErr(
  26687     sema: *Sema,
  26688     block: *Block,
  26689     src: LazySrcLoc,
  26690     operand: Air.Inst.Ref,
  26691 ) CompileError!Air.Inst.Ref {
  26692     const result = try sema.analyzeIsNonErrComptimeOnly(block, src, operand);
  26693     if (result == .none) {
  26694         try sema.requireRuntimeBlock(block, src, null);
  26695         return block.addUnOp(.is_non_err, operand);
  26696     } else {
  26697         return result;
  26698     }
  26699 }
  26700 
  26701 fn analyzePtrIsNonErr(
  26702     sema: *Sema,
  26703     block: *Block,
  26704     src: LazySrcLoc,
  26705     operand: Air.Inst.Ref,
  26706 ) CompileError!Air.Inst.Ref {
  26707     const result = try sema.analyzePtrIsNonErrComptimeOnly(block, src, operand);
  26708     if (result == .none) {
  26709         try sema.requireRuntimeBlock(block, src, null);
  26710         return block.addUnOp(.is_non_err_ptr, operand);
  26711     } else {
  26712         return result;
  26713     }
  26714 }
  26715 
  26716 fn analyzeSlice(
  26717     sema: *Sema,
  26718     block: *Block,
  26719     src: LazySrcLoc,
  26720     ptr_ptr: Air.Inst.Ref,
  26721     uncasted_start: Air.Inst.Ref,
  26722     uncasted_end_opt: Air.Inst.Ref,
  26723     sentinel_opt: Air.Inst.Ref,
  26724     sentinel_src: LazySrcLoc,
  26725 ) CompileError!Air.Inst.Ref {
  26726     const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = src.node_offset.x };
  26727     const start_src: LazySrcLoc = .{ .node_offset_slice_start = src.node_offset.x };
  26728     const end_src: LazySrcLoc = .{ .node_offset_slice_end = src.node_offset.x };
  26729     // Slice expressions can operate on a variable whose type is an array. This requires
  26730     // the slice operand to be a pointer. In the case of a non-array, it will be a double pointer.
  26731     const ptr_ptr_ty = sema.typeOf(ptr_ptr);
  26732     const target = sema.mod.getTarget();
  26733     const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag()) {
  26734         .Pointer => ptr_ptr_ty.elemType(),
  26735         else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(sema.mod)}),
  26736     };
  26737     const mod = sema.mod;
  26738 
  26739     var array_ty = ptr_ptr_child_ty;
  26740     var slice_ty = ptr_ptr_ty;
  26741     var ptr_or_slice = ptr_ptr;
  26742     var elem_ty: Type = undefined;
  26743     var ptr_sentinel: ?Value = null;
  26744     switch (ptr_ptr_child_ty.zigTypeTag()) {
  26745         .Array => {
  26746             ptr_sentinel = ptr_ptr_child_ty.sentinel();
  26747             elem_ty = ptr_ptr_child_ty.childType();
  26748         },
  26749         .Pointer => switch (ptr_ptr_child_ty.ptrSize()) {
  26750             .One => {
  26751                 const double_child_ty = ptr_ptr_child_ty.childType();
  26752                 if (double_child_ty.zigTypeTag() == .Array) {
  26753                     ptr_sentinel = double_child_ty.sentinel();
  26754                     ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
  26755                     slice_ty = ptr_ptr_child_ty;
  26756                     array_ty = double_child_ty;
  26757                     elem_ty = double_child_ty.childType();
  26758                 } else {
  26759                     return sema.fail(block, src, "slice of single-item pointer", .{});
  26760                 }
  26761             },
  26762             .Many, .C => {
  26763                 ptr_sentinel = ptr_ptr_child_ty.sentinel();
  26764                 ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
  26765                 slice_ty = ptr_ptr_child_ty;
  26766                 array_ty = ptr_ptr_child_ty;
  26767                 elem_ty = ptr_ptr_child_ty.childType();
  26768 
  26769                 if (ptr_ptr_child_ty.ptrSize() == .C) {
  26770                     if (try sema.resolveDefinedValue(block, ptr_src, ptr_or_slice)) |ptr_val| {
  26771                         if (ptr_val.isNull()) {
  26772                             return sema.fail(block, src, "slice of null pointer", .{});
  26773                         }
  26774                     }
  26775                 }
  26776             },
  26777             .Slice => {
  26778                 ptr_sentinel = ptr_ptr_child_ty.sentinel();
  26779                 ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
  26780                 slice_ty = ptr_ptr_child_ty;
  26781                 array_ty = ptr_ptr_child_ty;
  26782                 elem_ty = ptr_ptr_child_ty.childType();
  26783             },
  26784         },
  26785         else => return sema.fail(block, src, "slice of non-array type '{}'", .{ptr_ptr_child_ty.fmt(mod)}),
  26786     }
  26787 
  26788     const ptr = if (slice_ty.isSlice())
  26789         try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty)
  26790     else
  26791         ptr_or_slice;
  26792 
  26793     const start = try sema.coerce(block, Type.usize, uncasted_start, start_src);
  26794     const new_ptr = try analyzePtrArithmetic(sema, block, src, ptr, start, .ptr_add, ptr_src, start_src);
  26795 
  26796     // true if and only if the end index of the slice, implicitly or explicitly, equals
  26797     // the length of the underlying object being sliced. we might learn the length of the
  26798     // underlying object because it is an array (which has the length in the type), or
  26799     // we might learn of the length because it is a comptime-known slice value.
  26800     var end_is_len = uncasted_end_opt == .none;
  26801     const end = e: {
  26802         if (array_ty.zigTypeTag() == .Array) {
  26803             const len_val = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen());
  26804 
  26805             if (!end_is_len) {
  26806                 const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
  26807                 if (try sema.resolveMaybeUndefVal(block, end_src, end)) |end_val| {
  26808                     const len_s_val = try Value.Tag.int_u64.create(
  26809                         sema.arena,
  26810                         array_ty.arrayLenIncludingSentinel(),
  26811                     );
  26812                     if (try sema.compare(block, src, end_val, .gt, len_s_val, Type.usize)) {
  26813                         const sentinel_label: []const u8 = if (array_ty.sentinel() != null)
  26814                             " +1 (sentinel)"
  26815                         else
  26816                             "";
  26817 
  26818                         return sema.fail(
  26819                             block,
  26820                             end_src,
  26821                             "end index {} out of bounds for array of length {}{s}",
  26822                             .{
  26823                                 end_val.fmtValue(Type.usize, mod),
  26824                                 len_val.fmtValue(Type.usize, mod),
  26825                                 sentinel_label,
  26826                             },
  26827                         );
  26828                     }
  26829 
  26830                     // end_is_len is only true if we are NOT using the sentinel
  26831                     // length. For sentinel-length, we don't want the type to
  26832                     // contain the sentinel.
  26833                     if (end_val.eql(len_val, Type.usize, mod)) {
  26834                         end_is_len = true;
  26835                     }
  26836                 }
  26837                 break :e end;
  26838             }
  26839 
  26840             break :e try sema.addConstant(Type.usize, len_val);
  26841         } else if (slice_ty.isSlice()) {
  26842             if (!end_is_len) {
  26843                 const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
  26844                 if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {
  26845                     if (try sema.resolveMaybeUndefVal(block, src, ptr_or_slice)) |slice_val| {
  26846                         if (slice_val.isUndef()) {
  26847                             return sema.fail(block, src, "slice of undefined", .{});
  26848                         }
  26849                         const has_sentinel = slice_ty.sentinel() != null;
  26850                         var int_payload: Value.Payload.U64 = .{
  26851                             .base = .{ .tag = .int_u64 },
  26852                             .data = slice_val.sliceLen(mod) + @boolToInt(has_sentinel),
  26853                         };
  26854                         const slice_len_val = Value.initPayload(&int_payload.base);
  26855                         if (try sema.compare(block, src, end_val, .gt, slice_len_val, Type.usize)) {
  26856                             const sentinel_label: []const u8 = if (has_sentinel)
  26857                                 " +1 (sentinel)"
  26858                             else
  26859                                 "";
  26860 
  26861                             return sema.fail(
  26862                                 block,
  26863                                 end_src,
  26864                                 "end index {} out of bounds for slice of length {d}{s}",
  26865                                 .{
  26866                                     end_val.fmtValue(Type.usize, mod),
  26867                                     slice_val.sliceLen(mod),
  26868                                     sentinel_label,
  26869                                 },
  26870                             );
  26871                         }
  26872 
  26873                         // If the slice has a sentinel, we subtract one so that
  26874                         // end_is_len is only true if it equals the length WITHOUT
  26875                         // the sentinel, so we don't add a sentinel type.
  26876                         if (has_sentinel) {
  26877                             int_payload.data -= 1;
  26878                         }
  26879 
  26880                         if (end_val.eql(slice_len_val, Type.usize, mod)) {
  26881                             end_is_len = true;
  26882                         }
  26883                     }
  26884                 }
  26885                 break :e end;
  26886             }
  26887             break :e try sema.analyzeSliceLen(block, src, ptr_or_slice);
  26888         }
  26889         if (!end_is_len) {
  26890             break :e try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
  26891         }
  26892         return sema.fail(block, end_src, "slice of pointer must include end value", .{});
  26893     };
  26894 
  26895     const sentinel = s: {
  26896         if (sentinel_opt != .none) {
  26897             const casted = try sema.coerce(block, elem_ty, sentinel_opt, sentinel_src);
  26898             break :s try sema.resolveConstValue(block, sentinel_src, casted, "slice sentinel must be comptime known");
  26899         }
  26900         // If we are slicing to the end of something that is sentinel-terminated
  26901         // then the resulting slice type is also sentinel-terminated.
  26902         if (end_is_len) {
  26903             if (ptr_sentinel) |sent| {
  26904                 break :s sent;
  26905             }
  26906         }
  26907         break :s null;
  26908     };
  26909     const slice_sentinel = if (sentinel_opt != .none) sentinel else null;
  26910 
  26911     // requirement: start <= end
  26912     if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {
  26913         if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| {
  26914             if (try sema.compare(block, src, start_val, .gt, end_val, Type.usize)) {
  26915                 return sema.fail(
  26916                     block,
  26917                     start_src,
  26918                     "start index {} is larger than end index {}",
  26919                     .{
  26920                         start_val.fmtValue(Type.usize, mod),
  26921                         end_val.fmtValue(Type.usize, mod),
  26922                     },
  26923                 );
  26924             }
  26925             if (try sema.resolveMaybeUndefVal(block, ptr_src, new_ptr)) |ptr_val| sentinel_check: {
  26926                 const expected_sentinel = sentinel orelse break :sentinel_check;
  26927                 const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?;
  26928                 const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?;
  26929                 const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int);
  26930 
  26931                 const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod);
  26932                 const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false);
  26933                 const actual_sentinel = switch (res) {
  26934                     .runtime_load => break :sentinel_check,
  26935                     .val => |v| v,
  26936                     .needed_well_defined => |ty| return sema.fail(
  26937                         block,
  26938                         src,
  26939                         "comptime dereference requires '{}' to have a well-defined layout, but it does not.",
  26940                         .{ty.fmt(sema.mod)},
  26941                     ),
  26942                     .out_of_bounds => |ty| return sema.fail(
  26943                         block,
  26944                         end_src,
  26945                         "slice end index {d} exceeds bounds of containing decl of type '{}'",
  26946                         .{ end_int, ty.fmt(sema.mod) },
  26947                     ),
  26948                 };
  26949 
  26950                 if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) {
  26951                     const msg = msg: {
  26952                         const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{});
  26953                         errdefer msg.destroy(sema.gpa);
  26954                         try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{
  26955                             expected_sentinel.fmtValue(elem_ty, sema.mod),
  26956                             actual_sentinel.fmtValue(elem_ty, sema.mod),
  26957                         });
  26958 
  26959                         break :msg msg;
  26960                     };
  26961                     return sema.failWithOwnedErrorMsg(msg);
  26962                 }
  26963             }
  26964         }
  26965     }
  26966 
  26967     const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src);
  26968     const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);
  26969 
  26970     const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;
  26971     const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize() != .C;
  26972 
  26973     if (opt_new_len_val) |new_len_val| {
  26974         const new_len_int = new_len_val.toUnsignedInt(target);
  26975 
  26976         const return_ty = try Type.ptr(sema.arena, mod, .{
  26977             .pointee_type = try Type.array(sema.arena, new_len_int, sentinel, elem_ty, mod),
  26978             .sentinel = null,
  26979             .@"align" = new_ptr_ty_info.@"align",
  26980             .@"addrspace" = new_ptr_ty_info.@"addrspace",
  26981             .mutable = new_ptr_ty_info.mutable,
  26982             .@"allowzero" = new_allowzero,
  26983             .@"volatile" = new_ptr_ty_info.@"volatile",
  26984             .size = .One,
  26985         });
  26986 
  26987         const opt_new_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, new_ptr);
  26988         const new_ptr_val = opt_new_ptr_val orelse {
  26989             const result = try block.addBitCast(return_ty, new_ptr);
  26990             if (block.wantSafety()) {
  26991                 // requirement: slicing C ptr is non-null
  26992                 if (ptr_ptr_child_ty.isCPtr()) {
  26993                     const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true);
  26994                     try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
  26995                 }
  26996 
  26997                 if (slice_ty.isSlice()) {
  26998                     const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice);
  26999                     const actual_len = if (slice_ty.sentinel() == null)
  27000                         slice_len_inst
  27001                     else
  27002                         try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);
  27003 
  27004                     const actual_end = if (slice_sentinel != null)
  27005                         try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src)
  27006                     else
  27007                         end;
  27008 
  27009                     try sema.panicIndexOutOfBounds(block, src, actual_end, actual_len, .cmp_lte);
  27010                 }
  27011 
  27012                 // requirement: result[new_len] == slice_sentinel
  27013                 try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len);
  27014             }
  27015             return result;
  27016         };
  27017 
  27018         if (!new_ptr_val.isUndef()) {
  27019             return sema.addConstant(return_ty, new_ptr_val);
  27020         }
  27021 
  27022         // Special case: @as([]i32, undefined)[x..x]
  27023         if (new_len_int == 0) {
  27024             return sema.addConstUndef(return_ty);
  27025         }
  27026 
  27027         return sema.fail(block, src, "non-zero length slice of undefined pointer", .{});
  27028     }
  27029 
  27030     const return_ty = try Type.ptr(sema.arena, mod, .{
  27031         .pointee_type = elem_ty,
  27032         .sentinel = sentinel,
  27033         .@"align" = new_ptr_ty_info.@"align",
  27034         .@"addrspace" = new_ptr_ty_info.@"addrspace",
  27035         .mutable = new_ptr_ty_info.mutable,
  27036         .@"allowzero" = new_allowzero,
  27037         .@"volatile" = new_ptr_ty_info.@"volatile",
  27038         .size = .Slice,
  27039     });
  27040 
  27041     const runtime_src = if ((try sema.resolveMaybeUndefVal(block, ptr_src, ptr_or_slice)) == null)
  27042         ptr_src
  27043     else if ((try sema.resolveMaybeUndefVal(block, src, start)) == null)
  27044         start_src
  27045     else
  27046         end_src;
  27047 
  27048     try sema.requireRuntimeBlock(block, src, runtime_src);
  27049     if (block.wantSafety()) {
  27050         // requirement: slicing C ptr is non-null
  27051         if (ptr_ptr_child_ty.isCPtr()) {
  27052             const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true);
  27053             try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
  27054         }
  27055 
  27056         // requirement: end <= len
  27057         const opt_len_inst = if (array_ty.zigTypeTag() == .Array)
  27058             try sema.addIntUnsigned(Type.usize, array_ty.arrayLenIncludingSentinel())
  27059         else if (slice_ty.isSlice()) blk: {
  27060             if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| {
  27061                 // we don't need to add one for sentinels because the
  27062                 // underlying value data includes the sentinel
  27063                 break :blk try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(mod));
  27064             }
  27065 
  27066             const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice);
  27067             if (slice_ty.sentinel() == null) break :blk slice_len_inst;
  27068 
  27069             // we have to add one because slice lengths don't include the sentinel
  27070             break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);
  27071         } else null;
  27072         if (opt_len_inst) |len_inst| {
  27073             const actual_end = if (slice_sentinel != null)
  27074                 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src)
  27075             else
  27076                 end;
  27077             try sema.panicIndexOutOfBounds(block, src, actual_end, len_inst, .cmp_lte);
  27078         }
  27079 
  27080         // requirement: start <= end
  27081         try sema.panicIndexOutOfBounds(block, src, start, end, .cmp_lte);
  27082     }
  27083     const result = try block.addInst(.{
  27084         .tag = .slice,
  27085         .data = .{ .ty_pl = .{
  27086             .ty = try sema.addType(return_ty),
  27087             .payload = try sema.addExtra(Air.Bin{
  27088                 .lhs = new_ptr,
  27089                 .rhs = new_len,
  27090             }),
  27091         } },
  27092     });
  27093     if (block.wantSafety()) {
  27094         // requirement: result[new_len] == slice_sentinel
  27095         try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len);
  27096     }
  27097     return result;
  27098 }
  27099 
  27100 /// Asserts that lhs and rhs types are both numeric.
  27101 fn cmpNumeric(
  27102     sema: *Sema,
  27103     block: *Block,
  27104     src: LazySrcLoc,
  27105     uncasted_lhs: Air.Inst.Ref,
  27106     uncasted_rhs: Air.Inst.Ref,
  27107     op: std.math.CompareOperator,
  27108     lhs_src: LazySrcLoc,
  27109     rhs_src: LazySrcLoc,
  27110 ) CompileError!Air.Inst.Ref {
  27111     const lhs_ty = sema.typeOf(uncasted_lhs);
  27112     const rhs_ty = sema.typeOf(uncasted_rhs);
  27113 
  27114     assert(lhs_ty.isNumeric());
  27115     assert(rhs_ty.isNumeric());
  27116 
  27117     const lhs_ty_tag = lhs_ty.zigTypeTag();
  27118     const rhs_ty_tag = rhs_ty.zigTypeTag();
  27119     const target = sema.mod.getTarget();
  27120 
  27121     // One exception to heterogeneous comparison: comptime_float needs to
  27122     // coerce to fixed-width float.
  27123 
  27124     const lhs = if (lhs_ty_tag == .ComptimeFloat and rhs_ty_tag == .Float)
  27125         try sema.coerce(block, rhs_ty, uncasted_lhs, lhs_src)
  27126     else
  27127         uncasted_lhs;
  27128 
  27129     const rhs = if (lhs_ty_tag == .Float and rhs_ty_tag == .ComptimeFloat)
  27130         try sema.coerce(block, lhs_ty, uncasted_rhs, rhs_src)
  27131     else
  27132         uncasted_rhs;
  27133 
  27134     const runtime_src: LazySrcLoc = src: {
  27135         if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
  27136             if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
  27137                 if (lhs_val.isUndef() or rhs_val.isUndef()) {
  27138                     return sema.addConstUndef(Type.bool);
  27139                 }
  27140                 if (lhs_val.isNan() or rhs_val.isNan()) {
  27141                     if (op == std.math.CompareOperator.neq) {
  27142                         return Air.Inst.Ref.bool_true;
  27143                     } else {
  27144                         return Air.Inst.Ref.bool_false;
  27145                     }
  27146                 }
  27147                 if (try Value.compareHeteroAdvanced(lhs_val, op, rhs_val, target, sema.kit(block, src))) {
  27148                     return Air.Inst.Ref.bool_true;
  27149                 } else {
  27150                     return Air.Inst.Ref.bool_false;
  27151                 }
  27152             } else {
  27153                 break :src rhs_src;
  27154             }
  27155         } else {
  27156             break :src lhs_src;
  27157         }
  27158     };
  27159 
  27160     // TODO handle comparisons against lazy zero values
  27161     // Some values can be compared against zero without being runtime known or without forcing
  27162     // a full resolution of their value, for example `@sizeOf(@Frame(function))` is known to
  27163     // always be nonzero, and we benefit from not forcing the full evaluation and stack frame layout
  27164     // of this function if we don't need to.
  27165     try sema.requireRuntimeBlock(block, src, runtime_src);
  27166 
  27167     // For floats, emit a float comparison instruction.
  27168     const lhs_is_float = switch (lhs_ty_tag) {
  27169         .Float, .ComptimeFloat => true,
  27170         else => false,
  27171     };
  27172     const rhs_is_float = switch (rhs_ty_tag) {
  27173         .Float, .ComptimeFloat => true,
  27174         else => false,
  27175     };
  27176 
  27177     if (lhs_is_float and rhs_is_float) {
  27178         // Smaller fixed-width floats coerce to larger fixed-width floats.
  27179         // comptime_float coerces to fixed-width float.
  27180         const dest_ty = x: {
  27181             if (lhs_ty_tag == .ComptimeFloat) {
  27182                 break :x rhs_ty;
  27183             } else if (rhs_ty_tag == .ComptimeFloat) {
  27184                 break :x lhs_ty;
  27185             }
  27186             if (lhs_ty.floatBits(target) >= rhs_ty.floatBits(target)) {
  27187                 break :x lhs_ty;
  27188             } else {
  27189                 break :x rhs_ty;
  27190             }
  27191         };
  27192         const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src);
  27193         const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src);
  27194         return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs);
  27195     }
  27196     // For mixed unsigned integer sizes, implicit cast both operands to the larger integer.
  27197     // For mixed signed and unsigned integers, implicit cast both operands to a signed
  27198     // integer with + 1 bit.
  27199     // For mixed floats and integers, extract the integer part from the float, cast that to
  27200     // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
  27201     // add/subtract 1.
  27202     const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val|
  27203         (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))
  27204     else
  27205         (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt());
  27206     const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val|
  27207         (try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))
  27208     else
  27209         (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt());
  27210     const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
  27211 
  27212     var dest_float_type: ?Type = null;
  27213 
  27214     var lhs_bits: usize = undefined;
  27215     if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
  27216         if (lhs_val.isUndef())
  27217             return sema.addConstUndef(Type.bool);
  27218         if (!rhs_is_signed) {
  27219             switch (lhs_val.orderAgainstZero()) {
  27220                 .gt => {},
  27221                 .eq => switch (op) { // LHS = 0, RHS is unsigned
  27222                     .lte => return Air.Inst.Ref.bool_true,
  27223                     .gt => return Air.Inst.Ref.bool_false,
  27224                     else => {},
  27225                 },
  27226                 .lt => switch (op) { // LHS < 0, RHS is unsigned
  27227                     .neq, .lt, .lte => return Air.Inst.Ref.bool_true,
  27228                     .eq, .gt, .gte => return Air.Inst.Ref.bool_false,
  27229                 },
  27230             }
  27231         }
  27232         if (lhs_is_float) {
  27233             var bigint_space: Value.BigIntSpace = undefined;
  27234             var bigint = try lhs_val.toBigInt(&bigint_space, target).toManaged(sema.gpa);
  27235             defer bigint.deinit();
  27236             if (lhs_val.floatHasFraction()) {
  27237                 switch (op) {
  27238                     .eq => return Air.Inst.Ref.bool_false,
  27239                     .neq => return Air.Inst.Ref.bool_true,
  27240                     else => {},
  27241                 }
  27242                 if (lhs_is_signed) {
  27243                     try bigint.addScalar(&bigint, -1);
  27244                 } else {
  27245                     try bigint.addScalar(&bigint, 1);
  27246                 }
  27247             }
  27248             lhs_bits = bigint.toConst().bitCountTwosComp();
  27249         } else {
  27250             lhs_bits = lhs_val.intBitCountTwosComp(target);
  27251         }
  27252         lhs_bits += @boolToInt(!lhs_is_signed and dest_int_is_signed);
  27253     } else if (lhs_is_float) {
  27254         dest_float_type = lhs_ty;
  27255     } else {
  27256         const int_info = lhs_ty.intInfo(target);
  27257         lhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed);
  27258     }
  27259 
  27260     var rhs_bits: usize = undefined;
  27261     if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
  27262         if (rhs_val.isUndef())
  27263             return sema.addConstUndef(Type.bool);
  27264         if (!lhs_is_signed) {
  27265             switch (rhs_val.orderAgainstZero()) {
  27266                 .gt => {},
  27267                 .eq => switch (op) { // RHS = 0, LHS is unsigned
  27268                     .gte => return Air.Inst.Ref.bool_true,
  27269                     .lt => return Air.Inst.Ref.bool_false,
  27270                     else => {},
  27271                 },
  27272                 .lt => switch (op) { // RHS < 0, LHS is unsigned
  27273                     .neq, .gt, .gte => return Air.Inst.Ref.bool_true,
  27274                     .eq, .lt, .lte => return Air.Inst.Ref.bool_false,
  27275                 },
  27276             }
  27277         }
  27278         if (rhs_is_float) {
  27279             var bigint_space: Value.BigIntSpace = undefined;
  27280             var bigint = try rhs_val.toBigInt(&bigint_space, target).toManaged(sema.gpa);
  27281             defer bigint.deinit();
  27282             if (rhs_val.floatHasFraction()) {
  27283                 switch (op) {
  27284                     .eq => return Air.Inst.Ref.bool_false,
  27285                     .neq => return Air.Inst.Ref.bool_true,
  27286                     else => {},
  27287                 }
  27288                 if (rhs_is_signed) {
  27289                     try bigint.addScalar(&bigint, -1);
  27290                 } else {
  27291                     try bigint.addScalar(&bigint, 1);
  27292                 }
  27293             }
  27294             rhs_bits = bigint.toConst().bitCountTwosComp();
  27295         } else {
  27296             rhs_bits = rhs_val.intBitCountTwosComp(target);
  27297         }
  27298         rhs_bits += @boolToInt(!rhs_is_signed and dest_int_is_signed);
  27299     } else if (rhs_is_float) {
  27300         dest_float_type = rhs_ty;
  27301     } else {
  27302         const int_info = rhs_ty.intInfo(target);
  27303         rhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed);
  27304     }
  27305 
  27306     const dest_ty = if (dest_float_type) |ft| ft else blk: {
  27307         const max_bits = std.math.max(lhs_bits, rhs_bits);
  27308         const casted_bits = std.math.cast(u16, max_bits) orelse return sema.fail(block, src, "{d} exceeds maximum integer bit count", .{max_bits});
  27309         const signedness: std.builtin.Signedness = if (dest_int_is_signed) .signed else .unsigned;
  27310         break :blk try Module.makeIntType(sema.arena, signedness, casted_bits);
  27311     };
  27312     const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src);
  27313     const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src);
  27314 
  27315     return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs);
  27316 }
  27317 
  27318 /// Asserts that lhs and rhs types are both vectors.
  27319 fn cmpVector(
  27320     sema: *Sema,
  27321     block: *Block,
  27322     src: LazySrcLoc,
  27323     lhs: Air.Inst.Ref,
  27324     rhs: Air.Inst.Ref,
  27325     op: std.math.CompareOperator,
  27326     lhs_src: LazySrcLoc,
  27327     rhs_src: LazySrcLoc,
  27328 ) CompileError!Air.Inst.Ref {
  27329     const lhs_ty = sema.typeOf(lhs);
  27330     const rhs_ty = sema.typeOf(rhs);
  27331     assert(lhs_ty.zigTypeTag() == .Vector);
  27332     assert(rhs_ty.zigTypeTag() == .Vector);
  27333     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  27334 
  27335     const result_ty = try Type.vector(sema.arena, lhs_ty.vectorLen(), Type.@"bool");
  27336 
  27337     const runtime_src: LazySrcLoc = src: {
  27338         if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
  27339             if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
  27340                 if (lhs_val.isUndef() or rhs_val.isUndef()) {
  27341                     return sema.addConstUndef(result_ty);
  27342                 }
  27343                 const cmp_val = try sema.compareVector(block, src, lhs_val, op, rhs_val, lhs_ty);
  27344                 return sema.addConstant(result_ty, cmp_val);
  27345             } else {
  27346                 break :src rhs_src;
  27347             }
  27348         } else {
  27349             break :src lhs_src;
  27350         }
  27351     };
  27352 
  27353     try sema.requireRuntimeBlock(block, src, runtime_src);
  27354     const result_ty_inst = try sema.addType(result_ty);
  27355     return block.addCmpVector(lhs, rhs, op, result_ty_inst);
  27356 }
  27357 
  27358 fn wrapOptional(
  27359     sema: *Sema,
  27360     block: *Block,
  27361     dest_ty: Type,
  27362     inst: Air.Inst.Ref,
  27363     inst_src: LazySrcLoc,
  27364 ) !Air.Inst.Ref {
  27365     if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
  27366         return sema.addConstant(dest_ty, try Value.Tag.opt_payload.create(sema.arena, val));
  27367     }
  27368 
  27369     try sema.requireRuntimeBlock(block, inst_src, null);
  27370     return block.addTyOp(.wrap_optional, dest_ty, inst);
  27371 }
  27372 
  27373 fn wrapErrorUnionPayload(
  27374     sema: *Sema,
  27375     block: *Block,
  27376     dest_ty: Type,
  27377     inst: Air.Inst.Ref,
  27378     inst_src: LazySrcLoc,
  27379 ) !Air.Inst.Ref {
  27380     const dest_payload_ty = dest_ty.errorUnionPayload();
  27381     const coerced = try sema.coerceExtra(block, dest_payload_ty, inst, inst_src, .{ .report_err = false });
  27382     if (try sema.resolveMaybeUndefVal(block, inst_src, coerced)) |val| {
  27383         return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val));
  27384     }
  27385     try sema.requireRuntimeBlock(block, inst_src, null);
  27386     try sema.queueFullTypeResolution(dest_payload_ty);
  27387     return block.addTyOp(.wrap_errunion_payload, dest_ty, coerced);
  27388 }
  27389 
  27390 fn wrapErrorUnionSet(
  27391     sema: *Sema,
  27392     block: *Block,
  27393     dest_ty: Type,
  27394     inst: Air.Inst.Ref,
  27395     inst_src: LazySrcLoc,
  27396 ) !Air.Inst.Ref {
  27397     const inst_ty = sema.typeOf(inst);
  27398     const dest_err_set_ty = dest_ty.errorUnionSet();
  27399     if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
  27400         switch (dest_err_set_ty.tag()) {
  27401             .anyerror => {},
  27402             .error_set_single => ok: {
  27403                 const expected_name = val.castTag(.@"error").?.data.name;
  27404                 const n = dest_err_set_ty.castTag(.error_set_single).?.data;
  27405                 if (mem.eql(u8, expected_name, n)) break :ok;
  27406                 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
  27407             },
  27408             .error_set => {
  27409                 const expected_name = val.castTag(.@"error").?.data.name;
  27410                 const error_set = dest_err_set_ty.castTag(.error_set).?.data;
  27411                 if (!error_set.names.contains(expected_name)) {
  27412                     return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
  27413                 }
  27414             },
  27415             .error_set_inferred => ok: {
  27416                 const expected_name = val.castTag(.@"error").?.data.name;
  27417                 const ies = dest_err_set_ty.castTag(.error_set_inferred).?.data;
  27418 
  27419                 // We carefully do this in an order that avoids unnecessarily
  27420                 // resolving the destination error set type.
  27421                 if (ies.is_anyerror) break :ok;
  27422                 if (ies.errors.contains(expected_name)) break :ok;
  27423                 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) {
  27424                     break :ok;
  27425                 }
  27426 
  27427                 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
  27428             },
  27429             .error_set_merged => {
  27430                 const expected_name = val.castTag(.@"error").?.data.name;
  27431                 const error_set = dest_err_set_ty.castTag(.error_set_merged).?.data;
  27432                 if (!error_set.contains(expected_name)) {
  27433                     return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
  27434                 }
  27435             },
  27436             else => unreachable,
  27437         }
  27438         return sema.addConstant(dest_ty, val);
  27439     }
  27440 
  27441     try sema.requireRuntimeBlock(block, inst_src, null);
  27442     const coerced = try sema.coerce(block, dest_err_set_ty, inst, inst_src);
  27443     return block.addTyOp(.wrap_errunion_err, dest_ty, coerced);
  27444 }
  27445 
  27446 fn unionToTag(
  27447     sema: *Sema,
  27448     block: *Block,
  27449     enum_ty: Type,
  27450     un: Air.Inst.Ref,
  27451     un_src: LazySrcLoc,
  27452 ) !Air.Inst.Ref {
  27453     if ((try sema.typeHasOnePossibleValue(block, un_src, enum_ty))) |opv| {
  27454         return sema.addConstant(enum_ty, opv);
  27455     }
  27456     if (try sema.resolveMaybeUndefVal(block, un_src, un)) |un_val| {
  27457         return sema.addConstant(enum_ty, un_val.unionTag());
  27458     }
  27459     try sema.requireRuntimeBlock(block, un_src, null);
  27460     return block.addTyOp(.get_union_tag, enum_ty, un);
  27461 }
  27462 
  27463 fn resolvePeerTypes(
  27464     sema: *Sema,
  27465     block: *Block,
  27466     src: LazySrcLoc,
  27467     instructions: []const Air.Inst.Ref,
  27468     candidate_srcs: Module.PeerTypeCandidateSrc,
  27469 ) !Type {
  27470     switch (instructions.len) {
  27471         0 => return Type.initTag(.noreturn),
  27472         1 => return sema.typeOf(instructions[0]),
  27473         else => {},
  27474     }
  27475 
  27476     const target = sema.mod.getTarget();
  27477 
  27478     var chosen = instructions[0];
  27479     // If this is non-null then it does the following thing, depending on the chosen zigTypeTag().
  27480     //  * ErrorSet: this is an override
  27481     //  * ErrorUnion: this is an override of the error set only
  27482     //  * other: at the end we make an ErrorUnion with the other thing and this
  27483     var err_set_ty: ?Type = null;
  27484     var any_are_null = false;
  27485     var seen_const = false;
  27486     var convert_to_slice = false;
  27487     var chosen_i: usize = 0;
  27488     for (instructions[1..]) |candidate, candidate_i| {
  27489         const candidate_ty = sema.typeOf(candidate);
  27490         const chosen_ty = sema.typeOf(chosen);
  27491 
  27492         const candidate_ty_tag = try candidate_ty.zigTypeTagOrPoison();
  27493         const chosen_ty_tag = try chosen_ty.zigTypeTagOrPoison();
  27494 
  27495         if (candidate_ty.eql(chosen_ty, sema.mod))
  27496             continue;
  27497 
  27498         switch (candidate_ty_tag) {
  27499             .NoReturn, .Undefined => continue,
  27500 
  27501             .Null => {
  27502                 any_are_null = true;
  27503                 continue;
  27504             },
  27505 
  27506             .Int => switch (chosen_ty_tag) {
  27507                 .ComptimeInt => {
  27508                     chosen = candidate;
  27509                     chosen_i = candidate_i + 1;
  27510                     continue;
  27511                 },
  27512                 .Int => {
  27513                     const chosen_info = chosen_ty.intInfo(target);
  27514                     const candidate_info = candidate_ty.intInfo(target);
  27515 
  27516                     if (chosen_info.bits < candidate_info.bits) {
  27517                         chosen = candidate;
  27518                         chosen_i = candidate_i + 1;
  27519                     }
  27520                     continue;
  27521                 },
  27522                 .Pointer => if (chosen_ty.ptrSize() == .C) continue,
  27523                 else => {},
  27524             },
  27525             .ComptimeInt => switch (chosen_ty_tag) {
  27526                 .Int, .Float, .ComptimeFloat => continue,
  27527                 .Pointer => if (chosen_ty.ptrSize() == .C) continue,
  27528                 else => {},
  27529             },
  27530             .Float => switch (chosen_ty_tag) {
  27531                 .Float => {
  27532                     if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) {
  27533                         chosen = candidate;
  27534                         chosen_i = candidate_i + 1;
  27535                     }
  27536                     continue;
  27537                 },
  27538                 .ComptimeFloat, .ComptimeInt => {
  27539                     chosen = candidate;
  27540                     chosen_i = candidate_i + 1;
  27541                     continue;
  27542                 },
  27543                 else => {},
  27544             },
  27545             .ComptimeFloat => switch (chosen_ty_tag) {
  27546                 .Float => continue,
  27547                 .ComptimeInt => {
  27548                     chosen = candidate;
  27549                     chosen_i = candidate_i + 1;
  27550                     continue;
  27551                 },
  27552                 else => {},
  27553             },
  27554             .Enum => switch (chosen_ty_tag) {
  27555                 .EnumLiteral => {
  27556                     chosen = candidate;
  27557                     chosen_i = candidate_i + 1;
  27558                     continue;
  27559                 },
  27560                 .Union => continue,
  27561                 else => {},
  27562             },
  27563             .EnumLiteral => switch (chosen_ty_tag) {
  27564                 .Enum, .Union => continue,
  27565                 else => {},
  27566             },
  27567             .Union => switch (chosen_ty_tag) {
  27568                 .Enum, .EnumLiteral => {
  27569                     chosen = candidate;
  27570                     chosen_i = candidate_i + 1;
  27571                     continue;
  27572                 },
  27573                 else => {},
  27574             },
  27575             .ErrorSet => switch (chosen_ty_tag) {
  27576                 .ErrorSet => {
  27577                     // If chosen is superset of candidate, keep it.
  27578                     // If candidate is superset of chosen, switch it.
  27579                     // If neither is a superset, merge errors.
  27580                     const chosen_set_ty = err_set_ty orelse chosen_ty;
  27581 
  27582                     if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) {
  27583                         continue;
  27584                     }
  27585                     if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) {
  27586                         err_set_ty = null;
  27587                         chosen = candidate;
  27588                         chosen_i = candidate_i + 1;
  27589                         continue;
  27590                     }
  27591 
  27592                     err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty);
  27593                     continue;
  27594                 },
  27595                 .ErrorUnion => {
  27596                     const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet();
  27597 
  27598                     if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) {
  27599                         continue;
  27600                     }
  27601                     if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) {
  27602                         err_set_ty = candidate_ty;
  27603                         continue;
  27604                     }
  27605 
  27606                     err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty);
  27607                     continue;
  27608                 },
  27609                 else => {
  27610                     if (err_set_ty) |chosen_set_ty| {
  27611                         if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) {
  27612                             continue;
  27613                         }
  27614                         if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) {
  27615                             err_set_ty = candidate_ty;
  27616                             continue;
  27617                         }
  27618 
  27619                         err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty);
  27620                         continue;
  27621                     } else {
  27622                         err_set_ty = candidate_ty;
  27623                         continue;
  27624                     }
  27625                 },
  27626             },
  27627             .ErrorUnion => switch (chosen_ty_tag) {
  27628                 .ErrorSet => {
  27629                     const chosen_set_ty = err_set_ty orelse chosen_ty;
  27630                     const candidate_set_ty = candidate_ty.errorUnionSet();
  27631 
  27632                     if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) {
  27633                         err_set_ty = chosen_set_ty;
  27634                     } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) {
  27635                         err_set_ty = null;
  27636                     } else {
  27637                         err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
  27638                     }
  27639                     chosen = candidate;
  27640                     chosen_i = candidate_i + 1;
  27641                     continue;
  27642                 },
  27643 
  27644                 .ErrorUnion => {
  27645                     const chosen_payload_ty = chosen_ty.errorUnionPayload();
  27646                     const candidate_payload_ty = candidate_ty.errorUnionPayload();
  27647 
  27648                     const coerce_chosen = (try sema.coerceInMemoryAllowed(block, chosen_payload_ty, candidate_payload_ty, false, target, src, src)) == .ok;
  27649                     const coerce_candidate = (try sema.coerceInMemoryAllowed(block, candidate_payload_ty, chosen_payload_ty, false, target, src, src)) == .ok;
  27650 
  27651                     if (coerce_chosen or coerce_candidate) {
  27652                         // If we can coerce to the candidate, we switch to that
  27653                         // type. This is the same logic as the bare (non-union)
  27654                         // coercion check we do at the top of this func.
  27655                         if (coerce_candidate) {
  27656                             chosen = candidate;
  27657                             chosen_i = candidate_i + 1;
  27658                         }
  27659 
  27660                         const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet();
  27661                         const candidate_set_ty = candidate_ty.errorUnionSet();
  27662 
  27663                         if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) {
  27664                             err_set_ty = chosen_set_ty;
  27665                         } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) {
  27666                             err_set_ty = candidate_set_ty;
  27667                         } else {
  27668                             err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
  27669                         }
  27670                         continue;
  27671                     }
  27672                 },
  27673 
  27674                 else => {
  27675                     if (err_set_ty) |chosen_set_ty| {
  27676                         const candidate_set_ty = candidate_ty.errorUnionSet();
  27677                         if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) {
  27678                             err_set_ty = chosen_set_ty;
  27679                         } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) {
  27680                             err_set_ty = null;
  27681                         } else {
  27682                             err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
  27683                         }
  27684                     }
  27685                     seen_const = seen_const or chosen_ty.isConstPtr();
  27686                     chosen = candidate;
  27687                     chosen_i = candidate_i + 1;
  27688                     continue;
  27689                 },
  27690             },
  27691             .Pointer => {
  27692                 const cand_info = candidate_ty.ptrInfo().data;
  27693                 switch (chosen_ty_tag) {
  27694                     .Pointer => {
  27695                         const chosen_info = chosen_ty.ptrInfo().data;
  27696 
  27697                         seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable;
  27698 
  27699                         // *[N]T to [*]T
  27700                         // *[N]T to []T
  27701                         if ((cand_info.size == .Many or cand_info.size == .Slice) and
  27702                             chosen_info.size == .One and
  27703                             chosen_info.pointee_type.zigTypeTag() == .Array)
  27704                         {
  27705                             // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T`
  27706                             convert_to_slice = false;
  27707                             chosen = candidate;
  27708                             chosen_i = candidate_i + 1;
  27709                             continue;
  27710                         }
  27711                         if (cand_info.size == .One and
  27712                             cand_info.pointee_type.zigTypeTag() == .Array and
  27713                             (chosen_info.size == .Many or chosen_info.size == .Slice))
  27714                         {
  27715                             // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T`
  27716                             convert_to_slice = false;
  27717                             continue;
  27718                         }
  27719 
  27720                         // *[N]T and *[M]T
  27721                         // Verify both are single-pointers to arrays.
  27722                         // Keep the one whose element type can be coerced into.
  27723                         if (chosen_info.size == .One and
  27724                             cand_info.size == .One and
  27725                             chosen_info.pointee_type.zigTypeTag() == .Array and
  27726                             cand_info.pointee_type.zigTypeTag() == .Array)
  27727                         {
  27728                             const chosen_elem_ty = chosen_info.pointee_type.childType();
  27729                             const cand_elem_ty = cand_info.pointee_type.childType();
  27730 
  27731                             const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_elem_ty, cand_elem_ty, chosen_info.mutable, target, src, src);
  27732                             if (chosen_ok) {
  27733                                 convert_to_slice = true;
  27734                                 continue;
  27735                             }
  27736 
  27737                             const cand_ok = .ok == try sema.coerceInMemoryAllowed(block, cand_elem_ty, chosen_elem_ty, cand_info.mutable, target, src, src);
  27738                             if (cand_ok) {
  27739                                 convert_to_slice = true;
  27740                                 chosen = candidate;
  27741                                 chosen_i = candidate_i + 1;
  27742                                 continue;
  27743                             }
  27744 
  27745                             // They're both bad. Report error.
  27746                             // In the future we probably want to use the
  27747                             // coerceInMemoryAllowed error reporting mechanism,
  27748                             // however, for now we just fall through for the
  27749                             // "incompatible types" error below.
  27750                         }
  27751 
  27752                         // [*c]T and any other pointer size
  27753                         // Whichever element type can coerce to the other one, is
  27754                         // the one we will keep. If they're both OK then we keep the
  27755                         // C pointer since it matches both single and many pointers.
  27756                         if (cand_info.size == .C or chosen_info.size == .C) {
  27757                             const cand_ok = .ok == try sema.coerceInMemoryAllowed(block, cand_info.pointee_type, chosen_info.pointee_type, cand_info.mutable, target, src, src);
  27758                             const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_info.pointee_type, cand_info.pointee_type, chosen_info.mutable, target, src, src);
  27759 
  27760                             if (cand_ok) {
  27761                                 if (chosen_ok) {
  27762                                     if (chosen_info.size == .C) {
  27763                                         continue;
  27764                                     } else {
  27765                                         chosen = candidate;
  27766                                         chosen_i = candidate_i + 1;
  27767                                         continue;
  27768                                     }
  27769                                 } else {
  27770                                     chosen = candidate;
  27771                                     chosen_i = candidate_i + 1;
  27772                                     continue;
  27773                                 }
  27774                             } else {
  27775                                 if (chosen_ok) {
  27776                                     continue;
  27777                                 } else {
  27778                                     // They're both bad. Report error.
  27779                                     // In the future we probably want to use the
  27780                                     // coerceInMemoryAllowed error reporting mechanism,
  27781                                     // however, for now we just fall through for the
  27782                                     // "incompatible types" error below.
  27783                                 }
  27784                             }
  27785                         }
  27786                     },
  27787                     .Int, .ComptimeInt => {
  27788                         if (cand_info.size == .C) {
  27789                             chosen = candidate;
  27790                             chosen_i = candidate_i + 1;
  27791                             continue;
  27792                         }
  27793                     },
  27794                     .Optional => {
  27795                         var opt_child_buf: Type.Payload.ElemType = undefined;
  27796                         const chosen_ptr_ty = chosen_ty.optionalChild(&opt_child_buf);
  27797                         if (chosen_ptr_ty.zigTypeTag() == .Pointer) {
  27798                             const chosen_info = chosen_ptr_ty.ptrInfo().data;
  27799 
  27800                             seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable;
  27801 
  27802                             // *[N]T to ?![*]T
  27803                             // *[N]T to ?![]T
  27804                             if (cand_info.size == .One and
  27805                                 cand_info.pointee_type.zigTypeTag() == .Array and
  27806                                 (chosen_info.size == .Many or chosen_info.size == .Slice))
  27807                             {
  27808                                 continue;
  27809                             }
  27810                         }
  27811                     },
  27812                     .ErrorUnion => {
  27813                         const chosen_ptr_ty = chosen_ty.errorUnionPayload();
  27814                         if (chosen_ptr_ty.zigTypeTag() == .Pointer) {
  27815                             const chosen_info = chosen_ptr_ty.ptrInfo().data;
  27816 
  27817                             seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable;
  27818 
  27819                             // *[N]T to E![*]T
  27820                             // *[N]T to E![]T
  27821                             if (cand_info.size == .One and
  27822                                 cand_info.pointee_type.zigTypeTag() == .Array and
  27823                                 (chosen_info.size == .Many or chosen_info.size == .Slice))
  27824                             {
  27825                                 continue;
  27826                             }
  27827                         }
  27828                     },
  27829                     else => {},
  27830                 }
  27831             },
  27832             .Optional => {
  27833                 var opt_child_buf: Type.Payload.ElemType = undefined;
  27834                 const opt_child_ty = candidate_ty.optionalChild(&opt_child_buf);
  27835                 if ((try sema.coerceInMemoryAllowed(block, chosen_ty, opt_child_ty, false, target, src, src)) == .ok) {
  27836                     seen_const = seen_const or opt_child_ty.isConstPtr();
  27837                     any_are_null = true;
  27838                     continue;
  27839                 }
  27840 
  27841                 seen_const = seen_const or chosen_ty.isConstPtr();
  27842                 any_are_null = false;
  27843                 chosen = candidate;
  27844                 chosen_i = candidate_i + 1;
  27845                 continue;
  27846             },
  27847             .Vector => switch (chosen_ty_tag) {
  27848                 .Array => {
  27849                     chosen = candidate;
  27850                     chosen_i = candidate_i + 1;
  27851                     continue;
  27852                 },
  27853                 else => {},
  27854             },
  27855             .Array => switch (chosen_ty_tag) {
  27856                 .Vector => continue,
  27857                 else => {},
  27858             },
  27859             else => {},
  27860         }
  27861 
  27862         switch (chosen_ty_tag) {
  27863             .NoReturn, .Undefined => {
  27864                 chosen = candidate;
  27865                 chosen_i = candidate_i + 1;
  27866                 continue;
  27867             },
  27868             .Null => {
  27869                 any_are_null = true;
  27870                 chosen = candidate;
  27871                 chosen_i = candidate_i + 1;
  27872                 continue;
  27873             },
  27874             .Optional => {
  27875                 var opt_child_buf: Type.Payload.ElemType = undefined;
  27876                 const opt_child_ty = chosen_ty.optionalChild(&opt_child_buf);
  27877                 if ((try sema.coerceInMemoryAllowed(block, opt_child_ty, candidate_ty, false, target, src, src)) == .ok) {
  27878                     continue;
  27879                 }
  27880                 if ((try sema.coerceInMemoryAllowed(block, candidate_ty, opt_child_ty, false, target, src, src)) == .ok) {
  27881                     any_are_null = true;
  27882                     chosen = candidate;
  27883                     chosen_i = candidate_i + 1;
  27884                     continue;
  27885                 }
  27886             },
  27887             .ErrorUnion => {
  27888                 const payload_ty = chosen_ty.errorUnionPayload();
  27889                 if ((try sema.coerceInMemoryAllowed(block, payload_ty, candidate_ty, false, target, src, src)) == .ok) {
  27890                     continue;
  27891                 }
  27892             },
  27893             else => {},
  27894         }
  27895 
  27896         // If the candidate can coerce into our chosen type, we're done.
  27897         // If the chosen type can coerce into the candidate, use that.
  27898         if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) {
  27899             continue;
  27900         }
  27901         if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) {
  27902             chosen = candidate;
  27903             chosen_i = candidate_i + 1;
  27904             continue;
  27905         }
  27906 
  27907         // At this point, we hit a compile error. We need to recover
  27908         // the source locations.
  27909         const chosen_src = candidate_srcs.resolve(
  27910             sema.gpa,
  27911             sema.mod.declPtr(block.src_decl),
  27912             chosen_i,
  27913         );
  27914         const candidate_src = candidate_srcs.resolve(
  27915             sema.gpa,
  27916             sema.mod.declPtr(block.src_decl),
  27917             candidate_i + 1,
  27918         );
  27919 
  27920         const msg = msg: {
  27921             const msg = try sema.errMsg(block, src, "incompatible types: '{}' and '{}'", .{
  27922                 chosen_ty.fmt(sema.mod),
  27923                 candidate_ty.fmt(sema.mod),
  27924             });
  27925             errdefer msg.destroy(sema.gpa);
  27926 
  27927             if (chosen_src) |src_loc|
  27928                 try sema.errNote(block, src_loc, msg, "type '{}' here", .{chosen_ty.fmt(sema.mod)});
  27929 
  27930             if (candidate_src) |src_loc|
  27931                 try sema.errNote(block, src_loc, msg, "type '{}' here", .{candidate_ty.fmt(sema.mod)});
  27932 
  27933             break :msg msg;
  27934         };
  27935         return sema.failWithOwnedErrorMsg(msg);
  27936     }
  27937 
  27938     const chosen_ty = sema.typeOf(chosen);
  27939 
  27940     if (convert_to_slice) {
  27941         // turn *[N]T => []T
  27942         const chosen_child_ty = chosen_ty.childType();
  27943         var info = chosen_ty.ptrInfo();
  27944         info.data.sentinel = chosen_child_ty.sentinel();
  27945         info.data.size = .Slice;
  27946         info.data.mutable = !(seen_const or chosen_child_ty.isConstPtr());
  27947         info.data.pointee_type = chosen_child_ty.elemType2();
  27948 
  27949         const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data);
  27950         const opt_ptr_ty = if (any_are_null)
  27951             try Type.optional(sema.arena, new_ptr_ty)
  27952         else
  27953             new_ptr_ty;
  27954         const set_ty = err_set_ty orelse return opt_ptr_ty;
  27955         return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, sema.mod);
  27956     }
  27957 
  27958     if (seen_const) {
  27959         // turn []T => []const T
  27960         switch (chosen_ty.zigTypeTag()) {
  27961             .ErrorUnion => {
  27962                 const ptr_ty = chosen_ty.errorUnionPayload();
  27963                 var info = ptr_ty.ptrInfo();
  27964                 info.data.mutable = false;
  27965                 const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data);
  27966                 const opt_ptr_ty = if (any_are_null)
  27967                     try Type.optional(sema.arena, new_ptr_ty)
  27968                 else
  27969                     new_ptr_ty;
  27970                 const set_ty = err_set_ty orelse chosen_ty.errorUnionSet();
  27971                 return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, sema.mod);
  27972             },
  27973             .Pointer => {
  27974                 var info = chosen_ty.ptrInfo();
  27975                 info.data.mutable = false;
  27976                 const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data);
  27977                 const opt_ptr_ty = if (any_are_null)
  27978                     try Type.optional(sema.arena, new_ptr_ty)
  27979                 else
  27980                     new_ptr_ty;
  27981                 const set_ty = err_set_ty orelse return opt_ptr_ty;
  27982                 return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, sema.mod);
  27983             },
  27984             else => return chosen_ty,
  27985         }
  27986     }
  27987 
  27988     if (any_are_null) {
  27989         const opt_ty = switch (chosen_ty.zigTypeTag()) {
  27990             .Null, .Optional => chosen_ty,
  27991             else => try Type.optional(sema.arena, chosen_ty),
  27992         };
  27993         const set_ty = err_set_ty orelse return opt_ty;
  27994         return try Type.errorUnion(sema.arena, set_ty, opt_ty, sema.mod);
  27995     }
  27996 
  27997     if (err_set_ty) |ty| switch (chosen_ty.zigTypeTag()) {
  27998         .ErrorSet => return ty,
  27999         .ErrorUnion => {
  28000             const payload_ty = chosen_ty.errorUnionPayload();
  28001             return try Type.errorUnion(sema.arena, ty, payload_ty, sema.mod);
  28002         },
  28003         else => return try Type.errorUnion(sema.arena, ty, chosen_ty, sema.mod),
  28004     };
  28005 
  28006     return chosen_ty;
  28007 }
  28008 
  28009 pub fn resolveFnTypes(
  28010     sema: *Sema,
  28011     block: *Block,
  28012     src: LazySrcLoc,
  28013     fn_info: Type.Payload.Function.Data,
  28014 ) CompileError!void {
  28015     try sema.resolveTypeFully(block, src, fn_info.return_type);
  28016 
  28017     if (sema.mod.comp.bin_file.options.error_return_tracing and fn_info.return_type.isError()) {
  28018         // Ensure the type exists so that backends can assume that.
  28019         _ = try sema.getBuiltinType(block, src, "StackTrace");
  28020     }
  28021 
  28022     for (fn_info.param_types) |param_ty| {
  28023         try sema.resolveTypeFully(block, src, param_ty);
  28024     }
  28025 }
  28026 
  28027 /// Make it so that calling hash() and eql() on `val` will not assert due
  28028 /// to a type not having its layout resolved.
  28029 fn resolveLazyValue(
  28030     sema: *Sema,
  28031     block: *Block,
  28032     src: LazySrcLoc,
  28033     val: Value,
  28034 ) CompileError!void {
  28035     switch (val.tag()) {
  28036         .lazy_align => {
  28037             const ty = val.castTag(.lazy_align).?.data;
  28038             return sema.resolveTypeLayout(block, src, ty);
  28039         },
  28040         .lazy_size => {
  28041             const ty = val.castTag(.lazy_size).?.data;
  28042             return sema.resolveTypeLayout(block, src, ty);
  28043         },
  28044         else => return,
  28045     }
  28046 }
  28047 
  28048 pub fn resolveTypeLayout(
  28049     sema: *Sema,
  28050     block: *Block,
  28051     src: LazySrcLoc,
  28052     ty: Type,
  28053 ) CompileError!void {
  28054     switch (ty.zigTypeTag()) {
  28055         .Struct => return sema.resolveStructLayout(block, src, ty),
  28056         .Union => return sema.resolveUnionLayout(block, src, ty),
  28057         .Array => {
  28058             if (ty.arrayLenIncludingSentinel() == 0) return;
  28059             const elem_ty = ty.childType();
  28060             return sema.resolveTypeLayout(block, src, elem_ty);
  28061         },
  28062         .Optional => {
  28063             var buf: Type.Payload.ElemType = undefined;
  28064             const payload_ty = ty.optionalChild(&buf);
  28065             // In case of querying the ABI alignment of this optional, we will ask
  28066             // for hasRuntimeBits() of the payload type, so we need "requires comptime"
  28067             // to be known already before this function returns.
  28068             _ = try sema.typeRequiresComptime(payload_ty);
  28069             return sema.resolveTypeLayout(block, src, payload_ty);
  28070         },
  28071         .ErrorUnion => {
  28072             const payload_ty = ty.errorUnionPayload();
  28073             return sema.resolveTypeLayout(block, src, payload_ty);
  28074         },
  28075         else => {},
  28076     }
  28077 }
  28078 
  28079 fn resolveStructLayout(
  28080     sema: *Sema,
  28081     block: *Block,
  28082     src: LazySrcLoc,
  28083     ty: Type,
  28084 ) CompileError!void {
  28085     const resolved_ty = try sema.resolveTypeFields(block, src, ty);
  28086     if (resolved_ty.castTag(.@"struct")) |payload| {
  28087         const struct_obj = payload.data;
  28088         switch (struct_obj.status) {
  28089             .none, .have_field_types => {},
  28090             .field_types_wip, .layout_wip => {
  28091                 const msg = try Module.ErrorMsg.create(
  28092                     sema.gpa,
  28093                     struct_obj.srcLoc(sema.mod),
  28094                     "struct '{}' depends on itself",
  28095                     .{ty.fmt(sema.mod)},
  28096                 );
  28097                 return sema.failWithOwnedErrorMsg(msg);
  28098             },
  28099             .have_layout, .fully_resolved_wip, .fully_resolved => return,
  28100         }
  28101         struct_obj.status = .layout_wip;
  28102         for (struct_obj.fields.values()) |field, i| {
  28103             sema.resolveTypeLayout(block, src, field.ty) catch |err| switch (err) {
  28104                 error.AnalysisFail => {
  28105                     const msg = sema.err orelse return err;
  28106                     try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});
  28107                     return err;
  28108                 },
  28109                 else => return err,
  28110             };
  28111         }
  28112 
  28113         if (struct_obj.layout == .Packed) {
  28114             try semaBackingIntType(sema.mod, struct_obj);
  28115         }
  28116 
  28117         struct_obj.status = .have_layout;
  28118 
  28119         // In case of querying the ABI alignment of this struct, we will ask
  28120         // for hasRuntimeBits() of each field, so we need "requires comptime"
  28121         // to be known already before this function returns.
  28122         for (struct_obj.fields.values()) |field, i| {
  28123             _ = sema.typeRequiresComptime(field.ty) catch |err| switch (err) {
  28124                 error.AnalysisFail => {
  28125                     const msg = sema.err orelse return err;
  28126                     try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});
  28127                     return err;
  28128                 },
  28129                 else => return err,
  28130             };
  28131         }
  28132     }
  28133     // otherwise it's a tuple; no need to resolve anything
  28134 }
  28135 
  28136 fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
  28137     const gpa = mod.gpa;
  28138     const target = mod.getTarget();
  28139 
  28140     var fields_bit_sum: u64 = 0;
  28141     for (struct_obj.fields.values()) |field| {
  28142         fields_bit_sum += field.ty.bitSize(target);
  28143     }
  28144 
  28145     const decl_index = struct_obj.owner_decl;
  28146     const decl = mod.declPtr(decl_index);
  28147     var decl_arena = decl.value_arena.?.promote(gpa);
  28148     defer decl.value_arena.?.* = decl_arena.state;
  28149     const decl_arena_allocator = decl_arena.allocator();
  28150 
  28151     const zir = struct_obj.namespace.file_scope.zir;
  28152     const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
  28153     assert(extended.opcode == .struct_decl);
  28154     const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
  28155 
  28156     if (small.has_backing_int) {
  28157         var extra_index: usize = extended.operand;
  28158         extra_index += @boolToInt(small.has_src_node);
  28159         extra_index += @boolToInt(small.has_fields_len);
  28160         extra_index += @boolToInt(small.has_decls_len);
  28161 
  28162         const backing_int_body_len = zir.extra[extra_index];
  28163         extra_index += 1;
  28164 
  28165         var analysis_arena = std.heap.ArenaAllocator.init(gpa);
  28166         defer analysis_arena.deinit();
  28167 
  28168         var sema: Sema = .{
  28169             .mod = mod,
  28170             .gpa = gpa,
  28171             .arena = analysis_arena.allocator(),
  28172             .perm_arena = decl_arena_allocator,
  28173             .code = zir,
  28174             .owner_decl = decl,
  28175             .owner_decl_index = decl_index,
  28176             .func = null,
  28177             .fn_ret_ty = Type.void,
  28178             .owner_func = null,
  28179         };
  28180         defer sema.deinit();
  28181 
  28182         var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope);
  28183         defer wip_captures.deinit();
  28184 
  28185         var block: Block = .{
  28186             .parent = null,
  28187             .sema = &sema,
  28188             .src_decl = decl_index,
  28189             .namespace = &struct_obj.namespace,
  28190             .wip_capture_scope = wip_captures.scope,
  28191             .instructions = .{},
  28192             .inlining = null,
  28193             .is_comptime = true,
  28194         };
  28195         defer {
  28196             assert(block.instructions.items.len == 0);
  28197             block.params.deinit(gpa);
  28198         }
  28199 
  28200         const backing_int_src: LazySrcLoc = .{ .node_offset_container_tag = 0 };
  28201         const backing_int_ty = blk: {
  28202             if (backing_int_body_len == 0) {
  28203                 const backing_int_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
  28204                 break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref);
  28205             } else {
  28206                 const body = zir.extra[extra_index..][0..backing_int_body_len];
  28207                 const ty_ref = try sema.resolveBody(&block, body, struct_obj.zir_index);
  28208                 break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref);
  28209             }
  28210         };
  28211 
  28212         try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum);
  28213         struct_obj.backing_int_ty = try backing_int_ty.copy(decl_arena_allocator);
  28214     } else {
  28215         var buf: Type.Payload.Bits = .{
  28216             .base = .{ .tag = .int_unsigned },
  28217             .data = @intCast(u16, fields_bit_sum),
  28218         };
  28219         struct_obj.backing_int_ty = try Type.initPayload(&buf.base).copy(decl_arena_allocator);
  28220     }
  28221 }
  28222 
  28223 fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {
  28224     const target = sema.mod.getTarget();
  28225 
  28226     if (!backing_int_ty.isInt()) {
  28227         return sema.fail(block, src, "expected backing integer type, found '{}'", .{backing_int_ty.fmt(sema.mod)});
  28228     }
  28229     if (backing_int_ty.bitSize(target) != fields_bit_sum) {
  28230         return sema.fail(
  28231             block,
  28232             src,
  28233             "backing integer type '{}' has bit size {} but the struct fields have a total bit size of {}",
  28234             .{ backing_int_ty.fmt(sema.mod), backing_int_ty.bitSize(target), fields_bit_sum },
  28235         );
  28236     }
  28237 }
  28238 
  28239 fn resolveUnionLayout(
  28240     sema: *Sema,
  28241     block: *Block,
  28242     src: LazySrcLoc,
  28243     ty: Type,
  28244 ) CompileError!void {
  28245     const resolved_ty = try sema.resolveTypeFields(block, src, ty);
  28246     const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
  28247     switch (union_obj.status) {
  28248         .none, .have_field_types => {},
  28249         .field_types_wip, .layout_wip => {
  28250             const msg = try Module.ErrorMsg.create(
  28251                 sema.gpa,
  28252                 union_obj.srcLoc(sema.mod),
  28253                 "union '{}' depends on itself",
  28254                 .{ty.fmt(sema.mod)},
  28255             );
  28256             return sema.failWithOwnedErrorMsg(msg);
  28257         },
  28258         .have_layout, .fully_resolved_wip, .fully_resolved => return,
  28259     }
  28260     union_obj.status = .layout_wip;
  28261     for (union_obj.fields.values()) |field, i| {
  28262         sema.resolveTypeLayout(block, src, field.ty) catch |err| switch (err) {
  28263             error.AnalysisFail => {
  28264                 const msg = sema.err orelse return err;
  28265                 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});
  28266                 return err;
  28267             },
  28268             else => return err,
  28269         };
  28270     }
  28271     union_obj.status = .have_layout;
  28272 }
  28273 
  28274 /// Returns `error.AnalysisFail` if any of the types (recursively) failed to
  28275 /// be resolved.
  28276 pub fn resolveTypeFully(
  28277     sema: *Sema,
  28278     block: *Block,
  28279     src: LazySrcLoc,
  28280     ty: Type,
  28281 ) CompileError!void {
  28282     switch (ty.zigTypeTag()) {
  28283         .Pointer => {
  28284             const child_ty = try sema.resolveTypeFields(block, src, ty.childType());
  28285             return resolveTypeFully(sema, block, src, child_ty);
  28286         },
  28287         .Struct => switch (ty.tag()) {
  28288             .@"struct" => return resolveStructFully(sema, block, src, ty),
  28289             .tuple, .anon_struct => {
  28290                 const tuple = ty.tupleFields();
  28291 
  28292                 for (tuple.types) |field_ty| {
  28293                     try sema.resolveTypeFully(block, src, field_ty);
  28294                 }
  28295             },
  28296             else => {},
  28297         },
  28298         .Union => return resolveUnionFully(sema, block, src, ty),
  28299         .Array => return resolveTypeFully(sema, block, src, ty.childType()),
  28300         .Optional => {
  28301             var buf: Type.Payload.ElemType = undefined;
  28302             return resolveTypeFully(sema, block, src, ty.optionalChild(&buf));
  28303         },
  28304         .ErrorUnion => return resolveTypeFully(sema, block, src, ty.errorUnionPayload()),
  28305         .Fn => {
  28306             const info = ty.fnInfo();
  28307             if (info.is_generic) {
  28308                 // Resolving of generic function types is defeerred to when
  28309                 // the function is instantiated.
  28310                 return;
  28311             }
  28312             for (info.param_types) |param_ty| {
  28313                 const param_ty_src = src; // TODO better source location
  28314                 try sema.resolveTypeFully(block, param_ty_src, param_ty);
  28315             }
  28316             const return_ty_src = src; // TODO better source location
  28317             try sema.resolveTypeFully(block, return_ty_src, info.return_type);
  28318         },
  28319         else => {},
  28320     }
  28321 }
  28322 
  28323 fn resolveStructFully(
  28324     sema: *Sema,
  28325     block: *Block,
  28326     src: LazySrcLoc,
  28327     ty: Type,
  28328 ) CompileError!void {
  28329     try resolveStructLayout(sema, block, src, ty);
  28330 
  28331     const resolved_ty = try sema.resolveTypeFields(block, src, ty);
  28332     const payload = resolved_ty.castTag(.@"struct").?;
  28333     const struct_obj = payload.data;
  28334 
  28335     switch (struct_obj.status) {
  28336         .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
  28337         .fully_resolved_wip, .fully_resolved => return,
  28338     }
  28339 
  28340     {
  28341         // After we have resolve struct layout we have to go over the fields again to
  28342         // make sure pointer fields get their child types resolved as well.
  28343         // See also similar code for unions.
  28344         const prev_status = struct_obj.status;
  28345         errdefer struct_obj.status = prev_status;
  28346 
  28347         struct_obj.status = .fully_resolved_wip;
  28348         for (struct_obj.fields.values()) |field| {
  28349             try sema.resolveTypeFully(block, src, field.ty);
  28350         }
  28351         struct_obj.status = .fully_resolved;
  28352     }
  28353 
  28354     // And let's not forget comptime-only status.
  28355     _ = try sema.typeRequiresComptime(ty);
  28356 }
  28357 
  28358 fn resolveUnionFully(
  28359     sema: *Sema,
  28360     block: *Block,
  28361     src: LazySrcLoc,
  28362     ty: Type,
  28363 ) CompileError!void {
  28364     try resolveUnionLayout(sema, block, src, ty);
  28365 
  28366     const resolved_ty = try sema.resolveTypeFields(block, src, ty);
  28367     const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
  28368     switch (union_obj.status) {
  28369         .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
  28370         .fully_resolved_wip, .fully_resolved => return,
  28371     }
  28372 
  28373     {
  28374         // After we have resolve union layout we have to go over the fields again to
  28375         // make sure pointer fields get their child types resolved as well.
  28376         // See also similar code for structs.
  28377         const prev_status = union_obj.status;
  28378         errdefer union_obj.status = prev_status;
  28379 
  28380         union_obj.status = .fully_resolved_wip;
  28381         for (union_obj.fields.values()) |field| {
  28382             try sema.resolveTypeFully(block, src, field.ty);
  28383         }
  28384         union_obj.status = .fully_resolved;
  28385     }
  28386 
  28387     // And let's not forget comptime-only status.
  28388     _ = try sema.typeRequiresComptime(ty);
  28389 }
  28390 
  28391 pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type {
  28392     switch (ty.tag()) {
  28393         .@"struct" => {
  28394             const struct_obj = ty.castTag(.@"struct").?.data;
  28395             try sema.resolveTypeFieldsStruct(ty, struct_obj);
  28396             return ty;
  28397         },
  28398         .@"union", .union_safety_tagged, .union_tagged => {
  28399             const union_obj = ty.cast(Type.Payload.Union).?.data;
  28400             try sema.resolveTypeFieldsUnion(ty, union_obj);
  28401             return ty;
  28402         },
  28403         .type_info => return sema.resolveBuiltinTypeFields(block, src, "Type"),
  28404         .extern_options => return sema.resolveBuiltinTypeFields(block, src, "ExternOptions"),
  28405         .export_options => return sema.resolveBuiltinTypeFields(block, src, "ExportOptions"),
  28406         .atomic_order => return sema.resolveBuiltinTypeFields(block, src, "AtomicOrder"),
  28407         .atomic_rmw_op => return sema.resolveBuiltinTypeFields(block, src, "AtomicRmwOp"),
  28408         .calling_convention => return sema.resolveBuiltinTypeFields(block, src, "CallingConvention"),
  28409         .address_space => return sema.resolveBuiltinTypeFields(block, src, "AddressSpace"),
  28410         .float_mode => return sema.resolveBuiltinTypeFields(block, src, "FloatMode"),
  28411         .reduce_op => return sema.resolveBuiltinTypeFields(block, src, "ReduceOp"),
  28412         .call_options => return sema.resolveBuiltinTypeFields(block, src, "CallOptions"),
  28413         .prefetch_options => return sema.resolveBuiltinTypeFields(block, src, "PrefetchOptions"),
  28414 
  28415         else => return ty,
  28416     }
  28417 }
  28418 
  28419 fn resolveTypeFieldsStruct(
  28420     sema: *Sema,
  28421     ty: Type,
  28422     struct_obj: *Module.Struct,
  28423 ) CompileError!void {
  28424     switch (struct_obj.status) {
  28425         .none => {},
  28426         .field_types_wip => {
  28427             const msg = try Module.ErrorMsg.create(
  28428                 sema.gpa,
  28429                 struct_obj.srcLoc(sema.mod),
  28430                 "struct '{}' depends on itself",
  28431                 .{ty.fmt(sema.mod)},
  28432             );
  28433             return sema.failWithOwnedErrorMsg(msg);
  28434         },
  28435         .have_field_types,
  28436         .have_layout,
  28437         .layout_wip,
  28438         .fully_resolved_wip,
  28439         .fully_resolved,
  28440         => return,
  28441     }
  28442 
  28443     struct_obj.status = .field_types_wip;
  28444     try semaStructFields(sema.mod, struct_obj);
  28445 }
  28446 
  28447 fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_obj: *Module.Union) CompileError!void {
  28448     switch (union_obj.status) {
  28449         .none => {},
  28450         .field_types_wip => {
  28451             const msg = try Module.ErrorMsg.create(
  28452                 sema.gpa,
  28453                 union_obj.srcLoc(sema.mod),
  28454                 "union '{}' depends on itself",
  28455                 .{ty.fmt(sema.mod)},
  28456             );
  28457             return sema.failWithOwnedErrorMsg(msg);
  28458         },
  28459         .have_field_types,
  28460         .have_layout,
  28461         .layout_wip,
  28462         .fully_resolved_wip,
  28463         .fully_resolved,
  28464         => return,
  28465     }
  28466 
  28467     union_obj.status = .field_types_wip;
  28468     try semaUnionFields(sema.mod, union_obj);
  28469     union_obj.status = .have_field_types;
  28470 }
  28471 
  28472 fn resolveBuiltinTypeFields(
  28473     sema: *Sema,
  28474     block: *Block,
  28475     src: LazySrcLoc,
  28476     name: []const u8,
  28477 ) CompileError!Type {
  28478     const resolved_ty = try sema.getBuiltinType(block, src, name);
  28479     return sema.resolveTypeFields(block, src, resolved_ty);
  28480 }
  28481 
  28482 fn resolveInferredErrorSet(
  28483     sema: *Sema,
  28484     block: *Block,
  28485     src: LazySrcLoc,
  28486     ies: *Module.Fn.InferredErrorSet,
  28487 ) CompileError!void {
  28488     if (ies.is_resolved) return;
  28489 
  28490     if (ies.func.state == .in_progress) {
  28491         return sema.fail(block, src, "unable to resolve inferred error set", .{});
  28492     }
  28493 
  28494     // In order to ensure that all dependencies are properly added to the set, we
  28495     // need to ensure the function body is analyzed of the inferred error set.
  28496     // However, in the case of comptime/inline function calls with inferred error sets,
  28497     // each call gets a new InferredErrorSet object, which points to the same
  28498     // `*Module.Fn`. Not only is the function not relevant to the inferred error set
  28499     // in this case, it may be a generic function which would cause an assertion failure
  28500     // if we called `ensureFuncBodyAnalyzed` on it here.
  28501     const ies_func_owner_decl = sema.mod.declPtr(ies.func.owner_decl);
  28502     const ies_func_info = ies_func_owner_decl.ty.fnInfo();
  28503     // if ies declared by a inline function with generic return type, the return_type should be generic_poison,
  28504     // because inline function does not create a new declaration, and the ies has been filled with analyzeCall,
  28505     // so here we can simply skip this case.
  28506     if (ies_func_info.return_type.tag() == .generic_poison) {
  28507         assert(ies_func_info.cc == .Inline);
  28508     } else if (ies_func_info.return_type.errorUnionSet().castTag(.error_set_inferred).?.data == ies) {
  28509         // In this case we are dealing with the actual InferredErrorSet object that
  28510         // corresponds to the function, not one created to track an inline/comptime call.
  28511         try sema.ensureFuncBodyAnalyzed(ies.func);
  28512     }
  28513 
  28514     ies.is_resolved = true;
  28515 
  28516     var it = ies.inferred_error_sets.keyIterator();
  28517     while (it.next()) |other_error_set_ptr| {
  28518         const other_ies: *Module.Fn.InferredErrorSet = other_error_set_ptr.*;
  28519         if (ies == other_ies) continue;
  28520         try sema.resolveInferredErrorSet(block, src, other_ies);
  28521 
  28522         for (other_ies.errors.keys()) |key| {
  28523             try ies.errors.put(sema.gpa, key, {});
  28524         }
  28525         if (other_ies.is_anyerror)
  28526             ies.is_anyerror = true;
  28527     }
  28528 }
  28529 
  28530 fn resolveInferredErrorSetTy(
  28531     sema: *Sema,
  28532     block: *Block,
  28533     src: LazySrcLoc,
  28534     ty: Type,
  28535 ) CompileError!void {
  28536     if (ty.castTag(.error_set_inferred)) |inferred| {
  28537         try sema.resolveInferredErrorSet(block, src, inferred.data);
  28538     }
  28539 }
  28540 
  28541 fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
  28542     const gpa = mod.gpa;
  28543     const decl_index = struct_obj.owner_decl;
  28544     const file_scope = struct_obj.namespace.file_scope;
  28545     if (file_scope.status != .success_zir) return error.AnalysisFail;
  28546     const zir = file_scope.zir;
  28547     const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
  28548     assert(extended.opcode == .struct_decl);
  28549     const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
  28550     var extra_index: usize = extended.operand;
  28551 
  28552     const src = LazySrcLoc.nodeOffset(0);
  28553     extra_index += @boolToInt(small.has_src_node);
  28554 
  28555     const fields_len = if (small.has_fields_len) blk: {
  28556         const fields_len = zir.extra[extra_index];
  28557         extra_index += 1;
  28558         break :blk fields_len;
  28559     } else 0;
  28560 
  28561     const decls_len = if (small.has_decls_len) decls_len: {
  28562         const decls_len = zir.extra[extra_index];
  28563         extra_index += 1;
  28564         break :decls_len decls_len;
  28565     } else 0;
  28566 
  28567     // The backing integer cannot be handled until `resolveStructLayout()`.
  28568     if (small.has_backing_int) {
  28569         const backing_int_body_len = zir.extra[extra_index];
  28570         extra_index += 1; // backing_int_body_len
  28571         if (backing_int_body_len == 0) {
  28572             extra_index += 1; // backing_int_ref
  28573         } else {
  28574             extra_index += backing_int_body_len; // backing_int_body_inst
  28575         }
  28576     }
  28577 
  28578     // Skip over decls.
  28579     var decls_it = zir.declIteratorInner(extra_index, decls_len);
  28580     while (decls_it.next()) |_| {}
  28581     extra_index = decls_it.extra_index;
  28582 
  28583     if (fields_len == 0) {
  28584         if (struct_obj.layout == .Packed) {
  28585             try semaBackingIntType(mod, struct_obj);
  28586         }
  28587         struct_obj.status = .have_layout;
  28588         return;
  28589     }
  28590 
  28591     const decl = mod.declPtr(decl_index);
  28592     var decl_arena = decl.value_arena.?.promote(gpa);
  28593     defer decl.value_arena.?.* = decl_arena.state;
  28594     const decl_arena_allocator = decl_arena.allocator();
  28595 
  28596     var analysis_arena = std.heap.ArenaAllocator.init(gpa);
  28597     defer analysis_arena.deinit();
  28598 
  28599     var sema: Sema = .{
  28600         .mod = mod,
  28601         .gpa = gpa,
  28602         .arena = analysis_arena.allocator(),
  28603         .perm_arena = decl_arena_allocator,
  28604         .code = zir,
  28605         .owner_decl = decl,
  28606         .owner_decl_index = decl_index,
  28607         .func = null,
  28608         .fn_ret_ty = Type.void,
  28609         .owner_func = null,
  28610     };
  28611     defer sema.deinit();
  28612 
  28613     var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope);
  28614     defer wip_captures.deinit();
  28615 
  28616     var block_scope: Block = .{
  28617         .parent = null,
  28618         .sema = &sema,
  28619         .src_decl = decl_index,
  28620         .namespace = &struct_obj.namespace,
  28621         .wip_capture_scope = wip_captures.scope,
  28622         .instructions = .{},
  28623         .inlining = null,
  28624         .is_comptime = true,
  28625     };
  28626     defer {
  28627         assert(block_scope.instructions.items.len == 0);
  28628         block_scope.params.deinit(gpa);
  28629     }
  28630 
  28631     try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
  28632 
  28633     const Field = struct {
  28634         type_body_len: u32 = 0,
  28635         align_body_len: u32 = 0,
  28636         init_body_len: u32 = 0,
  28637         type_ref: Air.Inst.Ref = .none,
  28638     };
  28639     const fields = try sema.arena.alloc(Field, fields_len);
  28640     var any_inits = false;
  28641 
  28642     {
  28643         const bits_per_field = 4;
  28644         const fields_per_u32 = 32 / bits_per_field;
  28645         const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
  28646         const flags_index = extra_index;
  28647         var bit_bag_index: usize = flags_index;
  28648         extra_index += bit_bags_count;
  28649         var cur_bit_bag: u32 = undefined;
  28650         var field_i: u32 = 0;
  28651         while (field_i < fields_len) : (field_i += 1) {
  28652             if (field_i % fields_per_u32 == 0) {
  28653                 cur_bit_bag = zir.extra[bit_bag_index];
  28654                 bit_bag_index += 1;
  28655             }
  28656             const has_align = @truncate(u1, cur_bit_bag) != 0;
  28657             cur_bit_bag >>= 1;
  28658             const has_init = @truncate(u1, cur_bit_bag) != 0;
  28659             cur_bit_bag >>= 1;
  28660             const is_comptime = @truncate(u1, cur_bit_bag) != 0;
  28661             cur_bit_bag >>= 1;
  28662             const has_type_body = @truncate(u1, cur_bit_bag) != 0;
  28663             cur_bit_bag >>= 1;
  28664 
  28665             const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
  28666             extra_index += 1;
  28667             extra_index += 1; // doc_comment
  28668 
  28669             fields[field_i] = .{};
  28670 
  28671             if (has_type_body) {
  28672                 fields[field_i].type_body_len = zir.extra[extra_index];
  28673             } else {
  28674                 fields[field_i].type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
  28675             }
  28676             extra_index += 1;
  28677 
  28678             // This string needs to outlive the ZIR code.
  28679             const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
  28680 
  28681             const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
  28682             if (gop.found_existing) {
  28683                 const msg = msg: {
  28684                     const tree = try sema.getAstTree(&block_scope);
  28685                     const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i);
  28686                     const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name});
  28687                     errdefer msg.destroy(gpa);
  28688 
  28689                     const prev_field_index = struct_obj.fields.getIndex(field_name).?;
  28690                     const prev_field_src = enumFieldSrcLoc(decl, tree.*, 0, prev_field_index);
  28691                     try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});
  28692                     try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
  28693                     break :msg msg;
  28694                 };
  28695                 return sema.failWithOwnedErrorMsg(msg);
  28696             }
  28697             gop.value_ptr.* = .{
  28698                 .ty = Type.initTag(.noreturn),
  28699                 .abi_align = 0,
  28700                 .default_val = Value.initTag(.unreachable_value),
  28701                 .is_comptime = is_comptime,
  28702                 .offset = undefined,
  28703             };
  28704 
  28705             if (has_align) {
  28706                 fields[field_i].align_body_len = zir.extra[extra_index];
  28707                 extra_index += 1;
  28708             }
  28709             if (has_init) {
  28710                 fields[field_i].init_body_len = zir.extra[extra_index];
  28711                 extra_index += 1;
  28712                 any_inits = true;
  28713             }
  28714         }
  28715     }
  28716 
  28717     // Next we do only types and alignments, saving the inits for a second pass,
  28718     // so that init values may depend on type layout.
  28719     const bodies_index = extra_index;
  28720 
  28721     for (fields) |zir_field, i| {
  28722         // TODO emit compile errors for invalid field types
  28723         // such as arrays and pointers inside packed structs.
  28724         const field_ty: Type = ty: {
  28725             if (zir_field.type_ref != .none) {
  28726                 // TODO: if we need to report an error here, use a source location
  28727                 // that points to this type expression rather than the struct.
  28728                 // But only resolve the source location if we need to emit a compile error.
  28729                 break :ty try sema.resolveType(&block_scope, src, zir_field.type_ref);
  28730             }
  28731             assert(zir_field.type_body_len != 0);
  28732             const body = zir.extra[extra_index..][0..zir_field.type_body_len];
  28733             extra_index += body.len;
  28734             const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
  28735             break :ty try sema.analyzeAsType(&block_scope, src, ty_ref);
  28736         };
  28737         if (field_ty.tag() == .generic_poison) {
  28738             return error.GenericPoison;
  28739         }
  28740 
  28741         const field = &struct_obj.fields.values()[i];
  28742         field.ty = try field_ty.copy(decl_arena_allocator);
  28743 
  28744         if (field_ty.zigTypeTag() == .Opaque) {
  28745             const msg = msg: {
  28746                 const tree = try sema.getAstTree(&block_scope);
  28747                 const field_src = enumFieldSrcLoc(decl, tree.*, 0, i);
  28748                 const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
  28749                 errdefer msg.destroy(sema.gpa);
  28750 
  28751                 try sema.addDeclaredHereNote(msg, field_ty);
  28752                 break :msg msg;
  28753             };
  28754             return sema.failWithOwnedErrorMsg(msg);
  28755         }
  28756         if (field_ty.zigTypeTag() == .NoReturn) {
  28757             const msg = msg: {
  28758                 const tree = try sema.getAstTree(&block_scope);
  28759                 const field_src = enumFieldSrcLoc(decl, tree.*, 0, i);
  28760                 const msg = try sema.errMsg(&block_scope, field_src, "struct fields cannot be 'noreturn'", .{});
  28761                 errdefer msg.destroy(sema.gpa);
  28762 
  28763                 try sema.addDeclaredHereNote(msg, field_ty);
  28764                 break :msg msg;
  28765             };
  28766             return sema.failWithOwnedErrorMsg(msg);
  28767         }
  28768         if (struct_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field.ty, .other)) {
  28769             const msg = msg: {
  28770                 const tree = try sema.getAstTree(&block_scope);
  28771                 const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i);
  28772                 const msg = try sema.errMsg(&block_scope, fields_src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
  28773                 errdefer msg.destroy(sema.gpa);
  28774 
  28775                 try sema.explainWhyTypeIsNotExtern(msg, fields_src.toSrcLoc(decl), field.ty, .other);
  28776 
  28777                 try sema.addDeclaredHereNote(msg, field.ty);
  28778                 break :msg msg;
  28779             };
  28780             return sema.failWithOwnedErrorMsg(msg);
  28781         } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty))) {
  28782             const msg = msg: {
  28783                 const tree = try sema.getAstTree(&block_scope);
  28784                 const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i);
  28785                 const msg = try sema.errMsg(&block_scope, fields_src, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
  28786                 errdefer msg.destroy(sema.gpa);
  28787 
  28788                 try sema.explainWhyTypeIsNotPacked(msg, fields_src.toSrcLoc(decl), field.ty);
  28789 
  28790                 try sema.addDeclaredHereNote(msg, field.ty);
  28791                 break :msg msg;
  28792             };
  28793             return sema.failWithOwnedErrorMsg(msg);
  28794         }
  28795 
  28796         if (zir_field.align_body_len > 0) {
  28797             const body = zir.extra[extra_index..][0..zir_field.align_body_len];
  28798             extra_index += body.len;
  28799             const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
  28800             field.abi_align = try sema.analyzeAsAlign(&block_scope, src, align_ref);
  28801         }
  28802 
  28803         extra_index += zir_field.init_body_len;
  28804     }
  28805 
  28806     struct_obj.status = .have_field_types;
  28807 
  28808     if (any_inits) {
  28809         extra_index = bodies_index;
  28810         for (fields) |zir_field, i| {
  28811             extra_index += zir_field.type_body_len;
  28812             extra_index += zir_field.align_body_len;
  28813             if (zir_field.init_body_len > 0) {
  28814                 const body = zir.extra[extra_index..][0..zir_field.init_body_len];
  28815                 extra_index += body.len;
  28816                 const init = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
  28817                 const field = &struct_obj.fields.values()[i];
  28818                 const coerced = try sema.coerce(&block_scope, field.ty, init, src);
  28819                 const default_val = (try sema.resolveMaybeUndefVal(&block_scope, src, coerced)) orelse
  28820                     return sema.failWithNeededComptime(&block_scope, src, "struct field default value must be comptime known");
  28821                 field.default_val = try default_val.copy(decl_arena_allocator);
  28822             }
  28823         }
  28824     }
  28825 
  28826     struct_obj.have_field_inits = true;
  28827 }
  28828 
  28829 fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
  28830     const tracy = trace(@src());
  28831     defer tracy.end();
  28832 
  28833     const gpa = mod.gpa;
  28834     const decl_index = union_obj.owner_decl;
  28835     const zir = union_obj.namespace.file_scope.zir;
  28836     const extended = zir.instructions.items(.data)[union_obj.zir_index].extended;
  28837     assert(extended.opcode == .union_decl);
  28838     const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
  28839     var extra_index: usize = extended.operand;
  28840 
  28841     const src = LazySrcLoc.nodeOffset(0);
  28842     extra_index += @boolToInt(small.has_src_node);
  28843 
  28844     const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: {
  28845         const ty_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
  28846         extra_index += 1;
  28847         break :blk ty_ref;
  28848     } else .none;
  28849 
  28850     const body_len = if (small.has_body_len) blk: {
  28851         const body_len = zir.extra[extra_index];
  28852         extra_index += 1;
  28853         break :blk body_len;
  28854     } else 0;
  28855 
  28856     const fields_len = if (small.has_fields_len) blk: {
  28857         const fields_len = zir.extra[extra_index];
  28858         extra_index += 1;
  28859         break :blk fields_len;
  28860     } else 0;
  28861 
  28862     const decls_len = if (small.has_decls_len) decls_len: {
  28863         const decls_len = zir.extra[extra_index];
  28864         extra_index += 1;
  28865         break :decls_len decls_len;
  28866     } else 0;
  28867 
  28868     // Skip over decls.
  28869     var decls_it = zir.declIteratorInner(extra_index, decls_len);
  28870     while (decls_it.next()) |_| {}
  28871     extra_index = decls_it.extra_index;
  28872 
  28873     const body = zir.extra[extra_index..][0..body_len];
  28874     extra_index += body.len;
  28875 
  28876     const decl = mod.declPtr(decl_index);
  28877 
  28878     var decl_arena = decl.value_arena.?.promote(gpa);
  28879     defer decl.value_arena.?.* = decl_arena.state;
  28880     const decl_arena_allocator = decl_arena.allocator();
  28881 
  28882     var analysis_arena = std.heap.ArenaAllocator.init(gpa);
  28883     defer analysis_arena.deinit();
  28884 
  28885     var sema: Sema = .{
  28886         .mod = mod,
  28887         .gpa = gpa,
  28888         .arena = analysis_arena.allocator(),
  28889         .perm_arena = decl_arena_allocator,
  28890         .code = zir,
  28891         .owner_decl = decl,
  28892         .owner_decl_index = decl_index,
  28893         .func = null,
  28894         .fn_ret_ty = Type.void,
  28895         .owner_func = null,
  28896     };
  28897     defer sema.deinit();
  28898 
  28899     var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope);
  28900     defer wip_captures.deinit();
  28901 
  28902     var block_scope: Block = .{
  28903         .parent = null,
  28904         .sema = &sema,
  28905         .src_decl = decl_index,
  28906         .namespace = &union_obj.namespace,
  28907         .wip_capture_scope = wip_captures.scope,
  28908         .instructions = .{},
  28909         .inlining = null,
  28910         .is_comptime = true,
  28911     };
  28912     defer {
  28913         assert(block_scope.instructions.items.len == 0);
  28914         block_scope.params.deinit(gpa);
  28915     }
  28916 
  28917     if (body.len != 0) {
  28918         try sema.analyzeBody(&block_scope, body);
  28919     }
  28920 
  28921     try wip_captures.finalize();
  28922 
  28923     try union_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
  28924 
  28925     var int_tag_ty: Type = undefined;
  28926     var enum_field_names: ?*Module.EnumNumbered.NameMap = null;
  28927     var enum_value_map: ?*Module.EnumNumbered.ValueMap = null;
  28928     var tag_ty_field_names: ?Module.EnumFull.NameMap = null;
  28929     if (tag_type_ref != .none) {
  28930         const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x };
  28931         const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref);
  28932         if (small.auto_enum_tag) {
  28933             // The provided type is an integer type and we must construct the enum tag type here.
  28934             int_tag_ty = provided_ty;
  28935             if (int_tag_ty.zigTypeTag() != .Int and int_tag_ty.zigTypeTag() != .ComptimeInt) {
  28936                 return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{}'", .{int_tag_ty.fmt(sema.mod)});
  28937             }
  28938             union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, fields_len, provided_ty, union_obj);
  28939             const enum_obj = union_obj.tag_ty.castTag(.enum_numbered).?.data;
  28940             enum_field_names = &enum_obj.fields;
  28941             enum_value_map = &enum_obj.values;
  28942         } else {
  28943             // The provided type is the enum tag type.
  28944             union_obj.tag_ty = try provided_ty.copy(decl_arena_allocator);
  28945             if (union_obj.tag_ty.zigTypeTag() != .Enum) {
  28946                 return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(sema.mod)});
  28947             }
  28948             // The fields of the union must match the enum exactly.
  28949             // Store a copy of the enum field names so we can check for
  28950             // missing or extraneous fields later.
  28951             tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena);
  28952         }
  28953     } else {
  28954         // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis
  28955         // purposes, we still auto-generate an enum tag type the same way. That the union is
  28956         // untagged is represented by the Type tag (union vs union_tagged).
  28957         union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, fields_len, union_obj);
  28958         enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
  28959     }
  28960 
  28961     if (fields_len == 0) {
  28962         return;
  28963     }
  28964 
  28965     const bits_per_field = 4;
  28966     const fields_per_u32 = 32 / bits_per_field;
  28967     const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
  28968     var bit_bag_index: usize = extra_index;
  28969     extra_index += bit_bags_count;
  28970     var cur_bit_bag: u32 = undefined;
  28971     var field_i: u32 = 0;
  28972     var last_tag_val: ?Value = null;
  28973     while (field_i < fields_len) : (field_i += 1) {
  28974         if (field_i % fields_per_u32 == 0) {
  28975             cur_bit_bag = zir.extra[bit_bag_index];
  28976             bit_bag_index += 1;
  28977         }
  28978         const has_type = @truncate(u1, cur_bit_bag) != 0;
  28979         cur_bit_bag >>= 1;
  28980         const has_align = @truncate(u1, cur_bit_bag) != 0;
  28981         cur_bit_bag >>= 1;
  28982         const has_tag = @truncate(u1, cur_bit_bag) != 0;
  28983         cur_bit_bag >>= 1;
  28984         const unused = @truncate(u1, cur_bit_bag) != 0;
  28985         cur_bit_bag >>= 1;
  28986         _ = unused;
  28987 
  28988         const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
  28989         extra_index += 1;
  28990 
  28991         // doc_comment
  28992         extra_index += 1;
  28993 
  28994         const field_type_ref: Zir.Inst.Ref = if (has_type) blk: {
  28995             const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
  28996             extra_index += 1;
  28997             break :blk field_type_ref;
  28998         } else .none;
  28999 
  29000         const align_ref: Zir.Inst.Ref = if (has_align) blk: {
  29001             const align_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
  29002             extra_index += 1;
  29003             break :blk align_ref;
  29004         } else .none;
  29005 
  29006         const tag_ref: Zir.Inst.Ref = if (has_tag) blk: {
  29007             const tag_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
  29008             extra_index += 1;
  29009             break :blk try sema.resolveInst(tag_ref);
  29010         } else .none;
  29011 
  29012         if (enum_value_map) |map| {
  29013             if (tag_ref != .none) {
  29014                 const tag_src = src; // TODO better source location
  29015                 const coerced = try sema.coerce(&block_scope, int_tag_ty, tag_ref, tag_src);
  29016                 const val = try sema.resolveConstValue(&block_scope, tag_src, coerced, "enum tag value must be comptime known");
  29017                 last_tag_val = val;
  29018 
  29019                 // This puts the memory into the union arena, not the enum arena, but
  29020                 // it is OK since they share the same lifetime.
  29021                 const copied_val = try val.copy(decl_arena_allocator);
  29022                 map.putAssumeCapacityContext(copied_val, {}, .{
  29023                     .ty = int_tag_ty,
  29024                     .mod = mod,
  29025                 });
  29026             } else {
  29027                 const val = if (last_tag_val) |val|
  29028                     try sema.intAdd(&block_scope, src, val, Value.one, int_tag_ty)
  29029                 else
  29030                     Value.zero;
  29031                 last_tag_val = val;
  29032 
  29033                 const copied_val = try val.copy(decl_arena_allocator);
  29034                 map.putAssumeCapacityContext(copied_val, {}, .{
  29035                     .ty = int_tag_ty,
  29036                     .mod = mod,
  29037                 });
  29038             }
  29039         }
  29040 
  29041         // This string needs to outlive the ZIR code.
  29042         const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
  29043         if (enum_field_names) |set| {
  29044             set.putAssumeCapacity(field_name, {});
  29045         }
  29046 
  29047         const field_ty: Type = if (!has_type)
  29048             Type.void
  29049         else if (field_type_ref == .none)
  29050             Type.initTag(.noreturn)
  29051         else
  29052             // TODO: if we need to report an error here, use a source location
  29053             // that points to this type expression rather than the union.
  29054             // But only resolve the source location if we need to emit a compile error.
  29055             try sema.resolveType(&block_scope, src, field_type_ref);
  29056 
  29057         if (field_ty.tag() == .generic_poison) {
  29058             return error.GenericPoison;
  29059         }
  29060 
  29061         const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
  29062         if (gop.found_existing) {
  29063             const msg = msg: {
  29064                 const tree = try sema.getAstTree(&block_scope);
  29065                 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i);
  29066                 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name});
  29067                 errdefer msg.destroy(gpa);
  29068 
  29069                 const prev_field_index = union_obj.fields.getIndex(field_name).?;
  29070                 const prev_field_src = enumFieldSrcLoc(decl, tree.*, 0, prev_field_index);
  29071                 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});
  29072                 try sema.errNote(&block_scope, src, msg, "union declared here", .{});
  29073                 break :msg msg;
  29074             };
  29075             return sema.failWithOwnedErrorMsg(msg);
  29076         }
  29077 
  29078         if (tag_ty_field_names) |*names| {
  29079             const enum_has_field = names.orderedRemove(field_name);
  29080             if (!enum_has_field) {
  29081                 const msg = msg: {
  29082                     const tree = try sema.getAstTree(&block_scope);
  29083                     const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i);
  29084                     const msg = try sema.errMsg(&block_scope, field_src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
  29085                     errdefer msg.destroy(sema.gpa);
  29086                     try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
  29087                     break :msg msg;
  29088                 };
  29089                 return sema.failWithOwnedErrorMsg(msg);
  29090             }
  29091         }
  29092 
  29093         if (field_ty.zigTypeTag() == .Opaque) {
  29094             const msg = msg: {
  29095                 const tree = try sema.getAstTree(&block_scope);
  29096                 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i);
  29097                 const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
  29098                 errdefer msg.destroy(sema.gpa);
  29099 
  29100                 try sema.addDeclaredHereNote(msg, field_ty);
  29101                 break :msg msg;
  29102             };
  29103             return sema.failWithOwnedErrorMsg(msg);
  29104         }
  29105         if (union_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field_ty, .union_field)) {
  29106             const msg = msg: {
  29107                 const tree = try sema.getAstTree(&block_scope);
  29108                 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i);
  29109                 const msg = try sema.errMsg(&block_scope, field_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
  29110                 errdefer msg.destroy(sema.gpa);
  29111 
  29112                 try sema.explainWhyTypeIsNotExtern(msg, field_src.toSrcLoc(decl), field_ty, .union_field);
  29113 
  29114                 try sema.addDeclaredHereNote(msg, field_ty);
  29115                 break :msg msg;
  29116             };
  29117             return sema.failWithOwnedErrorMsg(msg);
  29118         } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty))) {
  29119             const msg = msg: {
  29120                 const tree = try sema.getAstTree(&block_scope);
  29121                 const fields_src = enumFieldSrcLoc(decl, tree.*, 0, field_i);
  29122                 const msg = try sema.errMsg(&block_scope, fields_src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
  29123                 errdefer msg.destroy(sema.gpa);
  29124 
  29125                 try sema.explainWhyTypeIsNotPacked(msg, fields_src.toSrcLoc(decl), field_ty);
  29126 
  29127                 try sema.addDeclaredHereNote(msg, field_ty);
  29128                 break :msg msg;
  29129             };
  29130             return sema.failWithOwnedErrorMsg(msg);
  29131         }
  29132 
  29133         gop.value_ptr.* = .{
  29134             .ty = try field_ty.copy(decl_arena_allocator),
  29135             .abi_align = 0,
  29136         };
  29137 
  29138         if (align_ref != .none) {
  29139             // TODO: if we need to report an error here, use a source location
  29140             // that points to this alignment expression rather than the struct.
  29141             // But only resolve the source location if we need to emit a compile error.
  29142             gop.value_ptr.abi_align = try sema.resolveAlign(&block_scope, src, align_ref);
  29143         } else {
  29144             gop.value_ptr.abi_align = 0;
  29145         }
  29146     }
  29147 
  29148     if (tag_ty_field_names) |names| {
  29149         if (names.count() > 0) {
  29150             const msg = msg: {
  29151                 const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{});
  29152                 errdefer msg.destroy(sema.gpa);
  29153 
  29154                 const enum_ty = union_obj.tag_ty;
  29155                 for (names.keys()) |field_name| {
  29156                     const field_index = enum_ty.enumFieldIndex(field_name).?;
  29157                     try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name});
  29158                 }
  29159                 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
  29160                 break :msg msg;
  29161             };
  29162             return sema.failWithOwnedErrorMsg(msg);
  29163         }
  29164     }
  29165 }
  29166 
  29167 fn generateUnionTagTypeNumbered(
  29168     sema: *Sema,
  29169     block: *Block,
  29170     fields_len: u32,
  29171     int_ty: Type,
  29172     union_obj: *Module.Union,
  29173 ) !Type {
  29174     const mod = sema.mod;
  29175 
  29176     var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
  29177     errdefer new_decl_arena.deinit();
  29178     const new_decl_arena_allocator = new_decl_arena.allocator();
  29179 
  29180     const enum_obj = try new_decl_arena_allocator.create(Module.EnumNumbered);
  29181     const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumNumbered);
  29182     enum_ty_payload.* = .{
  29183         .base = .{ .tag = .enum_numbered },
  29184         .data = enum_obj,
  29185     };
  29186     const enum_ty = Type.initPayload(&enum_ty_payload.base);
  29187     const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
  29188 
  29189     const src_decl = mod.declPtr(block.src_decl);
  29190     const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
  29191     errdefer mod.destroyDecl(new_decl_index);
  29192     const name = name: {
  29193         const fqn = try union_obj.getFullyQualifiedName(mod);
  29194         defer sema.gpa.free(fqn);
  29195         break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn});
  29196     };
  29197     try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{
  29198         .ty = Type.type,
  29199         .val = enum_val,
  29200     }, name);
  29201     sema.mod.declPtr(new_decl_index).name_fully_qualified = true;
  29202 
  29203     const new_decl = mod.declPtr(new_decl_index);
  29204     new_decl.owns_tv = true;
  29205     new_decl.name_fully_qualified = true;
  29206     errdefer mod.abortAnonDecl(new_decl_index);
  29207 
  29208     enum_obj.* = .{
  29209         .owner_decl = new_decl_index,
  29210         .tag_ty = int_ty,
  29211         .fields = .{},
  29212         .values = .{},
  29213     };
  29214     // Here we pre-allocate the maps using the decl arena.
  29215     try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
  29216     try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
  29217         .ty = int_ty,
  29218         .mod = mod,
  29219     });
  29220     try new_decl.finalizeNewArena(&new_decl_arena);
  29221     return enum_ty;
  29222 }
  29223 
  29224 fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, maybe_union_obj: ?*Module.Union) !Type {
  29225     const mod = sema.mod;
  29226 
  29227     var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
  29228     errdefer new_decl_arena.deinit();
  29229     const new_decl_arena_allocator = new_decl_arena.allocator();
  29230 
  29231     const enum_obj = try new_decl_arena_allocator.create(Module.EnumSimple);
  29232     const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumSimple);
  29233     enum_ty_payload.* = .{
  29234         .base = .{ .tag = .enum_simple },
  29235         .data = enum_obj,
  29236     };
  29237     const enum_ty = Type.initPayload(&enum_ty_payload.base);
  29238     const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
  29239 
  29240     const new_decl_index = new_decl_index: {
  29241         const union_obj = maybe_union_obj orelse {
  29242             break :new_decl_index try mod.createAnonymousDecl(block, .{
  29243                 .ty = Type.type,
  29244                 .val = enum_val,
  29245             });
  29246         };
  29247         const src_decl = mod.declPtr(block.src_decl);
  29248         const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
  29249         errdefer mod.destroyDecl(new_decl_index);
  29250         const name = name: {
  29251             const fqn = try union_obj.getFullyQualifiedName(mod);
  29252             defer sema.gpa.free(fqn);
  29253             break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn});
  29254         };
  29255         try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{
  29256             .ty = Type.type,
  29257             .val = enum_val,
  29258         }, name);
  29259         sema.mod.declPtr(new_decl_index).name_fully_qualified = true;
  29260         break :new_decl_index new_decl_index;
  29261     };
  29262 
  29263     const new_decl = mod.declPtr(new_decl_index);
  29264     new_decl.owns_tv = true;
  29265     errdefer mod.abortAnonDecl(new_decl_index);
  29266 
  29267     enum_obj.* = .{
  29268         .owner_decl = new_decl_index,
  29269         .fields = .{},
  29270     };
  29271     // Here we pre-allocate the maps using the decl arena.
  29272     try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
  29273     try new_decl.finalizeNewArena(&new_decl_arena);
  29274     return enum_ty;
  29275 }
  29276 
  29277 fn getBuiltin(
  29278     sema: *Sema,
  29279     block: *Block,
  29280     src: LazySrcLoc,
  29281     name: []const u8,
  29282 ) CompileError!Air.Inst.Ref {
  29283     const mod = sema.mod;
  29284     const std_pkg = mod.main_pkg.table.get("std").?;
  29285     const std_file = (mod.importPkg(std_pkg) catch unreachable).file;
  29286     const opt_builtin_inst = try sema.namespaceLookupRef(
  29287         block,
  29288         src,
  29289         mod.declPtr(std_file.root_decl.unwrap().?).src_namespace,
  29290         "builtin",
  29291     );
  29292     const builtin_inst = try sema.analyzeLoad(block, src, opt_builtin_inst.?, src);
  29293     const builtin_ty = try sema.analyzeAsType(block, src, builtin_inst);
  29294     const opt_ty_decl = try sema.namespaceLookup(
  29295         block,
  29296         src,
  29297         builtin_ty.getNamespace().?,
  29298         name,
  29299     );
  29300     return sema.analyzeDeclVal(block, src, opt_ty_decl.?);
  29301 }
  29302 
  29303 fn getBuiltinType(
  29304     sema: *Sema,
  29305     block: *Block,
  29306     src: LazySrcLoc,
  29307     name: []const u8,
  29308 ) CompileError!Type {
  29309     const ty_inst = try sema.getBuiltin(block, src, name);
  29310     const result_ty = try sema.analyzeAsType(block, src, ty_inst);
  29311     try sema.resolveTypeFully(block, src, result_ty); // Should not fail
  29312     return result_ty;
  29313 }
  29314 
  29315 /// There is another implementation of this in `Type.onePossibleValue`. This one
  29316 /// in `Sema` is for calling during semantic analysis, and performs field resolution
  29317 /// to get the answer. The one in `Type` is for calling during codegen and asserts
  29318 /// that the types are already resolved.
  29319 /// TODO assert the return value matches `ty.onePossibleValue`
  29320 pub fn typeHasOnePossibleValue(
  29321     sema: *Sema,
  29322     block: *Block,
  29323     src: LazySrcLoc,
  29324     ty: Type,
  29325 ) CompileError!?Value {
  29326     switch (ty.tag()) {
  29327         .f16,
  29328         .f32,
  29329         .f64,
  29330         .f80,
  29331         .f128,
  29332         .c_longdouble,
  29333         .comptime_int,
  29334         .comptime_float,
  29335         .u1,
  29336         .u8,
  29337         .i8,
  29338         .u16,
  29339         .i16,
  29340         .u29,
  29341         .u32,
  29342         .i32,
  29343         .u64,
  29344         .i64,
  29345         .u128,
  29346         .i128,
  29347         .usize,
  29348         .isize,
  29349         .c_short,
  29350         .c_ushort,
  29351         .c_int,
  29352         .c_uint,
  29353         .c_long,
  29354         .c_ulong,
  29355         .c_longlong,
  29356         .c_ulonglong,
  29357         .bool,
  29358         .type,
  29359         .anyerror,
  29360         .error_set_single,
  29361         .error_set,
  29362         .error_set_merged,
  29363         .error_union,
  29364         .fn_noreturn_no_args,
  29365         .fn_void_no_args,
  29366         .fn_naked_noreturn_no_args,
  29367         .fn_ccc_void_no_args,
  29368         .function,
  29369         .single_const_pointer_to_comptime_int,
  29370         .array_sentinel,
  29371         .array_u8_sentinel_0,
  29372         .const_slice_u8,
  29373         .const_slice_u8_sentinel_0,
  29374         .const_slice,
  29375         .mut_slice,
  29376         .anyopaque,
  29377         .optional_single_mut_pointer,
  29378         .optional_single_const_pointer,
  29379         .enum_literal,
  29380         .anyerror_void_error_union,
  29381         .error_set_inferred,
  29382         .@"opaque",
  29383         .var_args_param,
  29384         .manyptr_u8,
  29385         .manyptr_const_u8,
  29386         .manyptr_const_u8_sentinel_0,
  29387         .atomic_order,
  29388         .atomic_rmw_op,
  29389         .calling_convention,
  29390         .address_space,
  29391         .float_mode,
  29392         .reduce_op,
  29393         .call_options,
  29394         .prefetch_options,
  29395         .export_options,
  29396         .extern_options,
  29397         .type_info,
  29398         .@"anyframe",
  29399         .anyframe_T,
  29400         .many_const_pointer,
  29401         .many_mut_pointer,
  29402         .c_const_pointer,
  29403         .c_mut_pointer,
  29404         .single_const_pointer,
  29405         .single_mut_pointer,
  29406         .pointer,
  29407         .bound_fn,
  29408         => return null,
  29409 
  29410         .optional => {
  29411             var buf: Type.Payload.ElemType = undefined;
  29412             const child_ty = ty.optionalChild(&buf);
  29413             if (child_ty.isNoReturn()) {
  29414                 return Value.@"null";
  29415             } else {
  29416                 return null;
  29417             }
  29418         },
  29419 
  29420         .@"struct" => {
  29421             const resolved_ty = try sema.resolveTypeFields(block, src, ty);
  29422             const s = resolved_ty.castTag(.@"struct").?.data;
  29423             for (s.fields.values()) |field, i| {
  29424                 if (field.is_comptime) continue;
  29425                 if (field.ty.eql(resolved_ty, sema.mod)) {
  29426                     const msg = try Module.ErrorMsg.create(
  29427                         sema.gpa,
  29428                         s.srcLoc(sema.mod),
  29429                         "struct '{}' depends on itself",
  29430                         .{ty.fmt(sema.mod)},
  29431                     );
  29432                     try sema.addFieldErrNote(resolved_ty, i, msg, "while checking this field", .{});
  29433                     return sema.failWithOwnedErrorMsg(msg);
  29434                 }
  29435                 if ((try sema.typeHasOnePossibleValue(block, src, field.ty)) == null) {
  29436                     return null;
  29437                 }
  29438             }
  29439             return Value.initTag(.empty_struct_value);
  29440         },
  29441 
  29442         .tuple, .anon_struct => {
  29443             const tuple = ty.tupleFields();
  29444             for (tuple.values) |val, i| {
  29445                 const is_comptime = val.tag() != .unreachable_value;
  29446                 if (is_comptime) continue;
  29447                 if ((try sema.typeHasOnePossibleValue(block, src, tuple.types[i])) != null) continue;
  29448                 return null;
  29449             }
  29450             return Value.initTag(.empty_struct_value);
  29451         },
  29452 
  29453         .enum_numbered => {
  29454             const resolved_ty = try sema.resolveTypeFields(block, src, ty);
  29455             const enum_obj = resolved_ty.castTag(.enum_numbered).?.data;
  29456             // An explicit tag type is always provided for enum_numbered.
  29457             if (enum_obj.tag_ty.hasRuntimeBits()) {
  29458                 return null;
  29459             }
  29460             if (enum_obj.fields.count() == 1) {
  29461                 if (enum_obj.values.count() == 0) {
  29462                     return Value.zero; // auto-numbered
  29463                 } else {
  29464                     return enum_obj.values.keys()[0];
  29465                 }
  29466             } else {
  29467                 return null;
  29468             }
  29469         },
  29470         .enum_full => {
  29471             const resolved_ty = try sema.resolveTypeFields(block, src, ty);
  29472             const enum_obj = resolved_ty.castTag(.enum_full).?.data;
  29473             if (enum_obj.tag_ty.hasRuntimeBits()) {
  29474                 return null;
  29475             }
  29476             if (enum_obj.fields.count() == 1) {
  29477                 if (enum_obj.values.count() == 0) {
  29478                     return Value.zero; // auto-numbered
  29479                 } else {
  29480                     return enum_obj.values.keys()[0];
  29481                 }
  29482             } else {
  29483                 return null;
  29484             }
  29485         },
  29486         .enum_simple => {
  29487             const resolved_ty = try sema.resolveTypeFields(block, src, ty);
  29488             const enum_simple = resolved_ty.castTag(.enum_simple).?.data;
  29489             if (enum_simple.fields.count() == 1) {
  29490                 return Value.zero;
  29491             } else {
  29492                 return null;
  29493             }
  29494         },
  29495         .enum_nonexhaustive => {
  29496             const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
  29497             if (tag_ty.zigTypeTag() != .ComptimeInt and !(try sema.typeHasRuntimeBits(block, src, tag_ty))) {
  29498                 return Value.zero;
  29499             } else {
  29500                 return null;
  29501             }
  29502         },
  29503         .@"union", .union_safety_tagged, .union_tagged => {
  29504             const resolved_ty = try sema.resolveTypeFields(block, src, ty);
  29505             const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
  29506             const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse
  29507                 return null;
  29508             const fields = union_obj.fields.values();
  29509             if (fields.len == 0) return Value.initTag(.empty_struct_value);
  29510             const only_field = fields[0];
  29511             if (only_field.ty.eql(resolved_ty, sema.mod)) {
  29512                 const msg = try Module.ErrorMsg.create(
  29513                     sema.gpa,
  29514                     union_obj.srcLoc(sema.mod),
  29515                     "union '{}' depends on itself",
  29516                     .{ty.fmt(sema.mod)},
  29517                 );
  29518                 try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{});
  29519                 return sema.failWithOwnedErrorMsg(msg);
  29520             }
  29521             const val_val = (try sema.typeHasOnePossibleValue(block, src, only_field.ty)) orelse
  29522                 return null;
  29523             // TODO make this not allocate. The function in `Type.onePossibleValue`
  29524             // currently returns `empty_struct_value` and we should do that here too.
  29525             return try Value.Tag.@"union".create(sema.arena, .{
  29526                 .tag = tag_val,
  29527                 .val = val_val,
  29528             });
  29529         },
  29530 
  29531         .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
  29532         .void => return Value.void,
  29533         .noreturn => return Value.initTag(.unreachable_value),
  29534         .@"null" => return Value.@"null",
  29535         .@"undefined" => return Value.initTag(.undef),
  29536 
  29537         .int_unsigned, .int_signed => {
  29538             if (ty.cast(Type.Payload.Bits).?.data == 0) {
  29539                 return Value.zero;
  29540             } else {
  29541                 return null;
  29542             }
  29543         },
  29544         .vector, .array, .array_u8 => {
  29545             if (ty.arrayLen() == 0)
  29546                 return Value.initTag(.empty_array);
  29547             if ((try sema.typeHasOnePossibleValue(block, src, ty.elemType())) != null) {
  29548                 return Value.initTag(.the_only_possible_value);
  29549             }
  29550             return null;
  29551         },
  29552 
  29553         .inferred_alloc_const => unreachable,
  29554         .inferred_alloc_mut => unreachable,
  29555         .generic_poison => return error.GenericPoison,
  29556     }
  29557 }
  29558 
  29559 fn getAstTree(sema: *Sema, block: *Block) CompileError!*const std.zig.Ast {
  29560     return block.namespace.file_scope.getTree(sema.gpa) catch |err| {
  29561         log.err("unable to load AST to report compile error: {s}", .{@errorName(err)});
  29562         return error.AnalysisFail;
  29563     };
  29564 }
  29565 
  29566 fn enumFieldSrcLoc(
  29567     decl: *Decl,
  29568     tree: std.zig.Ast,
  29569     node_offset: i32,
  29570     field_index: usize,
  29571 ) LazySrcLoc {
  29572     @setCold(true);
  29573     const enum_node = decl.relativeToNodeIndex(node_offset);
  29574     const node_tags = tree.nodes.items(.tag);
  29575     var buffer: [2]std.zig.Ast.Node.Index = undefined;
  29576     const container_decl = switch (node_tags[enum_node]) {
  29577         .container_decl,
  29578         .container_decl_trailing,
  29579         => tree.containerDecl(enum_node),
  29580 
  29581         .container_decl_two,
  29582         .container_decl_two_trailing,
  29583         => tree.containerDeclTwo(&buffer, enum_node),
  29584 
  29585         .container_decl_arg,
  29586         .container_decl_arg_trailing,
  29587         => tree.containerDeclArg(enum_node),
  29588 
  29589         .tagged_union,
  29590         .tagged_union_trailing,
  29591         => tree.taggedUnion(enum_node),
  29592         .tagged_union_two,
  29593         .tagged_union_two_trailing,
  29594         => tree.taggedUnionTwo(&buffer, enum_node),
  29595         .tagged_union_enum_tag,
  29596         .tagged_union_enum_tag_trailing,
  29597         => tree.taggedUnionEnumTag(enum_node),
  29598 
  29599         // Container was constructed with `@Type`.
  29600         else => return LazySrcLoc.nodeOffset(0),
  29601     };
  29602     var it_index: usize = 0;
  29603     for (container_decl.ast.members) |member_node| {
  29604         switch (node_tags[member_node]) {
  29605             .container_field_init,
  29606             .container_field_align,
  29607             .container_field,
  29608             => {
  29609                 if (it_index == field_index) {
  29610                     return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(member_node));
  29611                 }
  29612                 it_index += 1;
  29613             },
  29614 
  29615             else => continue,
  29616         }
  29617     } else unreachable;
  29618 }
  29619 
  29620 /// Returns the type of the AIR instruction.
  29621 fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type {
  29622     return sema.getTmpAir().typeOf(inst);
  29623 }
  29624 
  29625 pub fn getTmpAir(sema: Sema) Air {
  29626     return .{
  29627         .instructions = sema.air_instructions.slice(),
  29628         .extra = sema.air_extra.items,
  29629         .values = sema.air_values.items,
  29630     };
  29631 }
  29632 
  29633 pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
  29634     switch (ty.tag()) {
  29635         .u1 => return .u1_type,
  29636         .u8 => return .u8_type,
  29637         .i8 => return .i8_type,
  29638         .u16 => return .u16_type,
  29639         .u29 => return .u29_type,
  29640         .i16 => return .i16_type,
  29641         .u32 => return .u32_type,
  29642         .i32 => return .i32_type,
  29643         .u64 => return .u64_type,
  29644         .i64 => return .i64_type,
  29645         .u128 => return .u128_type,
  29646         .i128 => return .i128_type,
  29647         .usize => return .usize_type,
  29648         .isize => return .isize_type,
  29649         .c_short => return .c_short_type,
  29650         .c_ushort => return .c_ushort_type,
  29651         .c_int => return .c_int_type,
  29652         .c_uint => return .c_uint_type,
  29653         .c_long => return .c_long_type,
  29654         .c_ulong => return .c_ulong_type,
  29655         .c_longlong => return .c_longlong_type,
  29656         .c_ulonglong => return .c_ulonglong_type,
  29657         .c_longdouble => return .c_longdouble_type,
  29658         .f16 => return .f16_type,
  29659         .f32 => return .f32_type,
  29660         .f64 => return .f64_type,
  29661         .f80 => return .f80_type,
  29662         .f128 => return .f128_type,
  29663         .anyopaque => return .anyopaque_type,
  29664         .bool => return .bool_type,
  29665         .void => return .void_type,
  29666         .type => return .type_type,
  29667         .anyerror => return .anyerror_type,
  29668         .comptime_int => return .comptime_int_type,
  29669         .comptime_float => return .comptime_float_type,
  29670         .noreturn => return .noreturn_type,
  29671         .@"anyframe" => return .anyframe_type,
  29672         .@"null" => return .null_type,
  29673         .@"undefined" => return .undefined_type,
  29674         .enum_literal => return .enum_literal_type,
  29675         .atomic_order => return .atomic_order_type,
  29676         .atomic_rmw_op => return .atomic_rmw_op_type,
  29677         .calling_convention => return .calling_convention_type,
  29678         .address_space => return .address_space_type,
  29679         .float_mode => return .float_mode_type,
  29680         .reduce_op => return .reduce_op_type,
  29681         .call_options => return .call_options_type,
  29682         .prefetch_options => return .prefetch_options_type,
  29683         .export_options => return .export_options_type,
  29684         .extern_options => return .extern_options_type,
  29685         .type_info => return .type_info_type,
  29686         .manyptr_u8 => return .manyptr_u8_type,
  29687         .manyptr_const_u8 => return .manyptr_const_u8_type,
  29688         .fn_noreturn_no_args => return .fn_noreturn_no_args_type,
  29689         .fn_void_no_args => return .fn_void_no_args_type,
  29690         .fn_naked_noreturn_no_args => return .fn_naked_noreturn_no_args_type,
  29691         .fn_ccc_void_no_args => return .fn_ccc_void_no_args_type,
  29692         .single_const_pointer_to_comptime_int => return .single_const_pointer_to_comptime_int_type,
  29693         .const_slice_u8 => return .const_slice_u8_type,
  29694         .anyerror_void_error_union => return .anyerror_void_error_union_type,
  29695         .generic_poison => return .generic_poison_type,
  29696         else => {},
  29697     }
  29698     try sema.air_instructions.append(sema.gpa, .{
  29699         .tag = .const_ty,
  29700         .data = .{ .ty = ty },
  29701     });
  29702     return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
  29703 }
  29704 
  29705 fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref {
  29706     return sema.addConstant(ty, try Value.Tag.int_u64.create(sema.arena, int));
  29707 }
  29708 
  29709 fn addBool(sema: *Sema, ty: Type, boolean: bool) CompileError!Air.Inst.Ref {
  29710     return switch (ty.zigTypeTag()) {
  29711         .Vector => sema.addConstant(ty, try Value.Tag.repeated.create(sema.arena, Value.makeBool(boolean))),
  29712         .Bool => try sema.resolveInst(if (boolean) .bool_true else .bool_false),
  29713         else => unreachable,
  29714     };
  29715 }
  29716 
  29717 fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {
  29718     return sema.addConstant(ty, Value.undef);
  29719 }
  29720 
  29721 pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref {
  29722     const gpa = sema.gpa;
  29723     const ty_inst = try sema.addType(ty);
  29724     try sema.air_values.append(gpa, val);
  29725     try sema.air_instructions.append(gpa, .{
  29726         .tag = .constant,
  29727         .data = .{ .ty_pl = .{
  29728             .ty = ty_inst,
  29729             .payload = @intCast(u32, sema.air_values.items.len - 1),
  29730         } },
  29731     });
  29732     return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
  29733 }
  29734 
  29735 pub fn addExtra(sema: *Sema, extra: anytype) Allocator.Error!u32 {
  29736     const fields = std.meta.fields(@TypeOf(extra));
  29737     try sema.air_extra.ensureUnusedCapacity(sema.gpa, fields.len);
  29738     return addExtraAssumeCapacity(sema, extra);
  29739 }
  29740 
  29741 pub fn addExtraAssumeCapacity(sema: *Sema, extra: anytype) u32 {
  29742     const fields = std.meta.fields(@TypeOf(extra));
  29743     const result = @intCast(u32, sema.air_extra.items.len);
  29744     inline for (fields) |field| {
  29745         sema.air_extra.appendAssumeCapacity(switch (field.field_type) {
  29746             u32 => @field(extra, field.name),
  29747             Air.Inst.Ref => @enumToInt(@field(extra, field.name)),
  29748             i32 => @bitCast(u32, @field(extra, field.name)),
  29749             else => @compileError("bad field type"),
  29750         });
  29751     }
  29752     return result;
  29753 }
  29754 
  29755 fn appendRefsAssumeCapacity(sema: *Sema, refs: []const Air.Inst.Ref) void {
  29756     const coerced = @ptrCast([]const u32, refs);
  29757     sema.air_extra.appendSliceAssumeCapacity(coerced);
  29758 }
  29759 
  29760 fn getBreakBlock(sema: *Sema, inst_index: Air.Inst.Index) ?Air.Inst.Index {
  29761     const air_datas = sema.air_instructions.items(.data);
  29762     const air_tags = sema.air_instructions.items(.tag);
  29763     switch (air_tags[inst_index]) {
  29764         .br => return air_datas[inst_index].br.block_inst,
  29765         else => return null,
  29766     }
  29767 }
  29768 
  29769 fn isComptimeKnown(
  29770     sema: *Sema,
  29771     block: *Block,
  29772     src: LazySrcLoc,
  29773     inst: Air.Inst.Ref,
  29774 ) !bool {
  29775     return (try sema.resolveMaybeUndefVal(block, src, inst)) != null;
  29776 }
  29777 
  29778 fn analyzeComptimeAlloc(
  29779     sema: *Sema,
  29780     block: *Block,
  29781     var_type: Type,
  29782     alignment: u32,
  29783     src: LazySrcLoc,
  29784 ) CompileError!Air.Inst.Ref {
  29785     // Needed to make an anon decl with type `var_type` (the `finish()` call below).
  29786     _ = try sema.typeHasOnePossibleValue(block, src, var_type);
  29787 
  29788     const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
  29789         .pointee_type = var_type,
  29790         .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant),
  29791         .@"align" = alignment,
  29792     });
  29793 
  29794     var anon_decl = try block.startAnonDecl(src);
  29795     defer anon_decl.deinit();
  29796 
  29797     const decl_index = try anon_decl.finish(
  29798         try var_type.copy(anon_decl.arena()),
  29799         // There will be stores before the first load, but they may be to sub-elements or
  29800         // sub-fields. So we need to initialize with undef to allow the mechanism to expand
  29801         // into fields/elements and have those overridden with stored values.
  29802         Value.undef,
  29803         alignment,
  29804     );
  29805     const decl = sema.mod.declPtr(decl_index);
  29806     decl.@"align" = alignment;
  29807 
  29808     try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index);
  29809     return sema.addConstant(ptr_type, try Value.Tag.decl_ref_mut.create(sema.arena, .{
  29810         .runtime_index = block.runtime_index,
  29811         .decl_index = decl_index,
  29812     }));
  29813 }
  29814 
  29815 /// The places where a user can specify an address space attribute
  29816 pub const AddressSpaceContext = enum {
  29817     /// A function is specified to be placed in a certain address space.
  29818     function,
  29819 
  29820     /// A (global) variable is specified to be placed in a certain address space.
  29821     /// In contrast to .constant, these values (and thus the address space they will be
  29822     /// placed in) are required to be mutable.
  29823     variable,
  29824 
  29825     /// A (global) constant value is specified to be placed in a certain address space.
  29826     /// In contrast to .variable, values placed in this address space are not required to be mutable.
  29827     constant,
  29828 
  29829     /// A pointer is ascripted to point into a certain address space.
  29830     pointer,
  29831 };
  29832 
  29833 pub fn analyzeAddrspace(
  29834     sema: *Sema,
  29835     block: *Block,
  29836     src: LazySrcLoc,
  29837     zir_ref: Zir.Inst.Ref,
  29838     ctx: AddressSpaceContext,
  29839 ) !std.builtin.AddressSpace {
  29840     const addrspace_tv = try sema.resolveInstConst(block, src, zir_ref, "addresspace must be comptime known");
  29841     const address_space = addrspace_tv.val.toEnum(std.builtin.AddressSpace);
  29842     const target = sema.mod.getTarget();
  29843     const arch = target.cpu.arch;
  29844     const is_gpu = arch == .nvptx or arch == .nvptx64;
  29845 
  29846     const supported = switch (address_space) {
  29847         .generic => true,
  29848         .gs, .fs, .ss => (arch == .i386 or arch == .x86_64) and ctx == .pointer,
  29849         // TODO: check that .shared and .local are left uninitialized
  29850         .global, .param, .shared, .local => is_gpu,
  29851         .constant => is_gpu and (ctx == .constant),
  29852     };
  29853 
  29854     if (!supported) {
  29855         // TODO error messages could be made more elaborate here
  29856         const entity = switch (ctx) {
  29857             .function => "functions",
  29858             .variable => "mutable values",
  29859             .constant => "constant values",
  29860             .pointer => "pointers",
  29861         };
  29862         return sema.fail(
  29863             block,
  29864             src,
  29865             "{s} with address space '{s}' are not supported on {s}",
  29866             .{ entity, @tagName(address_space), arch.genericName() },
  29867         );
  29868     }
  29869 
  29870     return address_space;
  29871 }
  29872 
  29873 /// Asserts the value is a pointer and dereferences it.
  29874 /// Returns `null` if the pointer contents cannot be loaded at comptime.
  29875 fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value {
  29876     const load_ty = ptr_ty.childType();
  29877     const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty, true);
  29878     switch (res) {
  29879         .runtime_load => return null,
  29880         .val => |v| return v,
  29881         .needed_well_defined => |ty| return sema.fail(
  29882             block,
  29883             src,
  29884             "comptime dereference requires '{}' to have a well-defined layout, but it does not.",
  29885             .{ty.fmt(sema.mod)},
  29886         ),
  29887         .out_of_bounds => |ty| return sema.fail(
  29888             block,
  29889             src,
  29890             "dereference of '{}' exceeds bounds of containing decl of type '{}'",
  29891             .{ ptr_ty.fmt(sema.mod), ty.fmt(sema.mod) },
  29892         ),
  29893     }
  29894 }
  29895 
  29896 const DerefResult = union(enum) {
  29897     runtime_load,
  29898     val: Value,
  29899     needed_well_defined: Type,
  29900     out_of_bounds: Type,
  29901 };
  29902 
  29903 fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type, want_mutable: bool) CompileError!DerefResult {
  29904     const target = sema.mod.getTarget();
  29905     const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) {
  29906         error.RuntimeLoad => return DerefResult{ .runtime_load = {} },
  29907         else => |e| return e,
  29908     };
  29909 
  29910     if (deref.pointee) |tv| {
  29911         const coerce_in_mem_ok =
  29912             (try sema.coerceInMemoryAllowed(block, load_ty, tv.ty, false, target, src, src)) == .ok or
  29913             (try sema.coerceInMemoryAllowed(block, tv.ty, load_ty, false, target, src, src)) == .ok;
  29914         if (coerce_in_mem_ok) {
  29915             // We have a Value that lines up in virtual memory exactly with what we want to load,
  29916             // and it is in-memory coercible to load_ty. It may be returned without modifications.
  29917             if (deref.is_mutable and want_mutable) {
  29918                 // The decl whose value we are obtaining here may be overwritten with
  29919                 // a different value upon further semantic analysis, which would
  29920                 // invalidate this memory. So we must copy here.
  29921                 return DerefResult{ .val = try tv.val.copy(sema.arena) };
  29922             }
  29923             return DerefResult{ .val = tv.val };
  29924         }
  29925     }
  29926 
  29927     // The type is not in-memory coercible or the direct dereference failed, so it must
  29928     // be bitcast according to the pointer type we are performing the load through.
  29929     if (!load_ty.hasWellDefinedLayout()) {
  29930         return DerefResult{ .needed_well_defined = load_ty };
  29931     }
  29932 
  29933     const load_sz = try sema.typeAbiSize(block, src, load_ty);
  29934 
  29935     // Try the smaller bit-cast first, since that's more efficient than using the larger `parent`
  29936     if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(block, src, tv.ty))
  29937         return DerefResult{ .val = try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0) };
  29938 
  29939     // If that fails, try to bit-cast from the largest parent value with a well-defined layout
  29940     if (deref.parent) |parent| if (load_sz + parent.byte_offset <= try sema.typeAbiSize(block, src, parent.tv.ty))
  29941         return DerefResult{ .val = try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset) };
  29942 
  29943     if (deref.ty_without_well_defined_layout) |bad_ty| {
  29944         // We got no parent for bit-casting, or the parent we got was too small. Either way, the problem
  29945         // is that some type we encountered when de-referencing does not have a well-defined layout.
  29946         return DerefResult{ .needed_well_defined = bad_ty };
  29947     } else {
  29948         // If all encountered types had well-defined layouts, the parent is the root decl and it just
  29949         // wasn't big enough for the load.
  29950         return DerefResult{ .out_of_bounds = deref.parent.?.tv.ty };
  29951     }
  29952 }
  29953 
  29954 /// Used to convert a u64 value to a usize value, emitting a compile error if the number
  29955 /// is too big to fit.
  29956 fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError!usize {
  29957     if (@bitSizeOf(u64) <= @bitSizeOf(usize)) return int;
  29958     return std.math.cast(usize, int) orelse return sema.fail(block, src, "expression produces integer value '{d}' which is too big for this compiler implementation to handle", .{int});
  29959 }
  29960 
  29961 /// For pointer-like optionals, it returns the pointer type. For pointers,
  29962 /// the type is returned unmodified.
  29963 /// This can return `error.AnalysisFail` because it sometimes requires resolving whether
  29964 /// a type has zero bits, which can cause a "foo depends on itself" compile error.
  29965 /// This logic must be kept in sync with `Type.isPtrLikeOptional`.
  29966 fn typePtrOrOptionalPtrTy(
  29967     sema: *Sema,
  29968     block: *Block,
  29969     ty: Type,
  29970     buf: *Type.Payload.ElemType,
  29971     src: LazySrcLoc,
  29972 ) !?Type {
  29973     switch (ty.tag()) {
  29974         .optional_single_const_pointer,
  29975         .optional_single_mut_pointer,
  29976         .c_const_pointer,
  29977         .c_mut_pointer,
  29978         => return ty.optionalChild(buf),
  29979 
  29980         .single_const_pointer_to_comptime_int,
  29981         .single_const_pointer,
  29982         .single_mut_pointer,
  29983         .many_const_pointer,
  29984         .many_mut_pointer,
  29985         .manyptr_u8,
  29986         .manyptr_const_u8,
  29987         .manyptr_const_u8_sentinel_0,
  29988         => return ty,
  29989 
  29990         .pointer => switch (ty.ptrSize()) {
  29991             .Slice => return null,
  29992             .C => return ty.optionalChild(buf),
  29993             else => return ty,
  29994         },
  29995 
  29996         .inferred_alloc_const => unreachable,
  29997         .inferred_alloc_mut => unreachable,
  29998 
  29999         .optional => {
  30000             const child_type = ty.optionalChild(buf);
  30001             if (child_type.zigTypeTag() != .Pointer) return null;
  30002 
  30003             const info = child_type.ptrInfo().data;
  30004             switch (info.size) {
  30005                 .Slice, .C => return null,
  30006                 .Many, .One => {
  30007                     if (info.@"allowzero") return null;
  30008 
  30009                     // optionals of zero sized types behave like bools, not pointers
  30010                     if ((try sema.typeHasOnePossibleValue(block, src, child_type)) != null) {
  30011                         return null;
  30012                     }
  30013 
  30014                     return child_type;
  30015                 },
  30016             }
  30017         },
  30018 
  30019         else => return null,
  30020     }
  30021 }
  30022 
  30023 /// `generic_poison` will return false.
  30024 /// This function returns false negatives when structs and unions are having their
  30025 /// field types resolved.
  30026 /// TODO assert the return value matches `ty.comptimeOnly`
  30027 /// TODO merge these implementations together with the "advanced"/sema_kit pattern seen
  30028 /// elsewhere in value.zig
  30029 pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
  30030     return switch (ty.tag()) {
  30031         .u1,
  30032         .u8,
  30033         .i8,
  30034         .u16,
  30035         .i16,
  30036         .u29,
  30037         .u32,
  30038         .i32,
  30039         .u64,
  30040         .i64,
  30041         .u128,
  30042         .i128,
  30043         .usize,
  30044         .isize,
  30045         .c_short,
  30046         .c_ushort,
  30047         .c_int,
  30048         .c_uint,
  30049         .c_long,
  30050         .c_ulong,
  30051         .c_longlong,
  30052         .c_ulonglong,
  30053         .c_longdouble,
  30054         .f16,
  30055         .f32,
  30056         .f64,
  30057         .f80,
  30058         .f128,
  30059         .anyopaque,
  30060         .bool,
  30061         .void,
  30062         .anyerror,
  30063         .noreturn,
  30064         .@"anyframe",
  30065         .@"null",
  30066         .@"undefined",
  30067         .atomic_order,
  30068         .atomic_rmw_op,
  30069         .calling_convention,
  30070         .address_space,
  30071         .float_mode,
  30072         .reduce_op,
  30073         .call_options,
  30074         .prefetch_options,
  30075         .export_options,
  30076         .extern_options,
  30077         .manyptr_u8,
  30078         .manyptr_const_u8,
  30079         .manyptr_const_u8_sentinel_0,
  30080         .const_slice_u8,
  30081         .const_slice_u8_sentinel_0,
  30082         .anyerror_void_error_union,
  30083         .empty_struct_literal,
  30084         .empty_struct,
  30085         .error_set,
  30086         .error_set_single,
  30087         .error_set_inferred,
  30088         .error_set_merged,
  30089         .@"opaque",
  30090         .generic_poison,
  30091         .array_u8,
  30092         .array_u8_sentinel_0,
  30093         .int_signed,
  30094         .int_unsigned,
  30095         .enum_simple,
  30096         => false,
  30097 
  30098         .single_const_pointer_to_comptime_int,
  30099         .type,
  30100         .comptime_int,
  30101         .comptime_float,
  30102         .enum_literal,
  30103         .type_info,
  30104         // These are function bodies, not function pointers.
  30105         .fn_noreturn_no_args,
  30106         .fn_void_no_args,
  30107         .fn_naked_noreturn_no_args,
  30108         .fn_ccc_void_no_args,
  30109         .function,
  30110         => true,
  30111 
  30112         .var_args_param => unreachable,
  30113         .inferred_alloc_mut => unreachable,
  30114         .inferred_alloc_const => unreachable,
  30115         .bound_fn => unreachable,
  30116 
  30117         .array,
  30118         .array_sentinel,
  30119         .vector,
  30120         => return sema.typeRequiresComptime(ty.childType()),
  30121 
  30122         .pointer,
  30123         .single_const_pointer,
  30124         .single_mut_pointer,
  30125         .many_const_pointer,
  30126         .many_mut_pointer,
  30127         .c_const_pointer,
  30128         .c_mut_pointer,
  30129         .const_slice,
  30130         .mut_slice,
  30131         => {
  30132             const child_ty = ty.childType();
  30133             if (child_ty.zigTypeTag() == .Fn) {
  30134                 return child_ty.fnInfo().is_generic;
  30135             } else {
  30136                 return sema.typeRequiresComptime(child_ty);
  30137             }
  30138         },
  30139 
  30140         .optional,
  30141         .optional_single_mut_pointer,
  30142         .optional_single_const_pointer,
  30143         => {
  30144             var buf: Type.Payload.ElemType = undefined;
  30145             return sema.typeRequiresComptime(ty.optionalChild(&buf));
  30146         },
  30147 
  30148         .tuple, .anon_struct => {
  30149             const tuple = ty.tupleFields();
  30150             for (tuple.types) |field_ty, i| {
  30151                 const have_comptime_val = tuple.values[i].tag() != .unreachable_value;
  30152                 if (!have_comptime_val and try sema.typeRequiresComptime(field_ty)) {
  30153                     return true;
  30154                 }
  30155             }
  30156             return false;
  30157         },
  30158 
  30159         .@"struct" => {
  30160             const struct_obj = ty.castTag(.@"struct").?.data;
  30161             switch (struct_obj.requires_comptime) {
  30162                 .no, .wip => return false,
  30163                 .yes => return true,
  30164                 .unknown => {
  30165                     if (struct_obj.status == .field_types_wip)
  30166                         return false;
  30167 
  30168                     try sema.resolveTypeFieldsStruct(ty, struct_obj);
  30169 
  30170                     struct_obj.requires_comptime = .wip;
  30171                     for (struct_obj.fields.values()) |field| {
  30172                         if (field.is_comptime) continue;
  30173                         if (try sema.typeRequiresComptime(field.ty)) {
  30174                             struct_obj.requires_comptime = .yes;
  30175                             return true;
  30176                         }
  30177                     }
  30178                     struct_obj.requires_comptime = .no;
  30179                     return false;
  30180                 },
  30181             }
  30182         },
  30183 
  30184         .@"union", .union_safety_tagged, .union_tagged => {
  30185             const union_obj = ty.cast(Type.Payload.Union).?.data;
  30186             switch (union_obj.requires_comptime) {
  30187                 .no, .wip => return false,
  30188                 .yes => return true,
  30189                 .unknown => {
  30190                     if (union_obj.status == .field_types_wip)
  30191                         return false;
  30192 
  30193                     try sema.resolveTypeFieldsUnion(ty, union_obj);
  30194 
  30195                     union_obj.requires_comptime = .wip;
  30196                     for (union_obj.fields.values()) |field| {
  30197                         if (try sema.typeRequiresComptime(field.ty)) {
  30198                             union_obj.requires_comptime = .yes;
  30199                             return true;
  30200                         }
  30201                     }
  30202                     union_obj.requires_comptime = .no;
  30203                     return false;
  30204                 },
  30205             }
  30206         },
  30207 
  30208         .error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()),
  30209         .anyframe_T => {
  30210             const child_ty = ty.castTag(.anyframe_T).?.data;
  30211             return sema.typeRequiresComptime(child_ty);
  30212         },
  30213         .enum_numbered => {
  30214             const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty;
  30215             return sema.typeRequiresComptime(tag_ty);
  30216         },
  30217         .enum_full, .enum_nonexhaustive => {
  30218             const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty;
  30219             return sema.typeRequiresComptime(tag_ty);
  30220         },
  30221     };
  30222 }
  30223 
  30224 pub fn typeHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
  30225     return ty.hasRuntimeBitsAdvanced(false, sema.kit(block, src));
  30226 }
  30227 
  30228 fn typeAbiSize(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u64 {
  30229     try sema.resolveTypeLayout(block, src, ty);
  30230     const target = sema.mod.getTarget();
  30231     return ty.abiSize(target);
  30232 }
  30233 
  30234 fn typeAbiAlignment(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!u32 {
  30235     const target = sema.mod.getTarget();
  30236     return (try ty.abiAlignmentAdvanced(target, .{ .sema_kit = sema.kit(block, src) })).scalar;
  30237 }
  30238 
  30239 /// Not valid to call for packed unions.
  30240 /// Keep implementation in sync with `Module.Union.Field.normalAlignment`.
  30241 fn unionFieldAlignment(
  30242     sema: *Sema,
  30243     block: *Block,
  30244     src: LazySrcLoc,
  30245     field: Module.Union.Field,
  30246 ) !u32 {
  30247     if (field.ty.zigTypeTag() == .NoReturn) {
  30248         return @as(u32, 0);
  30249     } else if (field.abi_align == 0) {
  30250         return sema.typeAbiAlignment(block, src, field.ty);
  30251     } else {
  30252         return field.abi_align;
  30253     }
  30254 }
  30255 
  30256 /// Synchronize logic with `Type.isFnOrHasRuntimeBits`.
  30257 pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
  30258     const fn_info = ty.fnInfo();
  30259     if (fn_info.is_generic) return false;
  30260     if (fn_info.is_var_args) return true;
  30261     switch (fn_info.cc) {
  30262         // If there was a comptime calling convention, it should also return false here.
  30263         .Inline => return false,
  30264         else => {},
  30265     }
  30266     if (try sema.typeRequiresComptime(fn_info.return_type)) {
  30267         return false;
  30268     }
  30269     return true;
  30270 }
  30271 
  30272 fn unionFieldIndex(
  30273     sema: *Sema,
  30274     block: *Block,
  30275     unresolved_union_ty: Type,
  30276     field_name: []const u8,
  30277     field_src: LazySrcLoc,
  30278 ) !u32 {
  30279     const union_ty = try sema.resolveTypeFields(block, field_src, unresolved_union_ty);
  30280     const union_obj = union_ty.cast(Type.Payload.Union).?.data;
  30281     const field_index_usize = union_obj.fields.getIndex(field_name) orelse
  30282         return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
  30283     return @intCast(u32, field_index_usize);
  30284 }
  30285 
  30286 fn structFieldIndex(
  30287     sema: *Sema,
  30288     block: *Block,
  30289     unresolved_struct_ty: Type,
  30290     field_name: []const u8,
  30291     field_src: LazySrcLoc,
  30292 ) !u32 {
  30293     const struct_ty = try sema.resolveTypeFields(block, field_src, unresolved_struct_ty);
  30294     if (struct_ty.isAnonStruct()) {
  30295         return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src);
  30296     } else {
  30297         const struct_obj = struct_ty.castTag(.@"struct").?.data;
  30298         const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
  30299             return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
  30300         return @intCast(u32, field_index_usize);
  30301     }
  30302 }
  30303 
  30304 fn anonStructFieldIndex(
  30305     sema: *Sema,
  30306     block: *Block,
  30307     struct_ty: Type,
  30308     field_name: []const u8,
  30309     field_src: LazySrcLoc,
  30310 ) !u32 {
  30311     const anon_struct = struct_ty.castTag(.anon_struct).?.data;
  30312     for (anon_struct.names) |name, i| {
  30313         if (mem.eql(u8, name, field_name)) {
  30314             return @intCast(u32, i);
  30315         }
  30316     }
  30317     return sema.fail(block, field_src, "no field named '{s}' in anonymous struct '{}'", .{
  30318         field_name, struct_ty.fmt(sema.mod),
  30319     });
  30320 }
  30321 
  30322 fn kit(sema: *Sema, block: *Block, src: LazySrcLoc) Module.WipAnalysis {
  30323     return .{ .sema = sema, .block = block, .src = src };
  30324 }
  30325 
  30326 fn queueFullTypeResolution(sema: *Sema, ty: Type) !void {
  30327     const inst_ref = try sema.addType(ty);
  30328     try sema.types_to_resolve.append(sema.gpa, inst_ref);
  30329 }
  30330 
  30331 fn intAdd(sema: *Sema, block: *Block, src: LazySrcLoc, lhs: Value, rhs: Value, ty: Type) !Value {
  30332     if (ty.zigTypeTag() == .Vector) {
  30333         const result_data = try sema.arena.alloc(Value, ty.vectorLen());
  30334         for (result_data) |*scalar, i| {
  30335             scalar.* = try sema.intAddScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i));
  30336         }
  30337         return Value.Tag.aggregate.create(sema.arena, result_data);
  30338     }
  30339     return sema.intAddScalar(block, src, lhs, rhs);
  30340 }
  30341 
  30342 fn intAddScalar(sema: *Sema, block: *Block, src: LazySrcLoc, lhs: Value, rhs: Value) !Value {
  30343     // TODO is this a performance issue? maybe we should try the operation without
  30344     // resorting to BigInt first.
  30345     var lhs_space: Value.BigIntSpace = undefined;
  30346     var rhs_space: Value.BigIntSpace = undefined;
  30347     const target = sema.mod.getTarget();
  30348     const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, src));
  30349     const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, src));
  30350     const limbs = try sema.arena.alloc(
  30351         std.math.big.Limb,
  30352         std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
  30353     );
  30354     var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
  30355     result_bigint.add(lhs_bigint, rhs_bigint);
  30356     return Value.fromBigInt(sema.arena, result_bigint.toConst());
  30357 }
  30358 
  30359 /// Supports both (vectors of) floats and ints; handles undefined scalars.
  30360 fn numberAddWrap(
  30361     sema: *Sema,
  30362     block: *Block,
  30363     src: LazySrcLoc,
  30364     lhs: Value,
  30365     rhs: Value,
  30366     ty: Type,
  30367 ) !Value {
  30368     if (ty.zigTypeTag() == .Vector) {
  30369         const result_data = try sema.arena.alloc(Value, ty.vectorLen());
  30370         for (result_data) |*scalar, i| {
  30371             scalar.* = try sema.numberAddWrapScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType());
  30372         }
  30373         return Value.Tag.aggregate.create(sema.arena, result_data);
  30374     }
  30375     return sema.numberAddWrapScalar(block, src, lhs, rhs, ty);
  30376 }
  30377 
  30378 /// Supports both floats and ints; handles undefined.
  30379 fn numberAddWrapScalar(
  30380     sema: *Sema,
  30381     block: *Block,
  30382     src: LazySrcLoc,
  30383     lhs: Value,
  30384     rhs: Value,
  30385     ty: Type,
  30386 ) !Value {
  30387     if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
  30388 
  30389     if (ty.zigTypeTag() == .ComptimeInt) {
  30390         return sema.intAdd(block, src, lhs, rhs, ty);
  30391     }
  30392 
  30393     if (ty.isAnyFloat()) {
  30394         return sema.floatAdd(lhs, rhs, ty);
  30395     }
  30396 
  30397     const overflow_result = try sema.intAddWithOverflow(block, src, lhs, rhs, ty);
  30398     return overflow_result.wrapped_result;
  30399 }
  30400 
  30401 fn intSub(
  30402     sema: *Sema,
  30403     block: *Block,
  30404     src: LazySrcLoc,
  30405     lhs: Value,
  30406     rhs: Value,
  30407     ty: Type,
  30408 ) !Value {
  30409     if (ty.zigTypeTag() == .Vector) {
  30410         const result_data = try sema.arena.alloc(Value, ty.vectorLen());
  30411         for (result_data) |*scalar, i| {
  30412             scalar.* = try sema.intSubScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i));
  30413         }
  30414         return Value.Tag.aggregate.create(sema.arena, result_data);
  30415     }
  30416     return sema.intSubScalar(block, src, lhs, rhs);
  30417 }
  30418 
  30419 fn intSubScalar(sema: *Sema, block: *Block, src: LazySrcLoc, lhs: Value, rhs: Value) !Value {
  30420     // TODO is this a performance issue? maybe we should try the operation without
  30421     // resorting to BigInt first.
  30422     var lhs_space: Value.BigIntSpace = undefined;
  30423     var rhs_space: Value.BigIntSpace = undefined;
  30424     const target = sema.mod.getTarget();
  30425     const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, src));
  30426     const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, src));
  30427     const limbs = try sema.arena.alloc(
  30428         std.math.big.Limb,
  30429         std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
  30430     );
  30431     var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
  30432     result_bigint.sub(lhs_bigint, rhs_bigint);
  30433     return Value.fromBigInt(sema.arena, result_bigint.toConst());
  30434 }
  30435 
  30436 /// Supports both (vectors of) floats and ints; handles undefined scalars.
  30437 fn numberSubWrap(
  30438     sema: *Sema,
  30439     block: *Block,
  30440     src: LazySrcLoc,
  30441     lhs: Value,
  30442     rhs: Value,
  30443     ty: Type,
  30444 ) !Value {
  30445     if (ty.zigTypeTag() == .Vector) {
  30446         const result_data = try sema.arena.alloc(Value, ty.vectorLen());
  30447         for (result_data) |*scalar, i| {
  30448             scalar.* = try sema.numberSubWrapScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType());
  30449         }
  30450         return Value.Tag.aggregate.create(sema.arena, result_data);
  30451     }
  30452     return sema.numberSubWrapScalar(block, src, lhs, rhs, ty);
  30453 }
  30454 
  30455 /// Supports both floats and ints; handles undefined.
  30456 fn numberSubWrapScalar(
  30457     sema: *Sema,
  30458     block: *Block,
  30459     src: LazySrcLoc,
  30460     lhs: Value,
  30461     rhs: Value,
  30462     ty: Type,
  30463 ) !Value {
  30464     if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
  30465 
  30466     if (ty.zigTypeTag() == .ComptimeInt) {
  30467         return sema.intSub(block, src, lhs, rhs, ty);
  30468     }
  30469 
  30470     if (ty.isAnyFloat()) {
  30471         return sema.floatSub(lhs, rhs, ty);
  30472     }
  30473 
  30474     const overflow_result = try sema.intSubWithOverflow(block, src, lhs, rhs, ty);
  30475     return overflow_result.wrapped_result;
  30476 }
  30477 
  30478 fn floatAdd(
  30479     sema: *Sema,
  30480     lhs: Value,
  30481     rhs: Value,
  30482     float_type: Type,
  30483 ) !Value {
  30484     if (float_type.zigTypeTag() == .Vector) {
  30485         const result_data = try sema.arena.alloc(Value, float_type.vectorLen());
  30486         for (result_data) |*scalar, i| {
  30487             scalar.* = try sema.floatAddScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType());
  30488         }
  30489         return Value.Tag.aggregate.create(sema.arena, result_data);
  30490     }
  30491     return sema.floatAddScalar(lhs, rhs, float_type);
  30492 }
  30493 
  30494 fn floatAddScalar(
  30495     sema: *Sema,
  30496     lhs: Value,
  30497     rhs: Value,
  30498     float_type: Type,
  30499 ) !Value {
  30500     const target = sema.mod.getTarget();
  30501     switch (float_type.floatBits(target)) {
  30502         16 => {
  30503             const lhs_val = lhs.toFloat(f16);
  30504             const rhs_val = rhs.toFloat(f16);
  30505             return Value.Tag.float_16.create(sema.arena, lhs_val + rhs_val);
  30506         },
  30507         32 => {
  30508             const lhs_val = lhs.toFloat(f32);
  30509             const rhs_val = rhs.toFloat(f32);
  30510             return Value.Tag.float_32.create(sema.arena, lhs_val + rhs_val);
  30511         },
  30512         64 => {
  30513             const lhs_val = lhs.toFloat(f64);
  30514             const rhs_val = rhs.toFloat(f64);
  30515             return Value.Tag.float_64.create(sema.arena, lhs_val + rhs_val);
  30516         },
  30517         80 => {
  30518             const lhs_val = lhs.toFloat(f80);
  30519             const rhs_val = rhs.toFloat(f80);
  30520             return Value.Tag.float_80.create(sema.arena, lhs_val + rhs_val);
  30521         },
  30522         128 => {
  30523             const lhs_val = lhs.toFloat(f128);
  30524             const rhs_val = rhs.toFloat(f128);
  30525             return Value.Tag.float_128.create(sema.arena, lhs_val + rhs_val);
  30526         },
  30527         else => unreachable,
  30528     }
  30529 }
  30530 
  30531 fn floatSub(
  30532     sema: *Sema,
  30533     lhs: Value,
  30534     rhs: Value,
  30535     float_type: Type,
  30536 ) !Value {
  30537     if (float_type.zigTypeTag() == .Vector) {
  30538         const result_data = try sema.arena.alloc(Value, float_type.vectorLen());
  30539         for (result_data) |*scalar, i| {
  30540             scalar.* = try sema.floatSubScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType());
  30541         }
  30542         return Value.Tag.aggregate.create(sema.arena, result_data);
  30543     }
  30544     return sema.floatSubScalar(lhs, rhs, float_type);
  30545 }
  30546 
  30547 fn floatSubScalar(
  30548     sema: *Sema,
  30549     lhs: Value,
  30550     rhs: Value,
  30551     float_type: Type,
  30552 ) !Value {
  30553     const target = sema.mod.getTarget();
  30554     switch (float_type.floatBits(target)) {
  30555         16 => {
  30556             const lhs_val = lhs.toFloat(f16);
  30557             const rhs_val = rhs.toFloat(f16);
  30558             return Value.Tag.float_16.create(sema.arena, lhs_val - rhs_val);
  30559         },
  30560         32 => {
  30561             const lhs_val = lhs.toFloat(f32);
  30562             const rhs_val = rhs.toFloat(f32);
  30563             return Value.Tag.float_32.create(sema.arena, lhs_val - rhs_val);
  30564         },
  30565         64 => {
  30566             const lhs_val = lhs.toFloat(f64);
  30567             const rhs_val = rhs.toFloat(f64);
  30568             return Value.Tag.float_64.create(sema.arena, lhs_val - rhs_val);
  30569         },
  30570         80 => {
  30571             const lhs_val = lhs.toFloat(f80);
  30572             const rhs_val = rhs.toFloat(f80);
  30573             return Value.Tag.float_80.create(sema.arena, lhs_val - rhs_val);
  30574         },
  30575         128 => {
  30576             const lhs_val = lhs.toFloat(f128);
  30577             const rhs_val = rhs.toFloat(f128);
  30578             return Value.Tag.float_128.create(sema.arena, lhs_val - rhs_val);
  30579         },
  30580         else => unreachable,
  30581     }
  30582 }
  30583 
  30584 fn intSubWithOverflow(
  30585     sema: *Sema,
  30586     block: *Block,
  30587     src: LazySrcLoc,
  30588     lhs: Value,
  30589     rhs: Value,
  30590     ty: Type,
  30591 ) !Value.OverflowArithmeticResult {
  30592     if (ty.zigTypeTag() == .Vector) {
  30593         const overflowed_data = try sema.arena.alloc(Value, ty.vectorLen());
  30594         const result_data = try sema.arena.alloc(Value, ty.vectorLen());
  30595         for (result_data) |*scalar, i| {
  30596             const of_math_result = try sema.intSubWithOverflowScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType());
  30597             overflowed_data[i] = of_math_result.overflowed;
  30598             scalar.* = of_math_result.wrapped_result;
  30599         }
  30600         return Value.OverflowArithmeticResult{
  30601             .overflowed = try Value.Tag.aggregate.create(sema.arena, overflowed_data),
  30602             .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data),
  30603         };
  30604     }
  30605     return sema.intSubWithOverflowScalar(block, src, lhs, rhs, ty);
  30606 }
  30607 
  30608 fn intSubWithOverflowScalar(
  30609     sema: *Sema,
  30610     block: *Block,
  30611     src: LazySrcLoc,
  30612     lhs: Value,
  30613     rhs: Value,
  30614     ty: Type,
  30615 ) !Value.OverflowArithmeticResult {
  30616     const target = sema.mod.getTarget();
  30617     const info = ty.intInfo(target);
  30618 
  30619     var lhs_space: Value.BigIntSpace = undefined;
  30620     var rhs_space: Value.BigIntSpace = undefined;
  30621     const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, src));
  30622     const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, src));
  30623     const limbs = try sema.arena.alloc(
  30624         std.math.big.Limb,
  30625         std.math.big.int.calcTwosCompLimbCount(info.bits),
  30626     );
  30627     var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
  30628     const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
  30629     const wrapped_result = try Value.fromBigInt(sema.arena, result_bigint.toConst());
  30630     return Value.OverflowArithmeticResult{
  30631         .overflowed = Value.makeBool(overflowed),
  30632         .wrapped_result = wrapped_result,
  30633     };
  30634 }
  30635 
  30636 fn floatToInt(
  30637     sema: *Sema,
  30638     block: *Block,
  30639     src: LazySrcLoc,
  30640     val: Value,
  30641     float_ty: Type,
  30642     int_ty: Type,
  30643 ) CompileError!Value {
  30644     if (float_ty.zigTypeTag() == .Vector) {
  30645         const elem_ty = float_ty.childType();
  30646         const result_data = try sema.arena.alloc(Value, float_ty.vectorLen());
  30647         for (result_data) |*scalar, i| {
  30648             scalar.* = try sema.floatToIntScalar(block, src, val.indexVectorlike(i), elem_ty, int_ty.scalarType());
  30649         }
  30650         return Value.Tag.aggregate.create(sema.arena, result_data);
  30651     }
  30652     return sema.floatToIntScalar(block, src, val, float_ty, int_ty);
  30653 }
  30654 
  30655 fn floatToIntScalar(
  30656     sema: *Sema,
  30657     block: *Block,
  30658     src: LazySrcLoc,
  30659     val: Value,
  30660     float_ty: Type,
  30661     int_ty: Type,
  30662 ) CompileError!Value {
  30663     const Limb = std.math.big.Limb;
  30664 
  30665     const float = val.toFloat(f128);
  30666     if (std.math.isNan(float)) {
  30667         return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{
  30668             int_ty.fmt(sema.mod),
  30669         });
  30670     }
  30671     if (std.math.isInf(float)) {
  30672         return sema.fail(block, src, "float value Inf cannot be stored in integer type '{}'", .{
  30673             int_ty.fmt(sema.mod),
  30674         });
  30675     }
  30676 
  30677     const is_negative = std.math.signbit(float);
  30678     const floored = @floor(@fabs(float));
  30679 
  30680     var rational = try std.math.big.Rational.init(sema.arena);
  30681     defer rational.deinit();
  30682     rational.setFloat(f128, floored) catch |err| switch (err) {
  30683         error.NonFiniteFloat => unreachable,
  30684         error.OutOfMemory => return error.OutOfMemory,
  30685     };
  30686 
  30687     // The float is reduced in rational.setFloat, so we assert that denominator is equal to one
  30688     const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true };
  30689     assert(rational.q.toConst().eqAbs(big_one));
  30690 
  30691     const result_limbs = try sema.arena.dupe(Limb, rational.p.toConst().limbs);
  30692     const result = if (is_negative)
  30693         try Value.Tag.int_big_negative.create(sema.arena, result_limbs)
  30694     else
  30695         try Value.Tag.int_big_positive.create(sema.arena, result_limbs);
  30696 
  30697     if (!(try sema.intFitsInType(block, src, result, int_ty, null))) {
  30698         return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{
  30699             val.fmtValue(float_ty, sema.mod), int_ty.fmt(sema.mod),
  30700         });
  30701     }
  30702     return result;
  30703 }
  30704 
  30705 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
  30706 /// Vectors are also accepted. Vector results are reduced with AND.
  30707 fn intFitsInType(
  30708     sema: *Sema,
  30709     block: *Block,
  30710     src: LazySrcLoc,
  30711     val: Value,
  30712     ty: Type,
  30713     vector_index: ?*usize,
  30714 ) CompileError!bool {
  30715     const target = sema.mod.getTarget();
  30716     switch (val.tag()) {
  30717         .zero,
  30718         .undef,
  30719         .bool_false,
  30720         => return true,
  30721 
  30722         .one,
  30723         .bool_true,
  30724         => switch (ty.zigTypeTag()) {
  30725             .Int => {
  30726                 const info = ty.intInfo(target);
  30727                 return switch (info.signedness) {
  30728                     .signed => info.bits >= 2,
  30729                     .unsigned => info.bits >= 1,
  30730                 };
  30731             },
  30732             .ComptimeInt => return true,
  30733             else => unreachable,
  30734         },
  30735 
  30736         .lazy_align => switch (ty.zigTypeTag()) {
  30737             .Int => {
  30738                 const info = ty.intInfo(target);
  30739                 const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed);
  30740                 // If it is u16 or bigger we know the alignment fits without resolving it.
  30741                 if (info.bits >= max_needed_bits) return true;
  30742                 const x = try sema.typeAbiAlignment(block, src, val.castTag(.lazy_align).?.data);
  30743                 if (x == 0) return true;
  30744                 const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
  30745                 return info.bits >= actual_needed_bits;
  30746             },
  30747             .ComptimeInt => return true,
  30748             else => unreachable,
  30749         },
  30750         .lazy_size => switch (ty.zigTypeTag()) {
  30751             .Int => {
  30752                 const info = ty.intInfo(target);
  30753                 const max_needed_bits = @as(u16, 64) + @boolToInt(info.signedness == .signed);
  30754                 // If it is u64 or bigger we know the size fits without resolving it.
  30755                 if (info.bits >= max_needed_bits) return true;
  30756                 const x = try sema.typeAbiSize(block, src, val.castTag(.lazy_size).?.data);
  30757                 if (x == 0) return true;
  30758                 const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
  30759                 return info.bits >= actual_needed_bits;
  30760             },
  30761             .ComptimeInt => return true,
  30762             else => unreachable,
  30763         },
  30764 
  30765         .int_u64 => switch (ty.zigTypeTag()) {
  30766             .Int => {
  30767                 const x = val.castTag(.int_u64).?.data;
  30768                 if (x == 0) return true;
  30769                 const info = ty.intInfo(target);
  30770                 const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
  30771                 return info.bits >= needed_bits;
  30772             },
  30773             .ComptimeInt => return true,
  30774             else => unreachable,
  30775         },
  30776         .int_i64 => switch (ty.zigTypeTag()) {
  30777             .Int => {
  30778                 const x = val.castTag(.int_i64).?.data;
  30779                 if (x == 0) return true;
  30780                 const info = ty.intInfo(target);
  30781                 if (info.signedness == .unsigned and x < 0)
  30782                     return false;
  30783                 var buffer: Value.BigIntSpace = undefined;
  30784                 return (try val.toBigIntAdvanced(&buffer, target, sema.kit(block, src))).fitsInTwosComp(info.signedness, info.bits);
  30785             },
  30786             .ComptimeInt => return true,
  30787             else => unreachable,
  30788         },
  30789         .int_big_positive => switch (ty.zigTypeTag()) {
  30790             .Int => {
  30791                 const info = ty.intInfo(target);
  30792                 return val.castTag(.int_big_positive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
  30793             },
  30794             .ComptimeInt => return true,
  30795             else => unreachable,
  30796         },
  30797         .int_big_negative => switch (ty.zigTypeTag()) {
  30798             .Int => {
  30799                 const info = ty.intInfo(target);
  30800                 return val.castTag(.int_big_negative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
  30801             },
  30802             .ComptimeInt => return true,
  30803             else => unreachable,
  30804         },
  30805 
  30806         .the_only_possible_value => {
  30807             assert(ty.intInfo(target).bits == 0);
  30808             return true;
  30809         },
  30810 
  30811         .decl_ref_mut,
  30812         .extern_fn,
  30813         .decl_ref,
  30814         .function,
  30815         .variable,
  30816         => switch (ty.zigTypeTag()) {
  30817             .Int => {
  30818                 const info = ty.intInfo(target);
  30819                 const ptr_bits = target.cpu.arch.ptrBitWidth();
  30820                 return switch (info.signedness) {
  30821                     .signed => info.bits > ptr_bits,
  30822                     .unsigned => info.bits >= ptr_bits,
  30823                 };
  30824             },
  30825             .ComptimeInt => return true,
  30826             else => unreachable,
  30827         },
  30828 
  30829         .aggregate => {
  30830             assert(ty.zigTypeTag() == .Vector);
  30831             for (val.castTag(.aggregate).?.data) |elem, i| {
  30832                 if (!(try sema.intFitsInType(block, src, elem, ty.scalarType(), null))) {
  30833                     if (vector_index) |some| some.* = i;
  30834                     return false;
  30835                 }
  30836             }
  30837             return true;
  30838         },
  30839 
  30840         else => unreachable,
  30841     }
  30842 }
  30843 
  30844 fn intInRange(
  30845     sema: *Sema,
  30846     block: *Block,
  30847     src: LazySrcLoc,
  30848     tag_ty: Type,
  30849     int_val: Value,
  30850     end: usize,
  30851 ) !bool {
  30852     if (try int_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) return false;
  30853     var end_payload: Value.Payload.U64 = .{
  30854         .base = .{ .tag = .int_u64 },
  30855         .data = end,
  30856     };
  30857     const end_val = Value.initPayload(&end_payload.base);
  30858     if (try sema.compare(block, src, int_val, .gte, end_val, tag_ty)) return false;
  30859     return true;
  30860 }
  30861 
  30862 /// Asserts the type is an enum.
  30863 fn enumHasInt(
  30864     sema: *Sema,
  30865     block: *Block,
  30866     src: LazySrcLoc,
  30867     ty: Type,
  30868     int: Value,
  30869 ) CompileError!bool {
  30870     switch (ty.tag()) {
  30871         .enum_nonexhaustive => return sema.intFitsInType(block, src, int, ty, null),
  30872         .enum_full => {
  30873             const enum_full = ty.castTag(.enum_full).?.data;
  30874             const tag_ty = enum_full.tag_ty;
  30875             if (enum_full.values.count() == 0) {
  30876                 return intInRange(sema, block, src, tag_ty, int, enum_full.fields.count());
  30877             } else {
  30878                 return enum_full.values.containsContext(int, .{
  30879                     .ty = tag_ty,
  30880                     .mod = sema.mod,
  30881                 });
  30882             }
  30883         },
  30884         .enum_numbered => {
  30885             const enum_obj = ty.castTag(.enum_numbered).?.data;
  30886             const tag_ty = enum_obj.tag_ty;
  30887             if (enum_obj.values.count() == 0) {
  30888                 return intInRange(sema, block, src, tag_ty, int, enum_obj.fields.count());
  30889             } else {
  30890                 return enum_obj.values.containsContext(int, .{
  30891                     .ty = tag_ty,
  30892                     .mod = sema.mod,
  30893                 });
  30894             }
  30895         },
  30896         .enum_simple => {
  30897             const enum_simple = ty.castTag(.enum_simple).?.data;
  30898             const fields_len = enum_simple.fields.count();
  30899             const bits = std.math.log2_int_ceil(usize, fields_len);
  30900             var buffer: Type.Payload.Bits = .{
  30901                 .base = .{ .tag = .int_unsigned },
  30902                 .data = bits,
  30903             };
  30904             const tag_ty = Type.initPayload(&buffer.base);
  30905             return intInRange(sema, block, src, tag_ty, int, fields_len);
  30906         },
  30907         .atomic_order,
  30908         .atomic_rmw_op,
  30909         .calling_convention,
  30910         .address_space,
  30911         .float_mode,
  30912         .reduce_op,
  30913         .call_options,
  30914         .prefetch_options,
  30915         .export_options,
  30916         .extern_options,
  30917         => unreachable,
  30918 
  30919         else => unreachable,
  30920     }
  30921 }
  30922 
  30923 fn intAddWithOverflow(
  30924     sema: *Sema,
  30925     block: *Block,
  30926     src: LazySrcLoc,
  30927     lhs: Value,
  30928     rhs: Value,
  30929     ty: Type,
  30930 ) !Value.OverflowArithmeticResult {
  30931     if (ty.zigTypeTag() == .Vector) {
  30932         const overflowed_data = try sema.arena.alloc(Value, ty.vectorLen());
  30933         const result_data = try sema.arena.alloc(Value, ty.vectorLen());
  30934         for (result_data) |*scalar, i| {
  30935             const of_math_result = try sema.intAddWithOverflowScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType());
  30936             overflowed_data[i] = of_math_result.overflowed;
  30937             scalar.* = of_math_result.wrapped_result;
  30938         }
  30939         return Value.OverflowArithmeticResult{
  30940             .overflowed = try Value.Tag.aggregate.create(sema.arena, overflowed_data),
  30941             .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data),
  30942         };
  30943     }
  30944     return sema.intAddWithOverflowScalar(block, src, lhs, rhs, ty);
  30945 }
  30946 
  30947 fn intAddWithOverflowScalar(
  30948     sema: *Sema,
  30949     block: *Block,
  30950     src: LazySrcLoc,
  30951     lhs: Value,
  30952     rhs: Value,
  30953     ty: Type,
  30954 ) !Value.OverflowArithmeticResult {
  30955     const target = sema.mod.getTarget();
  30956     const info = ty.intInfo(target);
  30957 
  30958     var lhs_space: Value.BigIntSpace = undefined;
  30959     var rhs_space: Value.BigIntSpace = undefined;
  30960     const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, src));
  30961     const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, src));
  30962     const limbs = try sema.arena.alloc(
  30963         std.math.big.Limb,
  30964         std.math.big.int.calcTwosCompLimbCount(info.bits),
  30965     );
  30966     var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
  30967     const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
  30968     const result = try Value.fromBigInt(sema.arena, result_bigint.toConst());
  30969     return Value.OverflowArithmeticResult{
  30970         .overflowed = Value.makeBool(overflowed),
  30971         .wrapped_result = result,
  30972     };
  30973 }
  30974 
  30975 /// Asserts the values are comparable. Both operands have type `ty`.
  30976 /// Vector results will be reduced with AND.
  30977 fn compare(
  30978     sema: *Sema,
  30979     block: *Block,
  30980     src: LazySrcLoc,
  30981     lhs: Value,
  30982     op: std.math.CompareOperator,
  30983     rhs: Value,
  30984     ty: Type,
  30985 ) CompileError!bool {
  30986     if (ty.zigTypeTag() == .Vector) {
  30987         var i: usize = 0;
  30988         while (i < ty.vectorLen()) : (i += 1) {
  30989             if (!(try sema.compareScalar(block, src, lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType()))) {
  30990                 return false;
  30991             }
  30992         }
  30993         return true;
  30994     }
  30995     return sema.compareScalar(block, src, lhs, op, rhs, ty);
  30996 }
  30997 
  30998 /// Asserts the values are comparable. Both operands have type `ty`.
  30999 fn compareScalar(
  31000     sema: *Sema,
  31001     block: *Block,
  31002     src: LazySrcLoc,
  31003     lhs: Value,
  31004     op: std.math.CompareOperator,
  31005     rhs: Value,
  31006     ty: Type,
  31007 ) CompileError!bool {
  31008     switch (op) {
  31009         .eq => return sema.valuesEqual(block, src, lhs, rhs, ty),
  31010         .neq => return !(try sema.valuesEqual(block, src, lhs, rhs, ty)),
  31011         else => return Value.compareHeteroAdvanced(lhs, op, rhs, sema.mod.getTarget(), sema.kit(block, src)),
  31012     }
  31013 }
  31014 
  31015 fn valuesEqual(
  31016     sema: *Sema,
  31017     block: *Block,
  31018     src: LazySrcLoc,
  31019     lhs: Value,
  31020     rhs: Value,
  31021     ty: Type,
  31022 ) CompileError!bool {
  31023     return Value.eqlAdvanced(lhs, ty, rhs, ty, sema.mod, sema.kit(block, src));
  31024 }
  31025 
  31026 /// Asserts the values are comparable vectors of type `ty`.
  31027 fn compareVector(
  31028     sema: *Sema,
  31029     block: *Block,
  31030     src: LazySrcLoc,
  31031     lhs: Value,
  31032     op: std.math.CompareOperator,
  31033     rhs: Value,
  31034     ty: Type,
  31035 ) !Value {
  31036     assert(ty.zigTypeTag() == .Vector);
  31037     const result_data = try sema.arena.alloc(Value, ty.vectorLen());
  31038     for (result_data) |*scalar, i| {
  31039         const res_bool = try sema.compareScalar(block, src, lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType());
  31040         scalar.* = Value.makeBool(res_bool);
  31041     }
  31042     return Value.Tag.aggregate.create(sema.arena, result_data);
  31043 }
  31044 
  31045 /// Returns the type of a pointer to an element.
  31046 /// Asserts that the type is a pointer, and that the element type is indexable.
  31047 /// For *[N]T, return *T
  31048 /// For [*]T, returns *T
  31049 /// For []T, returns *T
  31050 /// Handles const-ness and address spaces in particular.
  31051 /// This code is duplicated in `analyzePtrArithmetic`.
  31052 fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
  31053     const ptr_info = ptr_ty.ptrInfo().data;
  31054     const elem_ty = ptr_ty.elemType2();
  31055     const allow_zero = ptr_info.@"allowzero" and (offset orelse 0) == 0;
  31056     const alignment: u32 = a: {
  31057         // Calculate the new pointer alignment.
  31058         if (ptr_info.@"align" == 0) {
  31059             // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness.
  31060             break :a 0;
  31061         }
  31062         // If the addend is not a comptime-known value we can still count on
  31063         // it being a multiple of the type size.
  31064         const target = sema.mod.getTarget();
  31065         const elem_size = elem_ty.abiSize(target);
  31066         const addend = if (offset) |off| elem_size * off else elem_size;
  31067 
  31068         // The resulting pointer is aligned to the lcd between the offset (an
  31069         // arbitrary number) and the alignment factor (always a power of two,
  31070         // non zero).
  31071         const new_align = @as(u32, 1) << @intCast(u5, @ctz(addend | ptr_info.@"align"));
  31072         break :a new_align;
  31073     };
  31074     return try Type.ptr(sema.arena, sema.mod, .{
  31075         .pointee_type = elem_ty,
  31076         .mutable = ptr_info.mutable,
  31077         .@"addrspace" = ptr_info.@"addrspace",
  31078         .@"allowzero" = allow_zero,
  31079         .@"volatile" = ptr_info.@"volatile",
  31080         .@"align" = alignment,
  31081     });
  31082 }