zig

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

blob 385ea7e9 (1487359B) - 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 /// Maps ZIR to AIR.
     21 inst_map: InstMap = .{},
     22 /// When analyzing an inline function call, owner_decl is the Decl of the caller
     23 /// and `src_decl` of `Block` is the `Decl` of the callee.
     24 /// This `Decl` owns the arena memory of this `Sema`.
     25 owner_decl: *Decl,
     26 owner_decl_index: Decl.Index,
     27 /// For an inline or comptime function call, this will be the root parent function
     28 /// which contains the callsite. Corresponds to `owner_decl`.
     29 owner_func: ?*Module.Fn,
     30 owner_func_index: Module.Fn.OptionalIndex,
     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 func_index: Module.Fn.OptionalIndex,
     36 /// Used to restore the error return trace when returning a non-error from a function.
     37 error_return_trace_index_on_fn_entry: Air.Inst.Ref = .none,
     38 /// When semantic analysis needs to know the return type of the function whose body
     39 /// is being analyzed, this `Type` should be used instead of going through `func`.
     40 /// This will correctly handle the case of a comptime/inline function call of a
     41 /// generic function which uses a type expression for the return type.
     42 /// The type will be `void` in the case that `func` is `null`.
     43 fn_ret_ty: Type,
     44 branch_quota: u32 = default_branch_quota,
     45 branch_count: u32 = 0,
     46 /// Populated when returning `error.ComptimeBreak`. Used to communicate the
     47 /// break instruction up the stack to find the corresponding Block.
     48 comptime_break_inst: Zir.Inst.Index = undefined,
     49 /// This field is updated when a new source location becomes active, so that
     50 /// instructions which do not have explicitly mapped source locations still have
     51 /// access to the source location set by the previous instruction which did
     52 /// contain a mapped source location.
     53 src: LazySrcLoc = .{ .token_offset = 0 },
     54 decl_val_table: std.AutoHashMapUnmanaged(Decl.Index, Air.Inst.Ref) = .{},
     55 /// When doing a generic function instantiation, this array collects a
     56 /// `Value` object for each parameter that is comptime-known and thus elided
     57 /// from the generated function. This memory is allocated by a parent `Sema` and
     58 /// owned by the values arena of the Sema owner_decl.
     59 comptime_args: []TypedValue = &.{},
     60 /// Marks the function instruction that `comptime_args` applies to so that we
     61 /// don't accidentally apply it to a function prototype which is used in the
     62 /// type expression of a generic function parameter.
     63 comptime_args_fn_inst: Zir.Inst.Index = 0,
     64 /// When `comptime_args` is provided, this field is also provided. It was used as
     65 /// the key in the `monomorphed_funcs` set. The `func` instruction is supposed
     66 /// to use this instead of allocating a fresh one. This avoids an unnecessary
     67 /// extra hash table lookup in the `monomorphed_funcs` set.
     68 /// Sema will set this to null when it takes ownership.
     69 preallocated_new_func: Module.Fn.OptionalIndex = .none,
     70 /// The key is types that must be fully resolved prior to machine code
     71 /// generation pass. Types are added to this set when resolving them
     72 /// immediately could cause a dependency loop, but they do need to be resolved
     73 /// before machine code generation passes process the AIR.
     74 /// It would work fine if this were an array list instead of an array hash map.
     75 /// I chose array hash map with the intention to save time by omitting
     76 /// duplicates.
     77 types_to_resolve: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{},
     78 /// These are lazily created runtime blocks from block_inline instructions.
     79 /// They are created when an break_inline passes through a runtime condition, because
     80 /// Sema must convert comptime control flow to runtime control flow, which means
     81 /// breaking from a block.
     82 post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},
     83 /// Populated with the last compile error created.
     84 err: ?*Module.ErrorMsg = null,
     85 /// True when analyzing a generic instantiation. Used to suppress some errors.
     86 is_generic_instantiation: bool = false,
     87 /// Set to true when analyzing a func type instruction so that nested generic
     88 /// function types will emit generic poison instead of a partial type.
     89 no_partial_func_ty: bool = false,
     90 
     91 /// The temporary arena is used for the memory of the `InferredAlloc` values
     92 /// here so the values can be dropped without any cleanup.
     93 unresolved_inferred_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, InferredAlloc) = .{},
     94 
     95 const std = @import("std");
     96 const math = std.math;
     97 const mem = std.mem;
     98 const Allocator = mem.Allocator;
     99 const assert = std.debug.assert;
    100 const log = std.log.scoped(.sema);
    101 
    102 const Sema = @This();
    103 const Value = @import("value.zig").Value;
    104 const Type = @import("type.zig").Type;
    105 const TypedValue = @import("TypedValue.zig");
    106 const Air = @import("Air.zig");
    107 const Zir = @import("Zir.zig");
    108 const Module = @import("Module.zig");
    109 const trace = @import("tracy.zig").trace;
    110 const Namespace = Module.Namespace;
    111 const CompileError = Module.CompileError;
    112 const SemaError = Module.SemaError;
    113 const Decl = Module.Decl;
    114 const CaptureScope = Module.CaptureScope;
    115 const WipCaptureScope = Module.WipCaptureScope;
    116 const LazySrcLoc = Module.LazySrcLoc;
    117 const RangeSet = @import("RangeSet.zig");
    118 const target_util = @import("target.zig");
    119 const Package = @import("Package.zig");
    120 const crash_report = @import("crash_report.zig");
    121 const build_options = @import("build_options");
    122 const Compilation = @import("Compilation.zig");
    123 const InternPool = @import("InternPool.zig");
    124 
    125 pub const default_branch_quota = 1000;
    126 pub const default_reference_trace_len = 2;
    127 
    128 /// Stores the mapping from `Zir.Inst.Index -> Air.Inst.Ref`, which is used by sema to resolve
    129 /// instructions during analysis.
    130 /// Instead of a hash table approach, InstMap is simply a slice that is indexed into using the
    131 /// zir instruction index and a start offset. An index is not pressent in the map if the value
    132 /// at the index is `Air.Inst.Ref.none`.
    133 /// `ensureSpaceForInstructions` can be called to force InstMap to have a mapped range that
    134 /// includes all instructions in a slice. After calling this function, `putAssumeCapacity*` can
    135 /// be called safely for any of the instructions passed in.
    136 pub const InstMap = struct {
    137     items: []Air.Inst.Ref = &[_]Air.Inst.Ref{},
    138     start: Zir.Inst.Index = 0,
    139 
    140     pub fn deinit(map: InstMap, allocator: mem.Allocator) void {
    141         allocator.free(map.items);
    142     }
    143 
    144     pub fn get(map: InstMap, key: Zir.Inst.Index) ?Air.Inst.Ref {
    145         if (!map.contains(key)) return null;
    146         return map.items[key - map.start];
    147     }
    148 
    149     pub fn putAssumeCapacity(
    150         map: *InstMap,
    151         key: Zir.Inst.Index,
    152         ref: Air.Inst.Ref,
    153     ) void {
    154         map.items[key - map.start] = ref;
    155     }
    156 
    157     pub fn putAssumeCapacityNoClobber(
    158         map: *InstMap,
    159         key: Zir.Inst.Index,
    160         ref: Air.Inst.Ref,
    161     ) void {
    162         assert(!map.contains(key));
    163         map.putAssumeCapacity(key, ref);
    164     }
    165 
    166     pub const GetOrPutResult = struct {
    167         value_ptr: *Air.Inst.Ref,
    168         found_existing: bool,
    169     };
    170 
    171     pub fn getOrPutAssumeCapacity(
    172         map: *InstMap,
    173         key: Zir.Inst.Index,
    174     ) GetOrPutResult {
    175         const index = key - map.start;
    176         return GetOrPutResult{
    177             .value_ptr = &map.items[index],
    178             .found_existing = map.items[index] != .none,
    179         };
    180     }
    181 
    182     pub fn remove(map: InstMap, key: Zir.Inst.Index) bool {
    183         if (!map.contains(key)) return false;
    184         map.items[key - map.start] = .none;
    185         return true;
    186     }
    187 
    188     pub fn contains(map: InstMap, key: Zir.Inst.Index) bool {
    189         return map.items[key - map.start] != .none;
    190     }
    191 
    192     pub fn ensureSpaceForInstructions(
    193         map: *InstMap,
    194         allocator: mem.Allocator,
    195         insts: []const Zir.Inst.Index,
    196     ) !void {
    197         const min_max = mem.minMax(Zir.Inst.Index, insts);
    198         const start = min_max.min;
    199         const end = min_max.max;
    200         if (map.start <= start and end < map.items.len + map.start)
    201             return;
    202 
    203         const old_start = if (map.items.len == 0) start else map.start;
    204         var better_capacity = map.items.len;
    205         var better_start = old_start;
    206         while (true) {
    207             const extra_capacity = better_capacity / 2 + 16;
    208             better_capacity += extra_capacity;
    209             better_start -|= @intCast(Zir.Inst.Index, extra_capacity / 2);
    210             if (better_start <= start and end < better_capacity + better_start)
    211                 break;
    212         }
    213 
    214         const start_diff = old_start - better_start;
    215         const new_items = try allocator.alloc(Air.Inst.Ref, better_capacity);
    216         @memset(new_items[0..start_diff], .none);
    217         @memcpy(new_items[start_diff..][0..map.items.len], map.items);
    218         @memset(new_items[start_diff + map.items.len ..], .none);
    219 
    220         allocator.free(map.items);
    221         map.items = new_items;
    222         map.start = @intCast(Zir.Inst.Index, better_start);
    223     }
    224 };
    225 
    226 /// This is the context needed to semantically analyze ZIR instructions and
    227 /// produce AIR instructions.
    228 /// This is a temporary structure stored on the stack; references to it are valid only
    229 /// during semantic analysis of the block.
    230 pub const Block = struct {
    231     parent: ?*Block,
    232     /// Shared among all child blocks.
    233     sema: *Sema,
    234     /// The namespace to use for lookups from this source block
    235     /// When analyzing fields, this is different from src_decl.src_namespace.
    236     namespace: Namespace.Index,
    237     /// The AIR instructions generated for this block.
    238     instructions: std.ArrayListUnmanaged(Air.Inst.Index),
    239     // `param` instructions are collected here to be used by the `func` instruction.
    240     params: std.ArrayListUnmanaged(Param) = .{},
    241 
    242     wip_capture_scope: *CaptureScope,
    243 
    244     label: ?*Label = null,
    245     inlining: ?*Inlining,
    246     /// If runtime_index is not 0 then one of these is guaranteed to be non null.
    247     runtime_cond: ?LazySrcLoc = null,
    248     runtime_loop: ?LazySrcLoc = null,
    249     /// This Decl is the Decl according to the Zig source code corresponding to this Block.
    250     /// This can vary during inline or comptime function calls. See `Sema.owner_decl`
    251     /// for the one that will be the same for all Block instances.
    252     src_decl: Decl.Index,
    253     /// Non zero if a non-inline loop or a runtime conditional have been encountered.
    254     /// Stores to comptime variables are only allowed when var.runtime_index <= runtime_index.
    255     runtime_index: Value.RuntimeIndex = .zero,
    256     inline_block: Zir.Inst.Index = 0,
    257 
    258     comptime_reason: ?*const ComptimeReason = null,
    259     // TODO is_comptime and comptime_reason should probably be merged together.
    260     is_comptime: bool,
    261     is_typeof: bool = false,
    262 
    263     /// Keep track of the active error return trace index around blocks so that we can correctly
    264     /// pop the error trace upon block exit.
    265     error_return_trace_index: Air.Inst.Ref = .none,
    266 
    267     /// when null, it is determined by build mode, changed by @setRuntimeSafety
    268     want_safety: ?bool = null,
    269 
    270     /// What mode to generate float operations in, set by @setFloatMode
    271     float_mode: std.builtin.FloatMode = .Strict,
    272 
    273     c_import_buf: ?*std.ArrayList(u8) = null,
    274 
    275     /// type of `err` in `else => |err|`
    276     switch_else_err_ty: ?Type = null,
    277 
    278     /// Value for switch_capture in an inline case
    279     inline_case_capture: Air.Inst.Ref = .none,
    280 
    281     const ComptimeReason = union(enum) {
    282         c_import: struct {
    283             block: *Block,
    284             src: LazySrcLoc,
    285         },
    286         comptime_ret_ty: struct {
    287             block: *Block,
    288             func: Air.Inst.Ref,
    289             func_src: LazySrcLoc,
    290             return_ty: Type,
    291         },
    292 
    293         fn explain(cr: ComptimeReason, sema: *Sema, msg: ?*Module.ErrorMsg) !void {
    294             const parent = msg orelse return;
    295             const mod = sema.mod;
    296             const prefix = "expression is evaluated at comptime because ";
    297             switch (cr) {
    298                 .c_import => |ci| {
    299                     try sema.errNote(ci.block, ci.src, parent, prefix ++ "it is inside a @cImport", .{});
    300                 },
    301                 .comptime_ret_ty => |rt| {
    302                     const src_loc = if (try sema.funcDeclSrc(rt.func)) |fn_decl| blk: {
    303                         var src_loc = fn_decl.srcLoc(mod);
    304                         src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 };
    305                         break :blk src_loc;
    306                     } else blk: {
    307                         const src_decl = sema.mod.declPtr(rt.block.src_decl);
    308                         break :blk rt.func_src.toSrcLoc(src_decl, mod);
    309                     };
    310                     if (rt.return_ty.isGenericPoison()) {
    311                         return sema.mod.errNoteNonLazy(src_loc, parent, prefix ++ "the generic function was instantiated with a comptime-only return type", .{});
    312                     }
    313                     try sema.mod.errNoteNonLazy(
    314                         src_loc,
    315                         parent,
    316                         prefix ++ "the function returns a comptime-only type '{}'",
    317                         .{rt.return_ty.fmt(sema.mod)},
    318                     );
    319                     try sema.explainWhyTypeIsComptime(parent, src_loc, rt.return_ty);
    320                 },
    321             }
    322         }
    323     };
    324 
    325     const Param = struct {
    326         /// `noreturn` means `anytype`.
    327         ty: Type,
    328         is_comptime: bool,
    329         name: []const u8,
    330     };
    331 
    332     /// This `Block` maps a block ZIR instruction to the corresponding
    333     /// AIR instruction for break instruction analysis.
    334     pub const Label = struct {
    335         zir_block: Zir.Inst.Index,
    336         merges: Merges,
    337     };
    338 
    339     /// This `Block` indicates that an inline function call is happening
    340     /// and return instructions should be analyzed as a break instruction
    341     /// to this AIR block instruction.
    342     /// It is shared among all the blocks in an inline or comptime called
    343     /// function.
    344     pub const Inlining = struct {
    345         func: ?*Module.Fn,
    346         comptime_result: Air.Inst.Ref,
    347         merges: Merges,
    348     };
    349 
    350     pub const Merges = struct {
    351         block_inst: Air.Inst.Index,
    352         /// Separate array list from break_inst_list so that it can be passed directly
    353         /// to resolvePeerTypes.
    354         results: std.ArrayListUnmanaged(Air.Inst.Ref),
    355         /// Keeps track of the break instructions so that the operand can be replaced
    356         /// if we need to add type coercion at the end of block analysis.
    357         /// Same indexes, capacity, length as `results`.
    358         br_list: std.ArrayListUnmanaged(Air.Inst.Index),
    359         /// Keeps the source location of the rhs operand of the break instruction,
    360         /// to enable more precise compile errors.
    361         /// Same indexes, capacity, length as `results`.
    362         src_locs: std.ArrayListUnmanaged(?LazySrcLoc),
    363 
    364         pub fn deinit(merges: *@This(), allocator: mem.Allocator) void {
    365             merges.results.deinit(allocator);
    366             merges.br_list.deinit(allocator);
    367             merges.src_locs.deinit(allocator);
    368         }
    369     };
    370 
    371     /// For debugging purposes.
    372     pub fn dump(block: *Block, mod: Module) void {
    373         Zir.dumpBlock(mod, block);
    374     }
    375 
    376     pub fn makeSubBlock(parent: *Block) Block {
    377         return .{
    378             .parent = parent,
    379             .sema = parent.sema,
    380             .src_decl = parent.src_decl,
    381             .namespace = parent.namespace,
    382             .instructions = .{},
    383             .wip_capture_scope = parent.wip_capture_scope,
    384             .label = null,
    385             .inlining = parent.inlining,
    386             .is_comptime = parent.is_comptime,
    387             .comptime_reason = parent.comptime_reason,
    388             .is_typeof = parent.is_typeof,
    389             .runtime_cond = parent.runtime_cond,
    390             .runtime_loop = parent.runtime_loop,
    391             .runtime_index = parent.runtime_index,
    392             .want_safety = parent.want_safety,
    393             .float_mode = parent.float_mode,
    394             .c_import_buf = parent.c_import_buf,
    395             .switch_else_err_ty = parent.switch_else_err_ty,
    396             .error_return_trace_index = parent.error_return_trace_index,
    397         };
    398     }
    399 
    400     pub fn wantSafety(block: *const Block) bool {
    401         return block.want_safety orelse switch (block.sema.mod.optimizeMode()) {
    402             .Debug => true,
    403             .ReleaseSafe => true,
    404             .ReleaseFast => false,
    405             .ReleaseSmall => false,
    406         };
    407     }
    408 
    409     pub fn getFileScope(block: *Block, mod: *Module) *Module.File {
    410         return mod.namespacePtr(block.namespace).file_scope;
    411     }
    412 
    413     fn addTy(
    414         block: *Block,
    415         tag: Air.Inst.Tag,
    416         ty: Type,
    417     ) error{OutOfMemory}!Air.Inst.Ref {
    418         return block.addInst(.{
    419             .tag = tag,
    420             .data = .{ .ty = ty },
    421         });
    422     }
    423 
    424     fn addTyOp(
    425         block: *Block,
    426         tag: Air.Inst.Tag,
    427         ty: Type,
    428         operand: Air.Inst.Ref,
    429     ) error{OutOfMemory}!Air.Inst.Ref {
    430         return block.addInst(.{
    431             .tag = tag,
    432             .data = .{ .ty_op = .{
    433                 .ty = try block.sema.addType(ty),
    434                 .operand = operand,
    435             } },
    436         });
    437     }
    438 
    439     fn addBitCast(block: *Block, ty: Type, operand: Air.Inst.Ref) Allocator.Error!Air.Inst.Ref {
    440         return block.addInst(.{
    441             .tag = .bitcast,
    442             .data = .{ .ty_op = .{
    443                 .ty = try block.sema.addType(ty),
    444                 .operand = operand,
    445             } },
    446         });
    447     }
    448 
    449     fn addNoOp(block: *Block, tag: Air.Inst.Tag) error{OutOfMemory}!Air.Inst.Ref {
    450         return block.addInst(.{
    451             .tag = tag,
    452             .data = .{ .no_op = {} },
    453         });
    454     }
    455 
    456     fn addUnOp(
    457         block: *Block,
    458         tag: Air.Inst.Tag,
    459         operand: Air.Inst.Ref,
    460     ) error{OutOfMemory}!Air.Inst.Ref {
    461         return block.addInst(.{
    462             .tag = tag,
    463             .data = .{ .un_op = operand },
    464         });
    465     }
    466 
    467     fn addBr(
    468         block: *Block,
    469         target_block: Air.Inst.Index,
    470         operand: Air.Inst.Ref,
    471     ) error{OutOfMemory}!Air.Inst.Ref {
    472         return block.addInst(.{
    473             .tag = .br,
    474             .data = .{ .br = .{
    475                 .block_inst = target_block,
    476                 .operand = operand,
    477             } },
    478         });
    479     }
    480 
    481     fn addBinOp(
    482         block: *Block,
    483         tag: Air.Inst.Tag,
    484         lhs: Air.Inst.Ref,
    485         rhs: Air.Inst.Ref,
    486     ) error{OutOfMemory}!Air.Inst.Ref {
    487         return block.addInst(.{
    488             .tag = tag,
    489             .data = .{ .bin_op = .{
    490                 .lhs = lhs,
    491                 .rhs = rhs,
    492             } },
    493         });
    494     }
    495 
    496     fn addStructFieldPtr(
    497         block: *Block,
    498         struct_ptr: Air.Inst.Ref,
    499         field_index: u32,
    500         ptr_field_ty: Type,
    501     ) !Air.Inst.Ref {
    502         const ty = try block.sema.addType(ptr_field_ty);
    503         const tag: Air.Inst.Tag = switch (field_index) {
    504             0 => .struct_field_ptr_index_0,
    505             1 => .struct_field_ptr_index_1,
    506             2 => .struct_field_ptr_index_2,
    507             3 => .struct_field_ptr_index_3,
    508             else => {
    509                 return block.addInst(.{
    510                     .tag = .struct_field_ptr,
    511                     .data = .{ .ty_pl = .{
    512                         .ty = ty,
    513                         .payload = try block.sema.addExtra(Air.StructField{
    514                             .struct_operand = struct_ptr,
    515                             .field_index = field_index,
    516                         }),
    517                     } },
    518                 });
    519             },
    520         };
    521         return block.addInst(.{
    522             .tag = tag,
    523             .data = .{ .ty_op = .{
    524                 .ty = ty,
    525                 .operand = struct_ptr,
    526             } },
    527         });
    528     }
    529 
    530     fn addStructFieldVal(
    531         block: *Block,
    532         struct_val: Air.Inst.Ref,
    533         field_index: u32,
    534         field_ty: Type,
    535     ) !Air.Inst.Ref {
    536         return block.addInst(.{
    537             .tag = .struct_field_val,
    538             .data = .{ .ty_pl = .{
    539                 .ty = try block.sema.addType(field_ty),
    540                 .payload = try block.sema.addExtra(Air.StructField{
    541                     .struct_operand = struct_val,
    542                     .field_index = field_index,
    543                 }),
    544             } },
    545         });
    546     }
    547 
    548     fn addSliceElemPtr(
    549         block: *Block,
    550         slice: Air.Inst.Ref,
    551         elem_index: Air.Inst.Ref,
    552         elem_ptr_ty: Type,
    553     ) !Air.Inst.Ref {
    554         return block.addInst(.{
    555             .tag = .slice_elem_ptr,
    556             .data = .{ .ty_pl = .{
    557                 .ty = try block.sema.addType(elem_ptr_ty),
    558                 .payload = try block.sema.addExtra(Air.Bin{
    559                     .lhs = slice,
    560                     .rhs = elem_index,
    561                 }),
    562             } },
    563         });
    564     }
    565 
    566     fn addPtrElemPtr(
    567         block: *Block,
    568         array_ptr: Air.Inst.Ref,
    569         elem_index: Air.Inst.Ref,
    570         elem_ptr_ty: Type,
    571     ) !Air.Inst.Ref {
    572         const ty_ref = try block.sema.addType(elem_ptr_ty);
    573         return block.addPtrElemPtrTypeRef(array_ptr, elem_index, ty_ref);
    574     }
    575 
    576     fn addPtrElemPtrTypeRef(
    577         block: *Block,
    578         array_ptr: Air.Inst.Ref,
    579         elem_index: Air.Inst.Ref,
    580         elem_ptr_ty: Air.Inst.Ref,
    581     ) !Air.Inst.Ref {
    582         return block.addInst(.{
    583             .tag = .ptr_elem_ptr,
    584             .data = .{ .ty_pl = .{
    585                 .ty = elem_ptr_ty,
    586                 .payload = try block.sema.addExtra(Air.Bin{
    587                     .lhs = array_ptr,
    588                     .rhs = elem_index,
    589                 }),
    590             } },
    591         });
    592     }
    593 
    594     fn addCmpVector(block: *Block, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref, cmp_op: std.math.CompareOperator) !Air.Inst.Ref {
    595         const sema = block.sema;
    596         const mod = sema.mod;
    597         return block.addInst(.{
    598             .tag = if (block.float_mode == .Optimized) .cmp_vector_optimized else .cmp_vector,
    599             .data = .{ .ty_pl = .{
    600                 .ty = try sema.addType(
    601                     try mod.vectorType(.{
    602                         .len = sema.typeOf(lhs).vectorLen(mod),
    603                         .child = .bool_type,
    604                     }),
    605                 ),
    606                 .payload = try sema.addExtra(Air.VectorCmp{
    607                     .lhs = lhs,
    608                     .rhs = rhs,
    609                     .op = Air.VectorCmp.encodeOp(cmp_op),
    610                 }),
    611             } },
    612         });
    613     }
    614 
    615     fn addAggregateInit(
    616         block: *Block,
    617         aggregate_ty: Type,
    618         elements: []const Air.Inst.Ref,
    619     ) !Air.Inst.Ref {
    620         const sema = block.sema;
    621         const ty_ref = try sema.addType(aggregate_ty);
    622         try sema.air_extra.ensureUnusedCapacity(sema.gpa, elements.len);
    623         const extra_index = @intCast(u32, sema.air_extra.items.len);
    624         sema.appendRefsAssumeCapacity(elements);
    625 
    626         return block.addInst(.{
    627             .tag = .aggregate_init,
    628             .data = .{ .ty_pl = .{
    629                 .ty = ty_ref,
    630                 .payload = extra_index,
    631             } },
    632         });
    633     }
    634 
    635     fn addUnionInit(
    636         block: *Block,
    637         union_ty: Type,
    638         field_index: u32,
    639         init: Air.Inst.Ref,
    640     ) !Air.Inst.Ref {
    641         return block.addInst(.{
    642             .tag = .union_init,
    643             .data = .{ .ty_pl = .{
    644                 .ty = try block.sema.addType(union_ty),
    645                 .payload = try block.sema.addExtra(Air.UnionInit{
    646                     .field_index = field_index,
    647                     .init = init,
    648                 }),
    649             } },
    650         });
    651     }
    652 
    653     pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {
    654         return Air.indexToRef(try block.addInstAsIndex(inst));
    655     }
    656 
    657     pub fn addInstAsIndex(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Index {
    658         const sema = block.sema;
    659         const gpa = sema.gpa;
    660 
    661         try sema.air_instructions.ensureUnusedCapacity(gpa, 1);
    662         try block.instructions.ensureUnusedCapacity(gpa, 1);
    663 
    664         const result_index = @intCast(Air.Inst.Index, sema.air_instructions.len);
    665         sema.air_instructions.appendAssumeCapacity(inst);
    666         block.instructions.appendAssumeCapacity(result_index);
    667         return result_index;
    668     }
    669 
    670     /// Insert an instruction into the block at `index`. Moves all following
    671     /// instructions forward in the block to make room. Operation is O(N).
    672     pub fn insertInst(block: *Block, index: Air.Inst.Index, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {
    673         return Air.indexToRef(try block.insertInstAsIndex(index, inst));
    674     }
    675 
    676     pub fn insertInstAsIndex(block: *Block, index: Air.Inst.Index, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Index {
    677         const sema = block.sema;
    678         const gpa = sema.gpa;
    679 
    680         try sema.air_instructions.ensureUnusedCapacity(gpa, 1);
    681 
    682         const result_index = @intCast(Air.Inst.Index, sema.air_instructions.len);
    683         sema.air_instructions.appendAssumeCapacity(inst);
    684 
    685         try block.instructions.insert(gpa, index, result_index);
    686         return result_index;
    687     }
    688 
    689     fn addUnreachable(block: *Block, safety_check: bool) !void {
    690         if (safety_check and block.wantSafety()) {
    691             try block.sema.safetyPanic(block, .unreach);
    692         } else {
    693             _ = try block.addNoOp(.unreach);
    694         }
    695     }
    696 
    697     pub fn startAnonDecl(block: *Block) !WipAnonDecl {
    698         return WipAnonDecl{
    699             .block = block,
    700             .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa),
    701             .finished = false,
    702         };
    703     }
    704 
    705     pub const WipAnonDecl = struct {
    706         block: *Block,
    707         new_decl_arena: std.heap.ArenaAllocator,
    708         finished: bool,
    709 
    710         pub fn arena(wad: *WipAnonDecl) Allocator {
    711             return wad.new_decl_arena.allocator();
    712         }
    713 
    714         pub fn deinit(wad: *WipAnonDecl) void {
    715             if (!wad.finished) {
    716                 wad.new_decl_arena.deinit();
    717             }
    718             wad.* = undefined;
    719         }
    720 
    721         /// `alignment` value of 0 means to use ABI alignment.
    722         pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value, alignment: u64) !Decl.Index {
    723             const sema = wad.block.sema;
    724             // Do this ahead of time because `createAnonymousDecl` depends on calling
    725             // `type.hasRuntimeBits()`.
    726             _ = try sema.typeHasRuntimeBits(ty);
    727             const new_decl_index = try sema.mod.createAnonymousDecl(wad.block, .{
    728                 .ty = ty,
    729                 .val = val,
    730             });
    731             const new_decl = sema.mod.declPtr(new_decl_index);
    732             // TODO: migrate Decl alignment to use `InternPool.Alignment`
    733             new_decl.@"align" = @intCast(u32, alignment);
    734             errdefer sema.mod.abortAnonDecl(new_decl_index);
    735             try new_decl.finalizeNewArena(&wad.new_decl_arena);
    736             wad.finished = true;
    737             try sema.mod.finalizeAnonDecl(new_decl_index);
    738             return new_decl_index;
    739         }
    740     };
    741 };
    742 
    743 const LabeledBlock = struct {
    744     block: Block,
    745     label: Block.Label,
    746 
    747     fn destroy(lb: *LabeledBlock, gpa: Allocator) void {
    748         lb.block.instructions.deinit(gpa);
    749         lb.label.merges.deinit(gpa);
    750         gpa.destroy(lb);
    751     }
    752 };
    753 
    754 /// The value stored in the inferred allocation. This will go into
    755 /// peer type resolution. This is stored in a separate list so that
    756 /// the items are contiguous in memory and thus can be passed to
    757 /// `Module.resolvePeerTypes`.
    758 const InferredAlloc = struct {
    759     prongs: std.MultiArrayList(struct {
    760         /// The dummy instruction used as a peer to resolve the type.
    761         /// Although this has a redundant type with placeholder, this is
    762         /// needed in addition because it may be a constant value, which
    763         /// affects peer type resolution.
    764         stored_inst: Air.Inst.Ref,
    765         /// The bitcast instruction used as a placeholder when the
    766         /// new result pointer type is not yet known.
    767         placeholder: Air.Inst.Index,
    768     }) = .{},
    769 };
    770 
    771 pub fn deinit(sema: *Sema) void {
    772     const gpa = sema.gpa;
    773     sema.air_instructions.deinit(gpa);
    774     sema.air_extra.deinit(gpa);
    775     sema.inst_map.deinit(gpa);
    776     sema.decl_val_table.deinit(gpa);
    777     sema.types_to_resolve.deinit(gpa);
    778     {
    779         var it = sema.post_hoc_blocks.iterator();
    780         while (it.next()) |entry| {
    781             const labeled_block = entry.value_ptr.*;
    782             labeled_block.destroy(gpa);
    783         }
    784         sema.post_hoc_blocks.deinit(gpa);
    785     }
    786     sema.unresolved_inferred_allocs.deinit(gpa);
    787     sema.* = undefined;
    788 }
    789 
    790 /// Returns only the result from the body that is specified.
    791 /// Only appropriate to call when it is determined at comptime that this body
    792 /// has no peers.
    793 fn resolveBody(
    794     sema: *Sema,
    795     block: *Block,
    796     body: []const Zir.Inst.Index,
    797     /// This is the instruction that a break instruction within `body` can
    798     /// use to return from the body.
    799     body_inst: Zir.Inst.Index,
    800 ) CompileError!Air.Inst.Ref {
    801     const break_data = (try sema.analyzeBodyBreak(block, body)) orelse
    802         return Air.Inst.Ref.unreachable_value;
    803     // For comptime control flow, we need to detect when `analyzeBody` reports
    804     // that we need to break from an outer block. In such case we
    805     // use Zig's error mechanism to send control flow up the stack until
    806     // we find the corresponding block to this break.
    807     if (block.is_comptime and break_data.block_inst != body_inst) {
    808         sema.comptime_break_inst = break_data.inst;
    809         return error.ComptimeBreak;
    810     }
    811     return try sema.resolveInst(break_data.operand);
    812 }
    813 
    814 fn analyzeBodyRuntimeBreak(sema: *Sema, block: *Block, body: []const Zir.Inst.Index) !void {
    815     _ = sema.analyzeBodyInner(block, body) catch |err| switch (err) {
    816         error.ComptimeBreak => {
    817             const zir_datas = sema.code.instructions.items(.data);
    818             const break_data = zir_datas[sema.comptime_break_inst].@"break";
    819             const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data;
    820             try sema.addRuntimeBreak(block, .{
    821                 .block_inst = extra.block_inst,
    822                 .operand = break_data.operand,
    823                 .inst = sema.comptime_break_inst,
    824             });
    825         },
    826         else => |e| return e,
    827     };
    828 }
    829 
    830 pub fn analyzeBody(
    831     sema: *Sema,
    832     block: *Block,
    833     body: []const Zir.Inst.Index,
    834 ) !void {
    835     _ = sema.analyzeBodyInner(block, body) catch |err| switch (err) {
    836         error.ComptimeBreak => unreachable, // unexpected comptime control flow
    837         else => |e| return e,
    838     };
    839 }
    840 
    841 const BreakData = struct {
    842     block_inst: Zir.Inst.Index,
    843     operand: Zir.Inst.Ref,
    844     inst: Zir.Inst.Index,
    845 };
    846 
    847 pub fn analyzeBodyBreak(
    848     sema: *Sema,
    849     block: *Block,
    850     body: []const Zir.Inst.Index,
    851 ) CompileError!?BreakData {
    852     const break_inst = sema.analyzeBodyInner(block, body) catch |err| switch (err) {
    853         error.ComptimeBreak => sema.comptime_break_inst,
    854         else => |e| return e,
    855     };
    856     if (block.instructions.items.len != 0 and
    857         sema.isNoReturn(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1])))
    858         return null;
    859     const break_data = sema.code.instructions.items(.data)[break_inst].@"break";
    860     const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data;
    861     return BreakData{
    862         .block_inst = extra.block_inst,
    863         .operand = break_data.operand,
    864         .inst = break_inst,
    865     };
    866 }
    867 
    868 /// ZIR instructions which are always `noreturn` return this. This matches the
    869 /// return type of `analyzeBody` so that we can tail call them.
    870 /// Only appropriate to return when the instruction is known to be NoReturn
    871 /// solely based on the ZIR tag.
    872 const always_noreturn: CompileError!Zir.Inst.Index = @as(Zir.Inst.Index, undefined);
    873 
    874 /// This function is the main loop of `Sema` and it can be used in two different ways:
    875 /// * The traditional way where there are N breaks out of the block and peer type
    876 ///   resolution is done on the break operands. In this case, the `Zir.Inst.Index`
    877 ///   part of the return value will be `undefined`, and callsites should ignore it,
    878 ///   finding the block result value via the block scope.
    879 /// * The "flat" way. There is only 1 break out of the block, and it is with a `break_inline`
    880 ///   instruction. In this case, the `Zir.Inst.Index` part of the return value will be
    881 ///   the break instruction. This communicates both which block the break applies to, as
    882 ///   well as the operand. No block scope needs to be created for this strategy.
    883 fn analyzeBodyInner(
    884     sema: *Sema,
    885     block: *Block,
    886     body: []const Zir.Inst.Index,
    887 ) CompileError!Zir.Inst.Index {
    888     // No tracy calls here, to avoid interfering with the tail call mechanism.
    889 
    890     try sema.inst_map.ensureSpaceForInstructions(sema.gpa, body);
    891 
    892     // Most of the time, we don't need to construct a new capture scope for a
    893     // block. However, successive iterations of comptime loops can capture
    894     // different values for the same Zir.Inst.Index, so in those cases, we will
    895     // have to create nested capture scopes; see the `.repeat` case below.
    896     const parent_capture_scope = block.wip_capture_scope;
    897     parent_capture_scope.incRef();
    898     var wip_captures: WipCaptureScope = .{
    899         .scope = parent_capture_scope,
    900         .gpa = sema.gpa,
    901         .finalized = true, // don't finalize the parent scope
    902     };
    903     defer wip_captures.deinit();
    904 
    905     const mod = sema.mod;
    906     const map = &sema.inst_map;
    907     const tags = sema.code.instructions.items(.tag);
    908     const datas = sema.code.instructions.items(.data);
    909 
    910     var orig_captures: usize = parent_capture_scope.captures.count();
    911 
    912     var crash_info = crash_report.prepAnalyzeBody(sema, block, body);
    913     crash_info.push();
    914     defer crash_info.pop();
    915 
    916     var dbg_block_begins: u32 = 0;
    917 
    918     // We use a while (true) loop here to avoid a redundant way of breaking out of
    919     // the loop. The only way to break out of the loop is with a `noreturn`
    920     // instruction.
    921     var i: usize = 0;
    922     const result = while (true) {
    923         crash_info.setBodyIndex(i);
    924         const inst = body[i];
    925         std.log.scoped(.sema_zir).debug("sema ZIR {s} %{d}", .{
    926             mod.namespacePtr(mod.declPtr(block.src_decl).src_namespace).file_scope.sub_file_path, inst,
    927         });
    928         const air_inst: Air.Inst.Ref = switch (tags[inst]) {
    929             // zig fmt: off
    930             .alloc                        => try sema.zirAlloc(block, inst),
    931             .alloc_inferred               => try sema.zirAllocInferred(block, inst, true),
    932             .alloc_inferred_mut           => try sema.zirAllocInferred(block, inst, false),
    933             .alloc_inferred_comptime      => try sema.zirAllocInferredComptime(inst, true),
    934             .alloc_inferred_comptime_mut  => try sema.zirAllocInferredComptime(inst, false),
    935             .alloc_mut                    => try sema.zirAllocMut(block, inst),
    936             .alloc_comptime_mut           => try sema.zirAllocComptime(block, inst),
    937             .make_ptr_const               => try sema.zirMakePtrConst(block, inst),
    938             .anyframe_type                => try sema.zirAnyframeType(block, inst),
    939             .array_cat                    => try sema.zirArrayCat(block, inst),
    940             .array_mul                    => try sema.zirArrayMul(block, inst),
    941             .array_type                   => try sema.zirArrayType(block, inst),
    942             .array_type_sentinel          => try sema.zirArrayTypeSentinel(block, inst),
    943             .vector_type                  => try sema.zirVectorType(block, inst),
    944             .as                           => try sema.zirAs(block, inst),
    945             .as_node                      => try sema.zirAsNode(block, inst),
    946             .as_shift_operand             => try sema.zirAsShiftOperand(block, inst),
    947             .bit_and                      => try sema.zirBitwise(block, inst, .bit_and),
    948             .bit_not                      => try sema.zirBitNot(block, inst),
    949             .bit_or                       => try sema.zirBitwise(block, inst, .bit_or),
    950             .bitcast                      => try sema.zirBitcast(block, inst),
    951             .suspend_block                => try sema.zirSuspendBlock(block, inst),
    952             .bool_not                     => try sema.zirBoolNot(block, inst),
    953             .bool_br_and                  => try sema.zirBoolBr(block, inst, false),
    954             .bool_br_or                   => try sema.zirBoolBr(block, inst, true),
    955             .c_import                     => try sema.zirCImport(block, inst),
    956             .call                         => try sema.zirCall(block, inst, .direct),
    957             .field_call                   => try sema.zirCall(block, inst, .field),
    958             .closure_get                  => try sema.zirClosureGet(block, inst),
    959             .cmp_lt                       => try sema.zirCmp(block, inst, .lt),
    960             .cmp_lte                      => try sema.zirCmp(block, inst, .lte),
    961             .cmp_eq                       => try sema.zirCmpEq(block, inst, .eq, Air.Inst.Tag.fromCmpOp(.eq, block.float_mode == .Optimized)),
    962             .cmp_gte                      => try sema.zirCmp(block, inst, .gte),
    963             .cmp_gt                       => try sema.zirCmp(block, inst, .gt),
    964             .cmp_neq                      => try sema.zirCmpEq(block, inst, .neq, Air.Inst.Tag.fromCmpOp(.neq, block.float_mode == .Optimized)),
    965             .coerce_result_ptr            => try sema.zirCoerceResultPtr(block, inst),
    966             .decl_ref                     => try sema.zirDeclRef(block, inst),
    967             .decl_val                     => try sema.zirDeclVal(block, inst),
    968             .load                         => try sema.zirLoad(block, inst),
    969             .elem_ptr                     => try sema.zirElemPtr(block, inst),
    970             .elem_ptr_node                => try sema.zirElemPtrNode(block, inst),
    971             .elem_ptr_imm                 => try sema.zirElemPtrImm(block, inst),
    972             .elem_val                     => try sema.zirElemVal(block, inst),
    973             .elem_val_node                => try sema.zirElemValNode(block, inst),
    974             .elem_type_index              => try sema.zirElemTypeIndex(block, inst),
    975             .enum_literal                 => try sema.zirEnumLiteral(block, inst),
    976             .enum_to_int                  => try sema.zirEnumToInt(block, inst),
    977             .int_to_enum                  => try sema.zirIntToEnum(block, inst),
    978             .err_union_code               => try sema.zirErrUnionCode(block, inst),
    979             .err_union_code_ptr           => try sema.zirErrUnionCodePtr(block, inst),
    980             .err_union_payload_unsafe     => try sema.zirErrUnionPayload(block, inst),
    981             .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst),
    982             .error_union_type             => try sema.zirErrorUnionType(block, inst),
    983             .error_value                  => try sema.zirErrorValue(block, inst),
    984             .field_ptr                    => try sema.zirFieldPtr(block, inst, false),
    985             .field_ptr_init               => try sema.zirFieldPtr(block, inst, true),
    986             .field_ptr_named              => try sema.zirFieldPtrNamed(block, inst),
    987             .field_val                    => try sema.zirFieldVal(block, inst),
    988             .field_val_named              => try sema.zirFieldValNamed(block, inst),
    989             .func                         => try sema.zirFunc(block, inst, false),
    990             .func_inferred                => try sema.zirFunc(block, inst, true),
    991             .func_fancy                   => try sema.zirFuncFancy(block, inst),
    992             .import                       => try sema.zirImport(block, inst),
    993             .indexable_ptr_len            => try sema.zirIndexablePtrLen(block, inst),
    994             .int                          => try sema.zirInt(block, inst),
    995             .int_big                      => try sema.zirIntBig(block, inst),
    996             .float                        => try sema.zirFloat(block, inst),
    997             .float128                     => try sema.zirFloat128(block, inst),
    998             .int_type                     => try sema.zirIntType(inst),
    999             .is_non_err                   => try sema.zirIsNonErr(block, inst),
   1000             .is_non_err_ptr               => try sema.zirIsNonErrPtr(block, inst),
   1001             .ret_is_non_err               => try sema.zirRetIsNonErr(block, inst),
   1002             .is_non_null                  => try sema.zirIsNonNull(block, inst),
   1003             .is_non_null_ptr              => try sema.zirIsNonNullPtr(block, inst),
   1004             .merge_error_sets             => try sema.zirMergeErrorSets(block, inst),
   1005             .negate                       => try sema.zirNegate(block, inst),
   1006             .negate_wrap                  => try sema.zirNegateWrap(block, inst),
   1007             .optional_payload_safe        => try sema.zirOptionalPayload(block, inst, true),
   1008             .optional_payload_safe_ptr    => try sema.zirOptionalPayloadPtr(block, inst, true),
   1009             .optional_payload_unsafe      => try sema.zirOptionalPayload(block, inst, false),
   1010             .optional_payload_unsafe_ptr  => try sema.zirOptionalPayloadPtr(block, inst, false),
   1011             .optional_type                => try sema.zirOptionalType(block, inst),
   1012             .ptr_type                     => try sema.zirPtrType(block, inst),
   1013             .ref                          => try sema.zirRef(block, inst),
   1014             .ret_err_value_code           => try sema.zirRetErrValueCode(inst),
   1015             .shr                          => try sema.zirShr(block, inst, .shr),
   1016             .shr_exact                    => try sema.zirShr(block, inst, .shr_exact),
   1017             .slice_end                    => try sema.zirSliceEnd(block, inst),
   1018             .slice_sentinel               => try sema.zirSliceSentinel(block, inst),
   1019             .slice_start                  => try sema.zirSliceStart(block, inst),
   1020             .slice_length                 => try sema.zirSliceLength(block, inst),
   1021             .str                          => try sema.zirStr(block, inst),
   1022             .switch_block                 => try sema.zirSwitchBlock(block, inst),
   1023             .switch_cond                  => try sema.zirSwitchCond(block, inst, false),
   1024             .switch_cond_ref              => try sema.zirSwitchCond(block, inst, true),
   1025             .switch_capture               => try sema.zirSwitchCapture(block, inst, false, false),
   1026             .switch_capture_ref           => try sema.zirSwitchCapture(block, inst, false, true),
   1027             .switch_capture_multi         => try sema.zirSwitchCapture(block, inst, true, false),
   1028             .switch_capture_multi_ref     => try sema.zirSwitchCapture(block, inst, true, true),
   1029             .switch_capture_tag           => try sema.zirSwitchCaptureTag(block, inst),
   1030             .type_info                    => try sema.zirTypeInfo(block, inst),
   1031             .size_of                      => try sema.zirSizeOf(block, inst),
   1032             .bit_size_of                  => try sema.zirBitSizeOf(block, inst),
   1033             .typeof                       => try sema.zirTypeof(block, inst),
   1034             .typeof_builtin               => try sema.zirTypeofBuiltin(block, inst),
   1035             .typeof_log2_int_type         => try sema.zirTypeofLog2IntType(block, inst),
   1036             .xor                          => try sema.zirBitwise(block, inst, .xor),
   1037             .struct_init_empty            => try sema.zirStructInitEmpty(block, inst),
   1038             .struct_init                  => try sema.zirStructInit(block, inst, false),
   1039             .struct_init_ref              => try sema.zirStructInit(block, inst, true),
   1040             .struct_init_anon             => try sema.zirStructInitAnon(block, inst, false),
   1041             .struct_init_anon_ref         => try sema.zirStructInitAnon(block, inst, true),
   1042             .array_init                   => try sema.zirArrayInit(block, inst, false),
   1043             .array_init_ref               => try sema.zirArrayInit(block, inst, true),
   1044             .array_init_anon              => try sema.zirArrayInitAnon(block, inst, false),
   1045             .array_init_anon_ref          => try sema.zirArrayInitAnon(block, inst, true),
   1046             .union_init                   => try sema.zirUnionInit(block, inst),
   1047             .field_type                   => try sema.zirFieldType(block, inst),
   1048             .field_type_ref               => try sema.zirFieldTypeRef(block, inst),
   1049             .ptr_to_int                   => try sema.zirPtrToInt(block, inst),
   1050             .align_of                     => try sema.zirAlignOf(block, inst),
   1051             .bool_to_int                  => try sema.zirBoolToInt(block, inst),
   1052             .embed_file                   => try sema.zirEmbedFile(block, inst),
   1053             .error_name                   => try sema.zirErrorName(block, inst),
   1054             .tag_name                     => try sema.zirTagName(block, inst),
   1055             .type_name                    => try sema.zirTypeName(block, inst),
   1056             .frame_type                   => try sema.zirFrameType(block, inst),
   1057             .frame_size                   => try sema.zirFrameSize(block, inst),
   1058             .float_to_int                 => try sema.zirFloatToInt(block, inst),
   1059             .int_to_float                 => try sema.zirIntToFloat(block, inst),
   1060             .int_to_ptr                   => try sema.zirIntToPtr(block, inst),
   1061             .float_cast                   => try sema.zirFloatCast(block, inst),
   1062             .int_cast                     => try sema.zirIntCast(block, inst),
   1063             .ptr_cast                     => try sema.zirPtrCast(block, inst),
   1064             .truncate                     => try sema.zirTruncate(block, inst),
   1065             .align_cast                   => try sema.zirAlignCast(block, inst),
   1066             .has_decl                     => try sema.zirHasDecl(block, inst),
   1067             .has_field                    => try sema.zirHasField(block, inst),
   1068             .byte_swap                    => try sema.zirByteSwap(block, inst),
   1069             .bit_reverse                  => try sema.zirBitReverse(block, inst),
   1070             .bit_offset_of                => try sema.zirBitOffsetOf(block, inst),
   1071             .offset_of                    => try sema.zirOffsetOf(block, inst),
   1072             .splat                        => try sema.zirSplat(block, inst),
   1073             .reduce                       => try sema.zirReduce(block, inst),
   1074             .shuffle                      => try sema.zirShuffle(block, inst),
   1075             .atomic_load                  => try sema.zirAtomicLoad(block, inst),
   1076             .atomic_rmw                   => try sema.zirAtomicRmw(block, inst),
   1077             .mul_add                      => try sema.zirMulAdd(block, inst),
   1078             .builtin_call                 => try sema.zirBuiltinCall(block, inst),
   1079             .field_parent_ptr             => try sema.zirFieldParentPtr(block, inst),
   1080             .@"resume"                    => try sema.zirResume(block, inst),
   1081             .@"await"                     => try sema.zirAwait(block, inst),
   1082             .array_base_ptr               => try sema.zirArrayBasePtr(block, inst),
   1083             .field_base_ptr               => try sema.zirFieldBasePtr(block, inst),
   1084             .for_len                      => try sema.zirForLen(block, inst),
   1085 
   1086             .clz       => try sema.zirBitCount(block, inst, .clz,      Value.clz),
   1087             .ctz       => try sema.zirBitCount(block, inst, .ctz,      Value.ctz),
   1088             .pop_count => try sema.zirBitCount(block, inst, .popcount, Value.popCount),
   1089 
   1090             .sqrt  => try sema.zirUnaryMath(block, inst, .sqrt, Value.sqrt),
   1091             .sin   => try sema.zirUnaryMath(block, inst, .sin, Value.sin),
   1092             .cos   => try sema.zirUnaryMath(block, inst, .cos, Value.cos),
   1093             .tan   => try sema.zirUnaryMath(block, inst, .tan, Value.tan),
   1094             .exp   => try sema.zirUnaryMath(block, inst, .exp, Value.exp),
   1095             .exp2  => try sema.zirUnaryMath(block, inst, .exp2, Value.exp2),
   1096             .log   => try sema.zirUnaryMath(block, inst, .log, Value.log),
   1097             .log2  => try sema.zirUnaryMath(block, inst, .log2, Value.log2),
   1098             .log10 => try sema.zirUnaryMath(block, inst, .log10, Value.log10),
   1099             .fabs  => try sema.zirUnaryMath(block, inst, .fabs, Value.fabs),
   1100             .floor => try sema.zirUnaryMath(block, inst, .floor, Value.floor),
   1101             .ceil  => try sema.zirUnaryMath(block, inst, .ceil, Value.ceil),
   1102             .round => try sema.zirUnaryMath(block, inst, .round, Value.round),
   1103             .trunc => try sema.zirUnaryMath(block, inst, .trunc_float, Value.trunc),
   1104 
   1105             .error_set_decl      => try sema.zirErrorSetDecl(block, inst, .parent),
   1106             .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
   1107             .error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func),
   1108 
   1109             .add       => try sema.zirArithmetic(block, inst, .add,        true),
   1110             .addwrap   => try sema.zirArithmetic(block, inst, .addwrap,    true),
   1111             .add_sat   => try sema.zirArithmetic(block, inst, .add_sat,    true),
   1112             .add_unsafe=> try sema.zirArithmetic(block, inst, .add_unsafe, false),
   1113             .mul       => try sema.zirArithmetic(block, inst, .mul,        true),
   1114             .mulwrap   => try sema.zirArithmetic(block, inst, .mulwrap,    true),
   1115             .mul_sat   => try sema.zirArithmetic(block, inst, .mul_sat,    true),
   1116             .sub       => try sema.zirArithmetic(block, inst, .sub,        true),
   1117             .subwrap   => try sema.zirArithmetic(block, inst, .subwrap,    true),
   1118             .sub_sat   => try sema.zirArithmetic(block, inst, .sub_sat,    true),
   1119 
   1120             .div       => try sema.zirDiv(block, inst),
   1121             .div_exact => try sema.zirDivExact(block, inst),
   1122             .div_floor => try sema.zirDivFloor(block, inst),
   1123             .div_trunc => try sema.zirDivTrunc(block, inst),
   1124 
   1125             .mod_rem   => try sema.zirModRem(block, inst),
   1126             .mod       => try sema.zirMod(block, inst),
   1127             .rem       => try sema.zirRem(block, inst),
   1128 
   1129             .max => try sema.zirMinMax(block, inst, .max),
   1130             .min => try sema.zirMinMax(block, inst, .min),
   1131 
   1132             .shl       => try sema.zirShl(block, inst, .shl),
   1133             .shl_exact => try sema.zirShl(block, inst, .shl_exact),
   1134             .shl_sat   => try sema.zirShl(block, inst, .shl_sat),
   1135 
   1136             .ret_ptr  => try sema.zirRetPtr(block),
   1137             .ret_type => try sema.addType(sema.fn_ret_ty),
   1138 
   1139             // Instructions that we know to *always* be noreturn based solely on their tag.
   1140             // These functions match the return type of analyzeBody so that we can
   1141             // tail call them here.
   1142             .compile_error  => break sema.zirCompileError(block, inst),
   1143             .ret_implicit   => break sema.zirRetImplicit(block, inst),
   1144             .ret_node       => break sema.zirRetNode(block, inst),
   1145             .ret_load       => break sema.zirRetLoad(block, inst),
   1146             .ret_err_value  => break sema.zirRetErrValue(block, inst),
   1147             .@"unreachable" => break sema.zirUnreachable(block, inst),
   1148             .panic          => break sema.zirPanic(block, inst),
   1149             .trap           => break sema.zirTrap(block, inst),
   1150             // zig fmt: on
   1151 
   1152             .extended => ext: {
   1153                 const extended = datas[inst].extended;
   1154                 break :ext switch (extended.opcode) {
   1155                     // zig fmt: off
   1156                     .variable              => try sema.zirVarExtended(       block, extended),
   1157                     .struct_decl           => try sema.zirStructDecl(        block, extended, inst),
   1158                     .enum_decl             => try sema.zirEnumDecl(          block, extended, inst),
   1159                     .union_decl            => try sema.zirUnionDecl(         block, extended, inst),
   1160                     .opaque_decl           => try sema.zirOpaqueDecl(        block, extended, inst),
   1161                     .this                  => try sema.zirThis(              block, extended),
   1162                     .ret_addr              => try sema.zirRetAddr(           block, extended),
   1163                     .builtin_src           => try sema.zirBuiltinSrc(        block, extended),
   1164                     .error_return_trace    => try sema.zirErrorReturnTrace(  block),
   1165                     .frame                 => try sema.zirFrame(             block, extended),
   1166                     .frame_address         => try sema.zirFrameAddress(      block, extended),
   1167                     .alloc                 => try sema.zirAllocExtended(     block, extended),
   1168                     .builtin_extern        => try sema.zirBuiltinExtern(     block, extended),
   1169                     .@"asm"                => try sema.zirAsm(               block, extended, false),
   1170                     .asm_expr              => try sema.zirAsm(               block, extended, true),
   1171                     .typeof_peer           => try sema.zirTypeofPeer(        block, extended),
   1172                     .compile_log           => try sema.zirCompileLog(               extended),
   1173                     .min_multi             => try sema.zirMinMaxMulti(       block, extended, .min),
   1174                     .max_multi             => try sema.zirMinMaxMulti(       block, extended, .max),
   1175                     .add_with_overflow     => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
   1176                     .sub_with_overflow     => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
   1177                     .mul_with_overflow     => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
   1178                     .shl_with_overflow     => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
   1179                     .c_undef               => try sema.zirCUndef(            block, extended),
   1180                     .c_include             => try sema.zirCInclude(          block, extended),
   1181                     .c_define              => try sema.zirCDefine(           block, extended),
   1182                     .wasm_memory_size      => try sema.zirWasmMemorySize(    block, extended),
   1183                     .wasm_memory_grow      => try sema.zirWasmMemoryGrow(    block, extended),
   1184                     .prefetch              => try sema.zirPrefetch(          block, extended),
   1185                     .err_set_cast          => try sema.zirErrSetCast(        block, extended),
   1186                     .await_nosuspend       => try sema.zirAwaitNosuspend(    block, extended),
   1187                     .select                => try sema.zirSelect(            block, extended),
   1188                     .error_to_int          => try sema.zirErrorToInt(        block, extended),
   1189                     .int_to_error          => try sema.zirIntToError(        block, extended),
   1190                     .reify                 => try sema.zirReify(             block, extended, inst),
   1191                     .builtin_async_call    => try sema.zirBuiltinAsyncCall(  block, extended),
   1192                     .cmpxchg               => try sema.zirCmpxchg(           block, extended),
   1193                     .addrspace_cast        => try sema.zirAddrSpaceCast(     block, extended),
   1194                     .c_va_arg              => try sema.zirCVaArg(            block, extended),
   1195                     .c_va_copy             => try sema.zirCVaCopy(           block, extended),
   1196                     .c_va_end              => try sema.zirCVaEnd(            block, extended),
   1197                     .c_va_start            => try sema.zirCVaStart(          block, extended),
   1198                     .const_cast,           => try sema.zirConstCast(         block, extended),
   1199                     .volatile_cast,        => try sema.zirVolatileCast(      block, extended),
   1200                     .work_item_id          => try sema.zirWorkItem(          block, extended, extended.opcode),
   1201                     .work_group_size       => try sema.zirWorkItem(          block, extended, extended.opcode),
   1202                     .work_group_id         => try sema.zirWorkItem(          block, extended, extended.opcode),
   1203                     .in_comptime           => try sema.zirInComptime(        block),
   1204                     // zig fmt: on
   1205 
   1206                     .fence => {
   1207                         try sema.zirFence(block, extended);
   1208                         i += 1;
   1209                         continue;
   1210                     },
   1211                     .set_float_mode => {
   1212                         try sema.zirSetFloatMode(block, extended);
   1213                         i += 1;
   1214                         continue;
   1215                     },
   1216                     .set_align_stack => {
   1217                         try sema.zirSetAlignStack(block, extended);
   1218                         i += 1;
   1219                         continue;
   1220                     },
   1221                     .set_cold => {
   1222                         try sema.zirSetCold(block, extended);
   1223                         i += 1;
   1224                         continue;
   1225                     },
   1226                     .breakpoint => {
   1227                         if (!block.is_comptime) {
   1228                             _ = try block.addNoOp(.breakpoint);
   1229                         }
   1230                         i += 1;
   1231                         continue;
   1232                     },
   1233                     .errdefer_err_code => unreachable, // never appears in a body
   1234                 };
   1235             },
   1236 
   1237             // Instructions that we know can *never* be noreturn based solely on
   1238             // their tag. We avoid needlessly checking if they are noreturn and
   1239             // continue the loop.
   1240             // We also know that they cannot be referenced later, so we avoid
   1241             // putting them into the map.
   1242             .dbg_stmt => {
   1243                 try sema.zirDbgStmt(block, inst);
   1244                 i += 1;
   1245                 continue;
   1246             },
   1247             .dbg_var_ptr => {
   1248                 try sema.zirDbgVar(block, inst, .dbg_var_ptr);
   1249                 i += 1;
   1250                 continue;
   1251             },
   1252             .dbg_var_val => {
   1253                 try sema.zirDbgVar(block, inst, .dbg_var_val);
   1254                 i += 1;
   1255                 continue;
   1256             },
   1257             .dbg_block_begin => {
   1258                 dbg_block_begins += 1;
   1259                 try sema.zirDbgBlockBegin(block);
   1260                 i += 1;
   1261                 continue;
   1262             },
   1263             .dbg_block_end => {
   1264                 dbg_block_begins -= 1;
   1265                 try sema.zirDbgBlockEnd(block);
   1266                 i += 1;
   1267                 continue;
   1268             },
   1269             .ensure_err_union_payload_void => {
   1270                 try sema.zirEnsureErrUnionPayloadVoid(block, inst);
   1271                 i += 1;
   1272                 continue;
   1273             },
   1274             .ensure_result_non_error => {
   1275                 try sema.zirEnsureResultNonError(block, inst);
   1276                 i += 1;
   1277                 continue;
   1278             },
   1279             .ensure_result_used => {
   1280                 try sema.zirEnsureResultUsed(block, inst);
   1281                 i += 1;
   1282                 continue;
   1283             },
   1284             .set_eval_branch_quota => {
   1285                 try sema.zirSetEvalBranchQuota(block, inst);
   1286                 i += 1;
   1287                 continue;
   1288             },
   1289             .atomic_store => {
   1290                 try sema.zirAtomicStore(block, inst);
   1291                 i += 1;
   1292                 continue;
   1293             },
   1294             .store => {
   1295                 try sema.zirStore(block, inst);
   1296                 i += 1;
   1297                 continue;
   1298             },
   1299             .store_node => {
   1300                 try sema.zirStoreNode(block, inst);
   1301                 i += 1;
   1302                 continue;
   1303             },
   1304             .store_to_block_ptr => {
   1305                 try sema.zirStoreToBlockPtr(block, inst);
   1306                 i += 1;
   1307                 continue;
   1308             },
   1309             .store_to_inferred_ptr => {
   1310                 try sema.zirStoreToInferredPtr(block, inst);
   1311                 i += 1;
   1312                 continue;
   1313             },
   1314             .resolve_inferred_alloc => {
   1315                 try sema.zirResolveInferredAlloc(block, inst);
   1316                 i += 1;
   1317                 continue;
   1318             },
   1319             .validate_array_init_ty => {
   1320                 try sema.validateArrayInitTy(block, inst);
   1321                 i += 1;
   1322                 continue;
   1323             },
   1324             .validate_struct_init_ty => {
   1325                 try sema.validateStructInitTy(block, inst);
   1326                 i += 1;
   1327                 continue;
   1328             },
   1329             .validate_struct_init => {
   1330                 try sema.zirValidateStructInit(block, inst);
   1331                 i += 1;
   1332                 continue;
   1333             },
   1334             .validate_array_init => {
   1335                 try sema.zirValidateArrayInit(block, inst);
   1336                 i += 1;
   1337                 continue;
   1338             },
   1339             .validate_deref => {
   1340                 try sema.zirValidateDeref(block, inst);
   1341                 i += 1;
   1342                 continue;
   1343             },
   1344             .@"export" => {
   1345                 try sema.zirExport(block, inst);
   1346                 i += 1;
   1347                 continue;
   1348             },
   1349             .export_value => {
   1350                 try sema.zirExportValue(block, inst);
   1351                 i += 1;
   1352                 continue;
   1353             },
   1354             .set_runtime_safety => {
   1355                 try sema.zirSetRuntimeSafety(block, inst);
   1356                 i += 1;
   1357                 continue;
   1358             },
   1359             .param => {
   1360                 try sema.zirParam(block, inst, false);
   1361                 i += 1;
   1362                 continue;
   1363             },
   1364             .param_comptime => {
   1365                 try sema.zirParam(block, inst, true);
   1366                 i += 1;
   1367                 continue;
   1368             },
   1369             .param_anytype => {
   1370                 try sema.zirParamAnytype(block, inst, false);
   1371                 i += 1;
   1372                 continue;
   1373             },
   1374             .param_anytype_comptime => {
   1375                 try sema.zirParamAnytype(block, inst, true);
   1376                 i += 1;
   1377                 continue;
   1378             },
   1379             .closure_capture => {
   1380                 try sema.zirClosureCapture(block, inst);
   1381                 i += 1;
   1382                 continue;
   1383             },
   1384             .memcpy => {
   1385                 try sema.zirMemcpy(block, inst);
   1386                 i += 1;
   1387                 continue;
   1388             },
   1389             .memset => {
   1390                 try sema.zirMemset(block, inst);
   1391                 i += 1;
   1392                 continue;
   1393             },
   1394             .check_comptime_control_flow => {
   1395                 if (!block.is_comptime) {
   1396                     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   1397                     const src = inst_data.src();
   1398                     const inline_block = Zir.refToIndex(inst_data.operand).?;
   1399 
   1400                     var check_block = block;
   1401                     const target_runtime_index = while (true) {
   1402                         if (check_block.inline_block == inline_block) {
   1403                             break check_block.runtime_index;
   1404                         }
   1405                         check_block = check_block.parent.?;
   1406                     };
   1407 
   1408                     if (@enumToInt(target_runtime_index) < @enumToInt(block.runtime_index)) {
   1409                         const runtime_src = block.runtime_cond orelse block.runtime_loop.?;
   1410                         const msg = msg: {
   1411                             const msg = try sema.errMsg(block, src, "comptime control flow inside runtime block", .{});
   1412                             errdefer msg.destroy(sema.gpa);
   1413 
   1414                             try sema.errNote(block, runtime_src, msg, "runtime control flow here", .{});
   1415                             break :msg msg;
   1416                         };
   1417                         return sema.failWithOwnedErrorMsg(msg);
   1418                     }
   1419                 }
   1420                 i += 1;
   1421                 continue;
   1422             },
   1423             .save_err_ret_index => {
   1424                 try sema.zirSaveErrRetIndex(block, inst);
   1425                 i += 1;
   1426                 continue;
   1427             },
   1428             .restore_err_ret_index => {
   1429                 try sema.zirRestoreErrRetIndex(block, inst);
   1430                 i += 1;
   1431                 continue;
   1432             },
   1433 
   1434             // Special case instructions to handle comptime control flow.
   1435             .@"break" => {
   1436                 if (block.is_comptime) {
   1437                     break inst; // same as break_inline
   1438                 } else {
   1439                     break sema.zirBreak(block, inst);
   1440                 }
   1441             },
   1442             .break_inline => {
   1443                 if (block.is_comptime) {
   1444                     break inst;
   1445                 } else {
   1446                     sema.comptime_break_inst = inst;
   1447                     return error.ComptimeBreak;
   1448                 }
   1449             },
   1450             .repeat => {
   1451                 if (block.is_comptime) {
   1452                     // Send comptime control flow back to the beginning of this block.
   1453                     const src = LazySrcLoc.nodeOffset(datas[inst].node);
   1454                     try sema.emitBackwardBranch(block, src);
   1455                     if (wip_captures.scope.captures.count() != orig_captures) {
   1456                         // We need to construct new capture scopes for the next loop iteration so it
   1457                         // can capture values without clobbering the earlier iteration's captures.
   1458                         // At first, we reused the parent capture scope as an optimization, but for
   1459                         // successive scopes we have to create new ones as children of the parent
   1460                         // scope.
   1461                         try wip_captures.reset(parent_capture_scope);
   1462                         block.wip_capture_scope = wip_captures.scope;
   1463                         orig_captures = 0;
   1464                     }
   1465                     i = 0;
   1466                     continue;
   1467                 } else {
   1468                     break always_noreturn;
   1469                 }
   1470             },
   1471             .repeat_inline => {
   1472                 // Send comptime control flow back to the beginning of this block.
   1473                 const src = LazySrcLoc.nodeOffset(datas[inst].node);
   1474                 try sema.emitBackwardBranch(block, src);
   1475                 if (wip_captures.scope.captures.count() != orig_captures) {
   1476                     // We need to construct new capture scopes for the next loop iteration so it
   1477                     // can capture values without clobbering the earlier iteration's captures.
   1478                     // At first, we reused the parent capture scope as an optimization, but for
   1479                     // successive scopes we have to create new ones as children of the parent
   1480                     // scope.
   1481                     try wip_captures.reset(parent_capture_scope);
   1482                     block.wip_capture_scope = wip_captures.scope;
   1483                     orig_captures = 0;
   1484                 }
   1485                 i = 0;
   1486                 continue;
   1487             },
   1488             .loop => blk: {
   1489                 if (!block.is_comptime) break :blk try sema.zirLoop(block, inst);
   1490                 // Same as `block_inline`. TODO https://github.com/ziglang/zig/issues/8220
   1491                 const inst_data = datas[inst].pl_node;
   1492                 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
   1493                 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
   1494                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
   1495                     break always_noreturn;
   1496                 if (inst == break_data.block_inst) {
   1497                     break :blk try sema.resolveInst(break_data.operand);
   1498                 } else {
   1499                     break break_data.inst;
   1500                 }
   1501             },
   1502             .block, .block_comptime => blk: {
   1503                 if (!block.is_comptime) {
   1504                     break :blk try sema.zirBlock(block, inst, tags[inst] == .block_comptime);
   1505                 }
   1506                 // Same as `block_inline`. TODO https://github.com/ziglang/zig/issues/8220
   1507                 const inst_data = datas[inst].pl_node;
   1508                 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
   1509                 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
   1510                 // If this block contains a function prototype, we need to reset the
   1511                 // current list of parameters and restore it later.
   1512                 // Note: this probably needs to be resolved in a more general manner.
   1513                 const prev_params = block.params;
   1514                 block.params = .{};
   1515                 defer {
   1516                     block.params.deinit(sema.gpa);
   1517                     block.params = prev_params;
   1518                 }
   1519                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
   1520                     break always_noreturn;
   1521                 if (inst == break_data.block_inst) {
   1522                     break :blk try sema.resolveInst(break_data.operand);
   1523                 } else {
   1524                     break break_data.inst;
   1525                 }
   1526             },
   1527             .block_inline => blk: {
   1528                 // Directly analyze the block body without introducing a new block.
   1529                 // However, in the case of a corresponding break_inline which reaches
   1530                 // through a runtime conditional branch, we must retroactively emit
   1531                 // a block, so we remember the block index here just in case.
   1532                 const block_index = block.instructions.items.len;
   1533                 const inst_data = datas[inst].pl_node;
   1534                 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
   1535                 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
   1536                 const gpa = sema.gpa;
   1537 
   1538                 const opt_break_data = b: {
   1539                     // Create a temporary child block so that this inline block is properly
   1540                     // labeled for any .restore_err_ret_index instructions
   1541                     var child_block = block.makeSubBlock();
   1542 
   1543                     // If this block contains a function prototype, we need to reset the
   1544                     // current list of parameters and restore it later.
   1545                     // Note: this probably needs to be resolved in a more general manner.
   1546                     child_block.inline_block =
   1547                         if (tags[inline_body[inline_body.len - 1]] == .repeat_inline) inline_body[0] else inst;
   1548 
   1549                     var label: Block.Label = .{
   1550                         .zir_block = inst,
   1551                         .merges = undefined,
   1552                     };
   1553                     child_block.label = &label;
   1554                     defer child_block.params.deinit(gpa);
   1555 
   1556                     // Write these instructions directly into the parent block
   1557                     child_block.instructions = block.instructions;
   1558                     defer block.instructions = child_block.instructions;
   1559 
   1560                     break :b try sema.analyzeBodyBreak(&child_block, inline_body);
   1561                 };
   1562 
   1563                 // A runtime conditional branch that needs a post-hoc block to be
   1564                 // emitted communicates this by mapping the block index into the inst map.
   1565                 if (map.get(inst)) |new_block_ref| ph: {
   1566                     // Comptime control flow populates the map, so we don't actually know
   1567                     // if this is a post-hoc runtime block until we check the
   1568                     // post_hoc_block map.
   1569                     const new_block_inst = Air.refToIndex(new_block_ref) orelse break :ph;
   1570                     const labeled_block = sema.post_hoc_blocks.get(new_block_inst) orelse
   1571                         break :ph;
   1572 
   1573                     // In this case we need to move all the instructions starting at
   1574                     // block_index from the current block into this new one.
   1575 
   1576                     if (opt_break_data) |break_data| {
   1577                         // This is a comptime break which we now change to a runtime break
   1578                         // since it crosses a runtime branch.
   1579                         // It may pass through our currently being analyzed block_inline or it
   1580                         // may point directly to it. In the latter case, this modifies the
   1581                         // block that we are about to look up in the post_hoc_blocks map below.
   1582                         try sema.addRuntimeBreak(block, break_data);
   1583                     } else {
   1584                         // Here the comptime control flow ends with noreturn; however
   1585                         // we have runtime control flow continuing after this block.
   1586                         // This branch is therefore handled by the `i += 1; continue;`
   1587                         // logic below.
   1588                     }
   1589 
   1590                     try labeled_block.block.instructions.appendSlice(gpa, block.instructions.items[block_index..]);
   1591                     block.instructions.items.len = block_index;
   1592 
   1593                     const block_result = try sema.analyzeBlockBody(block, inst_data.src(), &labeled_block.block, &labeled_block.label.merges);
   1594                     {
   1595                         // Destroy the ad-hoc block entry so that it does not interfere with
   1596                         // the next iteration of comptime control flow, if any.
   1597                         labeled_block.destroy(gpa);
   1598                         assert(sema.post_hoc_blocks.remove(new_block_inst));
   1599                     }
   1600                     map.putAssumeCapacity(inst, block_result);
   1601                     i += 1;
   1602                     continue;
   1603                 }
   1604 
   1605                 const break_data = opt_break_data orelse break always_noreturn;
   1606                 if (inst == break_data.block_inst) {
   1607                     break :blk try sema.resolveInst(break_data.operand);
   1608                 } else {
   1609                     break break_data.inst;
   1610                 }
   1611             },
   1612             .condbr => blk: {
   1613                 if (!block.is_comptime) break sema.zirCondbr(block, inst);
   1614                 // Same as condbr_inline. TODO https://github.com/ziglang/zig/issues/8220
   1615                 const inst_data = datas[inst].pl_node;
   1616                 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
   1617                 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
   1618                 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
   1619                 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
   1620                 const cond = sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime-known") catch |err| {
   1621                     if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
   1622                     return err;
   1623                 };
   1624                 const inline_body = if (cond.val.toBool()) then_body else else_body;
   1625 
   1626                 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src);
   1627                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
   1628                     break always_noreturn;
   1629                 if (inst == break_data.block_inst) {
   1630                     break :blk try sema.resolveInst(break_data.operand);
   1631                 } else {
   1632                     break break_data.inst;
   1633                 }
   1634             },
   1635             .condbr_inline => blk: {
   1636                 const inst_data = datas[inst].pl_node;
   1637                 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
   1638                 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
   1639                 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
   1640                 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
   1641                 const cond = sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime-known") catch |err| {
   1642                     if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
   1643                     return err;
   1644                 };
   1645                 const inline_body = if (cond.val.toBool()) then_body else else_body;
   1646 
   1647                 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src);
   1648                 const old_runtime_index = block.runtime_index;
   1649                 defer block.runtime_index = old_runtime_index;
   1650                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
   1651                     break always_noreturn;
   1652                 if (inst == break_data.block_inst) {
   1653                     break :blk try sema.resolveInst(break_data.operand);
   1654                 } else {
   1655                     break break_data.inst;
   1656                 }
   1657             },
   1658             .@"try" => blk: {
   1659                 if (!block.is_comptime) break :blk try sema.zirTry(block, inst);
   1660                 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1661                 const src = inst_data.src();
   1662                 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   1663                 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
   1664                 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
   1665                 const err_union = try sema.resolveInst(extra.data.operand);
   1666                 const err_union_ty = sema.typeOf(err_union);
   1667                 if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) {
   1668                     return sema.fail(block, operand_src, "expected error union type, found '{}'", .{
   1669                         err_union_ty.fmt(mod),
   1670                     });
   1671                 }
   1672                 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);
   1673                 assert(is_non_err != .none);
   1674                 const is_non_err_val = sema.resolveConstValue(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known") catch |err| {
   1675                     if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
   1676                     return err;
   1677                 };
   1678                 if (is_non_err_val.toBool()) {
   1679                     break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false);
   1680                 }
   1681                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
   1682                     break always_noreturn;
   1683                 if (inst == break_data.block_inst) {
   1684                     break :blk try sema.resolveInst(break_data.operand);
   1685                 } else {
   1686                     break break_data.inst;
   1687                 }
   1688             },
   1689             .try_ptr => blk: {
   1690                 if (!block.is_comptime) break :blk try sema.zirTryPtr(block, inst);
   1691                 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1692                 const src = inst_data.src();
   1693                 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   1694                 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
   1695                 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
   1696                 const operand = try sema.resolveInst(extra.data.operand);
   1697                 const err_union = try sema.analyzeLoad(block, src, operand, operand_src);
   1698                 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);
   1699                 assert(is_non_err != .none);
   1700                 const is_non_err_val = sema.resolveConstValue(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known") catch |err| {
   1701                     if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
   1702                     return err;
   1703                 };
   1704                 if (is_non_err_val.toBool()) {
   1705                     break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
   1706                 }
   1707                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
   1708                     break always_noreturn;
   1709                 if (inst == break_data.block_inst) {
   1710                     break :blk try sema.resolveInst(break_data.operand);
   1711                 } else {
   1712                     break break_data.inst;
   1713                 }
   1714             },
   1715             .@"defer" => blk: {
   1716                 const inst_data = sema.code.instructions.items(.data)[inst].@"defer";
   1717                 const defer_body = sema.code.extra[inst_data.index..][0..inst_data.len];
   1718                 const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) {
   1719                     error.ComptimeBreak => sema.comptime_break_inst,
   1720                     else => |e| return e,
   1721                 };
   1722                 if (break_inst != defer_body[defer_body.len - 1]) break always_noreturn;
   1723                 break :blk Air.Inst.Ref.void_value;
   1724             },
   1725             .defer_err_code => blk: {
   1726                 const inst_data = sema.code.instructions.items(.data)[inst].defer_err_code;
   1727                 const extra = sema.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data;
   1728                 const defer_body = sema.code.extra[extra.index..][0..extra.len];
   1729                 const err_code = try sema.resolveInst(inst_data.err_code);
   1730                 map.putAssumeCapacity(extra.remapped_err_code, err_code);
   1731                 const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) {
   1732                     error.ComptimeBreak => sema.comptime_break_inst,
   1733                     else => |e| return e,
   1734                 };
   1735                 if (break_inst != defer_body[defer_body.len - 1]) break always_noreturn;
   1736                 break :blk Air.Inst.Ref.void_value;
   1737             },
   1738         };
   1739         if (sema.isNoReturn(air_inst)) {
   1740             // We're going to assume that the body itself is noreturn, so let's ensure that now
   1741             assert(block.instructions.items.len > 0);
   1742             assert(sema.isNoReturn(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1])));
   1743             break always_noreturn;
   1744         }
   1745         map.putAssumeCapacity(inst, air_inst);
   1746         i += 1;
   1747     };
   1748 
   1749     // balance out dbg_block_begins in case of early noreturn
   1750     const noreturn_inst = block.instructions.popOrNull();
   1751     while (dbg_block_begins > 0) {
   1752         dbg_block_begins -= 1;
   1753         if (block.is_comptime or mod.comp.bin_file.options.strip) continue;
   1754 
   1755         _ = try block.addInst(.{
   1756             .tag = .dbg_block_end,
   1757             .data = undefined,
   1758         });
   1759     }
   1760     if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some);
   1761 
   1762     if (!wip_captures.finalized) {
   1763         // We've updated the capture scope due to a `repeat` instruction where
   1764         // the body had a capture; finalize our child scope and reset
   1765         try wip_captures.finalize();
   1766         block.wip_capture_scope = parent_capture_scope;
   1767     }
   1768 
   1769     return result;
   1770 }
   1771 
   1772 pub fn resolveInstAllowNone(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
   1773     if (zir_ref == .none) {
   1774         return .none;
   1775     } else {
   1776         return resolveInst(sema, zir_ref);
   1777     }
   1778 }
   1779 
   1780 pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
   1781     assert(zir_ref != .none);
   1782     const i = @enumToInt(zir_ref);
   1783     // First section of indexes correspond to a set number of constant values.
   1784     // We intentionally map the same indexes to the same values between ZIR and AIR.
   1785     if (i < InternPool.static_len) return @intToEnum(Air.Inst.Ref, i);
   1786     // The last section of indexes refers to the map of ZIR => AIR.
   1787     const inst = sema.inst_map.get(i - InternPool.static_len).?;
   1788     if (inst == .generic_poison) return error.GenericPoison;
   1789     return inst;
   1790 }
   1791 
   1792 fn resolveConstBool(
   1793     sema: *Sema,
   1794     block: *Block,
   1795     src: LazySrcLoc,
   1796     zir_ref: Zir.Inst.Ref,
   1797     reason: []const u8,
   1798 ) !bool {
   1799     const air_inst = try sema.resolveInst(zir_ref);
   1800     const wanted_type = Type.bool;
   1801     const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
   1802     const val = try sema.resolveConstValue(block, src, coerced_inst, reason);
   1803     return val.toBool();
   1804 }
   1805 
   1806 pub fn resolveConstString(
   1807     sema: *Sema,
   1808     block: *Block,
   1809     src: LazySrcLoc,
   1810     zir_ref: Zir.Inst.Ref,
   1811     reason: []const u8,
   1812 ) ![]u8 {
   1813     const air_inst = try sema.resolveInst(zir_ref);
   1814     const wanted_type = Type.slice_const_u8;
   1815     const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
   1816     const val = try sema.resolveConstValue(block, src, coerced_inst, reason);
   1817     return val.toAllocatedBytes(wanted_type, sema.arena, sema.mod);
   1818 }
   1819 
   1820 pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type {
   1821     const air_inst = try sema.resolveInst(zir_ref);
   1822     assert(air_inst != .var_args_param_type);
   1823     const ty = try sema.analyzeAsType(block, src, air_inst);
   1824     if (ty.isGenericPoison()) return error.GenericPoison;
   1825     return ty;
   1826 }
   1827 
   1828 fn analyzeAsType(
   1829     sema: *Sema,
   1830     block: *Block,
   1831     src: LazySrcLoc,
   1832     air_inst: Air.Inst.Ref,
   1833 ) !Type {
   1834     const wanted_type = Type.type;
   1835     const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
   1836     const val = try sema.resolveConstValue(block, src, coerced_inst, "types must be comptime-known");
   1837     return val.toType();
   1838 }
   1839 
   1840 pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void {
   1841     const mod = sema.mod;
   1842     if (!mod.backendSupportsFeature(.error_return_trace)) return;
   1843 
   1844     assert(!block.is_comptime);
   1845     var err_trace_block = block.makeSubBlock();
   1846     defer err_trace_block.instructions.deinit(sema.gpa);
   1847 
   1848     const src: LazySrcLoc = .unneeded;
   1849 
   1850     // var addrs: [err_return_trace_addr_count]usize = undefined;
   1851     const err_return_trace_addr_count = 32;
   1852     const addr_arr_ty = try Type.array(sema.arena, err_return_trace_addr_count, null, Type.usize, mod);
   1853     const addrs_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(addr_arr_ty));
   1854 
   1855     // var st: StackTrace = undefined;
   1856     const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
   1857     const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
   1858     const st_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(stack_trace_ty));
   1859 
   1860     // st.instruction_addresses = &addrs;
   1861     const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "instruction_addresses", src, true);
   1862     try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store);
   1863 
   1864     // st.index = 0;
   1865     const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src, true);
   1866     try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, .zero_usize, src, .store);
   1867 
   1868     // @errorReturnTrace() = &st;
   1869     _ = try err_trace_block.addUnOp(.set_err_return_trace, st_ptr);
   1870 
   1871     try block.instructions.insertSlice(sema.gpa, last_arg_index, err_trace_block.instructions.items);
   1872 }
   1873 
   1874 /// May return Value Tags: `variable`, `undef`.
   1875 /// See `resolveConstValue` for an alternative.
   1876 /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned.
   1877 fn resolveValue(
   1878     sema: *Sema,
   1879     block: *Block,
   1880     src: LazySrcLoc,
   1881     air_ref: Air.Inst.Ref,
   1882     reason: []const u8,
   1883 ) CompileError!Value {
   1884     if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| {
   1885         if (val.isGenericPoison()) return error.GenericPoison;
   1886         return val;
   1887     }
   1888     return sema.failWithNeededComptime(block, src, reason);
   1889 }
   1890 
   1891 /// Value Tag `variable` will cause a compile error.
   1892 /// Value Tag `undef` may be returned.
   1893 fn resolveConstMaybeUndefVal(
   1894     sema: *Sema,
   1895     block: *Block,
   1896     src: LazySrcLoc,
   1897     inst: Air.Inst.Ref,
   1898     reason: []const u8,
   1899 ) CompileError!Value {
   1900     if (try sema.resolveMaybeUndefValAllowVariables(inst)) |val| {
   1901         switch (val.toIntern()) {
   1902             .generic_poison => return error.GenericPoison,
   1903             else => switch (sema.mod.intern_pool.indexToKey(val.toIntern())) {
   1904                 .variable => return sema.failWithNeededComptime(block, src, reason),
   1905                 else => return val,
   1906             },
   1907         }
   1908     }
   1909     return sema.failWithNeededComptime(block, src, reason);
   1910 }
   1911 
   1912 /// Will not return Value Tags: `variable`, `undef`. Instead they will emit compile errors.
   1913 /// See `resolveValue` for an alternative.
   1914 fn resolveConstValue(
   1915     sema: *Sema,
   1916     block: *Block,
   1917     src: LazySrcLoc,
   1918     air_ref: Air.Inst.Ref,
   1919     reason: []const u8,
   1920 ) CompileError!Value {
   1921     if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| {
   1922         switch (val.toIntern()) {
   1923             .generic_poison => return error.GenericPoison,
   1924             .undef => return sema.failWithUseOfUndef(block, src),
   1925             else => switch (sema.mod.intern_pool.indexToKey(val.toIntern())) {
   1926                 .undef => return sema.failWithUseOfUndef(block, src),
   1927                 .variable => return sema.failWithNeededComptime(block, src, reason),
   1928                 else => return val,
   1929             },
   1930         }
   1931     }
   1932     return sema.failWithNeededComptime(block, src, reason);
   1933 }
   1934 
   1935 /// Will not return Value Tags: `variable`, `undef`. Instead they will emit compile errors.
   1936 /// Lazy values are recursively resolved.
   1937 fn resolveConstLazyValue(
   1938     sema: *Sema,
   1939     block: *Block,
   1940     src: LazySrcLoc,
   1941     air_ref: Air.Inst.Ref,
   1942     reason: []const u8,
   1943 ) CompileError!Value {
   1944     return sema.resolveLazyValue(try sema.resolveConstValue(block, src, air_ref, reason));
   1945 }
   1946 
   1947 /// Value Tag `variable` causes this function to return `null`.
   1948 /// Value Tag `undef` causes this function to return a compile error.
   1949 fn resolveDefinedValue(
   1950     sema: *Sema,
   1951     block: *Block,
   1952     src: LazySrcLoc,
   1953     air_ref: Air.Inst.Ref,
   1954 ) CompileError!?Value {
   1955     const mod = sema.mod;
   1956     if (try sema.resolveMaybeUndefVal(air_ref)) |val| {
   1957         if (val.isUndef(mod)) {
   1958             if (block.is_typeof) return null;
   1959             return sema.failWithUseOfUndef(block, src);
   1960         }
   1961         return val;
   1962     }
   1963     return null;
   1964 }
   1965 
   1966 /// Value Tag `variable` causes this function to return `null`.
   1967 /// Value Tag `undef` causes this function to return the Value.
   1968 /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned.
   1969 fn resolveMaybeUndefVal(
   1970     sema: *Sema,
   1971     inst: Air.Inst.Ref,
   1972 ) CompileError!?Value {
   1973     const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null;
   1974     switch (val.ip_index) {
   1975         .generic_poison => return error.GenericPoison,
   1976         .none => return val,
   1977         else => switch (sema.mod.intern_pool.indexToKey(val.toIntern())) {
   1978             .variable => return null,
   1979             else => return val,
   1980         },
   1981     }
   1982 }
   1983 
   1984 /// Value Tag `variable` causes this function to return `null`.
   1985 /// Value Tag `undef` causes this function to return the Value.
   1986 /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned.
   1987 /// Lazy values are recursively resolved.
   1988 fn resolveMaybeUndefLazyVal(
   1989     sema: *Sema,
   1990     inst: Air.Inst.Ref,
   1991 ) CompileError!?Value {
   1992     return try sema.resolveLazyValue((try sema.resolveMaybeUndefVal(inst)) orelse return null);
   1993 }
   1994 
   1995 /// Value Tag `variable` results in `null`.
   1996 /// Value Tag `undef` results in the Value.
   1997 /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned.
   1998 /// Value Tag `decl_ref` and `decl_ref_mut` or any nested such value results in `null`.
   1999 /// Lazy values are recursively resolved.
   2000 fn resolveMaybeUndefValIntable(
   2001     sema: *Sema,
   2002     inst: Air.Inst.Ref,
   2003 ) CompileError!?Value {
   2004     const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null;
   2005     var check = val;
   2006     while (true) switch (check.ip_index) {
   2007         .generic_poison => return error.GenericPoison,
   2008         .none => break,
   2009         else => switch (sema.mod.intern_pool.indexToKey(check.toIntern())) {
   2010             .variable => return null,
   2011             .ptr => |ptr| switch (ptr.addr) {
   2012                 .decl, .mut_decl, .comptime_field => return null,
   2013                 .int => break,
   2014                 .eu_payload, .opt_payload => |base| check = base.toValue(),
   2015                 .elem, .field => |base_index| check = base_index.base.toValue(),
   2016             },
   2017             else => break,
   2018         },
   2019     };
   2020     return try sema.resolveLazyValue(val);
   2021 }
   2022 
   2023 /// Returns all Value tags including `variable` and `undef`.
   2024 fn resolveMaybeUndefValAllowVariables(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
   2025     var make_runtime = false;
   2026     if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(inst, &make_runtime)) |val| {
   2027         if (make_runtime) return null;
   2028         return val;
   2029     }
   2030     return null;
   2031 }
   2032 
   2033 /// Returns all Value tags including `variable`, `undef` and `runtime_value`.
   2034 fn resolveMaybeUndefValAllowVariablesMaybeRuntime(
   2035     sema: *Sema,
   2036     inst: Air.Inst.Ref,
   2037     make_runtime: *bool,
   2038 ) CompileError!?Value {
   2039     assert(inst != .none);
   2040     // First section of indexes correspond to a set number of constant values.
   2041     const int = @enumToInt(inst);
   2042     if (int < InternPool.static_len) {
   2043         return @intToEnum(InternPool.Index, int).toValue();
   2044     }
   2045 
   2046     const i = int - InternPool.static_len;
   2047     const air_tags = sema.air_instructions.items(.tag);
   2048     if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| {
   2049         if (air_tags[i] == .interned) {
   2050             const interned = sema.air_instructions.items(.data)[i].interned;
   2051             const val = interned.toValue();
   2052             if (val.getVariable(sema.mod) != null) return val;
   2053         }
   2054         return opv;
   2055     }
   2056     const air_datas = sema.air_instructions.items(.data);
   2057     const val = switch (air_tags[i]) {
   2058         .inferred_alloc => unreachable,
   2059         .inferred_alloc_comptime => unreachable,
   2060         .interned => air_datas[i].interned.toValue(),
   2061         else => return null,
   2062     };
   2063     if (val.isRuntimeValue(sema.mod)) make_runtime.* = true;
   2064     if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true;
   2065     return val;
   2066 }
   2067 
   2068 fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: []const u8) CompileError {
   2069     const msg = msg: {
   2070         const msg = try sema.errMsg(block, src, "unable to resolve comptime value", .{});
   2071         errdefer msg.destroy(sema.gpa);
   2072 
   2073         try sema.errNote(block, src, msg, "{s}", .{reason});
   2074         break :msg msg;
   2075     };
   2076     return sema.failWithOwnedErrorMsg(msg);
   2077 }
   2078 
   2079 fn failWithUseOfUndef(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError {
   2080     return sema.fail(block, src, "use of undefined value here causes undefined behavior", .{});
   2081 }
   2082 
   2083 fn failWithDivideByZero(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError {
   2084     return sema.fail(block, src, "division by zero here causes undefined behavior", .{});
   2085 }
   2086 
   2087 fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: Type, rhs_ty: Type) CompileError {
   2088     return sema.fail(block, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{
   2089         lhs_ty.fmt(sema.mod), rhs_ty.fmt(sema.mod),
   2090     });
   2091 }
   2092 
   2093 fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, optional_ty: Type) CompileError {
   2094     return sema.fail(block, src, "expected optional type, found '{}'", .{optional_ty.fmt(sema.mod)});
   2095 }
   2096 
   2097 fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
   2098     const mod = sema.mod;
   2099     const msg = msg: {
   2100         const msg = try sema.errMsg(block, src, "type '{}' does not support array initialization syntax", .{
   2101             ty.fmt(mod),
   2102         });
   2103         errdefer msg.destroy(sema.gpa);
   2104         if (ty.isSlice(mod)) {
   2105             try sema.errNote(block, src, msg, "inferred array length is specified with an underscore: '[_]{}'", .{ty.elemType2(mod).fmt(mod)});
   2106         }
   2107         break :msg msg;
   2108     };
   2109     return sema.failWithOwnedErrorMsg(msg);
   2110 }
   2111 
   2112 fn failWithStructInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
   2113     return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{
   2114         ty.fmt(sema.mod),
   2115     });
   2116 }
   2117 
   2118 fn failWithErrorSetCodeMissing(
   2119     sema: *Sema,
   2120     block: *Block,
   2121     src: LazySrcLoc,
   2122     dest_err_set_ty: Type,
   2123     src_err_set_ty: Type,
   2124 ) CompileError {
   2125     return sema.fail(block, src, "expected type '{}', found type '{}'", .{
   2126         dest_err_set_ty.fmt(sema.mod), src_err_set_ty.fmt(sema.mod),
   2127     });
   2128 }
   2129 
   2130 fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: usize) CompileError {
   2131     const mod = sema.mod;
   2132     if (int_ty.zigTypeTag(mod) == .Vector) {
   2133         const msg = msg: {
   2134             const msg = try sema.errMsg(block, src, "overflow of vector type '{}' with value '{}'", .{
   2135                 int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod),
   2136             });
   2137             errdefer msg.destroy(sema.gpa);
   2138             try sema.errNote(block, src, msg, "when computing vector element at index '{d}'", .{vector_index});
   2139             break :msg msg;
   2140         };
   2141         return sema.failWithOwnedErrorMsg(msg);
   2142     }
   2143     return sema.fail(block, src, "overflow of integer type '{}' with value '{}'", .{
   2144         int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod),
   2145     });
   2146 }
   2147 
   2148 fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazySrcLoc, container_ty: Type, field_index: usize) CompileError {
   2149     const mod = sema.mod;
   2150     const msg = msg: {
   2151         const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{});
   2152         errdefer msg.destroy(sema.gpa);
   2153 
   2154         const struct_ty = mod.typeToStruct(container_ty) orelse break :msg msg;
   2155         const default_value_src = mod.fieldSrcLoc(struct_ty.owner_decl, .{
   2156             .index = field_index,
   2157             .range = .value,
   2158         });
   2159         try mod.errNoteNonLazy(default_value_src, msg, "default value set here", .{});
   2160         break :msg msg;
   2161     };
   2162     return sema.failWithOwnedErrorMsg(msg);
   2163 }
   2164 
   2165 fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError {
   2166     const msg = msg: {
   2167         const msg = try sema.errMsg(block, src, "async has not been implemented in the self-hosted compiler yet", .{});
   2168         errdefer msg.destroy(sema.gpa);
   2169         break :msg msg;
   2170     };
   2171     return sema.failWithOwnedErrorMsg(msg);
   2172 }
   2173 
   2174 fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, object_ty: Type, field_name: []const u8) CompileError {
   2175     const mod = sema.mod;
   2176     const inner_ty = if (object_ty.isSinglePointer(mod)) object_ty.childType(mod) else object_ty;
   2177 
   2178     if (inner_ty.zigTypeTag(mod) == .Optional) opt: {
   2179         const child_ty = inner_ty.optionalChild(mod);
   2180         if (!typeSupportsFieldAccess(mod, child_ty, field_name)) break :opt;
   2181         const msg = msg: {
   2182             const msg = try sema.errMsg(block, src, "optional type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
   2183             errdefer msg.destroy(sema.gpa);
   2184             try sema.errNote(block, src, msg, "consider using '.?', 'orelse', or 'if'", .{});
   2185             break :msg msg;
   2186         };
   2187         return sema.failWithOwnedErrorMsg(msg);
   2188     } else if (inner_ty.zigTypeTag(mod) == .ErrorUnion) err: {
   2189         const child_ty = inner_ty.errorUnionPayload(mod);
   2190         if (!typeSupportsFieldAccess(mod, child_ty, field_name)) break :err;
   2191         const msg = msg: {
   2192             const msg = try sema.errMsg(block, src, "error union type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
   2193             errdefer msg.destroy(sema.gpa);
   2194             try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{});
   2195             break :msg msg;
   2196         };
   2197         return sema.failWithOwnedErrorMsg(msg);
   2198     }
   2199     return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
   2200 }
   2201 
   2202 fn typeSupportsFieldAccess(mod: *const Module, ty: Type, field_name: []const u8) bool {
   2203     switch (ty.zigTypeTag(mod)) {
   2204         .Array => return mem.eql(u8, field_name, "len"),
   2205         .Pointer => {
   2206             const ptr_info = ty.ptrInfo(mod);
   2207             if (ptr_info.size == .Slice) {
   2208                 return mem.eql(u8, field_name, "ptr") or mem.eql(u8, field_name, "len");
   2209             } else if (ptr_info.pointee_type.zigTypeTag(mod) == .Array) {
   2210                 return mem.eql(u8, field_name, "len");
   2211             } else return false;
   2212         },
   2213         .Type, .Struct, .Union => return true,
   2214         else => return false,
   2215     }
   2216 }
   2217 
   2218 /// We don't return a pointer to the new error note because the pointer
   2219 /// becomes invalid when you add another one.
   2220 fn errNote(
   2221     sema: *Sema,
   2222     block: *Block,
   2223     src: LazySrcLoc,
   2224     parent: *Module.ErrorMsg,
   2225     comptime format: []const u8,
   2226     args: anytype,
   2227 ) error{OutOfMemory}!void {
   2228     const mod = sema.mod;
   2229     const src_decl = mod.declPtr(block.src_decl);
   2230     return mod.errNoteNonLazy(src.toSrcLoc(src_decl, mod), parent, format, args);
   2231 }
   2232 
   2233 fn addFieldErrNote(
   2234     sema: *Sema,
   2235     container_ty: Type,
   2236     field_index: usize,
   2237     parent: *Module.ErrorMsg,
   2238     comptime format: []const u8,
   2239     args: anytype,
   2240 ) !void {
   2241     @setCold(true);
   2242     const mod = sema.mod;
   2243     const decl_index = container_ty.getOwnerDecl(mod);
   2244     const decl = mod.declPtr(decl_index);
   2245 
   2246     const field_src = blk: {
   2247         const tree = decl.getFileScope(mod).getTree(sema.gpa) catch |err| {
   2248             log.err("unable to load AST to report compile error: {s}", .{@errorName(err)});
   2249             break :blk decl.srcLoc(mod);
   2250         };
   2251 
   2252         const container_node = decl.relativeToNodeIndex(0);
   2253         const node_tags = tree.nodes.items(.tag);
   2254         var buf: [2]std.zig.Ast.Node.Index = undefined;
   2255         const container_decl = tree.fullContainerDecl(&buf, container_node) orelse break :blk decl.srcLoc(mod);
   2256 
   2257         var it_index: usize = 0;
   2258         for (container_decl.ast.members) |member_node| {
   2259             switch (node_tags[member_node]) {
   2260                 .container_field_init,
   2261                 .container_field_align,
   2262                 .container_field,
   2263                 => {
   2264                     if (it_index == field_index) {
   2265                         break :blk decl.nodeOffsetSrcLoc(decl.nodeIndexToRelative(member_node), mod);
   2266                     }
   2267                     it_index += 1;
   2268                 },
   2269                 else => continue,
   2270             }
   2271         }
   2272         unreachable;
   2273     };
   2274     try mod.errNoteNonLazy(field_src, parent, format, args);
   2275 }
   2276 
   2277 fn errMsg(
   2278     sema: *Sema,
   2279     block: *Block,
   2280     src: LazySrcLoc,
   2281     comptime format: []const u8,
   2282     args: anytype,
   2283 ) error{OutOfMemory}!*Module.ErrorMsg {
   2284     const mod = sema.mod;
   2285     const src_decl = mod.declPtr(block.src_decl);
   2286     return Module.ErrorMsg.create(sema.gpa, src.toSrcLoc(src_decl, mod), format, args);
   2287 }
   2288 
   2289 pub fn fail(
   2290     sema: *Sema,
   2291     block: *Block,
   2292     src: LazySrcLoc,
   2293     comptime format: []const u8,
   2294     args: anytype,
   2295 ) CompileError {
   2296     const err_msg = try sema.errMsg(block, src, format, args);
   2297     return sema.failWithOwnedErrorMsg(err_msg);
   2298 }
   2299 
   2300 fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
   2301     @setCold(true);
   2302     const gpa = sema.gpa;
   2303 
   2304     if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) {
   2305         if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation;
   2306         var wip_errors: std.zig.ErrorBundle.Wip = undefined;
   2307         wip_errors.init(gpa) catch unreachable;
   2308         Compilation.addModuleErrorMsg(&wip_errors, err_msg.*) catch unreachable;
   2309         std.debug.print("compile error during Sema:\n", .{});
   2310         var error_bundle = wip_errors.toOwnedBundle("") catch unreachable;
   2311         error_bundle.renderToStdErr(.{ .ttyconf = .no_color });
   2312         crash_report.compilerPanic("unexpected compile error occurred", null, null);
   2313     }
   2314 
   2315     const mod = sema.mod;
   2316     ref: {
   2317         errdefer err_msg.destroy(gpa);
   2318         if (err_msg.src_loc.lazy == .unneeded) {
   2319             return error.NeededSourceLocation;
   2320         }
   2321         try mod.failed_decls.ensureUnusedCapacity(gpa, 1);
   2322         try mod.failed_files.ensureUnusedCapacity(gpa, 1);
   2323 
   2324         const max_references = blk: {
   2325             if (sema.mod.comp.reference_trace) |num| break :blk num;
   2326             // Do not add multiple traces without explicit request.
   2327             if (sema.mod.failed_decls.count() != 0) break :ref;
   2328             break :blk default_reference_trace_len;
   2329         };
   2330 
   2331         var referenced_by = if (sema.func) |some| some.owner_decl else sema.owner_decl_index;
   2332         var reference_stack = std.ArrayList(Module.ErrorMsg.Trace).init(gpa);
   2333         defer reference_stack.deinit();
   2334 
   2335         // Avoid infinite loops.
   2336         var seen = std.AutoHashMap(Decl.Index, void).init(gpa);
   2337         defer seen.deinit();
   2338 
   2339         var cur_reference_trace: u32 = 0;
   2340         while (sema.mod.reference_table.get(referenced_by)) |ref| : (cur_reference_trace += 1) {
   2341             const gop = try seen.getOrPut(ref.referencer);
   2342             if (gop.found_existing) break;
   2343             if (cur_reference_trace < max_references) {
   2344                 const decl = sema.mod.declPtr(ref.referencer);
   2345                 try reference_stack.append(.{ .decl = decl.name, .src_loc = ref.src.toSrcLoc(decl, mod) });
   2346             }
   2347             referenced_by = ref.referencer;
   2348         }
   2349         if (sema.mod.comp.reference_trace == null and cur_reference_trace > 0) {
   2350             try reference_stack.append(.{
   2351                 .decl = null,
   2352                 .src_loc = undefined,
   2353                 .hidden = 0,
   2354             });
   2355         } else if (cur_reference_trace > max_references) {
   2356             try reference_stack.append(.{
   2357                 .decl = undefined,
   2358                 .src_loc = undefined,
   2359                 .hidden = cur_reference_trace - max_references,
   2360             });
   2361         }
   2362         err_msg.reference_trace = try reference_stack.toOwnedSlice();
   2363     }
   2364     if (sema.owner_func) |func| {
   2365         func.state = .sema_failure;
   2366     } else {
   2367         sema.owner_decl.analysis = .sema_failure;
   2368         sema.owner_decl.generation = mod.generation;
   2369     }
   2370     if (sema.func) |func| {
   2371         func.state = .sema_failure;
   2372     }
   2373     const gop = mod.failed_decls.getOrPutAssumeCapacity(sema.owner_decl_index);
   2374     if (gop.found_existing) {
   2375         // If there are multiple errors for the same Decl, prefer the first one added.
   2376         sema.err = null;
   2377         err_msg.destroy(gpa);
   2378     } else {
   2379         sema.err = err_msg;
   2380         gop.value_ptr.* = err_msg;
   2381     }
   2382     return error.AnalysisFail;
   2383 }
   2384 
   2385 const align_ty = Type.u29;
   2386 
   2387 fn analyzeAsAlign(
   2388     sema: *Sema,
   2389     block: *Block,
   2390     src: LazySrcLoc,
   2391     air_ref: Air.Inst.Ref,
   2392 ) !u32 {
   2393     const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, "alignment must be comptime-known");
   2394     const alignment = @intCast(u32, alignment_big); // We coerce to u16 in the prev line.
   2395     try sema.validateAlign(block, src, alignment);
   2396     return alignment;
   2397 }
   2398 
   2399 fn validateAlign(
   2400     sema: *Sema,
   2401     block: *Block,
   2402     src: LazySrcLoc,
   2403     alignment: u32,
   2404 ) !void {
   2405     if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{});
   2406     if (!std.math.isPowerOfTwo(alignment)) {
   2407         return sema.fail(block, src, "alignment value '{d}' is not a power of two", .{
   2408             alignment,
   2409         });
   2410     }
   2411 }
   2412 
   2413 pub fn resolveAlign(
   2414     sema: *Sema,
   2415     block: *Block,
   2416     src: LazySrcLoc,
   2417     zir_ref: Zir.Inst.Ref,
   2418 ) !u32 {
   2419     const air_ref = try sema.resolveInst(zir_ref);
   2420     return sema.analyzeAsAlign(block, src, air_ref);
   2421 }
   2422 
   2423 fn resolveInt(
   2424     sema: *Sema,
   2425     block: *Block,
   2426     src: LazySrcLoc,
   2427     zir_ref: Zir.Inst.Ref,
   2428     dest_ty: Type,
   2429     reason: []const u8,
   2430 ) !u64 {
   2431     const air_ref = try sema.resolveInst(zir_ref);
   2432     return sema.analyzeAsInt(block, src, air_ref, dest_ty, reason);
   2433 }
   2434 
   2435 fn analyzeAsInt(
   2436     sema: *Sema,
   2437     block: *Block,
   2438     src: LazySrcLoc,
   2439     air_ref: Air.Inst.Ref,
   2440     dest_ty: Type,
   2441     reason: []const u8,
   2442 ) !u64 {
   2443     const mod = sema.mod;
   2444     const coerced = try sema.coerce(block, dest_ty, air_ref, src);
   2445     const val = try sema.resolveConstValue(block, src, coerced, reason);
   2446     return (try val.getUnsignedIntAdvanced(mod, sema)).?;
   2447 }
   2448 
   2449 // Returns a compile error if the value has tag `variable`. See `resolveInstValue` for
   2450 // a function that does not.
   2451 pub fn resolveInstConst(
   2452     sema: *Sema,
   2453     block: *Block,
   2454     src: LazySrcLoc,
   2455     zir_ref: Zir.Inst.Ref,
   2456     reason: []const u8,
   2457 ) CompileError!TypedValue {
   2458     const air_ref = try sema.resolveInst(zir_ref);
   2459     const val = try sema.resolveConstValue(block, src, air_ref, reason);
   2460     return TypedValue{
   2461         .ty = sema.typeOf(air_ref),
   2462         .val = val,
   2463     };
   2464 }
   2465 
   2466 // Value Tag may be `undef` or `variable`.
   2467 // See `resolveInstConst` for an alternative.
   2468 pub fn resolveInstValue(
   2469     sema: *Sema,
   2470     block: *Block,
   2471     src: LazySrcLoc,
   2472     zir_ref: Zir.Inst.Ref,
   2473     reason: []const u8,
   2474 ) CompileError!TypedValue {
   2475     const air_ref = try sema.resolveInst(zir_ref);
   2476     const val = try sema.resolveValue(block, src, air_ref, reason);
   2477     return TypedValue{
   2478         .ty = sema.typeOf(air_ref),
   2479         .val = val,
   2480     };
   2481 }
   2482 
   2483 fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   2484     const tracy = trace(@src());
   2485     defer tracy.end();
   2486 
   2487     const mod = sema.mod;
   2488     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2489     const src = inst_data.src();
   2490     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   2491     const pointee_ty = try sema.resolveType(block, src, extra.lhs);
   2492     const ptr = try sema.resolveInst(extra.rhs);
   2493     const target = mod.getTarget();
   2494     const addr_space = target_util.defaultAddressSpace(target, .local);
   2495 
   2496     if (Air.refToIndex(ptr)) |ptr_inst| {
   2497         switch (sema.air_instructions.items(.tag)[ptr_inst]) {
   2498             .inferred_alloc => {
   2499                 const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc;
   2500                 const ia2 = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?;
   2501                 // Add the stored instruction to the set we will use to resolve peer types
   2502                 // for the inferred allocation.
   2503                 // This instruction will not make it to codegen; it is only to participate
   2504                 // in the `stored_inst_list` of the `inferred_alloc`.
   2505                 var trash_block = block.makeSubBlock();
   2506                 defer trash_block.instructions.deinit(sema.gpa);
   2507                 const operand = try trash_block.addBitCast(pointee_ty, .void_value);
   2508 
   2509                 const ptr_ty = try mod.ptrType(.{
   2510                     .child = pointee_ty.toIntern(),
   2511                     .flags = .{
   2512                         .alignment = ia1.alignment,
   2513                         .address_space = addr_space,
   2514                     },
   2515                 });
   2516                 const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);
   2517 
   2518                 try ia2.prongs.append(sema.arena, .{
   2519                     .stored_inst = operand,
   2520                     .placeholder = Air.refToIndex(bitcasted_ptr).?,
   2521                 });
   2522 
   2523                 return bitcasted_ptr;
   2524             },
   2525             .inferred_alloc_comptime => {
   2526                 const alignment = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime.alignment;
   2527                 // There will be only one coerce_result_ptr because we are running at comptime.
   2528                 // The alloc will turn into a Decl.
   2529                 var anon_decl = try block.startAnonDecl();
   2530                 defer anon_decl.deinit();
   2531                 const decl_index = try anon_decl.finish(
   2532                     pointee_ty,
   2533                     (try mod.intern(.{ .undef = pointee_ty.toIntern() })).toValue(),
   2534                     alignment.toByteUnits(0),
   2535                 );
   2536                 sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime.decl_index = decl_index;
   2537                 if (alignment != .none) {
   2538                     try sema.resolveTypeLayout(pointee_ty);
   2539                 }
   2540                 const ptr_ty = try mod.ptrType(.{
   2541                     .child = pointee_ty.toIntern(),
   2542                     .flags = .{
   2543                         .alignment = alignment,
   2544                         .address_space = addr_space,
   2545                     },
   2546                 });
   2547                 try sema.maybeQueueFuncBodyAnalysis(decl_index);
   2548                 return sema.addConstant(ptr_ty, (try mod.intern(.{ .ptr = .{
   2549                     .ty = ptr_ty.toIntern(),
   2550                     .addr = .{ .mut_decl = .{
   2551                         .decl = decl_index,
   2552                         .runtime_index = block.runtime_index,
   2553                     } },
   2554                 } })).toValue());
   2555             },
   2556             else => {},
   2557         }
   2558     }
   2559 
   2560     // Make a dummy store through the pointer to test the coercion.
   2561     // We will then use the generated instructions to decide what
   2562     // kind of transformations to make on the result pointer.
   2563     var trash_block = block.makeSubBlock();
   2564     trash_block.is_comptime = false;
   2565     defer trash_block.instructions.deinit(sema.gpa);
   2566 
   2567     const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr));
   2568     const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value);
   2569     return sema.coerceResultPtr(block, src, ptr, dummy_ptr, dummy_operand, &trash_block);
   2570 }
   2571 
   2572 fn coerceResultPtr(
   2573     sema: *Sema,
   2574     block: *Block,
   2575     src: LazySrcLoc,
   2576     ptr: Air.Inst.Ref,
   2577     dummy_ptr: Air.Inst.Ref,
   2578     dummy_operand: Air.Inst.Ref,
   2579     trash_block: *Block,
   2580 ) CompileError!Air.Inst.Ref {
   2581     const mod = sema.mod;
   2582     const target = sema.mod.getTarget();
   2583     const addr_space = target_util.defaultAddressSpace(target, .local);
   2584     const pointee_ty = sema.typeOf(dummy_operand);
   2585     const prev_trash_len = trash_block.instructions.items.len;
   2586 
   2587     try sema.storePtr2(trash_block, src, dummy_ptr, src, dummy_operand, src, .bitcast);
   2588 
   2589     {
   2590         const air_tags = sema.air_instructions.items(.tag);
   2591 
   2592         //std.debug.print("dummy storePtr instructions:\n", .{});
   2593         //for (trash_block.instructions.items) |item| {
   2594         //    std.debug.print("  {s}\n", .{@tagName(air_tags[item])});
   2595         //}
   2596 
   2597         // The last one is always `store`.
   2598         const trash_inst = trash_block.instructions.items[trash_block.instructions.items.len - 1];
   2599         if (air_tags[trash_inst] != .store and air_tags[trash_inst] != .store_safe) {
   2600             // no store instruction is generated for zero sized types
   2601             assert((try sema.typeHasOnePossibleValue(pointee_ty)) != null);
   2602         } else {
   2603             trash_block.instructions.items.len -= 1;
   2604             assert(trash_inst == sema.air_instructions.len - 1);
   2605             sema.air_instructions.len -= 1;
   2606         }
   2607     }
   2608 
   2609     const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
   2610         .pointee_type = pointee_ty,
   2611         .@"addrspace" = addr_space,
   2612     });
   2613 
   2614     var new_ptr = ptr;
   2615 
   2616     while (true) {
   2617         const air_tags = sema.air_instructions.items(.tag);
   2618         const air_datas = sema.air_instructions.items(.data);
   2619 
   2620         if (trash_block.instructions.items.len == prev_trash_len) {
   2621             if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
   2622                 return sema.addConstant(ptr_ty, ptr_val);
   2623             }
   2624             if (pointee_ty.eql(Type.null, sema.mod)) {
   2625                 const opt_ty = sema.typeOf(new_ptr).childType(mod);
   2626                 const null_inst = try sema.addConstant(opt_ty, Value.null);
   2627                 _ = try block.addBinOp(.store, new_ptr, null_inst);
   2628                 return Air.Inst.Ref.void_value;
   2629             }
   2630             return sema.bitCast(block, ptr_ty, new_ptr, src, null);
   2631         }
   2632 
   2633         const trash_inst = trash_block.instructions.pop();
   2634 
   2635         switch (air_tags[trash_inst]) {
   2636             // Array coerced to Vector where element size is not equal but coercible.
   2637             .aggregate_init => {
   2638                 const ty_pl = air_datas[trash_inst].ty_pl;
   2639                 const ptr_operand_ty = try Type.ptr(sema.arena, sema.mod, .{
   2640                     .pointee_type = try sema.analyzeAsType(block, src, ty_pl.ty),
   2641                     .@"addrspace" = addr_space,
   2642                 });
   2643 
   2644                 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
   2645                     return sema.addConstant(ptr_operand_ty, ptr_val);
   2646                 } else {
   2647                     return sema.bitCast(block, ptr_operand_ty, new_ptr, src, null);
   2648                 }
   2649             },
   2650             .bitcast => {
   2651                 const ty_op = air_datas[trash_inst].ty_op;
   2652                 const operand_ty = sema.typeOf(ty_op.operand);
   2653                 const ptr_operand_ty = try Type.ptr(sema.arena, sema.mod, .{
   2654                     .pointee_type = operand_ty,
   2655                     .@"addrspace" = addr_space,
   2656                 });
   2657                 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
   2658                     new_ptr = try sema.addConstant(ptr_operand_ty, try mod.getCoerced(ptr_val, ptr_operand_ty));
   2659                 } else {
   2660                     new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src, null);
   2661                 }
   2662             },
   2663             .wrap_optional => {
   2664                 new_ptr = try sema.analyzeOptionalPayloadPtr(block, src, new_ptr, false, true);
   2665             },
   2666             .wrap_errunion_err => {
   2667                 return sema.fail(block, src, "TODO coerce_result_ptr wrap_errunion_err", .{});
   2668             },
   2669             .wrap_errunion_payload => {
   2670                 new_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, new_ptr, false, true);
   2671             },
   2672             .array_to_slice => {
   2673                 return sema.fail(block, src, "TODO coerce_result_ptr array_to_slice", .{});
   2674             },
   2675             .get_union_tag => {
   2676                 return sema.fail(block, src, "TODO coerce_result_ptr get_union_tag", .{});
   2677             },
   2678             else => {
   2679                 if (std.debug.runtime_safety) {
   2680                     std.debug.panic("unexpected AIR tag for coerce_result_ptr: {}", .{
   2681                         air_tags[trash_inst],
   2682                     });
   2683                 } else {
   2684                     unreachable;
   2685                 }
   2686             },
   2687         }
   2688     }
   2689 }
   2690 
   2691 pub fn analyzeStructDecl(
   2692     sema: *Sema,
   2693     new_decl: *Decl,
   2694     inst: Zir.Inst.Index,
   2695     struct_index: Module.Struct.Index,
   2696 ) SemaError!void {
   2697     const mod = sema.mod;
   2698     const struct_obj = mod.structPtr(struct_index);
   2699     const extended = sema.code.instructions.items(.data)[inst].extended;
   2700     assert(extended.opcode == .struct_decl);
   2701     const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
   2702 
   2703     struct_obj.known_non_opv = small.known_non_opv;
   2704     if (small.known_comptime_only) {
   2705         struct_obj.requires_comptime = .yes;
   2706     }
   2707 
   2708     var extra_index: usize = extended.operand;
   2709     extra_index += @boolToInt(small.has_src_node);
   2710     extra_index += @boolToInt(small.has_fields_len);
   2711     const decls_len = if (small.has_decls_len) blk: {
   2712         const decls_len = sema.code.extra[extra_index];
   2713         extra_index += 1;
   2714         break :blk decls_len;
   2715     } else 0;
   2716 
   2717     if (small.has_backing_int) {
   2718         const backing_int_body_len = sema.code.extra[extra_index];
   2719         extra_index += 1; // backing_int_body_len
   2720         if (backing_int_body_len == 0) {
   2721             extra_index += 1; // backing_int_ref
   2722         } else {
   2723             extra_index += backing_int_body_len; // backing_int_body_inst
   2724         }
   2725     }
   2726 
   2727     _ = try mod.scanNamespace(struct_obj.namespace, extra_index, decls_len, new_decl);
   2728 }
   2729 
   2730 fn zirStructDecl(
   2731     sema: *Sema,
   2732     block: *Block,
   2733     extended: Zir.Inst.Extended.InstData,
   2734     inst: Zir.Inst.Index,
   2735 ) CompileError!Air.Inst.Ref {
   2736     const mod = sema.mod;
   2737     const gpa = sema.gpa;
   2738     const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
   2739     const src: LazySrcLoc = if (small.has_src_node) blk: {
   2740         const node_offset = @bitCast(i32, sema.code.extra[extended.operand]);
   2741         break :blk LazySrcLoc.nodeOffset(node_offset);
   2742     } else sema.src;
   2743 
   2744     var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
   2745     errdefer new_decl_arena.deinit();
   2746 
   2747     // Because these three things each reference each other, `undefined`
   2748     // placeholders are used before being set after the struct type gains an
   2749     // InternPool index.
   2750 
   2751     const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
   2752         .ty = Type.type,
   2753         .val = undefined,
   2754     }, small.name_strategy, "struct", inst);
   2755     const new_decl = mod.declPtr(new_decl_index);
   2756     new_decl.owns_tv = true;
   2757     errdefer mod.abortAnonDecl(new_decl_index);
   2758 
   2759     const new_namespace_index = try mod.createNamespace(.{
   2760         .parent = block.namespace.toOptional(),
   2761         .ty = undefined,
   2762         .file_scope = block.getFileScope(mod),
   2763     });
   2764     const new_namespace = mod.namespacePtr(new_namespace_index);
   2765     errdefer mod.destroyNamespace(new_namespace_index);
   2766 
   2767     const struct_index = try mod.createStruct(.{
   2768         .owner_decl = new_decl_index,
   2769         .fields = .{},
   2770         .zir_index = inst,
   2771         .layout = small.layout,
   2772         .status = .none,
   2773         .known_non_opv = undefined,
   2774         .is_tuple = small.is_tuple,
   2775         .namespace = new_namespace_index,
   2776     });
   2777     errdefer mod.destroyStruct(struct_index);
   2778 
   2779     const struct_ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{
   2780         .index = struct_index.toOptional(),
   2781         .namespace = new_namespace_index.toOptional(),
   2782     } });
   2783     errdefer mod.intern_pool.remove(struct_ty);
   2784 
   2785     new_decl.val = struct_ty.toValue();
   2786     new_namespace.ty = struct_ty.toType();
   2787 
   2788     try sema.analyzeStructDecl(new_decl, inst, struct_index);
   2789     try new_decl.finalizeNewArena(&new_decl_arena);
   2790     const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
   2791     try mod.finalizeAnonDecl(new_decl_index);
   2792     return decl_val;
   2793 }
   2794 
   2795 fn createAnonymousDeclTypeNamed(
   2796     sema: *Sema,
   2797     block: *Block,
   2798     src: LazySrcLoc,
   2799     typed_value: TypedValue,
   2800     name_strategy: Zir.Inst.NameStrategy,
   2801     anon_prefix: []const u8,
   2802     inst: ?Zir.Inst.Index,
   2803 ) !Decl.Index {
   2804     const mod = sema.mod;
   2805     const gpa = sema.gpa;
   2806     const namespace = block.namespace;
   2807     const src_scope = block.wip_capture_scope;
   2808     const src_decl = mod.declPtr(block.src_decl);
   2809     const src_node = src_decl.relativeToNodeIndex(src.node_offset.x);
   2810     const new_decl_index = try mod.allocateNewDecl(namespace, src_node, src_scope);
   2811     errdefer mod.destroyDecl(new_decl_index);
   2812 
   2813     switch (name_strategy) {
   2814         .anon => {
   2815             // It would be neat to have "struct:line:column" but this name has
   2816             // to survive incremental updates, where it may have been shifted down
   2817             // or up to a different line, but unchanged, and thus not unnecessarily
   2818             // semantically analyzed.
   2819             // This name is also used as the key in the parent namespace so it cannot be
   2820             // renamed.
   2821             const name = try std.fmt.allocPrintZ(gpa, "{s}__{s}_{d}", .{
   2822                 src_decl.name, anon_prefix, @enumToInt(new_decl_index),
   2823             });
   2824             errdefer gpa.free(name);
   2825             try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
   2826             return new_decl_index;
   2827         },
   2828         .parent => {
   2829             const name = try gpa.dupeZ(u8, mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0));
   2830             errdefer gpa.free(name);
   2831             try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
   2832             return new_decl_index;
   2833         },
   2834         .func => {
   2835             const fn_info = sema.code.getFnInfo(sema.func.?.zir_body_inst);
   2836             const zir_tags = sema.code.instructions.items(.tag);
   2837 
   2838             var buf = std.ArrayList(u8).init(gpa);
   2839             defer buf.deinit();
   2840             try buf.appendSlice(mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0));
   2841             try buf.appendSlice("(");
   2842 
   2843             var arg_i: usize = 0;
   2844             for (fn_info.param_body) |zir_inst| switch (zir_tags[zir_inst]) {
   2845                 .param, .param_comptime, .param_anytype, .param_anytype_comptime => {
   2846                     const arg = sema.inst_map.get(zir_inst).?;
   2847                     // If this is being called in a generic function then analyzeCall will
   2848                     // have already resolved the args and this will work.
   2849                     // If not then this is a struct type being returned from a non-generic
   2850                     // function and the name doesn't matter since it will later
   2851                     // result in a compile error.
   2852                     const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg, "") catch
   2853                         return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null);
   2854 
   2855                     if (arg_i != 0) try buf.appendSlice(",");
   2856                     try buf.writer().print("{}", .{arg_val.fmtValue(sema.typeOf(arg), sema.mod)});
   2857 
   2858                     arg_i += 1;
   2859                     continue;
   2860                 },
   2861                 else => continue,
   2862             };
   2863 
   2864             try buf.appendSlice(")");
   2865             const name = try buf.toOwnedSliceSentinel(0);
   2866             errdefer gpa.free(name);
   2867             try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
   2868             return new_decl_index;
   2869         },
   2870         .dbg_var => {
   2871             const ref = Zir.indexToRef(inst.?);
   2872             const zir_tags = sema.code.instructions.items(.tag);
   2873             const zir_data = sema.code.instructions.items(.data);
   2874             var i = inst.?;
   2875             while (i < zir_tags.len) : (i += 1) switch (zir_tags[i]) {
   2876                 .dbg_var_ptr, .dbg_var_val => {
   2877                     if (zir_data[i].str_op.operand != ref) continue;
   2878 
   2879                     const name = try std.fmt.allocPrintZ(gpa, "{s}.{s}", .{
   2880                         src_decl.name, zir_data[i].str_op.getStr(sema.code),
   2881                     });
   2882                     errdefer gpa.free(name);
   2883 
   2884                     try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
   2885                     return new_decl_index;
   2886                 },
   2887                 else => {},
   2888             };
   2889             return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null);
   2890         },
   2891     }
   2892 }
   2893 
   2894 fn zirEnumDecl(
   2895     sema: *Sema,
   2896     block: *Block,
   2897     extended: Zir.Inst.Extended.InstData,
   2898     inst: Zir.Inst.Index,
   2899 ) CompileError!Air.Inst.Ref {
   2900     const tracy = trace(@src());
   2901     defer tracy.end();
   2902 
   2903     const mod = sema.mod;
   2904     const gpa = sema.gpa;
   2905     const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small);
   2906     var extra_index: usize = extended.operand;
   2907 
   2908     const src: LazySrcLoc = if (small.has_src_node) blk: {
   2909         const node_offset = @bitCast(i32, sema.code.extra[extra_index]);
   2910         extra_index += 1;
   2911         break :blk LazySrcLoc.nodeOffset(node_offset);
   2912     } else sema.src;
   2913     const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x };
   2914 
   2915     const tag_type_ref = if (small.has_tag_type) blk: {
   2916         const tag_type_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   2917         extra_index += 1;
   2918         break :blk tag_type_ref;
   2919     } else .none;
   2920 
   2921     const body_len = if (small.has_body_len) blk: {
   2922         const body_len = sema.code.extra[extra_index];
   2923         extra_index += 1;
   2924         break :blk body_len;
   2925     } else 0;
   2926 
   2927     const fields_len = if (small.has_fields_len) blk: {
   2928         const fields_len = sema.code.extra[extra_index];
   2929         extra_index += 1;
   2930         break :blk fields_len;
   2931     } else 0;
   2932 
   2933     const decls_len = if (small.has_decls_len) blk: {
   2934         const decls_len = sema.code.extra[extra_index];
   2935         extra_index += 1;
   2936         break :blk decls_len;
   2937     } else 0;
   2938 
   2939     // Because these three things each reference each other, `undefined`
   2940     // placeholders are used before being set after the enum type gains an
   2941     // InternPool index.
   2942 
   2943     var done = false;
   2944     const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
   2945         .ty = Type.type,
   2946         .val = undefined,
   2947     }, small.name_strategy, "enum", inst);
   2948     const new_decl = mod.declPtr(new_decl_index);
   2949     new_decl.owns_tv = true;
   2950     errdefer if (!done) mod.abortAnonDecl(new_decl_index);
   2951 
   2952     const new_namespace_index = try mod.createNamespace(.{
   2953         .parent = block.namespace.toOptional(),
   2954         .ty = undefined,
   2955         .file_scope = block.getFileScope(mod),
   2956     });
   2957     const new_namespace = mod.namespacePtr(new_namespace_index);
   2958     errdefer if (!done) mod.destroyNamespace(new_namespace_index);
   2959 
   2960     extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
   2961 
   2962     const body = sema.code.extra[extra_index..][0..body_len];
   2963     extra_index += body.len;
   2964 
   2965     const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
   2966     const body_end = extra_index;
   2967     extra_index += bit_bags_count;
   2968 
   2969     const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
   2970         if (bag != 0) break true;
   2971     } else false;
   2972 
   2973     const incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{
   2974         .decl = new_decl_index,
   2975         .namespace = new_namespace_index.toOptional(),
   2976         .fields_len = fields_len,
   2977         .has_values = any_values,
   2978         .tag_mode = if (small.nonexhaustive)
   2979             .nonexhaustive
   2980         else if (tag_type_ref == .none)
   2981             .auto
   2982         else
   2983             .explicit,
   2984     });
   2985     errdefer if (!done) mod.intern_pool.remove(incomplete_enum.index);
   2986 
   2987     new_decl.val = incomplete_enum.index.toValue();
   2988     new_namespace.ty = incomplete_enum.index.toType();
   2989 
   2990     const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index);
   2991     try mod.finalizeAnonDecl(new_decl_index);
   2992     done = true;
   2993 
   2994     const int_tag_ty = ty: {
   2995         // We create a block for the field type instructions because they
   2996         // may need to reference Decls from inside the enum namespace.
   2997         // Within the field type, default value, and alignment expressions, the "owner decl"
   2998         // should be the enum itself.
   2999 
   3000         const prev_owner_decl = sema.owner_decl;
   3001         const prev_owner_decl_index = sema.owner_decl_index;
   3002         sema.owner_decl = new_decl;
   3003         sema.owner_decl_index = new_decl_index;
   3004         defer {
   3005             sema.owner_decl = prev_owner_decl;
   3006             sema.owner_decl_index = prev_owner_decl_index;
   3007         }
   3008 
   3009         const prev_owner_func = sema.owner_func;
   3010         const prev_owner_func_index = sema.owner_func_index;
   3011         sema.owner_func = null;
   3012         sema.owner_func_index = .none;
   3013         defer sema.owner_func = prev_owner_func;
   3014         defer sema.owner_func_index = prev_owner_func_index;
   3015 
   3016         const prev_func = sema.func;
   3017         const prev_func_index = sema.func_index;
   3018         sema.func = null;
   3019         sema.func_index = .none;
   3020         defer sema.func = prev_func;
   3021         defer sema.func_index = prev_func_index;
   3022 
   3023         var wip_captures = try WipCaptureScope.init(gpa, new_decl.src_scope);
   3024         defer wip_captures.deinit();
   3025 
   3026         var enum_block: Block = .{
   3027             .parent = null,
   3028             .sema = sema,
   3029             .src_decl = new_decl_index,
   3030             .namespace = new_namespace_index,
   3031             .wip_capture_scope = wip_captures.scope,
   3032             .instructions = .{},
   3033             .inlining = null,
   3034             .is_comptime = true,
   3035         };
   3036         defer enum_block.instructions.deinit(sema.gpa);
   3037 
   3038         if (body.len != 0) {
   3039             try sema.analyzeBody(&enum_block, body);
   3040         }
   3041 
   3042         try wip_captures.finalize();
   3043 
   3044         if (tag_type_ref != .none) {
   3045             const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref);
   3046             if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) {
   3047                 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)});
   3048             }
   3049             incomplete_enum.setTagType(&mod.intern_pool, ty.toIntern());
   3050             break :ty ty;
   3051         } else if (fields_len == 0) {
   3052             break :ty try mod.intType(.unsigned, 0);
   3053         } else {
   3054             const bits = std.math.log2_int_ceil(usize, fields_len);
   3055             break :ty try mod.intType(.unsigned, bits);
   3056         }
   3057     };
   3058 
   3059     if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {
   3060         if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(mod)) {
   3061             return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
   3062         }
   3063     }
   3064 
   3065     var bit_bag_index: usize = body_end;
   3066     var cur_bit_bag: u32 = undefined;
   3067     var field_i: u32 = 0;
   3068     var last_tag_val: ?Value = null;
   3069     while (field_i < fields_len) : (field_i += 1) {
   3070         if (field_i % 32 == 0) {
   3071             cur_bit_bag = sema.code.extra[bit_bag_index];
   3072             bit_bag_index += 1;
   3073         }
   3074         const has_tag_value = @truncate(u1, cur_bit_bag) != 0;
   3075         cur_bit_bag >>= 1;
   3076 
   3077         const field_name_zir = sema.code.nullTerminatedString(sema.code.extra[extra_index]);
   3078         extra_index += 1;
   3079 
   3080         // doc comment
   3081         extra_index += 1;
   3082 
   3083         const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir);
   3084         if (try incomplete_enum.addFieldName(&mod.intern_pool, gpa, field_name)) |other_index| {
   3085             const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
   3086             const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
   3087             const msg = msg: {
   3088                 const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name_zir});
   3089                 errdefer msg.destroy(gpa);
   3090                 try sema.errNote(block, other_field_src, msg, "other field here", .{});
   3091                 break :msg msg;
   3092             };
   3093             return sema.failWithOwnedErrorMsg(msg);
   3094         }
   3095 
   3096         if (has_tag_value) {
   3097             const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   3098             extra_index += 1;
   3099             const tag_inst = try sema.resolveInst(tag_val_ref);
   3100             const tag_val = sema.resolveConstValue(block, .unneeded, tag_inst, "") catch |err| switch (err) {
   3101                 error.NeededSourceLocation => {
   3102                     const value_src = mod.fieldSrcLoc(new_decl_index, .{
   3103                         .index = field_i,
   3104                         .range = .value,
   3105                     }).lazy;
   3106                     _ = try sema.resolveConstValue(block, value_src, tag_inst, "enum tag value must be comptime-known");
   3107                     unreachable;
   3108                 },
   3109                 else => |e| return e,
   3110             };
   3111             last_tag_val = tag_val;
   3112             if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, tag_val.toIntern())) |other_index| {
   3113                 const value_src = mod.fieldSrcLoc(new_decl_index, .{
   3114                     .index = field_i,
   3115                     .range = .value,
   3116                 }).lazy;
   3117                 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
   3118                 const msg = msg: {
   3119                     const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{tag_val.fmtValue(int_tag_ty, sema.mod)});
   3120                     errdefer msg.destroy(gpa);
   3121                     try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
   3122                     break :msg msg;
   3123                 };
   3124                 return sema.failWithOwnedErrorMsg(msg);
   3125             }
   3126         } else if (any_values) {
   3127             const tag_val = if (last_tag_val) |val|
   3128                 try sema.intAdd(val, try mod.intValue(int_tag_ty, 1), int_tag_ty)
   3129             else
   3130                 try mod.intValue(int_tag_ty, 0);
   3131             last_tag_val = tag_val;
   3132             if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, tag_val.toIntern())) |other_index| {
   3133                 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
   3134                 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
   3135                 const msg = msg: {
   3136                     const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(int_tag_ty, sema.mod)});
   3137                     errdefer msg.destroy(gpa);
   3138                     try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
   3139                     break :msg msg;
   3140                 };
   3141                 return sema.failWithOwnedErrorMsg(msg);
   3142             }
   3143         } else {
   3144             last_tag_val = try mod.intValue(int_tag_ty, field_i);
   3145         }
   3146 
   3147         if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) {
   3148             const value_src = mod.fieldSrcLoc(new_decl_index, .{
   3149                 .index = field_i,
   3150                 .range = if (has_tag_value) .value else .name,
   3151             }).lazy;
   3152             const msg = try sema.errMsg(block, value_src, "enumeration value '{}' too large for type '{}'", .{
   3153                 last_tag_val.?.fmtValue(int_tag_ty, mod), int_tag_ty.fmt(mod),
   3154             });
   3155             return sema.failWithOwnedErrorMsg(msg);
   3156         }
   3157     }
   3158     return decl_val;
   3159 }
   3160 
   3161 fn zirUnionDecl(
   3162     sema: *Sema,
   3163     block: *Block,
   3164     extended: Zir.Inst.Extended.InstData,
   3165     inst: Zir.Inst.Index,
   3166 ) CompileError!Air.Inst.Ref {
   3167     const tracy = trace(@src());
   3168     defer tracy.end();
   3169 
   3170     const mod = sema.mod;
   3171     const gpa = sema.gpa;
   3172     const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
   3173     var extra_index: usize = extended.operand;
   3174 
   3175     const src: LazySrcLoc = if (small.has_src_node) blk: {
   3176         const node_offset = @bitCast(i32, sema.code.extra[extra_index]);
   3177         extra_index += 1;
   3178         break :blk LazySrcLoc.nodeOffset(node_offset);
   3179     } else sema.src;
   3180 
   3181     extra_index += @boolToInt(small.has_tag_type);
   3182     extra_index += @boolToInt(small.has_body_len);
   3183     extra_index += @boolToInt(small.has_fields_len);
   3184 
   3185     const decls_len = if (small.has_decls_len) blk: {
   3186         const decls_len = sema.code.extra[extra_index];
   3187         extra_index += 1;
   3188         break :blk decls_len;
   3189     } else 0;
   3190 
   3191     var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
   3192     errdefer new_decl_arena.deinit();
   3193 
   3194     // Because these three things each reference each other, `undefined`
   3195     // placeholders are used before being set after the union type gains an
   3196     // InternPool index.
   3197 
   3198     const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
   3199         .ty = Type.type,
   3200         .val = undefined,
   3201     }, small.name_strategy, "union", inst);
   3202     const new_decl = mod.declPtr(new_decl_index);
   3203     new_decl.owns_tv = true;
   3204     errdefer mod.abortAnonDecl(new_decl_index);
   3205 
   3206     const new_namespace_index = try mod.createNamespace(.{
   3207         .parent = block.namespace.toOptional(),
   3208         .ty = undefined,
   3209         .file_scope = block.getFileScope(mod),
   3210     });
   3211     const new_namespace = mod.namespacePtr(new_namespace_index);
   3212     errdefer mod.destroyNamespace(new_namespace_index);
   3213 
   3214     const union_index = try mod.createUnion(.{
   3215         .owner_decl = new_decl_index,
   3216         .tag_ty = Type.null,
   3217         .fields = .{},
   3218         .zir_index = inst,
   3219         .layout = small.layout,
   3220         .status = .none,
   3221         .namespace = new_namespace_index,
   3222     });
   3223     errdefer mod.destroyUnion(union_index);
   3224 
   3225     const union_ty = try mod.intern_pool.get(gpa, .{ .union_type = .{
   3226         .index = union_index,
   3227         .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
   3228             .tagged
   3229         else if (small.layout != .Auto)
   3230             .none
   3231         else switch (block.sema.mod.optimizeMode()) {
   3232             .Debug, .ReleaseSafe => .safety,
   3233             .ReleaseFast, .ReleaseSmall => .none,
   3234         },
   3235     } });
   3236     errdefer mod.intern_pool.remove(union_ty);
   3237 
   3238     new_decl.val = union_ty.toValue();
   3239     new_namespace.ty = union_ty.toType();
   3240 
   3241     _ = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
   3242 
   3243     try new_decl.finalizeNewArena(&new_decl_arena);
   3244     const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
   3245     try mod.finalizeAnonDecl(new_decl_index);
   3246     return decl_val;
   3247 }
   3248 
   3249 fn zirOpaqueDecl(
   3250     sema: *Sema,
   3251     block: *Block,
   3252     extended: Zir.Inst.Extended.InstData,
   3253     inst: Zir.Inst.Index,
   3254 ) CompileError!Air.Inst.Ref {
   3255     const tracy = trace(@src());
   3256     defer tracy.end();
   3257 
   3258     const mod = sema.mod;
   3259     const gpa = sema.gpa;
   3260     const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small);
   3261     var extra_index: usize = extended.operand;
   3262 
   3263     const src: LazySrcLoc = if (small.has_src_node) blk: {
   3264         const node_offset = @bitCast(i32, sema.code.extra[extra_index]);
   3265         extra_index += 1;
   3266         break :blk LazySrcLoc.nodeOffset(node_offset);
   3267     } else sema.src;
   3268 
   3269     const decls_len = if (small.has_decls_len) blk: {
   3270         const decls_len = sema.code.extra[extra_index];
   3271         extra_index += 1;
   3272         break :blk decls_len;
   3273     } else 0;
   3274 
   3275     var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
   3276     errdefer new_decl_arena.deinit();
   3277 
   3278     // Because these three things each reference each other, `undefined`
   3279     // placeholders are used in two places before being set after the opaque
   3280     // type gains an InternPool index.
   3281 
   3282     const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
   3283         .ty = Type.type,
   3284         .val = undefined,
   3285     }, small.name_strategy, "opaque", inst);
   3286     const new_decl = mod.declPtr(new_decl_index);
   3287     new_decl.owns_tv = true;
   3288     errdefer mod.abortAnonDecl(new_decl_index);
   3289 
   3290     const new_namespace_index = try mod.createNamespace(.{
   3291         .parent = block.namespace.toOptional(),
   3292         .ty = undefined,
   3293         .file_scope = block.getFileScope(mod),
   3294     });
   3295     const new_namespace = mod.namespacePtr(new_namespace_index);
   3296     errdefer mod.destroyNamespace(new_namespace_index);
   3297 
   3298     const opaque_ty = try mod.intern(.{ .opaque_type = .{
   3299         .decl = new_decl_index,
   3300         .namespace = new_namespace_index,
   3301     } });
   3302     errdefer mod.intern_pool.remove(opaque_ty);
   3303 
   3304     new_decl.val = opaque_ty.toValue();
   3305     new_namespace.ty = opaque_ty.toType();
   3306 
   3307     extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
   3308 
   3309     try new_decl.finalizeNewArena(&new_decl_arena);
   3310     const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
   3311     try mod.finalizeAnonDecl(new_decl_index);
   3312     return decl_val;
   3313 }
   3314 
   3315 fn zirErrorSetDecl(
   3316     sema: *Sema,
   3317     block: *Block,
   3318     inst: Zir.Inst.Index,
   3319     name_strategy: Zir.Inst.NameStrategy,
   3320 ) CompileError!Air.Inst.Ref {
   3321     const tracy = trace(@src());
   3322     defer tracy.end();
   3323 
   3324     const mod = sema.mod;
   3325     const gpa = sema.gpa;
   3326     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   3327     const src = inst_data.src();
   3328     const extra = sema.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index);
   3329 
   3330     var names: Module.Fn.InferredErrorSet.NameMap = .{};
   3331     try names.ensureUnusedCapacity(sema.arena, extra.data.fields_len);
   3332 
   3333     var extra_index = @intCast(u32, extra.end);
   3334     const extra_index_end = extra_index + (extra.data.fields_len * 2);
   3335     while (extra_index < extra_index_end) : (extra_index += 2) { // +2 to skip over doc_string
   3336         const str_index = sema.code.extra[extra_index];
   3337         const name = sema.code.nullTerminatedString(str_index);
   3338         const kv = try mod.getErrorValue(name);
   3339         const name_ip = try mod.intern_pool.getOrPutString(gpa, kv.key);
   3340         const result = names.getOrPutAssumeCapacity(name_ip);
   3341         assert(!result.found_existing); // verified in AstGen
   3342     }
   3343 
   3344     const error_set_ty = try mod.errorSetFromUnsortedNames(names.keys());
   3345 
   3346     const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
   3347         .ty = Type.type,
   3348         .val = error_set_ty.toValue(),
   3349     }, name_strategy, "error", inst);
   3350     const new_decl = mod.declPtr(new_decl_index);
   3351     new_decl.owns_tv = true;
   3352     errdefer mod.abortAnonDecl(new_decl_index);
   3353 
   3354     const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
   3355     try mod.finalizeAnonDecl(new_decl_index);
   3356     return decl_val;
   3357 }
   3358 
   3359 fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
   3360     const tracy = trace(@src());
   3361     defer tracy.end();
   3362 
   3363     if (block.is_comptime or try sema.typeRequiresComptime(sema.fn_ret_ty)) {
   3364         const fn_ret_ty = try sema.resolveTypeFields(sema.fn_ret_ty);
   3365         return sema.analyzeComptimeAlloc(block, fn_ret_ty, 0);
   3366     }
   3367 
   3368     const target = sema.mod.getTarget();
   3369     const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
   3370         .pointee_type = sema.fn_ret_ty,
   3371         .@"addrspace" = target_util.defaultAddressSpace(target, .local),
   3372     });
   3373 
   3374     if (block.inlining != null) {
   3375         // We are inlining a function call; this should be emitted as an alloc, not a ret_ptr.
   3376         // TODO when functions gain result location support, the inlining struct in
   3377         // Block should contain the return pointer, and we would pass that through here.
   3378         return block.addTy(.alloc, ptr_type);
   3379     }
   3380 
   3381     return block.addTy(.ret_ptr, ptr_type);
   3382 }
   3383 
   3384 fn zirRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   3385     const tracy = trace(@src());
   3386     defer tracy.end();
   3387 
   3388     const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
   3389     const operand = try sema.resolveInst(inst_data.operand);
   3390     return sema.analyzeRef(block, inst_data.src(), operand);
   3391 }
   3392 
   3393 fn zirEnsureResultUsed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   3394     const tracy = trace(@src());
   3395     defer tracy.end();
   3396 
   3397     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3398     const operand = try sema.resolveInst(inst_data.operand);
   3399     const src = inst_data.src();
   3400 
   3401     return sema.ensureResultUsed(block, sema.typeOf(operand), src);
   3402 }
   3403 
   3404 fn ensureResultUsed(
   3405     sema: *Sema,
   3406     block: *Block,
   3407     ty: Type,
   3408     src: LazySrcLoc,
   3409 ) CompileError!void {
   3410     const mod = sema.mod;
   3411     switch (ty.zigTypeTag(mod)) {
   3412         .Void, .NoReturn => return,
   3413         .ErrorSet, .ErrorUnion => {
   3414             const msg = msg: {
   3415                 const msg = try sema.errMsg(block, src, "error is ignored", .{});
   3416                 errdefer msg.destroy(sema.gpa);
   3417                 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{});
   3418                 break :msg msg;
   3419             };
   3420             return sema.failWithOwnedErrorMsg(msg);
   3421         },
   3422         else => {
   3423             const msg = msg: {
   3424                 const msg = try sema.errMsg(block, src, "value of type '{}' ignored", .{ty.fmt(sema.mod)});
   3425                 errdefer msg.destroy(sema.gpa);
   3426                 try sema.errNote(block, src, msg, "all non-void values must be used", .{});
   3427                 try sema.errNote(block, src, msg, "this error can be suppressed by assigning the value to '_'", .{});
   3428                 break :msg msg;
   3429             };
   3430             return sema.failWithOwnedErrorMsg(msg);
   3431         },
   3432     }
   3433 }
   3434 
   3435 fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   3436     const tracy = trace(@src());
   3437     defer tracy.end();
   3438 
   3439     const mod = sema.mod;
   3440     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3441     const operand = try sema.resolveInst(inst_data.operand);
   3442     const src = inst_data.src();
   3443     const operand_ty = sema.typeOf(operand);
   3444     switch (operand_ty.zigTypeTag(mod)) {
   3445         .ErrorSet, .ErrorUnion => {
   3446             const msg = msg: {
   3447                 const msg = try sema.errMsg(block, src, "error is discarded", .{});
   3448                 errdefer msg.destroy(sema.gpa);
   3449                 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{});
   3450                 break :msg msg;
   3451             };
   3452             return sema.failWithOwnedErrorMsg(msg);
   3453         },
   3454         else => return,
   3455     }
   3456 }
   3457 
   3458 fn zirEnsureErrUnionPayloadVoid(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   3459     const tracy = trace(@src());
   3460     defer tracy.end();
   3461 
   3462     const mod = sema.mod;
   3463     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3464     const src = inst_data.src();
   3465     const operand = try sema.resolveInst(inst_data.operand);
   3466     const operand_ty = sema.typeOf(operand);
   3467     const err_union_ty = if (operand_ty.zigTypeTag(mod) == .Pointer)
   3468         operand_ty.childType(mod)
   3469     else
   3470         operand_ty;
   3471     if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) return;
   3472     const payload_ty = err_union_ty.errorUnionPayload(mod).zigTypeTag(mod);
   3473     if (payload_ty != .Void and payload_ty != .NoReturn) {
   3474         const msg = msg: {
   3475             const msg = try sema.errMsg(block, src, "error union payload is ignored", .{});
   3476             errdefer msg.destroy(sema.gpa);
   3477             try sema.errNote(block, src, msg, "payload value can be explicitly ignored with '|_|'", .{});
   3478             break :msg msg;
   3479         };
   3480         return sema.failWithOwnedErrorMsg(msg);
   3481     }
   3482 }
   3483 
   3484 fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   3485     const tracy = trace(@src());
   3486     defer tracy.end();
   3487 
   3488     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3489     const src = inst_data.src();
   3490     const object = try sema.resolveInst(inst_data.operand);
   3491 
   3492     return indexablePtrLen(sema, block, src, object);
   3493 }
   3494 
   3495 fn indexablePtrLen(
   3496     sema: *Sema,
   3497     block: *Block,
   3498     src: LazySrcLoc,
   3499     object: Air.Inst.Ref,
   3500 ) CompileError!Air.Inst.Ref {
   3501     const mod = sema.mod;
   3502     const object_ty = sema.typeOf(object);
   3503     const is_pointer_to = object_ty.isSinglePointer(mod);
   3504     const indexable_ty = if (is_pointer_to) object_ty.childType(mod) else object_ty;
   3505     try checkIndexable(sema, block, src, indexable_ty);
   3506     return sema.fieldVal(block, src, object, "len", src);
   3507 }
   3508 
   3509 fn indexablePtrLenOrNone(
   3510     sema: *Sema,
   3511     block: *Block,
   3512     src: LazySrcLoc,
   3513     operand: Air.Inst.Ref,
   3514 ) CompileError!Air.Inst.Ref {
   3515     const mod = sema.mod;
   3516     const operand_ty = sema.typeOf(operand);
   3517     try checkMemOperand(sema, block, src, operand_ty);
   3518     if (operand_ty.ptrSize(mod) == .Many) return .none;
   3519     return sema.fieldVal(block, src, operand, "len", src);
   3520 }
   3521 
   3522 fn zirAllocExtended(
   3523     sema: *Sema,
   3524     block: *Block,
   3525     extended: Zir.Inst.Extended.InstData,
   3526 ) CompileError!Air.Inst.Ref {
   3527     const gpa = sema.gpa;
   3528     const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand);
   3529     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = extra.data.src_node };
   3530     const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = extra.data.src_node };
   3531     const small = @bitCast(Zir.Inst.AllocExtended.Small, extended.small);
   3532 
   3533     var extra_index: usize = extra.end;
   3534 
   3535     const var_ty: Type = if (small.has_type) blk: {
   3536         const type_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   3537         extra_index += 1;
   3538         break :blk try sema.resolveType(block, ty_src, type_ref);
   3539     } else undefined;
   3540 
   3541     const alignment: u32 = if (small.has_align) blk: {
   3542         const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   3543         extra_index += 1;
   3544         const alignment = try sema.resolveAlign(block, align_src, align_ref);
   3545         break :blk alignment;
   3546     } else 0;
   3547 
   3548     if (block.is_comptime or small.is_comptime) {
   3549         if (small.has_type) {
   3550             return sema.analyzeComptimeAlloc(block, var_ty, alignment);
   3551         } else {
   3552             try sema.air_instructions.append(gpa, .{
   3553                 .tag = .inferred_alloc_comptime,
   3554                 .data = .{ .inferred_alloc_comptime = .{
   3555                     .decl_index = undefined,
   3556                     .alignment = InternPool.Alignment.fromByteUnits(alignment),
   3557                     .is_const = small.is_const,
   3558                 } },
   3559             });
   3560             return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
   3561         }
   3562     }
   3563 
   3564     if (small.has_type) {
   3565         if (!small.is_const) {
   3566             try sema.validateVarType(block, ty_src, var_ty, false);
   3567         }
   3568         const target = sema.mod.getTarget();
   3569         try sema.resolveTypeLayout(var_ty);
   3570         const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
   3571             .pointee_type = var_ty,
   3572             .@"align" = alignment,
   3573             .@"addrspace" = target_util.defaultAddressSpace(target, .local),
   3574         });
   3575         return block.addTy(.alloc, ptr_type);
   3576     }
   3577 
   3578     const result_index = try block.addInstAsIndex(.{
   3579         .tag = .inferred_alloc,
   3580         .data = .{ .inferred_alloc = .{
   3581             .alignment = InternPool.Alignment.fromByteUnits(alignment),
   3582             .is_const = small.is_const,
   3583         } },
   3584     });
   3585     try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{});
   3586     return Air.indexToRef(result_index);
   3587 }
   3588 
   3589 fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   3590     const tracy = trace(@src());
   3591     defer tracy.end();
   3592 
   3593     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3594     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
   3595     const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
   3596     return sema.analyzeComptimeAlloc(block, var_ty, 0);
   3597 }
   3598 
   3599 fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   3600     const mod = sema.mod;
   3601     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3602     const alloc = try sema.resolveInst(inst_data.operand);
   3603     const alloc_ty = sema.typeOf(alloc);
   3604 
   3605     var ptr_info = alloc_ty.ptrInfo(mod);
   3606     const elem_ty = ptr_info.pointee_type;
   3607 
   3608     // Detect if all stores to an `.alloc` were comptime-known.
   3609     ct: {
   3610         var search_index: usize = block.instructions.items.len;
   3611         const air_tags = sema.air_instructions.items(.tag);
   3612         const air_datas = sema.air_instructions.items(.data);
   3613 
   3614         const store_inst = while (true) {
   3615             if (search_index == 0) break :ct;
   3616             search_index -= 1;
   3617 
   3618             const candidate = block.instructions.items[search_index];
   3619             switch (air_tags[candidate]) {
   3620                 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
   3621                 .store, .store_safe => break candidate,
   3622                 else => break :ct,
   3623             }
   3624         };
   3625 
   3626         while (true) {
   3627             if (search_index == 0) break :ct;
   3628             search_index -= 1;
   3629 
   3630             const candidate = block.instructions.items[search_index];
   3631             switch (air_tags[candidate]) {
   3632                 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
   3633                 .alloc => {
   3634                     if (Air.indexToRef(candidate) != alloc) break :ct;
   3635                     break;
   3636                 },
   3637                 else => break :ct,
   3638             }
   3639         }
   3640 
   3641         const store_op = air_datas[store_inst].bin_op;
   3642         const store_val = (try sema.resolveMaybeUndefVal(store_op.rhs)) orelse break :ct;
   3643         if (store_op.lhs != alloc) break :ct;
   3644 
   3645         // Remove all the unnecessary runtime instructions.
   3646         block.instructions.shrinkRetainingCapacity(search_index);
   3647 
   3648         var anon_decl = try block.startAnonDecl();
   3649         defer anon_decl.deinit();
   3650         return sema.analyzeDeclRef(try anon_decl.finish(
   3651             elem_ty,
   3652             try store_val.copy(anon_decl.arena()),
   3653             ptr_info.@"align",
   3654         ));
   3655     }
   3656 
   3657     return sema.makePtrConst(block, alloc);
   3658 }
   3659 
   3660 fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Air.Inst.Ref {
   3661     const mod = sema.mod;
   3662     const alloc_ty = sema.typeOf(alloc);
   3663 
   3664     var ptr_info = alloc_ty.ptrInfo(mod);
   3665     ptr_info.mutable = false;
   3666     const const_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
   3667 
   3668     // Detect if a comptime value simply needs to have its type changed.
   3669     if (try sema.resolveMaybeUndefVal(alloc)) |val| {
   3670         return sema.addConstant(const_ptr_ty, try mod.getCoerced(val, const_ptr_ty));
   3671     }
   3672 
   3673     return block.addBitCast(const_ptr_ty, alloc);
   3674 }
   3675 
   3676 fn zirAllocInferredComptime(
   3677     sema: *Sema,
   3678     inst: Zir.Inst.Index,
   3679     is_const: bool,
   3680 ) CompileError!Air.Inst.Ref {
   3681     const gpa = sema.gpa;
   3682     const src_node = sema.code.instructions.items(.data)[inst].node;
   3683     const src = LazySrcLoc.nodeOffset(src_node);
   3684     sema.src = src;
   3685 
   3686     try sema.air_instructions.append(gpa, .{
   3687         .tag = .inferred_alloc_comptime,
   3688         .data = .{ .inferred_alloc_comptime = .{
   3689             .decl_index = undefined,
   3690             .alignment = .none,
   3691             .is_const = is_const,
   3692         } },
   3693     });
   3694     return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
   3695 }
   3696 
   3697 fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   3698     const tracy = trace(@src());
   3699     defer tracy.end();
   3700 
   3701     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3702     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
   3703     const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
   3704     if (block.is_comptime) {
   3705         return sema.analyzeComptimeAlloc(block, var_ty, 0);
   3706     }
   3707     const target = sema.mod.getTarget();
   3708     const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
   3709         .pointee_type = var_ty,
   3710         .@"addrspace" = target_util.defaultAddressSpace(target, .local),
   3711     });
   3712     try sema.queueFullTypeResolution(var_ty);
   3713     return block.addTy(.alloc, ptr_type);
   3714 }
   3715 
   3716 fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   3717     const tracy = trace(@src());
   3718     defer tracy.end();
   3719 
   3720     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3721     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
   3722     const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
   3723     if (block.is_comptime) {
   3724         return sema.analyzeComptimeAlloc(block, var_ty, 0);
   3725     }
   3726     try sema.validateVarType(block, ty_src, var_ty, false);
   3727     const target = sema.mod.getTarget();
   3728     const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
   3729         .pointee_type = var_ty,
   3730         .@"addrspace" = target_util.defaultAddressSpace(target, .local),
   3731     });
   3732     try sema.queueFullTypeResolution(var_ty);
   3733     return block.addTy(.alloc, ptr_type);
   3734 }
   3735 
   3736 fn zirAllocInferred(
   3737     sema: *Sema,
   3738     block: *Block,
   3739     inst: Zir.Inst.Index,
   3740     is_const: bool,
   3741 ) CompileError!Air.Inst.Ref {
   3742     const tracy = trace(@src());
   3743     defer tracy.end();
   3744 
   3745     const gpa = sema.gpa;
   3746     const src_node = sema.code.instructions.items(.data)[inst].node;
   3747     const src = LazySrcLoc.nodeOffset(src_node);
   3748     sema.src = src;
   3749 
   3750     if (block.is_comptime) {
   3751         try sema.air_instructions.append(gpa, .{
   3752             .tag = .inferred_alloc_comptime,
   3753             .data = .{ .inferred_alloc_comptime = .{
   3754                 .decl_index = undefined,
   3755                 .alignment = .none,
   3756                 .is_const = is_const,
   3757             } },
   3758         });
   3759         return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
   3760     }
   3761 
   3762     const result_index = try block.addInstAsIndex(.{
   3763         .tag = .inferred_alloc,
   3764         .data = .{ .inferred_alloc = .{
   3765             .alignment = .none,
   3766             .is_const = is_const,
   3767         } },
   3768     });
   3769     try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{});
   3770     return Air.indexToRef(result_index);
   3771 }
   3772 
   3773 fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   3774     const tracy = trace(@src());
   3775     defer tracy.end();
   3776 
   3777     const mod = sema.mod;
   3778     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3779     const src = inst_data.src();
   3780     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
   3781     const ptr = try sema.resolveInst(inst_data.operand);
   3782     const ptr_inst = Air.refToIndex(ptr).?;
   3783     const target = mod.getTarget();
   3784 
   3785     switch (sema.air_instructions.items(.tag)[ptr_inst]) {
   3786         .inferred_alloc_comptime => {
   3787             const iac = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime;
   3788             const decl_index = iac.decl_index;
   3789             try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
   3790 
   3791             const decl = mod.declPtr(decl_index);
   3792             if (iac.is_const) try decl.intern(mod);
   3793             const final_elem_ty = decl.ty;
   3794             const final_ptr_ty = try mod.ptrType(.{
   3795                 .child = final_elem_ty.toIntern(),
   3796                 .flags = .{
   3797                     .is_const = false,
   3798                     .alignment = iac.alignment,
   3799                     .address_space = target_util.defaultAddressSpace(target, .local),
   3800                 },
   3801             });
   3802 
   3803             try sema.maybeQueueFuncBodyAnalysis(decl_index);
   3804             // Change it to an interned.
   3805             sema.air_instructions.set(ptr_inst, .{
   3806                 .tag = .interned,
   3807                 .data = .{ .interned = try mod.intern(.{ .ptr = .{
   3808                     .ty = final_ptr_ty.toIntern(),
   3809                     .addr = if (!iac.is_const) .{ .mut_decl = .{
   3810                         .decl = decl_index,
   3811                         .runtime_index = block.runtime_index,
   3812                     } } else .{ .decl = decl_index },
   3813                 } }) },
   3814             });
   3815         },
   3816         .inferred_alloc => {
   3817             const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc;
   3818             const ia2 = sema.unresolved_inferred_allocs.fetchRemove(ptr_inst).?.value;
   3819             const peer_inst_list = ia2.prongs.items(.stored_inst);
   3820             const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none);
   3821 
   3822             const final_ptr_ty = try mod.ptrType(.{
   3823                 .child = final_elem_ty.toIntern(),
   3824                 .flags = .{
   3825                     .alignment = ia1.alignment,
   3826                     .address_space = target_util.defaultAddressSpace(target, .local),
   3827                 },
   3828             });
   3829 
   3830             if (!ia1.is_const) {
   3831                 try sema.validateVarType(block, ty_src, final_elem_ty, false);
   3832             } else ct: {
   3833                 // Detect if the value is comptime-known. In such case, the
   3834                 // last 3 AIR instructions of the block will look like this:
   3835                 //
   3836                 //   %a = inferred_alloc
   3837                 //   %b = bitcast(%a)
   3838                 //   %c = store(%b, %d)
   3839                 //
   3840                 // If `%d` is comptime-known, then we want to store the value
   3841                 // inside an anonymous Decl and then erase these three AIR
   3842                 // instructions from the block, replacing the inst_map entry
   3843                 // corresponding to the ZIR alloc instruction with a constant
   3844                 // decl_ref pointing at our new Decl.
   3845                 // dbg_stmt instructions may be interspersed into this pattern
   3846                 // which must be ignored.
   3847                 if (block.instructions.items.len < 3) break :ct;
   3848                 var search_index: usize = block.instructions.items.len;
   3849                 const air_tags = sema.air_instructions.items(.tag);
   3850                 const air_datas = sema.air_instructions.items(.data);
   3851 
   3852                 const store_inst = while (true) {
   3853                     if (search_index == 0) break :ct;
   3854                     search_index -= 1;
   3855 
   3856                     const candidate = block.instructions.items[search_index];
   3857                     switch (air_tags[candidate]) {
   3858                         .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
   3859                         .store, .store_safe => break candidate,
   3860                         else => break :ct,
   3861                     }
   3862                 };
   3863 
   3864                 const bitcast_inst = while (true) {
   3865                     if (search_index == 0) break :ct;
   3866                     search_index -= 1;
   3867 
   3868                     const candidate = block.instructions.items[search_index];
   3869                     switch (air_tags[candidate]) {
   3870                         .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
   3871                         .bitcast => break candidate,
   3872                         else => break :ct,
   3873                     }
   3874                 };
   3875 
   3876                 while (true) {
   3877                     if (search_index == 0) break :ct;
   3878                     search_index -= 1;
   3879 
   3880                     const candidate = block.instructions.items[search_index];
   3881                     if (candidate == ptr_inst) break;
   3882                     switch (air_tags[candidate]) {
   3883                         .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
   3884                         else => break :ct,
   3885                     }
   3886                 }
   3887 
   3888                 const store_op = air_datas[store_inst].bin_op;
   3889                 const store_val = (try sema.resolveMaybeUndefVal(store_op.rhs)) orelse break :ct;
   3890                 if (store_op.lhs != Air.indexToRef(bitcast_inst)) break :ct;
   3891                 if (air_datas[bitcast_inst].ty_op.operand != ptr) break :ct;
   3892 
   3893                 const new_decl_index = d: {
   3894                     var anon_decl = try block.startAnonDecl();
   3895                     defer anon_decl.deinit();
   3896                     const new_decl_index = try anon_decl.finish(
   3897                         final_elem_ty,
   3898                         try store_val.copy(anon_decl.arena()),
   3899                         ia1.alignment.toByteUnits(0),
   3900                     );
   3901                     break :d new_decl_index;
   3902                 };
   3903                 try mod.declareDeclDependency(sema.owner_decl_index, new_decl_index);
   3904 
   3905                 // Even though we reuse the constant instruction, we still remove it from the
   3906                 // block so that codegen does not see it.
   3907                 block.instructions.shrinkRetainingCapacity(search_index);
   3908                 try sema.maybeQueueFuncBodyAnalysis(new_decl_index);
   3909                 sema.air_instructions.set(ptr_inst, .{
   3910                     .tag = .interned,
   3911                     .data = .{ .interned = try mod.intern(.{ .ptr = .{
   3912                         .ty = final_ptr_ty.toIntern(),
   3913                         .addr = .{ .decl = new_decl_index },
   3914                     } }) },
   3915                 });
   3916 
   3917                 // Unless the block is comptime, `alloc_inferred` always produces
   3918                 // a runtime constant. The final inferred type needs to be
   3919                 // fully resolved so it can be lowered in codegen.
   3920                 try sema.resolveTypeFully(final_elem_ty);
   3921 
   3922                 return;
   3923             }
   3924 
   3925             try sema.queueFullTypeResolution(final_elem_ty);
   3926 
   3927             // Change it to a normal alloc.
   3928             sema.air_instructions.set(ptr_inst, .{
   3929                 .tag = .alloc,
   3930                 .data = .{ .ty = final_ptr_ty },
   3931             });
   3932 
   3933             // Now we need to go back over all the coerce_result_ptr instructions, which
   3934             // previously inserted a bitcast as a placeholder, and do the logic as if
   3935             // the new result ptr type was available.
   3936             const placeholders = ia2.prongs.items(.placeholder);
   3937             const gpa = sema.gpa;
   3938 
   3939             var trash_block = block.makeSubBlock();
   3940             trash_block.is_comptime = false;
   3941             defer trash_block.instructions.deinit(gpa);
   3942 
   3943             const mut_final_ptr_ty = try mod.ptrType(.{
   3944                 .child = final_elem_ty.toIntern(),
   3945                 .flags = .{
   3946                     .alignment = ia1.alignment,
   3947                     .address_space = target_util.defaultAddressSpace(target, .local),
   3948                 },
   3949             });
   3950             const dummy_ptr = try trash_block.addTy(.alloc, mut_final_ptr_ty);
   3951             const empty_trash_count = trash_block.instructions.items.len;
   3952 
   3953             for (peer_inst_list, placeholders) |peer_inst, placeholder_inst| {
   3954                 const sub_ptr_ty = sema.typeOf(Air.indexToRef(placeholder_inst));
   3955 
   3956                 if (mut_final_ptr_ty.eql(sub_ptr_ty, mod)) {
   3957                     // New result location type is the same as the old one; nothing
   3958                     // to do here.
   3959                     continue;
   3960                 }
   3961 
   3962                 var replacement_block = block.makeSubBlock();
   3963                 defer replacement_block.instructions.deinit(gpa);
   3964 
   3965                 const result = switch (sema.air_instructions.items(.tag)[placeholder_inst]) {
   3966                     .bitcast => result: {
   3967                         trash_block.instructions.shrinkRetainingCapacity(empty_trash_count);
   3968                         const sub_ptr = try sema.coerceResultPtr(&replacement_block, src, ptr, dummy_ptr, peer_inst, &trash_block);
   3969 
   3970                         assert(replacement_block.instructions.items.len > 0);
   3971                         break :result sub_ptr;
   3972                     },
   3973                     .store, .store_safe => result: {
   3974                         const bin_op = sema.air_instructions.items(.data)[placeholder_inst].bin_op;
   3975                         try sema.storePtr2(&replacement_block, src, bin_op.lhs, src, bin_op.rhs, src, .bitcast);
   3976                         break :result .void_value;
   3977                     },
   3978                     else => unreachable,
   3979                 };
   3980 
   3981                 // If only one instruction is produced then we can replace the bitcast
   3982                 // placeholder instruction with this instruction; no need for an entire block.
   3983                 if (replacement_block.instructions.items.len == 1) {
   3984                     const only_inst = replacement_block.instructions.items[0];
   3985                     sema.air_instructions.set(placeholder_inst, sema.air_instructions.get(only_inst));
   3986                     continue;
   3987                 }
   3988 
   3989                 // Here we replace the placeholder bitcast instruction with a block
   3990                 // that does the coerce_result_ptr logic.
   3991                 _ = try replacement_block.addBr(placeholder_inst, result);
   3992                 const ty_inst = if (result == .void_value)
   3993                     .void_type
   3994                 else
   3995                     sema.air_instructions.items(.data)[placeholder_inst].ty_op.ty;
   3996                 try sema.air_extra.ensureUnusedCapacity(
   3997                     gpa,
   3998                     @typeInfo(Air.Block).Struct.fields.len + replacement_block.instructions.items.len,
   3999                 );
   4000                 sema.air_instructions.set(placeholder_inst, .{
   4001                     .tag = .block,
   4002                     .data = .{ .ty_pl = .{
   4003                         .ty = ty_inst,
   4004                         .payload = sema.addExtraAssumeCapacity(Air.Block{
   4005                             .body_len = @intCast(u32, replacement_block.instructions.items.len),
   4006                         }),
   4007                     } },
   4008                 });
   4009                 sema.air_extra.appendSliceAssumeCapacity(replacement_block.instructions.items);
   4010             }
   4011         },
   4012         else => unreachable,
   4013     }
   4014 }
   4015 
   4016 fn zirArrayBasePtr(
   4017     sema: *Sema,
   4018     block: *Block,
   4019     inst: Zir.Inst.Index,
   4020 ) CompileError!Air.Inst.Ref {
   4021     const mod = sema.mod;
   4022     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   4023     const src = inst_data.src();
   4024 
   4025     const start_ptr = try sema.resolveInst(inst_data.operand);
   4026     var base_ptr = start_ptr;
   4027     while (true) switch (sema.typeOf(base_ptr).childType(mod).zigTypeTag(mod)) {
   4028         .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
   4029         .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
   4030         else => break,
   4031     };
   4032 
   4033     const elem_ty = sema.typeOf(base_ptr).childType(mod);
   4034     switch (elem_ty.zigTypeTag(mod)) {
   4035         .Array, .Vector => return base_ptr,
   4036         .Struct => if (elem_ty.isTuple(mod)) {
   4037             // TODO validate element count
   4038             return base_ptr;
   4039         },
   4040         else => {},
   4041     }
   4042     return sema.failWithArrayInitNotSupported(block, src, sema.typeOf(start_ptr).childType(mod));
   4043 }
   4044 
   4045 fn zirFieldBasePtr(
   4046     sema: *Sema,
   4047     block: *Block,
   4048     inst: Zir.Inst.Index,
   4049 ) CompileError!Air.Inst.Ref {
   4050     const mod = sema.mod;
   4051     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   4052     const src = inst_data.src();
   4053 
   4054     const start_ptr = try sema.resolveInst(inst_data.operand);
   4055     var base_ptr = start_ptr;
   4056     while (true) switch (sema.typeOf(base_ptr).childType(mod).zigTypeTag(mod)) {
   4057         .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
   4058         .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
   4059         else => break,
   4060     };
   4061 
   4062     const elem_ty = sema.typeOf(base_ptr).childType(mod);
   4063     switch (elem_ty.zigTypeTag(mod)) {
   4064         .Struct, .Union => return base_ptr,
   4065         else => {},
   4066     }
   4067     return sema.failWithStructInitNotSupported(block, src, sema.typeOf(start_ptr).childType(mod));
   4068 }
   4069 
   4070 fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   4071     const mod = sema.mod;
   4072     const gpa = sema.gpa;
   4073     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   4074     const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
   4075     const args = sema.code.refSlice(extra.end, extra.data.operands_len);
   4076     const src = inst_data.src();
   4077 
   4078     var len: Air.Inst.Ref = .none;
   4079     var len_val: ?Value = null;
   4080     var len_idx: u32 = undefined;
   4081     var any_runtime = false;
   4082 
   4083     const runtime_arg_lens = try gpa.alloc(Air.Inst.Ref, args.len);
   4084     defer gpa.free(runtime_arg_lens);
   4085 
   4086     // First pass to look for comptime values.
   4087     for (args, 0..) |zir_arg, i_usize| {
   4088         const i = @intCast(u32, i_usize);
   4089         runtime_arg_lens[i] = .none;
   4090         if (zir_arg == .none) continue;
   4091         const object = try sema.resolveInst(zir_arg);
   4092         const object_ty = sema.typeOf(object);
   4093         // Each arg could be an indexable, or a range, in which case the length
   4094         // is passed directly as an integer.
   4095         const is_int = switch (object_ty.zigTypeTag(mod)) {
   4096             .Int, .ComptimeInt => true,
   4097             else => false,
   4098         };
   4099         const arg_src: LazySrcLoc = .{ .for_input = .{
   4100             .for_node_offset = inst_data.src_node,
   4101             .input_index = i,
   4102         } };
   4103         const arg_len_uncoerced = if (is_int) object else l: {
   4104             if (!object_ty.isIndexable(mod)) {
   4105                 // Instead of using checkIndexable we customize this error.
   4106                 const msg = msg: {
   4107                     const msg = try sema.errMsg(block, arg_src, "type '{}' is not indexable and not a range", .{object_ty.fmt(sema.mod)});
   4108                     errdefer msg.destroy(sema.gpa);
   4109                     try sema.errNote(block, arg_src, msg, "for loop operand must be a range, array, slice, tuple, or vector", .{});
   4110                     break :msg msg;
   4111                 };
   4112                 return sema.failWithOwnedErrorMsg(msg);
   4113             }
   4114             if (!object_ty.indexableHasLen(mod)) continue;
   4115 
   4116             break :l try sema.fieldVal(block, arg_src, object, "len", arg_src);
   4117         };
   4118         const arg_len = try sema.coerce(block, Type.usize, arg_len_uncoerced, arg_src);
   4119         if (len == .none) {
   4120             len = arg_len;
   4121             len_idx = i;
   4122         }
   4123         if (try sema.resolveDefinedValue(block, src, arg_len)) |arg_val| {
   4124             if (len_val) |v| {
   4125                 if (!(try sema.valuesEqual(arg_val, v, Type.usize))) {
   4126                     const msg = msg: {
   4127                         const msg = try sema.errMsg(block, src, "non-matching for loop lengths", .{});
   4128                         errdefer msg.destroy(gpa);
   4129                         const a_src: LazySrcLoc = .{ .for_input = .{
   4130                             .for_node_offset = inst_data.src_node,
   4131                             .input_index = len_idx,
   4132                         } };
   4133                         try sema.errNote(block, a_src, msg, "length {} here", .{
   4134                             v.fmtValue(Type.usize, sema.mod),
   4135                         });
   4136                         try sema.errNote(block, arg_src, msg, "length {} here", .{
   4137                             arg_val.fmtValue(Type.usize, sema.mod),
   4138                         });
   4139                         break :msg msg;
   4140                     };
   4141                     return sema.failWithOwnedErrorMsg(msg);
   4142                 }
   4143             } else {
   4144                 len = arg_len;
   4145                 len_val = arg_val;
   4146                 len_idx = i;
   4147             }
   4148             continue;
   4149         }
   4150         runtime_arg_lens[i] = arg_len;
   4151         any_runtime = true;
   4152     }
   4153 
   4154     if (len == .none) {
   4155         const msg = msg: {
   4156             const msg = try sema.errMsg(block, src, "unbounded for loop", .{});
   4157             errdefer msg.destroy(gpa);
   4158             for (args, 0..) |zir_arg, i_usize| {
   4159                 const i = @intCast(u32, i_usize);
   4160                 if (zir_arg == .none) continue;
   4161                 const object = try sema.resolveInst(zir_arg);
   4162                 const object_ty = sema.typeOf(object);
   4163                 // Each arg could be an indexable, or a range, in which case the length
   4164                 // is passed directly as an integer.
   4165                 switch (object_ty.zigTypeTag(mod)) {
   4166                     .Int, .ComptimeInt => continue,
   4167                     else => {},
   4168                 }
   4169                 const arg_src: LazySrcLoc = .{ .for_input = .{
   4170                     .for_node_offset = inst_data.src_node,
   4171                     .input_index = i,
   4172                 } };
   4173                 try sema.errNote(block, arg_src, msg, "type '{}' has no upper bound", .{
   4174                     object_ty.fmt(sema.mod),
   4175                 });
   4176             }
   4177             break :msg msg;
   4178         };
   4179         return sema.failWithOwnedErrorMsg(msg);
   4180     }
   4181 
   4182     // Now for the runtime checks.
   4183     if (any_runtime and block.wantSafety()) {
   4184         for (runtime_arg_lens, 0..) |arg_len, i| {
   4185             if (arg_len == .none) continue;
   4186             if (i == len_idx) continue;
   4187             const ok = try block.addBinOp(.cmp_eq, len, arg_len);
   4188             try sema.addSafetyCheck(block, ok, .for_len_mismatch);
   4189         }
   4190     }
   4191 
   4192     return len;
   4193 }
   4194 
   4195 fn validateArrayInitTy(
   4196     sema: *Sema,
   4197     block: *Block,
   4198     inst: Zir.Inst.Index,
   4199 ) CompileError!void {
   4200     const mod = sema.mod;
   4201     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   4202     const src = inst_data.src();
   4203     const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node };
   4204     const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data;
   4205     const ty = try sema.resolveType(block, ty_src, extra.ty);
   4206 
   4207     switch (ty.zigTypeTag(mod)) {
   4208         .Array => {
   4209             const array_len = ty.arrayLen(mod);
   4210             if (extra.init_count != array_len) {
   4211                 return sema.fail(block, src, "expected {d} array elements; found {d}", .{
   4212                     array_len, extra.init_count,
   4213                 });
   4214             }
   4215             return;
   4216         },
   4217         .Vector => {
   4218             const array_len = ty.arrayLen(mod);
   4219             if (extra.init_count != array_len) {
   4220                 return sema.fail(block, src, "expected {d} vector elements; found {d}", .{
   4221                     array_len, extra.init_count,
   4222                 });
   4223             }
   4224             return;
   4225         },
   4226         .Struct => if (ty.isTuple(mod)) {
   4227             _ = try sema.resolveTypeFields(ty);
   4228             const array_len = ty.arrayLen(mod);
   4229             if (extra.init_count > array_len) {
   4230                 return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{
   4231                     array_len, extra.init_count,
   4232                 });
   4233             }
   4234             return;
   4235         },
   4236         else => {},
   4237     }
   4238     return sema.failWithArrayInitNotSupported(block, ty_src, ty);
   4239 }
   4240 
   4241 fn validateStructInitTy(
   4242     sema: *Sema,
   4243     block: *Block,
   4244     inst: Zir.Inst.Index,
   4245 ) CompileError!void {
   4246     const mod = sema.mod;
   4247     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   4248     const src = inst_data.src();
   4249     const ty = try sema.resolveType(block, src, inst_data.operand);
   4250 
   4251     switch (ty.zigTypeTag(mod)) {
   4252         .Struct, .Union => return,
   4253         else => {},
   4254     }
   4255     return sema.failWithStructInitNotSupported(block, src, ty);
   4256 }
   4257 
   4258 fn zirValidateStructInit(
   4259     sema: *Sema,
   4260     block: *Block,
   4261     inst: Zir.Inst.Index,
   4262 ) CompileError!void {
   4263     const tracy = trace(@src());
   4264     defer tracy.end();
   4265 
   4266     const mod = sema.mod;
   4267     const validate_inst = sema.code.instructions.items(.data)[inst].pl_node;
   4268     const init_src = validate_inst.src();
   4269     const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index);
   4270     const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len];
   4271     const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
   4272     const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
   4273     const object_ptr = try sema.resolveInst(field_ptr_extra.lhs);
   4274     const agg_ty = sema.typeOf(object_ptr).childType(mod);
   4275     switch (agg_ty.zigTypeTag(mod)) {
   4276         .Struct => return sema.validateStructInit(
   4277             block,
   4278             agg_ty,
   4279             init_src,
   4280             instrs,
   4281         ),
   4282         .Union => return sema.validateUnionInit(
   4283             block,
   4284             agg_ty,
   4285             init_src,
   4286             instrs,
   4287             object_ptr,
   4288         ),
   4289         else => unreachable,
   4290     }
   4291 }
   4292 
   4293 fn validateUnionInit(
   4294     sema: *Sema,
   4295     block: *Block,
   4296     union_ty: Type,
   4297     init_src: LazySrcLoc,
   4298     instrs: []const Zir.Inst.Index,
   4299     union_ptr: Air.Inst.Ref,
   4300 ) CompileError!void {
   4301     const mod = sema.mod;
   4302 
   4303     if (instrs.len != 1) {
   4304         const msg = msg: {
   4305             const msg = try sema.errMsg(
   4306                 block,
   4307                 init_src,
   4308                 "cannot initialize multiple union fields at once; unions can only have one active field",
   4309                 .{},
   4310             );
   4311             errdefer msg.destroy(sema.gpa);
   4312 
   4313             for (instrs[1..]) |inst| {
   4314                 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   4315                 const inst_src: LazySrcLoc = .{ .node_offset_initializer = inst_data.src_node };
   4316                 try sema.errNote(block, inst_src, msg, "additional initializer here", .{});
   4317             }
   4318             try sema.addDeclaredHereNote(msg, union_ty);
   4319             break :msg msg;
   4320         };
   4321         return sema.failWithOwnedErrorMsg(msg);
   4322     }
   4323 
   4324     if (block.is_comptime and
   4325         (try sema.resolveDefinedValue(block, init_src, union_ptr)) != null)
   4326     {
   4327         // In this case, comptime machinery already did everything. No work to do here.
   4328         return;
   4329     }
   4330 
   4331     const field_ptr = instrs[0];
   4332     const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node;
   4333     const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node };
   4334     const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
   4335     const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
   4336     // Validate the field access but ignore the index since we want the tag enum field index.
   4337     _ = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
   4338     const air_tags = sema.air_instructions.items(.tag);
   4339     const air_datas = sema.air_instructions.items(.data);
   4340     const field_ptr_air_ref = sema.inst_map.get(field_ptr).?;
   4341     const field_ptr_air_inst = Air.refToIndex(field_ptr_air_ref).?;
   4342 
   4343     // Our task here is to determine if the union is comptime-known. In such case,
   4344     // we erase the runtime AIR instructions for initializing the union, and replace
   4345     // the mapping with the comptime value. Either way, we will need to populate the tag.
   4346 
   4347     // We expect to see something like this in the current block AIR:
   4348     //   %a = alloc(*const U)
   4349     //   %b = bitcast(*U, %a)
   4350     //   %c = field_ptr(..., %b)
   4351     //   %e!= store(%c!, %d!)
   4352     // If %d is a comptime operand, the union is comptime.
   4353     // If the union is comptime, we want `first_block_index`
   4354     // to point at %c so that the bitcast becomes the last instruction in the block.
   4355     //
   4356     // In the case of a comptime-known pointer to a union, the
   4357     // the field_ptr instruction is missing, so we have to pattern-match
   4358     // based only on the store instructions.
   4359     // `first_block_index` needs to point to the `field_ptr` if it exists;
   4360     // the `store` otherwise.
   4361     //
   4362     // It's also possible for there to be no store instruction, in the case
   4363     // of nested `coerce_result_ptr` instructions. If we see the `field_ptr`
   4364     // but we have not found a `store`, treat as a runtime-known field.
   4365     var first_block_index = block.instructions.items.len;
   4366     var block_index = block.instructions.items.len - 1;
   4367     var init_val: ?Value = null;
   4368     var make_runtime = false;
   4369     while (block_index > 0) : (block_index -= 1) {
   4370         const store_inst = block.instructions.items[block_index];
   4371         if (store_inst == field_ptr_air_inst) break;
   4372         switch (air_tags[store_inst]) {
   4373             .store, .store_safe => {},
   4374             else => continue,
   4375         }
   4376         const bin_op = air_datas[store_inst].bin_op;
   4377         var lhs = bin_op.lhs;
   4378         if (Air.refToIndex(lhs)) |lhs_index| {
   4379             if (air_tags[lhs_index] == .bitcast) {
   4380                 lhs = air_datas[lhs_index].ty_op.operand;
   4381                 block_index -= 1;
   4382             }
   4383         }
   4384         if (lhs != field_ptr_air_ref) continue;
   4385         while (block_index > 0) : (block_index -= 1) {
   4386             const block_inst = block.instructions.items[block_index - 1];
   4387             if (air_tags[block_inst] != .dbg_stmt) break;
   4388         }
   4389         if (block_index > 0 and
   4390             field_ptr_air_inst == block.instructions.items[block_index - 1])
   4391         {
   4392             first_block_index = @min(first_block_index, block_index - 1);
   4393         } else {
   4394             first_block_index = @min(first_block_index, block_index);
   4395         }
   4396         init_val = try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime);
   4397         break;
   4398     }
   4399 
   4400     const tag_ty = union_ty.unionTagTypeHypothetical(mod);
   4401     const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?);
   4402     const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
   4403 
   4404     if (init_val) |val| {
   4405         // Our task is to delete all the `field_ptr` and `store` instructions, and insert
   4406         // instead a single `store` to the result ptr with a comptime union value.
   4407         block.instructions.shrinkRetainingCapacity(first_block_index);
   4408 
   4409         var union_val = try mod.intern(.{ .un = .{
   4410             .ty = union_ty.toIntern(),
   4411             .tag = tag_val.toIntern(),
   4412             .val = val.toIntern(),
   4413         } });
   4414         if (make_runtime) union_val = try mod.intern(.{ .runtime_value = .{
   4415             .ty = union_ty.toIntern(),
   4416             .val = union_val,
   4417         } });
   4418         const union_init = try sema.addConstant(union_ty, union_val.toValue());
   4419         try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store);
   4420         return;
   4421     } else if (try sema.typeRequiresComptime(union_ty)) {
   4422         return sema.failWithNeededComptime(block, field_ptr_data.src(), "initializer of comptime only union must be comptime-known");
   4423     }
   4424 
   4425     const new_tag = try sema.addConstant(tag_ty, tag_val);
   4426     _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag);
   4427 }
   4428 
   4429 fn validateStructInit(
   4430     sema: *Sema,
   4431     block: *Block,
   4432     struct_ty: Type,
   4433     init_src: LazySrcLoc,
   4434     instrs: []const Zir.Inst.Index,
   4435 ) CompileError!void {
   4436     const mod = sema.mod;
   4437     const gpa = sema.gpa;
   4438 
   4439     // Maps field index to field_ptr index of where it was already initialized.
   4440     const found_fields = try gpa.alloc(Zir.Inst.Index, struct_ty.structFieldCount(mod));
   4441     defer gpa.free(found_fields);
   4442     @memset(found_fields, 0);
   4443 
   4444     var struct_ptr_zir_ref: Zir.Inst.Ref = undefined;
   4445 
   4446     for (instrs) |field_ptr| {
   4447         const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node;
   4448         const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node };
   4449         const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
   4450         struct_ptr_zir_ref = field_ptr_extra.lhs;
   4451         const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
   4452         const field_index = if (struct_ty.isTuple(mod))
   4453             try sema.tupleFieldIndex(block, struct_ty, field_name, field_src)
   4454         else
   4455             try sema.structFieldIndex(block, struct_ty, field_name, field_src);
   4456         if (found_fields[field_index] != 0) {
   4457             const other_field_ptr = found_fields[field_index];
   4458             const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node;
   4459             const other_field_src: LazySrcLoc = .{ .node_offset_initializer = other_field_ptr_data.src_node };
   4460             const msg = msg: {
   4461                 const msg = try sema.errMsg(block, field_src, "duplicate field", .{});
   4462                 errdefer msg.destroy(gpa);
   4463                 try sema.errNote(block, other_field_src, msg, "other field here", .{});
   4464                 break :msg msg;
   4465             };
   4466             return sema.failWithOwnedErrorMsg(msg);
   4467         }
   4468         found_fields[field_index] = field_ptr;
   4469     }
   4470 
   4471     var root_msg: ?*Module.ErrorMsg = null;
   4472     errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
   4473 
   4474     const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);
   4475     if (block.is_comptime and
   4476         (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null)
   4477     {
   4478         try sema.resolveStructLayout(struct_ty);
   4479         // In this case the only thing we need to do is evaluate the implicit
   4480         // store instructions for default field values, and report any missing fields.
   4481         // Avoid the cost of the extra machinery for detecting a comptime struct init value.
   4482         for (found_fields, 0..) |field_ptr, i| {
   4483             if (field_ptr != 0) continue;
   4484 
   4485             const default_val = struct_ty.structFieldDefaultValue(i, mod);
   4486             if (default_val.toIntern() == .unreachable_value) {
   4487                 if (struct_ty.isTuple(mod)) {
   4488                     const template = "missing tuple field with index {d}";
   4489                     if (root_msg) |msg| {
   4490                         try sema.errNote(block, init_src, msg, template, .{i});
   4491                     } else {
   4492                         root_msg = try sema.errMsg(block, init_src, template, .{i});
   4493                     }
   4494                     continue;
   4495                 }
   4496                 const field_name = struct_ty.structFieldName(i, mod);
   4497                 const template = "missing struct field: {s}";
   4498                 const args = .{field_name};
   4499                 if (root_msg) |msg| {
   4500                     try sema.errNote(block, init_src, msg, template, args);
   4501                 } else {
   4502                     root_msg = try sema.errMsg(block, init_src, template, args);
   4503                 }
   4504                 continue;
   4505             }
   4506 
   4507             const field_src = init_src; // TODO better source location
   4508             const default_field_ptr = if (struct_ty.isTuple(mod))
   4509                 try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true)
   4510             else
   4511                 try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true);
   4512             const field_ty = sema.typeOf(default_field_ptr).childType(mod);
   4513             const init = try sema.addConstant(field_ty, default_val);
   4514             try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
   4515         }
   4516 
   4517         if (root_msg) |msg| {
   4518             if (mod.typeToStruct(struct_ty)) |struct_obj| {
   4519                 const fqn = try struct_obj.getFullyQualifiedName(mod);
   4520                 defer gpa.free(fqn);
   4521                 try mod.errNoteNonLazy(
   4522                     struct_obj.srcLoc(mod),
   4523                     msg,
   4524                     "struct '{s}' declared here",
   4525                     .{fqn},
   4526                 );
   4527             }
   4528             root_msg = null;
   4529             return sema.failWithOwnedErrorMsg(msg);
   4530         }
   4531 
   4532         return;
   4533     }
   4534 
   4535     var struct_is_comptime = true;
   4536     var first_block_index = block.instructions.items.len;
   4537     var make_runtime = false;
   4538 
   4539     const require_comptime = try sema.typeRequiresComptime(struct_ty);
   4540     const air_tags = sema.air_instructions.items(.tag);
   4541     const air_datas = sema.air_instructions.items(.data);
   4542 
   4543     // We collect the comptime field values in case the struct initialization
   4544     // ends up being comptime-known.
   4545     const field_values = try sema.arena.alloc(InternPool.Index, struct_ty.structFieldCount(mod));
   4546 
   4547     field: for (found_fields, 0..) |field_ptr, i| {
   4548         if (field_ptr != 0) {
   4549             // Determine whether the value stored to this pointer is comptime-known.
   4550             const field_ty = struct_ty.structFieldType(i, mod);
   4551             if (try sema.typeHasOnePossibleValue(field_ty)) |opv| {
   4552                 field_values[i] = opv.toIntern();
   4553                 continue;
   4554             }
   4555 
   4556             const field_ptr_air_ref = sema.inst_map.get(field_ptr).?;
   4557             const field_ptr_air_inst = Air.refToIndex(field_ptr_air_ref).?;
   4558 
   4559             //std.debug.print("validateStructInit (field_ptr_air_inst=%{d}):\n", .{
   4560             //    field_ptr_air_inst,
   4561             //});
   4562             //for (block.instructions.items) |item| {
   4563             //    std.debug.print("  %{d} = {s}\n", .{item, @tagName(air_tags[item])});
   4564             //}
   4565 
   4566             // We expect to see something like this in the current block AIR:
   4567             //   %a = field_ptr(...)
   4568             //   store(%a, %b)
   4569             // With an optional bitcast between the store and the field_ptr.
   4570             // If %b is a comptime operand, this field is comptime.
   4571             //
   4572             // However, in the case of a comptime-known pointer to a struct, the
   4573             // the field_ptr instruction is missing, so we have to pattern-match
   4574             // based only on the store instructions.
   4575             // `first_block_index` needs to point to the `field_ptr` if it exists;
   4576             // the `store` otherwise.
   4577             //
   4578             // It's also possible for there to be no store instruction, in the case
   4579             // of nested `coerce_result_ptr` instructions. If we see the `field_ptr`
   4580             // but we have not found a `store`, treat as a runtime-known field.
   4581 
   4582             // Possible performance enhancement: save the `block_index` between iterations
   4583             // of the for loop.
   4584             var block_index = block.instructions.items.len - 1;
   4585             while (block_index > 0) : (block_index -= 1) {
   4586                 const store_inst = block.instructions.items[block_index];
   4587                 if (store_inst == field_ptr_air_inst) {
   4588                     struct_is_comptime = false;
   4589                     continue :field;
   4590                 }
   4591                 switch (air_tags[store_inst]) {
   4592                     .store, .store_safe => {},
   4593                     else => continue,
   4594                 }
   4595                 const bin_op = air_datas[store_inst].bin_op;
   4596                 var lhs = bin_op.lhs;
   4597                 {
   4598                     const lhs_index = Air.refToIndex(lhs) orelse continue;
   4599                     if (air_tags[lhs_index] == .bitcast) {
   4600                         lhs = air_datas[lhs_index].ty_op.operand;
   4601                         block_index -= 1;
   4602                     }
   4603                 }
   4604                 if (lhs != field_ptr_air_ref) continue;
   4605                 while (block_index > 0) : (block_index -= 1) {
   4606                     const block_inst = block.instructions.items[block_index - 1];
   4607                     if (air_tags[block_inst] != .dbg_stmt) break;
   4608                 }
   4609                 if (block_index > 0 and
   4610                     field_ptr_air_inst == block.instructions.items[block_index - 1])
   4611                 {
   4612                     first_block_index = @min(first_block_index, block_index - 1);
   4613                 } else {
   4614                     first_block_index = @min(first_block_index, block_index);
   4615                 }
   4616                 if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| {
   4617                     field_values[i] = val.toIntern();
   4618                 } else if (require_comptime) {
   4619                     const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node;
   4620                     return sema.failWithNeededComptime(block, field_ptr_data.src(), "initializer of comptime only struct must be comptime-known");
   4621                 } else {
   4622                     struct_is_comptime = false;
   4623                 }
   4624                 continue :field;
   4625             }
   4626             struct_is_comptime = false;
   4627             continue :field;
   4628         }
   4629 
   4630         const default_val = struct_ty.structFieldDefaultValue(i, mod);
   4631         if (default_val.toIntern() == .unreachable_value) {
   4632             if (struct_ty.isTuple(mod)) {
   4633                 const template = "missing tuple field with index {d}";
   4634                 if (root_msg) |msg| {
   4635                     try sema.errNote(block, init_src, msg, template, .{i});
   4636                 } else {
   4637                     root_msg = try sema.errMsg(block, init_src, template, .{i});
   4638                 }
   4639                 continue;
   4640             }
   4641             const field_name = struct_ty.structFieldName(i, mod);
   4642             const template = "missing struct field: {s}";
   4643             const args = .{field_name};
   4644             if (root_msg) |msg| {
   4645                 try sema.errNote(block, init_src, msg, template, args);
   4646             } else {
   4647                 root_msg = try sema.errMsg(block, init_src, template, args);
   4648             }
   4649             continue;
   4650         }
   4651         field_values[i] = default_val.toIntern();
   4652     }
   4653 
   4654     if (root_msg) |msg| {
   4655         if (mod.typeToStruct(struct_ty)) |struct_obj| {
   4656             const fqn = try struct_obj.getFullyQualifiedName(sema.mod);
   4657             defer gpa.free(fqn);
   4658             try sema.mod.errNoteNonLazy(
   4659                 struct_obj.srcLoc(sema.mod),
   4660                 msg,
   4661                 "struct '{s}' declared here",
   4662                 .{fqn},
   4663             );
   4664         }
   4665         root_msg = null;
   4666         return sema.failWithOwnedErrorMsg(msg);
   4667     }
   4668 
   4669     if (struct_is_comptime) {
   4670         // Our task is to delete all the `field_ptr` and `store` instructions, and insert
   4671         // instead a single `store` to the struct_ptr with a comptime struct value.
   4672 
   4673         block.instructions.shrinkRetainingCapacity(first_block_index);
   4674         var struct_val = try mod.intern(.{ .aggregate = .{
   4675             .ty = struct_ty.toIntern(),
   4676             .storage = .{ .elems = field_values },
   4677         } });
   4678         if (make_runtime) struct_val = try mod.intern(.{ .runtime_value = .{
   4679             .ty = struct_ty.toIntern(),
   4680             .val = struct_val,
   4681         } });
   4682         const struct_init = try sema.addConstant(struct_ty, struct_val.toValue());
   4683         try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
   4684         return;
   4685     }
   4686     try sema.resolveStructLayout(struct_ty);
   4687 
   4688     // Our task is to insert `store` instructions for all the default field values.
   4689     for (found_fields, 0..) |field_ptr, i| {
   4690         if (field_ptr != 0) continue;
   4691 
   4692         const field_src = init_src; // TODO better source location
   4693         const default_field_ptr = if (struct_ty.isTuple(mod))
   4694             try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true)
   4695         else
   4696             try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true);
   4697         const field_ty = sema.typeOf(default_field_ptr).childType(mod);
   4698         const init = try sema.addConstant(field_ty, field_values[i].toValue());
   4699         try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
   4700     }
   4701 }
   4702 
   4703 fn zirValidateArrayInit(
   4704     sema: *Sema,
   4705     block: *Block,
   4706     inst: Zir.Inst.Index,
   4707 ) CompileError!void {
   4708     const mod = sema.mod;
   4709     const validate_inst = sema.code.instructions.items(.data)[inst].pl_node;
   4710     const init_src = validate_inst.src();
   4711     const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index);
   4712     const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len];
   4713     const first_elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
   4714     const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data;
   4715     const array_ptr = try sema.resolveInst(elem_ptr_extra.ptr);
   4716     const array_ty = sema.typeOf(array_ptr).childType(mod);
   4717     const array_len = array_ty.arrayLen(mod);
   4718 
   4719     if (instrs.len != array_len) switch (array_ty.zigTypeTag(mod)) {
   4720         .Struct => {
   4721             var root_msg: ?*Module.ErrorMsg = null;
   4722             errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
   4723 
   4724             var i = instrs.len;
   4725             while (i < array_len) : (i += 1) {
   4726                 const default_val = array_ty.structFieldDefaultValue(i, mod);
   4727                 if (default_val.toIntern() == .unreachable_value) {
   4728                     const template = "missing tuple field with index {d}";
   4729                     if (root_msg) |msg| {
   4730                         try sema.errNote(block, init_src, msg, template, .{i});
   4731                     } else {
   4732                         root_msg = try sema.errMsg(block, init_src, template, .{i});
   4733                     }
   4734                 }
   4735             }
   4736 
   4737             if (root_msg) |msg| {
   4738                 root_msg = null;
   4739                 return sema.failWithOwnedErrorMsg(msg);
   4740             }
   4741         },
   4742         .Array => {
   4743             return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{
   4744                 array_len, instrs.len,
   4745             });
   4746         },
   4747         .Vector => {
   4748             return sema.fail(block, init_src, "expected {d} vector elements; found {d}", .{
   4749                 array_len, instrs.len,
   4750             });
   4751         },
   4752         else => unreachable,
   4753     };
   4754 
   4755     if (block.is_comptime and
   4756         (try sema.resolveDefinedValue(block, init_src, array_ptr)) != null)
   4757     {
   4758         // In this case the comptime machinery will have evaluated the store instructions
   4759         // at comptime so we have almost nothing to do here. However, in case of a
   4760         // sentinel-terminated array, the sentinel will not have been populated by
   4761         // any ZIR instructions at comptime; we need to do that here.
   4762         if (array_ty.sentinel(mod)) |sentinel_val| {
   4763             const array_len_ref = try sema.addIntUnsigned(Type.usize, array_len);
   4764             const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true, true);
   4765             const sentinel = try sema.addConstant(array_ty.childType(mod), sentinel_val);
   4766             try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store);
   4767         }
   4768         return;
   4769     }
   4770 
   4771     // If the array has one possible value, the value is always comptime-known.
   4772     if (try sema.typeHasOnePossibleValue(array_ty)) |array_opv| {
   4773         const array_init = try sema.addConstant(array_ty, array_opv);
   4774         try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
   4775         return;
   4776     }
   4777 
   4778     var array_is_comptime = true;
   4779     var first_block_index = block.instructions.items.len;
   4780     var make_runtime = false;
   4781 
   4782     // Collect the comptime element values in case the array literal ends up
   4783     // being comptime-known.
   4784     const element_vals = try sema.arena.alloc(
   4785         InternPool.Index,
   4786         try sema.usizeCast(block, init_src, array_len),
   4787     );
   4788     const air_tags = sema.air_instructions.items(.tag);
   4789     const air_datas = sema.air_instructions.items(.data);
   4790 
   4791     outer: for (instrs, 0..) |elem_ptr, i| {
   4792         // Determine whether the value stored to this pointer is comptime-known.
   4793 
   4794         if (array_ty.isTuple(mod)) {
   4795             if (try array_ty.structFieldValueComptime(mod, i)) |opv| {
   4796                 element_vals[i] = opv.toIntern();
   4797                 continue;
   4798             }
   4799         }
   4800 
   4801         const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;
   4802         const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?;
   4803 
   4804         // We expect to see something like this in the current block AIR:
   4805         //   %a = elem_ptr(...)
   4806         //   store(%a, %b)
   4807         // With an optional bitcast between the store and the elem_ptr.
   4808         // If %b is a comptime operand, this element is comptime.
   4809         //
   4810         // However, in the case of a comptime-known pointer to an array, the
   4811         // the elem_ptr instruction is missing, so we have to pattern-match
   4812         // based only on the store instructions.
   4813         // `first_block_index` needs to point to the `elem_ptr` if it exists;
   4814         // the `store` otherwise.
   4815         //
   4816         // It's also possible for there to be no store instruction, in the case
   4817         // of nested `coerce_result_ptr` instructions. If we see the `elem_ptr`
   4818         // but we have not found a `store`, treat as a runtime-known element.
   4819         //
   4820         // This is nearly identical to similar logic in `validateStructInit`.
   4821 
   4822         // Possible performance enhancement: save the `block_index` between iterations
   4823         // of the for loop.
   4824         var block_index = block.instructions.items.len - 1;
   4825         while (block_index > 0) : (block_index -= 1) {
   4826             const store_inst = block.instructions.items[block_index];
   4827             if (store_inst == elem_ptr_air_inst) {
   4828                 array_is_comptime = false;
   4829                 continue :outer;
   4830             }
   4831             switch (air_tags[store_inst]) {
   4832                 .store, .store_safe => {},
   4833                 else => continue,
   4834             }
   4835             const bin_op = air_datas[store_inst].bin_op;
   4836             var lhs = bin_op.lhs;
   4837             {
   4838                 const lhs_index = Air.refToIndex(lhs) orelse continue;
   4839                 if (air_tags[lhs_index] == .bitcast) {
   4840                     lhs = air_datas[lhs_index].ty_op.operand;
   4841                     block_index -= 1;
   4842                 }
   4843             }
   4844             if (lhs != elem_ptr_air_ref) continue;
   4845             while (block_index > 0) : (block_index -= 1) {
   4846                 const block_inst = block.instructions.items[block_index - 1];
   4847                 if (air_tags[block_inst] != .dbg_stmt) break;
   4848             }
   4849             if (block_index > 0 and
   4850                 elem_ptr_air_inst == block.instructions.items[block_index - 1])
   4851             {
   4852                 first_block_index = @min(first_block_index, block_index - 1);
   4853             } else {
   4854                 first_block_index = @min(first_block_index, block_index);
   4855             }
   4856             if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| {
   4857                 element_vals[i] = val.toIntern();
   4858             } else {
   4859                 array_is_comptime = false;
   4860             }
   4861             continue :outer;
   4862         }
   4863         array_is_comptime = false;
   4864         continue :outer;
   4865     }
   4866 
   4867     if (array_is_comptime) {
   4868         if (try sema.resolveDefinedValue(block, init_src, array_ptr)) |ptr_val| {
   4869             switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {
   4870                 .ptr => |ptr| switch (ptr.addr) {
   4871                     .comptime_field => return, // This store was validated by the individual elem ptrs.
   4872                     else => {},
   4873                 },
   4874                 else => {},
   4875             }
   4876         }
   4877 
   4878         // Our task is to delete all the `elem_ptr` and `store` instructions, and insert
   4879         // instead a single `store` to the array_ptr with a comptime struct value.
   4880         block.instructions.shrinkRetainingCapacity(first_block_index);
   4881 
   4882         var array_val = try mod.intern(.{ .aggregate = .{
   4883             .ty = array_ty.toIntern(),
   4884             .storage = .{ .elems = element_vals },
   4885         } });
   4886         if (make_runtime) array_val = try mod.intern(.{ .runtime_value = .{
   4887             .ty = array_ty.toIntern(),
   4888             .val = array_val,
   4889         } });
   4890         const array_init = try sema.addConstant(array_ty, array_val.toValue());
   4891         try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
   4892     }
   4893 }
   4894 
   4895 fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   4896     const mod = sema.mod;
   4897     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   4898     const src = inst_data.src();
   4899     const operand = try sema.resolveInst(inst_data.operand);
   4900     const operand_ty = sema.typeOf(operand);
   4901 
   4902     if (operand_ty.zigTypeTag(mod) != .Pointer) {
   4903         return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(sema.mod)});
   4904     } else switch (operand_ty.ptrSize(mod)) {
   4905         .One, .C => {},
   4906         .Many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(sema.mod)}),
   4907         .Slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(sema.mod)}),
   4908     }
   4909 
   4910     if ((try sema.typeHasOnePossibleValue(operand_ty.childType(mod))) != null) {
   4911         // No need to validate the actual pointer value, we don't need it!
   4912         return;
   4913     }
   4914 
   4915     const elem_ty = operand_ty.elemType2(mod);
   4916     if (try sema.resolveMaybeUndefVal(operand)) |val| {
   4917         if (val.isUndef(mod)) {
   4918             return sema.fail(block, src, "cannot dereference undefined value", .{});
   4919         }
   4920     } else if (!(try sema.validateRunTimeType(elem_ty, false))) {
   4921         const msg = msg: {
   4922             const msg = try sema.errMsg(
   4923                 block,
   4924                 src,
   4925                 "values of type '{}' must be comptime-known, but operand value is runtime-known",
   4926                 .{elem_ty.fmt(sema.mod)},
   4927             );
   4928             errdefer msg.destroy(sema.gpa);
   4929 
   4930             const src_decl = sema.mod.declPtr(block.src_decl);
   4931             try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), elem_ty);
   4932             break :msg msg;
   4933         };
   4934         return sema.failWithOwnedErrorMsg(msg);
   4935     }
   4936 }
   4937 
   4938 fn failWithBadMemberAccess(
   4939     sema: *Sema,
   4940     block: *Block,
   4941     agg_ty: Type,
   4942     field_src: LazySrcLoc,
   4943     field_name: []const u8,
   4944 ) CompileError {
   4945     const mod = sema.mod;
   4946     const kw_name = switch (agg_ty.zigTypeTag(mod)) {
   4947         .Union => "union",
   4948         .Struct => "struct",
   4949         .Opaque => "opaque",
   4950         .Enum => "enum",
   4951         else => unreachable,
   4952     };
   4953     if (agg_ty.getOwnerDeclOrNull(mod)) |some| if (sema.mod.declIsRoot(some)) {
   4954         return sema.fail(block, field_src, "root struct of file '{}' has no member named '{s}'", .{
   4955             agg_ty.fmt(sema.mod), field_name,
   4956         });
   4957     };
   4958     const msg = msg: {
   4959         const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{s}'", .{
   4960             kw_name, agg_ty.fmt(sema.mod), field_name,
   4961         });
   4962         errdefer msg.destroy(sema.gpa);
   4963         try sema.addDeclaredHereNote(msg, agg_ty);
   4964         break :msg msg;
   4965     };
   4966     return sema.failWithOwnedErrorMsg(msg);
   4967 }
   4968 
   4969 fn failWithBadStructFieldAccess(
   4970     sema: *Sema,
   4971     block: *Block,
   4972     struct_obj: *Module.Struct,
   4973     field_src: LazySrcLoc,
   4974     field_name: []const u8,
   4975 ) CompileError {
   4976     const gpa = sema.gpa;
   4977 
   4978     const fqn = try struct_obj.getFullyQualifiedName(sema.mod);
   4979     defer gpa.free(fqn);
   4980 
   4981     const msg = msg: {
   4982         const msg = try sema.errMsg(
   4983             block,
   4984             field_src,
   4985             "no field named '{s}' in struct '{s}'",
   4986             .{ field_name, fqn },
   4987         );
   4988         errdefer msg.destroy(gpa);
   4989         try sema.mod.errNoteNonLazy(struct_obj.srcLoc(sema.mod), msg, "struct declared here", .{});
   4990         break :msg msg;
   4991     };
   4992     return sema.failWithOwnedErrorMsg(msg);
   4993 }
   4994 
   4995 fn failWithBadUnionFieldAccess(
   4996     sema: *Sema,
   4997     block: *Block,
   4998     union_obj: *Module.Union,
   4999     field_src: LazySrcLoc,
   5000     field_name: []const u8,
   5001 ) CompileError {
   5002     const gpa = sema.gpa;
   5003 
   5004     const fqn = try union_obj.getFullyQualifiedName(sema.mod);
   5005     defer gpa.free(fqn);
   5006 
   5007     const msg = msg: {
   5008         const msg = try sema.errMsg(
   5009             block,
   5010             field_src,
   5011             "no field named '{s}' in union '{s}'",
   5012             .{ field_name, fqn },
   5013         );
   5014         errdefer msg.destroy(gpa);
   5015         try sema.mod.errNoteNonLazy(union_obj.srcLoc(sema.mod), msg, "union declared here", .{});
   5016         break :msg msg;
   5017     };
   5018     return sema.failWithOwnedErrorMsg(msg);
   5019 }
   5020 
   5021 fn addDeclaredHereNote(sema: *Sema, parent: *Module.ErrorMsg, decl_ty: Type) !void {
   5022     const mod = sema.mod;
   5023     const src_loc = decl_ty.declSrcLocOrNull(mod) orelse return;
   5024     const category = switch (decl_ty.zigTypeTag(mod)) {
   5025         .Union => "union",
   5026         .Struct => "struct",
   5027         .Enum => "enum",
   5028         .Opaque => "opaque",
   5029         .ErrorSet => "error set",
   5030         else => unreachable,
   5031     };
   5032     try mod.errNoteNonLazy(src_loc, parent, "{s} declared here", .{category});
   5033 }
   5034 
   5035 fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   5036     const tracy = trace(@src());
   5037     defer tracy.end();
   5038 
   5039     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
   5040     const ptr = sema.inst_map.get(Zir.refToIndex(bin_inst.lhs).?) orelse {
   5041         // This is an elided instruction, but AstGen was unable to omit it.
   5042         return;
   5043     };
   5044     const operand = try sema.resolveInst(bin_inst.rhs);
   5045     const src: LazySrcLoc = sema.src;
   5046     blk: {
   5047         const ptr_inst = Air.refToIndex(ptr) orelse break :blk;
   5048         switch (sema.air_instructions.items(.tag)[ptr_inst]) {
   5049             .inferred_alloc_comptime => {
   5050                 const iac = &sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime;
   5051                 return sema.storeToInferredAllocComptime(block, src, operand, iac);
   5052             },
   5053             .inferred_alloc => {
   5054                 const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?;
   5055                 return sema.storeToInferredAlloc(block, ptr, operand, ia);
   5056             },
   5057             else => break :blk,
   5058         }
   5059     }
   5060 
   5061     return sema.storePtr(block, src, ptr, operand);
   5062 }
   5063 
   5064 fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   5065     const tracy = trace(@src());
   5066     defer tracy.end();
   5067 
   5068     const src: LazySrcLoc = sema.src;
   5069     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
   5070     const ptr = try sema.resolveInst(bin_inst.lhs);
   5071     const operand = try sema.resolveInst(bin_inst.rhs);
   5072     const ptr_inst = Air.refToIndex(ptr).?;
   5073     const air_datas = sema.air_instructions.items(.data);
   5074 
   5075     switch (sema.air_instructions.items(.tag)[ptr_inst]) {
   5076         .inferred_alloc_comptime => {
   5077             const iac = &air_datas[ptr_inst].inferred_alloc_comptime;
   5078             return sema.storeToInferredAllocComptime(block, src, operand, iac);
   5079         },
   5080         .inferred_alloc => {
   5081             const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?;
   5082             return sema.storeToInferredAlloc(block, ptr, operand, ia);
   5083         },
   5084         else => unreachable,
   5085     }
   5086 }
   5087 
   5088 fn storeToInferredAlloc(
   5089     sema: *Sema,
   5090     block: *Block,
   5091     ptr: Air.Inst.Ref,
   5092     operand: Air.Inst.Ref,
   5093     inferred_alloc: *InferredAlloc,
   5094 ) CompileError!void {
   5095     // Create a store instruction as a placeholder.  This will be replaced by a
   5096     // proper store sequence once we know the stored type.
   5097     const dummy_store = try block.addBinOp(.store, ptr, operand);
   5098     // Add the stored instruction to the set we will use to resolve peer types
   5099     // for the inferred allocation.
   5100     try inferred_alloc.prongs.append(sema.arena, .{
   5101         .stored_inst = operand,
   5102         .placeholder = Air.refToIndex(dummy_store).?,
   5103     });
   5104 }
   5105 
   5106 fn storeToInferredAllocComptime(
   5107     sema: *Sema,
   5108     block: *Block,
   5109     src: LazySrcLoc,
   5110     operand: Air.Inst.Ref,
   5111     iac: *Air.Inst.Data.InferredAllocComptime,
   5112 ) CompileError!void {
   5113     const operand_ty = sema.typeOf(operand);
   5114     // There will be only one store_to_inferred_ptr because we are running at comptime.
   5115     // The alloc will turn into a Decl.
   5116     if (try sema.resolveMaybeUndefValAllowVariables(operand)) |operand_val| store: {
   5117         if (operand_val.getVariable(sema.mod) != null) break :store;
   5118         var anon_decl = try block.startAnonDecl();
   5119         defer anon_decl.deinit();
   5120         iac.decl_index = try anon_decl.finish(
   5121             operand_ty,
   5122             try operand_val.copy(anon_decl.arena()),
   5123             iac.alignment.toByteUnits(0),
   5124         );
   5125         return;
   5126     }
   5127 
   5128     return sema.failWithNeededComptime(block, src, "value being stored to a comptime variable must be comptime-known");
   5129 }
   5130 
   5131 fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   5132     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   5133     const src = inst_data.src();
   5134     const quota = @intCast(u32, try sema.resolveInt(block, src, inst_data.operand, Type.u32, "eval branch quota must be comptime-known"));
   5135     sema.branch_quota = @max(sema.branch_quota, quota);
   5136 }
   5137 
   5138 fn zirStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   5139     const tracy = trace(@src());
   5140     defer tracy.end();
   5141 
   5142     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
   5143     const ptr = try sema.resolveInst(bin_inst.lhs);
   5144     const value = try sema.resolveInst(bin_inst.rhs);
   5145     return sema.storePtr(block, sema.src, ptr, value);
   5146 }
   5147 
   5148 fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   5149     const tracy = trace(@src());
   5150     defer tracy.end();
   5151 
   5152     const mod = sema.mod;
   5153     const zir_tags = sema.code.instructions.items(.tag);
   5154     const zir_datas = sema.code.instructions.items(.data);
   5155     const inst_data = zir_datas[inst].pl_node;
   5156     const src = inst_data.src();
   5157     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   5158     const ptr = try sema.resolveInst(extra.lhs);
   5159     const operand = try sema.resolveInst(extra.rhs);
   5160 
   5161     const is_ret = if (Zir.refToIndex(extra.lhs)) |ptr_index|
   5162         zir_tags[ptr_index] == .ret_ptr
   5163     else
   5164         false;
   5165 
   5166     // Check for the possibility of this pattern:
   5167     //   %a = ret_ptr
   5168     //   %b = store(%a, %c)
   5169     // Where %c is an error union or error set. In such case we need to add
   5170     // to the current function's inferred error set, if any.
   5171     if (is_ret and (sema.typeOf(operand).zigTypeTag(mod) == .ErrorUnion or
   5172         sema.typeOf(operand).zigTypeTag(mod) == .ErrorSet) and
   5173         sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion)
   5174     {
   5175         try sema.addToInferredErrorSet(operand);
   5176     }
   5177 
   5178     const ptr_src: LazySrcLoc = .{ .node_offset_store_ptr = inst_data.src_node };
   5179     const operand_src: LazySrcLoc = .{ .node_offset_store_operand = inst_data.src_node };
   5180     const air_tag: Air.Inst.Tag = if (is_ret)
   5181         .ret_ptr
   5182     else if (block.wantSafety())
   5183         .store_safe
   5184     else
   5185         .store;
   5186     return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag);
   5187 }
   5188 
   5189 fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   5190     const tracy = trace(@src());
   5191     defer tracy.end();
   5192 
   5193     const bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code);
   5194     return sema.addStrLit(block, bytes);
   5195 }
   5196 
   5197 fn addStrLit(sema: *Sema, block: *Block, bytes: []const u8) CompileError!Air.Inst.Ref {
   5198     const mod = sema.mod;
   5199     const gpa = sema.gpa;
   5200     const ty = try mod.arrayType(.{
   5201         .len = bytes.len,
   5202         .child = .u8_type,
   5203         .sentinel = .zero_u8,
   5204     });
   5205     const val = try mod.intern(.{ .aggregate = .{
   5206         .ty = ty.toIntern(),
   5207         .storage = .{ .bytes = bytes },
   5208     } });
   5209     const gop = try mod.memoized_decls.getOrPut(gpa, val);
   5210     if (!gop.found_existing) {
   5211         const new_decl_index = try mod.createAnonymousDecl(block, .{
   5212             .ty = ty,
   5213             .val = val.toValue(),
   5214         });
   5215         gop.value_ptr.* = new_decl_index;
   5216         try mod.finalizeAnonDecl(new_decl_index);
   5217     }
   5218     return sema.analyzeDeclRef(gop.value_ptr.*);
   5219 }
   5220 
   5221 fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   5222     _ = block;
   5223     const tracy = trace(@src());
   5224     defer tracy.end();
   5225 
   5226     const int = sema.code.instructions.items(.data)[inst].int;
   5227     return sema.addIntUnsigned(Type.comptime_int, int);
   5228 }
   5229 
   5230 fn zirIntBig(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   5231     _ = block;
   5232     const tracy = trace(@src());
   5233     defer tracy.end();
   5234 
   5235     const mod = sema.mod;
   5236     const int = sema.code.instructions.items(.data)[inst].str;
   5237     const byte_count = int.len * @sizeOf(std.math.big.Limb);
   5238     const limb_bytes = sema.code.string_bytes[int.start..][0..byte_count];
   5239 
   5240     // TODO: this allocation and copy is only needed because the limbs may be unaligned.
   5241     // If ZIR is adjusted so that big int limbs are guaranteed to be aligned, these
   5242     // two lines can be removed.
   5243     const limbs = try sema.arena.alloc(std.math.big.Limb, int.len);
   5244     @memcpy(mem.sliceAsBytes(limbs), limb_bytes);
   5245 
   5246     return sema.addConstant(
   5247         Type.comptime_int,
   5248         try mod.intValue_big(Type.comptime_int, .{
   5249             .limbs = limbs,
   5250             .positive = true,
   5251         }),
   5252     );
   5253 }
   5254 
   5255 fn zirFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   5256     _ = block;
   5257     const number = sema.code.instructions.items(.data)[inst].float;
   5258     return sema.addConstant(
   5259         Type.comptime_float,
   5260         try sema.mod.floatValue(Type.comptime_float, number),
   5261     );
   5262 }
   5263 
   5264 fn zirFloat128(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   5265     _ = block;
   5266     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   5267     const extra = sema.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data;
   5268     const number = extra.get();
   5269     return sema.addConstant(
   5270         Type.comptime_float,
   5271         try sema.mod.floatValue(Type.comptime_float, number),
   5272     );
   5273 }
   5274 
   5275 fn zirCompileError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
   5276     const tracy = trace(@src());
   5277     defer tracy.end();
   5278 
   5279     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   5280     const src = inst_data.src();
   5281     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   5282     const msg = try sema.resolveConstString(block, operand_src, inst_data.operand, "compile error string must be comptime-known");
   5283     return sema.fail(block, src, "{s}", .{msg});
   5284 }
   5285 
   5286 fn zirCompileLog(
   5287     sema: *Sema,
   5288     extended: Zir.Inst.Extended.InstData,
   5289 ) CompileError!Air.Inst.Ref {
   5290     var managed = sema.mod.compile_log_text.toManaged(sema.gpa);
   5291     defer sema.mod.compile_log_text = managed.moveToUnmanaged();
   5292     const writer = managed.writer();
   5293 
   5294     const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand);
   5295     const src_node = extra.data.src_node;
   5296     const args = sema.code.refSlice(extra.end, extended.small);
   5297 
   5298     for (args, 0..) |arg_ref, i| {
   5299         if (i != 0) try writer.print(", ", .{});
   5300 
   5301         const arg = try sema.resolveInst(arg_ref);
   5302         const arg_ty = sema.typeOf(arg);
   5303         if (try sema.resolveMaybeUndefLazyVal(arg)) |val| {
   5304             try writer.print("@as({}, {})", .{
   5305                 arg_ty.fmt(sema.mod), val.fmtValue(arg_ty, sema.mod),
   5306             });
   5307         } else {
   5308             try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(sema.mod)});
   5309         }
   5310     }
   5311     try writer.print("\n", .{});
   5312 
   5313     const decl_index = if (sema.func) |some| some.owner_decl else sema.owner_decl_index;
   5314     const gop = try sema.mod.compile_log_decls.getOrPut(sema.gpa, decl_index);
   5315     if (!gop.found_existing) {
   5316         gop.value_ptr.* = src_node;
   5317     }
   5318     return Air.Inst.Ref.void_value;
   5319 }
   5320 
   5321 fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
   5322     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   5323     const src = inst_data.src();
   5324     const msg_inst = try sema.resolveInst(inst_data.operand);
   5325 
   5326     if (block.is_comptime) {
   5327         return sema.fail(block, src, "encountered @panic at comptime", .{});
   5328     }
   5329     try sema.panicWithMsg(block, msg_inst);
   5330     return always_noreturn;
   5331 }
   5332 
   5333 fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
   5334     const src_node = sema.code.instructions.items(.data)[inst].node;
   5335     const src = LazySrcLoc.nodeOffset(src_node);
   5336     sema.src = src;
   5337     _ = try block.addNoOp(.trap);
   5338     return always_noreturn;
   5339 }
   5340 
   5341 fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   5342     const tracy = trace(@src());
   5343     defer tracy.end();
   5344 
   5345     const mod = sema.mod;
   5346     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   5347     const src = inst_data.src();
   5348     const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
   5349     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
   5350     const gpa = sema.gpa;
   5351 
   5352     // AIR expects a block outside the loop block too.
   5353     // Reserve space for a Loop instruction so that generated Break instructions can
   5354     // point to it, even if it doesn't end up getting used because the code ends up being
   5355     // comptime evaluated.
   5356     const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
   5357     const loop_inst = block_inst + 1;
   5358     try sema.air_instructions.ensureUnusedCapacity(gpa, 2);
   5359     sema.air_instructions.appendAssumeCapacity(.{
   5360         .tag = .block,
   5361         .data = undefined,
   5362     });
   5363     sema.air_instructions.appendAssumeCapacity(.{
   5364         .tag = .loop,
   5365         .data = .{ .ty_pl = .{
   5366             .ty = .noreturn_type,
   5367             .payload = undefined,
   5368         } },
   5369     });
   5370     var label: Block.Label = .{
   5371         .zir_block = inst,
   5372         .merges = .{
   5373             .src_locs = .{},
   5374             .results = .{},
   5375             .br_list = .{},
   5376             .block_inst = block_inst,
   5377         },
   5378     };
   5379     var child_block = parent_block.makeSubBlock();
   5380     child_block.label = &label;
   5381     child_block.runtime_cond = null;
   5382     child_block.runtime_loop = src;
   5383     child_block.runtime_index.increment();
   5384     const merges = &child_block.label.?.merges;
   5385 
   5386     defer child_block.instructions.deinit(gpa);
   5387     defer merges.deinit(gpa);
   5388 
   5389     var loop_block = child_block.makeSubBlock();
   5390     defer loop_block.instructions.deinit(gpa);
   5391 
   5392     try sema.analyzeBody(&loop_block, body);
   5393 
   5394     const loop_block_len = loop_block.instructions.items.len;
   5395     if (loop_block_len > 0 and sema.typeOf(Air.indexToRef(loop_block.instructions.items[loop_block_len - 1])).isNoReturn(mod)) {
   5396         // If the loop ended with a noreturn terminator, then there is no way for it to loop,
   5397         // so we can just use the block instead.
   5398         try child_block.instructions.appendSlice(gpa, loop_block.instructions.items);
   5399     } else {
   5400         try child_block.instructions.append(gpa, loop_inst);
   5401 
   5402         try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + loop_block_len);
   5403         sema.air_instructions.items(.data)[loop_inst].ty_pl.payload = sema.addExtraAssumeCapacity(
   5404             Air.Block{ .body_len = @intCast(u32, loop_block_len) },
   5405         );
   5406         sema.air_extra.appendSliceAssumeCapacity(loop_block.instructions.items);
   5407     }
   5408     return sema.analyzeBlockBody(parent_block, src, &child_block, merges);
   5409 }
   5410 
   5411 fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   5412     const tracy = trace(@src());
   5413     defer tracy.end();
   5414 
   5415     const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
   5416     const src = pl_node.src();
   5417     const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index);
   5418     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
   5419 
   5420     // we check this here to avoid undefined symbols
   5421     if (!@import("build_options").have_llvm)
   5422         return sema.fail(parent_block, src, "cannot do C import on Zig compiler not built with LLVM-extension", .{});
   5423 
   5424     var c_import_buf = std.ArrayList(u8).init(sema.gpa);
   5425     defer c_import_buf.deinit();
   5426 
   5427     var comptime_reason: Block.ComptimeReason = .{ .c_import = .{
   5428         .block = parent_block,
   5429         .src = src,
   5430     } };
   5431     var child_block: Block = .{
   5432         .parent = parent_block,
   5433         .sema = sema,
   5434         .src_decl = parent_block.src_decl,
   5435         .namespace = parent_block.namespace,
   5436         .wip_capture_scope = parent_block.wip_capture_scope,
   5437         .instructions = .{},
   5438         .inlining = parent_block.inlining,
   5439         .is_comptime = true,
   5440         .comptime_reason = &comptime_reason,
   5441         .c_import_buf = &c_import_buf,
   5442         .runtime_cond = parent_block.runtime_cond,
   5443         .runtime_loop = parent_block.runtime_loop,
   5444         .runtime_index = parent_block.runtime_index,
   5445     };
   5446     defer child_block.instructions.deinit(sema.gpa);
   5447 
   5448     // Ignore the result, all the relevant operations have written to c_import_buf already.
   5449     _ = try sema.analyzeBodyBreak(&child_block, body);
   5450 
   5451     const mod = sema.mod;
   5452     const c_import_res = mod.comp.cImport(c_import_buf.items) catch |err|
   5453         return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
   5454 
   5455     if (c_import_res.errors.len != 0) {
   5456         const msg = msg: {
   5457             defer @import("clang.zig").ErrorMsg.delete(c_import_res.errors.ptr, c_import_res.errors.len);
   5458 
   5459             const msg = try sema.errMsg(&child_block, src, "C import failed", .{});
   5460             errdefer msg.destroy(sema.gpa);
   5461 
   5462             if (!mod.comp.bin_file.options.link_libc)
   5463                 try sema.errNote(&child_block, src, msg, "libc headers not available; compilation does not link against libc", .{});
   5464 
   5465             const gop = try sema.mod.cimport_errors.getOrPut(sema.gpa, sema.owner_decl_index);
   5466             if (!gop.found_existing) {
   5467                 var errs = try std.ArrayListUnmanaged(Module.CImportError).initCapacity(sema.gpa, c_import_res.errors.len);
   5468                 errdefer {
   5469                     for (errs.items) |err| err.deinit(sema.gpa);
   5470                     errs.deinit(sema.gpa);
   5471                 }
   5472 
   5473                 for (c_import_res.errors) |c_error| {
   5474                     const path = if (c_error.filename_ptr) |some|
   5475                         try sema.gpa.dupeZ(u8, some[0..c_error.filename_len])
   5476                     else
   5477                         null;
   5478                     errdefer if (path) |some| sema.gpa.free(some);
   5479 
   5480                     const c_msg = try sema.gpa.dupeZ(u8, c_error.msg_ptr[0..c_error.msg_len]);
   5481                     errdefer sema.gpa.free(c_msg);
   5482 
   5483                     const line = line: {
   5484                         const source = c_error.source orelse break :line null;
   5485                         var start = c_error.offset;
   5486                         while (start > 0) : (start -= 1) {
   5487                             if (source[start - 1] == '\n') break;
   5488                         }
   5489                         var end = c_error.offset;
   5490                         while (true) : (end += 1) {
   5491                             if (source[end] == 0) break;
   5492                             if (source[end] == '\n') break;
   5493                         }
   5494                         break :line try sema.gpa.dupeZ(u8, source[start..end]);
   5495                     };
   5496                     errdefer if (line) |some| sema.gpa.free(some);
   5497 
   5498                     errs.appendAssumeCapacity(.{
   5499                         .path = path orelse null,
   5500                         .source_line = line orelse null,
   5501                         .line = c_error.line,
   5502                         .column = c_error.column,
   5503                         .offset = c_error.offset,
   5504                         .msg = c_msg,
   5505                     });
   5506                 }
   5507                 gop.value_ptr.* = errs.items;
   5508             }
   5509             break :msg msg;
   5510         };
   5511         return sema.failWithOwnedErrorMsg(msg);
   5512     }
   5513     const c_import_pkg = Package.create(
   5514         sema.gpa,
   5515         null,
   5516         c_import_res.out_zig_path,
   5517     ) catch |err| switch (err) {
   5518         error.OutOfMemory => return error.OutOfMemory,
   5519         else => unreachable, // we pass null for root_src_dir_path
   5520     };
   5521 
   5522     const result = mod.importPkg(c_import_pkg) catch |err|
   5523         return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
   5524 
   5525     mod.astGenFile(result.file) catch |err|
   5526         return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
   5527 
   5528     try mod.semaFile(result.file);
   5529     const file_root_decl_index = result.file.root_decl.unwrap().?;
   5530     const file_root_decl = mod.declPtr(file_root_decl_index);
   5531     try mod.declareDeclDependency(sema.owner_decl_index, file_root_decl_index);
   5532     return sema.addConstant(file_root_decl.ty, file_root_decl.val);
   5533 }
   5534 
   5535 fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   5536     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   5537     const src = inst_data.src();
   5538     return sema.failWithUseOfAsync(parent_block, src);
   5539 }
   5540 
   5541 fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index, force_comptime: bool) CompileError!Air.Inst.Ref {
   5542     const tracy = trace(@src());
   5543     defer tracy.end();
   5544 
   5545     const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
   5546     const src = pl_node.src();
   5547     const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index);
   5548     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
   5549     const gpa = sema.gpa;
   5550 
   5551     // Reserve space for a Block instruction so that generated Break instructions can
   5552     // point to it, even if it doesn't end up getting used because the code ends up being
   5553     // comptime evaluated or is an unlabeled block.
   5554     const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
   5555     try sema.air_instructions.append(gpa, .{
   5556         .tag = .block,
   5557         .data = undefined,
   5558     });
   5559 
   5560     var label: Block.Label = .{
   5561         .zir_block = inst,
   5562         .merges = .{
   5563             .src_locs = .{},
   5564             .results = .{},
   5565             .br_list = .{},
   5566             .block_inst = block_inst,
   5567         },
   5568     };
   5569 
   5570     var child_block: Block = .{
   5571         .parent = parent_block,
   5572         .sema = sema,
   5573         .src_decl = parent_block.src_decl,
   5574         .namespace = parent_block.namespace,
   5575         .wip_capture_scope = parent_block.wip_capture_scope,
   5576         .instructions = .{},
   5577         .label = &label,
   5578         .inlining = parent_block.inlining,
   5579         .is_comptime = parent_block.is_comptime or force_comptime,
   5580         .comptime_reason = parent_block.comptime_reason,
   5581         .is_typeof = parent_block.is_typeof,
   5582         .want_safety = parent_block.want_safety,
   5583         .float_mode = parent_block.float_mode,
   5584         .c_import_buf = parent_block.c_import_buf,
   5585         .runtime_cond = parent_block.runtime_cond,
   5586         .runtime_loop = parent_block.runtime_loop,
   5587         .runtime_index = parent_block.runtime_index,
   5588         .error_return_trace_index = parent_block.error_return_trace_index,
   5589     };
   5590 
   5591     defer child_block.instructions.deinit(gpa);
   5592     defer label.merges.deinit(gpa);
   5593 
   5594     return sema.resolveBlockBody(parent_block, src, &child_block, body, inst, &label.merges);
   5595 }
   5596 
   5597 fn resolveBlockBody(
   5598     sema: *Sema,
   5599     parent_block: *Block,
   5600     src: LazySrcLoc,
   5601     child_block: *Block,
   5602     body: []const Zir.Inst.Index,
   5603     /// This is the instruction that a break instruction within `body` can
   5604     /// use to return from the body.
   5605     body_inst: Zir.Inst.Index,
   5606     merges: *Block.Merges,
   5607 ) CompileError!Air.Inst.Ref {
   5608     if (child_block.is_comptime) {
   5609         return sema.resolveBody(child_block, body, body_inst);
   5610     } else {
   5611         if (sema.analyzeBodyInner(child_block, body)) |_| {
   5612             return sema.analyzeBlockBody(parent_block, src, child_block, merges);
   5613         } else |err| switch (err) {
   5614             error.ComptimeBreak => {
   5615                 // Comptime control flow is happening, however child_block may still contain
   5616                 // runtime instructions which need to be copied to the parent block.
   5617                 try parent_block.instructions.appendSlice(sema.gpa, child_block.instructions.items);
   5618 
   5619                 const break_inst = sema.comptime_break_inst;
   5620                 const break_data = sema.code.instructions.items(.data)[break_inst].@"break";
   5621                 const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data;
   5622                 if (extra.block_inst == body_inst) {
   5623                     return try sema.resolveInst(break_data.operand);
   5624                 } else {
   5625                     return error.ComptimeBreak;
   5626                 }
   5627             },
   5628             else => |e| return e,
   5629         }
   5630     }
   5631 }
   5632 
   5633 fn analyzeBlockBody(
   5634     sema: *Sema,
   5635     parent_block: *Block,
   5636     src: LazySrcLoc,
   5637     child_block: *Block,
   5638     merges: *Block.Merges,
   5639 ) CompileError!Air.Inst.Ref {
   5640     const tracy = trace(@src());
   5641     defer tracy.end();
   5642 
   5643     const gpa = sema.gpa;
   5644     const mod = sema.mod;
   5645 
   5646     // Blocks must terminate with noreturn instruction.
   5647     assert(child_block.instructions.items.len != 0);
   5648     assert(sema.typeOf(Air.indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1])).isNoReturn(mod));
   5649 
   5650     if (merges.results.items.len == 0) {
   5651         // No need for a block instruction. We can put the new instructions
   5652         // directly into the parent block.
   5653         try parent_block.instructions.appendSlice(gpa, child_block.instructions.items);
   5654         return Air.indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1]);
   5655     }
   5656     if (merges.results.items.len == 1) {
   5657         const last_inst_index = child_block.instructions.items.len - 1;
   5658         const last_inst = child_block.instructions.items[last_inst_index];
   5659         if (sema.getBreakBlock(last_inst)) |br_block| {
   5660             if (br_block == merges.block_inst) {
   5661                 // No need for a block instruction. We can put the new instructions directly
   5662                 // into the parent block. Here we omit the break instruction.
   5663                 const without_break = child_block.instructions.items[0..last_inst_index];
   5664                 try parent_block.instructions.appendSlice(gpa, without_break);
   5665                 return merges.results.items[0];
   5666             }
   5667         }
   5668     }
   5669     // It is impossible to have the number of results be > 1 in a comptime scope.
   5670     assert(!child_block.is_comptime); // Should already got a compile error in the condbr condition.
   5671 
   5672     // Need to set the type and emit the Block instruction. This allows machine code generation
   5673     // to emit a jump instruction to after the block when it encounters the break.
   5674     try parent_block.instructions.append(gpa, merges.block_inst);
   5675     const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .{ .override = merges.src_locs.items });
   5676     // TODO add note "missing else causes void value"
   5677 
   5678     const type_src = src; // TODO: better source location
   5679     const valid_rt = try sema.validateRunTimeType(resolved_ty, false);
   5680     if (!valid_rt) {
   5681         const msg = msg: {
   5682             const msg = try sema.errMsg(child_block, type_src, "value with comptime-only type '{}' depends on runtime control flow", .{resolved_ty.fmt(mod)});
   5683             errdefer msg.destroy(sema.gpa);
   5684 
   5685             const runtime_src = child_block.runtime_cond orelse child_block.runtime_loop.?;
   5686             try sema.errNote(child_block, runtime_src, msg, "runtime control flow here", .{});
   5687 
   5688             const child_src_decl = mod.declPtr(child_block.src_decl);
   5689             try sema.explainWhyTypeIsComptime(msg, type_src.toSrcLoc(child_src_decl, mod), resolved_ty);
   5690 
   5691             break :msg msg;
   5692         };
   5693         return sema.failWithOwnedErrorMsg(msg);
   5694     }
   5695     const ty_inst = try sema.addType(resolved_ty);
   5696     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
   5697         child_block.instructions.items.len);
   5698     sema.air_instructions.items(.data)[merges.block_inst] = .{ .ty_pl = .{
   5699         .ty = ty_inst,
   5700         .payload = sema.addExtraAssumeCapacity(Air.Block{
   5701             .body_len = @intCast(u32, child_block.instructions.items.len),
   5702         }),
   5703     } };
   5704     sema.air_extra.appendSliceAssumeCapacity(child_block.instructions.items);
   5705     // Now that the block has its type resolved, we need to go back into all the break
   5706     // instructions, and insert type coercion on the operands.
   5707     for (merges.br_list.items) |br| {
   5708         const br_operand = sema.air_instructions.items(.data)[br].br.operand;
   5709         const br_operand_src = src;
   5710         const br_operand_ty = sema.typeOf(br_operand);
   5711         if (br_operand_ty.eql(resolved_ty, mod)) {
   5712             // No type coercion needed.
   5713             continue;
   5714         }
   5715         var coerce_block = parent_block.makeSubBlock();
   5716         defer coerce_block.instructions.deinit(gpa);
   5717         const coerced_operand = try sema.coerce(&coerce_block, resolved_ty, br_operand, br_operand_src);
   5718         // If no instructions were produced, such as in the case of a coercion of a
   5719         // constant value to a new type, we can simply point the br operand to it.
   5720         if (coerce_block.instructions.items.len == 0) {
   5721             sema.air_instructions.items(.data)[br].br.operand = coerced_operand;
   5722             continue;
   5723         }
   5724         assert(coerce_block.instructions.items[coerce_block.instructions.items.len - 1] ==
   5725             Air.refToIndex(coerced_operand).?);
   5726 
   5727         // Convert the br instruction to a block instruction that has the coercion
   5728         // and then a new br inside that returns the coerced instruction.
   5729         const sub_block_len = @intCast(u32, coerce_block.instructions.items.len + 1);
   5730         try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
   5731             sub_block_len);
   5732         try sema.air_instructions.ensureUnusedCapacity(gpa, 1);
   5733         const sub_br_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
   5734 
   5735         sema.air_instructions.items(.tag)[br] = .block;
   5736         sema.air_instructions.items(.data)[br] = .{ .ty_pl = .{
   5737             .ty = Air.Inst.Ref.noreturn_type,
   5738             .payload = sema.addExtraAssumeCapacity(Air.Block{
   5739                 .body_len = sub_block_len,
   5740             }),
   5741         } };
   5742         sema.air_extra.appendSliceAssumeCapacity(coerce_block.instructions.items);
   5743         sema.air_extra.appendAssumeCapacity(sub_br_inst);
   5744 
   5745         sema.air_instructions.appendAssumeCapacity(.{
   5746             .tag = .br,
   5747             .data = .{ .br = .{
   5748                 .block_inst = merges.block_inst,
   5749                 .operand = coerced_operand,
   5750             } },
   5751         });
   5752     }
   5753     return Air.indexToRef(merges.block_inst);
   5754 }
   5755 
   5756 fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   5757     const tracy = trace(@src());
   5758     defer tracy.end();
   5759 
   5760     const mod = sema.mod;
   5761     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   5762     const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data;
   5763     const src = inst_data.src();
   5764     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   5765     const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   5766     const decl_name = sema.code.nullTerminatedString(extra.decl_name);
   5767     const decl_index = if (extra.namespace != .none) index_blk: {
   5768         const container_ty = try sema.resolveType(block, operand_src, extra.namespace);
   5769         const container_namespace = container_ty.getNamespaceIndex(mod).unwrap().?;
   5770 
   5771         const maybe_index = try sema.lookupInNamespace(block, operand_src, container_namespace, decl_name, false);
   5772         break :index_blk maybe_index orelse
   5773             return sema.failWithBadMemberAccess(block, container_ty, operand_src, decl_name);
   5774     } else try sema.lookupIdentifier(block, operand_src, decl_name);
   5775     const options = sema.resolveExportOptions(block, .unneeded, extra.options) catch |err| switch (err) {
   5776         error.NeededSourceLocation => {
   5777             _ = try sema.resolveExportOptions(block, options_src, extra.options);
   5778             unreachable;
   5779         },
   5780         else => |e| return e,
   5781     };
   5782     {
   5783         try mod.ensureDeclAnalyzed(decl_index);
   5784         const exported_decl = mod.declPtr(decl_index);
   5785         if (exported_decl.val.getFunction(mod)) |function| {
   5786             return sema.analyzeExport(block, src, options, function.owner_decl);
   5787         }
   5788     }
   5789     try sema.analyzeExport(block, src, options, decl_index);
   5790 }
   5791 
   5792 fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   5793     const tracy = trace(@src());
   5794     defer tracy.end();
   5795 
   5796     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   5797     const extra = sema.code.extraData(Zir.Inst.ExportValue, inst_data.payload_index).data;
   5798     const src = inst_data.src();
   5799     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   5800     const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   5801     const operand = try sema.resolveInstConst(block, operand_src, extra.operand, "export target must be comptime-known");
   5802     const options = sema.resolveExportOptions(block, .unneeded, extra.options) catch |err| switch (err) {
   5803         error.NeededSourceLocation => {
   5804             _ = try sema.resolveExportOptions(block, options_src, extra.options);
   5805             unreachable;
   5806         },
   5807         else => |e| return e,
   5808     };
   5809     const decl_index = if (operand.val.getFunction(sema.mod)) |function| function.owner_decl else blk: {
   5810         var anon_decl = try block.startAnonDecl();
   5811         defer anon_decl.deinit();
   5812         break :blk try anon_decl.finish(
   5813             operand.ty,
   5814             try operand.val.copy(anon_decl.arena()),
   5815             0,
   5816         );
   5817     };
   5818     try sema.analyzeExport(block, src, options, decl_index);
   5819 }
   5820 
   5821 pub fn analyzeExport(
   5822     sema: *Sema,
   5823     block: *Block,
   5824     src: LazySrcLoc,
   5825     borrowed_options: std.builtin.ExportOptions,
   5826     exported_decl_index: Decl.Index,
   5827 ) !void {
   5828     const Export = Module.Export;
   5829     const mod = sema.mod;
   5830 
   5831     if (borrowed_options.linkage == .Internal) {
   5832         return;
   5833     }
   5834 
   5835     try mod.ensureDeclAnalyzed(exported_decl_index);
   5836     const exported_decl = mod.declPtr(exported_decl_index);
   5837 
   5838     if (!try sema.validateExternType(exported_decl.ty, .other)) {
   5839         const msg = msg: {
   5840             const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(sema.mod)});
   5841             errdefer msg.destroy(sema.gpa);
   5842 
   5843             const src_decl = sema.mod.declPtr(block.src_decl);
   5844             try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), exported_decl.ty, .other);
   5845 
   5846             try sema.addDeclaredHereNote(msg, exported_decl.ty);
   5847             break :msg msg;
   5848         };
   5849         return sema.failWithOwnedErrorMsg(msg);
   5850     }
   5851 
   5852     // TODO: some backends might support re-exporting extern decls
   5853     if (exported_decl.isExtern(mod)) {
   5854         return sema.fail(block, src, "export target cannot be extern", .{});
   5855     }
   5856 
   5857     // This decl is alive no matter what, since it's being exported
   5858     try mod.markDeclAlive(exported_decl);
   5859     try sema.maybeQueueFuncBodyAnalysis(exported_decl_index);
   5860 
   5861     const gpa = sema.gpa;
   5862 
   5863     try mod.decl_exports.ensureUnusedCapacity(gpa, 1);
   5864     try mod.export_owners.ensureUnusedCapacity(gpa, 1);
   5865 
   5866     const new_export = try gpa.create(Export);
   5867     errdefer gpa.destroy(new_export);
   5868 
   5869     const symbol_name = try gpa.dupe(u8, borrowed_options.name);
   5870     errdefer gpa.free(symbol_name);
   5871 
   5872     const section: ?[]const u8 = if (borrowed_options.section) |s| try gpa.dupe(u8, s) else null;
   5873     errdefer if (section) |s| gpa.free(s);
   5874 
   5875     new_export.* = .{
   5876         .options = .{
   5877             .name = symbol_name,
   5878             .linkage = borrowed_options.linkage,
   5879             .section = section,
   5880             .visibility = borrowed_options.visibility,
   5881         },
   5882         .src = src,
   5883         .owner_decl = sema.owner_decl_index,
   5884         .src_decl = block.src_decl,
   5885         .exported_decl = exported_decl_index,
   5886         .status = .in_progress,
   5887     };
   5888 
   5889     // Add to export_owners table.
   5890     const eo_gop = mod.export_owners.getOrPutAssumeCapacity(sema.owner_decl_index);
   5891     if (!eo_gop.found_existing) {
   5892         eo_gop.value_ptr.* = .{};
   5893     }
   5894     try eo_gop.value_ptr.append(gpa, new_export);
   5895     errdefer _ = eo_gop.value_ptr.pop();
   5896 
   5897     // Add to exported_decl table.
   5898     const de_gop = mod.decl_exports.getOrPutAssumeCapacity(exported_decl_index);
   5899     if (!de_gop.found_existing) {
   5900         de_gop.value_ptr.* = .{};
   5901     }
   5902     try de_gop.value_ptr.append(gpa, new_export);
   5903     errdefer _ = de_gop.value_ptr.pop();
   5904 }
   5905 
   5906 fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
   5907     const mod = sema.mod;
   5908     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
   5909     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
   5910     const src = LazySrcLoc.nodeOffset(extra.node);
   5911     const alignment = try sema.resolveAlign(block, operand_src, extra.operand);
   5912     if (alignment > 256) {
   5913         return sema.fail(block, src, "attempt to @setAlignStack({d}); maximum is 256", .{
   5914             alignment,
   5915         });
   5916     }
   5917     const func_index = sema.func_index.unwrap() orelse
   5918         return sema.fail(block, src, "@setAlignStack outside function body", .{});
   5919     const func = mod.funcPtr(func_index);
   5920 
   5921     const fn_owner_decl = mod.declPtr(func.owner_decl);
   5922     switch (fn_owner_decl.ty.fnCallingConvention(mod)) {
   5923         .Naked => return sema.fail(block, src, "@setAlignStack in naked function", .{}),
   5924         .Inline => return sema.fail(block, src, "@setAlignStack in inline function", .{}),
   5925         else => if (block.inlining != null) {
   5926             return sema.fail(block, src, "@setAlignStack in inline call", .{});
   5927         },
   5928     }
   5929 
   5930     const gop = try mod.align_stack_fns.getOrPut(sema.gpa, func_index);
   5931     if (gop.found_existing) {
   5932         const msg = msg: {
   5933             const msg = try sema.errMsg(block, src, "multiple @setAlignStack in the same function body", .{});
   5934             errdefer msg.destroy(sema.gpa);
   5935             try sema.errNote(block, gop.value_ptr.src, msg, "other instance here", .{});
   5936             break :msg msg;
   5937         };
   5938         return sema.failWithOwnedErrorMsg(msg);
   5939     }
   5940     gop.value_ptr.* = .{ .alignment = alignment, .src = src };
   5941 }
   5942 
   5943 fn zirSetCold(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
   5944     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
   5945     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
   5946     const is_cold = try sema.resolveConstBool(block, operand_src, extra.operand, "operand to @setCold must be comptime-known");
   5947     const func = sema.func orelse return; // does nothing outside a function
   5948     func.is_cold = is_cold;
   5949 }
   5950 
   5951 fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
   5952     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
   5953     const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
   5954     block.float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, "FloatMode", "operand to @setFloatMode must be comptime-known");
   5955 }
   5956 
   5957 fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   5958     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   5959     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   5960     block.want_safety = try sema.resolveConstBool(block, operand_src, inst_data.operand, "operand to @setRuntimeSafety must be comptime-known");
   5961 }
   5962 
   5963 fn zirFence(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
   5964     if (block.is_comptime) return;
   5965 
   5966     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
   5967     const order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
   5968     const order = try sema.resolveAtomicOrder(block, order_src, extra.operand, "atomic order of @fence must be comptime-known");
   5969 
   5970     if (@enumToInt(order) < @enumToInt(std.builtin.AtomicOrder.Acquire)) {
   5971         return sema.fail(block, order_src, "atomic ordering must be Acquire or stricter", .{});
   5972     }
   5973 
   5974     _ = try block.addInst(.{
   5975         .tag = .fence,
   5976         .data = .{ .fence = order },
   5977     });
   5978 }
   5979 
   5980 fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
   5981     const tracy = trace(@src());
   5982     defer tracy.end();
   5983 
   5984     const inst_data = sema.code.instructions.items(.data)[inst].@"break";
   5985     const extra = sema.code.extraData(Zir.Inst.Break, inst_data.payload_index).data;
   5986     const operand = try sema.resolveInst(inst_data.operand);
   5987     const zir_block = extra.block_inst;
   5988 
   5989     var block = start_block;
   5990     while (true) {
   5991         if (block.label) |label| {
   5992             if (label.zir_block == zir_block) {
   5993                 const br_ref = try start_block.addBr(label.merges.block_inst, operand);
   5994                 const src_loc = if (extra.operand_src_node != Zir.Inst.Break.no_src_node)
   5995                     LazySrcLoc.nodeOffset(extra.operand_src_node)
   5996                 else
   5997                     null;
   5998                 try label.merges.src_locs.append(sema.gpa, src_loc);
   5999                 try label.merges.results.append(sema.gpa, operand);
   6000                 try label.merges.br_list.append(sema.gpa, Air.refToIndex(br_ref).?);
   6001                 block.runtime_index.increment();
   6002                 if (block.runtime_cond == null and block.runtime_loop == null) {
   6003                     block.runtime_cond = start_block.runtime_cond orelse start_block.runtime_loop;
   6004                     block.runtime_loop = start_block.runtime_loop;
   6005                 }
   6006                 return inst;
   6007             }
   6008         }
   6009         block = block.parent.?;
   6010     }
   6011 }
   6012 
   6013 fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
   6014     // We do not set sema.src here because dbg_stmt instructions are only emitted for
   6015     // ZIR code that possibly will need to generate runtime code. So error messages
   6016     // and other source locations must not rely on sema.src being set from dbg_stmt
   6017     // instructions.
   6018     if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return;
   6019 
   6020     const inst_data = sema.code.instructions.items(.data)[inst].dbg_stmt;
   6021 
   6022     if (block.instructions.items.len != 0) {
   6023         const idx = block.instructions.items[block.instructions.items.len - 1];
   6024         if (sema.air_instructions.items(.tag)[idx] == .dbg_stmt) {
   6025             // The previous dbg_stmt didn't correspond to any actual code, so replace it.
   6026             sema.air_instructions.items(.data)[idx].dbg_stmt = .{
   6027                 .line = inst_data.line,
   6028                 .column = inst_data.column,
   6029             };
   6030             return;
   6031         }
   6032     }
   6033 
   6034     _ = try block.addInst(.{
   6035         .tag = .dbg_stmt,
   6036         .data = .{ .dbg_stmt = .{
   6037             .line = inst_data.line,
   6038             .column = inst_data.column,
   6039         } },
   6040     });
   6041 }
   6042 
   6043 fn zirDbgBlockBegin(sema: *Sema, block: *Block) CompileError!void {
   6044     if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return;
   6045 
   6046     _ = try block.addInst(.{
   6047         .tag = .dbg_block_begin,
   6048         .data = undefined,
   6049     });
   6050 }
   6051 
   6052 fn zirDbgBlockEnd(sema: *Sema, block: *Block) CompileError!void {
   6053     if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return;
   6054 
   6055     _ = try block.addInst(.{
   6056         .tag = .dbg_block_end,
   6057         .data = undefined,
   6058     });
   6059 }
   6060 
   6061 fn zirDbgVar(
   6062     sema: *Sema,
   6063     block: *Block,
   6064     inst: Zir.Inst.Index,
   6065     air_tag: Air.Inst.Tag,
   6066 ) CompileError!void {
   6067     if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return;
   6068 
   6069     const str_op = sema.code.instructions.items(.data)[inst].str_op;
   6070     const operand = try sema.resolveInst(str_op.operand);
   6071     const name = str_op.getStr(sema.code);
   6072     try sema.addDbgVar(block, operand, air_tag, name);
   6073 }
   6074 
   6075 fn addDbgVar(
   6076     sema: *Sema,
   6077     block: *Block,
   6078     operand: Air.Inst.Ref,
   6079     air_tag: Air.Inst.Tag,
   6080     name: []const u8,
   6081 ) CompileError!void {
   6082     const mod = sema.mod;
   6083     const operand_ty = sema.typeOf(operand);
   6084     switch (air_tag) {
   6085         .dbg_var_ptr => {
   6086             if (!(try sema.typeHasRuntimeBits(operand_ty.childType(mod)))) return;
   6087         },
   6088         .dbg_var_val => {
   6089             if (!(try sema.typeHasRuntimeBits(operand_ty))) return;
   6090         },
   6091         else => unreachable,
   6092     }
   6093 
   6094     try sema.queueFullTypeResolution(operand_ty);
   6095 
   6096     // Add the name to the AIR.
   6097     const name_extra_index = @intCast(u32, sema.air_extra.items.len);
   6098     const elements_used = name.len / 4 + 1;
   6099     try sema.air_extra.ensureUnusedCapacity(sema.gpa, elements_used);
   6100     const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
   6101     @memcpy(buffer[0..name.len], name);
   6102     buffer[name.len] = 0;
   6103     sema.air_extra.items.len += elements_used;
   6104 
   6105     _ = try block.addInst(.{
   6106         .tag = air_tag,
   6107         .data = .{ .pl_op = .{
   6108             .payload = name_extra_index,
   6109             .operand = operand,
   6110         } },
   6111     });
   6112 }
   6113 
   6114 fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   6115     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
   6116     const src = inst_data.src();
   6117     const decl_name = inst_data.get(sema.code);
   6118     const decl_index = try sema.lookupIdentifier(block, src, decl_name);
   6119     try sema.addReferencedBy(block, src, decl_index);
   6120     return sema.analyzeDeclRef(decl_index);
   6121 }
   6122 
   6123 fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   6124     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
   6125     const src = inst_data.src();
   6126     const decl_name = inst_data.get(sema.code);
   6127     const decl = try sema.lookupIdentifier(block, src, decl_name);
   6128     return sema.analyzeDeclVal(block, src, decl);
   6129 }
   6130 
   6131 fn lookupIdentifier(sema: *Sema, block: *Block, src: LazySrcLoc, name: []const u8) !Decl.Index {
   6132     const mod = sema.mod;
   6133     var namespace = block.namespace;
   6134     while (true) {
   6135         if (try sema.lookupInNamespace(block, src, namespace, name, false)) |decl_index| {
   6136             return decl_index;
   6137         }
   6138         namespace = mod.namespacePtr(namespace).parent.unwrap() orelse break;
   6139     }
   6140     unreachable; // AstGen detects use of undeclared identifier errors.
   6141 }
   6142 
   6143 /// This looks up a member of a specific namespace. It is affected by `usingnamespace` but
   6144 /// only for ones in the specified namespace.
   6145 fn lookupInNamespace(
   6146     sema: *Sema,
   6147     block: *Block,
   6148     src: LazySrcLoc,
   6149     namespace_index: Namespace.Index,
   6150     ident_name: []const u8,
   6151     observe_usingnamespace: bool,
   6152 ) CompileError!?Decl.Index {
   6153     const mod = sema.mod;
   6154 
   6155     const namespace = mod.namespacePtr(namespace_index);
   6156     const namespace_decl_index = namespace.getDeclIndex(mod);
   6157     const namespace_decl = sema.mod.declPtr(namespace_decl_index);
   6158     if (namespace_decl.analysis == .file_failure) {
   6159         try mod.declareDeclDependency(sema.owner_decl_index, namespace_decl_index);
   6160         return error.AnalysisFail;
   6161     }
   6162 
   6163     if (observe_usingnamespace and namespace.usingnamespace_set.count() != 0) {
   6164         const src_file = mod.namespacePtr(block.namespace).file_scope;
   6165 
   6166         const gpa = sema.gpa;
   6167         var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Namespace, bool) = .{};
   6168         defer checked_namespaces.deinit(gpa);
   6169 
   6170         // Keep track of name conflicts for error notes.
   6171         var candidates: std.ArrayListUnmanaged(Decl.Index) = .{};
   6172         defer candidates.deinit(gpa);
   6173 
   6174         try checked_namespaces.put(gpa, namespace, namespace.file_scope == src_file);
   6175         var check_i: usize = 0;
   6176 
   6177         while (check_i < checked_namespaces.count()) : (check_i += 1) {
   6178             const check_ns = checked_namespaces.keys()[check_i];
   6179             if (check_ns.decls.getKeyAdapted(ident_name, Module.DeclAdapter{ .mod = mod })) |decl_index| {
   6180                 // Skip decls which are not marked pub, which are in a different
   6181                 // file than the `a.b`/`@hasDecl` syntax.
   6182                 const decl = mod.declPtr(decl_index);
   6183                 if (decl.is_pub or (src_file == decl.getFileScope(mod) and checked_namespaces.values()[check_i])) {
   6184                     try candidates.append(gpa, decl_index);
   6185                 }
   6186             }
   6187             var it = check_ns.usingnamespace_set.iterator();
   6188             while (it.next()) |entry| {
   6189                 const sub_usingnamespace_decl_index = entry.key_ptr.*;
   6190                 // Skip the decl we're currently analysing.
   6191                 if (sub_usingnamespace_decl_index == sema.owner_decl_index) continue;
   6192                 const sub_usingnamespace_decl = mod.declPtr(sub_usingnamespace_decl_index);
   6193                 const sub_is_pub = entry.value_ptr.*;
   6194                 if (!sub_is_pub and src_file != sub_usingnamespace_decl.getFileScope(mod)) {
   6195                     // Skip usingnamespace decls which are not marked pub, which are in
   6196                     // a different file than the `a.b`/`@hasDecl` syntax.
   6197                     continue;
   6198                 }
   6199                 try sema.ensureDeclAnalyzed(sub_usingnamespace_decl_index);
   6200                 const ns_ty = sub_usingnamespace_decl.val.toType();
   6201                 const sub_ns = ns_ty.getNamespace(mod).?;
   6202                 try checked_namespaces.put(gpa, sub_ns, src_file == sub_usingnamespace_decl.getFileScope(mod));
   6203             }
   6204         }
   6205 
   6206         {
   6207             var i: usize = 0;
   6208             while (i < candidates.items.len) {
   6209                 if (candidates.items[i] == sema.owner_decl_index) {
   6210                     _ = candidates.orderedRemove(i);
   6211                 } else {
   6212                     i += 1;
   6213                 }
   6214             }
   6215         }
   6216 
   6217         switch (candidates.items.len) {
   6218             0 => {},
   6219             1 => {
   6220                 const decl_index = candidates.items[0];
   6221                 try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
   6222                 return decl_index;
   6223             },
   6224             else => {
   6225                 const msg = msg: {
   6226                     const msg = try sema.errMsg(block, src, "ambiguous reference", .{});
   6227                     errdefer msg.destroy(gpa);
   6228                     for (candidates.items) |candidate_index| {
   6229                         const candidate = mod.declPtr(candidate_index);
   6230                         const src_loc = candidate.srcLoc(mod);
   6231                         try mod.errNoteNonLazy(src_loc, msg, "declared here", .{});
   6232                     }
   6233                     break :msg msg;
   6234                 };
   6235                 return sema.failWithOwnedErrorMsg(msg);
   6236             },
   6237         }
   6238     } else if (namespace.decls.getKeyAdapted(ident_name, Module.DeclAdapter{ .mod = mod })) |decl_index| {
   6239         try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
   6240         return decl_index;
   6241     }
   6242 
   6243     log.debug("{*} ({s}) depends on non-existence of '{s}' in {*} ({s})", .{
   6244         sema.owner_decl, sema.owner_decl.name, ident_name, namespace_decl, namespace_decl.name,
   6245     });
   6246     // TODO This dependency is too strong. Really, it should only be a dependency
   6247     // on the non-existence of `ident_name` in the namespace. We can lessen the number of
   6248     // outdated declarations by making this dependency more sophisticated.
   6249     try mod.declareDeclDependency(sema.owner_decl_index, namespace_decl_index);
   6250     return null;
   6251 }
   6252 
   6253 fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl {
   6254     const mod = sema.mod;
   6255     const func_val = (try sema.resolveMaybeUndefVal(func_inst)) orelse return null;
   6256     if (func_val.isUndef(mod)) return null;
   6257     const owner_decl_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
   6258         .extern_func => |extern_func| extern_func.decl,
   6259         .func => |func| mod.funcPtr(func.index).owner_decl,
   6260         .ptr => |ptr| switch (ptr.addr) {
   6261             .decl => |decl| mod.declPtr(decl).val.getFunction(mod).?.owner_decl,
   6262             else => return null,
   6263         },
   6264         else => return null,
   6265     };
   6266     return mod.declPtr(owner_decl_index);
   6267 }
   6268 
   6269 pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref {
   6270     const src = sema.src;
   6271 
   6272     if (!sema.mod.backendSupportsFeature(.error_return_trace)) return .none;
   6273     if (!sema.mod.comp.bin_file.options.error_return_tracing) return .none;
   6274 
   6275     if (block.is_comptime)
   6276         return .none;
   6277 
   6278     const unresolved_stack_trace_ty = sema.getBuiltinType("StackTrace") catch |err| switch (err) {
   6279         error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,
   6280         else => |e| return e,
   6281     };
   6282     const stack_trace_ty = sema.resolveTypeFields(unresolved_stack_trace_ty) catch |err| switch (err) {
   6283         error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,
   6284         else => |e| return e,
   6285     };
   6286     const field_index = sema.structFieldIndex(block, stack_trace_ty, "index", src) catch |err| switch (err) {
   6287         error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,
   6288         else => |e| return e,
   6289     };
   6290 
   6291     return try block.addInst(.{
   6292         .tag = .save_err_return_trace_index,
   6293         .data = .{ .ty_pl = .{
   6294             .ty = try sema.addType(stack_trace_ty),
   6295             .payload = @intCast(u32, field_index),
   6296         } },
   6297     });
   6298 }
   6299 
   6300 /// Add instructions to block to "pop" the error return trace.
   6301 /// If `operand` is provided, only pops if operand is non-error.
   6302 fn popErrorReturnTrace(
   6303     sema: *Sema,
   6304     block: *Block,
   6305     src: LazySrcLoc,
   6306     operand: Air.Inst.Ref,
   6307     saved_error_trace_index: Air.Inst.Ref,
   6308 ) CompileError!void {
   6309     const mod = sema.mod;
   6310     var is_non_error: ?bool = null;
   6311     var is_non_error_inst: Air.Inst.Ref = undefined;
   6312     if (operand != .none) {
   6313         is_non_error_inst = try sema.analyzeIsNonErr(block, src, operand);
   6314         if (try sema.resolveDefinedValue(block, src, is_non_error_inst)) |cond_val|
   6315             is_non_error = cond_val.toBool();
   6316     } else is_non_error = true; // no operand means pop unconditionally
   6317 
   6318     if (is_non_error == true) {
   6319         // AstGen determined this result does not go to an error-handling expr (try/catch/return etc.), or
   6320         // the result is comptime-known to be a non-error. Either way, pop unconditionally.
   6321 
   6322         const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
   6323         const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
   6324         const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty);
   6325         const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
   6326         const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, "index", src, stack_trace_ty, true);
   6327         try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store);
   6328     } else if (is_non_error == null) {
   6329         // The result might be an error. If it is, we leave the error trace alone. If it isn't, we need
   6330         // to pop any error trace that may have been propagated from our arguments.
   6331 
   6332         try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Block).Struct.fields.len);
   6333         const cond_block_inst = try block.addInstAsIndex(.{
   6334             .tag = .block,
   6335             .data = .{
   6336                 .ty_pl = .{
   6337                     .ty = Air.Inst.Ref.void_type,
   6338                     .payload = undefined, // updated below
   6339                 },
   6340             },
   6341         });
   6342 
   6343         var then_block = block.makeSubBlock();
   6344         defer then_block.instructions.deinit(sema.gpa);
   6345 
   6346         // If non-error, then pop the error return trace by restoring the index.
   6347         const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
   6348         const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
   6349         const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty);
   6350         const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty);
   6351         const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, "index", src, stack_trace_ty, true);
   6352         try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store);
   6353         _ = try then_block.addBr(cond_block_inst, Air.Inst.Ref.void_value);
   6354 
   6355         // Otherwise, do nothing
   6356         var else_block = block.makeSubBlock();
   6357         defer else_block.instructions.deinit(sema.gpa);
   6358         _ = try else_block.addBr(cond_block_inst, Air.Inst.Ref.void_value);
   6359 
   6360         try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.CondBr).Struct.fields.len +
   6361             then_block.instructions.items.len + else_block.instructions.items.len +
   6362             @typeInfo(Air.Block).Struct.fields.len + 1); // +1 for the sole .cond_br instruction in the .block
   6363 
   6364         const cond_br_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
   6365         try sema.air_instructions.append(sema.gpa, .{ .tag = .cond_br, .data = .{ .pl_op = .{
   6366             .operand = is_non_error_inst,
   6367             .payload = sema.addExtraAssumeCapacity(Air.CondBr{
   6368                 .then_body_len = @intCast(u32, then_block.instructions.items.len),
   6369                 .else_body_len = @intCast(u32, else_block.instructions.items.len),
   6370             }),
   6371         } } });
   6372         sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items);
   6373         sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items);
   6374 
   6375         sema.air_instructions.items(.data)[cond_block_inst].ty_pl.payload = sema.addExtraAssumeCapacity(Air.Block{ .body_len = 1 });
   6376         sema.air_extra.appendAssumeCapacity(cond_br_inst);
   6377     }
   6378 }
   6379 
   6380 fn zirCall(
   6381     sema: *Sema,
   6382     block: *Block,
   6383     inst: Zir.Inst.Index,
   6384     comptime kind: enum { direct, field },
   6385 ) CompileError!Air.Inst.Ref {
   6386     const tracy = trace(@src());
   6387     defer tracy.end();
   6388 
   6389     const mod = sema.mod;
   6390     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   6391     const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
   6392     const call_src = inst_data.src();
   6393     const ExtraType = switch (kind) {
   6394         .direct => Zir.Inst.Call,
   6395         .field => Zir.Inst.FieldCall,
   6396     };
   6397     const extra = sema.code.extraData(ExtraType, inst_data.payload_index);
   6398     const args_len = extra.data.flags.args_len;
   6399 
   6400     const modifier = @intToEnum(std.builtin.CallModifier, extra.data.flags.packed_modifier);
   6401     const ensure_result_used = extra.data.flags.ensure_result_used;
   6402     const pop_error_return_trace = extra.data.flags.pop_error_return_trace;
   6403 
   6404     const callee: ResolvedFieldCallee = switch (kind) {
   6405         .direct => .{ .direct = try sema.resolveInst(extra.data.callee) },
   6406         .field => blk: {
   6407             const object_ptr = try sema.resolveInst(extra.data.obj_ptr);
   6408             const field_name = sema.code.nullTerminatedString(extra.data.field_name_start);
   6409             const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
   6410             break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src);
   6411         },
   6412     };
   6413     var resolved_args: []Air.Inst.Ref = undefined;
   6414     var bound_arg_src: ?LazySrcLoc = null;
   6415     var func: Air.Inst.Ref = undefined;
   6416     var arg_index: u32 = 0;
   6417     switch (callee) {
   6418         .direct => |func_inst| {
   6419             resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
   6420             func = func_inst;
   6421         },
   6422         .method => |method| {
   6423             resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
   6424             func = method.func_inst;
   6425             resolved_args[0] = method.arg0_inst;
   6426             arg_index += 1;
   6427             bound_arg_src = callee_src;
   6428         },
   6429     }
   6430 
   6431     const callee_ty = sema.typeOf(func);
   6432     const total_args = args_len + @boolToInt(bound_arg_src != null);
   6433     const func_ty = try sema.checkCallArgumentCount(block, func, callee_src, callee_ty, total_args, bound_arg_src != null);
   6434 
   6435     const args_body = sema.code.extra[extra.end..];
   6436 
   6437     var input_is_error = false;
   6438     const block_index = @intCast(Air.Inst.Index, block.instructions.items.len);
   6439 
   6440     const fn_params_len = mod.typeToFunc(func_ty).?.param_types.len;
   6441     const parent_comptime = block.is_comptime;
   6442     // `extra_index` and `arg_index` are separate since the bound function is passed as the first argument.
   6443     var extra_index: usize = 0;
   6444     var arg_start: u32 = args_len;
   6445     while (extra_index < args_len) : ({
   6446         extra_index += 1;
   6447         arg_index += 1;
   6448     }) {
   6449         const func_ty_info = mod.typeToFunc(func_ty).?;
   6450         const arg_end = sema.code.extra[extra.end + extra_index];
   6451         defer arg_start = arg_end;
   6452 
   6453         // Generate args to comptime params in comptime block.
   6454         defer block.is_comptime = parent_comptime;
   6455         if (arg_index < @min(fn_params_len, 32) and func_ty_info.paramIsComptime(@intCast(u5, arg_index))) {
   6456             block.is_comptime = true;
   6457             // TODO set comptime_reason
   6458         }
   6459 
   6460         sema.inst_map.putAssumeCapacity(inst, inst: {
   6461             if (arg_index >= fn_params_len)
   6462                 break :inst Air.Inst.Ref.var_args_param_type;
   6463 
   6464             if (func_ty_info.param_types[arg_index] == .generic_poison_type)
   6465                 break :inst Air.Inst.Ref.generic_poison_type;
   6466 
   6467             break :inst try sema.addType(func_ty_info.param_types[arg_index].toType());
   6468         });
   6469 
   6470         const resolved = try sema.resolveBody(block, args_body[arg_start..arg_end], inst);
   6471         const resolved_ty = sema.typeOf(resolved);
   6472         if (resolved_ty.zigTypeTag(mod) == .NoReturn) {
   6473             return resolved;
   6474         }
   6475         if (resolved_ty.isError(mod)) {
   6476             input_is_error = true;
   6477         }
   6478         resolved_args[arg_index] = resolved;
   6479     }
   6480     if (sema.owner_func == null or !sema.owner_func.?.calls_or_awaits_errorable_fn) {
   6481         input_is_error = false; // input was an error type, but no errorable fn's were actually called
   6482     }
   6483 
   6484     // AstGen ensures that a call instruction is always preceded by a dbg_stmt instruction.
   6485     const call_dbg_node = inst - 1;
   6486 
   6487     if (sema.mod.backendSupportsFeature(.error_return_trace) and sema.mod.comp.bin_file.options.error_return_tracing and
   6488         !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace))
   6489     {
   6490         const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: {
   6491             break :b try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
   6492         };
   6493 
   6494         const return_ty = sema.typeOf(call_inst);
   6495         if (modifier != .always_tail and return_ty.isNoReturn(mod))
   6496             return call_inst; // call to "fn(...) noreturn", don't pop
   6497 
   6498         // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only
   6499         // need to clean-up our own trace if we were passed to a non-error-handling expression.
   6500         if (input_is_error or (pop_error_return_trace and modifier != .always_tail and return_ty.isError(mod))) {
   6501             const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
   6502             const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
   6503             const field_index = try sema.structFieldIndex(block, stack_trace_ty, "index", call_src);
   6504 
   6505             // Insert a save instruction before the arg resolution + call instructions we just generated
   6506             const save_inst = try block.insertInst(block_index, .{
   6507                 .tag = .save_err_return_trace_index,
   6508                 .data = .{ .ty_pl = .{
   6509                     .ty = try sema.addType(stack_trace_ty),
   6510                     .payload = @intCast(u32, field_index),
   6511                 } },
   6512             });
   6513 
   6514             // Pop the error return trace, testing the result for non-error if necessary
   6515             const operand = if (pop_error_return_trace or modifier == .always_tail) .none else call_inst;
   6516             try sema.popErrorReturnTrace(block, call_src, operand, save_inst);
   6517         }
   6518 
   6519         if (modifier == .always_tail) // Perform the call *after* the restore, so that a tail call is possible.
   6520             return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
   6521 
   6522         return call_inst;
   6523     } else {
   6524         return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
   6525     }
   6526 }
   6527 
   6528 fn checkCallArgumentCount(
   6529     sema: *Sema,
   6530     block: *Block,
   6531     func: Air.Inst.Ref,
   6532     func_src: LazySrcLoc,
   6533     callee_ty: Type,
   6534     total_args: usize,
   6535     member_fn: bool,
   6536 ) !Type {
   6537     const mod = sema.mod;
   6538     const func_ty = func_ty: {
   6539         switch (callee_ty.zigTypeTag(mod)) {
   6540             .Fn => break :func_ty callee_ty,
   6541             .Pointer => {
   6542                 const ptr_info = callee_ty.ptrInfo(mod);
   6543                 if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag(mod) == .Fn) {
   6544                     break :func_ty ptr_info.pointee_type;
   6545                 }
   6546             },
   6547             .Optional => {
   6548                 const opt_child = callee_ty.optionalChild(mod);
   6549                 if (opt_child.zigTypeTag(mod) == .Fn or (opt_child.isSinglePointer(mod) and
   6550                     opt_child.childType(mod).zigTypeTag(mod) == .Fn))
   6551                 {
   6552                     const msg = msg: {
   6553                         const msg = try sema.errMsg(block, func_src, "cannot call optional type '{}'", .{
   6554                             callee_ty.fmt(sema.mod),
   6555                         });
   6556                         errdefer msg.destroy(sema.gpa);
   6557                         try sema.errNote(block, func_src, msg, "consider using '.?', 'orelse' or 'if'", .{});
   6558                         break :msg msg;
   6559                     };
   6560                     return sema.failWithOwnedErrorMsg(msg);
   6561                 }
   6562             },
   6563             else => {},
   6564         }
   6565         return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
   6566     };
   6567 
   6568     const func_ty_info = mod.typeToFunc(func_ty).?;
   6569     const fn_params_len = func_ty_info.param_types.len;
   6570     const args_len = total_args - @boolToInt(member_fn);
   6571     if (func_ty_info.is_var_args) {
   6572         assert(func_ty_info.cc == .C);
   6573         if (total_args >= fn_params_len) return func_ty;
   6574     } else if (fn_params_len == total_args) {
   6575         return func_ty;
   6576     }
   6577 
   6578     const maybe_decl = try sema.funcDeclSrc(func);
   6579     const member_str = if (member_fn) "member function " else "";
   6580     const variadic_str = if (func_ty_info.is_var_args) "at least " else "";
   6581     const msg = msg: {
   6582         const msg = try sema.errMsg(
   6583             block,
   6584             func_src,
   6585             "{s}expected {s}{d} argument(s), found {d}",
   6586             .{
   6587                 member_str,
   6588                 variadic_str,
   6589                 fn_params_len - @boolToInt(member_fn),
   6590                 args_len,
   6591             },
   6592         );
   6593         errdefer msg.destroy(sema.gpa);
   6594 
   6595         if (maybe_decl) |fn_decl| try sema.mod.errNoteNonLazy(fn_decl.srcLoc(mod), msg, "function declared here", .{});
   6596         break :msg msg;
   6597     };
   6598     return sema.failWithOwnedErrorMsg(msg);
   6599 }
   6600 
   6601 fn callBuiltin(
   6602     sema: *Sema,
   6603     block: *Block,
   6604     builtin_fn: Air.Inst.Ref,
   6605     modifier: std.builtin.CallModifier,
   6606     args: []const Air.Inst.Ref,
   6607 ) !void {
   6608     const mod = sema.mod;
   6609     const callee_ty = sema.typeOf(builtin_fn);
   6610     const func_ty = func_ty: {
   6611         switch (callee_ty.zigTypeTag(mod)) {
   6612             .Fn => break :func_ty callee_ty,
   6613             .Pointer => {
   6614                 const ptr_info = callee_ty.ptrInfo(mod);
   6615                 if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag(mod) == .Fn) {
   6616                     break :func_ty ptr_info.pointee_type;
   6617                 }
   6618             },
   6619             else => {},
   6620         }
   6621         std.debug.panic("type '{}' is not a function calling builtin fn", .{callee_ty.fmt(sema.mod)});
   6622     };
   6623 
   6624     const func_ty_info = mod.typeToFunc(func_ty).?;
   6625     const fn_params_len = func_ty_info.param_types.len;
   6626     if (args.len != fn_params_len or (func_ty_info.is_var_args and args.len < fn_params_len)) {
   6627         std.debug.panic("parameter count mismatch calling builtin fn, expected {d}, found {d}", .{ fn_params_len, args.len });
   6628     }
   6629     _ = try sema.analyzeCall(block, builtin_fn, func_ty, sema.src, sema.src, modifier, false, args, null, null);
   6630 }
   6631 
   6632 const GenericCallAdapter = struct {
   6633     generic_fn: *Module.Fn,
   6634     precomputed_hash: u64,
   6635     func_ty_info: InternPool.Key.FuncType,
   6636     args: []const Arg,
   6637     module: *Module,
   6638 
   6639     const Arg = struct {
   6640         ty: Type,
   6641         val: Value,
   6642         is_anytype: bool,
   6643     };
   6644 
   6645     pub fn eql(ctx: @This(), adapted_key: void, other_key: Module.Fn.Index) bool {
   6646         _ = adapted_key;
   6647         const other_func = ctx.module.funcPtr(other_key);
   6648 
   6649         // Checking for equality may happen on an item that has been inserted
   6650         // into the map but is not yet fully initialized. In such case, the
   6651         // two initialized fields are `hash` and `generic_owner_decl`.
   6652         if (ctx.generic_fn.owner_decl != other_func.generic_owner_decl.unwrap().?) return false;
   6653 
   6654         const other_comptime_args = other_func.comptime_args.?;
   6655         for (other_comptime_args[0..ctx.func_ty_info.param_types.len], 0..) |other_arg, i| {
   6656             const this_arg = ctx.args[i];
   6657             const this_is_comptime = !this_arg.val.isGenericPoison();
   6658             const other_is_comptime = !other_arg.val.isGenericPoison();
   6659             const this_is_anytype = this_arg.is_anytype;
   6660             const other_is_anytype = other_func.isAnytypeParam(ctx.module, @intCast(u32, i));
   6661 
   6662             if (other_is_anytype != this_is_anytype) return false;
   6663             if (other_is_comptime != this_is_comptime) return false;
   6664 
   6665             if (this_is_anytype) {
   6666                 // Both are anytype parameters.
   6667                 if (!this_arg.ty.eql(other_arg.ty, ctx.module)) {
   6668                     return false;
   6669                 }
   6670                 if (this_is_comptime) {
   6671                     // Both are comptime and anytype parameters with matching types.
   6672                     if (!this_arg.val.eql(other_arg.val, other_arg.ty, ctx.module)) {
   6673                         return false;
   6674                     }
   6675                 }
   6676             } else if (this_is_comptime) {
   6677                 // Both are comptime parameters but not anytype parameters.
   6678                 // We assert no error is possible here because any lazy values must be resolved
   6679                 // before inserting into the generic function hash map.
   6680                 const is_eql = Value.eqlAdvanced(
   6681                     this_arg.val,
   6682                     this_arg.ty,
   6683                     other_arg.val,
   6684                     other_arg.ty,
   6685                     ctx.module,
   6686                     null,
   6687                 ) catch unreachable;
   6688                 if (!is_eql) {
   6689                     return false;
   6690                 }
   6691             }
   6692         }
   6693         return true;
   6694     }
   6695 
   6696     /// The implementation of the hash is in semantic analysis of function calls, so
   6697     /// that any errors when computing the hash can be properly reported.
   6698     pub fn hash(ctx: @This(), adapted_key: void) u64 {
   6699         _ = adapted_key;
   6700         return ctx.precomputed_hash;
   6701     }
   6702 };
   6703 
   6704 fn analyzeCall(
   6705     sema: *Sema,
   6706     block: *Block,
   6707     func: Air.Inst.Ref,
   6708     func_ty: Type,
   6709     func_src: LazySrcLoc,
   6710     call_src: LazySrcLoc,
   6711     modifier: std.builtin.CallModifier,
   6712     ensure_result_used: bool,
   6713     uncasted_args: []const Air.Inst.Ref,
   6714     bound_arg_src: ?LazySrcLoc,
   6715     call_dbg_node: ?Zir.Inst.Index,
   6716 ) CompileError!Air.Inst.Ref {
   6717     const mod = sema.mod;
   6718 
   6719     const callee_ty = sema.typeOf(func);
   6720     const func_ty_info = mod.typeToFunc(func_ty).?;
   6721     const fn_params_len = func_ty_info.param_types.len;
   6722     const cc = func_ty_info.cc;
   6723     if (cc == .Naked) {
   6724         const maybe_decl = try sema.funcDeclSrc(func);
   6725         const msg = msg: {
   6726             const msg = try sema.errMsg(
   6727                 block,
   6728                 func_src,
   6729                 "unable to call function with naked calling convention",
   6730                 .{},
   6731             );
   6732             errdefer msg.destroy(sema.gpa);
   6733 
   6734             if (maybe_decl) |fn_decl| try mod.errNoteNonLazy(fn_decl.srcLoc(mod), msg, "function declared here", .{});
   6735             break :msg msg;
   6736         };
   6737         return sema.failWithOwnedErrorMsg(msg);
   6738     }
   6739 
   6740     const call_tag: Air.Inst.Tag = switch (modifier) {
   6741         .auto,
   6742         .always_inline,
   6743         .compile_time,
   6744         .no_async,
   6745         => Air.Inst.Tag.call,
   6746 
   6747         .never_tail => Air.Inst.Tag.call_never_tail,
   6748         .never_inline => Air.Inst.Tag.call_never_inline,
   6749         .always_tail => Air.Inst.Tag.call_always_tail,
   6750 
   6751         .async_kw => return sema.failWithUseOfAsync(block, call_src),
   6752     };
   6753 
   6754     if (modifier == .never_inline and func_ty_info.cc == .Inline) {
   6755         return sema.fail(block, call_src, "'never_inline' call of inline function", .{});
   6756     }
   6757     if (modifier == .always_inline and func_ty_info.is_noinline) {
   6758         return sema.fail(block, call_src, "'always_inline' call of noinline function", .{});
   6759     }
   6760 
   6761     const gpa = sema.gpa;
   6762 
   6763     var is_generic_call = func_ty_info.is_generic;
   6764     var is_comptime_call = block.is_comptime or modifier == .compile_time;
   6765     var comptime_reason_buf: Block.ComptimeReason = undefined;
   6766     var comptime_reason: ?*const Block.ComptimeReason = null;
   6767     if (!is_comptime_call) {
   6768         if (sema.typeRequiresComptime(func_ty_info.return_type.toType())) |ct| {
   6769             is_comptime_call = ct;
   6770             if (ct) {
   6771                 // stage1 can't handle doing this directly
   6772                 comptime_reason_buf = .{ .comptime_ret_ty = .{
   6773                     .block = block,
   6774                     .func = func,
   6775                     .func_src = func_src,
   6776                     .return_ty = func_ty_info.return_type.toType(),
   6777                 } };
   6778                 comptime_reason = &comptime_reason_buf;
   6779             }
   6780         } else |err| switch (err) {
   6781             error.GenericPoison => is_generic_call = true,
   6782             else => |e| return e,
   6783         }
   6784     }
   6785     var is_inline_call = is_comptime_call or modifier == .always_inline or
   6786         func_ty_info.cc == .Inline;
   6787 
   6788     if (!is_inline_call and is_generic_call) {
   6789         if (sema.instantiateGenericCall(
   6790             block,
   6791             func,
   6792             func_src,
   6793             call_src,
   6794             func_ty_info,
   6795             ensure_result_used,
   6796             uncasted_args,
   6797             call_tag,
   6798             bound_arg_src,
   6799             call_dbg_node,
   6800         )) |some| {
   6801             return some;
   6802         } else |err| switch (err) {
   6803             error.GenericPoison => {
   6804                 is_inline_call = true;
   6805             },
   6806             error.ComptimeReturn => {
   6807                 is_inline_call = true;
   6808                 is_comptime_call = true;
   6809                 // stage1 can't handle doing this directly
   6810                 comptime_reason_buf = .{ .comptime_ret_ty = .{
   6811                     .block = block,
   6812                     .func = func,
   6813                     .func_src = func_src,
   6814                     .return_ty = func_ty_info.return_type.toType(),
   6815                 } };
   6816                 comptime_reason = &comptime_reason_buf;
   6817             },
   6818             else => |e| return e,
   6819         }
   6820     }
   6821 
   6822     if (is_comptime_call and modifier == .never_inline) {
   6823         return sema.fail(block, call_src, "unable to perform 'never_inline' call at compile-time", .{});
   6824     }
   6825 
   6826     const result: Air.Inst.Ref = if (is_inline_call) res: {
   6827         const func_val = sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime-known") catch |err| {
   6828             if (err == error.AnalysisFail and comptime_reason != null) try comptime_reason.?.explain(sema, sema.err);
   6829             return err;
   6830         };
   6831         const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
   6832             .extern_func => return sema.fail(block, call_src, "{s} call of extern function", .{
   6833                 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
   6834             }),
   6835             .func => |function| function.index,
   6836             .ptr => |ptr| switch (ptr.addr) {
   6837                 .decl => |decl| mod.declPtr(decl).val.getFunctionIndex(mod).unwrap().?,
   6838                 else => {
   6839                     assert(callee_ty.isPtrAtRuntime(mod));
   6840                     return sema.fail(block, call_src, "{s} call of function pointer", .{
   6841                         @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
   6842                     });
   6843                 },
   6844             },
   6845             else => unreachable,
   6846         };
   6847         if (func_ty_info.is_var_args) {
   6848             return sema.fail(block, call_src, "{s} call of variadic function", .{
   6849                 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
   6850             });
   6851         }
   6852 
   6853         // Analyze the ZIR. The same ZIR gets analyzed into a runtime function
   6854         // or an inlined call depending on what union tag the `label` field is
   6855         // set to in the `Block`.
   6856         // This block instruction will be used to capture the return value from the
   6857         // inlined function.
   6858         const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
   6859         try sema.air_instructions.append(gpa, .{
   6860             .tag = .block,
   6861             .data = undefined,
   6862         });
   6863         // This one is shared among sub-blocks within the same callee, but not
   6864         // shared among the entire inline/comptime call stack.
   6865         var inlining: Block.Inlining = .{
   6866             .func = null,
   6867             .comptime_result = undefined,
   6868             .merges = .{
   6869                 .src_locs = .{},
   6870                 .results = .{},
   6871                 .br_list = .{},
   6872                 .block_inst = block_inst,
   6873             },
   6874         };
   6875         // In order to save a bit of stack space, directly modify Sema rather
   6876         // than create a child one.
   6877         const parent_zir = sema.code;
   6878         const module_fn = mod.funcPtr(module_fn_index);
   6879         const fn_owner_decl = mod.declPtr(module_fn.owner_decl);
   6880         sema.code = fn_owner_decl.getFileScope(mod).zir;
   6881         defer sema.code = parent_zir;
   6882 
   6883         try mod.declareDeclDependencyType(sema.owner_decl_index, module_fn.owner_decl, .function_body);
   6884 
   6885         const parent_inst_map = sema.inst_map;
   6886         sema.inst_map = .{};
   6887         defer {
   6888             sema.src = call_src;
   6889             sema.inst_map.deinit(gpa);
   6890             sema.inst_map = parent_inst_map;
   6891         }
   6892 
   6893         const parent_func = sema.func;
   6894         const parent_func_index = sema.func_index;
   6895         sema.func = module_fn;
   6896         sema.func_index = module_fn_index.toOptional();
   6897         defer sema.func = parent_func;
   6898         defer sema.func_index = parent_func_index;
   6899 
   6900         const parent_err_ret_index = sema.error_return_trace_index_on_fn_entry;
   6901         sema.error_return_trace_index_on_fn_entry = block.error_return_trace_index;
   6902         defer sema.error_return_trace_index_on_fn_entry = parent_err_ret_index;
   6903 
   6904         var wip_captures = try WipCaptureScope.init(gpa, fn_owner_decl.src_scope);
   6905         defer wip_captures.deinit();
   6906 
   6907         var child_block: Block = .{
   6908             .parent = null,
   6909             .sema = sema,
   6910             .src_decl = module_fn.owner_decl,
   6911             .namespace = fn_owner_decl.src_namespace,
   6912             .wip_capture_scope = wip_captures.scope,
   6913             .instructions = .{},
   6914             .label = null,
   6915             .inlining = &inlining,
   6916             .is_typeof = block.is_typeof,
   6917             .is_comptime = is_comptime_call,
   6918             .comptime_reason = comptime_reason,
   6919             .error_return_trace_index = block.error_return_trace_index,
   6920         };
   6921 
   6922         const merges = &child_block.inlining.?.merges;
   6923 
   6924         defer child_block.instructions.deinit(gpa);
   6925         defer merges.deinit(gpa);
   6926 
   6927         try sema.emitBackwardBranch(block, call_src);
   6928 
   6929         // Whether this call should be memoized, set to false if the call can mutate comptime state.
   6930         var should_memoize = true;
   6931 
   6932         // If it's a comptime function call, we need to memoize it as long as no external
   6933         // comptime memory is mutated.
   6934         const memoized_arg_values = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len);
   6935 
   6936         var new_fn_info = mod.typeToFunc(fn_owner_decl.ty).?;
   6937         new_fn_info.param_types = try sema.arena.alloc(InternPool.Index, new_fn_info.param_types.len);
   6938         new_fn_info.comptime_bits = 0;
   6939 
   6940         // This will have return instructions analyzed as break instructions to
   6941         // the block_inst above. Here we are performing "comptime/inline semantic analysis"
   6942         // for a function body, which means we must map the parameter ZIR instructions to
   6943         // the AIR instructions of the callsite. The callee could be a generic function
   6944         // which means its parameter type expressions must be resolved in order and used
   6945         // to successively coerce the arguments.
   6946         const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst);
   6947         try sema.inst_map.ensureSpaceForInstructions(sema.gpa, fn_info.param_body);
   6948 
   6949         var has_comptime_args = false;
   6950         var arg_i: usize = 0;
   6951         for (fn_info.param_body) |inst| {
   6952             sema.analyzeInlineCallArg(
   6953                 block,
   6954                 &child_block,
   6955                 .unneeded,
   6956                 inst,
   6957                 &new_fn_info,
   6958                 &arg_i,
   6959                 uncasted_args,
   6960                 is_comptime_call,
   6961                 &should_memoize,
   6962                 memoized_arg_values,
   6963                 mod.typeToFunc(func_ty).?.param_types,
   6964                 func,
   6965                 &has_comptime_args,
   6966             ) catch |err| switch (err) {
   6967                 error.NeededSourceLocation => {
   6968                     _ = sema.inst_map.remove(inst);
   6969                     const decl = sema.mod.declPtr(block.src_decl);
   6970                     try sema.analyzeInlineCallArg(
   6971                         block,
   6972                         &child_block,
   6973                         mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src),
   6974                         inst,
   6975                         &new_fn_info,
   6976                         &arg_i,
   6977                         uncasted_args,
   6978                         is_comptime_call,
   6979                         &should_memoize,
   6980                         memoized_arg_values,
   6981                         mod.typeToFunc(func_ty).?.param_types,
   6982                         func,
   6983                         &has_comptime_args,
   6984                     );
   6985                     unreachable;
   6986                 },
   6987                 else => |e| return e,
   6988             };
   6989         }
   6990 
   6991         if (!has_comptime_args and module_fn.state == .sema_failure) return error.AnalysisFail;
   6992 
   6993         const recursive_msg = "inline call is recursive";
   6994         var head = if (!has_comptime_args) block else null;
   6995         while (head) |some| {
   6996             const parent_inlining = some.inlining orelse break;
   6997             if (parent_inlining.func == module_fn) {
   6998                 return sema.fail(block, call_src, recursive_msg, .{});
   6999             }
   7000             head = some.parent;
   7001         }
   7002         if (!has_comptime_args) inlining.func = module_fn;
   7003 
   7004         // In case it is a generic function with an expression for the return type that depends
   7005         // on parameters, we must now do the same for the return type as we just did with
   7006         // each of the parameters, resolving the return type and providing it to the child
   7007         // `Sema` so that it can be used for the `ret_ptr` instruction.
   7008         const ret_ty_inst = if (fn_info.ret_ty_body.len != 0)
   7009             try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst)
   7010         else
   7011             try sema.resolveInst(fn_info.ret_ty_ref);
   7012         const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
   7013         const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);
   7014         // Create a fresh inferred error set type for inline/comptime calls.
   7015         const fn_ret_ty = blk: {
   7016             if (module_fn.hasInferredErrorSet(mod)) {
   7017                 const ies_index = try mod.intern_pool.createInferredErrorSet(gpa, .{
   7018                     .func = module_fn_index,
   7019                 });
   7020                 const error_set_ty = try mod.intern(.{ .inferred_error_set_type = ies_index });
   7021                 break :blk try mod.errorUnionType(error_set_ty.toType(), bare_return_type);
   7022             }
   7023             break :blk bare_return_type;
   7024         };
   7025         new_fn_info.return_type = fn_ret_ty.toIntern();
   7026         const parent_fn_ret_ty = sema.fn_ret_ty;
   7027         sema.fn_ret_ty = fn_ret_ty;
   7028         defer sema.fn_ret_ty = parent_fn_ret_ty;
   7029 
   7030         // This `res2` is here instead of directly breaking from `res` due to a stage1
   7031         // bug generating invalid LLVM IR.
   7032         const res2: Air.Inst.Ref = res2: {
   7033             if (should_memoize and is_comptime_call) {
   7034                 if (mod.intern_pool.getIfExists(.{ .memoized_call = .{
   7035                     .func = module_fn_index,
   7036                     .arg_values = memoized_arg_values,
   7037                     .result = .none,
   7038                 } })) |memoized_call_index| {
   7039                     const memoized_call = mod.intern_pool.indexToKey(memoized_call_index).memoized_call;
   7040                     break :res2 try sema.addConstant(
   7041                         mod.intern_pool.typeOf(memoized_call.result).toType(),
   7042                         memoized_call.result.toValue(),
   7043                     );
   7044                 }
   7045             }
   7046 
   7047             const new_func_resolved_ty = try mod.funcType(new_fn_info);
   7048             if (!is_comptime_call and !block.is_typeof) {
   7049                 try sema.emitDbgInline(block, parent_func_index.unwrap().?, module_fn_index, new_func_resolved_ty, .dbg_inline_begin);
   7050 
   7051                 const zir_tags = sema.code.instructions.items(.tag);
   7052                 for (fn_info.param_body) |param| switch (zir_tags[param]) {
   7053                     .param, .param_comptime => {
   7054                         const inst_data = sema.code.instructions.items(.data)[param].pl_tok;
   7055                         const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);
   7056                         const param_name = sema.code.nullTerminatedString(extra.data.name);
   7057                         const inst = sema.inst_map.get(param).?;
   7058 
   7059                         try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name);
   7060                     },
   7061                     .param_anytype, .param_anytype_comptime => {
   7062                         const inst_data = sema.code.instructions.items(.data)[param].str_tok;
   7063                         const param_name = inst_data.get(sema.code);
   7064                         const inst = sema.inst_map.get(param).?;
   7065 
   7066                         try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name);
   7067                     },
   7068                     else => continue,
   7069                 };
   7070             }
   7071 
   7072             if (is_comptime_call and ensure_result_used) {
   7073                 try sema.ensureResultUsed(block, fn_ret_ty, call_src);
   7074             }
   7075 
   7076             const result = result: {
   7077                 sema.analyzeBody(&child_block, fn_info.body) catch |err| switch (err) {
   7078                     error.ComptimeReturn => break :result inlining.comptime_result,
   7079                     error.AnalysisFail => {
   7080                         const err_msg = sema.err orelse return err;
   7081                         if (mem.eql(u8, err_msg.msg, recursive_msg)) return err;
   7082                         try sema.errNote(block, call_src, err_msg, "called from here", .{});
   7083                         err_msg.clearTrace(sema.gpa);
   7084                         return err;
   7085                     },
   7086                     else => |e| return e,
   7087                 };
   7088                 break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges);
   7089             };
   7090 
   7091             if (!is_comptime_call and !block.is_typeof and sema.typeOf(result).zigTypeTag(mod) != .NoReturn) {
   7092                 try sema.emitDbgInline(
   7093                     block,
   7094                     module_fn_index,
   7095                     parent_func_index.unwrap().?,
   7096                     mod.declPtr(parent_func.?.owner_decl).ty,
   7097                     .dbg_inline_end,
   7098                 );
   7099             }
   7100 
   7101             if (should_memoize and is_comptime_call) {
   7102                 const result_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, result, "");
   7103 
   7104                 // TODO: check whether any external comptime memory was mutated by the
   7105                 // comptime function call. If so, then do not memoize the call here.
   7106                 _ = try mod.intern(.{ .memoized_call = .{
   7107                     .func = module_fn_index,
   7108                     .arg_values = memoized_arg_values,
   7109                     .result = try result_val.intern(fn_ret_ty, mod),
   7110                 } });
   7111             }
   7112 
   7113             break :res2 result;
   7114         };
   7115 
   7116         try wip_captures.finalize();
   7117 
   7118         break :res res2;
   7119     } else res: {
   7120         assert(!func_ty_info.is_generic);
   7121 
   7122         const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);
   7123         for (uncasted_args, 0..) |uncasted_arg, i| {
   7124             if (i < fn_params_len) {
   7125                 const opts: CoerceOpts = .{ .param_src = .{
   7126                     .func_inst = func,
   7127                     .param_i = @intCast(u32, i),
   7128                 } };
   7129                 const param_ty = mod.typeToFunc(func_ty).?.param_types[i].toType();
   7130                 args[i] = sema.analyzeCallArg(
   7131                     block,
   7132                     .unneeded,
   7133                     param_ty,
   7134                     uncasted_arg,
   7135                     opts,
   7136                 ) catch |err| switch (err) {
   7137                     error.NeededSourceLocation => {
   7138                         const decl = sema.mod.declPtr(block.src_decl);
   7139                         _ = try sema.analyzeCallArg(
   7140                             block,
   7141                             mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src),
   7142                             param_ty,
   7143                             uncasted_arg,
   7144                             opts,
   7145                         );
   7146                         unreachable;
   7147                     },
   7148                     else => |e| return e,
   7149                 };
   7150             } else {
   7151                 args[i] = sema.coerceVarArgParam(block, uncasted_arg, .unneeded) catch |err| switch (err) {
   7152                     error.NeededSourceLocation => {
   7153                         const decl = sema.mod.declPtr(block.src_decl);
   7154                         _ = try sema.coerceVarArgParam(
   7155                             block,
   7156                             uncasted_arg,
   7157                             mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src),
   7158                         );
   7159                         unreachable;
   7160                     },
   7161                     else => |e| return e,
   7162                 };
   7163             }
   7164         }
   7165 
   7166         if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
   7167 
   7168         try sema.queueFullTypeResolution(func_ty_info.return_type.toType());
   7169         if (sema.owner_func != null and func_ty_info.return_type.toType().isError(mod)) {
   7170             sema.owner_func.?.calls_or_awaits_errorable_fn = true;
   7171         }
   7172 
   7173         if (try sema.resolveMaybeUndefVal(func)) |func_val| {
   7174             if (mod.intern_pool.indexToFunc(func_val.toIntern()).unwrap()) |func_index| {
   7175                 try sema.mod.ensureFuncBodyAnalysisQueued(func_index);
   7176             }
   7177         }
   7178 
   7179         try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
   7180             args.len);
   7181         const func_inst = try block.addInst(.{
   7182             .tag = call_tag,
   7183             .data = .{ .pl_op = .{
   7184                 .operand = func,
   7185                 .payload = sema.addExtraAssumeCapacity(Air.Call{
   7186                     .args_len = @intCast(u32, args.len),
   7187                 }),
   7188             } },
   7189         });
   7190         sema.appendRefsAssumeCapacity(args);
   7191 
   7192         if (call_tag == .call_always_tail) {
   7193             if (ensure_result_used) {
   7194                 try sema.ensureResultUsed(block, sema.typeOf(func_inst), call_src);
   7195             }
   7196             return sema.handleTailCall(block, call_src, func_ty, func_inst);
   7197         } else if (block.wantSafety() and func_ty_info.return_type == .noreturn_type) {
   7198             // Function pointers and extern functions aren't guaranteed to
   7199             // actually be noreturn so we add a safety check for them.
   7200             check: {
   7201                 const func_val = (try sema.resolveMaybeUndefVal(func)) orelse break :check;
   7202                 switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
   7203                     .func, .extern_func, .ptr => {
   7204                         _ = try block.addNoOp(.unreach);
   7205                         return Air.Inst.Ref.unreachable_value;
   7206                     },
   7207                     else => break :check,
   7208                 }
   7209             }
   7210 
   7211             try sema.safetyPanic(block, .noreturn_returned);
   7212             return Air.Inst.Ref.unreachable_value;
   7213         } else if (func_ty_info.return_type == .noreturn_type) {
   7214             _ = try block.addNoOp(.unreach);
   7215             return Air.Inst.Ref.unreachable_value;
   7216         }
   7217         break :res func_inst;
   7218     };
   7219 
   7220     if (ensure_result_used) {
   7221         try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
   7222     }
   7223     return result;
   7224 }
   7225 
   7226 fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref {
   7227     const target = sema.mod.getTarget();
   7228     const backend = sema.mod.comp.getZigBackend();
   7229     if (!target_util.supportsTailCall(target, backend)) {
   7230         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", .{
   7231             @tagName(backend), @tagName(target.cpu.arch),
   7232         });
   7233     }
   7234     const func_decl = sema.mod.declPtr(sema.owner_func.?.owner_decl);
   7235     if (!func_ty.eql(func_decl.ty, sema.mod)) {
   7236         return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{
   7237             func_ty.fmt(sema.mod), func_decl.ty.fmt(sema.mod),
   7238         });
   7239     }
   7240     _ = try block.addUnOp(.ret, result);
   7241     return Air.Inst.Ref.unreachable_value;
   7242 }
   7243 
   7244 fn analyzeInlineCallArg(
   7245     sema: *Sema,
   7246     arg_block: *Block,
   7247     param_block: *Block,
   7248     arg_src: LazySrcLoc,
   7249     inst: Zir.Inst.Index,
   7250     new_fn_info: *InternPool.Key.FuncType,
   7251     arg_i: *usize,
   7252     uncasted_args: []const Air.Inst.Ref,
   7253     is_comptime_call: bool,
   7254     should_memoize: *bool,
   7255     memoized_arg_values: []InternPool.Index,
   7256     raw_param_types: []const InternPool.Index,
   7257     func_inst: Air.Inst.Ref,
   7258     has_comptime_args: *bool,
   7259 ) !void {
   7260     const mod = sema.mod;
   7261     const zir_tags = sema.code.instructions.items(.tag);
   7262     switch (zir_tags[inst]) {
   7263         .param_comptime, .param_anytype_comptime => has_comptime_args.* = true,
   7264         else => {},
   7265     }
   7266     switch (zir_tags[inst]) {
   7267         .param, .param_comptime => {
   7268             // Evaluate the parameter type expression now that previous ones have
   7269             // been mapped, and coerce the corresponding argument to it.
   7270             const pl_tok = sema.code.instructions.items(.data)[inst].pl_tok;
   7271             const param_src = pl_tok.src();
   7272             const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index);
   7273             const param_body = sema.code.extra[extra.end..][0..extra.data.body_len];
   7274             const param_ty = param_ty: {
   7275                 const raw_param_ty = raw_param_types[arg_i.*];
   7276                 if (raw_param_ty != .generic_poison_type) break :param_ty raw_param_ty;
   7277                 const param_ty_inst = try sema.resolveBody(param_block, param_body, inst);
   7278                 const param_ty = try sema.analyzeAsType(param_block, param_src, param_ty_inst);
   7279                 break :param_ty param_ty.toIntern();
   7280             };
   7281             new_fn_info.param_types[arg_i.*] = param_ty;
   7282             const uncasted_arg = uncasted_args[arg_i.*];
   7283             if (try sema.typeRequiresComptime(param_ty.toType())) {
   7284                 _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime-only type must be comptime-known") catch |err| {
   7285                     if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
   7286                     return err;
   7287                 };
   7288             } else if (!is_comptime_call and zir_tags[inst] == .param_comptime) {
   7289                 _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime");
   7290             }
   7291             const casted_arg = sema.coerceExtra(arg_block, param_ty.toType(), uncasted_arg, arg_src, .{ .param_src = .{
   7292                 .func_inst = func_inst,
   7293                 .param_i = @intCast(u32, arg_i.*),
   7294             } }) catch |err| switch (err) {
   7295                 error.NotCoercible => unreachable,
   7296                 else => |e| return e,
   7297             };
   7298 
   7299             if (is_comptime_call) {
   7300                 sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg);
   7301                 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {
   7302                     if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
   7303                     return err;
   7304                 };
   7305                 switch (arg_val.toIntern()) {
   7306                     .generic_poison, .generic_poison_type => {
   7307                         // This function is currently evaluated as part of an as-of-yet unresolvable
   7308                         // parameter or return type.
   7309                         return error.GenericPoison;
   7310                     },
   7311                     else => {},
   7312                 }
   7313                 // Needed so that lazy values do not trigger
   7314                 // assertion due to type not being resolved
   7315                 // when the hash function is called.
   7316                 const resolved_arg_val = try sema.resolveLazyValue(arg_val);
   7317                 should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod);
   7318                 memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(param_ty.toType(), mod);
   7319             } else {
   7320                 sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg);
   7321             }
   7322 
   7323             if (try sema.resolveMaybeUndefVal(casted_arg)) |_| {
   7324                 has_comptime_args.* = true;
   7325             }
   7326 
   7327             arg_i.* += 1;
   7328         },
   7329         .param_anytype, .param_anytype_comptime => {
   7330             // No coercion needed.
   7331             const uncasted_arg = uncasted_args[arg_i.*];
   7332             new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg).toIntern();
   7333 
   7334             if (is_comptime_call) {
   7335                 sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
   7336                 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {
   7337                     if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
   7338                     return err;
   7339                 };
   7340                 switch (arg_val.toIntern()) {
   7341                     .generic_poison, .generic_poison_type => {
   7342                         // This function is currently evaluated as part of an as-of-yet unresolvable
   7343                         // parameter or return type.
   7344                         return error.GenericPoison;
   7345                     },
   7346                     else => {},
   7347                 }
   7348                 // Needed so that lazy values do not trigger
   7349                 // assertion due to type not being resolved
   7350                 // when the hash function is called.
   7351                 const resolved_arg_val = try sema.resolveLazyValue(arg_val);
   7352                 should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod);
   7353                 memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(sema.typeOf(uncasted_arg), mod);
   7354             } else {
   7355                 if (zir_tags[inst] == .param_anytype_comptime) {
   7356                     _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime");
   7357                 }
   7358                 sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
   7359             }
   7360 
   7361             if (try sema.resolveMaybeUndefVal(uncasted_arg)) |_| {
   7362                 has_comptime_args.* = true;
   7363             }
   7364 
   7365             arg_i.* += 1;
   7366         },
   7367         else => {},
   7368     }
   7369 }
   7370 
   7371 fn analyzeCallArg(
   7372     sema: *Sema,
   7373     block: *Block,
   7374     arg_src: LazySrcLoc,
   7375     param_ty: Type,
   7376     uncasted_arg: Air.Inst.Ref,
   7377     opts: CoerceOpts,
   7378 ) !Air.Inst.Ref {
   7379     try sema.resolveTypeFully(param_ty);
   7380     return sema.coerceExtra(block, param_ty, uncasted_arg, arg_src, opts) catch |err| switch (err) {
   7381         error.NotCoercible => unreachable,
   7382         else => |e| return e,
   7383     };
   7384 }
   7385 
   7386 fn analyzeGenericCallArg(
   7387     sema: *Sema,
   7388     block: *Block,
   7389     arg_src: LazySrcLoc,
   7390     uncasted_arg: Air.Inst.Ref,
   7391     comptime_arg: TypedValue,
   7392     runtime_args: []Air.Inst.Ref,
   7393     new_fn_info: InternPool.Key.FuncType,
   7394     runtime_i: *u32,
   7395 ) !void {
   7396     const mod = sema.mod;
   7397     const is_runtime = comptime_arg.val.isGenericPoison() and
   7398         comptime_arg.ty.hasRuntimeBits(mod) and
   7399         !(try sema.typeRequiresComptime(comptime_arg.ty));
   7400     if (is_runtime) {
   7401         const param_ty = new_fn_info.param_types[runtime_i.*].toType();
   7402         const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
   7403         try sema.queueFullTypeResolution(param_ty);
   7404         runtime_args[runtime_i.*] = casted_arg;
   7405         runtime_i.* += 1;
   7406     } else if (try sema.typeHasOnePossibleValue(comptime_arg.ty)) |_| {
   7407         _ = try sema.coerce(block, comptime_arg.ty, uncasted_arg, arg_src);
   7408     }
   7409 }
   7410 
   7411 fn analyzeGenericCallArgVal(sema: *Sema, block: *Block, arg_src: LazySrcLoc, uncasted_arg: Air.Inst.Ref) !Value {
   7412     return sema.resolveLazyValue(try sema.resolveValue(block, arg_src, uncasted_arg, "parameter is comptime"));
   7413 }
   7414 
   7415 fn instantiateGenericCall(
   7416     sema: *Sema,
   7417     block: *Block,
   7418     func: Air.Inst.Ref,
   7419     func_src: LazySrcLoc,
   7420     call_src: LazySrcLoc,
   7421     func_ty_info: InternPool.Key.FuncType,
   7422     ensure_result_used: bool,
   7423     uncasted_args: []const Air.Inst.Ref,
   7424     call_tag: Air.Inst.Tag,
   7425     bound_arg_src: ?LazySrcLoc,
   7426     call_dbg_node: ?Zir.Inst.Index,
   7427 ) CompileError!Air.Inst.Ref {
   7428     const mod = sema.mod;
   7429     const gpa = sema.gpa;
   7430 
   7431     const func_val = try sema.resolveConstValue(block, func_src, func, "generic function being called must be comptime-known");
   7432     const module_fn = mod.funcPtr(switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
   7433         .func => |function| function.index,
   7434         .ptr => |ptr| mod.declPtr(ptr.addr.decl).val.getFunctionIndex(mod).unwrap().?,
   7435         else => unreachable,
   7436     });
   7437     // Check the Module's generic function map with an adapted context, so that we
   7438     // can match against `uncasted_args` rather than doing the work below to create a
   7439     // generic Scope only to junk it if it matches an existing instantiation.
   7440     const fn_owner_decl = mod.declPtr(module_fn.owner_decl);
   7441     const namespace_index = fn_owner_decl.src_namespace;
   7442     const namespace = mod.namespacePtr(namespace_index);
   7443     const fn_zir = namespace.file_scope.zir;
   7444     const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst);
   7445     const zir_tags = fn_zir.instructions.items(.tag);
   7446 
   7447     // This hash must match `Module.MonomorphedFuncsContext.hash`.
   7448     // For parameters explicitly marked comptime and simple parameter type expressions,
   7449     // we know whether a parameter is elided from a monomorphed function, and can
   7450     // use it in the hash here. However, for parameter type expressions that are not
   7451     // explicitly marked comptime and rely on previous parameter comptime values, we
   7452     // don't find out until after generating a monomorphed function whether the parameter
   7453     // type ended up being a "must-be-comptime-known" type.
   7454     var hasher = std.hash.Wyhash.init(0);
   7455     std.hash.autoHash(&hasher, module_fn.owner_decl);
   7456 
   7457     const generic_args = try sema.arena.alloc(GenericCallAdapter.Arg, func_ty_info.param_types.len);
   7458     {
   7459         var i: usize = 0;
   7460         for (fn_info.param_body) |inst| {
   7461             var is_comptime = false;
   7462             var is_anytype = false;
   7463             switch (zir_tags[inst]) {
   7464                 .param => {
   7465                     is_comptime = func_ty_info.paramIsComptime(@intCast(u5, i));
   7466                 },
   7467                 .param_comptime => {
   7468                     is_comptime = true;
   7469                 },
   7470                 .param_anytype => {
   7471                     is_anytype = true;
   7472                     is_comptime = func_ty_info.paramIsComptime(@intCast(u5, i));
   7473                 },
   7474                 .param_anytype_comptime => {
   7475                     is_anytype = true;
   7476                     is_comptime = true;
   7477                 },
   7478                 else => continue,
   7479             }
   7480 
   7481             const arg_ty = sema.typeOf(uncasted_args[i]);
   7482             if (is_comptime or is_anytype) {
   7483                 // Tuple default values are a part of the type and need to be
   7484                 // resolved to hash the type.
   7485                 try sema.resolveTupleLazyValues(block, call_src, arg_ty);
   7486             }
   7487 
   7488             if (is_comptime) {
   7489                 const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[i]) catch |err| switch (err) {
   7490                     error.NeededSourceLocation => {
   7491                         const decl = sema.mod.declPtr(block.src_decl);
   7492                         const arg_src = mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src);
   7493                         _ = try sema.analyzeGenericCallArgVal(block, arg_src, uncasted_args[i]);
   7494                         unreachable;
   7495                     },
   7496                     else => |e| return e,
   7497                 };
   7498                 arg_val.hashUncoerced(arg_ty, &hasher, mod);
   7499                 if (is_anytype) {
   7500                     std.hash.autoHash(&hasher, arg_ty.toIntern());
   7501                     generic_args[i] = .{
   7502                         .ty = arg_ty,
   7503                         .val = arg_val,
   7504                         .is_anytype = true,
   7505                     };
   7506                 } else {
   7507                     generic_args[i] = .{
   7508                         .ty = arg_ty,
   7509                         .val = arg_val,
   7510                         .is_anytype = false,
   7511                     };
   7512                 }
   7513             } else if (is_anytype) {
   7514                 std.hash.autoHash(&hasher, arg_ty.toIntern());
   7515                 generic_args[i] = .{
   7516                     .ty = arg_ty,
   7517                     .val = Value.generic_poison,
   7518                     .is_anytype = true,
   7519                 };
   7520             } else {
   7521                 generic_args[i] = .{
   7522                     .ty = arg_ty,
   7523                     .val = Value.generic_poison,
   7524                     .is_anytype = false,
   7525                 };
   7526             }
   7527 
   7528             i += 1;
   7529         }
   7530     }
   7531 
   7532     const precomputed_hash = hasher.final();
   7533 
   7534     const adapter: GenericCallAdapter = .{
   7535         .generic_fn = module_fn,
   7536         .precomputed_hash = precomputed_hash,
   7537         .func_ty_info = func_ty_info,
   7538         .args = generic_args,
   7539         .module = mod,
   7540     };
   7541     const gop = try mod.monomorphed_funcs.getOrPutContextAdapted(gpa, {}, adapter, .{ .mod = mod });
   7542     const callee_index = if (!gop.found_existing) callee: {
   7543         const new_module_func_index = try mod.createFunc(undefined);
   7544         const new_module_func = mod.funcPtr(new_module_func_index);
   7545 
   7546         // This ensures that we can operate on the hash map before the Module.Fn
   7547         // struct is fully initialized.
   7548         new_module_func.hash = precomputed_hash;
   7549         new_module_func.generic_owner_decl = module_fn.owner_decl.toOptional();
   7550         new_module_func.comptime_args = null;
   7551         gop.key_ptr.* = new_module_func_index;
   7552 
   7553         try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);
   7554 
   7555         // Create a Decl for the new function.
   7556         const src_decl_index = namespace.getDeclIndex(mod);
   7557         const src_decl = mod.declPtr(src_decl_index);
   7558         const new_decl_index = try mod.allocateNewDecl(namespace_index, fn_owner_decl.src_node, src_decl.src_scope);
   7559         const new_decl = mod.declPtr(new_decl_index);
   7560         // TODO better names for generic function instantiations
   7561         const decl_name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{
   7562             fn_owner_decl.name, @enumToInt(new_decl_index),
   7563         });
   7564         new_decl.name = decl_name;
   7565         new_decl.src_line = fn_owner_decl.src_line;
   7566         new_decl.is_pub = fn_owner_decl.is_pub;
   7567         new_decl.is_exported = fn_owner_decl.is_exported;
   7568         new_decl.has_align = fn_owner_decl.has_align;
   7569         new_decl.has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace;
   7570         new_decl.@"linksection" = fn_owner_decl.@"linksection";
   7571         new_decl.@"addrspace" = fn_owner_decl.@"addrspace";
   7572         new_decl.zir_decl_index = fn_owner_decl.zir_decl_index;
   7573         new_decl.alive = true; // This Decl is called at runtime.
   7574         new_decl.analysis = .in_progress;
   7575         new_decl.generation = mod.generation;
   7576 
   7577         namespace.anon_decls.putAssumeCapacityNoClobber(new_decl_index, {});
   7578 
   7579         // The generic function Decl is guaranteed to be the first dependency
   7580         // of each of its instantiations.
   7581         assert(new_decl.dependencies.keys().len == 0);
   7582         try mod.declareDeclDependencyType(new_decl_index, module_fn.owner_decl, .function_body);
   7583 
   7584         var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
   7585         const new_decl_arena_allocator = new_decl_arena.allocator();
   7586 
   7587         const new_func = sema.resolveGenericInstantiationType(
   7588             block,
   7589             new_decl_arena_allocator,
   7590             fn_zir,
   7591             new_decl,
   7592             new_decl_index,
   7593             uncasted_args,
   7594             module_fn,
   7595             new_module_func_index,
   7596             namespace_index,
   7597             func_ty_info,
   7598             call_src,
   7599             bound_arg_src,
   7600         ) catch |err| switch (err) {
   7601             error.GenericPoison, error.ComptimeReturn => {
   7602                 new_decl_arena.deinit();
   7603                 // Resolving the new function type below will possibly declare more decl dependencies
   7604                 // and so we remove them all here in case of error.
   7605                 for (new_decl.dependencies.keys()) |dep_index| {
   7606                     const dep = mod.declPtr(dep_index);
   7607                     dep.removeDependant(new_decl_index);
   7608                 }
   7609                 assert(namespace.anon_decls.orderedRemove(new_decl_index));
   7610                 mod.destroyDecl(new_decl_index);
   7611                 assert(mod.monomorphed_funcs.removeContext(new_module_func_index, .{ .mod = mod }));
   7612                 mod.destroyFunc(new_module_func_index);
   7613                 return err;
   7614             },
   7615             else => {
   7616                 assert(mod.monomorphed_funcs.removeContext(new_module_func_index, .{ .mod = mod }));
   7617                 {
   7618                     errdefer new_decl_arena.deinit();
   7619                     try new_decl.finalizeNewArena(&new_decl_arena);
   7620                 }
   7621                 // TODO look up the compile error that happened here and attach a note to it
   7622                 // pointing here, at the generic instantiation callsite.
   7623                 if (sema.owner_func) |owner_func| {
   7624                     owner_func.state = .dependency_failure;
   7625                 } else {
   7626                     sema.owner_decl.analysis = .dependency_failure;
   7627                 }
   7628                 return err;
   7629             },
   7630         };
   7631         errdefer new_decl_arena.deinit();
   7632 
   7633         try new_decl.finalizeNewArena(&new_decl_arena);
   7634         break :callee new_func;
   7635     } else gop.key_ptr.*;
   7636     const callee = mod.funcPtr(callee_index);
   7637 
   7638     callee.branch_quota = @max(callee.branch_quota, sema.branch_quota);
   7639 
   7640     const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl);
   7641 
   7642     // Make a runtime call to the new function, making sure to omit the comptime args.
   7643     const comptime_args = callee.comptime_args.?;
   7644     const func_ty = mod.declPtr(callee.owner_decl).ty;
   7645     const new_fn_info = mod.typeToFunc(func_ty).?;
   7646     const runtime_args_len = @intCast(u32, new_fn_info.param_types.len);
   7647     const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len);
   7648     {
   7649         var runtime_i: u32 = 0;
   7650         var total_i: u32 = 0;
   7651         for (fn_info.param_body) |inst| {
   7652             switch (zir_tags[inst]) {
   7653                 .param_comptime, .param_anytype_comptime, .param, .param_anytype => {},
   7654                 else => continue,
   7655             }
   7656             sema.analyzeGenericCallArg(
   7657                 block,
   7658                 .unneeded,
   7659                 uncasted_args[total_i],
   7660                 comptime_args[total_i],
   7661                 runtime_args,
   7662                 new_fn_info,
   7663                 &runtime_i,
   7664             ) catch |err| switch (err) {
   7665                 error.NeededSourceLocation => {
   7666                     const decl = sema.mod.declPtr(block.src_decl);
   7667                     _ = try sema.analyzeGenericCallArg(
   7668                         block,
   7669                         mod.argSrc(call_src.node_offset.x, decl, total_i, bound_arg_src),
   7670                         uncasted_args[total_i],
   7671                         comptime_args[total_i],
   7672                         runtime_args,
   7673                         new_fn_info,
   7674                         &runtime_i,
   7675                     );
   7676                     unreachable;
   7677                 },
   7678                 else => |e| return e,
   7679             };
   7680             total_i += 1;
   7681         }
   7682 
   7683         try sema.queueFullTypeResolution(new_fn_info.return_type.toType());
   7684     }
   7685 
   7686     if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
   7687 
   7688     if (sema.owner_func != null and new_fn_info.return_type.toType().isError(mod)) {
   7689         sema.owner_func.?.calls_or_awaits_errorable_fn = true;
   7690     }
   7691 
   7692     try sema.mod.ensureFuncBodyAnalysisQueued(callee_index);
   7693 
   7694     try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
   7695         runtime_args_len);
   7696     const result = try block.addInst(.{
   7697         .tag = call_tag,
   7698         .data = .{ .pl_op = .{
   7699             .operand = callee_inst,
   7700             .payload = sema.addExtraAssumeCapacity(Air.Call{
   7701                 .args_len = runtime_args_len,
   7702             }),
   7703         } },
   7704     });
   7705     sema.appendRefsAssumeCapacity(runtime_args);
   7706 
   7707     if (ensure_result_used) {
   7708         try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
   7709     }
   7710     if (call_tag == .call_always_tail) {
   7711         return sema.handleTailCall(block, call_src, func_ty, result);
   7712     }
   7713     if (new_fn_info.return_type == .noreturn_type) {
   7714         _ = try block.addNoOp(.unreach);
   7715         return Air.Inst.Ref.unreachable_value;
   7716     }
   7717     return result;
   7718 }
   7719 
   7720 fn resolveGenericInstantiationType(
   7721     sema: *Sema,
   7722     block: *Block,
   7723     new_decl_arena_allocator: Allocator,
   7724     fn_zir: Zir,
   7725     new_decl: *Decl,
   7726     new_decl_index: Decl.Index,
   7727     uncasted_args: []const Air.Inst.Ref,
   7728     module_fn: *Module.Fn,
   7729     new_module_func: Module.Fn.Index,
   7730     namespace: Namespace.Index,
   7731     func_ty_info: InternPool.Key.FuncType,
   7732     call_src: LazySrcLoc,
   7733     bound_arg_src: ?LazySrcLoc,
   7734 ) !Module.Fn.Index {
   7735     const mod = sema.mod;
   7736     const gpa = sema.gpa;
   7737 
   7738     const zir_tags = fn_zir.instructions.items(.tag);
   7739     const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst);
   7740 
   7741     // Re-run the block that creates the function, with the comptime parameters
   7742     // pre-populated inside `inst_map`. This causes `param_comptime` and
   7743     // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a
   7744     // new, monomorphized function, with the comptime parameters elided.
   7745     var child_sema: Sema = .{
   7746         .mod = mod,
   7747         .gpa = gpa,
   7748         .arena = sema.arena,
   7749         .perm_arena = new_decl_arena_allocator,
   7750         .code = fn_zir,
   7751         .owner_decl = new_decl,
   7752         .owner_decl_index = new_decl_index,
   7753         .func = null,
   7754         .func_index = .none,
   7755         .fn_ret_ty = Type.void,
   7756         .owner_func = null,
   7757         .owner_func_index = .none,
   7758         .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len),
   7759         .comptime_args_fn_inst = module_fn.zir_body_inst,
   7760         .preallocated_new_func = new_module_func.toOptional(),
   7761         .is_generic_instantiation = true,
   7762         .branch_quota = sema.branch_quota,
   7763         .branch_count = sema.branch_count,
   7764     };
   7765     defer child_sema.deinit();
   7766 
   7767     var wip_captures = try WipCaptureScope.init(gpa, new_decl.src_scope);
   7768     defer wip_captures.deinit();
   7769 
   7770     var child_block: Block = .{
   7771         .parent = null,
   7772         .sema = &child_sema,
   7773         .src_decl = new_decl_index,
   7774         .namespace = namespace,
   7775         .wip_capture_scope = wip_captures.scope,
   7776         .instructions = .{},
   7777         .inlining = null,
   7778         .is_comptime = true,
   7779     };
   7780     defer {
   7781         child_block.instructions.deinit(gpa);
   7782         child_block.params.deinit(gpa);
   7783     }
   7784 
   7785     try child_sema.inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);
   7786 
   7787     var arg_i: usize = 0;
   7788     for (fn_info.param_body) |inst| {
   7789         var is_comptime = false;
   7790         var is_anytype = false;
   7791         switch (zir_tags[inst]) {
   7792             .param => {
   7793                 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i));
   7794             },
   7795             .param_comptime => {
   7796                 is_comptime = true;
   7797             },
   7798             .param_anytype => {
   7799                 is_anytype = true;
   7800                 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i));
   7801             },
   7802             .param_anytype_comptime => {
   7803                 is_anytype = true;
   7804                 is_comptime = true;
   7805             },
   7806             else => continue,
   7807         }
   7808         const arg = uncasted_args[arg_i];
   7809         if (is_comptime) {
   7810             const arg_val = (try sema.resolveMaybeUndefVal(arg)).?;
   7811             const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val);
   7812             child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
   7813         } else if (is_anytype) {
   7814             const arg_ty = sema.typeOf(arg);
   7815             if (try sema.typeRequiresComptime(arg_ty)) {
   7816                 const arg_val = sema.resolveConstValue(block, .unneeded, arg, "") catch |err| switch (err) {
   7817                     error.NeededSourceLocation => {
   7818                         const decl = sema.mod.declPtr(block.src_decl);
   7819                         const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src);
   7820                         _ = try sema.resolveConstValue(block, arg_src, arg, "argument to parameter with comptime-only type must be comptime-known");
   7821                         unreachable;
   7822                     },
   7823                     else => |e| return e,
   7824                 };
   7825                 const child_arg = try child_sema.addConstant(arg_ty, arg_val);
   7826                 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
   7827             } else {
   7828                 // We insert into the map an instruction which is runtime-known
   7829                 // but has the type of the argument.
   7830                 const child_arg = try child_block.addInst(.{
   7831                     .tag = .arg,
   7832                     .data = .{ .arg = .{
   7833                         .ty = try child_sema.addType(arg_ty),
   7834                         .src_index = @intCast(u32, arg_i),
   7835                     } },
   7836                 });
   7837                 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
   7838             }
   7839         }
   7840         arg_i += 1;
   7841     }
   7842 
   7843     // Save the error trace as our first action in the function.
   7844     // If this is unnecessary after all, Liveness will clean it up for us.
   7845     const error_return_trace_index = try sema.analyzeSaveErrRetIndex(&child_block);
   7846     child_sema.error_return_trace_index_on_fn_entry = error_return_trace_index;
   7847     child_block.error_return_trace_index = error_return_trace_index;
   7848 
   7849     const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst);
   7850     const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst, undefined) catch unreachable;
   7851     const new_func = new_func_val.getFunctionIndex(mod).unwrap().?;
   7852     assert(new_func == new_module_func);
   7853 
   7854     arg_i = 0;
   7855     for (fn_info.param_body) |inst| {
   7856         var is_comptime = false;
   7857         switch (zir_tags[inst]) {
   7858             .param => {
   7859                 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i));
   7860             },
   7861             .param_comptime => {
   7862                 is_comptime = true;
   7863             },
   7864             .param_anytype => {
   7865                 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i));
   7866             },
   7867             .param_anytype_comptime => {
   7868                 is_comptime = true;
   7869             },
   7870             else => continue,
   7871         }
   7872 
   7873         // We populate the Type here regardless because it is needed by
   7874         // `GenericCallAdapter.eql` as well as function body analysis.
   7875         // Whether it is anytype is communicated by `isAnytypeParam`.
   7876         const arg = child_sema.inst_map.get(inst).?;
   7877         const arg_ty = child_sema.typeOf(arg);
   7878 
   7879         if (try sema.typeRequiresComptime(arg_ty)) {
   7880             is_comptime = true;
   7881         }
   7882 
   7883         if (is_comptime) {
   7884             const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(arg) catch unreachable).?;
   7885             child_sema.comptime_args[arg_i] = .{
   7886                 .ty = arg_ty,
   7887                 .val = (try arg_val.intern(arg_ty, mod)).toValue(),
   7888             };
   7889         } else {
   7890             child_sema.comptime_args[arg_i] = .{
   7891                 .ty = arg_ty,
   7892                 .val = Value.generic_poison,
   7893             };
   7894         }
   7895 
   7896         arg_i += 1;
   7897     }
   7898 
   7899     try wip_captures.finalize();
   7900 
   7901     // Populate the Decl ty/val with the function and its type.
   7902     new_decl.ty = child_sema.typeOf(new_func_inst);
   7903     // If the call evaluated to a return type that requires comptime, never mind
   7904     // our generic instantiation. Instead we need to perform a comptime call.
   7905     const new_fn_info = mod.typeToFunc(new_decl.ty).?;
   7906     if (try sema.typeRequiresComptime(new_fn_info.return_type.toType())) {
   7907         return error.ComptimeReturn;
   7908     }
   7909     // Similarly, if the call evaluated to a generic type we need to instead
   7910     // call it inline.
   7911     if (new_fn_info.is_generic or new_fn_info.cc == .Inline) {
   7912         return error.GenericPoison;
   7913     }
   7914 
   7915     new_decl.val = (try mod.intern(.{ .func = .{
   7916         .ty = new_decl.ty.toIntern(),
   7917         .index = new_func,
   7918     } })).toValue();
   7919     new_decl.@"align" = 0;
   7920     new_decl.has_tv = true;
   7921     new_decl.owns_tv = true;
   7922     new_decl.analysis = .complete;
   7923 
   7924     log.debug("generic function '{s}' instantiated with type {}", .{
   7925         new_decl.name, new_decl.ty.fmtDebug(),
   7926     });
   7927 
   7928     // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field
   7929     // will be populated, ensuring it will have `analyzeBody` called with the ZIR
   7930     // parameters mapped appropriately.
   7931     try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func });
   7932     return new_func;
   7933 }
   7934 
   7935 fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void {
   7936     const mod = sema.mod;
   7937     const tuple = switch (mod.intern_pool.indexToKey(ty.toIntern())) {
   7938         .anon_struct_type => |tuple| tuple,
   7939         else => return,
   7940     };
   7941     for (tuple.types, tuple.values) |field_ty, field_val| {
   7942         try sema.resolveTupleLazyValues(block, src, field_ty.toType());
   7943         if (field_val == .none) continue;
   7944         // TODO: mutate in intern pool
   7945         _ = try sema.resolveLazyValue(field_val.toValue());
   7946     }
   7947 }
   7948 
   7949 fn emitDbgInline(
   7950     sema: *Sema,
   7951     block: *Block,
   7952     old_func: Module.Fn.Index,
   7953     new_func: Module.Fn.Index,
   7954     new_func_ty: Type,
   7955     tag: Air.Inst.Tag,
   7956 ) CompileError!void {
   7957     const mod = sema.mod;
   7958     if (mod.comp.bin_file.options.strip) return;
   7959 
   7960     // Recursive inline call; no dbg_inline needed.
   7961     if (old_func == new_func) return;
   7962 
   7963     _ = try block.addInst(.{
   7964         .tag = tag,
   7965         .data = .{ .ty_fn = .{
   7966             .ty = try sema.addType(new_func_ty),
   7967             .func = new_func,
   7968         } },
   7969     });
   7970 }
   7971 
   7972 fn zirIntType(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   7973     const mod = sema.mod;
   7974     const int_type = sema.code.instructions.items(.data)[inst].int_type;
   7975     const ty = try mod.intType(int_type.signedness, int_type.bit_count);
   7976     return sema.addType(ty);
   7977 }
   7978 
   7979 fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   7980     const tracy = trace(@src());
   7981     defer tracy.end();
   7982 
   7983     const mod = sema.mod;
   7984     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   7985     const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
   7986     const child_type = try sema.resolveType(block, operand_src, inst_data.operand);
   7987     if (child_type.zigTypeTag(mod) == .Opaque) {
   7988         return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(sema.mod)});
   7989     } else if (child_type.zigTypeTag(mod) == .Null) {
   7990         return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(sema.mod)});
   7991     }
   7992     const opt_type = try Type.optional(sema.arena, child_type, mod);
   7993 
   7994     return sema.addType(opt_type);
   7995 }
   7996 
   7997 fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   7998     const mod = sema.mod;
   7999     const bin = sema.code.instructions.items(.data)[inst].bin;
   8000     const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs);
   8001     assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction
   8002     if (indexable_ty.zigTypeTag(mod) == .Struct) {
   8003         const elem_type = indexable_ty.structFieldType(@enumToInt(bin.rhs), mod);
   8004         return sema.addType(elem_type);
   8005     } else {
   8006         const elem_type = indexable_ty.elemType2(mod);
   8007         return sema.addType(elem_type);
   8008     }
   8009 }
   8010 
   8011 fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8012     const mod = sema.mod;
   8013     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8014     const elem_type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   8015     const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   8016     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   8017     const len = @intCast(u32, try sema.resolveInt(block, len_src, extra.lhs, Type.u32, "vector length must be comptime-known"));
   8018     const elem_type = try sema.resolveType(block, elem_type_src, extra.rhs);
   8019     try sema.checkVectorElemType(block, elem_type_src, elem_type);
   8020     const vector_type = try mod.vectorType(.{
   8021         .len = len,
   8022         .child = elem_type.toIntern(),
   8023     });
   8024     return sema.addType(vector_type);
   8025 }
   8026 
   8027 fn zirArrayType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8028     const tracy = trace(@src());
   8029     defer tracy.end();
   8030 
   8031     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8032     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   8033     const len_src: LazySrcLoc = .{ .node_offset_array_type_len = inst_data.src_node };
   8034     const elem_src: LazySrcLoc = .{ .node_offset_array_type_elem = inst_data.src_node };
   8035     const len = try sema.resolveInt(block, len_src, extra.lhs, Type.usize, "array length must be comptime-known");
   8036     const elem_type = try sema.resolveType(block, elem_src, extra.rhs);
   8037     try sema.validateArrayElemType(block, elem_type, elem_src);
   8038     const array_ty = try Type.array(sema.arena, len, null, elem_type, sema.mod);
   8039 
   8040     return sema.addType(array_ty);
   8041 }
   8042 
   8043 fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8044     const tracy = trace(@src());
   8045     defer tracy.end();
   8046 
   8047     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8048     const extra = sema.code.extraData(Zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data;
   8049     const len_src: LazySrcLoc = .{ .node_offset_array_type_len = inst_data.src_node };
   8050     const sentinel_src: LazySrcLoc = .{ .node_offset_array_type_sentinel = inst_data.src_node };
   8051     const elem_src: LazySrcLoc = .{ .node_offset_array_type_elem = inst_data.src_node };
   8052     const len = try sema.resolveInt(block, len_src, extra.len, Type.usize, "array length must be comptime-known");
   8053     const elem_type = try sema.resolveType(block, elem_src, extra.elem_type);
   8054     try sema.validateArrayElemType(block, elem_type, elem_src);
   8055     const uncasted_sentinel = try sema.resolveInst(extra.sentinel);
   8056     const sentinel = try sema.coerce(block, elem_type, uncasted_sentinel, sentinel_src);
   8057     const sentinel_val = try sema.resolveConstValue(block, sentinel_src, sentinel, "array sentinel value must be comptime-known");
   8058     const array_ty = try Type.array(sema.arena, len, sentinel_val, elem_type, sema.mod);
   8059 
   8060     return sema.addType(array_ty);
   8061 }
   8062 
   8063 fn validateArrayElemType(sema: *Sema, block: *Block, elem_type: Type, elem_src: LazySrcLoc) !void {
   8064     const mod = sema.mod;
   8065     if (elem_type.zigTypeTag(mod) == .Opaque) {
   8066         return sema.fail(block, elem_src, "array of opaque type '{}' not allowed", .{elem_type.fmt(sema.mod)});
   8067     } else if (elem_type.zigTypeTag(mod) == .NoReturn) {
   8068         return sema.fail(block, elem_src, "array of 'noreturn' not allowed", .{});
   8069     }
   8070 }
   8071 
   8072 fn zirAnyframeType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8073     const tracy = trace(@src());
   8074     defer tracy.end();
   8075 
   8076     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   8077     if (true) {
   8078         return sema.failWithUseOfAsync(block, inst_data.src());
   8079     }
   8080     const mod = sema.mod;
   8081     const operand_src: LazySrcLoc = .{ .node_offset_anyframe_type = inst_data.src_node };
   8082     const return_type = try sema.resolveType(block, operand_src, inst_data.operand);
   8083     const anyframe_type = try mod.anyframeType(return_type);
   8084 
   8085     return sema.addType(anyframe_type);
   8086 }
   8087 
   8088 fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8089     const tracy = trace(@src());
   8090     defer tracy.end();
   8091 
   8092     const mod = sema.mod;
   8093     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8094     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   8095     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   8096     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
   8097     const error_set = try sema.resolveType(block, lhs_src, extra.lhs);
   8098     const payload = try sema.resolveType(block, rhs_src, extra.rhs);
   8099 
   8100     if (error_set.zigTypeTag(mod) != .ErrorSet) {
   8101         return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{
   8102             error_set.fmt(sema.mod),
   8103         });
   8104     }
   8105     try sema.validateErrorUnionPayloadType(block, payload, rhs_src);
   8106     const err_union_ty = try mod.errorUnionType(error_set, payload);
   8107     return sema.addType(err_union_ty);
   8108 }
   8109 
   8110 fn validateErrorUnionPayloadType(sema: *Sema, block: *Block, payload_ty: Type, payload_src: LazySrcLoc) !void {
   8111     const mod = sema.mod;
   8112     if (payload_ty.zigTypeTag(mod) == .Opaque) {
   8113         return sema.fail(block, payload_src, "error union with payload of opaque type '{}' not allowed", .{
   8114             payload_ty.fmt(sema.mod),
   8115         });
   8116     } else if (payload_ty.zigTypeTag(mod) == .ErrorSet) {
   8117         return sema.fail(block, payload_src, "error union with payload of error set type '{}' not allowed", .{
   8118             payload_ty.fmt(sema.mod),
   8119         });
   8120     }
   8121 }
   8122 
   8123 fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8124     _ = block;
   8125     const mod = sema.mod;
   8126     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
   8127     const name = inst_data.get(sema.code);
   8128     // Create an error set type with only this error value, and return the value.
   8129     const kv = try sema.mod.getErrorValue(name);
   8130     const error_set_type = try mod.singleErrorSetType(kv.key);
   8131     return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{
   8132         .ty = error_set_type.toIntern(),
   8133         .name = try mod.intern_pool.getOrPutString(sema.gpa, kv.key),
   8134     } })).toValue());
   8135 }
   8136 
   8137 fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
   8138     const tracy = trace(@src());
   8139     defer tracy.end();
   8140 
   8141     const mod = sema.mod;
   8142     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
   8143     const src = LazySrcLoc.nodeOffset(extra.node);
   8144     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
   8145     const uncasted_operand = try sema.resolveInst(extra.operand);
   8146     const operand = try sema.coerce(block, Type.anyerror, uncasted_operand, operand_src);
   8147 
   8148     if (try sema.resolveMaybeUndefVal(operand)) |val| {
   8149         if (val.isUndef(mod)) {
   8150             return sema.addConstUndef(Type.err_int);
   8151         }
   8152         const err_name = mod.intern_pool.indexToKey(val.toIntern()).err.name;
   8153         return sema.addConstant(Type.err_int, try mod.intValue(
   8154             Type.err_int,
   8155             (try mod.getErrorValue(mod.intern_pool.stringToSlice(err_name))).value,
   8156         ));
   8157     }
   8158 
   8159     const op_ty = sema.typeOf(uncasted_operand);
   8160     try sema.resolveInferredErrorSetTy(block, src, op_ty);
   8161     if (!op_ty.isAnyError(mod)) {
   8162         const names = op_ty.errorSetNames(mod);
   8163         switch (names.len) {
   8164             0 => return sema.addConstant(Type.err_int, try mod.intValue(Type.err_int, 0)),
   8165             1 => {
   8166                 const name = mod.intern_pool.stringToSlice(names[0]);
   8167                 return sema.addIntUnsigned(Type.err_int, mod.global_error_set.get(name).?);
   8168             },
   8169             else => {},
   8170         }
   8171     }
   8172 
   8173     try sema.requireRuntimeBlock(block, src, operand_src);
   8174     return block.addBitCast(Type.err_int, operand);
   8175 }
   8176 
   8177 fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
   8178     const tracy = trace(@src());
   8179     defer tracy.end();
   8180 
   8181     const mod = sema.mod;
   8182     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
   8183     const src = LazySrcLoc.nodeOffset(extra.node);
   8184     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
   8185     const uncasted_operand = try sema.resolveInst(extra.operand);
   8186     const operand = try sema.coerce(block, Type.err_int, uncasted_operand, operand_src);
   8187 
   8188     if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| {
   8189         const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(mod));
   8190         if (int > sema.mod.global_error_set.count() or int == 0)
   8191             return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int});
   8192         return sema.addConstant(Type.anyerror, (try mod.intern(.{ .err = .{
   8193             .ty = .anyerror_type,
   8194             .name = mod.intern_pool.getString(sema.mod.error_name_list.items[int]).unwrap().?,
   8195         } })).toValue());
   8196     }
   8197     try sema.requireRuntimeBlock(block, src, operand_src);
   8198     if (block.wantSafety()) {
   8199         const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand);
   8200         const zero_val = try sema.addConstant(Type.err_int, try mod.intValue(Type.err_int, 0));
   8201         const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val);
   8202         const ok = try block.addBinOp(.bit_and, is_lt_len, is_non_zero);
   8203         try sema.addSafetyCheck(block, ok, .invalid_error_code);
   8204     }
   8205     return block.addInst(.{
   8206         .tag = .bitcast,
   8207         .data = .{ .ty_op = .{
   8208             .ty = Air.Inst.Ref.anyerror_type,
   8209             .operand = operand,
   8210         } },
   8211     });
   8212 }
   8213 
   8214 fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8215     const tracy = trace(@src());
   8216     defer tracy.end();
   8217 
   8218     const mod = sema.mod;
   8219     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8220     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   8221     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
   8222     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   8223     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
   8224     const lhs = try sema.resolveInst(extra.lhs);
   8225     const rhs = try sema.resolveInst(extra.rhs);
   8226     if (sema.typeOf(lhs).zigTypeTag(mod) == .Bool and sema.typeOf(rhs).zigTypeTag(mod) == .Bool) {
   8227         const msg = msg: {
   8228             const msg = try sema.errMsg(block, lhs_src, "expected error set type, found 'bool'", .{});
   8229             errdefer msg.destroy(sema.gpa);
   8230             try sema.errNote(block, src, msg, "'||' merges error sets; 'or' performs boolean OR", .{});
   8231             break :msg msg;
   8232         };
   8233         return sema.failWithOwnedErrorMsg(msg);
   8234     }
   8235     const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs);
   8236     const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs);
   8237     if (lhs_ty.zigTypeTag(mod) != .ErrorSet)
   8238         return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{lhs_ty.fmt(sema.mod)});
   8239     if (rhs_ty.zigTypeTag(mod) != .ErrorSet)
   8240         return sema.fail(block, rhs_src, "expected error set type, found '{}'", .{rhs_ty.fmt(sema.mod)});
   8241 
   8242     // Anything merged with anyerror is anyerror.
   8243     if (lhs_ty.toIntern() == .anyerror_type or rhs_ty.toIntern() == .anyerror_type) {
   8244         return Air.Inst.Ref.anyerror_type;
   8245     }
   8246 
   8247     if (mod.typeToInferredErrorSetIndex(lhs_ty).unwrap()) |ies_index| {
   8248         try sema.resolveInferredErrorSet(block, src, ies_index);
   8249         // isAnyError might have changed from a false negative to a true positive after resolution.
   8250         if (lhs_ty.isAnyError(mod)) {
   8251             return Air.Inst.Ref.anyerror_type;
   8252         }
   8253     }
   8254     if (mod.typeToInferredErrorSetIndex(rhs_ty).unwrap()) |ies_index| {
   8255         try sema.resolveInferredErrorSet(block, src, ies_index);
   8256         // isAnyError might have changed from a false negative to a true positive after resolution.
   8257         if (rhs_ty.isAnyError(mod)) {
   8258             return Air.Inst.Ref.anyerror_type;
   8259         }
   8260     }
   8261 
   8262     const err_set_ty = try sema.errorSetMerge(lhs_ty, rhs_ty);
   8263     return sema.addType(err_set_ty);
   8264 }
   8265 
   8266 fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8267     _ = block;
   8268     const tracy = trace(@src());
   8269     defer tracy.end();
   8270 
   8271     const mod = sema.mod;
   8272     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
   8273     const name = inst_data.get(sema.code);
   8274     return sema.addConstant(.{ .ip_index = .enum_literal_type }, (try mod.intern(.{
   8275         .enum_literal = try mod.intern_pool.getOrPutString(sema.gpa, name),
   8276     })).toValue());
   8277 }
   8278 
   8279 fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8280     const mod = sema.mod;
   8281     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   8282     const src = inst_data.src();
   8283     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   8284     const operand = try sema.resolveInst(inst_data.operand);
   8285     const operand_ty = sema.typeOf(operand);
   8286 
   8287     const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(mod)) {
   8288         .Enum => operand,
   8289         .Union => blk: {
   8290             const union_ty = try sema.resolveTypeFields(operand_ty);
   8291             const tag_ty = union_ty.unionTagType(mod) orelse {
   8292                 return sema.fail(
   8293                     block,
   8294                     operand_src,
   8295                     "untagged union '{}' cannot be converted to integer",
   8296                     .{src},
   8297                 );
   8298             };
   8299             break :blk try sema.unionToTag(block, tag_ty, operand, operand_src);
   8300         },
   8301         else => {
   8302             return sema.fail(block, operand_src, "expected enum or tagged union, found '{}'", .{
   8303                 operand_ty.fmt(sema.mod),
   8304             });
   8305         },
   8306     };
   8307     const enum_tag_ty = sema.typeOf(enum_tag);
   8308 
   8309     const int_tag_ty = enum_tag_ty.intTagType(mod);
   8310 
   8311     if (try sema.typeHasOnePossibleValue(enum_tag_ty)) |opv| {
   8312         return sema.addConstant(int_tag_ty, try mod.getCoerced(opv, int_tag_ty));
   8313     }
   8314 
   8315     if (try sema.resolveMaybeUndefVal(enum_tag)) |enum_tag_val| {
   8316         const val = try enum_tag_val.enumToInt(enum_tag_ty, mod);
   8317         return sema.addConstant(int_tag_ty, try val.copy(sema.arena));
   8318     }
   8319 
   8320     try sema.requireRuntimeBlock(block, src, operand_src);
   8321     return block.addBitCast(int_tag_ty, enum_tag);
   8322 }
   8323 
   8324 fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8325     const mod = sema.mod;
   8326     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8327     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   8328     const src = inst_data.src();
   8329     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   8330     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   8331     const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
   8332     const operand = try sema.resolveInst(extra.rhs);
   8333 
   8334     if (dest_ty.zigTypeTag(mod) != .Enum) {
   8335         return sema.fail(block, dest_ty_src, "expected enum, found '{}'", .{dest_ty.fmt(sema.mod)});
   8336     }
   8337     _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand));
   8338 
   8339     if (try sema.resolveMaybeUndefVal(operand)) |int_val| {
   8340         if (dest_ty.isNonexhaustiveEnum(mod)) {
   8341             const int_tag_ty = dest_ty.intTagType(mod);
   8342             if (try sema.intFitsInType(int_val, int_tag_ty, null)) {
   8343                 return sema.addConstant(dest_ty, try mod.getCoerced(int_val, dest_ty));
   8344             }
   8345             const msg = msg: {
   8346                 const msg = try sema.errMsg(
   8347                     block,
   8348                     src,
   8349                     "int value '{}' out of range of non-exhaustive enum '{}'",
   8350                     .{ int_val.fmtValue(sema.typeOf(operand), sema.mod), dest_ty.fmt(sema.mod) },
   8351                 );
   8352                 errdefer msg.destroy(sema.gpa);
   8353                 try sema.addDeclaredHereNote(msg, dest_ty);
   8354                 break :msg msg;
   8355             };
   8356             return sema.failWithOwnedErrorMsg(msg);
   8357         }
   8358         if (int_val.isUndef(mod)) {
   8359             return sema.failWithUseOfUndef(block, operand_src);
   8360         }
   8361         if (!(try sema.enumHasInt(dest_ty, int_val))) {
   8362             const msg = msg: {
   8363                 const msg = try sema.errMsg(
   8364                     block,
   8365                     src,
   8366                     "enum '{}' has no tag with value '{}'",
   8367                     .{ dest_ty.fmt(sema.mod), int_val.fmtValue(sema.typeOf(operand), sema.mod) },
   8368                 );
   8369                 errdefer msg.destroy(sema.gpa);
   8370                 try sema.addDeclaredHereNote(msg, dest_ty);
   8371                 break :msg msg;
   8372             };
   8373             return sema.failWithOwnedErrorMsg(msg);
   8374         }
   8375         return sema.addConstant(dest_ty, try mod.getCoerced(int_val, dest_ty));
   8376     }
   8377 
   8378     if (try sema.typeHasOnePossibleValue(dest_ty)) |opv| {
   8379         const result = try sema.addConstant(dest_ty, opv);
   8380         // The operand is runtime-known but the result is comptime-known. In
   8381         // this case we still need a safety check.
   8382         // TODO add a safety check here. we can't use is_named_enum_value -
   8383         // it needs to convert the enum back to int and make sure it equals the operand int.
   8384         return result;
   8385     }
   8386 
   8387     try sema.requireRuntimeBlock(block, src, operand_src);
   8388     const result = try block.addTyOp(.intcast, dest_ty, operand);
   8389     if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum(mod) and
   8390         sema.mod.backendSupportsFeature(.is_named_enum_value))
   8391     {
   8392         const ok = try block.addUnOp(.is_named_enum_value, result);
   8393         try sema.addSafetyCheck(block, ok, .invalid_enum_value);
   8394     }
   8395     return result;
   8396 }
   8397 
   8398 /// Pointer in, pointer out.
   8399 fn zirOptionalPayloadPtr(
   8400     sema: *Sema,
   8401     block: *Block,
   8402     inst: Zir.Inst.Index,
   8403     safety_check: bool,
   8404 ) CompileError!Air.Inst.Ref {
   8405     const tracy = trace(@src());
   8406     defer tracy.end();
   8407 
   8408     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   8409     const optional_ptr = try sema.resolveInst(inst_data.operand);
   8410     const src = inst_data.src();
   8411 
   8412     return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false);
   8413 }
   8414 
   8415 fn analyzeOptionalPayloadPtr(
   8416     sema: *Sema,
   8417     block: *Block,
   8418     src: LazySrcLoc,
   8419     optional_ptr: Air.Inst.Ref,
   8420     safety_check: bool,
   8421     initializing: bool,
   8422 ) CompileError!Air.Inst.Ref {
   8423     const mod = sema.mod;
   8424     const optional_ptr_ty = sema.typeOf(optional_ptr);
   8425     assert(optional_ptr_ty.zigTypeTag(mod) == .Pointer);
   8426 
   8427     const opt_type = optional_ptr_ty.childType(mod);
   8428     if (opt_type.zigTypeTag(mod) != .Optional) {
   8429         return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(sema.mod)});
   8430     }
   8431 
   8432     const child_type = opt_type.optionalChild(mod);
   8433     const child_pointer = try Type.ptr(sema.arena, sema.mod, .{
   8434         .pointee_type = child_type,
   8435         .mutable = !optional_ptr_ty.isConstPtr(mod),
   8436         .@"addrspace" = optional_ptr_ty.ptrAddressSpace(mod),
   8437     });
   8438 
   8439     if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| {
   8440         if (initializing) {
   8441             if (!ptr_val.isComptimeMutablePtr(mod)) {
   8442                 // If the pointer resulting from this function was stored at comptime,
   8443                 // the optional non-null bit would be set that way. But in this case,
   8444                 // we need to emit a runtime instruction to do it.
   8445                 _ = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);
   8446             }
   8447             return sema.addConstant(child_pointer, (try mod.intern(.{ .ptr = .{
   8448                 .ty = child_pointer.toIntern(),
   8449                 .addr = .{ .opt_payload = ptr_val.toIntern() },
   8450             } })).toValue());
   8451         }
   8452         if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| {
   8453             if (val.isNull(mod)) {
   8454                 return sema.fail(block, src, "unable to unwrap null", .{});
   8455             }
   8456             // The same Value represents the pointer to the optional and the payload.
   8457             return sema.addConstant(child_pointer, (try mod.intern(.{ .ptr = .{
   8458                 .ty = child_pointer.toIntern(),
   8459                 .addr = .{ .opt_payload = ptr_val.toIntern() },
   8460             } })).toValue());
   8461         }
   8462     }
   8463 
   8464     try sema.requireRuntimeBlock(block, src, null);
   8465     if (safety_check and block.wantSafety()) {
   8466         const is_non_null = try block.addUnOp(.is_non_null_ptr, optional_ptr);
   8467         try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
   8468     }
   8469     const air_tag: Air.Inst.Tag = if (initializing)
   8470         .optional_payload_ptr_set
   8471     else
   8472         .optional_payload_ptr;
   8473     return block.addTyOp(air_tag, child_pointer, optional_ptr);
   8474 }
   8475 
   8476 /// Value in, value out.
   8477 fn zirOptionalPayload(
   8478     sema: *Sema,
   8479     block: *Block,
   8480     inst: Zir.Inst.Index,
   8481     safety_check: bool,
   8482 ) CompileError!Air.Inst.Ref {
   8483     const tracy = trace(@src());
   8484     defer tracy.end();
   8485 
   8486     const mod = sema.mod;
   8487     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   8488     const src = inst_data.src();
   8489     const operand = try sema.resolveInst(inst_data.operand);
   8490     const operand_ty = sema.typeOf(operand);
   8491     const result_ty = switch (operand_ty.zigTypeTag(mod)) {
   8492         .Optional => operand_ty.optionalChild(mod),
   8493         .Pointer => t: {
   8494             if (operand_ty.ptrSize(mod) != .C) {
   8495                 return sema.failWithExpectedOptionalType(block, src, operand_ty);
   8496             }
   8497             // TODO https://github.com/ziglang/zig/issues/6597
   8498             if (true) break :t operand_ty;
   8499             const ptr_info = operand_ty.ptrInfo(mod);
   8500             break :t try Type.ptr(sema.arena, sema.mod, .{
   8501                 .pointee_type = ptr_info.pointee_type,
   8502                 .@"align" = ptr_info.@"align",
   8503                 .@"addrspace" = ptr_info.@"addrspace",
   8504                 .mutable = ptr_info.mutable,
   8505                 .@"allowzero" = ptr_info.@"allowzero",
   8506                 .@"volatile" = ptr_info.@"volatile",
   8507                 .size = .One,
   8508             });
   8509         },
   8510         else => return sema.failWithExpectedOptionalType(block, src, operand_ty),
   8511     };
   8512 
   8513     if (try sema.resolveDefinedValue(block, src, operand)) |val| {
   8514         return if (val.optionalValue(mod)) |payload|
   8515             sema.addConstant(result_ty, payload)
   8516         else
   8517             sema.fail(block, src, "unable to unwrap null", .{});
   8518     }
   8519 
   8520     try sema.requireRuntimeBlock(block, src, null);
   8521     if (safety_check and block.wantSafety()) {
   8522         const is_non_null = try block.addUnOp(.is_non_null, operand);
   8523         try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
   8524     }
   8525     return block.addTyOp(.optional_payload, result_ty, operand);
   8526 }
   8527 
   8528 /// Value in, value out
   8529 fn zirErrUnionPayload(
   8530     sema: *Sema,
   8531     block: *Block,
   8532     inst: Zir.Inst.Index,
   8533 ) CompileError!Air.Inst.Ref {
   8534     const tracy = trace(@src());
   8535     defer tracy.end();
   8536 
   8537     const mod = sema.mod;
   8538     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   8539     const src = inst_data.src();
   8540     const operand = try sema.resolveInst(inst_data.operand);
   8541     const operand_src = src;
   8542     const err_union_ty = sema.typeOf(operand);
   8543     if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) {
   8544         return sema.fail(block, operand_src, "expected error union type, found '{}'", .{
   8545             err_union_ty.fmt(sema.mod),
   8546         });
   8547     }
   8548     return sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false);
   8549 }
   8550 
   8551 fn analyzeErrUnionPayload(
   8552     sema: *Sema,
   8553     block: *Block,
   8554     src: LazySrcLoc,
   8555     err_union_ty: Type,
   8556     operand: Air.Inst.Ref,
   8557     operand_src: LazySrcLoc,
   8558     safety_check: bool,
   8559 ) CompileError!Air.Inst.Ref {
   8560     const mod = sema.mod;
   8561     const payload_ty = err_union_ty.errorUnionPayload(mod);
   8562     if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {
   8563         if (val.getError(mod)) |name| {
   8564             return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
   8565         }
   8566         return sema.addConstant(
   8567             payload_ty,
   8568             mod.intern_pool.indexToKey(val.toIntern()).error_union.val.payload.toValue(),
   8569         );
   8570     }
   8571 
   8572     try sema.requireRuntimeBlock(block, src, null);
   8573 
   8574     // If the error set has no fields then no safety check is needed.
   8575     if (safety_check and block.wantSafety() and
   8576         !err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod))
   8577     {
   8578         try sema.panicUnwrapError(block, operand, .unwrap_errunion_err, .is_non_err);
   8579     }
   8580 
   8581     return block.addTyOp(.unwrap_errunion_payload, payload_ty, operand);
   8582 }
   8583 
   8584 /// Pointer in, pointer out.
   8585 fn zirErrUnionPayloadPtr(
   8586     sema: *Sema,
   8587     block: *Block,
   8588     inst: Zir.Inst.Index,
   8589 ) CompileError!Air.Inst.Ref {
   8590     const tracy = trace(@src());
   8591     defer tracy.end();
   8592 
   8593     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   8594     const operand = try sema.resolveInst(inst_data.operand);
   8595     const src = inst_data.src();
   8596 
   8597     return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
   8598 }
   8599 
   8600 fn analyzeErrUnionPayloadPtr(
   8601     sema: *Sema,
   8602     block: *Block,
   8603     src: LazySrcLoc,
   8604     operand: Air.Inst.Ref,
   8605     safety_check: bool,
   8606     initializing: bool,
   8607 ) CompileError!Air.Inst.Ref {
   8608     const mod = sema.mod;
   8609     const operand_ty = sema.typeOf(operand);
   8610     assert(operand_ty.zigTypeTag(mod) == .Pointer);
   8611 
   8612     if (operand_ty.childType(mod).zigTypeTag(mod) != .ErrorUnion) {
   8613         return sema.fail(block, src, "expected error union type, found '{}'", .{
   8614             operand_ty.childType(mod).fmt(sema.mod),
   8615         });
   8616     }
   8617 
   8618     const err_union_ty = operand_ty.childType(mod);
   8619     const payload_ty = err_union_ty.errorUnionPayload(mod);
   8620     const operand_pointer_ty = try Type.ptr(sema.arena, sema.mod, .{
   8621         .pointee_type = payload_ty,
   8622         .mutable = !operand_ty.isConstPtr(mod),
   8623         .@"addrspace" = operand_ty.ptrAddressSpace(mod),
   8624     });
   8625 
   8626     if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| {
   8627         if (initializing) {
   8628             if (!ptr_val.isComptimeMutablePtr(mod)) {
   8629                 // If the pointer resulting from this function was stored at comptime,
   8630                 // the error union error code would be set that way. But in this case,
   8631                 // we need to emit a runtime instruction to do it.
   8632                 try sema.requireRuntimeBlock(block, src, null);
   8633                 _ = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand);
   8634             }
   8635             return sema.addConstant(operand_pointer_ty, (try mod.intern(.{ .ptr = .{
   8636                 .ty = operand_pointer_ty.toIntern(),
   8637                 .addr = .{ .eu_payload = ptr_val.toIntern() },
   8638             } })).toValue());
   8639         }
   8640         if (try sema.pointerDeref(block, src, ptr_val, operand_ty)) |val| {
   8641             if (val.getError(mod)) |name| {
   8642                 return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
   8643             }
   8644             return sema.addConstant(operand_pointer_ty, (try mod.intern(.{ .ptr = .{
   8645                 .ty = operand_pointer_ty.toIntern(),
   8646                 .addr = .{ .eu_payload = ptr_val.toIntern() },
   8647             } })).toValue());
   8648         }
   8649     }
   8650 
   8651     try sema.requireRuntimeBlock(block, src, null);
   8652 
   8653     // If the error set has no fields then no safety check is needed.
   8654     if (safety_check and block.wantSafety() and
   8655         !err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod))
   8656     {
   8657         try sema.panicUnwrapError(block, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);
   8658     }
   8659 
   8660     const air_tag: Air.Inst.Tag = if (initializing)
   8661         .errunion_payload_ptr_set
   8662     else
   8663         .unwrap_errunion_payload_ptr;
   8664     return block.addTyOp(air_tag, operand_pointer_ty, operand);
   8665 }
   8666 
   8667 /// Value in, value out
   8668 fn zirErrUnionCode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8669     const tracy = trace(@src());
   8670     defer tracy.end();
   8671 
   8672     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   8673     const src = inst_data.src();
   8674     const operand = try sema.resolveInst(inst_data.operand);
   8675     return sema.analyzeErrUnionCode(block, src, operand);
   8676 }
   8677 
   8678 fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref) CompileError!Air.Inst.Ref {
   8679     const mod = sema.mod;
   8680     const operand_ty = sema.typeOf(operand);
   8681     if (operand_ty.zigTypeTag(mod) != .ErrorUnion) {
   8682         return sema.fail(block, src, "expected error union type, found '{}'", .{
   8683             operand_ty.fmt(sema.mod),
   8684         });
   8685     }
   8686 
   8687     const result_ty = operand_ty.errorUnionSet(mod);
   8688 
   8689     if (try sema.resolveDefinedValue(block, src, operand)) |val| {
   8690         return sema.addConstant(result_ty, (try mod.intern(.{ .err = .{
   8691             .ty = result_ty.toIntern(),
   8692             .name = mod.intern_pool.indexToKey(val.toIntern()).error_union.val.err_name,
   8693         } })).toValue());
   8694     }
   8695 
   8696     try sema.requireRuntimeBlock(block, src, null);
   8697     return block.addTyOp(.unwrap_errunion_err, result_ty, operand);
   8698 }
   8699 
   8700 /// Pointer in, value out
   8701 fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   8702     const tracy = trace(@src());
   8703     defer tracy.end();
   8704 
   8705     const mod = sema.mod;
   8706     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   8707     const src = inst_data.src();
   8708     const operand = try sema.resolveInst(inst_data.operand);
   8709     const operand_ty = sema.typeOf(operand);
   8710     assert(operand_ty.zigTypeTag(mod) == .Pointer);
   8711 
   8712     if (operand_ty.childType(mod).zigTypeTag(mod) != .ErrorUnion) {
   8713         return sema.fail(block, src, "expected error union type, found '{}'", .{
   8714             operand_ty.childType(mod).fmt(sema.mod),
   8715         });
   8716     }
   8717 
   8718     const result_ty = operand_ty.childType(mod).errorUnionSet(mod);
   8719 
   8720     if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {
   8721         if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| {
   8722             assert(val.getError(mod) != null);
   8723             return sema.addConstant(result_ty, val);
   8724         }
   8725     }
   8726 
   8727     try sema.requireRuntimeBlock(block, src, null);
   8728     return block.addTyOp(.unwrap_errunion_err_ptr, result_ty, operand);
   8729 }
   8730 
   8731 fn zirFunc(
   8732     sema: *Sema,
   8733     block: *Block,
   8734     inst: Zir.Inst.Index,
   8735     inferred_error_set: bool,
   8736 ) CompileError!Air.Inst.Ref {
   8737     const tracy = trace(@src());
   8738     defer tracy.end();
   8739 
   8740     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   8741     const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
   8742     const target = sema.mod.getTarget();
   8743     const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = inst_data.src_node };
   8744 
   8745     var extra_index = extra.end;
   8746 
   8747     const ret_ty: Type = switch (extra.data.ret_body_len) {
   8748         0 => Type.void,
   8749         1 => blk: {
   8750             const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
   8751             extra_index += 1;
   8752             if (sema.resolveType(block, ret_ty_src, ret_ty_ref)) |ret_ty| {
   8753                 break :blk ret_ty;
   8754             } else |err| switch (err) {
   8755                 error.GenericPoison => {
   8756                     break :blk Type.generic_poison;
   8757                 },
   8758                 else => |e| return e,
   8759             }
   8760         },
   8761         else => blk: {
   8762             const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
   8763             extra_index += ret_ty_body.len;
   8764 
   8765             const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type, "return type must be comptime-known");
   8766             break :blk ret_ty_val.toType();
   8767         },
   8768     };
   8769 
   8770     var src_locs: Zir.Inst.Func.SrcLocs = undefined;
   8771     const has_body = extra.data.body_len != 0;
   8772     if (has_body) {
   8773         extra_index += extra.data.body_len;
   8774         src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
   8775     }
   8776 
   8777     // If this instruction has a body it means it's the type of the `owner_decl`
   8778     // otherwise it's a function type without a `callconv` attribute and should
   8779     // never be `.C`.
   8780     // NOTE: revisit when doing #1717
   8781     const cc: std.builtin.CallingConvention = if (sema.owner_decl.is_exported and has_body)
   8782         .C
   8783     else
   8784         .Unspecified;
   8785 
   8786     return sema.funcCommon(
   8787         block,
   8788         inst_data.src_node,
   8789         inst,
   8790         0,
   8791         target_util.defaultAddressSpace(target, .function),
   8792         FuncLinkSection.default,
   8793         cc,
   8794         ret_ty,
   8795         false,
   8796         inferred_error_set,
   8797         false,
   8798         has_body,
   8799         src_locs,
   8800         null,
   8801         0,
   8802         false,
   8803     );
   8804 }
   8805 
   8806 fn resolveGenericBody(
   8807     sema: *Sema,
   8808     block: *Block,
   8809     src: LazySrcLoc,
   8810     body: []const Zir.Inst.Index,
   8811     func_inst: Zir.Inst.Index,
   8812     dest_ty: Type,
   8813     reason: []const u8,
   8814 ) !Value {
   8815     assert(body.len != 0);
   8816 
   8817     const err = err: {
   8818         // Make sure any nested param instructions don't clobber our work.
   8819         const prev_params = block.params;
   8820         block.params = .{};
   8821         defer {
   8822             block.params.deinit(sema.gpa);
   8823             block.params = prev_params;
   8824         }
   8825 
   8826         const uncasted = sema.resolveBody(block, body, func_inst) catch |err| break :err err;
   8827         const result = sema.coerce(block, dest_ty, uncasted, src) catch |err| break :err err;
   8828         const val = sema.resolveConstValue(block, src, result, reason) catch |err| break :err err;
   8829         return val;
   8830     };
   8831     switch (err) {
   8832         error.GenericPoison => {
   8833             if (dest_ty.toIntern() == .type_type) {
   8834                 return Value.generic_poison_type;
   8835             } else {
   8836                 return Value.generic_poison;
   8837             }
   8838         },
   8839         else => |e| return e,
   8840     }
   8841 }
   8842 
   8843 /// Given a library name, examines if the library name should end up in
   8844 /// `link.File.Options.system_libs` table (for example, libc is always
   8845 /// specified via dedicated flag `link.File.Options.link_libc` instead),
   8846 /// and puts it there if it doesn't exist.
   8847 /// It also dupes the library name which can then be saved as part of the
   8848 /// respective `Decl` (either `ExternFn` or `Var`).
   8849 /// The liveness of the duped library name is tied to liveness of `Module`.
   8850 /// To deallocate, call `deinit` on the respective `Decl` (`ExternFn` or `Var`).
   8851 fn handleExternLibName(
   8852     sema: *Sema,
   8853     block: *Block,
   8854     src_loc: LazySrcLoc,
   8855     lib_name: []const u8,
   8856 ) CompileError![:0]u8 {
   8857     blk: {
   8858         const mod = sema.mod;
   8859         const comp = mod.comp;
   8860         const target = mod.getTarget();
   8861         log.debug("extern fn symbol expected in lib '{s}'", .{lib_name});
   8862         if (target_util.is_libc_lib_name(target, lib_name)) {
   8863             if (!comp.bin_file.options.link_libc and !comp.bin_file.options.parent_compilation_link_libc) {
   8864                 return sema.fail(
   8865                     block,
   8866                     src_loc,
   8867                     "dependency on libc must be explicitly specified in the build command",
   8868                     .{},
   8869                 );
   8870             }
   8871             comp.bin_file.options.link_libc = true;
   8872             break :blk;
   8873         }
   8874         if (target_util.is_libcpp_lib_name(target, lib_name)) {
   8875             if (!comp.bin_file.options.link_libcpp) {
   8876                 return sema.fail(
   8877                     block,
   8878                     src_loc,
   8879                     "dependency on libc++ must be explicitly specified in the build command",
   8880                     .{},
   8881                 );
   8882             }
   8883             comp.bin_file.options.link_libcpp = true;
   8884             break :blk;
   8885         }
   8886         if (mem.eql(u8, lib_name, "unwind")) {
   8887             comp.bin_file.options.link_libunwind = true;
   8888             break :blk;
   8889         }
   8890         if (!target.isWasm() and !comp.bin_file.options.pic) {
   8891             return sema.fail(
   8892                 block,
   8893                 src_loc,
   8894                 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by '-l{s}' or '-fPIC'.",
   8895                 .{ lib_name, lib_name },
   8896             );
   8897         }
   8898         comp.addLinkLib(lib_name) catch |err| {
   8899             return sema.fail(block, src_loc, "unable to add link lib '{s}': {s}", .{
   8900                 lib_name, @errorName(err),
   8901             });
   8902         };
   8903     }
   8904     return sema.gpa.dupeZ(u8, lib_name);
   8905 }
   8906 
   8907 const FuncLinkSection = union(enum) {
   8908     generic,
   8909     default,
   8910     explicit: []const u8,
   8911 };
   8912 
   8913 fn funcCommon(
   8914     sema: *Sema,
   8915     block: *Block,
   8916     src_node_offset: i32,
   8917     func_inst: Zir.Inst.Index,
   8918     /// null means generic poison
   8919     alignment: ?u32,
   8920     /// null means generic poison
   8921     address_space: ?std.builtin.AddressSpace,
   8922     /// outer null means generic poison; inner null means default link section
   8923     section: FuncLinkSection,
   8924     /// null means generic poison
   8925     cc: ?std.builtin.CallingConvention,
   8926     /// this might be Type.generic_poison
   8927     bare_return_type: Type,
   8928     var_args: bool,
   8929     inferred_error_set: bool,
   8930     is_extern: bool,
   8931     has_body: bool,
   8932     src_locs: Zir.Inst.Func.SrcLocs,
   8933     opt_lib_name: ?[]const u8,
   8934     noalias_bits: u32,
   8935     is_noinline: bool,
   8936 ) CompileError!Air.Inst.Ref {
   8937     const mod = sema.mod;
   8938     const gpa = sema.gpa;
   8939     const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
   8940     const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset };
   8941     const func_src = LazySrcLoc.nodeOffset(src_node_offset);
   8942 
   8943     var is_generic = bare_return_type.isGenericPoison() or
   8944         alignment == null or
   8945         address_space == null or
   8946         section == .generic or
   8947         cc == null;
   8948 
   8949     if (var_args) {
   8950         if (is_generic) {
   8951             return sema.fail(block, func_src, "generic function cannot be variadic", .{});
   8952         }
   8953         if (cc.? != .C) {
   8954             return sema.fail(block, cc_src, "variadic function must have 'C' calling convention", .{});
   8955         }
   8956     }
   8957 
   8958     var destroy_fn_on_error = false;
   8959     const new_func_index = new_func: {
   8960         if (!has_body) break :new_func undefined;
   8961         if (sema.comptime_args_fn_inst == func_inst) {
   8962             const new_func_index = sema.preallocated_new_func.unwrap().?;
   8963             sema.preallocated_new_func = .none; // take ownership
   8964             break :new_func new_func_index;
   8965         }
   8966         destroy_fn_on_error = true;
   8967         var new_func: Module.Fn = undefined;
   8968         // Set this here so that the inferred return type can be printed correctly if it appears in an error.
   8969         new_func.owner_decl = sema.owner_decl_index;
   8970         const new_func_index = try mod.createFunc(new_func);
   8971         break :new_func new_func_index;
   8972     };
   8973     errdefer if (destroy_fn_on_error) mod.destroyFunc(new_func_index);
   8974 
   8975     const target = sema.mod.getTarget();
   8976     const fn_ty: Type = fn_ty: {
   8977         // In the case of generic calling convention, or generic alignment, we use
   8978         // default values which are only meaningful for the generic function, *not*
   8979         // the instantiation, which can depend on comptime parameters.
   8980         // Related proposal: https://github.com/ziglang/zig/issues/11834
   8981         const cc_resolved = cc orelse .Unspecified;
   8982         const param_types = try sema.arena.alloc(InternPool.Index, block.params.items.len);
   8983         var comptime_bits: u32 = 0;
   8984         for (param_types, block.params.items, 0..) |*dest_param_ty, param, i| {
   8985             const is_noalias = blk: {
   8986                 const index = std.math.cast(u5, i) orelse break :blk false;
   8987                 break :blk @truncate(u1, noalias_bits >> index) != 0;
   8988             };
   8989             dest_param_ty.* = param.ty.toIntern();
   8990             sema.analyzeParameter(
   8991                 block,
   8992                 .unneeded,
   8993                 param,
   8994                 &comptime_bits,
   8995                 i,
   8996                 &is_generic,
   8997                 cc_resolved,
   8998                 has_body,
   8999                 is_noalias,
   9000             ) catch |err| switch (err) {
   9001                 error.NeededSourceLocation => {
   9002                     const decl = sema.mod.declPtr(block.src_decl);
   9003                     try sema.analyzeParameter(
   9004                         block,
   9005                         Module.paramSrc(src_node_offset, mod, decl, i),
   9006                         param,
   9007                         &comptime_bits,
   9008                         i,
   9009                         &is_generic,
   9010                         cc_resolved,
   9011                         has_body,
   9012                         is_noalias,
   9013                     );
   9014                     unreachable;
   9015                 },
   9016                 else => |e| return e,
   9017             };
   9018         }
   9019 
   9020         var ret_ty_requires_comptime = false;
   9021         const ret_poison = if (sema.typeRequiresComptime(bare_return_type)) |ret_comptime| rp: {
   9022             ret_ty_requires_comptime = ret_comptime;
   9023             break :rp bare_return_type.isGenericPoison();
   9024         } else |err| switch (err) {
   9025             error.GenericPoison => rp: {
   9026                 is_generic = true;
   9027                 break :rp true;
   9028             },
   9029             else => |e| return e,
   9030         };
   9031 
   9032         const return_type: Type = if (!inferred_error_set or ret_poison)
   9033             bare_return_type
   9034         else blk: {
   9035             try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src);
   9036             const ies_index = try mod.intern_pool.createInferredErrorSet(gpa, .{
   9037                 .func = new_func_index,
   9038             });
   9039             const error_set_ty = try mod.intern(.{ .inferred_error_set_type = ies_index });
   9040             break :blk try mod.errorUnionType(error_set_ty.toType(), bare_return_type);
   9041         };
   9042 
   9043         if (!return_type.isValidReturnType(mod)) {
   9044             const opaque_str = if (return_type.zigTypeTag(mod) == .Opaque) "opaque " else "";
   9045             const msg = msg: {
   9046                 const msg = try sema.errMsg(block, ret_ty_src, "{s}return type '{}' not allowed", .{
   9047                     opaque_str, return_type.fmt(sema.mod),
   9048                 });
   9049                 errdefer msg.destroy(gpa);
   9050 
   9051                 try sema.addDeclaredHereNote(msg, return_type);
   9052                 break :msg msg;
   9053             };
   9054             return sema.failWithOwnedErrorMsg(msg);
   9055         }
   9056         if (!ret_poison and !target_util.fnCallConvAllowsZigTypes(target, cc_resolved) and
   9057             !try sema.validateExternType(return_type, .ret_ty))
   9058         {
   9059             const msg = msg: {
   9060                 const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{
   9061                     return_type.fmt(sema.mod), @tagName(cc_resolved),
   9062                 });
   9063                 errdefer msg.destroy(gpa);
   9064 
   9065                 const src_decl = sema.mod.declPtr(block.src_decl);
   9066                 try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl, mod), return_type, .ret_ty);
   9067 
   9068                 try sema.addDeclaredHereNote(msg, return_type);
   9069                 break :msg msg;
   9070             };
   9071             return sema.failWithOwnedErrorMsg(msg);
   9072         }
   9073 
   9074         // If the return type is comptime-only but not dependent on parameters then all parameter types also need to be comptime
   9075         if (!sema.is_generic_instantiation and has_body and ret_ty_requires_comptime) comptime_check: {
   9076             for (block.params.items) |param| {
   9077                 if (!param.is_comptime) break;
   9078             } else break :comptime_check;
   9079 
   9080             const msg = try sema.errMsg(
   9081                 block,
   9082                 ret_ty_src,
   9083                 "function with comptime-only return type '{}' requires all parameters to be comptime",
   9084                 .{return_type.fmt(sema.mod)},
   9085             );
   9086             try sema.explainWhyTypeIsComptime(msg, ret_ty_src.toSrcLoc(sema.owner_decl, mod), return_type);
   9087 
   9088             const tags = sema.code.instructions.items(.tag);
   9089             const data = sema.code.instructions.items(.data);
   9090             const param_body = sema.code.getParamBody(func_inst);
   9091             for (block.params.items, 0..) |param, i| {
   9092                 if (!param.is_comptime) {
   9093                     const param_index = param_body[i];
   9094                     const param_src = switch (tags[param_index]) {
   9095                         .param => data[param_index].pl_tok.src(),
   9096                         .param_anytype => data[param_index].str_tok.src(),
   9097                         else => unreachable,
   9098                     };
   9099                     if (param.name.len != 0) {
   9100                         try sema.errNote(block, param_src, msg, "param '{s}' is required to be comptime", .{param.name});
   9101                     } else {
   9102                         try sema.errNote(block, param_src, msg, "param is required to be comptime", .{});
   9103                     }
   9104                 }
   9105             }
   9106             return sema.failWithOwnedErrorMsg(msg);
   9107         }
   9108 
   9109         const arch = sema.mod.getTarget().cpu.arch;
   9110         if (switch (cc_resolved) {
   9111             .Unspecified, .C, .Naked, .Async, .Inline => null,
   9112             .Interrupt => switch (arch) {
   9113                 .x86, .x86_64, .avr, .msp430 => null,
   9114                 else => @as([]const u8, "x86, x86_64, AVR, and MSP430"),
   9115             },
   9116             .Signal => switch (arch) {
   9117                 .avr => null,
   9118                 else => @as([]const u8, "AVR"),
   9119             },
   9120             .Stdcall, .Fastcall, .Thiscall => switch (arch) {
   9121                 .x86 => null,
   9122                 else => @as([]const u8, "x86"),
   9123             },
   9124             .Vectorcall => switch (arch) {
   9125                 .x86, .aarch64, .aarch64_be, .aarch64_32 => null,
   9126                 else => @as([]const u8, "x86 and AArch64"),
   9127             },
   9128             .APCS, .AAPCS, .AAPCSVFP => switch (arch) {
   9129                 .arm, .armeb, .aarch64, .aarch64_be, .aarch64_32, .thumb, .thumbeb => null,
   9130                 else => @as([]const u8, "ARM"),
   9131             },
   9132             .SysV, .Win64 => switch (arch) {
   9133                 .x86_64 => null,
   9134                 else => @as([]const u8, "x86_64"),
   9135             },
   9136             .Kernel => switch (arch) {
   9137                 .nvptx, .nvptx64, .amdgcn, .spirv32, .spirv64 => null,
   9138                 else => @as([]const u8, "nvptx, amdgcn and SPIR-V"),
   9139             },
   9140         }) |allowed_platform| {
   9141             return sema.fail(block, cc_src, "callconv '{s}' is only available on {s}, not {s}", .{
   9142                 @tagName(cc_resolved),
   9143                 allowed_platform,
   9144                 @tagName(arch),
   9145             });
   9146         }
   9147 
   9148         if (cc_resolved == .Inline and is_noinline) {
   9149             return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
   9150         }
   9151         if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;
   9152         is_generic = is_generic or comptime_bits != 0 or ret_ty_requires_comptime;
   9153 
   9154         if (!is_generic and sema.wantErrorReturnTracing(return_type)) {
   9155             // Make sure that StackTrace's fields are resolved so that the backend can
   9156             // lower this fn type.
   9157             const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
   9158             _ = try sema.resolveTypeFields(unresolved_stack_trace_ty);
   9159         }
   9160 
   9161         break :fn_ty try mod.funcType(.{
   9162             .param_types = param_types,
   9163             .noalias_bits = noalias_bits,
   9164             .comptime_bits = comptime_bits,
   9165             .return_type = return_type.toIntern(),
   9166             .cc = cc_resolved,
   9167             .cc_is_generic = cc == null,
   9168             .alignment = if (alignment) |a| InternPool.Alignment.fromByteUnits(a) else .none,
   9169             .align_is_generic = alignment == null,
   9170             .section_is_generic = section == .generic,
   9171             .addrspace_is_generic = address_space == null,
   9172             .is_var_args = var_args,
   9173             .is_generic = is_generic,
   9174             .is_noinline = is_noinline,
   9175         });
   9176     };
   9177 
   9178     sema.owner_decl.@"linksection" = switch (section) {
   9179         .generic => undefined,
   9180         .default => null,
   9181         .explicit => |section_name| try sema.perm_arena.dupeZ(u8, section_name),
   9182     };
   9183     sema.owner_decl.@"align" = alignment orelse 0;
   9184     sema.owner_decl.@"addrspace" = address_space orelse .generic;
   9185 
   9186     if (is_extern) {
   9187         return sema.addConstant(fn_ty, (try mod.intern(.{ .extern_func = .{
   9188             .ty = fn_ty.toIntern(),
   9189             .decl = sema.owner_decl_index,
   9190             .lib_name = if (opt_lib_name) |lib_name| (try mod.intern_pool.getOrPutString(
   9191                 gpa,
   9192                 try sema.handleExternLibName(block, .{
   9193                     .node_offset_lib_name = src_node_offset,
   9194                 }, lib_name),
   9195             )).toOptional() else .none,
   9196         } })).toValue());
   9197     }
   9198 
   9199     if (!has_body) {
   9200         return sema.addType(fn_ty);
   9201     }
   9202 
   9203     const is_inline = fn_ty.fnCallingConvention(mod) == .Inline;
   9204     const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .none;
   9205 
   9206     const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == func_inst) blk: {
   9207         break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;
   9208     } else null;
   9209 
   9210     const new_func = mod.funcPtr(new_func_index);
   9211     const hash = new_func.hash;
   9212     const generic_owner_decl = if (comptime_args == null) .none else new_func.generic_owner_decl;
   9213     new_func.* = .{
   9214         .state = anal_state,
   9215         .zir_body_inst = func_inst,
   9216         .owner_decl = sema.owner_decl_index,
   9217         .generic_owner_decl = generic_owner_decl,
   9218         .comptime_args = comptime_args,
   9219         .hash = hash,
   9220         .lbrace_line = src_locs.lbrace_line,
   9221         .rbrace_line = src_locs.rbrace_line,
   9222         .lbrace_column = @truncate(u16, src_locs.columns),
   9223         .rbrace_column = @truncate(u16, src_locs.columns >> 16),
   9224         .branch_quota = default_branch_quota,
   9225         .is_noinline = is_noinline,
   9226     };
   9227     return sema.addConstant(fn_ty, (try mod.intern(.{ .func = .{
   9228         .ty = fn_ty.toIntern(),
   9229         .index = new_func_index,
   9230     } })).toValue());
   9231 }
   9232 
   9233 fn analyzeParameter(
   9234     sema: *Sema,
   9235     block: *Block,
   9236     param_src: LazySrcLoc,
   9237     param: Block.Param,
   9238     comptime_bits: *u32,
   9239     i: usize,
   9240     is_generic: *bool,
   9241     cc: std.builtin.CallingConvention,
   9242     has_body: bool,
   9243     is_noalias: bool,
   9244 ) !void {
   9245     const mod = sema.mod;
   9246     const requires_comptime = try sema.typeRequiresComptime(param.ty);
   9247     if (param.is_comptime or requires_comptime) {
   9248         comptime_bits.* |= @as(u32, 1) << @intCast(u5, i); // TODO: handle cast error
   9249     }
   9250     const this_generic = param.ty.isGenericPoison();
   9251     is_generic.* = is_generic.* or this_generic;
   9252     const target = mod.getTarget();
   9253     if (param.is_comptime and !target_util.fnCallConvAllowsZigTypes(target, cc)) {
   9254         return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
   9255     }
   9256     if (this_generic and !sema.no_partial_func_ty and !target_util.fnCallConvAllowsZigTypes(target, cc)) {
   9257         return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
   9258     }
   9259     if (!param.ty.isValidParamType(mod)) {
   9260         const opaque_str = if (param.ty.zigTypeTag(mod) == .Opaque) "opaque " else "";
   9261         const msg = msg: {
   9262             const msg = try sema.errMsg(block, param_src, "parameter of {s}type '{}' not allowed", .{
   9263                 opaque_str, param.ty.fmt(mod),
   9264             });
   9265             errdefer msg.destroy(sema.gpa);
   9266 
   9267             try sema.addDeclaredHereNote(msg, param.ty);
   9268             break :msg msg;
   9269         };
   9270         return sema.failWithOwnedErrorMsg(msg);
   9271     }
   9272     if (!this_generic and !target_util.fnCallConvAllowsZigTypes(target, cc) and !try sema.validateExternType(param.ty, .param_ty)) {
   9273         const msg = msg: {
   9274             const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{
   9275                 param.ty.fmt(mod), @tagName(cc),
   9276             });
   9277             errdefer msg.destroy(sema.gpa);
   9278 
   9279             const src_decl = mod.declPtr(block.src_decl);
   9280             try sema.explainWhyTypeIsNotExtern(msg, param_src.toSrcLoc(src_decl, mod), param.ty, .param_ty);
   9281 
   9282             try sema.addDeclaredHereNote(msg, param.ty);
   9283             break :msg msg;
   9284         };
   9285         return sema.failWithOwnedErrorMsg(msg);
   9286     }
   9287     if (!sema.is_generic_instantiation and requires_comptime and !param.is_comptime and has_body) {
   9288         const msg = msg: {
   9289             const msg = try sema.errMsg(block, param_src, "parameter of type '{}' must be declared comptime", .{
   9290                 param.ty.fmt(mod),
   9291             });
   9292             errdefer msg.destroy(sema.gpa);
   9293 
   9294             const src_decl = mod.declPtr(block.src_decl);
   9295             try sema.explainWhyTypeIsComptime(msg, param_src.toSrcLoc(src_decl, mod), param.ty);
   9296 
   9297             try sema.addDeclaredHereNote(msg, param.ty);
   9298             break :msg msg;
   9299         };
   9300         return sema.failWithOwnedErrorMsg(msg);
   9301     }
   9302     if (!sema.is_generic_instantiation and !this_generic and is_noalias and
   9303         !(param.ty.zigTypeTag(mod) == .Pointer or param.ty.isPtrLikeOptional(mod)))
   9304     {
   9305         return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{});
   9306     }
   9307 }
   9308 
   9309 fn zirParam(
   9310     sema: *Sema,
   9311     block: *Block,
   9312     inst: Zir.Inst.Index,
   9313     comptime_syntax: bool,
   9314 ) CompileError!void {
   9315     const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
   9316     const src = inst_data.src();
   9317     const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);
   9318     const param_name = sema.code.nullTerminatedString(extra.data.name);
   9319     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
   9320 
   9321     // We could be in a generic function instantiation, or we could be evaluating a generic
   9322     // function without any comptime args provided.
   9323     const param_ty = param_ty: {
   9324         const err = err: {
   9325             // Make sure any nested param instructions don't clobber our work.
   9326             const prev_params = block.params;
   9327             const prev_preallocated_new_func = sema.preallocated_new_func;
   9328             const prev_no_partial_func_type = sema.no_partial_func_ty;
   9329             block.params = .{};
   9330             sema.preallocated_new_func = .none;
   9331             sema.no_partial_func_ty = true;
   9332             defer {
   9333                 block.params.deinit(sema.gpa);
   9334                 block.params = prev_params;
   9335                 sema.preallocated_new_func = prev_preallocated_new_func;
   9336                 sema.no_partial_func_ty = prev_no_partial_func_type;
   9337             }
   9338 
   9339             if (sema.resolveBody(block, body, inst)) |param_ty_inst| {
   9340                 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| {
   9341                     break :param_ty param_ty;
   9342                 } else |err| break :err err;
   9343             } else |err| break :err err;
   9344         };
   9345         switch (err) {
   9346             error.GenericPoison => {
   9347                 if (sema.inst_map.get(inst)) |_| {
   9348                     // A generic function is about to evaluate to another generic function.
   9349                     // Return an error instead.
   9350                     return error.GenericPoison;
   9351                 }
   9352                 // The type is not available until the generic instantiation.
   9353                 // We result the param instruction with a poison value and
   9354                 // insert an anytype parameter.
   9355                 try block.params.append(sema.gpa, .{
   9356                     .ty = Type.generic_poison,
   9357                     .is_comptime = comptime_syntax,
   9358                     .name = param_name,
   9359                 });
   9360                 sema.inst_map.putAssumeCapacityNoClobber(inst, .generic_poison);
   9361                 return;
   9362             },
   9363             else => |e| return e,
   9364         }
   9365     };
   9366     const is_comptime = sema.typeRequiresComptime(param_ty) catch |err| switch (err) {
   9367         error.GenericPoison => {
   9368             if (sema.inst_map.get(inst)) |_| {
   9369                 // A generic function is about to evaluate to another generic function.
   9370                 // Return an error instead.
   9371                 return error.GenericPoison;
   9372             }
   9373             // The type is not available until the generic instantiation.
   9374             // We result the param instruction with a poison value and
   9375             // insert an anytype parameter.
   9376             try block.params.append(sema.gpa, .{
   9377                 .ty = Type.generic_poison,
   9378                 .is_comptime = comptime_syntax,
   9379                 .name = param_name,
   9380             });
   9381             sema.inst_map.putAssumeCapacityNoClobber(inst, .generic_poison);
   9382             return;
   9383         },
   9384         else => |e| return e,
   9385     } or comptime_syntax;
   9386     if (sema.inst_map.get(inst)) |arg| {
   9387         if (is_comptime and sema.preallocated_new_func != .none) {
   9388             // We have a comptime value for this parameter so it should be elided from the
   9389             // function type of the function instruction in this block.
   9390             const coerced_arg = sema.coerce(block, param_ty, arg, .unneeded) catch |err| switch (err) {
   9391                 error.NeededSourceLocation => {
   9392                     // We are instantiating a generic function and a comptime arg
   9393                     // cannot be coerced to the param type, but since we don't
   9394                     // have the callee source location return `GenericPoison`
   9395                     // so that the instantiation is failed and the coercion
   9396                     // is handled by comptime call logic instead.
   9397                     assert(sema.is_generic_instantiation);
   9398                     return error.GenericPoison;
   9399                 },
   9400                 else => return err,
   9401             };
   9402             sema.inst_map.putAssumeCapacity(inst, coerced_arg);
   9403             return;
   9404         }
   9405         // Even though a comptime argument is provided, the generic function wants to treat
   9406         // this as a runtime parameter.
   9407         assert(sema.inst_map.remove(inst));
   9408     }
   9409 
   9410     if (sema.preallocated_new_func != .none) {
   9411         if (try sema.typeHasOnePossibleValue(param_ty)) |opv| {
   9412             // In this case we are instantiating a generic function call with a non-comptime
   9413             // non-anytype parameter that ended up being a one-possible-type.
   9414             // We don't want the parameter to be part of the instantiated function type.
   9415             const result = try sema.addConstant(param_ty, opv);
   9416             sema.inst_map.putAssumeCapacity(inst, result);
   9417             return;
   9418         }
   9419     }
   9420 
   9421     try block.params.append(sema.gpa, .{
   9422         .ty = param_ty,
   9423         .is_comptime = comptime_syntax,
   9424         .name = param_name,
   9425     });
   9426 
   9427     if (is_comptime) {
   9428         // If this is a comptime parameter we can add a constant generic_poison
   9429         // since this is also a generic parameter.
   9430         const result = try sema.addConstant(Type.generic_poison, Value.generic_poison);
   9431         sema.inst_map.putAssumeCapacityNoClobber(inst, result);
   9432     } else {
   9433         // Otherwise we need a dummy runtime instruction.
   9434         const result_index = @intCast(Air.Inst.Index, sema.air_instructions.len);
   9435         try sema.air_instructions.append(sema.gpa, .{
   9436             .tag = .alloc,
   9437             .data = .{ .ty = param_ty },
   9438         });
   9439         const result = Air.indexToRef(result_index);
   9440         sema.inst_map.putAssumeCapacityNoClobber(inst, result);
   9441     }
   9442 }
   9443 
   9444 fn zirParamAnytype(
   9445     sema: *Sema,
   9446     block: *Block,
   9447     inst: Zir.Inst.Index,
   9448     comptime_syntax: bool,
   9449 ) CompileError!void {
   9450     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
   9451     const param_name = inst_data.get(sema.code);
   9452 
   9453     if (sema.inst_map.get(inst)) |air_ref| {
   9454         const param_ty = sema.typeOf(air_ref);
   9455         if (comptime_syntax or try sema.typeRequiresComptime(param_ty)) {
   9456             // We have a comptime value for this parameter so it should be elided from the
   9457             // function type of the function instruction in this block.
   9458             return;
   9459         }
   9460         if (null != try sema.typeHasOnePossibleValue(param_ty)) {
   9461             return;
   9462         }
   9463         // The map is already populated but we do need to add a runtime parameter.
   9464         try block.params.append(sema.gpa, .{
   9465             .ty = param_ty,
   9466             .is_comptime = false,
   9467             .name = param_name,
   9468         });
   9469         return;
   9470     }
   9471 
   9472     // We are evaluating a generic function without any comptime args provided.
   9473 
   9474     try block.params.append(sema.gpa, .{
   9475         .ty = Type.generic_poison,
   9476         .is_comptime = comptime_syntax,
   9477         .name = param_name,
   9478     });
   9479     sema.inst_map.putAssumeCapacity(inst, .generic_poison);
   9480 }
   9481 
   9482 fn zirAs(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   9483     const tracy = trace(@src());
   9484     defer tracy.end();
   9485 
   9486     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
   9487     return sema.analyzeAs(block, sema.src, bin_inst.lhs, bin_inst.rhs, false);
   9488 }
   9489 
   9490 fn zirAsNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   9491     const tracy = trace(@src());
   9492     defer tracy.end();
   9493 
   9494     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   9495     const src = inst_data.src();
   9496     const extra = sema.code.extraData(Zir.Inst.As, inst_data.payload_index).data;
   9497     sema.src = src;
   9498     return sema.analyzeAs(block, src, extra.dest_type, extra.operand, false);
   9499 }
   9500 
   9501 fn zirAsShiftOperand(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   9502     const tracy = trace(@src());
   9503     defer tracy.end();
   9504 
   9505     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   9506     const src = inst_data.src();
   9507     const extra = sema.code.extraData(Zir.Inst.As, inst_data.payload_index).data;
   9508     return sema.analyzeAs(block, src, extra.dest_type, extra.operand, true);
   9509 }
   9510 
   9511 fn analyzeAs(
   9512     sema: *Sema,
   9513     block: *Block,
   9514     src: LazySrcLoc,
   9515     zir_dest_type: Zir.Inst.Ref,
   9516     zir_operand: Zir.Inst.Ref,
   9517     no_cast_to_comptime_int: bool,
   9518 ) CompileError!Air.Inst.Ref {
   9519     const mod = sema.mod;
   9520     const operand = try sema.resolveInst(zir_operand);
   9521     if (zir_dest_type == .var_args_param_type) return operand;
   9522     const dest_ty = sema.resolveType(block, src, zir_dest_type) catch |err| switch (err) {
   9523         error.GenericPoison => return operand,
   9524         else => |e| return e,
   9525     };
   9526     if (dest_ty.zigTypeTag(mod) == .NoReturn) {
   9527         return sema.fail(block, src, "cannot cast to noreturn", .{});
   9528     }
   9529     const is_ret = if (Zir.refToIndex(zir_dest_type)) |ptr_index|
   9530         sema.code.instructions.items(.tag)[ptr_index] == .ret_type
   9531     else
   9532         false;
   9533     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) {
   9534         error.NotCoercible => unreachable,
   9535         else => |e| return e,
   9536     };
   9537 }
   9538 
   9539 fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   9540     const tracy = trace(@src());
   9541     defer tracy.end();
   9542 
   9543     const mod = sema.mod;
   9544     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   9545     const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   9546     const ptr = try sema.resolveInst(inst_data.operand);
   9547     const ptr_ty = sema.typeOf(ptr);
   9548     if (!ptr_ty.isPtrAtRuntime(mod)) {
   9549         return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)});
   9550     }
   9551     if (try sema.resolveMaybeUndefValIntable(ptr)) |ptr_val| {
   9552         return sema.addConstant(
   9553             Type.usize,
   9554             try mod.intValue(Type.usize, (try ptr_val.getUnsignedIntAdvanced(mod, sema)).?),
   9555         );
   9556     }
   9557     try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
   9558     return block.addUnOp(.ptrtoint, ptr);
   9559 }
   9560 
   9561 fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   9562     const tracy = trace(@src());
   9563     defer tracy.end();
   9564 
   9565     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   9566     const src = inst_data.src();
   9567     const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
   9568     const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
   9569     const field_name = sema.code.nullTerminatedString(extra.field_name_start);
   9570     const object = try sema.resolveInst(extra.lhs);
   9571     return sema.fieldVal(block, src, object, field_name, field_name_src);
   9572 }
   9573 
   9574 fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: bool) CompileError!Air.Inst.Ref {
   9575     const tracy = trace(@src());
   9576     defer tracy.end();
   9577 
   9578     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   9579     const src = inst_data.src();
   9580     const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
   9581     const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
   9582     const field_name = sema.code.nullTerminatedString(extra.field_name_start);
   9583     const object_ptr = try sema.resolveInst(extra.lhs);
   9584     return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing);
   9585 }
   9586 
   9587 fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   9588     const tracy = trace(@src());
   9589     defer tracy.end();
   9590 
   9591     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   9592     const src = inst_data.src();
   9593     const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   9594     const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
   9595     const object = try sema.resolveInst(extra.lhs);
   9596     const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime-known");
   9597     return sema.fieldVal(block, src, object, field_name, field_name_src);
   9598 }
   9599 
   9600 fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   9601     const tracy = trace(@src());
   9602     defer tracy.end();
   9603 
   9604     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   9605     const src = inst_data.src();
   9606     const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   9607     const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
   9608     const object_ptr = try sema.resolveInst(extra.lhs);
   9609     const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime-known");
   9610     return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false);
   9611 }
   9612 
   9613 fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   9614     const tracy = trace(@src());
   9615     defer tracy.end();
   9616 
   9617     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   9618     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   9619     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   9620     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   9621 
   9622     const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
   9623     const operand = try sema.resolveInst(extra.rhs);
   9624 
   9625     return sema.intCast(block, inst_data.src(), dest_ty, dest_ty_src, operand, operand_src, true);
   9626 }
   9627 
   9628 fn intCast(
   9629     sema: *Sema,
   9630     block: *Block,
   9631     src: LazySrcLoc,
   9632     dest_ty: Type,
   9633     dest_ty_src: LazySrcLoc,
   9634     operand: Air.Inst.Ref,
   9635     operand_src: LazySrcLoc,
   9636     runtime_safety: bool,
   9637 ) CompileError!Air.Inst.Ref {
   9638     const mod = sema.mod;
   9639     const operand_ty = sema.typeOf(operand);
   9640     const dest_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, dest_ty, dest_ty_src);
   9641     const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
   9642 
   9643     if (try sema.isComptimeKnown(operand)) {
   9644         return sema.coerce(block, dest_ty, operand, operand_src);
   9645     } else if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
   9646         return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{});
   9647     }
   9648 
   9649     try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, dest_ty_src, operand_src);
   9650     const is_vector = dest_ty.zigTypeTag(mod) == .Vector;
   9651 
   9652     if ((try sema.typeHasOnePossibleValue(dest_ty))) |opv| {
   9653         // requirement: intCast(u0, input) iff input == 0
   9654         if (runtime_safety and block.wantSafety()) {
   9655             try sema.requireRuntimeBlock(block, src, operand_src);
   9656             const wanted_info = dest_scalar_ty.intInfo(mod);
   9657             const wanted_bits = wanted_info.bits;
   9658 
   9659             if (wanted_bits == 0) {
   9660                 const ok = if (is_vector) ok: {
   9661                     const zeros = try sema.splat(operand_ty, try mod.intValue(operand_scalar_ty, 0));
   9662                     const zero_inst = try sema.addConstant(operand_ty, zeros);
   9663                     const is_in_range = try block.addCmpVector(operand, zero_inst, .eq);
   9664                     const all_in_range = try block.addInst(.{
   9665                         .tag = .reduce,
   9666                         .data = .{ .reduce = .{ .operand = is_in_range, .operation = .And } },
   9667                     });
   9668                     break :ok all_in_range;
   9669                 } else ok: {
   9670                     const zero_inst = try sema.addConstant(operand_ty, try mod.intValue(operand_ty, 0));
   9671                     const is_in_range = try block.addBinOp(.cmp_lte, operand, zero_inst);
   9672                     break :ok is_in_range;
   9673                 };
   9674                 try sema.addSafetyCheck(block, ok, .cast_truncated_data);
   9675             }
   9676         }
   9677 
   9678         return sema.addConstant(dest_ty, opv);
   9679     }
   9680 
   9681     try sema.requireRuntimeBlock(block, src, operand_src);
   9682     if (runtime_safety and block.wantSafety()) {
   9683         const actual_info = operand_scalar_ty.intInfo(mod);
   9684         const wanted_info = dest_scalar_ty.intInfo(mod);
   9685         const actual_bits = actual_info.bits;
   9686         const wanted_bits = wanted_info.bits;
   9687         const actual_value_bits = actual_bits - @boolToInt(actual_info.signedness == .signed);
   9688         const wanted_value_bits = wanted_bits - @boolToInt(wanted_info.signedness == .signed);
   9689 
   9690         // range shrinkage
   9691         // requirement: int value fits into target type
   9692         if (wanted_value_bits < actual_value_bits) {
   9693             const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod, operand_scalar_ty);
   9694             const dest_max_val = try sema.splat(operand_ty, dest_max_val_scalar);
   9695             const dest_max = try sema.addConstant(operand_ty, dest_max_val);
   9696             const diff = try block.addBinOp(.subwrap, dest_max, operand);
   9697 
   9698             if (actual_info.signedness == .signed) {
   9699                 // Reinterpret the sign-bit as part of the value. This will make
   9700                 // negative differences (`operand` > `dest_max`) appear too big.
   9701                 const unsigned_operand_ty = try mod.intType(.unsigned, actual_bits);
   9702                 const diff_unsigned = try block.addBitCast(unsigned_operand_ty, diff);
   9703 
   9704                 // If the destination type is signed, then we need to double its
   9705                 // range to account for negative values.
   9706                 const dest_range_val = if (wanted_info.signedness == .signed) range_val: {
   9707                     const one = try mod.intValue(unsigned_operand_ty, 1);
   9708                     const range_minus_one = try dest_max_val.shl(one, unsigned_operand_ty, sema.arena, mod);
   9709                     break :range_val try sema.intAdd(range_minus_one, one, unsigned_operand_ty);
   9710                 } else try mod.getCoerced(dest_max_val, unsigned_operand_ty);
   9711                 const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val);
   9712 
   9713                 const ok = if (is_vector) ok: {
   9714                     const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte);
   9715                     const all_in_range = try block.addInst(.{
   9716                         .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
   9717                         .data = .{ .reduce = .{
   9718                             .operand = is_in_range,
   9719                             .operation = .And,
   9720                         } },
   9721                     });
   9722                     break :ok all_in_range;
   9723                 } else ok: {
   9724                     const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range);
   9725                     break :ok is_in_range;
   9726                 };
   9727                 // TODO negative_to_unsigned?
   9728                 try sema.addSafetyCheck(block, ok, .cast_truncated_data);
   9729             } else {
   9730                 const ok = if (is_vector) ok: {
   9731                     const is_in_range = try block.addCmpVector(diff, dest_max, .lte);
   9732                     const all_in_range = try block.addInst(.{
   9733                         .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
   9734                         .data = .{ .reduce = .{
   9735                             .operand = is_in_range,
   9736                             .operation = .And,
   9737                         } },
   9738                     });
   9739                     break :ok all_in_range;
   9740                 } else ok: {
   9741                     const is_in_range = try block.addBinOp(.cmp_lte, diff, dest_max);
   9742                     break :ok is_in_range;
   9743                 };
   9744                 try sema.addSafetyCheck(block, ok, .cast_truncated_data);
   9745             }
   9746         } else if (actual_info.signedness == .signed and wanted_info.signedness == .unsigned) {
   9747             // no shrinkage, yes sign loss
   9748             // requirement: signed to unsigned >= 0
   9749             const ok = if (is_vector) ok: {
   9750                 const scalar_zero = try mod.intValue(operand_scalar_ty, 0);
   9751                 const zero_val = try sema.splat(operand_ty, scalar_zero);
   9752                 const zero_inst = try sema.addConstant(operand_ty, zero_val);
   9753                 const is_in_range = try block.addCmpVector(operand, zero_inst, .gte);
   9754                 const all_in_range = try block.addInst(.{
   9755                     .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
   9756                     .data = .{ .reduce = .{
   9757                         .operand = is_in_range,
   9758                         .operation = .And,
   9759                     } },
   9760                 });
   9761                 break :ok all_in_range;
   9762             } else ok: {
   9763                 const zero_inst = try sema.addConstant(operand_ty, try mod.intValue(operand_ty, 0));
   9764                 const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst);
   9765                 break :ok is_in_range;
   9766             };
   9767             try sema.addSafetyCheck(block, ok, .negative_to_unsigned);
   9768         }
   9769     }
   9770     return block.addTyOp(.intcast, dest_ty, operand);
   9771 }
   9772 
   9773 fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   9774     const tracy = trace(@src());
   9775     defer tracy.end();
   9776 
   9777     const mod = sema.mod;
   9778     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   9779     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   9780     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   9781     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   9782 
   9783     const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
   9784     const operand = try sema.resolveInst(extra.rhs);
   9785     const operand_ty = sema.typeOf(operand);
   9786     switch (dest_ty.zigTypeTag(mod)) {
   9787         .AnyFrame,
   9788         .ComptimeFloat,
   9789         .ComptimeInt,
   9790         .EnumLiteral,
   9791         .ErrorSet,
   9792         .ErrorUnion,
   9793         .Fn,
   9794         .Frame,
   9795         .NoReturn,
   9796         .Null,
   9797         .Opaque,
   9798         .Optional,
   9799         .Type,
   9800         .Undefined,
   9801         .Void,
   9802         => return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)}),
   9803 
   9804         .Enum => {
   9805             const msg = msg: {
   9806                 const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)});
   9807                 errdefer msg.destroy(sema.gpa);
   9808                 switch (operand_ty.zigTypeTag(mod)) {
   9809                     .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToEnum to cast from '{}'", .{operand_ty.fmt(sema.mod)}),
   9810                     else => {},
   9811                 }
   9812 
   9813                 break :msg msg;
   9814             };
   9815             return sema.failWithOwnedErrorMsg(msg);
   9816         },
   9817 
   9818         .Pointer => {
   9819             const msg = msg: {
   9820                 const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)});
   9821                 errdefer msg.destroy(sema.gpa);
   9822                 switch (operand_ty.zigTypeTag(mod)) {
   9823                     .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToPtr to cast from '{}'", .{operand_ty.fmt(sema.mod)}),
   9824                     .Pointer => try sema.errNote(block, dest_ty_src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(sema.mod)}),
   9825                     else => {},
   9826                 }
   9827 
   9828                 break :msg msg;
   9829             };
   9830             return sema.failWithOwnedErrorMsg(msg);
   9831         },
   9832         .Struct, .Union => if (dest_ty.containerLayout(mod) == .Auto) {
   9833             const container = switch (dest_ty.zigTypeTag(mod)) {
   9834                 .Struct => "struct",
   9835                 .Union => "union",
   9836                 else => unreachable,
   9837             };
   9838             return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'; {s} does not have a guaranteed in-memory layout", .{
   9839                 dest_ty.fmt(sema.mod), container,
   9840             });
   9841         },
   9842 
   9843         .Array,
   9844         .Bool,
   9845         .Float,
   9846         .Int,
   9847         .Vector,
   9848         => {},
   9849     }
   9850     switch (operand_ty.zigTypeTag(mod)) {
   9851         .AnyFrame,
   9852         .ComptimeFloat,
   9853         .ComptimeInt,
   9854         .EnumLiteral,
   9855         .ErrorSet,
   9856         .ErrorUnion,
   9857         .Fn,
   9858         .Frame,
   9859         .NoReturn,
   9860         .Null,
   9861         .Opaque,
   9862         .Optional,
   9863         .Type,
   9864         .Undefined,
   9865         .Void,
   9866         => return sema.fail(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)}),
   9867 
   9868         .Enum => {
   9869             const msg = msg: {
   9870                 const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)});
   9871                 errdefer msg.destroy(sema.gpa);
   9872                 switch (dest_ty.zigTypeTag(mod)) {
   9873                     .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @enumToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}),
   9874                     else => {},
   9875                 }
   9876 
   9877                 break :msg msg;
   9878             };
   9879             return sema.failWithOwnedErrorMsg(msg);
   9880         },
   9881         .Pointer => {
   9882             const msg = msg: {
   9883                 const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)});
   9884                 errdefer msg.destroy(sema.gpa);
   9885                 switch (dest_ty.zigTypeTag(mod)) {
   9886                     .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @ptrToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}),
   9887                     .Pointer => try sema.errNote(block, operand_src, msg, "use @ptrCast to cast to '{}'", .{dest_ty.fmt(sema.mod)}),
   9888                     else => {},
   9889                 }
   9890 
   9891                 break :msg msg;
   9892             };
   9893             return sema.failWithOwnedErrorMsg(msg);
   9894         },
   9895         .Struct, .Union => if (operand_ty.containerLayout(mod) == .Auto) {
   9896             const container = switch (operand_ty.zigTypeTag(mod)) {
   9897                 .Struct => "struct",
   9898                 .Union => "union",
   9899                 else => unreachable,
   9900             };
   9901             return sema.fail(block, operand_src, "cannot @bitCast from '{}'; {s} does not have a guaranteed in-memory layout", .{
   9902                 operand_ty.fmt(sema.mod), container,
   9903             });
   9904         },
   9905 
   9906         .Array,
   9907         .Bool,
   9908         .Float,
   9909         .Int,
   9910         .Vector,
   9911         => {},
   9912     }
   9913     return sema.bitCast(block, dest_ty, operand, inst_data.src(), operand_src);
   9914 }
   9915 
   9916 fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   9917     const tracy = trace(@src());
   9918     defer tracy.end();
   9919 
   9920     const mod = sema.mod;
   9921     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   9922     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   9923     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   9924     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   9925 
   9926     const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
   9927     const operand = try sema.resolveInst(extra.rhs);
   9928 
   9929     const target = sema.mod.getTarget();
   9930     const dest_is_comptime_float = switch (dest_ty.zigTypeTag(mod)) {
   9931         .ComptimeFloat => true,
   9932         .Float => false,
   9933         else => return sema.fail(
   9934             block,
   9935             dest_ty_src,
   9936             "expected float type, found '{}'",
   9937             .{dest_ty.fmt(sema.mod)},
   9938         ),
   9939     };
   9940 
   9941     const operand_ty = sema.typeOf(operand);
   9942     switch (operand_ty.zigTypeTag(mod)) {
   9943         .ComptimeFloat, .Float, .ComptimeInt => {},
   9944         else => return sema.fail(
   9945             block,
   9946             operand_src,
   9947             "expected float type, found '{}'",
   9948             .{operand_ty.fmt(sema.mod)},
   9949         ),
   9950     }
   9951 
   9952     if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
   9953         return sema.addConstant(dest_ty, try operand_val.floatCast(dest_ty, mod));
   9954     }
   9955     if (dest_is_comptime_float) {
   9956         return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_float'", .{});
   9957     }
   9958     const src_bits = operand_ty.floatBits(target);
   9959     const dst_bits = dest_ty.floatBits(target);
   9960     if (dst_bits >= src_bits) {
   9961         return sema.coerce(block, dest_ty, operand, operand_src);
   9962     }
   9963     try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
   9964     return block.addTyOp(.fptrunc, dest_ty, operand);
   9965 }
   9966 
   9967 fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   9968     const tracy = trace(@src());
   9969     defer tracy.end();
   9970 
   9971     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   9972     const src = inst_data.src();
   9973     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   9974     const array = try sema.resolveInst(extra.lhs);
   9975     const elem_index = try sema.resolveInst(extra.rhs);
   9976     return sema.elemVal(block, src, array, elem_index, src, false);
   9977 }
   9978 
   9979 fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   9980     const tracy = trace(@src());
   9981     defer tracy.end();
   9982 
   9983     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   9984     const src = inst_data.src();
   9985     const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
   9986     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   9987     const array = try sema.resolveInst(extra.lhs);
   9988     const elem_index = try sema.resolveInst(extra.rhs);
   9989     return sema.elemVal(block, src, array, elem_index, elem_index_src, true);
   9990 }
   9991 
   9992 fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
   9993     const tracy = trace(@src());
   9994     defer tracy.end();
   9995 
   9996     const mod = sema.mod;
   9997     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   9998     const src = inst_data.src();
   9999     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  10000     const array_ptr = try sema.resolveInst(extra.lhs);
  10001     const elem_index = try sema.resolveInst(extra.rhs);
  10002     const indexable_ty = sema.typeOf(array_ptr);
  10003     if (indexable_ty.zigTypeTag(mod) != .Pointer) {
  10004         const capture_src: LazySrcLoc = .{ .for_capture_from_input = inst_data.src_node };
  10005         const msg = msg: {
  10006             const msg = try sema.errMsg(block, capture_src, "pointer capture of non pointer type '{}'", .{
  10007                 indexable_ty.fmt(sema.mod),
  10008             });
  10009             errdefer msg.destroy(sema.gpa);
  10010             if (indexable_ty.zigTypeTag(mod) == .Array) {
  10011                 try sema.errNote(block, src, msg, "consider using '&' here", .{});
  10012             }
  10013             break :msg msg;
  10014         };
  10015         return sema.failWithOwnedErrorMsg(msg);
  10016     }
  10017     return sema.elemPtrOneLayerOnly(block, src, array_ptr, elem_index, src, false, false);
  10018 }
  10019 
  10020 fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  10021     const tracy = trace(@src());
  10022     defer tracy.end();
  10023 
  10024     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  10025     const src = inst_data.src();
  10026     const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
  10027     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  10028     const array_ptr = try sema.resolveInst(extra.lhs);
  10029     const elem_index = try sema.resolveInst(extra.rhs);
  10030     return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false, true);
  10031 }
  10032 
  10033 fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  10034     const tracy = trace(@src());
  10035     defer tracy.end();
  10036 
  10037     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  10038     const src = inst_data.src();
  10039     const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;
  10040     const array_ptr = try sema.resolveInst(extra.ptr);
  10041     const elem_index = try sema.addIntUnsigned(Type.usize, extra.index);
  10042     return sema.elemPtr(block, src, array_ptr, elem_index, src, true, true);
  10043 }
  10044 
  10045 fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  10046     const tracy = trace(@src());
  10047     defer tracy.end();
  10048 
  10049     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  10050     const src = inst_data.src();
  10051     const extra = sema.code.extraData(Zir.Inst.SliceStart, inst_data.payload_index).data;
  10052     const array_ptr = try sema.resolveInst(extra.lhs);
  10053     const start = try sema.resolveInst(extra.start);
  10054     const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node };
  10055     const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
  10056     const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
  10057 
  10058     return sema.analyzeSlice(block, src, array_ptr, start, .none, .none, .unneeded, ptr_src, start_src, end_src, false);
  10059 }
  10060 
  10061 fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  10062     const tracy = trace(@src());
  10063     defer tracy.end();
  10064 
  10065     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  10066     const src = inst_data.src();
  10067     const extra = sema.code.extraData(Zir.Inst.SliceEnd, inst_data.payload_index).data;
  10068     const array_ptr = try sema.resolveInst(extra.lhs);
  10069     const start = try sema.resolveInst(extra.start);
  10070     const end = try sema.resolveInst(extra.end);
  10071     const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node };
  10072     const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
  10073     const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
  10074 
  10075     return sema.analyzeSlice(block, src, array_ptr, start, end, .none, .unneeded, ptr_src, start_src, end_src, false);
  10076 }
  10077 
  10078 fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  10079     const tracy = trace(@src());
  10080     defer tracy.end();
  10081 
  10082     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  10083     const src = inst_data.src();
  10084     const sentinel_src: LazySrcLoc = .{ .node_offset_slice_sentinel = inst_data.src_node };
  10085     const extra = sema.code.extraData(Zir.Inst.SliceSentinel, inst_data.payload_index).data;
  10086     const array_ptr = try sema.resolveInst(extra.lhs);
  10087     const start = try sema.resolveInst(extra.start);
  10088     const end = try sema.resolveInst(extra.end);
  10089     const sentinel = try sema.resolveInst(extra.sentinel);
  10090     const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node };
  10091     const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
  10092     const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
  10093 
  10094     return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src, ptr_src, start_src, end_src, false);
  10095 }
  10096 
  10097 fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  10098     const tracy = trace(@src());
  10099     defer tracy.end();
  10100 
  10101     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  10102     const src = inst_data.src();
  10103     const extra = sema.code.extraData(Zir.Inst.SliceLength, inst_data.payload_index).data;
  10104     const array_ptr = try sema.resolveInst(extra.lhs);
  10105     const start = try sema.resolveInst(extra.start);
  10106     const len = try sema.resolveInst(extra.len);
  10107     const sentinel = if (extra.sentinel == .none) .none else try sema.resolveInst(extra.sentinel);
  10108     const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node };
  10109     const start_src: LazySrcLoc = .{ .node_offset_slice_start = extra.start_src_node_offset };
  10110     const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
  10111     const sentinel_src: LazySrcLoc = if (sentinel == .none)
  10112         .unneeded
  10113     else
  10114         .{ .node_offset_slice_sentinel = inst_data.src_node };
  10115 
  10116     return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true);
  10117 }
  10118 
  10119 fn zirSwitchCapture(
  10120     sema: *Sema,
  10121     block: *Block,
  10122     inst: Zir.Inst.Index,
  10123     is_multi: bool,
  10124     is_ref: bool,
  10125 ) CompileError!Air.Inst.Ref {
  10126     const tracy = trace(@src());
  10127     defer tracy.end();
  10128 
  10129     const mod = sema.mod;
  10130     const gpa = sema.gpa;
  10131     const zir_datas = sema.code.instructions.items(.data);
  10132     const capture_info = zir_datas[inst].switch_capture;
  10133     const switch_info = zir_datas[capture_info.switch_inst].pl_node;
  10134     const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index);
  10135     const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_info.src_node };
  10136     const cond_inst = Zir.refToIndex(switch_extra.data.operand).?;
  10137     const cond_info = zir_datas[cond_inst].un_node;
  10138     const cond_tag = sema.code.instructions.items(.tag)[cond_inst];
  10139     const operand_is_ref = cond_tag == .switch_cond_ref;
  10140     const operand_ptr = try sema.resolveInst(cond_info.operand);
  10141     const operand_ptr_ty = sema.typeOf(operand_ptr);
  10142     const operand_ty = if (operand_is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty;
  10143 
  10144     if (block.inline_case_capture != .none) {
  10145         const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable;
  10146         const resolved_item_val = try sema.resolveLazyValue(item_val);
  10147         if (operand_ty.zigTypeTag(mod) == .Union) {
  10148             const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(resolved_item_val, sema.mod).?);
  10149             const union_obj = mod.typeToUnion(operand_ty).?;
  10150             const field_ty = union_obj.fields.values()[field_index].ty;
  10151             if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| {
  10152                 if (is_ref) {
  10153                     const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{
  10154                         .pointee_type = field_ty,
  10155                         .mutable = operand_ptr_ty.ptrIsMutable(mod),
  10156                         .@"volatile" = operand_ptr_ty.isVolatilePtr(mod),
  10157                         .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod),
  10158                     });
  10159                     return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{
  10160                         .ty = ptr_field_ty.toIntern(),
  10161                         .addr = .{ .field = .{
  10162                             .base = union_val.toIntern(),
  10163                             .index = field_index,
  10164                         } },
  10165                     } })).toValue());
  10166                 }
  10167                 return sema.addConstant(
  10168                     field_ty,
  10169                     mod.intern_pool.indexToKey(union_val.toIntern()).un.val.toValue(),
  10170                 );
  10171             }
  10172             if (is_ref) {
  10173                 const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{
  10174                     .pointee_type = field_ty,
  10175                     .mutable = operand_ptr_ty.ptrIsMutable(mod),
  10176                     .@"volatile" = operand_ptr_ty.isVolatilePtr(mod),
  10177                     .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod),
  10178                 });
  10179                 return block.addStructFieldPtr(operand_ptr, field_index, ptr_field_ty);
  10180             } else {
  10181                 return block.addStructFieldVal(operand_ptr, field_index, field_ty);
  10182             }
  10183         } else if (is_ref) {
  10184             return sema.addConstantMaybeRef(block, operand_ty, resolved_item_val, true);
  10185         } else {
  10186             return block.inline_case_capture;
  10187         }
  10188     }
  10189 
  10190     const operand = if (operand_is_ref)
  10191         try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src)
  10192     else
  10193         operand_ptr;
  10194 
  10195     if (capture_info.prong_index == std.math.maxInt(@TypeOf(capture_info.prong_index))) {
  10196         // It is the else/`_` prong.
  10197         if (is_ref) {
  10198             return operand_ptr;
  10199         }
  10200 
  10201         switch (operand_ty.zigTypeTag(mod)) {
  10202             .ErrorSet => if (block.switch_else_err_ty) |some| {
  10203                 return sema.bitCast(block, some, operand, operand_src, null);
  10204             } else {
  10205                 try block.addUnreachable(false);
  10206                 return Air.Inst.Ref.unreachable_value;
  10207             },
  10208             else => return operand,
  10209         }
  10210     }
  10211 
  10212     const items = if (is_multi)
  10213         switch_extra.data.getMultiProng(sema.code, switch_extra.end, capture_info.prong_index).items
  10214     else
  10215         &[_]Zir.Inst.Ref{
  10216             switch_extra.data.getScalarProng(sema.code, switch_extra.end, capture_info.prong_index).item,
  10217         };
  10218 
  10219     switch (operand_ty.zigTypeTag(mod)) {
  10220         .Union => {
  10221             const union_obj = mod.typeToUnion(operand_ty).?;
  10222             const first_item = try sema.resolveInst(items[0]);
  10223             // Previous switch validation ensured this will succeed
  10224             const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, "") catch unreachable;
  10225 
  10226             const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, sema.mod).?);
  10227             const first_field = union_obj.fields.values()[first_field_index];
  10228 
  10229             for (items[1..], 0..) |item, i| {
  10230                 const item_ref = try sema.resolveInst(item);
  10231                 // Previous switch validation ensured this will succeed
  10232                 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable;
  10233 
  10234                 const field_index = operand_ty.unionTagFieldIndex(item_val, sema.mod).?;
  10235                 const field = union_obj.fields.values()[field_index];
  10236                 if (!field.ty.eql(first_field.ty, sema.mod)) {
  10237                     const msg = msg: {
  10238                         const raw_capture_src = Module.SwitchProngSrc{ .multi_capture = capture_info.prong_index };
  10239                         const capture_src = raw_capture_src.resolve(mod, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first);
  10240 
  10241                         const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{});
  10242                         errdefer msg.destroy(gpa);
  10243 
  10244                         const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 0 } };
  10245                         const first_item_src = raw_first_item_src.resolve(mod, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first);
  10246                         const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 1 + @intCast(u32, i) } };
  10247                         const item_src = raw_item_src.resolve(mod, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first);
  10248                         try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(sema.mod)});
  10249                         try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(sema.mod)});
  10250                         break :msg msg;
  10251                     };
  10252                     return sema.failWithOwnedErrorMsg(msg);
  10253                 }
  10254             }
  10255 
  10256             if (is_ref) {
  10257                 const field_ty_ptr = try Type.ptr(sema.arena, sema.mod, .{
  10258                     .pointee_type = first_field.ty,
  10259                     .@"addrspace" = .generic,
  10260                     .mutable = operand_ptr_ty.ptrIsMutable(mod),
  10261                 });
  10262 
  10263                 if (try sema.resolveDefinedValue(block, operand_src, operand_ptr)) |op_ptr_val| {
  10264                     return sema.addConstant(field_ty_ptr, (try mod.intern(.{ .ptr = .{
  10265                         .ty = field_ty_ptr.toIntern(),
  10266                         .addr = .{ .field = .{
  10267                             .base = op_ptr_val.toIntern(),
  10268                             .index = first_field_index,
  10269                         } },
  10270                     } })).toValue());
  10271                 }
  10272                 try sema.requireRuntimeBlock(block, operand_src, null);
  10273                 return block.addStructFieldPtr(operand_ptr, first_field_index, field_ty_ptr);
  10274             }
  10275 
  10276             if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| {
  10277                 return sema.addConstant(
  10278                     first_field.ty,
  10279                     mod.intern_pool.indexToKey(operand_val.toIntern()).un.val.toValue(),
  10280                 );
  10281             }
  10282             try sema.requireRuntimeBlock(block, operand_src, null);
  10283             return block.addStructFieldVal(operand, first_field_index, first_field.ty);
  10284         },
  10285         .ErrorSet => {
  10286             if (is_multi) {
  10287                 var names: Module.Fn.InferredErrorSet.NameMap = .{};
  10288                 try names.ensureUnusedCapacity(sema.arena, items.len);
  10289                 for (items) |item| {
  10290                     const item_ref = try sema.resolveInst(item);
  10291                     // Previous switch validation ensured this will succeed
  10292                     const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable;
  10293                     const name_ip = try mod.intern_pool.getOrPutString(gpa, item_val.getError(mod).?);
  10294                     names.putAssumeCapacityNoClobber(name_ip, {});
  10295                 }
  10296                 const else_error_ty = try mod.errorSetFromUnsortedNames(names.keys());
  10297 
  10298                 return sema.bitCast(block, else_error_ty, operand, operand_src, null);
  10299             } else {
  10300                 const item_ref = try sema.resolveInst(items[0]);
  10301                 // Previous switch validation ensured this will succeed
  10302                 const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable;
  10303 
  10304                 const item_ty = try mod.singleErrorSetType(item_val.getError(mod).?);
  10305                 return sema.bitCast(block, item_ty, operand, operand_src, null);
  10306             }
  10307         },
  10308         else => {
  10309             // In this case the capture value is just the passed-through value of the
  10310             // switch condition.
  10311             if (is_ref) {
  10312                 return operand_ptr;
  10313             } else {
  10314                 return operand;
  10315             }
  10316         },
  10317     }
  10318 }
  10319 
  10320 fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  10321     const mod = sema.mod;
  10322     const zir_datas = sema.code.instructions.items(.data);
  10323     const inst_data = zir_datas[inst].un_tok;
  10324     const src = inst_data.src();
  10325 
  10326     const switch_tag = sema.code.instructions.items(.tag)[Zir.refToIndex(inst_data.operand).?];
  10327     const is_ref = switch_tag == .switch_cond_ref;
  10328     const cond_data = zir_datas[Zir.refToIndex(inst_data.operand).?].un_node;
  10329     const operand_ptr = try sema.resolveInst(cond_data.operand);
  10330     const operand_ptr_ty = sema.typeOf(operand_ptr);
  10331     const operand_ty = if (is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty;
  10332 
  10333     if (operand_ty.zigTypeTag(mod) != .Union) {
  10334         const msg = msg: {
  10335             const msg = try sema.errMsg(block, src, "cannot capture tag of non-union type '{}'", .{
  10336                 operand_ty.fmt(sema.mod),
  10337             });
  10338             errdefer msg.destroy(sema.gpa);
  10339             try sema.addDeclaredHereNote(msg, operand_ty);
  10340             break :msg msg;
  10341         };
  10342         return sema.failWithOwnedErrorMsg(msg);
  10343     }
  10344 
  10345     return block.inline_case_capture;
  10346 }
  10347 
  10348 fn zirSwitchCond(
  10349     sema: *Sema,
  10350     block: *Block,
  10351     inst: Zir.Inst.Index,
  10352     is_ref: bool,
  10353 ) CompileError!Air.Inst.Ref {
  10354     const mod = sema.mod;
  10355     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  10356     const src = inst_data.src();
  10357     const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node };
  10358     const operand_ptr = try sema.resolveInst(inst_data.operand);
  10359     const operand = if (is_ref)
  10360         try sema.analyzeLoad(block, src, operand_ptr, operand_src)
  10361     else
  10362         operand_ptr;
  10363     const operand_ty = sema.typeOf(operand);
  10364 
  10365     switch (operand_ty.zigTypeTag(mod)) {
  10366         .Type,
  10367         .Void,
  10368         .Bool,
  10369         .Int,
  10370         .Float,
  10371         .ComptimeFloat,
  10372         .ComptimeInt,
  10373         .EnumLiteral,
  10374         .Pointer,
  10375         .Fn,
  10376         .ErrorSet,
  10377         .Enum,
  10378         => {
  10379             if (operand_ty.isSlice(mod)) {
  10380                 return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)});
  10381             }
  10382             if ((try sema.typeHasOnePossibleValue(operand_ty))) |opv| {
  10383                 return sema.addConstant(operand_ty, opv);
  10384             }
  10385             return operand;
  10386         },
  10387 
  10388         .Union => {
  10389             const union_ty = try sema.resolveTypeFields(operand_ty);
  10390             const enum_ty = union_ty.unionTagType(mod) orelse {
  10391                 const msg = msg: {
  10392                     const msg = try sema.errMsg(block, src, "switch on union with no attached enum", .{});
  10393                     errdefer msg.destroy(sema.gpa);
  10394                     if (union_ty.declSrcLocOrNull(sema.mod)) |union_src| {
  10395                         try sema.mod.errNoteNonLazy(union_src, msg, "consider 'union(enum)' here", .{});
  10396                     }
  10397                     break :msg msg;
  10398                 };
  10399                 return sema.failWithOwnedErrorMsg(msg);
  10400             };
  10401             return sema.unionToTag(block, enum_ty, operand, src);
  10402         },
  10403 
  10404         .ErrorUnion,
  10405         .NoReturn,
  10406         .Array,
  10407         .Struct,
  10408         .Undefined,
  10409         .Null,
  10410         .Optional,
  10411         .Opaque,
  10412         .Vector,
  10413         .Frame,
  10414         .AnyFrame,
  10415         => return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)}),
  10416     }
  10417 }
  10418 
  10419 const SwitchErrorSet = std.StringHashMap(Module.SwitchProngSrc);
  10420 
  10421 fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  10422     const tracy = trace(@src());
  10423     defer tracy.end();
  10424 
  10425     const mod = sema.mod;
  10426     const gpa = sema.gpa;
  10427     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  10428     const src = inst_data.src();
  10429     const src_node_offset = inst_data.src_node;
  10430     const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };
  10431     const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset };
  10432     const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);
  10433 
  10434     const operand = try sema.resolveInst(extra.data.operand);
  10435     // AstGen guarantees that the instruction immediately following
  10436     // switch_cond(_ref) is a dbg_stmt
  10437     const cond_dbg_node_index = Zir.refToIndex(extra.data.operand).? + 1;
  10438 
  10439     var header_extra_index: usize = extra.end;
  10440 
  10441     const scalar_cases_len = extra.data.bits.scalar_cases_len;
  10442     const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: {
  10443         const multi_cases_len = sema.code.extra[header_extra_index];
  10444         header_extra_index += 1;
  10445         break :blk multi_cases_len;
  10446     } else 0;
  10447 
  10448     const special_prong = extra.data.bits.specialProng();
  10449     const special: struct { body: []const Zir.Inst.Index, end: usize, is_inline: bool } = switch (special_prong) {
  10450         .none => .{ .body = &.{}, .end = header_extra_index, .is_inline = false },
  10451         .under, .@"else" => blk: {
  10452             const body_len = @truncate(u31, sema.code.extra[header_extra_index]);
  10453             const extra_body_start = header_extra_index + 1;
  10454             break :blk .{
  10455                 .body = sema.code.extra[extra_body_start..][0..body_len],
  10456                 .end = extra_body_start + body_len,
  10457                 .is_inline = sema.code.extra[header_extra_index] >> 31 != 0,
  10458             };
  10459         },
  10460     };
  10461 
  10462     const maybe_union_ty = blk: {
  10463         const zir_tags = sema.code.instructions.items(.tag);
  10464         const zir_data = sema.code.instructions.items(.data);
  10465         const cond_index = Zir.refToIndex(extra.data.operand).?;
  10466         const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable;
  10467         const target_ty = sema.typeOf(raw_operand);
  10468         break :blk if (zir_tags[cond_index] == .switch_cond_ref) target_ty.childType(mod) else target_ty;
  10469     };
  10470     const union_originally = maybe_union_ty.zigTypeTag(mod) == .Union;
  10471 
  10472     // Duplicate checking variables later also used for `inline else`.
  10473     var seen_enum_fields: []?Module.SwitchProngSrc = &.{};
  10474     var seen_errors = SwitchErrorSet.init(gpa);
  10475     var range_set = RangeSet.init(gpa, mod);
  10476     var true_count: u8 = 0;
  10477     var false_count: u8 = 0;
  10478 
  10479     defer {
  10480         range_set.deinit();
  10481         gpa.free(seen_enum_fields);
  10482         seen_errors.deinit();
  10483     }
  10484 
  10485     var empty_enum = false;
  10486 
  10487     const operand_ty = sema.typeOf(operand);
  10488     const err_set = operand_ty.zigTypeTag(mod) == .ErrorSet;
  10489 
  10490     var else_error_ty: ?Type = null;
  10491 
  10492     // Validate usage of '_' prongs.
  10493     if (special_prong == .under and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally)) {
  10494         const msg = msg: {
  10495             const msg = try sema.errMsg(
  10496                 block,
  10497                 src,
  10498                 "'_' prong only allowed when switching on non-exhaustive enums",
  10499                 .{},
  10500             );
  10501             errdefer msg.destroy(gpa);
  10502             try sema.errNote(
  10503                 block,
  10504                 special_prong_src,
  10505                 msg,
  10506                 "'_' prong here",
  10507                 .{},
  10508             );
  10509             break :msg msg;
  10510         };
  10511         return sema.failWithOwnedErrorMsg(msg);
  10512     }
  10513 
  10514     // Validate for duplicate items, missing else prong, and invalid range.
  10515     switch (operand_ty.zigTypeTag(mod)) {
  10516         .Union => unreachable, // handled in zirSwitchCond
  10517         .Enum => {
  10518             seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount(mod));
  10519             empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(mod);
  10520             @memset(seen_enum_fields, null);
  10521             // `range_set` is used for non-exhaustive enum values that do not correspond to any tags.
  10522 
  10523             var extra_index: usize = special.end;
  10524             {
  10525                 var scalar_i: u32 = 0;
  10526                 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
  10527                     const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  10528                     extra_index += 1;
  10529                     const body_len = @truncate(u31, sema.code.extra[extra_index]);
  10530                     extra_index += 1;
  10531                     extra_index += body_len;
  10532 
  10533                     try sema.validateSwitchItemEnum(
  10534                         block,
  10535                         seen_enum_fields,
  10536                         &range_set,
  10537                         item_ref,
  10538                         src_node_offset,
  10539                         .{ .scalar = scalar_i },
  10540                     );
  10541                 }
  10542             }
  10543             {
  10544                 var multi_i: u32 = 0;
  10545                 while (multi_i < multi_cases_len) : (multi_i += 1) {
  10546                     const items_len = sema.code.extra[extra_index];
  10547                     extra_index += 1;
  10548                     const ranges_len = sema.code.extra[extra_index];
  10549                     extra_index += 1;
  10550                     const body_len = @truncate(u31, sema.code.extra[extra_index]);
  10551                     extra_index += 1;
  10552                     const items = sema.code.refSlice(extra_index, items_len);
  10553                     extra_index += items_len + body_len;
  10554 
  10555                     for (items, 0..) |item_ref, item_i| {
  10556                         try sema.validateSwitchItemEnum(
  10557                             block,
  10558                             seen_enum_fields,
  10559                             &range_set,
  10560                             item_ref,
  10561                             src_node_offset,
  10562                             .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
  10563                         );
  10564                     }
  10565 
  10566                     try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
  10567                 }
  10568             }
  10569             const all_tags_handled = for (seen_enum_fields) |seen_src| {
  10570                 if (seen_src == null) break false;
  10571             } else true;
  10572 
  10573             if (special_prong == .@"else") {
  10574                 if (all_tags_handled and !operand_ty.isNonexhaustiveEnum(mod)) return sema.fail(
  10575                     block,
  10576                     special_prong_src,
  10577                     "unreachable else prong; all cases already handled",
  10578                     .{},
  10579                 );
  10580             } else if (!all_tags_handled) {
  10581                 const msg = msg: {
  10582                     const msg = try sema.errMsg(
  10583                         block,
  10584                         src,
  10585                         "switch must handle all possibilities",
  10586                         .{},
  10587                     );
  10588                     errdefer msg.destroy(sema.gpa);
  10589                     for (seen_enum_fields, 0..) |seen_src, i| {
  10590                         if (seen_src != null) continue;
  10591 
  10592                         const field_name = operand_ty.enumFieldName(i, mod);
  10593                         try sema.addFieldErrNote(
  10594                             operand_ty,
  10595                             i,
  10596                             msg,
  10597                             "unhandled enumeration value: '{s}'",
  10598                             .{field_name},
  10599                         );
  10600                     }
  10601                     try mod.errNoteNonLazy(
  10602                         operand_ty.declSrcLoc(mod),
  10603                         msg,
  10604                         "enum '{}' declared here",
  10605                         .{operand_ty.fmt(mod)},
  10606                     );
  10607                     break :msg msg;
  10608                 };
  10609                 return sema.failWithOwnedErrorMsg(msg);
  10610             } else if (special_prong == .none and operand_ty.isNonexhaustiveEnum(mod) and !union_originally) {
  10611                 return sema.fail(
  10612                     block,
  10613                     src,
  10614                     "switch on non-exhaustive enum must include 'else' or '_' prong",
  10615                     .{},
  10616                 );
  10617             }
  10618         },
  10619         .ErrorSet => {
  10620             var extra_index: usize = special.end;
  10621             {
  10622                 var scalar_i: u32 = 0;
  10623                 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
  10624                     const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  10625                     extra_index += 1;
  10626                     const body_len = @truncate(u31, sema.code.extra[extra_index]);
  10627                     extra_index += 1;
  10628                     extra_index += body_len;
  10629 
  10630                     try sema.validateSwitchItemError(
  10631                         block,
  10632                         &seen_errors,
  10633                         item_ref,
  10634                         src_node_offset,
  10635                         .{ .scalar = scalar_i },
  10636                     );
  10637                 }
  10638             }
  10639             {
  10640                 var multi_i: u32 = 0;
  10641                 while (multi_i < multi_cases_len) : (multi_i += 1) {
  10642                     const items_len = sema.code.extra[extra_index];
  10643                     extra_index += 1;
  10644                     const ranges_len = sema.code.extra[extra_index];
  10645                     extra_index += 1;
  10646                     const body_len = @truncate(u31, sema.code.extra[extra_index]);
  10647                     extra_index += 1;
  10648                     const items = sema.code.refSlice(extra_index, items_len);
  10649                     extra_index += items_len + body_len;
  10650 
  10651                     for (items, 0..) |item_ref, item_i| {
  10652                         try sema.validateSwitchItemError(
  10653                             block,
  10654                             &seen_errors,
  10655                             item_ref,
  10656                             src_node_offset,
  10657                             .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
  10658                         );
  10659                     }
  10660 
  10661                     try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
  10662                 }
  10663             }
  10664 
  10665             try sema.resolveInferredErrorSetTy(block, src, operand_ty);
  10666 
  10667             if (operand_ty.isAnyError(mod)) {
  10668                 if (special_prong != .@"else") {
  10669                     return sema.fail(
  10670                         block,
  10671                         src,
  10672                         "else prong required when switching on type 'anyerror'",
  10673                         .{},
  10674                     );
  10675                 }
  10676                 else_error_ty = Type.anyerror;
  10677             } else else_validation: {
  10678                 var maybe_msg: ?*Module.ErrorMsg = null;
  10679                 errdefer if (maybe_msg) |msg| msg.destroy(sema.gpa);
  10680 
  10681                 for (operand_ty.errorSetNames(mod)) |error_name_ip| {
  10682                     const error_name = mod.intern_pool.stringToSlice(error_name_ip);
  10683                     if (!seen_errors.contains(error_name) and special_prong != .@"else") {
  10684                         const msg = maybe_msg orelse blk: {
  10685                             maybe_msg = try sema.errMsg(
  10686                                 block,
  10687                                 src,
  10688                                 "switch must handle all possibilities",
  10689                                 .{},
  10690                             );
  10691                             break :blk maybe_msg.?;
  10692                         };
  10693 
  10694                         try sema.errNote(
  10695                             block,
  10696                             src,
  10697                             msg,
  10698                             "unhandled error value: 'error.{s}'",
  10699                             .{error_name},
  10700                         );
  10701                     }
  10702                 }
  10703 
  10704                 if (maybe_msg) |msg| {
  10705                     maybe_msg = null;
  10706                     try sema.addDeclaredHereNote(msg, operand_ty);
  10707                     return sema.failWithOwnedErrorMsg(msg);
  10708                 }
  10709 
  10710                 if (special_prong == .@"else" and seen_errors.count() == operand_ty.errorSetNames(mod).len) {
  10711                     // In order to enable common patterns for generic code allow simple else bodies
  10712                     // else => unreachable,
  10713                     // else => return,
  10714                     // else => |e| return e,
  10715                     // even if all the possible errors were already handled.
  10716                     const tags = sema.code.instructions.items(.tag);
  10717                     for (special.body) |else_inst| switch (tags[else_inst]) {
  10718                         .dbg_block_begin,
  10719                         .dbg_block_end,
  10720                         .dbg_stmt,
  10721                         .dbg_var_val,
  10722                         .switch_capture,
  10723                         .ret_type,
  10724                         .as_node,
  10725                         .ret_node,
  10726                         .@"unreachable",
  10727                         .@"defer",
  10728                         .defer_err_code,
  10729                         .err_union_code,
  10730                         .ret_err_value_code,
  10731                         .restore_err_ret_index,
  10732                         .is_non_err,
  10733                         .ret_is_non_err,
  10734                         .condbr,
  10735                         => {},
  10736                         else => break,
  10737                     } else break :else_validation;
  10738 
  10739                     return sema.fail(
  10740                         block,
  10741                         special_prong_src,
  10742                         "unreachable else prong; all cases already handled",
  10743                         .{},
  10744                     );
  10745                 }
  10746 
  10747                 const error_names = operand_ty.errorSetNames(mod);
  10748                 var names: Module.Fn.InferredErrorSet.NameMap = .{};
  10749                 try names.ensureUnusedCapacity(sema.arena, error_names.len);
  10750                 for (error_names) |error_name_ip| {
  10751                     const error_name = mod.intern_pool.stringToSlice(error_name_ip);
  10752                     if (seen_errors.contains(error_name)) continue;
  10753 
  10754                     names.putAssumeCapacityNoClobber(error_name_ip, {});
  10755                 }
  10756                 // No need to keep the hash map metadata correct; here we
  10757                 // extract the (sorted) keys only.
  10758                 else_error_ty = try mod.errorSetFromUnsortedNames(names.keys());
  10759             }
  10760         },
  10761         .Int, .ComptimeInt => {
  10762             var extra_index: usize = special.end;
  10763             {
  10764                 var scalar_i: u32 = 0;
  10765                 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
  10766                     const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  10767                     extra_index += 1;
  10768                     const body_len = @truncate(u31, sema.code.extra[extra_index]);
  10769                     extra_index += 1;
  10770                     extra_index += body_len;
  10771 
  10772                     try sema.validateSwitchItem(
  10773                         block,
  10774                         &range_set,
  10775                         item_ref,
  10776                         src_node_offset,
  10777                         .{ .scalar = scalar_i },
  10778                     );
  10779                 }
  10780             }
  10781             {
  10782                 var multi_i: u32 = 0;
  10783                 while (multi_i < multi_cases_len) : (multi_i += 1) {
  10784                     const items_len = sema.code.extra[extra_index];
  10785                     extra_index += 1;
  10786                     const ranges_len = sema.code.extra[extra_index];
  10787                     extra_index += 1;
  10788                     const body_len = @truncate(u31, sema.code.extra[extra_index]);
  10789                     extra_index += 1;
  10790                     const items = sema.code.refSlice(extra_index, items_len);
  10791                     extra_index += items_len;
  10792 
  10793                     for (items, 0..) |item_ref, item_i| {
  10794                         try sema.validateSwitchItem(
  10795                             block,
  10796                             &range_set,
  10797                             item_ref,
  10798                             src_node_offset,
  10799                             .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
  10800                         );
  10801                     }
  10802 
  10803                     var range_i: u32 = 0;
  10804                     while (range_i < ranges_len) : (range_i += 1) {
  10805                         const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  10806                         extra_index += 1;
  10807                         const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  10808                         extra_index += 1;
  10809 
  10810                         try sema.validateSwitchRange(
  10811                             block,
  10812                             &range_set,
  10813                             item_first,
  10814                             item_last,
  10815                             src_node_offset,
  10816                             .{ .range = .{ .prong = multi_i, .item = range_i } },
  10817                         );
  10818                     }
  10819 
  10820                     extra_index += body_len;
  10821                 }
  10822             }
  10823 
  10824             check_range: {
  10825                 if (operand_ty.zigTypeTag(mod) == .Int) {
  10826                     const min_int = try operand_ty.minInt(mod, operand_ty);
  10827                     const max_int = try operand_ty.maxInt(mod, operand_ty);
  10828                     if (try range_set.spans(min_int.toIntern(), max_int.toIntern())) {
  10829                         if (special_prong == .@"else") {
  10830                             return sema.fail(
  10831                                 block,
  10832                                 special_prong_src,
  10833                                 "unreachable else prong; all cases already handled",
  10834                                 .{},
  10835                             );
  10836                         }
  10837                         break :check_range;
  10838                     }
  10839                 }
  10840                 if (special_prong != .@"else") {
  10841                     return sema.fail(
  10842                         block,
  10843                         src,
  10844                         "switch must handle all possibilities",
  10845                         .{},
  10846                     );
  10847                 }
  10848             }
  10849         },
  10850         .Bool => {
  10851             var extra_index: usize = special.end;
  10852             {
  10853                 var scalar_i: u32 = 0;
  10854                 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
  10855                     const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  10856                     extra_index += 1;
  10857                     const body_len = @truncate(u31, sema.code.extra[extra_index]);
  10858                     extra_index += 1;
  10859                     extra_index += body_len;
  10860 
  10861                     try sema.validateSwitchItemBool(
  10862                         block,
  10863                         &true_count,
  10864                         &false_count,
  10865                         item_ref,
  10866                         src_node_offset,
  10867                         .{ .scalar = scalar_i },
  10868                     );
  10869                 }
  10870             }
  10871             {
  10872                 var multi_i: u32 = 0;
  10873                 while (multi_i < multi_cases_len) : (multi_i += 1) {
  10874                     const items_len = sema.code.extra[extra_index];
  10875                     extra_index += 1;
  10876                     const ranges_len = sema.code.extra[extra_index];
  10877                     extra_index += 1;
  10878                     const body_len = @truncate(u31, sema.code.extra[extra_index]);
  10879                     extra_index += 1;
  10880                     const items = sema.code.refSlice(extra_index, items_len);
  10881                     extra_index += items_len + body_len;
  10882 
  10883                     for (items, 0..) |item_ref, item_i| {
  10884                         try sema.validateSwitchItemBool(
  10885                             block,
  10886                             &true_count,
  10887                             &false_count,
  10888                             item_ref,
  10889                             src_node_offset,
  10890                             .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
  10891                         );
  10892                     }
  10893 
  10894                     try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
  10895                 }
  10896             }
  10897             switch (special_prong) {
  10898                 .@"else" => {
  10899                     if (true_count + false_count == 2) {
  10900                         return sema.fail(
  10901                             block,
  10902                             special_prong_src,
  10903                             "unreachable else prong; all cases already handled",
  10904                             .{},
  10905                         );
  10906                     }
  10907                 },
  10908                 .under, .none => {
  10909                     if (true_count + false_count < 2) {
  10910                         return sema.fail(
  10911                             block,
  10912                             src,
  10913                             "switch must handle all possibilities",
  10914                             .{},
  10915                         );
  10916                     }
  10917                 },
  10918             }
  10919         },
  10920         .EnumLiteral, .Void, .Fn, .Pointer, .Type => {
  10921             if (special_prong != .@"else") {
  10922                 return sema.fail(
  10923                     block,
  10924                     src,
  10925                     "else prong required when switching on type '{}'",
  10926                     .{operand_ty.fmt(mod)},
  10927                 );
  10928             }
  10929 
  10930             var seen_values = ValueSrcMap{};
  10931             defer seen_values.deinit(gpa);
  10932 
  10933             var extra_index: usize = special.end;
  10934             {
  10935                 var scalar_i: u32 = 0;
  10936                 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
  10937                     const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  10938                     extra_index += 1;
  10939                     const body_len = @truncate(u31, sema.code.extra[extra_index]);
  10940                     extra_index += 1;
  10941                     extra_index += body_len;
  10942 
  10943                     try sema.validateSwitchItemSparse(
  10944                         block,
  10945                         &seen_values,
  10946                         item_ref,
  10947                         src_node_offset,
  10948                         .{ .scalar = scalar_i },
  10949                     );
  10950                 }
  10951             }
  10952             {
  10953                 var multi_i: u32 = 0;
  10954                 while (multi_i < multi_cases_len) : (multi_i += 1) {
  10955                     const items_len = sema.code.extra[extra_index];
  10956                     extra_index += 1;
  10957                     const ranges_len = sema.code.extra[extra_index];
  10958                     extra_index += 1;
  10959                     const body_len = @truncate(u31, sema.code.extra[extra_index]);
  10960                     extra_index += 1;
  10961                     const items = sema.code.refSlice(extra_index, items_len);
  10962                     extra_index += items_len + body_len;
  10963 
  10964                     for (items, 0..) |item_ref, item_i| {
  10965                         try sema.validateSwitchItemSparse(
  10966                             block,
  10967                             &seen_values,
  10968                             item_ref,
  10969                             src_node_offset,
  10970                             .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
  10971                         );
  10972                     }
  10973 
  10974                     try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
  10975                 }
  10976             }
  10977         },
  10978 
  10979         .ErrorUnion,
  10980         .NoReturn,
  10981         .Array,
  10982         .Struct,
  10983         .Undefined,
  10984         .Null,
  10985         .Optional,
  10986         .Opaque,
  10987         .Vector,
  10988         .Frame,
  10989         .AnyFrame,
  10990         .ComptimeFloat,
  10991         .Float,
  10992         => return sema.fail(block, operand_src, "invalid switch operand type '{}'", .{
  10993             operand_ty.fmt(mod),
  10994         }),
  10995     }
  10996 
  10997     const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
  10998     try sema.air_instructions.append(gpa, .{
  10999         .tag = .block,
  11000         .data = undefined,
  11001     });
  11002     var label: Block.Label = .{
  11003         .zir_block = inst,
  11004         .merges = .{
  11005             .src_locs = .{},
  11006             .results = .{},
  11007             .br_list = .{},
  11008             .block_inst = block_inst,
  11009         },
  11010     };
  11011 
  11012     var child_block: Block = .{
  11013         .parent = block,
  11014         .sema = sema,
  11015         .src_decl = block.src_decl,
  11016         .namespace = block.namespace,
  11017         .wip_capture_scope = block.wip_capture_scope,
  11018         .instructions = .{},
  11019         .label = &label,
  11020         .inlining = block.inlining,
  11021         .is_comptime = block.is_comptime,
  11022         .comptime_reason = block.comptime_reason,
  11023         .is_typeof = block.is_typeof,
  11024         .switch_else_err_ty = else_error_ty,
  11025         .c_import_buf = block.c_import_buf,
  11026         .runtime_cond = block.runtime_cond,
  11027         .runtime_loop = block.runtime_loop,
  11028         .runtime_index = block.runtime_index,
  11029         .error_return_trace_index = block.error_return_trace_index,
  11030     };
  11031     const merges = &child_block.label.?.merges;
  11032     defer child_block.instructions.deinit(gpa);
  11033     defer merges.deinit(gpa);
  11034 
  11035     if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| {
  11036         const resolved_operand_val = try sema.resolveLazyValue(operand_val);
  11037         var extra_index: usize = special.end;
  11038         {
  11039             var scalar_i: usize = 0;
  11040             while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
  11041                 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  11042                 extra_index += 1;
  11043                 const body_len = @truncate(u31, sema.code.extra[extra_index]);
  11044                 const is_inline = sema.code.extra[extra_index] >> 31 != 0;
  11045                 extra_index += 1;
  11046                 const body = sema.code.extra[extra_index..][0..body_len];
  11047                 extra_index += body_len;
  11048 
  11049                 const item = try sema.resolveInst(item_ref);
  11050                 // Validation above ensured these will succeed.
  11051                 const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable;
  11052                 if (resolved_operand_val.eql(item_val, operand_ty, mod)) {
  11053                     if (is_inline) child_block.inline_case_capture = operand;
  11054 
  11055                     if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
  11056                     return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
  11057                 }
  11058             }
  11059         }
  11060         {
  11061             var multi_i: usize = 0;
  11062             while (multi_i < multi_cases_len) : (multi_i += 1) {
  11063                 const items_len = sema.code.extra[extra_index];
  11064                 extra_index += 1;
  11065                 const ranges_len = sema.code.extra[extra_index];
  11066                 extra_index += 1;
  11067                 const body_len = @truncate(u31, sema.code.extra[extra_index]);
  11068                 const is_inline = sema.code.extra[extra_index] >> 31 != 0;
  11069                 extra_index += 1;
  11070                 const items = sema.code.refSlice(extra_index, items_len);
  11071                 extra_index += items_len;
  11072                 const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..body_len];
  11073 
  11074                 for (items) |item_ref| {
  11075                     const item = try sema.resolveInst(item_ref);
  11076                     // Validation above ensured these will succeed.
  11077                     const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable;
  11078                     if (resolved_operand_val.eql(item_val, operand_ty, mod)) {
  11079                         if (is_inline) child_block.inline_case_capture = operand;
  11080 
  11081                         if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
  11082                         return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
  11083                     }
  11084                 }
  11085 
  11086                 var range_i: usize = 0;
  11087                 while (range_i < ranges_len) : (range_i += 1) {
  11088                     const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  11089                     extra_index += 1;
  11090                     const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  11091                     extra_index += 1;
  11092 
  11093                     // Validation above ensured these will succeed.
  11094                     const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, "") catch unreachable;
  11095                     const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, "") catch unreachable;
  11096                     if ((try sema.compareAll(resolved_operand_val, .gte, first_tv.val, operand_ty)) and
  11097                         (try sema.compareAll(resolved_operand_val, .lte, last_tv.val, operand_ty)))
  11098                     {
  11099                         if (is_inline) child_block.inline_case_capture = operand;
  11100                         if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
  11101                         return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
  11102                     }
  11103                 }
  11104 
  11105                 extra_index += body_len;
  11106             }
  11107         }
  11108         if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);
  11109         if (special.is_inline) child_block.inline_case_capture = operand;
  11110         if (empty_enum) {
  11111             return Air.Inst.Ref.void_value;
  11112         }
  11113         return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
  11114     }
  11115 
  11116     if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) {
  11117         if (empty_enum) {
  11118             return Air.Inst.Ref.void_value;
  11119         }
  11120         if (special_prong == .none) {
  11121             return sema.fail(block, src, "switch must handle all possibilities", .{});
  11122         }
  11123         if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) {
  11124             return Air.Inst.Ref.unreachable_value;
  11125         }
  11126         if (mod.backendSupportsFeature(.is_named_enum_value) and block.wantSafety() and operand_ty.zigTypeTag(mod) == .Enum and
  11127             (!operand_ty.isNonexhaustiveEnum(mod) or union_originally))
  11128         {
  11129             try sema.zirDbgStmt(block, cond_dbg_node_index);
  11130             const ok = try block.addUnOp(.is_named_enum_value, operand);
  11131             try sema.addSafetyCheck(block, ok, .corrupt_switch);
  11132         }
  11133         return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
  11134     }
  11135 
  11136     if (child_block.is_comptime) {
  11137         _ = sema.resolveConstValue(&child_block, operand_src, operand, "condition in comptime switch must be comptime-known") catch |err| {
  11138             if (err == error.AnalysisFail and child_block.comptime_reason != null) try child_block.comptime_reason.?.explain(sema, sema.err);
  11139             return err;
  11140         };
  11141         unreachable;
  11142     }
  11143 
  11144     const estimated_cases_extra = (scalar_cases_len + multi_cases_len) *
  11145         @typeInfo(Air.SwitchBr.Case).Struct.fields.len + 2;
  11146     var cases_extra = try std.ArrayListUnmanaged(u32).initCapacity(gpa, estimated_cases_extra);
  11147     defer cases_extra.deinit(gpa);
  11148 
  11149     var case_block = child_block.makeSubBlock();
  11150     case_block.runtime_loop = null;
  11151     case_block.runtime_cond = operand_src;
  11152     case_block.runtime_index.increment();
  11153     defer case_block.instructions.deinit(gpa);
  11154 
  11155     var extra_index: usize = special.end;
  11156 
  11157     var scalar_i: usize = 0;
  11158     while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
  11159         const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  11160         extra_index += 1;
  11161         const body_len = @truncate(u31, sema.code.extra[extra_index]);
  11162         const is_inline = sema.code.extra[extra_index] >> 31 != 0;
  11163         extra_index += 1;
  11164         const body = sema.code.extra[extra_index..][0..body_len];
  11165         extra_index += body_len;
  11166 
  11167         var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope);
  11168         defer wip_captures.deinit();
  11169 
  11170         case_block.instructions.shrinkRetainingCapacity(0);
  11171         case_block.wip_capture_scope = wip_captures.scope;
  11172         case_block.inline_case_capture = .none;
  11173 
  11174         const item = try sema.resolveInst(item_ref);
  11175         if (is_inline) case_block.inline_case_capture = item;
  11176         // `item` is already guaranteed to be constant known.
  11177 
  11178         const analyze_body = if (union_originally) blk: {
  11179             const item_val = sema.resolveConstLazyValue(block, .unneeded, item, "") catch unreachable;
  11180             const field_ty = maybe_union_ty.unionFieldType(item_val, mod);
  11181             break :blk field_ty.zigTypeTag(mod) != .NoReturn;
  11182         } else true;
  11183 
  11184         if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
  11185             // nothing to do here
  11186         } else if (analyze_body) {
  11187             try sema.analyzeBodyRuntimeBreak(&case_block, body);
  11188         } else {
  11189             _ = try case_block.addNoOp(.unreach);
  11190         }
  11191 
  11192         try wip_captures.finalize();
  11193 
  11194         try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
  11195         cases_extra.appendAssumeCapacity(1); // items_len
  11196         cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
  11197         cases_extra.appendAssumeCapacity(@enumToInt(item));
  11198         cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
  11199     }
  11200 
  11201     var is_first = true;
  11202     var prev_cond_br: Air.Inst.Index = undefined;
  11203     var first_else_body: []const Air.Inst.Index = &.{};
  11204     defer gpa.free(first_else_body);
  11205     var prev_then_body: []const Air.Inst.Index = &.{};
  11206     defer gpa.free(prev_then_body);
  11207 
  11208     var cases_len = scalar_cases_len;
  11209     var multi_i: u32 = 0;
  11210     while (multi_i < multi_cases_len) : (multi_i += 1) {
  11211         const items_len = sema.code.extra[extra_index];
  11212         extra_index += 1;
  11213         const ranges_len = sema.code.extra[extra_index];
  11214         extra_index += 1;
  11215         const body_len = @truncate(u31, sema.code.extra[extra_index]);
  11216         const is_inline = sema.code.extra[extra_index] >> 31 != 0;
  11217         extra_index += 1;
  11218         const items = sema.code.refSlice(extra_index, items_len);
  11219         extra_index += items_len;
  11220 
  11221         case_block.instructions.shrinkRetainingCapacity(0);
  11222         case_block.wip_capture_scope = child_block.wip_capture_scope;
  11223         case_block.inline_case_capture = .none;
  11224 
  11225         // Generate all possible cases as scalar prongs.
  11226         if (is_inline) {
  11227             const body_start = extra_index + 2 * ranges_len;
  11228             const body = sema.code.extra[body_start..][0..body_len];
  11229             var emit_bb = false;
  11230 
  11231             var range_i: u32 = 0;
  11232             while (range_i < ranges_len) : (range_i += 1) {
  11233                 const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  11234                 extra_index += 1;
  11235                 const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  11236                 extra_index += 1;
  11237 
  11238                 const item_first_ref = try sema.resolveInst(first_ref);
  11239                 var item = sema.resolveConstValue(block, .unneeded, item_first_ref, undefined) catch unreachable;
  11240                 const item_last_ref = try sema.resolveInst(last_ref);
  11241                 const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable;
  11242 
  11243                 while (item.compareScalar(.lte, item_last, operand_ty, mod)) : ({
  11244                     // Previous validation has resolved any possible lazy values.
  11245                     item = try sema.intAddScalar(item, try mod.intValue(operand_ty, 1), operand_ty);
  11246                 }) {
  11247                     cases_len += 1;
  11248 
  11249                     const item_ref = try sema.addConstant(operand_ty, item);
  11250                     case_block.inline_case_capture = item_ref;
  11251 
  11252                     case_block.instructions.shrinkRetainingCapacity(0);
  11253                     case_block.wip_capture_scope = child_block.wip_capture_scope;
  11254 
  11255                     if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) {
  11256                         error.NeededSourceLocation => {
  11257                             const case_src = Module.SwitchProngSrc{ .range = .{ .prong = multi_i, .item = range_i } };
  11258                             const decl = mod.declPtr(case_block.src_decl);
  11259                             try sema.emitBackwardBranch(block, case_src.resolve(mod, decl, src_node_offset, .none));
  11260                             unreachable;
  11261                         },
  11262                         else => return err,
  11263                     };
  11264                     emit_bb = true;
  11265 
  11266                     try sema.analyzeBodyRuntimeBreak(&case_block, body);
  11267 
  11268                     try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
  11269                     cases_extra.appendAssumeCapacity(1); // items_len
  11270                     cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
  11271                     cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));
  11272                     cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
  11273                 }
  11274             }
  11275 
  11276             for (items, 0..) |item_ref, item_i| {
  11277                 cases_len += 1;
  11278 
  11279                 const item = try sema.resolveInst(item_ref);
  11280                 case_block.inline_case_capture = item;
  11281 
  11282                 case_block.instructions.shrinkRetainingCapacity(0);
  11283                 case_block.wip_capture_scope = child_block.wip_capture_scope;
  11284 
  11285                 const analyze_body = if (union_originally) blk: {
  11286                     const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable;
  11287                     const field_ty = maybe_union_ty.unionFieldType(item_val, mod);
  11288                     break :blk field_ty.zigTypeTag(mod) != .NoReturn;
  11289                 } else true;
  11290 
  11291                 if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) {
  11292                     error.NeededSourceLocation => {
  11293                         const case_src = Module.SwitchProngSrc{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } };
  11294                         const decl = mod.declPtr(case_block.src_decl);
  11295                         try sema.emitBackwardBranch(block, case_src.resolve(mod, decl, src_node_offset, .none));
  11296                         unreachable;
  11297                     },
  11298                     else => return err,
  11299                 };
  11300                 emit_bb = true;
  11301 
  11302                 if (analyze_body) {
  11303                     try sema.analyzeBodyRuntimeBreak(&case_block, body);
  11304                 } else {
  11305                     _ = try case_block.addNoOp(.unreach);
  11306                 }
  11307 
  11308                 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
  11309                 cases_extra.appendAssumeCapacity(1); // items_len
  11310                 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
  11311                 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));
  11312                 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
  11313             }
  11314 
  11315             extra_index += body_len;
  11316             continue;
  11317         }
  11318 
  11319         var any_ok: Air.Inst.Ref = .none;
  11320 
  11321         // If there are any ranges, we have to put all the items into the
  11322         // else prong. Otherwise, we can take advantage of multiple items
  11323         // mapping to the same body.
  11324         if (ranges_len == 0) {
  11325             cases_len += 1;
  11326 
  11327             const analyze_body = if (union_originally)
  11328                 for (items) |item_ref| {
  11329                     const item = try sema.resolveInst(item_ref);
  11330                     const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable;
  11331                     const field_ty = maybe_union_ty.unionFieldType(item_val, mod);
  11332                     if (field_ty.zigTypeTag(mod) != .NoReturn) break true;
  11333                 } else false
  11334             else
  11335                 true;
  11336 
  11337             const body = sema.code.extra[extra_index..][0..body_len];
  11338             extra_index += body_len;
  11339             if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
  11340                 // nothing to do here
  11341             } else if (analyze_body) {
  11342                 try sema.analyzeBodyRuntimeBreak(&case_block, body);
  11343             } else {
  11344                 _ = try case_block.addNoOp(.unreach);
  11345             }
  11346 
  11347             try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len +
  11348                 case_block.instructions.items.len);
  11349 
  11350             cases_extra.appendAssumeCapacity(@intCast(u32, items.len));
  11351             cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
  11352 
  11353             for (items) |item_ref| {
  11354                 const item = try sema.resolveInst(item_ref);
  11355                 cases_extra.appendAssumeCapacity(@enumToInt(item));
  11356             }
  11357 
  11358             cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
  11359         } else {
  11360             for (items) |item_ref| {
  11361                 const item = try sema.resolveInst(item_ref);
  11362                 const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item);
  11363                 if (any_ok != .none) {
  11364                     any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok);
  11365                 } else {
  11366                     any_ok = cmp_ok;
  11367                 }
  11368             }
  11369 
  11370             var range_i: usize = 0;
  11371             while (range_i < ranges_len) : (range_i += 1) {
  11372                 const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  11373                 extra_index += 1;
  11374                 const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  11375                 extra_index += 1;
  11376 
  11377                 const item_first = try sema.resolveInst(first_ref);
  11378                 const item_last = try sema.resolveInst(last_ref);
  11379 
  11380                 // operand >= first and operand <= last
  11381                 const range_first_ok = try case_block.addBinOp(
  11382                     if (case_block.float_mode == .Optimized) .cmp_gte_optimized else .cmp_gte,
  11383                     operand,
  11384                     item_first,
  11385                 );
  11386                 const range_last_ok = try case_block.addBinOp(
  11387                     if (case_block.float_mode == .Optimized) .cmp_lte_optimized else .cmp_lte,
  11388                     operand,
  11389                     item_last,
  11390                 );
  11391                 const range_ok = try case_block.addBinOp(
  11392                     .bool_and,
  11393                     range_first_ok,
  11394                     range_last_ok,
  11395                 );
  11396                 if (any_ok != .none) {
  11397                     any_ok = try case_block.addBinOp(.bool_or, any_ok, range_ok);
  11398                 } else {
  11399                     any_ok = range_ok;
  11400                 }
  11401             }
  11402 
  11403             const new_cond_br = try case_block.addInstAsIndex(.{ .tag = .cond_br, .data = .{
  11404                 .pl_op = .{
  11405                     .operand = any_ok,
  11406                     .payload = undefined,
  11407                 },
  11408             } });
  11409             var cond_body = try case_block.instructions.toOwnedSlice(gpa);
  11410             defer gpa.free(cond_body);
  11411 
  11412             var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope);
  11413             defer wip_captures.deinit();
  11414 
  11415             case_block.instructions.shrinkRetainingCapacity(0);
  11416             case_block.wip_capture_scope = wip_captures.scope;
  11417 
  11418             const body = sema.code.extra[extra_index..][0..body_len];
  11419             extra_index += body_len;
  11420             if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
  11421                 // nothing to do here
  11422             } else {
  11423                 try sema.analyzeBodyRuntimeBreak(&case_block, body);
  11424             }
  11425 
  11426             try wip_captures.finalize();
  11427 
  11428             if (is_first) {
  11429                 is_first = false;
  11430                 first_else_body = cond_body;
  11431                 cond_body = &.{};
  11432             } else {
  11433                 try sema.air_extra.ensureUnusedCapacity(
  11434                     gpa,
  11435                     @typeInfo(Air.CondBr).Struct.fields.len + prev_then_body.len + cond_body.len,
  11436                 );
  11437 
  11438                 sema.air_instructions.items(.data)[prev_cond_br].pl_op.payload =
  11439                     sema.addExtraAssumeCapacity(Air.CondBr{
  11440                     .then_body_len = @intCast(u32, prev_then_body.len),
  11441                     .else_body_len = @intCast(u32, cond_body.len),
  11442                 });
  11443                 sema.air_extra.appendSliceAssumeCapacity(prev_then_body);
  11444                 sema.air_extra.appendSliceAssumeCapacity(cond_body);
  11445             }
  11446             gpa.free(prev_then_body);
  11447             prev_then_body = try case_block.instructions.toOwnedSlice(gpa);
  11448             prev_cond_br = new_cond_br;
  11449         }
  11450     }
  11451 
  11452     var final_else_body: []const Air.Inst.Index = &.{};
  11453     if (special.body.len != 0 or !is_first or case_block.wantSafety()) {
  11454         var emit_bb = false;
  11455         if (special.is_inline) switch (operand_ty.zigTypeTag(mod)) {
  11456             .Enum => {
  11457                 if (operand_ty.isNonexhaustiveEnum(mod) and !union_originally) {
  11458                     return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{
  11459                         operand_ty.fmt(mod),
  11460                     });
  11461                 }
  11462                 for (seen_enum_fields, 0..) |f, i| {
  11463                     if (f != null) continue;
  11464                     cases_len += 1;
  11465 
  11466                     const item_val = try mod.enumValueFieldIndex(operand_ty, @intCast(u32, i));
  11467                     const item_ref = try sema.addConstant(operand_ty, item_val);
  11468                     case_block.inline_case_capture = item_ref;
  11469 
  11470                     case_block.instructions.shrinkRetainingCapacity(0);
  11471                     case_block.wip_capture_scope = child_block.wip_capture_scope;
  11472 
  11473                     const analyze_body = if (union_originally) blk: {
  11474                         const field_ty = maybe_union_ty.unionFieldType(item_val, mod);
  11475                         break :blk field_ty.zigTypeTag(mod) != .NoReturn;
  11476                     } else true;
  11477 
  11478                     if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
  11479                     emit_bb = true;
  11480 
  11481                     if (analyze_body) {
  11482                         try sema.analyzeBodyRuntimeBreak(&case_block, special.body);
  11483                     } else {
  11484                         _ = try case_block.addNoOp(.unreach);
  11485                     }
  11486 
  11487                     try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
  11488                     cases_extra.appendAssumeCapacity(1); // items_len
  11489                     cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
  11490                     cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));
  11491                     cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
  11492                 }
  11493             },
  11494             .ErrorSet => {
  11495                 if (operand_ty.isAnyError(mod)) {
  11496                     return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{
  11497                         operand_ty.fmt(mod),
  11498                     });
  11499                 }
  11500                 for (operand_ty.errorSetNames(mod)) |error_name_ip| {
  11501                     const error_name = mod.intern_pool.stringToSlice(error_name_ip);
  11502                     if (seen_errors.contains(error_name)) continue;
  11503                     cases_len += 1;
  11504 
  11505                     const item_val = try mod.intern(.{ .err = .{
  11506                         .ty = operand_ty.toIntern(),
  11507                         .name = error_name_ip,
  11508                     } });
  11509                     const item_ref = try sema.addConstant(operand_ty, item_val.toValue());
  11510                     case_block.inline_case_capture = item_ref;
  11511 
  11512                     case_block.instructions.shrinkRetainingCapacity(0);
  11513                     case_block.wip_capture_scope = child_block.wip_capture_scope;
  11514 
  11515                     if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
  11516                     emit_bb = true;
  11517 
  11518                     try sema.analyzeBodyRuntimeBreak(&case_block, special.body);
  11519 
  11520                     try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
  11521                     cases_extra.appendAssumeCapacity(1); // items_len
  11522                     cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
  11523                     cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));
  11524                     cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
  11525                 }
  11526             },
  11527             .Int => {
  11528                 var it = try RangeSetUnhandledIterator.init(sema, operand_ty, range_set);
  11529                 while (try it.next()) |cur| {
  11530                     cases_len += 1;
  11531 
  11532                     const item_ref = try sema.addConstant(operand_ty, cur.toValue());
  11533                     case_block.inline_case_capture = item_ref;
  11534 
  11535                     case_block.instructions.shrinkRetainingCapacity(0);
  11536                     case_block.wip_capture_scope = child_block.wip_capture_scope;
  11537 
  11538                     if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
  11539                     emit_bb = true;
  11540 
  11541                     try sema.analyzeBodyRuntimeBreak(&case_block, special.body);
  11542 
  11543                     try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
  11544                     cases_extra.appendAssumeCapacity(1); // items_len
  11545                     cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
  11546                     cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));
  11547                     cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
  11548                 }
  11549             },
  11550             .Bool => {
  11551                 if (true_count == 0) {
  11552                     cases_len += 1;
  11553                     case_block.inline_case_capture = Air.Inst.Ref.bool_true;
  11554 
  11555                     case_block.instructions.shrinkRetainingCapacity(0);
  11556                     case_block.wip_capture_scope = child_block.wip_capture_scope;
  11557 
  11558                     if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
  11559                     emit_bb = true;
  11560 
  11561                     try sema.analyzeBodyRuntimeBreak(&case_block, special.body);
  11562 
  11563                     try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
  11564                     cases_extra.appendAssumeCapacity(1); // items_len
  11565                     cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
  11566                     cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));
  11567                     cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
  11568                 }
  11569                 if (false_count == 0) {
  11570                     cases_len += 1;
  11571                     case_block.inline_case_capture = Air.Inst.Ref.bool_false;
  11572 
  11573                     case_block.instructions.shrinkRetainingCapacity(0);
  11574                     case_block.wip_capture_scope = child_block.wip_capture_scope;
  11575 
  11576                     if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
  11577                     emit_bb = true;
  11578 
  11579                     try sema.analyzeBodyRuntimeBreak(&case_block, special.body);
  11580 
  11581                     try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
  11582                     cases_extra.appendAssumeCapacity(1); // items_len
  11583                     cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
  11584                     cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));
  11585                     cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
  11586                 }
  11587             },
  11588             else => return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{
  11589                 operand_ty.fmt(mod),
  11590             }),
  11591         };
  11592 
  11593         var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope);
  11594         defer wip_captures.deinit();
  11595 
  11596         case_block.instructions.shrinkRetainingCapacity(0);
  11597         case_block.wip_capture_scope = wip_captures.scope;
  11598         case_block.inline_case_capture = .none;
  11599 
  11600         if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and
  11601             operand_ty.zigTypeTag(mod) == .Enum and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally))
  11602         {
  11603             try sema.zirDbgStmt(&case_block, cond_dbg_node_index);
  11604             const ok = try case_block.addUnOp(.is_named_enum_value, operand);
  11605             try sema.addSafetyCheck(&case_block, ok, .corrupt_switch);
  11606         }
  11607 
  11608         const analyze_body = if (union_originally and !special.is_inline)
  11609             for (seen_enum_fields, 0..) |seen_field, index| {
  11610                 if (seen_field != null) continue;
  11611                 const union_obj = mod.typeToUnion(maybe_union_ty).?;
  11612                 const field_ty = union_obj.fields.values()[index].ty;
  11613                 if (field_ty.zigTypeTag(mod) != .NoReturn) break true;
  11614             } else false
  11615         else
  11616             true;
  11617         if (special.body.len != 0 and err_set and
  11618             try sema.maybeErrorUnwrap(&case_block, special.body, operand))
  11619         {
  11620             // nothing to do here
  11621         } else if (special.body.len != 0 and analyze_body and !special.is_inline) {
  11622             try sema.analyzeBodyRuntimeBreak(&case_block, special.body);
  11623         } else {
  11624             // We still need a terminator in this block, but we have proven
  11625             // that it is unreachable.
  11626             if (case_block.wantSafety()) {
  11627                 try sema.zirDbgStmt(&case_block, cond_dbg_node_index);
  11628                 try sema.safetyPanic(&case_block, .corrupt_switch);
  11629             } else {
  11630                 _ = try case_block.addNoOp(.unreach);
  11631             }
  11632         }
  11633 
  11634         try wip_captures.finalize();
  11635 
  11636         if (is_first) {
  11637             final_else_body = case_block.instructions.items;
  11638         } else {
  11639             try sema.air_extra.ensureUnusedCapacity(gpa, prev_then_body.len +
  11640                 @typeInfo(Air.CondBr).Struct.fields.len + case_block.instructions.items.len);
  11641 
  11642             sema.air_instructions.items(.data)[prev_cond_br].pl_op.payload =
  11643                 sema.addExtraAssumeCapacity(Air.CondBr{
  11644                 .then_body_len = @intCast(u32, prev_then_body.len),
  11645                 .else_body_len = @intCast(u32, case_block.instructions.items.len),
  11646             });
  11647             sema.air_extra.appendSliceAssumeCapacity(prev_then_body);
  11648             sema.air_extra.appendSliceAssumeCapacity(case_block.instructions.items);
  11649             final_else_body = first_else_body;
  11650         }
  11651     }
  11652 
  11653     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr).Struct.fields.len +
  11654         cases_extra.items.len + final_else_body.len);
  11655 
  11656     _ = try child_block.addInst(.{ .tag = .switch_br, .data = .{ .pl_op = .{
  11657         .operand = operand,
  11658         .payload = sema.addExtraAssumeCapacity(Air.SwitchBr{
  11659             .cases_len = @intCast(u32, cases_len),
  11660             .else_body_len = @intCast(u32, final_else_body.len),
  11661         }),
  11662     } } });
  11663     sema.air_extra.appendSliceAssumeCapacity(cases_extra.items);
  11664     sema.air_extra.appendSliceAssumeCapacity(final_else_body);
  11665 
  11666     return sema.analyzeBlockBody(block, src, &child_block, merges);
  11667 }
  11668 
  11669 const RangeSetUnhandledIterator = struct {
  11670     mod: *Module,
  11671     cur: ?InternPool.Index,
  11672     max: InternPool.Index,
  11673     range_i: usize,
  11674     ranges: []const RangeSet.Range,
  11675     limbs: []math.big.Limb,
  11676 
  11677     const preallocated_limbs = math.big.int.calcTwosCompLimbCount(128);
  11678 
  11679     fn init(sema: *Sema, ty: Type, range_set: RangeSet) !RangeSetUnhandledIterator {
  11680         const mod = sema.mod;
  11681         const int_type = mod.intern_pool.indexToKey(ty.toIntern()).int_type;
  11682         const needed_limbs = math.big.int.calcTwosCompLimbCount(int_type.bits);
  11683         return .{
  11684             .mod = mod,
  11685             .cur = (try ty.minInt(mod, ty)).toIntern(),
  11686             .max = (try ty.maxInt(mod, ty)).toIntern(),
  11687             .range_i = 0,
  11688             .ranges = range_set.ranges.items,
  11689             .limbs = if (needed_limbs > preallocated_limbs)
  11690                 try sema.arena.alloc(math.big.Limb, needed_limbs)
  11691             else
  11692                 &.{},
  11693         };
  11694     }
  11695 
  11696     fn addOne(it: *const RangeSetUnhandledIterator, val: InternPool.Index) !?InternPool.Index {
  11697         if (val == it.max) return null;
  11698         const int = it.mod.intern_pool.indexToKey(val).int;
  11699 
  11700         switch (int.storage) {
  11701             inline .u64, .i64 => |val_int| {
  11702                 const next_int = @addWithOverflow(val_int, 1);
  11703                 if (next_int[1] == 0)
  11704                     return (try it.mod.intValue(int.ty.toType(), next_int[0])).toIntern();
  11705             },
  11706             .big_int => {},
  11707             .lazy_align, .lazy_size => unreachable,
  11708         }
  11709 
  11710         var val_space: InternPool.Key.Int.Storage.BigIntSpace = undefined;
  11711         const val_bigint = int.storage.toBigInt(&val_space);
  11712 
  11713         var result_limbs: [preallocated_limbs]math.big.Limb = undefined;
  11714         var result_bigint = math.big.int.Mutable.init(
  11715             if (it.limbs.len > 0) it.limbs else &result_limbs,
  11716             0,
  11717         );
  11718 
  11719         result_bigint.addScalar(val_bigint, 1);
  11720         return (try it.mod.intValue_big(int.ty.toType(), result_bigint.toConst())).toIntern();
  11721     }
  11722 
  11723     fn next(it: *RangeSetUnhandledIterator) !?InternPool.Index {
  11724         var cur = it.cur orelse return null;
  11725         while (it.range_i < it.ranges.len and cur == it.ranges[it.range_i].first) {
  11726             defer it.range_i += 1;
  11727             cur = (try it.addOne(it.ranges[it.range_i].last)) orelse {
  11728                 it.cur = null;
  11729                 return null;
  11730             };
  11731         }
  11732         it.cur = try it.addOne(cur);
  11733         return cur;
  11734     }
  11735 };
  11736 
  11737 fn resolveSwitchItemVal(
  11738     sema: *Sema,
  11739     block: *Block,
  11740     item_ref: Zir.Inst.Ref,
  11741     switch_node_offset: i32,
  11742     switch_prong_src: Module.SwitchProngSrc,
  11743     range_expand: Module.SwitchProngSrc.RangeExpand,
  11744 ) CompileError!InternPool.Index {
  11745     const mod = sema.mod;
  11746     const item = try sema.resolveInst(item_ref);
  11747     // Constructing a LazySrcLoc is costly because we only have the switch AST node.
  11748     // Only if we know for sure we need to report a compile error do we resolve the
  11749     // full source locations.
  11750     if (sema.resolveConstLazyValue(block, .unneeded, item, "")) |val| {
  11751         return val.toIntern();
  11752     } else |err| switch (err) {
  11753         error.NeededSourceLocation => {
  11754             const src = switch_prong_src.resolve(mod, sema.mod.declPtr(block.src_decl), switch_node_offset, range_expand);
  11755             _ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known");
  11756             unreachable;
  11757         },
  11758         else => |e| return e,
  11759     }
  11760 }
  11761 
  11762 fn validateSwitchRange(
  11763     sema: *Sema,
  11764     block: *Block,
  11765     range_set: *RangeSet,
  11766     first_ref: Zir.Inst.Ref,
  11767     last_ref: Zir.Inst.Ref,
  11768     src_node_offset: i32,
  11769     switch_prong_src: Module.SwitchProngSrc,
  11770 ) CompileError!void {
  11771     const mod = sema.mod;
  11772     const first = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first);
  11773     const last = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last);
  11774     if (first.toValue().compareScalar(.gt, last.toValue(), mod.intern_pool.typeOf(first).toType(), mod)) {
  11775         const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), src_node_offset, .first);
  11776         return sema.fail(block, src, "range start value is greater than the end value", .{});
  11777     }
  11778     const maybe_prev_src = try range_set.add(first, last, switch_prong_src);
  11779     return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
  11780 }
  11781 
  11782 fn validateSwitchItem(
  11783     sema: *Sema,
  11784     block: *Block,
  11785     range_set: *RangeSet,
  11786     item_ref: Zir.Inst.Ref,
  11787     src_node_offset: i32,
  11788     switch_prong_src: Module.SwitchProngSrc,
  11789 ) CompileError!void {
  11790     const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
  11791     const maybe_prev_src = try range_set.add(item, item, switch_prong_src);
  11792     return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
  11793 }
  11794 
  11795 fn validateSwitchItemEnum(
  11796     sema: *Sema,
  11797     block: *Block,
  11798     seen_fields: []?Module.SwitchProngSrc,
  11799     range_set: *RangeSet,
  11800     item_ref: Zir.Inst.Ref,
  11801     src_node_offset: i32,
  11802     switch_prong_src: Module.SwitchProngSrc,
  11803 ) CompileError!void {
  11804     const ip = &sema.mod.intern_pool;
  11805     const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
  11806     const int = ip.indexToKey(item).enum_tag.int;
  11807     const field_index = ip.indexToKey(ip.typeOf(item)).enum_type.tagValueIndex(ip, int) orelse {
  11808         const maybe_prev_src = try range_set.add(int, int, switch_prong_src);
  11809         return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
  11810     };
  11811     const maybe_prev_src = seen_fields[field_index];
  11812     seen_fields[field_index] = switch_prong_src;
  11813     return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
  11814 }
  11815 
  11816 fn validateSwitchItemError(
  11817     sema: *Sema,
  11818     block: *Block,
  11819     seen_errors: *SwitchErrorSet,
  11820     item_ref: Zir.Inst.Ref,
  11821     src_node_offset: i32,
  11822     switch_prong_src: Module.SwitchProngSrc,
  11823 ) CompileError!void {
  11824     const ip = &sema.mod.intern_pool;
  11825     const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
  11826     // TODO: Do i need to typecheck here?
  11827     const error_name = ip.stringToSlice(ip.indexToKey(item).err.name);
  11828     const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev|
  11829         prev.value
  11830     else
  11831         null;
  11832     return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
  11833 }
  11834 
  11835 fn validateSwitchDupe(
  11836     sema: *Sema,
  11837     block: *Block,
  11838     maybe_prev_src: ?Module.SwitchProngSrc,
  11839     switch_prong_src: Module.SwitchProngSrc,
  11840     src_node_offset: i32,
  11841 ) CompileError!void {
  11842     const prev_prong_src = maybe_prev_src orelse return;
  11843     const mod = sema.mod;
  11844     const block_src_decl = sema.mod.declPtr(block.src_decl);
  11845     const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none);
  11846     const prev_src = prev_prong_src.resolve(mod, block_src_decl, src_node_offset, .none);
  11847     const msg = msg: {
  11848         const msg = try sema.errMsg(
  11849             block,
  11850             src,
  11851             "duplicate switch value",
  11852             .{},
  11853         );
  11854         errdefer msg.destroy(sema.gpa);
  11855         try sema.errNote(
  11856             block,
  11857             prev_src,
  11858             msg,
  11859             "previous value here",
  11860             .{},
  11861         );
  11862         break :msg msg;
  11863     };
  11864     return sema.failWithOwnedErrorMsg(msg);
  11865 }
  11866 
  11867 fn validateSwitchItemBool(
  11868     sema: *Sema,
  11869     block: *Block,
  11870     true_count: *u8,
  11871     false_count: *u8,
  11872     item_ref: Zir.Inst.Ref,
  11873     src_node_offset: i32,
  11874     switch_prong_src: Module.SwitchProngSrc,
  11875 ) CompileError!void {
  11876     const mod = sema.mod;
  11877     const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
  11878     if (item.toValue().toBool()) {
  11879         true_count.* += 1;
  11880     } else {
  11881         false_count.* += 1;
  11882     }
  11883     if (true_count.* + false_count.* > 2) {
  11884         const block_src_decl = sema.mod.declPtr(block.src_decl);
  11885         const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none);
  11886         return sema.fail(block, src, "duplicate switch value", .{});
  11887     }
  11888 }
  11889 
  11890 const ValueSrcMap = std.AutoHashMapUnmanaged(InternPool.Index, Module.SwitchProngSrc);
  11891 
  11892 fn validateSwitchItemSparse(
  11893     sema: *Sema,
  11894     block: *Block,
  11895     seen_values: *ValueSrcMap,
  11896     item_ref: Zir.Inst.Ref,
  11897     src_node_offset: i32,
  11898     switch_prong_src: Module.SwitchProngSrc,
  11899 ) CompileError!void {
  11900     const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
  11901     const kv = (try seen_values.fetchPut(sema.gpa, item, switch_prong_src)) orelse return;
  11902     return sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset);
  11903 }
  11904 
  11905 fn validateSwitchNoRange(
  11906     sema: *Sema,
  11907     block: *Block,
  11908     ranges_len: u32,
  11909     operand_ty: Type,
  11910     src_node_offset: i32,
  11911 ) CompileError!void {
  11912     if (ranges_len == 0)
  11913         return;
  11914 
  11915     const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };
  11916     const range_src: LazySrcLoc = .{ .node_offset_switch_range = src_node_offset };
  11917 
  11918     const msg = msg: {
  11919         const msg = try sema.errMsg(
  11920             block,
  11921             operand_src,
  11922             "ranges not allowed when switching on type '{}'",
  11923             .{operand_ty.fmt(sema.mod)},
  11924         );
  11925         errdefer msg.destroy(sema.gpa);
  11926         try sema.errNote(
  11927             block,
  11928             range_src,
  11929             msg,
  11930             "range here",
  11931             .{},
  11932         );
  11933         break :msg msg;
  11934     };
  11935     return sema.failWithOwnedErrorMsg(msg);
  11936 }
  11937 
  11938 fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !bool {
  11939     const mod = sema.mod;
  11940     if (!mod.backendSupportsFeature(.panic_unwrap_error)) return false;
  11941 
  11942     const tags = sema.code.instructions.items(.tag);
  11943     for (body) |inst| {
  11944         switch (tags[inst]) {
  11945             .save_err_ret_index,
  11946             .dbg_block_begin,
  11947             .dbg_block_end,
  11948             .dbg_stmt,
  11949             .@"unreachable",
  11950             .str,
  11951             .as_node,
  11952             .panic,
  11953             .field_val,
  11954             => {},
  11955             else => return false,
  11956         }
  11957     }
  11958 
  11959     for (body) |inst| {
  11960         const air_inst = switch (tags[inst]) {
  11961             .dbg_block_begin,
  11962             .dbg_block_end,
  11963             => continue,
  11964             .dbg_stmt => {
  11965                 try sema.zirDbgStmt(block, inst);
  11966                 continue;
  11967             },
  11968             .save_err_ret_index => {
  11969                 try sema.zirSaveErrRetIndex(block, inst);
  11970                 continue;
  11971             },
  11972             .str => try sema.zirStr(block, inst),
  11973             .as_node => try sema.zirAsNode(block, inst),
  11974             .field_val => try sema.zirFieldVal(block, inst),
  11975             .@"unreachable" => {
  11976                 if (!mod.comp.formatted_panics) {
  11977                     try sema.safetyPanic(block, .unwrap_error);
  11978                     return true;
  11979                 }
  11980 
  11981                 const panic_fn = try sema.getBuiltin("panicUnwrapError");
  11982                 const err_return_trace = try sema.getErrorReturnTrace(block);
  11983                 const args: [2]Air.Inst.Ref = .{ err_return_trace, operand };
  11984                 try sema.callBuiltin(block, panic_fn, .auto, &args);
  11985                 return true;
  11986             },
  11987             .panic => {
  11988                 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  11989                 const msg_inst = try sema.resolveInst(inst_data.operand);
  11990 
  11991                 const panic_fn = try sema.getBuiltin("panic");
  11992                 const err_return_trace = try sema.getErrorReturnTrace(block);
  11993                 const args: [3]Air.Inst.Ref = .{ msg_inst, err_return_trace, .null_value };
  11994                 try sema.callBuiltin(block, panic_fn, .auto, &args);
  11995                 return true;
  11996             },
  11997             else => unreachable,
  11998         };
  11999         if (sema.typeOf(air_inst).isNoReturn(mod))
  12000             return true;
  12001         sema.inst_map.putAssumeCapacity(inst, air_inst);
  12002     }
  12003     unreachable;
  12004 }
  12005 
  12006 fn maybeErrorUnwrapCondbr(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, cond: Zir.Inst.Ref, cond_src: LazySrcLoc) !void {
  12007     const mod = sema.mod;
  12008     const index = Zir.refToIndex(cond) orelse return;
  12009     if (sema.code.instructions.items(.tag)[index] != .is_non_err) return;
  12010 
  12011     const err_inst_data = sema.code.instructions.items(.data)[index].un_node;
  12012     const err_operand = try sema.resolveInst(err_inst_data.operand);
  12013     const operand_ty = sema.typeOf(err_operand);
  12014     if (operand_ty.zigTypeTag(mod) == .ErrorSet) {
  12015         try sema.maybeErrorUnwrapComptime(block, body, err_operand);
  12016         return;
  12017     }
  12018     if (try sema.resolveDefinedValue(block, cond_src, err_operand)) |val| {
  12019         if (!operand_ty.isError(mod)) return;
  12020         if (val.getError(mod) == null) return;
  12021         try sema.maybeErrorUnwrapComptime(block, body, err_operand);
  12022     }
  12023 }
  12024 
  12025 fn maybeErrorUnwrapComptime(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !void {
  12026     const tags = sema.code.instructions.items(.tag);
  12027     const inst = for (body) |inst| {
  12028         switch (tags[inst]) {
  12029             .dbg_block_begin,
  12030             .dbg_block_end,
  12031             .dbg_stmt,
  12032             .save_err_ret_index,
  12033             => {},
  12034             .@"unreachable" => break inst,
  12035             else => return,
  12036         }
  12037     } else return;
  12038     const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable";
  12039     const src = inst_data.src();
  12040 
  12041     if (try sema.resolveDefinedValue(block, src, operand)) |val| {
  12042         if (val.getError(sema.mod)) |name| {
  12043             return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
  12044         }
  12045     }
  12046 }
  12047 
  12048 fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  12049     const mod = sema.mod;
  12050     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  12051     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  12052     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  12053     const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  12054     const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs);
  12055     const field_name = try sema.resolveConstString(block, name_src, extra.rhs, "field name must be comptime-known");
  12056     const ty = try sema.resolveTypeFields(unresolved_ty);
  12057     const ip = &mod.intern_pool;
  12058 
  12059     const has_field = hf: {
  12060         switch (ip.indexToKey(ty.toIntern())) {
  12061             .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
  12062                 .Slice => {
  12063                     if (mem.eql(u8, field_name, "ptr")) break :hf true;
  12064                     if (mem.eql(u8, field_name, "len")) break :hf true;
  12065                     break :hf false;
  12066                 },
  12067                 else => {},
  12068             },
  12069             .anon_struct_type => |anon_struct| {
  12070                 if (anon_struct.names.len != 0) {
  12071                     // If the string is not interned, then the field certainly is not present.
  12072                     const name_interned = ip.getString(field_name).unwrap() orelse break :hf false;
  12073                     break :hf mem.indexOfScalar(InternPool.NullTerminatedString, anon_struct.names, name_interned) != null;
  12074                 } else {
  12075                     const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch break :hf false;
  12076                     break :hf field_index < ty.structFieldCount(mod);
  12077                 }
  12078             },
  12079             .struct_type => |struct_type| {
  12080                 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :hf false;
  12081                 assert(struct_obj.haveFieldTypes());
  12082                 break :hf struct_obj.fields.contains(field_name);
  12083             },
  12084             .union_type => |union_type| {
  12085                 const union_obj = mod.unionPtr(union_type.index);
  12086                 assert(union_obj.haveFieldTypes());
  12087                 break :hf union_obj.fields.contains(field_name);
  12088             },
  12089             .enum_type => |enum_type| {
  12090                 // If the string is not interned, then the field certainly is not present.
  12091                 const name_interned = ip.getString(field_name).unwrap() orelse break :hf false;
  12092                 break :hf enum_type.nameIndex(ip, name_interned) != null;
  12093             },
  12094             .array_type => break :hf mem.eql(u8, field_name, "len"),
  12095             else => {},
  12096         }
  12097         return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{
  12098             ty.fmt(sema.mod),
  12099         });
  12100     };
  12101     if (has_field) {
  12102         return Air.Inst.Ref.bool_true;
  12103     } else {
  12104         return Air.Inst.Ref.bool_false;
  12105     }
  12106 }
  12107 
  12108 fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  12109     const mod = sema.mod;
  12110     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  12111     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  12112     const src = inst_data.src();
  12113     const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  12114     const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  12115     const container_type = try sema.resolveType(block, lhs_src, extra.lhs);
  12116     const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "decl name must be comptime-known");
  12117 
  12118     try sema.checkNamespaceType(block, lhs_src, container_type);
  12119 
  12120     const namespace = container_type.getNamespaceIndex(mod).unwrap() orelse
  12121         return Air.Inst.Ref.bool_false;
  12122     if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| {
  12123         const decl = mod.declPtr(decl_index);
  12124         if (decl.is_pub or decl.getFileScope(mod) == block.getFileScope(mod)) {
  12125             return Air.Inst.Ref.bool_true;
  12126         }
  12127     }
  12128     return Air.Inst.Ref.bool_false;
  12129 }
  12130 
  12131 fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  12132     const tracy = trace(@src());
  12133     defer tracy.end();
  12134 
  12135     const mod = sema.mod;
  12136     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
  12137     const operand_src = inst_data.src();
  12138     const operand = inst_data.get(sema.code);
  12139 
  12140     const result = mod.importFile(block.getFileScope(mod), operand) catch |err| switch (err) {
  12141         error.ImportOutsidePkgPath => {
  12142             return sema.fail(block, operand_src, "import of file outside package path: '{s}'", .{operand});
  12143         },
  12144         error.PackageNotFound => {
  12145             const name = try block.getFileScope(mod).pkg.getName(sema.gpa, mod.*);
  12146             defer sema.gpa.free(name);
  12147             return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, name });
  12148         },
  12149         else => {
  12150             // TODO: these errors are file system errors; make sure an update() will
  12151             // retry this and not cache the file system error, which may be transient.
  12152             return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
  12153         },
  12154     };
  12155     try mod.semaFile(result.file);
  12156     const file_root_decl_index = result.file.root_decl.unwrap().?;
  12157     const file_root_decl = mod.declPtr(file_root_decl_index);
  12158     try mod.declareDeclDependency(sema.owner_decl_index, file_root_decl_index);
  12159     return sema.addConstant(file_root_decl.ty, file_root_decl.val);
  12160 }
  12161 
  12162 fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  12163     const tracy = trace(@src());
  12164     defer tracy.end();
  12165 
  12166     const mod = sema.mod;
  12167     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  12168     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  12169     const name = try sema.resolveConstString(block, operand_src, inst_data.operand, "file path name must be comptime-known");
  12170 
  12171     const embed_file = mod.embedFile(block.getFileScope(mod), name) catch |err| switch (err) {
  12172         error.ImportOutsidePkgPath => {
  12173             return sema.fail(block, operand_src, "embed of file outside package path: '{s}'", .{name});
  12174         },
  12175         else => {
  12176             // TODO: these errors are file system errors; make sure an update() will
  12177             // retry this and not cache the file system error, which may be transient.
  12178             return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ name, @errorName(err) });
  12179         },
  12180     };
  12181 
  12182     var anon_decl = try block.startAnonDecl();
  12183     defer anon_decl.deinit();
  12184 
  12185     // TODO instead of using `.bytes`, create a new value tag for pointing at
  12186     // a `*Module.EmbedFile`. The purpose of this would be:
  12187     // - If only the length is read and the bytes are not inspected by comptime code,
  12188     //   there can be an optimization where the codegen backend does a copy_file_range
  12189     //   into the final binary, and never loads the data into memory.
  12190     // - When a Decl is destroyed, it can free the `*Module.EmbedFile`.
  12191     const ty = try mod.arrayType(.{
  12192         .len = embed_file.bytes.len,
  12193         .child = .u8_type,
  12194         .sentinel = .zero_u8,
  12195     });
  12196     embed_file.owner_decl = try anon_decl.finish(
  12197         ty,
  12198         (try mod.intern(.{ .aggregate = .{
  12199             .ty = ty.toIntern(),
  12200             .storage = .{ .bytes = embed_file.bytes },
  12201         } })).toValue(),
  12202         0, // default alignment
  12203     );
  12204 
  12205     return sema.analyzeDeclRef(embed_file.owner_decl);
  12206 }
  12207 
  12208 fn zirRetErrValueCode(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  12209     const mod = sema.mod;
  12210     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
  12211     const err_name = inst_data.get(sema.code);
  12212 
  12213     // Return the error code from the function.
  12214     const kv = try mod.getErrorValue(err_name);
  12215     const error_set_type = try mod.singleErrorSetType(kv.key);
  12216     return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{
  12217         .ty = error_set_type.toIntern(),
  12218         .name = mod.intern_pool.getString(kv.key).unwrap().?,
  12219     } })).toValue());
  12220 }
  12221 
  12222 fn zirShl(
  12223     sema: *Sema,
  12224     block: *Block,
  12225     inst: Zir.Inst.Index,
  12226     air_tag: Air.Inst.Tag,
  12227 ) CompileError!Air.Inst.Ref {
  12228     const tracy = trace(@src());
  12229     defer tracy.end();
  12230 
  12231     const mod = sema.mod;
  12232     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  12233     const src = inst_data.src();
  12234     sema.src = src;
  12235     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  12236     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  12237     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  12238     const lhs = try sema.resolveInst(extra.lhs);
  12239     const rhs = try sema.resolveInst(extra.rhs);
  12240     const lhs_ty = sema.typeOf(lhs);
  12241     const rhs_ty = sema.typeOf(rhs);
  12242     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  12243 
  12244     const scalar_ty = lhs_ty.scalarType(mod);
  12245     const scalar_rhs_ty = rhs_ty.scalarType(mod);
  12246 
  12247     // TODO coerce rhs if air_tag is not shl_sat
  12248     const rhs_is_comptime_int = try sema.checkIntType(block, rhs_src, scalar_rhs_ty);
  12249 
  12250     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(lhs);
  12251     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(rhs);
  12252 
  12253     if (maybe_rhs_val) |rhs_val| {
  12254         if (rhs_val.isUndef(mod)) {
  12255             return sema.addConstUndef(sema.typeOf(lhs));
  12256         }
  12257         // If rhs is 0, return lhs without doing any calculations.
  12258         if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  12259             return lhs;
  12260         }
  12261         if (scalar_ty.zigTypeTag(mod) != .ComptimeInt and air_tag != .shl_sat) {
  12262             const bit_value = try mod.intValue(Type.comptime_int, scalar_ty.intInfo(mod).bits);
  12263             if (rhs_ty.zigTypeTag(mod) == .Vector) {
  12264                 var i: usize = 0;
  12265                 while (i < rhs_ty.vectorLen(mod)) : (i += 1) {
  12266                     const rhs_elem = try rhs_val.elemValue(sema.mod, i);
  12267                     if (rhs_elem.compareHetero(.gte, bit_value, mod)) {
  12268                         return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{
  12269                             rhs_elem.fmtValue(scalar_ty, sema.mod),
  12270                             i,
  12271                             scalar_ty.fmt(sema.mod),
  12272                         });
  12273                     }
  12274                 }
  12275             } else if (rhs_val.compareHetero(.gte, bit_value, mod)) {
  12276                 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{
  12277                     rhs_val.fmtValue(scalar_ty, sema.mod),
  12278                     scalar_ty.fmt(sema.mod),
  12279                 });
  12280             }
  12281         }
  12282         if (rhs_ty.zigTypeTag(mod) == .Vector) {
  12283             var i: usize = 0;
  12284             while (i < rhs_ty.vectorLen(mod)) : (i += 1) {
  12285                 const rhs_elem = try rhs_val.elemValue(sema.mod, i);
  12286                 if (rhs_elem.compareHetero(.lt, try mod.intValue(scalar_rhs_ty, 0), mod)) {
  12287                     return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{
  12288                         rhs_elem.fmtValue(scalar_ty, sema.mod),
  12289                         i,
  12290                     });
  12291                 }
  12292             }
  12293         } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) {
  12294             return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{
  12295                 rhs_val.fmtValue(scalar_ty, sema.mod),
  12296             });
  12297         }
  12298     }
  12299 
  12300     const runtime_src = if (maybe_lhs_val) |lhs_val| rs: {
  12301         if (lhs_val.isUndef(mod)) return sema.addConstUndef(lhs_ty);
  12302         const rhs_val = maybe_rhs_val orelse {
  12303             if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
  12304                 return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be comptime-known", .{});
  12305             }
  12306             break :rs rhs_src;
  12307         };
  12308 
  12309         const val = switch (air_tag) {
  12310             .shl_exact => val: {
  12311                 const shifted = try lhs_val.shlWithOverflow(rhs_val, lhs_ty, sema.arena, sema.mod);
  12312                 if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
  12313                     break :val shifted.wrapped_result;
  12314                 }
  12315                 if (shifted.overflow_bit.compareAllWithZero(.eq, sema.mod)) {
  12316                     break :val shifted.wrapped_result;
  12317                 }
  12318                 return sema.fail(block, src, "operation caused overflow", .{});
  12319             },
  12320 
  12321             .shl_sat => if (scalar_ty.zigTypeTag(mod) == .ComptimeInt)
  12322                 try lhs_val.shl(rhs_val, lhs_ty, sema.arena, sema.mod)
  12323             else
  12324                 try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, sema.mod),
  12325 
  12326             .shl => if (scalar_ty.zigTypeTag(mod) == .ComptimeInt)
  12327                 try lhs_val.shl(rhs_val, lhs_ty, sema.arena, sema.mod)
  12328             else
  12329                 try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, sema.mod),
  12330 
  12331             else => unreachable,
  12332         };
  12333 
  12334         return sema.addConstant(lhs_ty, val);
  12335     } else lhs_src;
  12336 
  12337     const new_rhs = if (air_tag == .shl_sat) rhs: {
  12338         // Limit the RHS type for saturating shl to be an integer as small as the LHS.
  12339         if (rhs_is_comptime_int or
  12340             scalar_rhs_ty.intInfo(mod).bits > scalar_ty.intInfo(mod).bits)
  12341         {
  12342             const max_int = try sema.addConstant(
  12343                 lhs_ty,
  12344                 try lhs_ty.maxInt(mod, lhs_ty),
  12345             );
  12346             const rhs_limited = try sema.analyzeMinMax(block, rhs_src, .min, &.{ rhs, max_int }, &.{ rhs_src, rhs_src });
  12347             break :rhs try sema.intCast(block, src, lhs_ty, rhs_src, rhs_limited, rhs_src, false);
  12348         } else {
  12349             break :rhs rhs;
  12350         }
  12351     } else rhs;
  12352 
  12353     try sema.requireRuntimeBlock(block, src, runtime_src);
  12354     if (block.wantSafety()) {
  12355         const bit_count = scalar_ty.intInfo(mod).bits;
  12356         if (!std.math.isPowerOfTwo(bit_count)) {
  12357             const bit_count_val = try mod.intValue(scalar_rhs_ty, bit_count);
  12358             const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: {
  12359                 const bit_count_inst = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, bit_count_val));
  12360                 const lt = try block.addCmpVector(rhs, bit_count_inst, .lt);
  12361                 break :ok try block.addInst(.{
  12362                     .tag = .reduce,
  12363                     .data = .{ .reduce = .{
  12364                         .operand = lt,
  12365                         .operation = .And,
  12366                     } },
  12367                 });
  12368             } else ok: {
  12369                 const bit_count_inst = try sema.addConstant(rhs_ty, bit_count_val);
  12370                 break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst);
  12371             };
  12372             try sema.addSafetyCheck(block, ok, .shift_rhs_too_big);
  12373         }
  12374 
  12375         if (air_tag == .shl_exact) {
  12376             const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty);
  12377             const op_ov = try block.addInst(.{
  12378                 .tag = .shl_with_overflow,
  12379                 .data = .{ .ty_pl = .{
  12380                     .ty = try sema.addType(op_ov_tuple_ty),
  12381                     .payload = try sema.addExtra(Air.Bin{
  12382                         .lhs = lhs,
  12383                         .rhs = rhs,
  12384                     }),
  12385                 } },
  12386             });
  12387             const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
  12388             const any_ov_bit = if (lhs_ty.zigTypeTag(mod) == .Vector)
  12389                 try block.addInst(.{
  12390                     .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
  12391                     .data = .{ .reduce = .{
  12392                         .operand = ov_bit,
  12393                         .operation = .Or,
  12394                     } },
  12395                 })
  12396             else
  12397                 ov_bit;
  12398             const zero_ov = try sema.addConstant(Type.u1, try mod.intValue(Type.u1, 0));
  12399             const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
  12400 
  12401             try sema.addSafetyCheck(block, no_ov, .shl_overflow);
  12402             return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
  12403         }
  12404     }
  12405     return block.addBinOp(air_tag, lhs, new_rhs);
  12406 }
  12407 
  12408 fn zirShr(
  12409     sema: *Sema,
  12410     block: *Block,
  12411     inst: Zir.Inst.Index,
  12412     air_tag: Air.Inst.Tag,
  12413 ) CompileError!Air.Inst.Ref {
  12414     const tracy = trace(@src());
  12415     defer tracy.end();
  12416 
  12417     const mod = sema.mod;
  12418     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  12419     const src = inst_data.src();
  12420     sema.src = src;
  12421     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  12422     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  12423     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  12424     const lhs = try sema.resolveInst(extra.lhs);
  12425     const rhs = try sema.resolveInst(extra.rhs);
  12426     const lhs_ty = sema.typeOf(lhs);
  12427     const rhs_ty = sema.typeOf(rhs);
  12428     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  12429     const scalar_ty = lhs_ty.scalarType(mod);
  12430 
  12431     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(lhs);
  12432     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(rhs);
  12433 
  12434     const runtime_src = if (maybe_rhs_val) |rhs_val| rs: {
  12435         if (rhs_val.isUndef(mod)) {
  12436             return sema.addConstUndef(lhs_ty);
  12437         }
  12438         // If rhs is 0, return lhs without doing any calculations.
  12439         if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  12440             return lhs;
  12441         }
  12442         if (scalar_ty.zigTypeTag(mod) != .ComptimeInt) {
  12443             const bit_value = try mod.intValue(Type.comptime_int, scalar_ty.intInfo(mod).bits);
  12444             if (rhs_ty.zigTypeTag(mod) == .Vector) {
  12445                 var i: usize = 0;
  12446                 while (i < rhs_ty.vectorLen(mod)) : (i += 1) {
  12447                     const rhs_elem = try rhs_val.elemValue(sema.mod, i);
  12448                     if (rhs_elem.compareHetero(.gte, bit_value, mod)) {
  12449                         return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{
  12450                             rhs_elem.fmtValue(scalar_ty, sema.mod),
  12451                             i,
  12452                             scalar_ty.fmt(sema.mod),
  12453                         });
  12454                     }
  12455                 }
  12456             } else if (rhs_val.compareHetero(.gte, bit_value, mod)) {
  12457                 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{
  12458                     rhs_val.fmtValue(scalar_ty, sema.mod),
  12459                     scalar_ty.fmt(sema.mod),
  12460                 });
  12461             }
  12462         }
  12463         if (rhs_ty.zigTypeTag(mod) == .Vector) {
  12464             var i: usize = 0;
  12465             while (i < rhs_ty.vectorLen(mod)) : (i += 1) {
  12466                 const rhs_elem = try rhs_val.elemValue(sema.mod, i);
  12467                 if (rhs_elem.compareHetero(.lt, try mod.intValue(rhs_ty.childType(mod), 0), mod)) {
  12468                     return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{
  12469                         rhs_elem.fmtValue(scalar_ty, sema.mod),
  12470                         i,
  12471                     });
  12472                 }
  12473             }
  12474         } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) {
  12475             return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{
  12476                 rhs_val.fmtValue(scalar_ty, sema.mod),
  12477             });
  12478         }
  12479         if (maybe_lhs_val) |lhs_val| {
  12480             if (lhs_val.isUndef(mod)) {
  12481                 return sema.addConstUndef(lhs_ty);
  12482             }
  12483             if (air_tag == .shr_exact) {
  12484                 // Detect if any ones would be shifted out.
  12485                 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, sema.mod);
  12486                 if (!(try truncated.compareAllWithZeroAdvanced(.eq, sema))) {
  12487                     return sema.fail(block, src, "exact shift shifted out 1 bits", .{});
  12488                 }
  12489             }
  12490             const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, sema.mod);
  12491             return sema.addConstant(lhs_ty, val);
  12492         } else {
  12493             break :rs lhs_src;
  12494         }
  12495     } else rhs_src;
  12496 
  12497     if (maybe_rhs_val == null and scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
  12498         return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be comptime-known", .{});
  12499     }
  12500 
  12501     try sema.requireRuntimeBlock(block, src, runtime_src);
  12502     const result = try block.addBinOp(air_tag, lhs, rhs);
  12503     if (block.wantSafety()) {
  12504         const bit_count = scalar_ty.intInfo(mod).bits;
  12505         if (!std.math.isPowerOfTwo(bit_count)) {
  12506             const bit_count_val = try mod.intValue(rhs_ty.scalarType(mod), bit_count);
  12507 
  12508             const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: {
  12509                 const bit_count_inst = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, bit_count_val));
  12510                 const lt = try block.addCmpVector(rhs, bit_count_inst, .lt);
  12511                 break :ok try block.addInst(.{
  12512                     .tag = .reduce,
  12513                     .data = .{ .reduce = .{
  12514                         .operand = lt,
  12515                         .operation = .And,
  12516                     } },
  12517                 });
  12518             } else ok: {
  12519                 const bit_count_inst = try sema.addConstant(rhs_ty, bit_count_val);
  12520                 break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst);
  12521             };
  12522             try sema.addSafetyCheck(block, ok, .shift_rhs_too_big);
  12523         }
  12524 
  12525         if (air_tag == .shr_exact) {
  12526             const back = try block.addBinOp(.shl, result, rhs);
  12527 
  12528             const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: {
  12529                 const eql = try block.addCmpVector(lhs, back, .eq);
  12530                 break :ok try block.addInst(.{
  12531                     .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
  12532                     .data = .{ .reduce = .{
  12533                         .operand = eql,
  12534                         .operation = .And,
  12535                     } },
  12536                 });
  12537             } else try block.addBinOp(.cmp_eq, lhs, back);
  12538             try sema.addSafetyCheck(block, ok, .shr_overflow);
  12539         }
  12540     }
  12541     return result;
  12542 }
  12543 
  12544 fn zirBitwise(
  12545     sema: *Sema,
  12546     block: *Block,
  12547     inst: Zir.Inst.Index,
  12548     air_tag: Air.Inst.Tag,
  12549 ) CompileError!Air.Inst.Ref {
  12550     const tracy = trace(@src());
  12551     defer tracy.end();
  12552 
  12553     const mod = sema.mod;
  12554     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  12555     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  12556     sema.src = src;
  12557     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  12558     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  12559     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  12560     const lhs = try sema.resolveInst(extra.lhs);
  12561     const rhs = try sema.resolveInst(extra.rhs);
  12562     const lhs_ty = sema.typeOf(lhs);
  12563     const rhs_ty = sema.typeOf(rhs);
  12564     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  12565 
  12566     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  12567     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } });
  12568     const scalar_type = resolved_type.scalarType(mod);
  12569     const scalar_tag = scalar_type.zigTypeTag(mod);
  12570 
  12571     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  12572     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  12573 
  12574     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  12575 
  12576     if (!is_int) {
  12577         return sema.fail(block, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag(mod)), @tagName(rhs_ty.zigTypeTag(mod)) });
  12578     }
  12579 
  12580     const runtime_src = runtime: {
  12581         // TODO: ask the linker what kind of relocations are available, and
  12582         // in some cases emit a Value that means "this decl's address AND'd with this operand".
  12583         if (try sema.resolveMaybeUndefValIntable(casted_lhs)) |lhs_val| {
  12584             if (try sema.resolveMaybeUndefValIntable(casted_rhs)) |rhs_val| {
  12585                 const result_val = switch (air_tag) {
  12586                     .bit_and => try lhs_val.bitwiseAnd(rhs_val, resolved_type, sema.arena, sema.mod),
  12587                     .bit_or => try lhs_val.bitwiseOr(rhs_val, resolved_type, sema.arena, sema.mod),
  12588                     .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena, sema.mod),
  12589                     else => unreachable,
  12590                 };
  12591                 return sema.addConstant(resolved_type, result_val);
  12592             } else {
  12593                 break :runtime rhs_src;
  12594             }
  12595         } else {
  12596             break :runtime lhs_src;
  12597         }
  12598     };
  12599 
  12600     try sema.requireRuntimeBlock(block, src, runtime_src);
  12601     return block.addBinOp(air_tag, casted_lhs, casted_rhs);
  12602 }
  12603 
  12604 fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  12605     const tracy = trace(@src());
  12606     defer tracy.end();
  12607 
  12608     const mod = sema.mod;
  12609     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  12610     const src = inst_data.src();
  12611     const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
  12612 
  12613     const operand = try sema.resolveInst(inst_data.operand);
  12614     const operand_type = sema.typeOf(operand);
  12615     const scalar_type = operand_type.scalarType(mod);
  12616 
  12617     if (scalar_type.zigTypeTag(mod) != .Int) {
  12618         return sema.fail(block, src, "unable to perform binary not operation on type '{}'", .{
  12619             operand_type.fmt(sema.mod),
  12620         });
  12621     }
  12622 
  12623     if (try sema.resolveMaybeUndefVal(operand)) |val| {
  12624         if (val.isUndef(mod)) {
  12625             return sema.addConstUndef(operand_type);
  12626         } else if (operand_type.zigTypeTag(mod) == .Vector) {
  12627             const vec_len = try sema.usizeCast(block, operand_src, operand_type.vectorLen(mod));
  12628             const elems = try sema.arena.alloc(InternPool.Index, vec_len);
  12629             for (elems, 0..) |*elem, i| {
  12630                 const elem_val = try val.elemValue(sema.mod, i);
  12631                 elem.* = try (try elem_val.bitwiseNot(scalar_type, sema.arena, sema.mod)).intern(scalar_type, mod);
  12632             }
  12633             return sema.addConstant(operand_type, (try mod.intern(.{ .aggregate = .{
  12634                 .ty = operand_type.toIntern(),
  12635                 .storage = .{ .elems = elems },
  12636             } })).toValue());
  12637         } else {
  12638             const result_val = try val.bitwiseNot(operand_type, sema.arena, sema.mod);
  12639             return sema.addConstant(operand_type, result_val);
  12640         }
  12641     }
  12642 
  12643     try sema.requireRuntimeBlock(block, src, null);
  12644     return block.addTyOp(.not, operand_type, operand);
  12645 }
  12646 
  12647 fn analyzeTupleCat(
  12648     sema: *Sema,
  12649     block: *Block,
  12650     src_node: i32,
  12651     lhs: Air.Inst.Ref,
  12652     rhs: Air.Inst.Ref,
  12653 ) CompileError!Air.Inst.Ref {
  12654     const mod = sema.mod;
  12655     const lhs_ty = sema.typeOf(lhs);
  12656     const rhs_ty = sema.typeOf(rhs);
  12657     const src = LazySrcLoc.nodeOffset(src_node);
  12658     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node };
  12659     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node };
  12660 
  12661     const lhs_len = lhs_ty.structFieldCount(mod);
  12662     const rhs_len = rhs_ty.structFieldCount(mod);
  12663     const dest_fields = lhs_len + rhs_len;
  12664 
  12665     if (dest_fields == 0) {
  12666         return sema.addConstant(Type.empty_struct_literal, Value.empty_struct);
  12667     }
  12668     if (lhs_len == 0) {
  12669         return rhs;
  12670     }
  12671     if (rhs_len == 0) {
  12672         return lhs;
  12673     }
  12674     const final_len = try sema.usizeCast(block, rhs_src, dest_fields);
  12675 
  12676     const types = try sema.arena.alloc(InternPool.Index, final_len);
  12677     const values = try sema.arena.alloc(InternPool.Index, final_len);
  12678 
  12679     const opt_runtime_src = rs: {
  12680         var runtime_src: ?LazySrcLoc = null;
  12681         var i: u32 = 0;
  12682         while (i < lhs_len) : (i += 1) {
  12683             types[i] = lhs_ty.structFieldType(i, mod).toIntern();
  12684             const default_val = lhs_ty.structFieldDefaultValue(i, mod);
  12685             values[i] = default_val.toIntern();
  12686             const operand_src = lhs_src; // TODO better source location
  12687             if (default_val.toIntern() == .unreachable_value) {
  12688                 runtime_src = operand_src;
  12689                 values[i] = .none;
  12690             }
  12691         }
  12692         i = 0;
  12693         while (i < rhs_len) : (i += 1) {
  12694             types[i + lhs_len] = rhs_ty.structFieldType(i, mod).toIntern();
  12695             const default_val = rhs_ty.structFieldDefaultValue(i, mod);
  12696             values[i + lhs_len] = default_val.toIntern();
  12697             const operand_src = rhs_src; // TODO better source location
  12698             if (default_val.toIntern() == .unreachable_value) {
  12699                 runtime_src = operand_src;
  12700                 values[i + lhs_len] = .none;
  12701             }
  12702         }
  12703         break :rs runtime_src;
  12704     };
  12705 
  12706     const tuple_ty = try mod.intern(.{ .anon_struct_type = .{
  12707         .types = types,
  12708         .values = values,
  12709         .names = &.{},
  12710     } });
  12711 
  12712     const runtime_src = opt_runtime_src orelse {
  12713         const tuple_val = try mod.intern(.{ .aggregate = .{
  12714             .ty = tuple_ty,
  12715             .storage = .{ .elems = values },
  12716         } });
  12717         return sema.addConstant(tuple_ty.toType(), tuple_val.toValue());
  12718     };
  12719 
  12720     try sema.requireRuntimeBlock(block, src, runtime_src);
  12721 
  12722     const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len);
  12723     var i: u32 = 0;
  12724     while (i < lhs_len) : (i += 1) {
  12725         const operand_src = lhs_src; // TODO better source location
  12726         element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, lhs, i, lhs_ty);
  12727     }
  12728     i = 0;
  12729     while (i < rhs_len) : (i += 1) {
  12730         const operand_src = rhs_src; // TODO better source location
  12731         element_refs[i + lhs_len] =
  12732             try sema.tupleFieldValByIndex(block, operand_src, rhs, i, rhs_ty);
  12733     }
  12734 
  12735     return block.addAggregateInit(tuple_ty.toType(), element_refs);
  12736 }
  12737 
  12738 fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  12739     const tracy = trace(@src());
  12740     defer tracy.end();
  12741 
  12742     const mod = sema.mod;
  12743     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  12744     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  12745     const lhs = try sema.resolveInst(extra.lhs);
  12746     const rhs = try sema.resolveInst(extra.rhs);
  12747     const lhs_ty = sema.typeOf(lhs);
  12748     const rhs_ty = sema.typeOf(rhs);
  12749     const src = inst_data.src();
  12750 
  12751     const lhs_is_tuple = lhs_ty.isTuple(mod);
  12752     const rhs_is_tuple = rhs_ty.isTuple(mod);
  12753     if (lhs_is_tuple and rhs_is_tuple) {
  12754         return sema.analyzeTupleCat(block, inst_data.src_node, lhs, rhs);
  12755     }
  12756 
  12757     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  12758     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  12759 
  12760     const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, rhs_ty) orelse lhs_info: {
  12761         if (lhs_is_tuple) break :lhs_info @as(Type.ArrayInfo, undefined);
  12762         return sema.fail(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(mod)});
  12763     };
  12764     const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs, lhs_ty) orelse {
  12765         assert(!rhs_is_tuple);
  12766         return sema.fail(block, rhs_src, "expected indexable; found '{}'", .{rhs_ty.fmt(mod)});
  12767     };
  12768 
  12769     const resolved_elem_ty = t: {
  12770         var trash_block = block.makeSubBlock();
  12771         trash_block.is_comptime = false;
  12772         defer trash_block.instructions.deinit(sema.gpa);
  12773 
  12774         const instructions = [_]Air.Inst.Ref{
  12775             try trash_block.addBitCast(lhs_info.elem_type, .void_value),
  12776             try trash_block.addBitCast(rhs_info.elem_type, .void_value),
  12777         };
  12778         break :t try sema.resolvePeerTypes(block, src, &instructions, .{
  12779             .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
  12780         });
  12781     };
  12782 
  12783     // When there is a sentinel mismatch, no sentinel on the result.
  12784     // Otherwise, use the sentinel value provided by either operand,
  12785     // coercing it to the peer-resolved element type.
  12786     const res_sent_val: ?Value = s: {
  12787         if (lhs_info.sentinel) |lhs_sent_val| {
  12788             const lhs_sent = try sema.addConstant(lhs_info.elem_type, lhs_sent_val);
  12789             if (rhs_info.sentinel) |rhs_sent_val| {
  12790                 const rhs_sent = try sema.addConstant(rhs_info.elem_type, rhs_sent_val);
  12791                 const lhs_sent_casted = try sema.coerce(block, resolved_elem_ty, lhs_sent, lhs_src);
  12792                 const rhs_sent_casted = try sema.coerce(block, resolved_elem_ty, rhs_sent, rhs_src);
  12793                 const lhs_sent_casted_val = try sema.resolveConstValue(block, lhs_src, lhs_sent_casted, "array sentinel value must be comptime-known");
  12794                 const rhs_sent_casted_val = try sema.resolveConstValue(block, rhs_src, rhs_sent_casted, "array sentinel value must be comptime-known");
  12795                 if (try sema.valuesEqual(lhs_sent_casted_val, rhs_sent_casted_val, resolved_elem_ty)) {
  12796                     break :s lhs_sent_casted_val;
  12797                 } else {
  12798                     break :s null;
  12799                 }
  12800             } else {
  12801                 const lhs_sent_casted = try sema.coerce(block, resolved_elem_ty, lhs_sent, lhs_src);
  12802                 const lhs_sent_casted_val = try sema.resolveConstValue(block, lhs_src, lhs_sent_casted, "array sentinel value must be comptime-known");
  12803                 break :s lhs_sent_casted_val;
  12804             }
  12805         } else {
  12806             if (rhs_info.sentinel) |rhs_sent_val| {
  12807                 const rhs_sent = try sema.addConstant(rhs_info.elem_type, rhs_sent_val);
  12808                 const rhs_sent_casted = try sema.coerce(block, resolved_elem_ty, rhs_sent, rhs_src);
  12809                 const rhs_sent_casted_val = try sema.resolveConstValue(block, rhs_src, rhs_sent_casted, "array sentinel value must be comptime-known");
  12810                 break :s rhs_sent_casted_val;
  12811             } else {
  12812                 break :s null;
  12813             }
  12814         }
  12815     };
  12816 
  12817     const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);
  12818     const rhs_len = try sema.usizeCast(block, lhs_src, rhs_info.len);
  12819     const result_len = std.math.add(usize, lhs_len, rhs_len) catch |err| switch (err) {
  12820         error.Overflow => return sema.fail(
  12821             block,
  12822             src,
  12823             "concatenating arrays of length {d} and {d} produces an array too large for this compiler implementation to handle",
  12824             .{ lhs_len, rhs_len },
  12825         ),
  12826     };
  12827 
  12828     const result_ty = try Type.array(sema.arena, result_len, res_sent_val, resolved_elem_ty, mod);
  12829     const ptr_addrspace = p: {
  12830         if (lhs_ty.zigTypeTag(mod) == .Pointer) break :p lhs_ty.ptrAddressSpace(mod);
  12831         if (rhs_ty.zigTypeTag(mod) == .Pointer) break :p rhs_ty.ptrAddressSpace(mod);
  12832         break :p null;
  12833     };
  12834 
  12835     const runtime_src = if (switch (lhs_ty.zigTypeTag(mod)) {
  12836         .Array, .Struct => try sema.resolveMaybeUndefVal(lhs),
  12837         .Pointer => try sema.resolveDefinedValue(block, lhs_src, lhs),
  12838         else => unreachable,
  12839     }) |lhs_val| rs: {
  12840         if (switch (rhs_ty.zigTypeTag(mod)) {
  12841             .Array, .Struct => try sema.resolveMaybeUndefVal(rhs),
  12842             .Pointer => try sema.resolveDefinedValue(block, rhs_src, rhs),
  12843             else => unreachable,
  12844         }) |rhs_val| {
  12845             const lhs_sub_val = if (lhs_ty.isSinglePointer(mod))
  12846                 (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).?
  12847             else
  12848                 lhs_val;
  12849 
  12850             const rhs_sub_val = if (rhs_ty.isSinglePointer(mod))
  12851                 (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).?
  12852             else
  12853                 rhs_val;
  12854 
  12855             const element_vals = try sema.arena.alloc(InternPool.Index, result_len);
  12856             var elem_i: usize = 0;
  12857             while (elem_i < lhs_len) : (elem_i += 1) {
  12858                 const lhs_elem_i = elem_i;
  12859                 const elem_ty = if (lhs_is_tuple) lhs_ty.structFieldType(lhs_elem_i, mod) else lhs_info.elem_type;
  12860                 const elem_default_val = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i, mod) else Value.@"unreachable";
  12861                 const elem_val = if (elem_default_val.toIntern() == .unreachable_value) try lhs_sub_val.elemValue(mod, lhs_elem_i) else elem_default_val;
  12862                 const elem_val_inst = try sema.addConstant(elem_ty, elem_val);
  12863                 const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded);
  12864                 const coerced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, "");
  12865                 element_vals[elem_i] = try coerced_elem_val.intern(resolved_elem_ty, mod);
  12866             }
  12867             while (elem_i < result_len) : (elem_i += 1) {
  12868                 const rhs_elem_i = elem_i - lhs_len;
  12869                 const elem_ty = if (rhs_is_tuple) rhs_ty.structFieldType(rhs_elem_i, mod) else rhs_info.elem_type;
  12870                 const elem_default_val = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i, mod) else Value.@"unreachable";
  12871                 const elem_val = if (elem_default_val.toIntern() == .unreachable_value) try rhs_sub_val.elemValue(mod, rhs_elem_i) else elem_default_val;
  12872                 const elem_val_inst = try sema.addConstant(elem_ty, elem_val);
  12873                 const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded);
  12874                 const coerced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, "");
  12875                 element_vals[elem_i] = try coerced_elem_val.intern(resolved_elem_ty, mod);
  12876             }
  12877             return sema.addConstantMaybeRef(block, result_ty, (try mod.intern(.{ .aggregate = .{
  12878                 .ty = result_ty.toIntern(),
  12879                 .storage = .{ .elems = element_vals },
  12880             } })).toValue(), ptr_addrspace != null);
  12881         } else break :rs rhs_src;
  12882     } else lhs_src;
  12883 
  12884     try sema.requireRuntimeBlock(block, src, runtime_src);
  12885 
  12886     if (ptr_addrspace) |ptr_as| {
  12887         const alloc_ty = try Type.ptr(sema.arena, mod, .{
  12888             .pointee_type = result_ty,
  12889             .@"addrspace" = ptr_as,
  12890         });
  12891         const alloc = try block.addTy(.alloc, alloc_ty);
  12892         const elem_ptr_ty = try Type.ptr(sema.arena, mod, .{
  12893             .pointee_type = resolved_elem_ty,
  12894             .@"addrspace" = ptr_as,
  12895         });
  12896 
  12897         var elem_i: usize = 0;
  12898         while (elem_i < lhs_len) : (elem_i += 1) {
  12899             const elem_index = try sema.addIntUnsigned(Type.usize, elem_i);
  12900             const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
  12901             const init = try sema.elemVal(block, lhs_src, lhs, elem_index, src, true);
  12902             try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
  12903         }
  12904         while (elem_i < result_len) : (elem_i += 1) {
  12905             const elem_index = try sema.addIntUnsigned(Type.usize, elem_i);
  12906             const rhs_index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len);
  12907             const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
  12908             const init = try sema.elemVal(block, rhs_src, rhs, rhs_index, src, true);
  12909             try sema.storePtr2(block, src, elem_ptr, src, init, rhs_src, .store);
  12910         }
  12911         if (res_sent_val) |sent_val| {
  12912             const elem_index = try sema.addIntUnsigned(Type.usize, result_len);
  12913             const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
  12914             const init = try sema.addConstant(lhs_info.elem_type, try mod.getCoerced(sent_val, lhs_info.elem_type));
  12915             try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
  12916         }
  12917 
  12918         return alloc;
  12919     }
  12920 
  12921     const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len);
  12922     {
  12923         var elem_i: usize = 0;
  12924         while (elem_i < lhs_len) : (elem_i += 1) {
  12925             const index = try sema.addIntUnsigned(Type.usize, elem_i);
  12926             const init = try sema.elemVal(block, lhs_src, lhs, index, src, true);
  12927             element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, lhs_src);
  12928         }
  12929         while (elem_i < result_len) : (elem_i += 1) {
  12930             const index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len);
  12931             const init = try sema.elemVal(block, rhs_src, rhs, index, src, true);
  12932             element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, rhs_src);
  12933         }
  12934     }
  12935 
  12936     return block.addAggregateInit(result_ty, element_refs);
  12937 }
  12938 
  12939 fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref, peer_ty: Type) !?Type.ArrayInfo {
  12940     const mod = sema.mod;
  12941     const operand_ty = sema.typeOf(operand);
  12942     switch (operand_ty.zigTypeTag(mod)) {
  12943         .Array => return operand_ty.arrayInfo(mod),
  12944         .Pointer => {
  12945             const ptr_info = operand_ty.ptrInfo(mod);
  12946             switch (ptr_info.size) {
  12947                 // TODO: in the Many case here this should only work if the type
  12948                 // has a sentinel, and this code should compute the length based
  12949                 // on the sentinel value.
  12950                 .Slice, .Many => {
  12951                     const val = try sema.resolveConstValue(block, src, operand, "slice value being concatenated must be comptime-known");
  12952                     return Type.ArrayInfo{
  12953                         .elem_type = ptr_info.pointee_type,
  12954                         .sentinel = ptr_info.sentinel,
  12955                         .len = val.sliceLen(sema.mod),
  12956                     };
  12957                 },
  12958                 .One => {
  12959                     if (ptr_info.pointee_type.zigTypeTag(mod) == .Array) {
  12960                         return ptr_info.pointee_type.arrayInfo(mod);
  12961                     }
  12962                 },
  12963                 .C => {},
  12964             }
  12965         },
  12966         .Struct => {
  12967             if (operand_ty.isTuple(mod) and peer_ty.isIndexable(mod)) {
  12968                 assert(!peer_ty.isTuple(mod));
  12969                 return .{
  12970                     .elem_type = peer_ty.elemType2(mod),
  12971                     .sentinel = null,
  12972                     .len = operand_ty.arrayLen(mod),
  12973                 };
  12974             }
  12975         },
  12976         else => {},
  12977     }
  12978     return null;
  12979 }
  12980 
  12981 fn analyzeTupleMul(
  12982     sema: *Sema,
  12983     block: *Block,
  12984     src_node: i32,
  12985     operand: Air.Inst.Ref,
  12986     factor: usize,
  12987 ) CompileError!Air.Inst.Ref {
  12988     const mod = sema.mod;
  12989     const operand_ty = sema.typeOf(operand);
  12990     const src = LazySrcLoc.nodeOffset(src_node);
  12991     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node };
  12992     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node };
  12993 
  12994     const tuple_len = operand_ty.structFieldCount(mod);
  12995     const final_len = std.math.mul(usize, tuple_len, factor) catch
  12996         return sema.fail(block, rhs_src, "operation results in overflow", .{});
  12997 
  12998     if (final_len == 0) {
  12999         return sema.addConstant(Type.empty_struct_literal, Value.empty_struct);
  13000     }
  13001     const types = try sema.arena.alloc(InternPool.Index, final_len);
  13002     const values = try sema.arena.alloc(InternPool.Index, final_len);
  13003 
  13004     const opt_runtime_src = rs: {
  13005         var runtime_src: ?LazySrcLoc = null;
  13006         for (0..tuple_len) |i| {
  13007             types[i] = operand_ty.structFieldType(i, mod).toIntern();
  13008             values[i] = operand_ty.structFieldDefaultValue(i, mod).toIntern();
  13009             const operand_src = lhs_src; // TODO better source location
  13010             if (values[i] == .unreachable_value) {
  13011                 runtime_src = operand_src;
  13012                 values[i] = .none; // TODO don't treat unreachable_value as special
  13013             }
  13014         }
  13015         for (0..factor) |i| {
  13016             mem.copyForwards(InternPool.Index, types[tuple_len * i ..], types[0..tuple_len]);
  13017             mem.copyForwards(InternPool.Index, values[tuple_len * i ..], values[0..tuple_len]);
  13018         }
  13019         break :rs runtime_src;
  13020     };
  13021 
  13022     const tuple_ty = try mod.intern(.{ .anon_struct_type = .{
  13023         .types = types,
  13024         .values = values,
  13025         .names = &.{},
  13026     } });
  13027 
  13028     const runtime_src = opt_runtime_src orelse {
  13029         const tuple_val = try mod.intern(.{ .aggregate = .{
  13030             .ty = tuple_ty,
  13031             .storage = .{ .elems = values },
  13032         } });
  13033         return sema.addConstant(tuple_ty.toType(), tuple_val.toValue());
  13034     };
  13035 
  13036     try sema.requireRuntimeBlock(block, src, runtime_src);
  13037 
  13038     const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len);
  13039     var i: u32 = 0;
  13040     while (i < tuple_len) : (i += 1) {
  13041         const operand_src = lhs_src; // TODO better source location
  13042         element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, operand, @intCast(u32, i), operand_ty);
  13043     }
  13044     i = 1;
  13045     while (i < factor) : (i += 1) {
  13046         @memcpy(element_refs[tuple_len * i ..][0..tuple_len], element_refs[0..tuple_len]);
  13047     }
  13048 
  13049     return block.addAggregateInit(tuple_ty.toType(), element_refs);
  13050 }
  13051 
  13052 fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  13053     const tracy = trace(@src());
  13054     defer tracy.end();
  13055 
  13056     const mod = sema.mod;
  13057     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  13058     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  13059     const lhs = try sema.resolveInst(extra.lhs);
  13060     const lhs_ty = sema.typeOf(lhs);
  13061     const src: LazySrcLoc = inst_data.src();
  13062     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  13063     const operator_src: LazySrcLoc = .{ .node_offset_main_token = inst_data.src_node };
  13064     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  13065 
  13066     if (lhs_ty.isTuple(mod)) {
  13067         // In `**` rhs must be comptime-known, but lhs can be runtime-known
  13068         const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, "array multiplication factor must be comptime-known");
  13069         const factor_casted = try sema.usizeCast(block, rhs_src, factor);
  13070         return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor_casted);
  13071     }
  13072 
  13073     // Analyze the lhs first, to catch the case that someone tried to do exponentiation
  13074     const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, lhs_ty) orelse {
  13075         const msg = msg: {
  13076             const msg = try sema.errMsg(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(mod)});
  13077             errdefer msg.destroy(sema.gpa);
  13078             switch (lhs_ty.zigTypeTag(mod)) {
  13079                 .Int, .Float, .ComptimeFloat, .ComptimeInt, .Vector => {
  13080                     try sema.errNote(block, operator_src, msg, "this operator multiplies arrays; use std.math.pow for exponentiation", .{});
  13081                 },
  13082                 else => {},
  13083             }
  13084             break :msg msg;
  13085         };
  13086         return sema.failWithOwnedErrorMsg(msg);
  13087     };
  13088 
  13089     // In `**` rhs must be comptime-known, but lhs can be runtime-known
  13090     const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, "array multiplication factor must be comptime-known");
  13091 
  13092     const result_len_u64 = std.math.mul(u64, lhs_info.len, factor) catch
  13093         return sema.fail(block, rhs_src, "operation results in overflow", .{});
  13094     const result_len = try sema.usizeCast(block, src, result_len_u64);
  13095 
  13096     const result_ty = try Type.array(sema.arena, result_len, lhs_info.sentinel, lhs_info.elem_type, mod);
  13097 
  13098     const ptr_addrspace = if (lhs_ty.zigTypeTag(mod) == .Pointer) lhs_ty.ptrAddressSpace(mod) else null;
  13099     const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);
  13100 
  13101     if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| {
  13102         const lhs_sub_val = if (lhs_ty.isSinglePointer(mod))
  13103             (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).?
  13104         else
  13105             lhs_val;
  13106 
  13107         const val = v: {
  13108             // Optimization for the common pattern of a single element repeated N times, such
  13109             // as zero-filling a byte array.
  13110             if (lhs_len == 1 and lhs_info.sentinel == null) {
  13111                 const elem_val = try lhs_sub_val.elemValue(mod, 0);
  13112                 break :v try mod.intern(.{ .aggregate = .{
  13113                     .ty = result_ty.toIntern(),
  13114                     .storage = .{ .repeated_elem = elem_val.toIntern() },
  13115                 } });
  13116             }
  13117 
  13118             const element_vals = try sema.arena.alloc(InternPool.Index, result_len);
  13119             var elem_i: usize = 0;
  13120             while (elem_i < result_len) {
  13121                 var lhs_i: usize = 0;
  13122                 while (lhs_i < lhs_len) : (lhs_i += 1) {
  13123                     const elem_val = try lhs_sub_val.elemValue(mod, lhs_i);
  13124                     element_vals[elem_i] = elem_val.toIntern();
  13125                     elem_i += 1;
  13126                 }
  13127             }
  13128             break :v try mod.intern(.{ .aggregate = .{
  13129                 .ty = result_ty.toIntern(),
  13130                 .storage = .{ .elems = element_vals },
  13131             } });
  13132         };
  13133         return sema.addConstantMaybeRef(block, result_ty, val.toValue(), ptr_addrspace != null);
  13134     }
  13135 
  13136     try sema.requireRuntimeBlock(block, src, lhs_src);
  13137 
  13138     if (ptr_addrspace) |ptr_as| {
  13139         const alloc_ty = try Type.ptr(sema.arena, mod, .{
  13140             .pointee_type = result_ty,
  13141             .@"addrspace" = ptr_as,
  13142         });
  13143         const alloc = try block.addTy(.alloc, alloc_ty);
  13144         const elem_ptr_ty = try Type.ptr(sema.arena, mod, .{
  13145             .pointee_type = lhs_info.elem_type,
  13146             .@"addrspace" = ptr_as,
  13147         });
  13148 
  13149         var elem_i: usize = 0;
  13150         while (elem_i < result_len) {
  13151             var lhs_i: usize = 0;
  13152             while (lhs_i < lhs_len) : (lhs_i += 1) {
  13153                 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i);
  13154                 elem_i += 1;
  13155                 const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i);
  13156                 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
  13157                 const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src, true);
  13158                 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
  13159             }
  13160         }
  13161         if (lhs_info.sentinel) |sent_val| {
  13162             const elem_index = try sema.addIntUnsigned(Type.usize, result_len);
  13163             const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
  13164             const init = try sema.addConstant(lhs_info.elem_type, sent_val);
  13165             try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
  13166         }
  13167 
  13168         return alloc;
  13169     }
  13170 
  13171     const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len);
  13172     var elem_i: usize = 0;
  13173     while (elem_i < result_len) {
  13174         var lhs_i: usize = 0;
  13175         while (lhs_i < lhs_len) : (lhs_i += 1) {
  13176             const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i);
  13177             const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src, true);
  13178             element_refs[elem_i] = init;
  13179             elem_i += 1;
  13180         }
  13181     }
  13182 
  13183     return block.addAggregateInit(result_ty, element_refs);
  13184 }
  13185 
  13186 fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  13187     const mod = sema.mod;
  13188     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  13189     const src = inst_data.src();
  13190     const lhs_src = src;
  13191     const rhs_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
  13192 
  13193     const rhs = try sema.resolveInst(inst_data.operand);
  13194     const rhs_ty = sema.typeOf(rhs);
  13195     const rhs_scalar_ty = rhs_ty.scalarType(mod);
  13196 
  13197     if (rhs_scalar_ty.isUnsignedInt(mod) or switch (rhs_scalar_ty.zigTypeTag(mod)) {
  13198         .Int, .ComptimeInt, .Float, .ComptimeFloat => false,
  13199         else => true,
  13200     }) {
  13201         return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)});
  13202     }
  13203 
  13204     if (rhs_scalar_ty.isAnyFloat()) {
  13205         // We handle float negation here to ensure negative zero is represented in the bits.
  13206         if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| {
  13207             if (rhs_val.isUndef(mod)) return sema.addConstUndef(rhs_ty);
  13208             return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, sema.mod));
  13209         }
  13210         try sema.requireRuntimeBlock(block, src, null);
  13211         return block.addUnOp(if (block.float_mode == .Optimized) .neg_optimized else .neg, rhs);
  13212     }
  13213 
  13214     const lhs = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, try mod.intValue(rhs_scalar_ty, 0)));
  13215     return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src, true);
  13216 }
  13217 
  13218 fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  13219     const mod = sema.mod;
  13220     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  13221     const src = inst_data.src();
  13222     const lhs_src = src;
  13223     const rhs_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
  13224 
  13225     const rhs = try sema.resolveInst(inst_data.operand);
  13226     const rhs_ty = sema.typeOf(rhs);
  13227     const rhs_scalar_ty = rhs_ty.scalarType(mod);
  13228 
  13229     switch (rhs_scalar_ty.zigTypeTag(mod)) {
  13230         .Int, .ComptimeInt, .Float, .ComptimeFloat => {},
  13231         else => return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)}),
  13232     }
  13233 
  13234     const lhs = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, try mod.intValue(rhs_scalar_ty, 0)));
  13235     return sema.analyzeArithmetic(block, .subwrap, lhs, rhs, src, lhs_src, rhs_src, true);
  13236 }
  13237 
  13238 fn zirArithmetic(
  13239     sema: *Sema,
  13240     block: *Block,
  13241     inst: Zir.Inst.Index,
  13242     zir_tag: Zir.Inst.Tag,
  13243     safety: bool,
  13244 ) CompileError!Air.Inst.Ref {
  13245     const tracy = trace(@src());
  13246     defer tracy.end();
  13247 
  13248     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  13249     sema.src = .{ .node_offset_bin_op = inst_data.src_node };
  13250     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  13251     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  13252     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  13253     const lhs = try sema.resolveInst(extra.lhs);
  13254     const rhs = try sema.resolveInst(extra.rhs);
  13255 
  13256     return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src, safety);
  13257 }
  13258 
  13259 fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  13260     const mod = sema.mod;
  13261     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  13262     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  13263     sema.src = src;
  13264     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  13265     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  13266     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  13267     const lhs = try sema.resolveInst(extra.lhs);
  13268     const rhs = try sema.resolveInst(extra.rhs);
  13269     const lhs_ty = sema.typeOf(lhs);
  13270     const rhs_ty = sema.typeOf(rhs);
  13271     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
  13272     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
  13273     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  13274     try sema.checkInvalidPtrArithmetic(block, src, lhs_ty);
  13275 
  13276     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  13277     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  13278         .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
  13279     });
  13280 
  13281     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  13282     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  13283 
  13284     const lhs_scalar_ty = lhs_ty.scalarType(mod);
  13285     const rhs_scalar_ty = rhs_ty.scalarType(mod);
  13286     const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod);
  13287 
  13288     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  13289 
  13290     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div);
  13291 
  13292     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
  13293     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
  13294 
  13295     if ((lhs_ty.zigTypeTag(mod) == .ComptimeFloat and rhs_ty.zigTypeTag(mod) == .ComptimeInt) or
  13296         (lhs_ty.zigTypeTag(mod) == .ComptimeInt and rhs_ty.zigTypeTag(mod) == .ComptimeFloat))
  13297     {
  13298         // If it makes a difference whether we coerce to ints or floats before doing the division, error.
  13299         // If lhs % rhs is 0, it doesn't matter.
  13300         const lhs_val = maybe_lhs_val orelse unreachable;
  13301         const rhs_val = maybe_rhs_val orelse unreachable;
  13302         const rem = lhs_val.floatRem(rhs_val, resolved_type, sema.arena, mod) catch unreachable;
  13303         if (!rem.compareAllWithZero(.eq, mod)) {
  13304             return sema.fail(
  13305                 block,
  13306                 src,
  13307                 "ambiguous coercion of division operands '{}' and '{}'; non-zero remainder '{}'",
  13308                 .{ lhs_ty.fmt(mod), rhs_ty.fmt(mod), rem.fmtValue(resolved_type, mod) },
  13309             );
  13310         }
  13311     }
  13312 
  13313     // TODO: emit compile error when .div is used on integers and there would be an
  13314     // ambiguous result between div_floor and div_trunc.
  13315 
  13316     // For integers:
  13317     // If the lhs is zero, then zero is returned regardless of rhs.
  13318     // If the rhs is zero, compile error for division by zero.
  13319     // If the rhs is undefined, compile error because there is a possible
  13320     // value (zero) for which the division would be illegal behavior.
  13321     // If the lhs is undefined:
  13322     //   * if lhs type is signed:
  13323     //     * if rhs is comptime-known and not -1, result is undefined
  13324     //     * if rhs is -1 or runtime-known, compile error because there is a
  13325     //        possible value (-min_int / -1)  for which division would be
  13326     //        illegal behavior.
  13327     //   * if lhs type is unsigned, undef is returned regardless of rhs.
  13328     //
  13329     // For floats:
  13330     // If the rhs is zero:
  13331     //  * comptime_float: compile error for division by zero.
  13332     //  * other float type:
  13333     //    * if the lhs is zero: QNaN
  13334     //    * otherwise: +Inf or -Inf depending on lhs sign
  13335     // If the rhs is undefined:
  13336     //  * comptime_float: compile error because there is a possible
  13337     //    value (zero) for which the division would be illegal behavior.
  13338     //  * other float type: result is undefined
  13339     // If the lhs is undefined, result is undefined.
  13340     switch (scalar_tag) {
  13341         .Int, .ComptimeInt, .ComptimeFloat => {
  13342             if (maybe_lhs_val) |lhs_val| {
  13343                 if (!lhs_val.isUndef(mod)) {
  13344                     if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  13345                         const scalar_zero = switch (scalar_tag) {
  13346                             .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
  13347                             .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
  13348                             else => unreachable,
  13349                         };
  13350                         const zero_val = try sema.splat(resolved_type, scalar_zero);
  13351                         return sema.addConstant(resolved_type, zero_val);
  13352                     }
  13353                 }
  13354             }
  13355             if (maybe_rhs_val) |rhs_val| {
  13356                 if (rhs_val.isUndef(mod)) {
  13357                     return sema.failWithUseOfUndef(block, rhs_src);
  13358                 }
  13359                 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
  13360                     return sema.failWithDivideByZero(block, rhs_src);
  13361                 }
  13362                 // TODO: if the RHS is one, return the LHS directly
  13363             }
  13364         },
  13365         else => {},
  13366     }
  13367 
  13368     const runtime_src = rs: {
  13369         if (maybe_lhs_val) |lhs_val| {
  13370             if (lhs_val.isUndef(mod)) {
  13371                 if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) {
  13372                     if (maybe_rhs_val) |rhs_val| {
  13373                         if (try sema.compareAll(rhs_val, .neq, try mod.intValue(resolved_type, -1), resolved_type)) {
  13374                             return sema.addConstUndef(resolved_type);
  13375                         }
  13376                     }
  13377                     return sema.failWithUseOfUndef(block, rhs_src);
  13378                 }
  13379                 return sema.addConstUndef(resolved_type);
  13380             }
  13381 
  13382             if (maybe_rhs_val) |rhs_val| {
  13383                 if (is_int) {
  13384                     const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, mod);
  13385                     var vector_index: usize = undefined;
  13386                     if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) {
  13387                         return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index);
  13388                     }
  13389                     return sema.addConstant(resolved_type, res);
  13390                 } else {
  13391                     return sema.addConstant(
  13392                         resolved_type,
  13393                         try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, mod),
  13394                     );
  13395                 }
  13396             } else {
  13397                 break :rs rhs_src;
  13398             }
  13399         } else {
  13400             break :rs lhs_src;
  13401         }
  13402     };
  13403 
  13404     try sema.requireRuntimeBlock(block, src, runtime_src);
  13405 
  13406     if (block.wantSafety()) {
  13407         try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
  13408         try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
  13409     }
  13410 
  13411     const air_tag = if (is_int) blk: {
  13412         if (lhs_ty.isSignedInt(mod) or rhs_ty.isSignedInt(mod)) {
  13413             return sema.fail(
  13414                 block,
  13415                 src,
  13416                 "division with '{}' and '{}': signed integers must use @divTrunc, @divFloor, or @divExact",
  13417                 .{ lhs_ty.fmt(mod), rhs_ty.fmt(mod) },
  13418             );
  13419         }
  13420         break :blk Air.Inst.Tag.div_trunc;
  13421     } else switch (block.float_mode) {
  13422         .Optimized => Air.Inst.Tag.div_float_optimized,
  13423         .Strict => Air.Inst.Tag.div_float,
  13424     };
  13425     return block.addBinOp(air_tag, casted_lhs, casted_rhs);
  13426 }
  13427 
  13428 fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  13429     const mod = sema.mod;
  13430     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  13431     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  13432     sema.src = src;
  13433     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  13434     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  13435     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  13436     const lhs = try sema.resolveInst(extra.lhs);
  13437     const rhs = try sema.resolveInst(extra.rhs);
  13438     const lhs_ty = sema.typeOf(lhs);
  13439     const rhs_ty = sema.typeOf(rhs);
  13440     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
  13441     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
  13442     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  13443     try sema.checkInvalidPtrArithmetic(block, src, lhs_ty);
  13444 
  13445     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  13446     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  13447         .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
  13448     });
  13449 
  13450     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  13451     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  13452 
  13453     const lhs_scalar_ty = lhs_ty.scalarType(mod);
  13454     const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod);
  13455 
  13456     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  13457 
  13458     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_exact);
  13459 
  13460     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
  13461     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
  13462 
  13463     const runtime_src = rs: {
  13464         // For integers:
  13465         // If the lhs is zero, then zero is returned regardless of rhs.
  13466         // If the rhs is zero, compile error for division by zero.
  13467         // If the rhs is undefined, compile error because there is a possible
  13468         // value (zero) for which the division would be illegal behavior.
  13469         // If the lhs is undefined, compile error because there is a possible
  13470         // value for which the division would result in a remainder.
  13471         // TODO: emit runtime safety for if there is a remainder
  13472         // TODO: emit runtime safety for division by zero
  13473         //
  13474         // For floats:
  13475         // If the rhs is zero, compile error for division by zero.
  13476         // If the rhs is undefined, compile error because there is a possible
  13477         // value (zero) for which the division would be illegal behavior.
  13478         // If the lhs is undefined, compile error because there is a possible
  13479         // value for which the division would result in a remainder.
  13480         if (maybe_lhs_val) |lhs_val| {
  13481             if (lhs_val.isUndef(mod)) {
  13482                 return sema.failWithUseOfUndef(block, rhs_src);
  13483             } else {
  13484                 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  13485                     const scalar_zero = switch (scalar_tag) {
  13486                         .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
  13487                         .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
  13488                         else => unreachable,
  13489                     };
  13490                     const zero_val = try sema.splat(resolved_type, scalar_zero);
  13491                     return sema.addConstant(resolved_type, zero_val);
  13492                 }
  13493             }
  13494         }
  13495         if (maybe_rhs_val) |rhs_val| {
  13496             if (rhs_val.isUndef(mod)) {
  13497                 return sema.failWithUseOfUndef(block, rhs_src);
  13498             }
  13499             if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
  13500                 return sema.failWithDivideByZero(block, rhs_src);
  13501             }
  13502             // TODO: if the RHS is one, return the LHS directly
  13503         }
  13504         if (maybe_lhs_val) |lhs_val| {
  13505             if (maybe_rhs_val) |rhs_val| {
  13506                 if (is_int) {
  13507                     const modulus_val = try lhs_val.intMod(rhs_val, resolved_type, sema.arena, mod);
  13508                     if (!(modulus_val.compareAllWithZero(.eq, mod))) {
  13509                         return sema.fail(block, src, "exact division produced remainder", .{});
  13510                     }
  13511                     const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, mod);
  13512                     var vector_index: usize = undefined;
  13513                     if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) {
  13514                         return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index);
  13515                     }
  13516                     return sema.addConstant(resolved_type, res);
  13517                 } else {
  13518                     const modulus_val = try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, mod);
  13519                     if (!(modulus_val.compareAllWithZero(.eq, mod))) {
  13520                         return sema.fail(block, src, "exact division produced remainder", .{});
  13521                     }
  13522                     return sema.addConstant(
  13523                         resolved_type,
  13524                         try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, mod),
  13525                     );
  13526                 }
  13527             } else break :rs rhs_src;
  13528         } else break :rs lhs_src;
  13529     };
  13530 
  13531     try sema.requireRuntimeBlock(block, src, runtime_src);
  13532 
  13533     // Depending on whether safety is enabled, we will have a slightly different strategy
  13534     // here. The `div_exact` AIR instruction causes undefined behavior if a remainder
  13535     // is produced, so in the safety check case, it cannot be used. Instead we do a
  13536     // div_trunc and check for remainder.
  13537 
  13538     if (block.wantSafety()) {
  13539         try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
  13540         try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
  13541 
  13542         const result = try block.addBinOp(.div_trunc, casted_lhs, casted_rhs);
  13543         const ok = if (!is_int) ok: {
  13544             const floored = try block.addUnOp(.floor, result);
  13545 
  13546             if (resolved_type.zigTypeTag(mod) == .Vector) {
  13547                 const eql = try block.addCmpVector(result, floored, .eq);
  13548                 break :ok try block.addInst(.{
  13549                     .tag = switch (block.float_mode) {
  13550                         .Strict => .reduce,
  13551                         .Optimized => .reduce_optimized,
  13552                     },
  13553                     .data = .{ .reduce = .{
  13554                         .operand = eql,
  13555                         .operation = .And,
  13556                     } },
  13557                 });
  13558             } else {
  13559                 const is_in_range = try block.addBinOp(switch (block.float_mode) {
  13560                     .Strict => .cmp_eq,
  13561                     .Optimized => .cmp_eq_optimized,
  13562                 }, result, floored);
  13563                 break :ok is_in_range;
  13564             }
  13565         } else ok: {
  13566             const remainder = try block.addBinOp(.rem, casted_lhs, casted_rhs);
  13567 
  13568             const scalar_zero = switch (scalar_tag) {
  13569                 .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
  13570                 .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
  13571                 else => unreachable,
  13572             };
  13573             if (resolved_type.zigTypeTag(mod) == .Vector) {
  13574                 const zero_val = try sema.splat(resolved_type, scalar_zero);
  13575                 const zero = try sema.addConstant(resolved_type, zero_val);
  13576                 const eql = try block.addCmpVector(remainder, zero, .eq);
  13577                 break :ok try block.addInst(.{
  13578                     .tag = .reduce,
  13579                     .data = .{ .reduce = .{
  13580                         .operand = eql,
  13581                         .operation = .And,
  13582                     } },
  13583                 });
  13584             } else {
  13585                 const zero = try sema.addConstant(resolved_type, scalar_zero);
  13586                 const is_in_range = try block.addBinOp(.cmp_eq, remainder, zero);
  13587                 break :ok is_in_range;
  13588             }
  13589         };
  13590         try sema.addSafetyCheck(block, ok, .exact_division_remainder);
  13591         return result;
  13592     }
  13593 
  13594     return block.addBinOp(airTag(block, is_int, .div_exact, .div_exact_optimized), casted_lhs, casted_rhs);
  13595 }
  13596 
  13597 fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  13598     const mod = sema.mod;
  13599     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  13600     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  13601     sema.src = src;
  13602     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  13603     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  13604     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  13605     const lhs = try sema.resolveInst(extra.lhs);
  13606     const rhs = try sema.resolveInst(extra.rhs);
  13607     const lhs_ty = sema.typeOf(lhs);
  13608     const rhs_ty = sema.typeOf(rhs);
  13609     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
  13610     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
  13611     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  13612     try sema.checkInvalidPtrArithmetic(block, src, lhs_ty);
  13613 
  13614     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  13615     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  13616         .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
  13617     });
  13618 
  13619     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  13620     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  13621 
  13622     const lhs_scalar_ty = lhs_ty.scalarType(mod);
  13623     const rhs_scalar_ty = rhs_ty.scalarType(mod);
  13624     const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod);
  13625 
  13626     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  13627 
  13628     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_floor);
  13629 
  13630     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
  13631     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
  13632 
  13633     const runtime_src = rs: {
  13634         // For integers:
  13635         // If the lhs is zero, then zero is returned regardless of rhs.
  13636         // If the rhs is zero, compile error for division by zero.
  13637         // If the rhs is undefined, compile error because there is a possible
  13638         // value (zero) for which the division would be illegal behavior.
  13639         // If the lhs is undefined:
  13640         //   * if lhs type is signed:
  13641         //     * if rhs is comptime-known and not -1, result is undefined
  13642         //     * if rhs is -1 or runtime-known, compile error because there is a
  13643         //        possible value (-min_int / -1)  for which division would be
  13644         //        illegal behavior.
  13645         //   * if lhs type is unsigned, undef is returned regardless of rhs.
  13646         // TODO: emit runtime safety for division by zero
  13647         //
  13648         // For floats:
  13649         // If the rhs is zero, compile error for division by zero.
  13650         // If the rhs is undefined, compile error because there is a possible
  13651         // value (zero) for which the division would be illegal behavior.
  13652         // If the lhs is undefined, result is undefined.
  13653         if (maybe_lhs_val) |lhs_val| {
  13654             if (!lhs_val.isUndef(mod)) {
  13655                 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  13656                     const scalar_zero = switch (scalar_tag) {
  13657                         .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
  13658                         .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
  13659                         else => unreachable,
  13660                     };
  13661                     const zero_val = try sema.splat(resolved_type, scalar_zero);
  13662                     return sema.addConstant(resolved_type, zero_val);
  13663                 }
  13664             }
  13665         }
  13666         if (maybe_rhs_val) |rhs_val| {
  13667             if (rhs_val.isUndef(mod)) {
  13668                 return sema.failWithUseOfUndef(block, rhs_src);
  13669             }
  13670             if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
  13671                 return sema.failWithDivideByZero(block, rhs_src);
  13672             }
  13673             // TODO: if the RHS is one, return the LHS directly
  13674         }
  13675         if (maybe_lhs_val) |lhs_val| {
  13676             if (lhs_val.isUndef(mod)) {
  13677                 if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) {
  13678                     if (maybe_rhs_val) |rhs_val| {
  13679                         if (try sema.compareAll(rhs_val, .neq, try mod.intValue(resolved_type, -1), resolved_type)) {
  13680                             return sema.addConstUndef(resolved_type);
  13681                         }
  13682                     }
  13683                     return sema.failWithUseOfUndef(block, rhs_src);
  13684                 }
  13685                 return sema.addConstUndef(resolved_type);
  13686             }
  13687 
  13688             if (maybe_rhs_val) |rhs_val| {
  13689                 if (is_int) {
  13690                     return sema.addConstant(
  13691                         resolved_type,
  13692                         try lhs_val.intDivFloor(rhs_val, resolved_type, sema.arena, mod),
  13693                     );
  13694                 } else {
  13695                     return sema.addConstant(
  13696                         resolved_type,
  13697                         try lhs_val.floatDivFloor(rhs_val, resolved_type, sema.arena, mod),
  13698                     );
  13699                 }
  13700             } else break :rs rhs_src;
  13701         } else break :rs lhs_src;
  13702     };
  13703 
  13704     try sema.requireRuntimeBlock(block, src, runtime_src);
  13705 
  13706     if (block.wantSafety()) {
  13707         try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
  13708         try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
  13709     }
  13710 
  13711     return block.addBinOp(airTag(block, is_int, .div_floor, .div_floor_optimized), casted_lhs, casted_rhs);
  13712 }
  13713 
  13714 fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  13715     const mod = sema.mod;
  13716     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  13717     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  13718     sema.src = src;
  13719     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  13720     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  13721     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  13722     const lhs = try sema.resolveInst(extra.lhs);
  13723     const rhs = try sema.resolveInst(extra.rhs);
  13724     const lhs_ty = sema.typeOf(lhs);
  13725     const rhs_ty = sema.typeOf(rhs);
  13726     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
  13727     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
  13728     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  13729     try sema.checkInvalidPtrArithmetic(block, src, lhs_ty);
  13730 
  13731     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  13732     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  13733         .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
  13734     });
  13735 
  13736     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  13737     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  13738 
  13739     const lhs_scalar_ty = lhs_ty.scalarType(mod);
  13740     const rhs_scalar_ty = rhs_ty.scalarType(mod);
  13741     const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod);
  13742 
  13743     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  13744 
  13745     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_trunc);
  13746 
  13747     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
  13748     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
  13749 
  13750     const runtime_src = rs: {
  13751         // For integers:
  13752         // If the lhs is zero, then zero is returned regardless of rhs.
  13753         // If the rhs is zero, compile error for division by zero.
  13754         // If the rhs is undefined, compile error because there is a possible
  13755         // value (zero) for which the division would be illegal behavior.
  13756         // If the lhs is undefined:
  13757         //   * if lhs type is signed:
  13758         //     * if rhs is comptime-known and not -1, result is undefined
  13759         //     * if rhs is -1 or runtime-known, compile error because there is a
  13760         //        possible value (-min_int / -1)  for which division would be
  13761         //        illegal behavior.
  13762         //   * if lhs type is unsigned, undef is returned regardless of rhs.
  13763         // TODO: emit runtime safety for division by zero
  13764         //
  13765         // For floats:
  13766         // If the rhs is zero, compile error for division by zero.
  13767         // If the rhs is undefined, compile error because there is a possible
  13768         // value (zero) for which the division would be illegal behavior.
  13769         // If the lhs is undefined, result is undefined.
  13770         if (maybe_lhs_val) |lhs_val| {
  13771             if (!lhs_val.isUndef(mod)) {
  13772                 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  13773                     const scalar_zero = switch (scalar_tag) {
  13774                         .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
  13775                         .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
  13776                         else => unreachable,
  13777                     };
  13778                     const zero_val = try sema.splat(resolved_type, scalar_zero);
  13779                     return sema.addConstant(resolved_type, zero_val);
  13780                 }
  13781             }
  13782         }
  13783         if (maybe_rhs_val) |rhs_val| {
  13784             if (rhs_val.isUndef(mod)) {
  13785                 return sema.failWithUseOfUndef(block, rhs_src);
  13786             }
  13787             if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
  13788                 return sema.failWithDivideByZero(block, rhs_src);
  13789             }
  13790         }
  13791         if (maybe_lhs_val) |lhs_val| {
  13792             if (lhs_val.isUndef(mod)) {
  13793                 if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) {
  13794                     if (maybe_rhs_val) |rhs_val| {
  13795                         if (try sema.compareAll(rhs_val, .neq, try mod.intValue(resolved_type, -1), resolved_type)) {
  13796                             return sema.addConstUndef(resolved_type);
  13797                         }
  13798                     }
  13799                     return sema.failWithUseOfUndef(block, rhs_src);
  13800                 }
  13801                 return sema.addConstUndef(resolved_type);
  13802             }
  13803 
  13804             if (maybe_rhs_val) |rhs_val| {
  13805                 if (is_int) {
  13806                     const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, mod);
  13807                     var vector_index: usize = undefined;
  13808                     if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) {
  13809                         return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index);
  13810                     }
  13811                     return sema.addConstant(resolved_type, res);
  13812                 } else {
  13813                     return sema.addConstant(
  13814                         resolved_type,
  13815                         try lhs_val.floatDivTrunc(rhs_val, resolved_type, sema.arena, mod),
  13816                     );
  13817                 }
  13818             } else break :rs rhs_src;
  13819         } else break :rs lhs_src;
  13820     };
  13821 
  13822     try sema.requireRuntimeBlock(block, src, runtime_src);
  13823 
  13824     if (block.wantSafety()) {
  13825         try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
  13826         try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
  13827     }
  13828 
  13829     return block.addBinOp(airTag(block, is_int, .div_trunc, .div_trunc_optimized), casted_lhs, casted_rhs);
  13830 }
  13831 
  13832 fn addDivIntOverflowSafety(
  13833     sema: *Sema,
  13834     block: *Block,
  13835     resolved_type: Type,
  13836     lhs_scalar_ty: Type,
  13837     maybe_lhs_val: ?Value,
  13838     maybe_rhs_val: ?Value,
  13839     casted_lhs: Air.Inst.Ref,
  13840     casted_rhs: Air.Inst.Ref,
  13841     is_int: bool,
  13842 ) CompileError!void {
  13843     const mod = sema.mod;
  13844     if (!is_int) return;
  13845 
  13846     // If the LHS is unsigned, it cannot cause overflow.
  13847     if (!lhs_scalar_ty.isSignedInt(mod)) return;
  13848 
  13849     // If the LHS is widened to a larger integer type, no overflow is possible.
  13850     if (lhs_scalar_ty.intInfo(mod).bits < resolved_type.intInfo(mod).bits) {
  13851         return;
  13852     }
  13853 
  13854     const min_int = try resolved_type.minInt(mod, resolved_type);
  13855     const neg_one_scalar = try mod.intValue(lhs_scalar_ty, -1);
  13856     const neg_one = try sema.splat(resolved_type, neg_one_scalar);
  13857 
  13858     // If the LHS is comptime-known to be not equal to the min int,
  13859     // no overflow is possible.
  13860     if (maybe_lhs_val) |lhs_val| {
  13861         if (try lhs_val.compareAll(.neq, min_int, resolved_type, mod)) return;
  13862     }
  13863 
  13864     // If the RHS is comptime-known to not be equal to -1, no overflow is possible.
  13865     if (maybe_rhs_val) |rhs_val| {
  13866         if (try rhs_val.compareAll(.neq, neg_one, resolved_type, mod)) return;
  13867     }
  13868 
  13869     var ok: Air.Inst.Ref = .none;
  13870     if (resolved_type.zigTypeTag(mod) == .Vector) {
  13871         if (maybe_lhs_val == null) {
  13872             const min_int_ref = try sema.addConstant(resolved_type, min_int);
  13873             ok = try block.addCmpVector(casted_lhs, min_int_ref, .neq);
  13874         }
  13875         if (maybe_rhs_val == null) {
  13876             const neg_one_ref = try sema.addConstant(resolved_type, neg_one);
  13877             const rhs_ok = try block.addCmpVector(casted_rhs, neg_one_ref, .neq);
  13878             if (ok == .none) {
  13879                 ok = rhs_ok;
  13880             } else {
  13881                 ok = try block.addBinOp(.bool_or, ok, rhs_ok);
  13882             }
  13883         }
  13884         assert(ok != .none);
  13885         ok = try block.addInst(.{
  13886             .tag = .reduce,
  13887             .data = .{ .reduce = .{
  13888                 .operand = ok,
  13889                 .operation = .And,
  13890             } },
  13891         });
  13892     } else {
  13893         if (maybe_lhs_val == null) {
  13894             const min_int_ref = try sema.addConstant(resolved_type, min_int);
  13895             ok = try block.addBinOp(.cmp_neq, casted_lhs, min_int_ref);
  13896         }
  13897         if (maybe_rhs_val == null) {
  13898             const neg_one_ref = try sema.addConstant(resolved_type, neg_one);
  13899             const rhs_ok = try block.addBinOp(.cmp_neq, casted_rhs, neg_one_ref);
  13900             if (ok == .none) {
  13901                 ok = rhs_ok;
  13902             } else {
  13903                 ok = try block.addBinOp(.bool_or, ok, rhs_ok);
  13904             }
  13905         }
  13906         assert(ok != .none);
  13907     }
  13908     try sema.addSafetyCheck(block, ok, .integer_overflow);
  13909 }
  13910 
  13911 fn addDivByZeroSafety(
  13912     sema: *Sema,
  13913     block: *Block,
  13914     resolved_type: Type,
  13915     maybe_rhs_val: ?Value,
  13916     casted_rhs: Air.Inst.Ref,
  13917     is_int: bool,
  13918 ) CompileError!void {
  13919     // Strict IEEE floats have well-defined division by zero.
  13920     if (!is_int and block.float_mode == .Strict) return;
  13921 
  13922     // If rhs was comptime-known to be zero a compile error would have been
  13923     // emitted above.
  13924     if (maybe_rhs_val != null) return;
  13925 
  13926     const mod = sema.mod;
  13927     const scalar_zero = if (is_int)
  13928         try mod.intValue(resolved_type.scalarType(mod), 0)
  13929     else
  13930         try mod.floatValue(resolved_type.scalarType(mod), 0.0);
  13931     const ok = if (resolved_type.zigTypeTag(mod) == .Vector) ok: {
  13932         const zero_val = try sema.splat(resolved_type, scalar_zero);
  13933         const zero = try sema.addConstant(resolved_type, zero_val);
  13934         const ok = try block.addCmpVector(casted_rhs, zero, .neq);
  13935         break :ok try block.addInst(.{
  13936             .tag = if (is_int) .reduce else .reduce_optimized,
  13937             .data = .{ .reduce = .{
  13938                 .operand = ok,
  13939                 .operation = .And,
  13940             } },
  13941         });
  13942     } else ok: {
  13943         const zero = try sema.addConstant(resolved_type, scalar_zero);
  13944         break :ok try block.addBinOp(if (is_int) .cmp_neq else .cmp_neq_optimized, casted_rhs, zero);
  13945     };
  13946     try sema.addSafetyCheck(block, ok, .divide_by_zero);
  13947 }
  13948 
  13949 fn airTag(block: *Block, is_int: bool, normal: Air.Inst.Tag, optimized: Air.Inst.Tag) Air.Inst.Tag {
  13950     if (is_int) return normal;
  13951     return switch (block.float_mode) {
  13952         .Strict => normal,
  13953         .Optimized => optimized,
  13954     };
  13955 }
  13956 
  13957 fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  13958     const mod = sema.mod;
  13959     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  13960     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  13961     sema.src = src;
  13962     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  13963     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  13964     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  13965     const lhs = try sema.resolveInst(extra.lhs);
  13966     const rhs = try sema.resolveInst(extra.rhs);
  13967     const lhs_ty = sema.typeOf(lhs);
  13968     const rhs_ty = sema.typeOf(rhs);
  13969     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
  13970     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
  13971     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  13972     try sema.checkInvalidPtrArithmetic(block, src, lhs_ty);
  13973 
  13974     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  13975     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  13976         .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
  13977     });
  13978 
  13979     const is_vector = resolved_type.zigTypeTag(mod) == .Vector;
  13980 
  13981     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  13982     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  13983 
  13984     const lhs_scalar_ty = lhs_ty.scalarType(mod);
  13985     const rhs_scalar_ty = rhs_ty.scalarType(mod);
  13986     const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod);
  13987 
  13988     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  13989 
  13990     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod_rem);
  13991 
  13992     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
  13993     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
  13994 
  13995     const runtime_src = rs: {
  13996         // For integers:
  13997         // Either operand being undef is a compile error because there exists
  13998         // a possible value (TODO what is it?) that would invoke illegal behavior.
  13999         // TODO: can lhs undef be handled better?
  14000         //
  14001         // For floats:
  14002         // If the rhs is zero, compile error for division by zero.
  14003         // If the rhs is undefined, compile error because there is a possible
  14004         // value (zero) for which the division would be illegal behavior.
  14005         // If the lhs is undefined, result is undefined.
  14006         //
  14007         // For either one: if the result would be different between @mod and @rem,
  14008         // then emit a compile error saying you have to pick one.
  14009         if (is_int) {
  14010             if (maybe_lhs_val) |lhs_val| {
  14011                 if (lhs_val.isUndef(mod)) {
  14012                     return sema.failWithUseOfUndef(block, lhs_src);
  14013                 }
  14014                 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  14015                     const scalar_zero = switch (scalar_tag) {
  14016                         .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
  14017                         .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
  14018                         else => unreachable,
  14019                     };
  14020                     const zero_val = if (is_vector) (try mod.intern(.{ .aggregate = .{
  14021                         .ty = resolved_type.toIntern(),
  14022                         .storage = .{ .repeated_elem = scalar_zero.toIntern() },
  14023                     } })).toValue() else scalar_zero;
  14024                     return sema.addConstant(resolved_type, zero_val);
  14025                 }
  14026             } else if (lhs_scalar_ty.isSignedInt(mod)) {
  14027                 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
  14028             }
  14029             if (maybe_rhs_val) |rhs_val| {
  14030                 if (rhs_val.isUndef(mod)) {
  14031                     return sema.failWithUseOfUndef(block, rhs_src);
  14032                 }
  14033                 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
  14034                     return sema.failWithDivideByZero(block, rhs_src);
  14035                 }
  14036                 if (!(try rhs_val.compareAllWithZeroAdvanced(.gte, sema))) {
  14037                     return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
  14038                 }
  14039                 if (maybe_lhs_val) |lhs_val| {
  14040                     const rem_result = try sema.intRem(resolved_type, lhs_val, rhs_val);
  14041                     // If this answer could possibly be different by doing `intMod`,
  14042                     // we must emit a compile error. Otherwise, it's OK.
  14043                     if (!(try lhs_val.compareAllWithZeroAdvanced(.gte, sema)) and
  14044                         !(try rem_result.compareAllWithZeroAdvanced(.eq, sema)))
  14045                     {
  14046                         return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
  14047                     }
  14048                     return sema.addConstant(resolved_type, rem_result);
  14049                 }
  14050                 break :rs lhs_src;
  14051             } else if (rhs_scalar_ty.isSignedInt(mod)) {
  14052                 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
  14053             } else {
  14054                 break :rs rhs_src;
  14055             }
  14056         }
  14057         // float operands
  14058         if (maybe_rhs_val) |rhs_val| {
  14059             if (rhs_val.isUndef(mod)) {
  14060                 return sema.failWithUseOfUndef(block, rhs_src);
  14061             }
  14062             if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
  14063                 return sema.failWithDivideByZero(block, rhs_src);
  14064             }
  14065             if (!(try rhs_val.compareAllWithZeroAdvanced(.gte, sema))) {
  14066                 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
  14067             }
  14068             if (maybe_lhs_val) |lhs_val| {
  14069                 if (lhs_val.isUndef(mod) or !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema))) {
  14070                     return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
  14071                 }
  14072                 return sema.addConstant(
  14073                     resolved_type,
  14074                     try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, mod),
  14075                 );
  14076             } else {
  14077                 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
  14078             }
  14079         } else {
  14080             return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
  14081         }
  14082     };
  14083 
  14084     try sema.requireRuntimeBlock(block, src, runtime_src);
  14085 
  14086     if (block.wantSafety()) {
  14087         try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
  14088     }
  14089 
  14090     const air_tag = airTag(block, is_int, .rem, .rem_optimized);
  14091     return block.addBinOp(air_tag, casted_lhs, casted_rhs);
  14092 }
  14093 
  14094 fn intRem(
  14095     sema: *Sema,
  14096     ty: Type,
  14097     lhs: Value,
  14098     rhs: Value,
  14099 ) CompileError!Value {
  14100     const mod = sema.mod;
  14101     if (ty.zigTypeTag(mod) == .Vector) {
  14102         const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod));
  14103         const scalar_ty = ty.scalarType(mod);
  14104         for (result_data, 0..) |*scalar, i| {
  14105             const lhs_elem = try lhs.elemValue(sema.mod, i);
  14106             const rhs_elem = try rhs.elemValue(sema.mod, i);
  14107             scalar.* = try (try sema.intRemScalar(lhs_elem, rhs_elem, scalar_ty)).intern(scalar_ty, mod);
  14108         }
  14109         return (try mod.intern(.{ .aggregate = .{
  14110             .ty = ty.toIntern(),
  14111             .storage = .{ .elems = result_data },
  14112         } })).toValue();
  14113     }
  14114     return sema.intRemScalar(lhs, rhs, ty);
  14115 }
  14116 
  14117 fn intRemScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) CompileError!Value {
  14118     const mod = sema.mod;
  14119     // TODO is this a performance issue? maybe we should try the operation without
  14120     // resorting to BigInt first.
  14121     var lhs_space: Value.BigIntSpace = undefined;
  14122     var rhs_space: Value.BigIntSpace = undefined;
  14123     const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
  14124     const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
  14125     const limbs_q = try sema.arena.alloc(
  14126         math.big.Limb,
  14127         lhs_bigint.limbs.len,
  14128     );
  14129     const limbs_r = try sema.arena.alloc(
  14130         math.big.Limb,
  14131         // TODO: consider reworking Sema to re-use Values rather than
  14132         // always producing new Value objects.
  14133         rhs_bigint.limbs.len,
  14134     );
  14135     const limbs_buffer = try sema.arena.alloc(
  14136         math.big.Limb,
  14137         math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
  14138     );
  14139     var result_q = math.big.int.Mutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
  14140     var result_r = math.big.int.Mutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
  14141     result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
  14142     return mod.intValue_big(scalar_ty, result_r.toConst());
  14143 }
  14144 
  14145 fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  14146     const mod = sema.mod;
  14147     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  14148     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  14149     sema.src = src;
  14150     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  14151     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  14152     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  14153     const lhs = try sema.resolveInst(extra.lhs);
  14154     const rhs = try sema.resolveInst(extra.rhs);
  14155     const lhs_ty = sema.typeOf(lhs);
  14156     const rhs_ty = sema.typeOf(rhs);
  14157     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
  14158     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
  14159     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  14160     try sema.checkInvalidPtrArithmetic(block, src, lhs_ty);
  14161 
  14162     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  14163     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  14164         .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
  14165     });
  14166 
  14167     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  14168     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  14169 
  14170     const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod);
  14171 
  14172     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  14173 
  14174     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod);
  14175 
  14176     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
  14177     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
  14178 
  14179     const runtime_src = rs: {
  14180         // For integers:
  14181         // Either operand being undef is a compile error because there exists
  14182         // a possible value (TODO what is it?) that would invoke illegal behavior.
  14183         // TODO: can lhs zero be handled better?
  14184         // TODO: can lhs undef be handled better?
  14185         //
  14186         // For floats:
  14187         // If the rhs is zero, compile error for division by zero.
  14188         // If the rhs is undefined, compile error because there is a possible
  14189         // value (zero) for which the division would be illegal behavior.
  14190         // If the lhs is undefined, result is undefined.
  14191         if (is_int) {
  14192             if (maybe_lhs_val) |lhs_val| {
  14193                 if (lhs_val.isUndef(mod)) {
  14194                     return sema.failWithUseOfUndef(block, lhs_src);
  14195                 }
  14196             }
  14197             if (maybe_rhs_val) |rhs_val| {
  14198                 if (rhs_val.isUndef(mod)) {
  14199                     return sema.failWithUseOfUndef(block, rhs_src);
  14200                 }
  14201                 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
  14202                     return sema.failWithDivideByZero(block, rhs_src);
  14203                 }
  14204                 if (maybe_lhs_val) |lhs_val| {
  14205                     return sema.addConstant(
  14206                         resolved_type,
  14207                         try lhs_val.intMod(rhs_val, resolved_type, sema.arena, mod),
  14208                     );
  14209                 }
  14210                 break :rs lhs_src;
  14211             } else {
  14212                 break :rs rhs_src;
  14213             }
  14214         }
  14215         // float operands
  14216         if (maybe_rhs_val) |rhs_val| {
  14217             if (rhs_val.isUndef(mod)) {
  14218                 return sema.failWithUseOfUndef(block, rhs_src);
  14219             }
  14220             if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
  14221                 return sema.failWithDivideByZero(block, rhs_src);
  14222             }
  14223         }
  14224         if (maybe_lhs_val) |lhs_val| {
  14225             if (lhs_val.isUndef(mod)) {
  14226                 return sema.addConstUndef(resolved_type);
  14227             }
  14228             if (maybe_rhs_val) |rhs_val| {
  14229                 return sema.addConstant(
  14230                     resolved_type,
  14231                     try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, mod),
  14232                 );
  14233             } else break :rs rhs_src;
  14234         } else break :rs lhs_src;
  14235     };
  14236 
  14237     try sema.requireRuntimeBlock(block, src, runtime_src);
  14238 
  14239     if (block.wantSafety()) {
  14240         try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
  14241     }
  14242 
  14243     const air_tag = airTag(block, is_int, .mod, .mod_optimized);
  14244     return block.addBinOp(air_tag, casted_lhs, casted_rhs);
  14245 }
  14246 
  14247 fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  14248     const mod = sema.mod;
  14249     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  14250     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  14251     sema.src = src;
  14252     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  14253     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  14254     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  14255     const lhs = try sema.resolveInst(extra.lhs);
  14256     const rhs = try sema.resolveInst(extra.rhs);
  14257     const lhs_ty = sema.typeOf(lhs);
  14258     const rhs_ty = sema.typeOf(rhs);
  14259     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
  14260     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
  14261     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  14262     try sema.checkInvalidPtrArithmetic(block, src, lhs_ty);
  14263 
  14264     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  14265     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  14266         .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
  14267     });
  14268 
  14269     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  14270     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  14271 
  14272     const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod);
  14273 
  14274     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  14275 
  14276     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .rem);
  14277 
  14278     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
  14279     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
  14280 
  14281     const runtime_src = rs: {
  14282         // For integers:
  14283         // Either operand being undef is a compile error because there exists
  14284         // a possible value (TODO what is it?) that would invoke illegal behavior.
  14285         // TODO: can lhs zero be handled better?
  14286         // TODO: can lhs undef be handled better?
  14287         //
  14288         // For floats:
  14289         // If the rhs is zero, compile error for division by zero.
  14290         // If the rhs is undefined, compile error because there is a possible
  14291         // value (zero) for which the division would be illegal behavior.
  14292         // If the lhs is undefined, result is undefined.
  14293         if (is_int) {
  14294             if (maybe_lhs_val) |lhs_val| {
  14295                 if (lhs_val.isUndef(mod)) {
  14296                     return sema.failWithUseOfUndef(block, lhs_src);
  14297                 }
  14298             }
  14299             if (maybe_rhs_val) |rhs_val| {
  14300                 if (rhs_val.isUndef(mod)) {
  14301                     return sema.failWithUseOfUndef(block, rhs_src);
  14302                 }
  14303                 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
  14304                     return sema.failWithDivideByZero(block, rhs_src);
  14305                 }
  14306                 if (maybe_lhs_val) |lhs_val| {
  14307                     return sema.addConstant(
  14308                         resolved_type,
  14309                         try sema.intRem(resolved_type, lhs_val, rhs_val),
  14310                     );
  14311                 }
  14312                 break :rs lhs_src;
  14313             } else {
  14314                 break :rs rhs_src;
  14315             }
  14316         }
  14317         // float operands
  14318         if (maybe_rhs_val) |rhs_val| {
  14319             if (rhs_val.isUndef(mod)) {
  14320                 return sema.failWithUseOfUndef(block, rhs_src);
  14321             }
  14322             if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
  14323                 return sema.failWithDivideByZero(block, rhs_src);
  14324             }
  14325         }
  14326         if (maybe_lhs_val) |lhs_val| {
  14327             if (lhs_val.isUndef(mod)) {
  14328                 return sema.addConstUndef(resolved_type);
  14329             }
  14330             if (maybe_rhs_val) |rhs_val| {
  14331                 return sema.addConstant(
  14332                     resolved_type,
  14333                     try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, mod),
  14334                 );
  14335             } else break :rs rhs_src;
  14336         } else break :rs lhs_src;
  14337     };
  14338 
  14339     try sema.requireRuntimeBlock(block, src, runtime_src);
  14340 
  14341     if (block.wantSafety()) {
  14342         try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
  14343     }
  14344 
  14345     const air_tag = airTag(block, is_int, .rem, .rem_optimized);
  14346     return block.addBinOp(air_tag, casted_lhs, casted_rhs);
  14347 }
  14348 
  14349 fn zirOverflowArithmetic(
  14350     sema: *Sema,
  14351     block: *Block,
  14352     extended: Zir.Inst.Extended.InstData,
  14353     zir_tag: Zir.Inst.Extended,
  14354 ) CompileError!Air.Inst.Ref {
  14355     const tracy = trace(@src());
  14356     defer tracy.end();
  14357 
  14358     const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
  14359     const src = LazySrcLoc.nodeOffset(extra.node);
  14360 
  14361     const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  14362     const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  14363 
  14364     const uncasted_lhs = try sema.resolveInst(extra.lhs);
  14365     const uncasted_rhs = try sema.resolveInst(extra.rhs);
  14366 
  14367     const lhs_ty = sema.typeOf(uncasted_lhs);
  14368     const rhs_ty = sema.typeOf(uncasted_rhs);
  14369     const mod = sema.mod;
  14370 
  14371     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  14372 
  14373     const instructions = &[_]Air.Inst.Ref{ uncasted_lhs, uncasted_rhs };
  14374     const dest_ty = if (zir_tag == .shl_with_overflow)
  14375         lhs_ty
  14376     else
  14377         try sema.resolvePeerTypes(block, src, instructions, .{
  14378             .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
  14379         });
  14380 
  14381     const rhs_dest_ty = if (zir_tag == .shl_with_overflow)
  14382         try sema.log2IntType(block, lhs_ty, src)
  14383     else
  14384         dest_ty;
  14385 
  14386     const lhs = try sema.coerce(block, dest_ty, uncasted_lhs, lhs_src);
  14387     const rhs = try sema.coerce(block, rhs_dest_ty, uncasted_rhs, rhs_src);
  14388 
  14389     if (dest_ty.scalarType(mod).zigTypeTag(mod) != .Int) {
  14390         return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(mod)});
  14391     }
  14392 
  14393     const maybe_lhs_val = try sema.resolveMaybeUndefVal(lhs);
  14394     const maybe_rhs_val = try sema.resolveMaybeUndefVal(rhs);
  14395 
  14396     const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty);
  14397     const overflow_ty = mod.intern_pool.indexToKey(tuple_ty.toIntern()).anon_struct_type.types[1].toType();
  14398 
  14399     var result: struct {
  14400         inst: Air.Inst.Ref = .none,
  14401         wrapped: Value = Value.@"unreachable",
  14402         overflow_bit: Value,
  14403     } = result: {
  14404         const zero_bit = try mod.intValue(Type.u1, 0);
  14405         switch (zir_tag) {
  14406             .add_with_overflow => {
  14407                 // If either of the arguments is zero, `false` is returned and the other is stored
  14408                 // to the result, even if it is undefined..
  14409                 // Otherwise, if either of the argument is undefined, undefined is returned.
  14410                 if (maybe_lhs_val) |lhs_val| {
  14411                     if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
  14412                         break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs };
  14413                     }
  14414                 }
  14415                 if (maybe_rhs_val) |rhs_val| {
  14416                     if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
  14417                         break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
  14418                     }
  14419                 }
  14420                 if (maybe_lhs_val) |lhs_val| {
  14421                     if (maybe_rhs_val) |rhs_val| {
  14422                         if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) {
  14423                             break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
  14424                         }
  14425 
  14426                         const result = try sema.intAddWithOverflow(lhs_val, rhs_val, dest_ty);
  14427                         break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result };
  14428                     }
  14429                 }
  14430             },
  14431             .sub_with_overflow => {
  14432                 // If the rhs is zero, then the result is lhs and no overflow occured.
  14433                 // Otherwise, if either result is undefined, both results are undefined.
  14434                 if (maybe_rhs_val) |rhs_val| {
  14435                     if (rhs_val.isUndef(mod)) {
  14436                         break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
  14437                     } else if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  14438                         break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
  14439                     } else if (maybe_lhs_val) |lhs_val| {
  14440                         if (lhs_val.isUndef(mod)) {
  14441                             break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
  14442                         }
  14443 
  14444                         const result = try sema.intSubWithOverflow(lhs_val, rhs_val, dest_ty);
  14445                         break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result };
  14446                     }
  14447                 }
  14448             },
  14449             .mul_with_overflow => {
  14450                 // If either of the arguments is zero, the result is zero and no overflow occured.
  14451                 // If either of the arguments is one, the result is the other and no overflow occured.
  14452                 // Otherwise, if either of the arguments is undefined, both results are undefined.
  14453                 const scalar_one = try mod.intValue(dest_ty.scalarType(mod), 1);
  14454                 if (maybe_lhs_val) |lhs_val| {
  14455                     if (!lhs_val.isUndef(mod)) {
  14456                         if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  14457                             break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
  14458                         } else if (try sema.compareAll(lhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) {
  14459                             break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs };
  14460                         }
  14461                     }
  14462                 }
  14463 
  14464                 if (maybe_rhs_val) |rhs_val| {
  14465                     if (!rhs_val.isUndef(mod)) {
  14466                         if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  14467                             break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs };
  14468                         } else if (try sema.compareAll(rhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) {
  14469                             break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
  14470                         }
  14471                     }
  14472                 }
  14473 
  14474                 if (maybe_lhs_val) |lhs_val| {
  14475                     if (maybe_rhs_val) |rhs_val| {
  14476                         if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) {
  14477                             break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
  14478                         }
  14479 
  14480                         const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, mod);
  14481                         break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result };
  14482                     }
  14483                 }
  14484             },
  14485             .shl_with_overflow => {
  14486                 // If lhs is zero, the result is zero and no overflow occurred.
  14487                 // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred.
  14488                 // Oterhwise if either of the arguments is undefined, both results are undefined.
  14489                 if (maybe_lhs_val) |lhs_val| {
  14490                     if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
  14491                         break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
  14492                     }
  14493                 }
  14494                 if (maybe_rhs_val) |rhs_val| {
  14495                     if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
  14496                         break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
  14497                     }
  14498                 }
  14499                 if (maybe_lhs_val) |lhs_val| {
  14500                     if (maybe_rhs_val) |rhs_val| {
  14501                         if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) {
  14502                             break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
  14503                         }
  14504 
  14505                         const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, sema.mod);
  14506                         break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result };
  14507                     }
  14508                 }
  14509             },
  14510             else => unreachable,
  14511         }
  14512 
  14513         const air_tag: Air.Inst.Tag = switch (zir_tag) {
  14514             .add_with_overflow => .add_with_overflow,
  14515             .mul_with_overflow => .mul_with_overflow,
  14516             .sub_with_overflow => .sub_with_overflow,
  14517             .shl_with_overflow => .shl_with_overflow,
  14518             else => unreachable,
  14519         };
  14520 
  14521         const runtime_src = if (maybe_lhs_val == null) lhs_src else rhs_src;
  14522         try sema.requireRuntimeBlock(block, src, runtime_src);
  14523 
  14524         return block.addInst(.{
  14525             .tag = air_tag,
  14526             .data = .{ .ty_pl = .{
  14527                 .ty = try block.sema.addType(tuple_ty),
  14528                 .payload = try block.sema.addExtra(Air.Bin{
  14529                     .lhs = lhs,
  14530                     .rhs = rhs,
  14531                 }),
  14532             } },
  14533         });
  14534     };
  14535 
  14536     if (result.inst != .none) {
  14537         if (try sema.resolveMaybeUndefVal(result.inst)) |some| {
  14538             result.wrapped = some;
  14539             result.inst = .none;
  14540         }
  14541     }
  14542 
  14543     if (result.inst == .none) {
  14544         return sema.addConstant(tuple_ty, (try mod.intern(.{ .aggregate = .{
  14545             .ty = tuple_ty.toIntern(),
  14546             .storage = .{ .elems = &.{
  14547                 result.wrapped.toIntern(),
  14548                 result.overflow_bit.toIntern(),
  14549             } },
  14550         } })).toValue());
  14551     }
  14552 
  14553     const element_refs = try sema.arena.alloc(Air.Inst.Ref, 2);
  14554     element_refs[0] = result.inst;
  14555     element_refs[1] = try sema.addConstant(tuple_ty.structFieldType(1, mod), result.overflow_bit);
  14556     return block.addAggregateInit(tuple_ty, element_refs);
  14557 }
  14558 
  14559 fn splat(sema: *Sema, ty: Type, val: Value) !Value {
  14560     const mod = sema.mod;
  14561     if (ty.zigTypeTag(mod) != .Vector) return val;
  14562     const repeated = try mod.intern(.{ .aggregate = .{
  14563         .ty = ty.toIntern(),
  14564         .storage = .{ .repeated_elem = val.toIntern() },
  14565     } });
  14566     return repeated.toValue();
  14567 }
  14568 
  14569 fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type {
  14570     const mod = sema.mod;
  14571     const ov_ty = if (ty.zigTypeTag(mod) == .Vector) try mod.vectorType(.{
  14572         .len = ty.vectorLen(mod),
  14573         .child = .u1_type,
  14574     }) else Type.u1;
  14575 
  14576     const types = [2]InternPool.Index{ ty.toIntern(), ov_ty.toIntern() };
  14577     const values = [2]InternPool.Index{ .none, .none };
  14578     const tuple_ty = try mod.intern(.{ .anon_struct_type = .{
  14579         .types = &types,
  14580         .values = &values,
  14581         .names = &.{},
  14582     } });
  14583     return tuple_ty.toType();
  14584 }
  14585 
  14586 fn analyzeArithmetic(
  14587     sema: *Sema,
  14588     block: *Block,
  14589     /// TODO performance investigation: make this comptime?
  14590     zir_tag: Zir.Inst.Tag,
  14591     lhs: Air.Inst.Ref,
  14592     rhs: Air.Inst.Ref,
  14593     src: LazySrcLoc,
  14594     lhs_src: LazySrcLoc,
  14595     rhs_src: LazySrcLoc,
  14596     want_safety: bool,
  14597 ) CompileError!Air.Inst.Ref {
  14598     const mod = sema.mod;
  14599     const lhs_ty = sema.typeOf(lhs);
  14600     const rhs_ty = sema.typeOf(rhs);
  14601     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
  14602     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
  14603     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  14604 
  14605     if (lhs_zig_ty_tag == .Pointer) switch (lhs_ty.ptrSize(mod)) {
  14606         .One, .Slice => {},
  14607         .Many, .C => {
  14608             const air_tag: Air.Inst.Tag = switch (zir_tag) {
  14609                 .add => .ptr_add,
  14610                 .sub => .ptr_sub,
  14611                 else => return sema.fail(block, src, "invalid pointer arithmetic operator", .{}),
  14612             };
  14613             return sema.analyzePtrArithmetic(block, src, lhs, rhs, air_tag, lhs_src, rhs_src);
  14614         },
  14615     };
  14616 
  14617     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  14618     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
  14619         .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
  14620     });
  14621 
  14622     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  14623     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  14624 
  14625     const scalar_type = resolved_type.scalarType(mod);
  14626     const scalar_tag = scalar_type.zigTypeTag(mod);
  14627 
  14628     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  14629 
  14630     try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, zir_tag);
  14631 
  14632     const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
  14633     const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
  14634     const rs: struct { src: LazySrcLoc, air_tag: Air.Inst.Tag } = rs: {
  14635         switch (zir_tag) {
  14636             .add, .add_unsafe => {
  14637                 // For integers:intAddSat
  14638                 // If either of the operands are zero, then the other operand is
  14639                 // returned, even if it is undefined.
  14640                 // If either of the operands are undefined, it's a compile error
  14641                 // because there is a possible value for which the addition would
  14642                 // overflow (max_int), causing illegal behavior.
  14643                 // For floats: either operand being undef makes the result undef.
  14644                 if (maybe_lhs_val) |lhs_val| {
  14645                     if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
  14646                         return casted_rhs;
  14647                     }
  14648                 }
  14649                 if (maybe_rhs_val) |rhs_val| {
  14650                     if (rhs_val.isUndef(mod)) {
  14651                         if (is_int) {
  14652                             return sema.failWithUseOfUndef(block, rhs_src);
  14653                         } else {
  14654                             return sema.addConstUndef(resolved_type);
  14655                         }
  14656                     }
  14657                     if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  14658                         return casted_lhs;
  14659                     }
  14660                 }
  14661                 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .add_optimized else .add;
  14662                 if (maybe_lhs_val) |lhs_val| {
  14663                     if (lhs_val.isUndef(mod)) {
  14664                         if (is_int) {
  14665                             return sema.failWithUseOfUndef(block, lhs_src);
  14666                         } else {
  14667                             return sema.addConstUndef(resolved_type);
  14668                         }
  14669                     }
  14670                     if (maybe_rhs_val) |rhs_val| {
  14671                         if (is_int) {
  14672                             const sum = try sema.intAdd(lhs_val, rhs_val, resolved_type);
  14673                             var vector_index: usize = undefined;
  14674                             if (!(try sema.intFitsInType(sum, resolved_type, &vector_index))) {
  14675                                 return sema.failWithIntegerOverflow(block, src, resolved_type, sum, vector_index);
  14676                             }
  14677                             return sema.addConstant(resolved_type, sum);
  14678                         } else {
  14679                             return sema.addConstant(
  14680                                 resolved_type,
  14681                                 try Value.floatAdd(lhs_val, rhs_val, resolved_type, sema.arena, mod),
  14682                             );
  14683                         }
  14684                     } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
  14685                 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
  14686             },
  14687             .addwrap => {
  14688                 // Integers only; floats are checked above.
  14689                 // If either of the operands are zero, the other operand is returned.
  14690                 // If either of the operands are undefined, the result is undefined.
  14691                 if (maybe_lhs_val) |lhs_val| {
  14692                     if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
  14693                         return casted_rhs;
  14694                     }
  14695                 }
  14696                 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .addwrap_optimized else .addwrap;
  14697                 if (maybe_rhs_val) |rhs_val| {
  14698                     if (rhs_val.isUndef(mod)) {
  14699                         return sema.addConstUndef(resolved_type);
  14700                     }
  14701                     if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  14702                         return casted_lhs;
  14703                     }
  14704                     if (maybe_lhs_val) |lhs_val| {
  14705                         return sema.addConstant(
  14706                             resolved_type,
  14707                             try sema.numberAddWrapScalar(lhs_val, rhs_val, resolved_type),
  14708                         );
  14709                     } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
  14710                 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
  14711             },
  14712             .add_sat => {
  14713                 // Integers only; floats are checked above.
  14714                 // If either of the operands are zero, then the other operand is returned.
  14715                 // If either of the operands are undefined, the result is undefined.
  14716                 if (maybe_lhs_val) |lhs_val| {
  14717                     if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
  14718                         return casted_rhs;
  14719                     }
  14720                 }
  14721                 if (maybe_rhs_val) |rhs_val| {
  14722                     if (rhs_val.isUndef(mod)) {
  14723                         return sema.addConstUndef(resolved_type);
  14724                     }
  14725                     if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  14726                         return casted_lhs;
  14727                     }
  14728                     if (maybe_lhs_val) |lhs_val| {
  14729                         const val = if (scalar_tag == .ComptimeInt)
  14730                             try sema.intAdd(lhs_val, rhs_val, resolved_type)
  14731                         else
  14732                             try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, mod);
  14733 
  14734                         return sema.addConstant(resolved_type, val);
  14735                     } else break :rs .{ .src = lhs_src, .air_tag = .add_sat };
  14736                 } else break :rs .{ .src = rhs_src, .air_tag = .add_sat };
  14737             },
  14738             .sub => {
  14739                 // For integers:
  14740                 // If the rhs is zero, then the other operand is
  14741                 // returned, even if it is undefined.
  14742                 // If either of the operands are undefined, it's a compile error
  14743                 // because there is a possible value for which the subtraction would
  14744                 // overflow, causing illegal behavior.
  14745                 // For floats: either operand being undef makes the result undef.
  14746                 if (maybe_rhs_val) |rhs_val| {
  14747                     if (rhs_val.isUndef(mod)) {
  14748                         if (is_int) {
  14749                             return sema.failWithUseOfUndef(block, rhs_src);
  14750                         } else {
  14751                             return sema.addConstUndef(resolved_type);
  14752                         }
  14753                     }
  14754                     if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  14755                         return casted_lhs;
  14756                     }
  14757                 }
  14758                 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .sub_optimized else .sub;
  14759                 if (maybe_lhs_val) |lhs_val| {
  14760                     if (lhs_val.isUndef(mod)) {
  14761                         if (is_int) {
  14762                             return sema.failWithUseOfUndef(block, lhs_src);
  14763                         } else {
  14764                             return sema.addConstUndef(resolved_type);
  14765                         }
  14766                     }
  14767                     if (maybe_rhs_val) |rhs_val| {
  14768                         if (is_int) {
  14769                             const diff = try sema.intSub(lhs_val, rhs_val, resolved_type);
  14770                             var vector_index: usize = undefined;
  14771                             if (!(try sema.intFitsInType(diff, resolved_type, &vector_index))) {
  14772                                 return sema.failWithIntegerOverflow(block, src, resolved_type, diff, vector_index);
  14773                             }
  14774                             return sema.addConstant(resolved_type, diff);
  14775                         } else {
  14776                             return sema.addConstant(
  14777                                 resolved_type,
  14778                                 try Value.floatSub(lhs_val, rhs_val, resolved_type, sema.arena, mod),
  14779                             );
  14780                         }
  14781                     } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
  14782                 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
  14783             },
  14784             .subwrap => {
  14785                 // Integers only; floats are checked above.
  14786                 // If the RHS is zero, then the other operand is returned, even if it is undefined.
  14787                 // If either of the operands are undefined, the result is undefined.
  14788                 if (maybe_rhs_val) |rhs_val| {
  14789                     if (rhs_val.isUndef(mod)) {
  14790                         return sema.addConstUndef(resolved_type);
  14791                     }
  14792                     if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  14793                         return casted_lhs;
  14794                     }
  14795                 }
  14796                 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .subwrap_optimized else .subwrap;
  14797                 if (maybe_lhs_val) |lhs_val| {
  14798                     if (lhs_val.isUndef(mod)) {
  14799                         return sema.addConstUndef(resolved_type);
  14800                     }
  14801                     if (maybe_rhs_val) |rhs_val| {
  14802                         return sema.addConstant(
  14803                             resolved_type,
  14804                             try sema.numberSubWrapScalar(lhs_val, rhs_val, resolved_type),
  14805                         );
  14806                     } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
  14807                 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
  14808             },
  14809             .sub_sat => {
  14810                 // Integers only; floats are checked above.
  14811                 // If the RHS is zero, result is LHS.
  14812                 // If either of the operands are undefined, result is undefined.
  14813                 if (maybe_rhs_val) |rhs_val| {
  14814                     if (rhs_val.isUndef(mod)) {
  14815                         return sema.addConstUndef(resolved_type);
  14816                     }
  14817                     if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  14818                         return casted_lhs;
  14819                     }
  14820                 }
  14821                 if (maybe_lhs_val) |lhs_val| {
  14822                     if (lhs_val.isUndef(mod)) {
  14823                         return sema.addConstUndef(resolved_type);
  14824                     }
  14825                     if (maybe_rhs_val) |rhs_val| {
  14826                         const val = if (scalar_tag == .ComptimeInt)
  14827                             try sema.intSub(lhs_val, rhs_val, resolved_type)
  14828                         else
  14829                             try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, mod);
  14830 
  14831                         return sema.addConstant(resolved_type, val);
  14832                     } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat };
  14833                 } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat };
  14834             },
  14835             .mul => {
  14836                 // For integers:
  14837                 // If either of the operands are zero, the result is zero.
  14838                 // If either of the operands are one, the result is the other
  14839                 // operand, even if it is undefined.
  14840                 // If either of the operands are undefined, it's a compile error
  14841                 // because there is a possible value for which the addition would
  14842                 // overflow (max_int), causing illegal behavior.
  14843                 // For floats: either operand being undef makes the result undef.
  14844                 // If either of the operands are inf, and the other operand is zero,
  14845                 // the result is nan.
  14846                 // If either of the operands are nan, the result is nan.
  14847                 const scalar_zero = switch (scalar_tag) {
  14848                     .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 0.0),
  14849                     .ComptimeInt, .Int => try mod.intValue(scalar_type, 0),
  14850                     else => unreachable,
  14851                 };
  14852                 const scalar_one = switch (scalar_tag) {
  14853                     .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 1.0),
  14854                     .ComptimeInt, .Int => try mod.intValue(scalar_type, 1),
  14855                     else => unreachable,
  14856                 };
  14857                 if (maybe_lhs_val) |lhs_val| {
  14858                     if (!lhs_val.isUndef(mod)) {
  14859                         if (lhs_val.isNan(mod)) {
  14860                             return sema.addConstant(resolved_type, lhs_val);
  14861                         }
  14862                         if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) lz: {
  14863                             if (maybe_rhs_val) |rhs_val| {
  14864                                 if (rhs_val.isNan(mod)) {
  14865                                     return sema.addConstant(resolved_type, rhs_val);
  14866                                 }
  14867                                 if (rhs_val.isInf(mod)) {
  14868                                     return sema.addConstant(
  14869                                         resolved_type,
  14870                                         try mod.floatValue(resolved_type, std.math.nan_f128),
  14871                                     );
  14872                                 }
  14873                             } else if (resolved_type.isAnyFloat()) {
  14874                                 break :lz;
  14875                             }
  14876                             const zero_val = try sema.splat(resolved_type, scalar_zero);
  14877                             return sema.addConstant(resolved_type, zero_val);
  14878                         }
  14879                         if (try sema.compareAll(lhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
  14880                             return casted_rhs;
  14881                         }
  14882                     }
  14883                 }
  14884                 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mul_optimized else .mul;
  14885                 if (maybe_rhs_val) |rhs_val| {
  14886                     if (rhs_val.isUndef(mod)) {
  14887                         if (is_int) {
  14888                             return sema.failWithUseOfUndef(block, rhs_src);
  14889                         } else {
  14890                             return sema.addConstUndef(resolved_type);
  14891                         }
  14892                     }
  14893                     if (rhs_val.isNan(mod)) {
  14894                         return sema.addConstant(resolved_type, rhs_val);
  14895                     }
  14896                     if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) rz: {
  14897                         if (maybe_lhs_val) |lhs_val| {
  14898                             if (lhs_val.isInf(mod)) {
  14899                                 return sema.addConstant(
  14900                                     resolved_type,
  14901                                     try mod.floatValue(resolved_type, std.math.nan_f128),
  14902                                 );
  14903                             }
  14904                         } else if (resolved_type.isAnyFloat()) {
  14905                             break :rz;
  14906                         }
  14907                         const zero_val = try sema.splat(resolved_type, scalar_zero);
  14908                         return sema.addConstant(resolved_type, zero_val);
  14909                     }
  14910                     if (try sema.compareAll(rhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
  14911                         return casted_lhs;
  14912                     }
  14913                     if (maybe_lhs_val) |lhs_val| {
  14914                         if (lhs_val.isUndef(mod)) {
  14915                             if (is_int) {
  14916                                 return sema.failWithUseOfUndef(block, lhs_src);
  14917                             } else {
  14918                                 return sema.addConstUndef(resolved_type);
  14919                             }
  14920                         }
  14921                         if (is_int) {
  14922                             const product = try lhs_val.intMul(rhs_val, resolved_type, sema.arena, sema.mod);
  14923                             var vector_index: usize = undefined;
  14924                             if (!(try sema.intFitsInType(product, resolved_type, &vector_index))) {
  14925                                 return sema.failWithIntegerOverflow(block, src, resolved_type, product, vector_index);
  14926                             }
  14927                             return sema.addConstant(resolved_type, product);
  14928                         } else {
  14929                             return sema.addConstant(
  14930                                 resolved_type,
  14931                                 try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, sema.mod),
  14932                             );
  14933                         }
  14934                     } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
  14935                 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
  14936             },
  14937             .mulwrap => {
  14938                 // Integers only; floats are handled above.
  14939                 // If either of the operands are zero, result is zero.
  14940                 // If either of the operands are one, result is the other operand.
  14941                 // If either of the operands are undefined, result is undefined.
  14942                 const scalar_zero = switch (scalar_tag) {
  14943                     .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 0.0),
  14944                     .ComptimeInt, .Int => try mod.intValue(scalar_type, 0),
  14945                     else => unreachable,
  14946                 };
  14947                 const scalar_one = switch (scalar_tag) {
  14948                     .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 1.0),
  14949                     .ComptimeInt, .Int => try mod.intValue(scalar_type, 1),
  14950                     else => unreachable,
  14951                 };
  14952                 if (maybe_lhs_val) |lhs_val| {
  14953                     if (!lhs_val.isUndef(mod)) {
  14954                         if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  14955                             const zero_val = try sema.splat(resolved_type, scalar_zero);
  14956                             return sema.addConstant(resolved_type, zero_val);
  14957                         }
  14958                         if (try sema.compareAll(lhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
  14959                             return casted_rhs;
  14960                         }
  14961                     }
  14962                 }
  14963                 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mulwrap_optimized else .mulwrap;
  14964                 if (maybe_rhs_val) |rhs_val| {
  14965                     if (rhs_val.isUndef(mod)) {
  14966                         return sema.addConstUndef(resolved_type);
  14967                     }
  14968                     if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  14969                         const zero_val = try sema.splat(resolved_type, scalar_zero);
  14970                         return sema.addConstant(resolved_type, zero_val);
  14971                     }
  14972                     if (try sema.compareAll(rhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
  14973                         return casted_lhs;
  14974                     }
  14975                     if (maybe_lhs_val) |lhs_val| {
  14976                         if (lhs_val.isUndef(mod)) {
  14977                             return sema.addConstUndef(resolved_type);
  14978                         }
  14979                         return sema.addConstant(
  14980                             resolved_type,
  14981                             try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, sema.mod),
  14982                         );
  14983                     } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
  14984                 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
  14985             },
  14986             .mul_sat => {
  14987                 // Integers only; floats are checked above.
  14988                 // If either of the operands are zero, result is zero.
  14989                 // If either of the operands are one, result is the other operand.
  14990                 // If either of the operands are undefined, result is undefined.
  14991                 const scalar_zero = switch (scalar_tag) {
  14992                     .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 0.0),
  14993                     .ComptimeInt, .Int => try mod.intValue(scalar_type, 0),
  14994                     else => unreachable,
  14995                 };
  14996                 const scalar_one = switch (scalar_tag) {
  14997                     .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 1.0),
  14998                     .ComptimeInt, .Int => try mod.intValue(scalar_type, 1),
  14999                     else => unreachable,
  15000                 };
  15001                 if (maybe_lhs_val) |lhs_val| {
  15002                     if (!lhs_val.isUndef(mod)) {
  15003                         if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  15004                             const zero_val = try sema.splat(resolved_type, scalar_zero);
  15005                             return sema.addConstant(resolved_type, zero_val);
  15006                         }
  15007                         if (try sema.compareAll(lhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
  15008                             return casted_rhs;
  15009                         }
  15010                     }
  15011                 }
  15012                 if (maybe_rhs_val) |rhs_val| {
  15013                     if (rhs_val.isUndef(mod)) {
  15014                         return sema.addConstUndef(resolved_type);
  15015                     }
  15016                     if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
  15017                         const zero_val = try sema.splat(resolved_type, scalar_zero);
  15018                         return sema.addConstant(resolved_type, zero_val);
  15019                     }
  15020                     if (try sema.compareAll(rhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
  15021                         return casted_lhs;
  15022                     }
  15023                     if (maybe_lhs_val) |lhs_val| {
  15024                         if (lhs_val.isUndef(mod)) {
  15025                             return sema.addConstUndef(resolved_type);
  15026                         }
  15027 
  15028                         const val = if (scalar_tag == .ComptimeInt)
  15029                             try lhs_val.intMul(rhs_val, resolved_type, sema.arena, sema.mod)
  15030                         else
  15031                             try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, sema.mod);
  15032 
  15033                         return sema.addConstant(resolved_type, val);
  15034                     } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat };
  15035                 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat };
  15036             },
  15037             else => unreachable,
  15038         }
  15039     };
  15040 
  15041     try sema.requireRuntimeBlock(block, src, rs.src);
  15042     if (block.wantSafety() and want_safety) {
  15043         if (scalar_tag == .Int) {
  15044             const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) {
  15045                 .add => .add_with_overflow,
  15046                 .sub => .sub_with_overflow,
  15047                 .mul => .mul_with_overflow,
  15048                 else => null,
  15049             };
  15050             if (maybe_op_ov) |op_ov_tag| {
  15051                 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(resolved_type);
  15052                 const op_ov = try block.addInst(.{
  15053                     .tag = op_ov_tag,
  15054                     .data = .{ .ty_pl = .{
  15055                         .ty = try sema.addType(op_ov_tuple_ty),
  15056                         .payload = try sema.addExtra(Air.Bin{
  15057                             .lhs = casted_lhs,
  15058                             .rhs = casted_rhs,
  15059                         }),
  15060                     } },
  15061                 });
  15062                 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
  15063                 const any_ov_bit = if (resolved_type.zigTypeTag(mod) == .Vector)
  15064                     try block.addInst(.{
  15065                         .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
  15066                         .data = .{ .reduce = .{
  15067                             .operand = ov_bit,
  15068                             .operation = .Or,
  15069                         } },
  15070                     })
  15071                 else
  15072                     ov_bit;
  15073                 const zero_ov = try sema.addConstant(Type.u1, try mod.intValue(Type.u1, 0));
  15074                 const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
  15075 
  15076                 try sema.addSafetyCheck(block, no_ov, .integer_overflow);
  15077                 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
  15078             }
  15079         }
  15080     }
  15081     return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs);
  15082 }
  15083 
  15084 fn analyzePtrArithmetic(
  15085     sema: *Sema,
  15086     block: *Block,
  15087     op_src: LazySrcLoc,
  15088     ptr: Air.Inst.Ref,
  15089     uncasted_offset: Air.Inst.Ref,
  15090     air_tag: Air.Inst.Tag,
  15091     ptr_src: LazySrcLoc,
  15092     offset_src: LazySrcLoc,
  15093 ) CompileError!Air.Inst.Ref {
  15094     // TODO if the operand is comptime-known to be negative, or is a negative int,
  15095     // coerce to isize instead of usize.
  15096     const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src);
  15097     const mod = sema.mod;
  15098     const opt_ptr_val = try sema.resolveMaybeUndefVal(ptr);
  15099     const opt_off_val = try sema.resolveDefinedValue(block, offset_src, offset);
  15100     const ptr_ty = sema.typeOf(ptr);
  15101     const ptr_info = ptr_ty.ptrInfo(mod);
  15102     assert(ptr_info.size == .Many or ptr_info.size == .C);
  15103 
  15104     const new_ptr_ty = t: {
  15105         // Calculate the new pointer alignment.
  15106         // This code is duplicated in `elemPtrType`.
  15107         if (ptr_info.@"align" == 0) {
  15108             // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness.
  15109             break :t ptr_ty;
  15110         }
  15111         // If the addend is not a comptime-known value we can still count on
  15112         // it being a multiple of the type size.
  15113         const elem_size = ptr_info.pointee_type.abiSize(mod);
  15114         const addend = if (opt_off_val) |off_val| a: {
  15115             const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(mod));
  15116             break :a elem_size * off_int;
  15117         } else elem_size;
  15118 
  15119         // The resulting pointer is aligned to the lcd between the offset (an
  15120         // arbitrary number) and the alignment factor (always a power of two,
  15121         // non zero).
  15122         const new_align = @as(u32, 1) << @intCast(u5, @ctz(addend | ptr_info.@"align"));
  15123 
  15124         break :t try Type.ptr(sema.arena, sema.mod, .{
  15125             .pointee_type = ptr_info.pointee_type,
  15126             .sentinel = ptr_info.sentinel,
  15127             .@"align" = new_align,
  15128             .@"addrspace" = ptr_info.@"addrspace",
  15129             .mutable = ptr_info.mutable,
  15130             .@"allowzero" = ptr_info.@"allowzero",
  15131             .@"volatile" = ptr_info.@"volatile",
  15132             .size = ptr_info.size,
  15133         });
  15134     };
  15135 
  15136     const runtime_src = rs: {
  15137         if (opt_ptr_val) |ptr_val| {
  15138             if (opt_off_val) |offset_val| {
  15139                 if (ptr_val.isUndef(mod)) return sema.addConstUndef(new_ptr_ty);
  15140 
  15141                 const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(mod));
  15142                 if (offset_int == 0) return ptr;
  15143                 if (try ptr_val.getUnsignedIntAdvanced(mod, sema)) |addr| {
  15144                     const elem_size = ptr_info.pointee_type.abiSize(mod);
  15145                     const new_addr = switch (air_tag) {
  15146                         .ptr_add => addr + elem_size * offset_int,
  15147                         .ptr_sub => addr - elem_size * offset_int,
  15148                         else => unreachable,
  15149                     };
  15150                     const new_ptr_val = try mod.ptrIntValue(new_ptr_ty, new_addr);
  15151                     return sema.addConstant(new_ptr_ty, new_ptr_val);
  15152                 }
  15153                 if (air_tag == .ptr_sub) {
  15154                     return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{});
  15155                 }
  15156                 const new_ptr_val = try ptr_val.elemPtr(new_ptr_ty, offset_int, sema.mod);
  15157                 return sema.addConstant(new_ptr_ty, new_ptr_val);
  15158             } else break :rs offset_src;
  15159         } else break :rs ptr_src;
  15160     };
  15161 
  15162     try sema.requireRuntimeBlock(block, op_src, runtime_src);
  15163     return block.addInst(.{
  15164         .tag = air_tag,
  15165         .data = .{ .ty_pl = .{
  15166             .ty = try sema.addType(new_ptr_ty),
  15167             .payload = try sema.addExtra(Air.Bin{
  15168                 .lhs = ptr,
  15169                 .rhs = offset,
  15170             }),
  15171         } },
  15172     });
  15173 }
  15174 
  15175 fn zirLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  15176     const tracy = trace(@src());
  15177     defer tracy.end();
  15178 
  15179     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15180     const src = inst_data.src();
  15181     const ptr_src = src; // TODO better source location
  15182     const ptr = try sema.resolveInst(inst_data.operand);
  15183     return sema.analyzeLoad(block, src, ptr, ptr_src);
  15184 }
  15185 
  15186 fn zirAsm(
  15187     sema: *Sema,
  15188     block: *Block,
  15189     extended: Zir.Inst.Extended.InstData,
  15190     tmpl_is_expr: bool,
  15191 ) CompileError!Air.Inst.Ref {
  15192     const tracy = trace(@src());
  15193     defer tracy.end();
  15194 
  15195     const extra = sema.code.extraData(Zir.Inst.Asm, extended.operand);
  15196     const src = LazySrcLoc.nodeOffset(extra.data.src_node);
  15197     const ret_ty_src: LazySrcLoc = .{ .node_offset_asm_ret_ty = extra.data.src_node };
  15198     const outputs_len = @truncate(u5, extended.small);
  15199     const inputs_len = @truncate(u5, extended.small >> 5);
  15200     const clobbers_len = @truncate(u5, extended.small >> 10);
  15201     const is_volatile = @truncate(u1, extended.small >> 15) != 0;
  15202     const is_global_assembly = sema.func_index == .none;
  15203 
  15204     const asm_source: []const u8 = if (tmpl_is_expr) blk: {
  15205         const tmpl = @intToEnum(Zir.Inst.Ref, extra.data.asm_source);
  15206         const s: []const u8 = try sema.resolveConstString(block, src, tmpl, "assembly code must be comptime-known");
  15207         break :blk s;
  15208     } else sema.code.nullTerminatedString(extra.data.asm_source);
  15209 
  15210     if (is_global_assembly) {
  15211         if (outputs_len != 0) {
  15212             return sema.fail(block, src, "module-level assembly does not support outputs", .{});
  15213         }
  15214         if (inputs_len != 0) {
  15215             return sema.fail(block, src, "module-level assembly does not support inputs", .{});
  15216         }
  15217         if (clobbers_len != 0) {
  15218             return sema.fail(block, src, "module-level assembly does not support clobbers", .{});
  15219         }
  15220         if (is_volatile) {
  15221             return sema.fail(block, src, "volatile keyword is redundant on module-level assembly", .{});
  15222         }
  15223         try sema.mod.addGlobalAssembly(sema.owner_decl_index, asm_source);
  15224         return Air.Inst.Ref.void_value;
  15225     }
  15226 
  15227     if (block.is_comptime) {
  15228         try sema.requireRuntimeBlock(block, src, null);
  15229     }
  15230 
  15231     var extra_i = extra.end;
  15232     var output_type_bits = extra.data.output_type_bits;
  15233     var needed_capacity: usize = @typeInfo(Air.Asm).Struct.fields.len + outputs_len + inputs_len;
  15234 
  15235     const ConstraintName = struct { c: []const u8, n: []const u8 };
  15236     const out_args = try sema.arena.alloc(Air.Inst.Ref, outputs_len);
  15237     const outputs = try sema.arena.alloc(ConstraintName, outputs_len);
  15238     var expr_ty = Air.Inst.Ref.void_type;
  15239 
  15240     for (out_args, 0..) |*arg, out_i| {
  15241         const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i);
  15242         extra_i = output.end;
  15243 
  15244         const is_type = @truncate(u1, output_type_bits) != 0;
  15245         output_type_bits >>= 1;
  15246 
  15247         if (is_type) {
  15248             // Indicate the output is the asm instruction return value.
  15249             arg.* = .none;
  15250             const out_ty = try sema.resolveType(block, ret_ty_src, output.data.operand);
  15251             try sema.queueFullTypeResolution(out_ty);
  15252             expr_ty = try sema.addType(out_ty);
  15253         } else {
  15254             arg.* = try sema.resolveInst(output.data.operand);
  15255         }
  15256 
  15257         const constraint = sema.code.nullTerminatedString(output.data.constraint);
  15258         const name = sema.code.nullTerminatedString(output.data.name);
  15259         needed_capacity += (constraint.len + name.len + (2 + 3)) / 4;
  15260 
  15261         outputs[out_i] = .{ .c = constraint, .n = name };
  15262     }
  15263 
  15264     const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len);
  15265     const inputs = try sema.arena.alloc(ConstraintName, inputs_len);
  15266     const mod = sema.mod;
  15267 
  15268     for (args, 0..) |*arg, arg_i| {
  15269         const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i);
  15270         extra_i = input.end;
  15271 
  15272         const uncasted_arg = try sema.resolveInst(input.data.operand);
  15273         const uncasted_arg_ty = sema.typeOf(uncasted_arg);
  15274         switch (uncasted_arg_ty.zigTypeTag(mod)) {
  15275             .ComptimeInt => arg.* = try sema.coerce(block, Type.usize, uncasted_arg, src),
  15276             .ComptimeFloat => arg.* = try sema.coerce(block, Type.f64, uncasted_arg, src),
  15277             else => {
  15278                 arg.* = uncasted_arg;
  15279                 try sema.queueFullTypeResolution(uncasted_arg_ty);
  15280             },
  15281         }
  15282 
  15283         const constraint = sema.code.nullTerminatedString(input.data.constraint);
  15284         const name = sema.code.nullTerminatedString(input.data.name);
  15285         needed_capacity += (constraint.len + name.len + (2 + 3)) / 4;
  15286         inputs[arg_i] = .{ .c = constraint, .n = name };
  15287     }
  15288 
  15289     const clobbers = try sema.arena.alloc([]const u8, clobbers_len);
  15290     for (clobbers) |*name| {
  15291         name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
  15292         extra_i += 1;
  15293 
  15294         needed_capacity += name.*.len / 4 + 1;
  15295     }
  15296 
  15297     needed_capacity += (asm_source.len + 3) / 4;
  15298 
  15299     const gpa = sema.gpa;
  15300     try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity);
  15301     const asm_air = try block.addInst(.{
  15302         .tag = .assembly,
  15303         .data = .{ .ty_pl = .{
  15304             .ty = expr_ty,
  15305             .payload = sema.addExtraAssumeCapacity(Air.Asm{
  15306                 .source_len = @intCast(u32, asm_source.len),
  15307                 .outputs_len = outputs_len,
  15308                 .inputs_len = @intCast(u32, args.len),
  15309                 .flags = (@as(u32, @boolToInt(is_volatile)) << 31) | @intCast(u32, clobbers.len),
  15310             }),
  15311         } },
  15312     });
  15313     sema.appendRefsAssumeCapacity(out_args);
  15314     sema.appendRefsAssumeCapacity(args);
  15315     for (outputs) |o| {
  15316         const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
  15317         @memcpy(buffer[0..o.c.len], o.c);
  15318         buffer[o.c.len] = 0;
  15319         @memcpy(buffer[o.c.len + 1 ..][0..o.n.len], o.n);
  15320         buffer[o.c.len + 1 + o.n.len] = 0;
  15321         sema.air_extra.items.len += (o.c.len + o.n.len + (2 + 3)) / 4;
  15322     }
  15323     for (inputs) |input| {
  15324         const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
  15325         @memcpy(buffer[0..input.c.len], input.c);
  15326         buffer[input.c.len] = 0;
  15327         @memcpy(buffer[input.c.len + 1 ..][0..input.n.len], input.n);
  15328         buffer[input.c.len + 1 + input.n.len] = 0;
  15329         sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4;
  15330     }
  15331     for (clobbers) |clobber| {
  15332         const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
  15333         @memcpy(buffer[0..clobber.len], clobber);
  15334         buffer[clobber.len] = 0;
  15335         sema.air_extra.items.len += clobber.len / 4 + 1;
  15336     }
  15337     {
  15338         const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
  15339         @memcpy(buffer[0..asm_source.len], asm_source);
  15340         sema.air_extra.items.len += (asm_source.len + 3) / 4;
  15341     }
  15342     return asm_air;
  15343 }
  15344 
  15345 /// Only called for equality operators. See also `zirCmp`.
  15346 fn zirCmpEq(
  15347     sema: *Sema,
  15348     block: *Block,
  15349     inst: Zir.Inst.Index,
  15350     op: std.math.CompareOperator,
  15351     air_tag: Air.Inst.Tag,
  15352 ) CompileError!Air.Inst.Ref {
  15353     const tracy = trace(@src());
  15354     defer tracy.end();
  15355 
  15356     const mod = sema.mod;
  15357     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  15358     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  15359     const src: LazySrcLoc = inst_data.src();
  15360     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  15361     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  15362     const lhs = try sema.resolveInst(extra.lhs);
  15363     const rhs = try sema.resolveInst(extra.rhs);
  15364 
  15365     const lhs_ty = sema.typeOf(lhs);
  15366     const rhs_ty = sema.typeOf(rhs);
  15367     const lhs_ty_tag = lhs_ty.zigTypeTag(mod);
  15368     const rhs_ty_tag = rhs_ty.zigTypeTag(mod);
  15369     if (lhs_ty_tag == .Null and rhs_ty_tag == .Null) {
  15370         // null == null, null != null
  15371         if (op == .eq) {
  15372             return Air.Inst.Ref.bool_true;
  15373         } else {
  15374             return Air.Inst.Ref.bool_false;
  15375         }
  15376     }
  15377 
  15378     // comparing null with optionals
  15379     if (lhs_ty_tag == .Null and (rhs_ty_tag == .Optional or rhs_ty.isCPtr(mod))) {
  15380         return sema.analyzeIsNull(block, src, rhs, op == .neq);
  15381     }
  15382     if (rhs_ty_tag == .Null and (lhs_ty_tag == .Optional or lhs_ty.isCPtr(mod))) {
  15383         return sema.analyzeIsNull(block, src, lhs, op == .neq);
  15384     }
  15385 
  15386     if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {
  15387         const non_null_type = if (lhs_ty_tag == .Null) rhs_ty else lhs_ty;
  15388         return sema.fail(block, src, "comparison of '{}' with null", .{non_null_type.fmt(sema.mod)});
  15389     }
  15390 
  15391     if (lhs_ty_tag == .Union and (rhs_ty_tag == .EnumLiteral or rhs_ty_tag == .Enum)) {
  15392         return sema.analyzeCmpUnionTag(block, src, lhs, lhs_src, rhs, rhs_src, op);
  15393     }
  15394     if (rhs_ty_tag == .Union and (lhs_ty_tag == .EnumLiteral or lhs_ty_tag == .Enum)) {
  15395         return sema.analyzeCmpUnionTag(block, src, rhs, rhs_src, lhs, lhs_src, op);
  15396     }
  15397 
  15398     if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {
  15399         const runtime_src: LazySrcLoc = src: {
  15400             if (try sema.resolveMaybeUndefVal(lhs)) |lval| {
  15401                 if (try sema.resolveMaybeUndefVal(rhs)) |rval| {
  15402                     if (lval.isUndef(mod) or rval.isUndef(mod)) {
  15403                         return sema.addConstUndef(Type.bool);
  15404                     }
  15405                     const lkey = mod.intern_pool.indexToKey(lval.toIntern());
  15406                     const rkey = mod.intern_pool.indexToKey(rval.toIntern());
  15407                     if ((lkey.err.name == rkey.err.name) == (op == .eq)) {
  15408                         return Air.Inst.Ref.bool_true;
  15409                     } else {
  15410                         return Air.Inst.Ref.bool_false;
  15411                     }
  15412                 } else {
  15413                     break :src rhs_src;
  15414                 }
  15415             } else {
  15416                 break :src lhs_src;
  15417             }
  15418         };
  15419         try sema.requireRuntimeBlock(block, src, runtime_src);
  15420         return block.addBinOp(air_tag, lhs, rhs);
  15421     }
  15422     if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {
  15423         const lhs_as_type = try sema.analyzeAsType(block, lhs_src, lhs);
  15424         const rhs_as_type = try sema.analyzeAsType(block, rhs_src, rhs);
  15425         if (lhs_as_type.eql(rhs_as_type, sema.mod) == (op == .eq)) {
  15426             return Air.Inst.Ref.bool_true;
  15427         } else {
  15428             return Air.Inst.Ref.bool_false;
  15429         }
  15430     }
  15431     return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, true);
  15432 }
  15433 
  15434 fn analyzeCmpUnionTag(
  15435     sema: *Sema,
  15436     block: *Block,
  15437     src: LazySrcLoc,
  15438     un: Air.Inst.Ref,
  15439     un_src: LazySrcLoc,
  15440     tag: Air.Inst.Ref,
  15441     tag_src: LazySrcLoc,
  15442     op: std.math.CompareOperator,
  15443 ) CompileError!Air.Inst.Ref {
  15444     const mod = sema.mod;
  15445     const union_ty = try sema.resolveTypeFields(sema.typeOf(un));
  15446     const union_tag_ty = union_ty.unionTagType(mod) orelse {
  15447         const msg = msg: {
  15448             const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
  15449             errdefer msg.destroy(sema.gpa);
  15450             try sema.mod.errNoteNonLazy(union_ty.declSrcLoc(sema.mod), msg, "union '{}' is not a tagged union", .{union_ty.fmt(sema.mod)});
  15451             break :msg msg;
  15452         };
  15453         return sema.failWithOwnedErrorMsg(msg);
  15454     };
  15455     // Coerce both the union and the tag to the union's tag type, and then execute the
  15456     // enum comparison codepath.
  15457     const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src);
  15458     const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src);
  15459 
  15460     if (try sema.resolveMaybeUndefVal(coerced_tag)) |enum_val| {
  15461         if (enum_val.isUndef(mod)) return sema.addConstUndef(Type.bool);
  15462         const field_ty = union_ty.unionFieldType(enum_val, sema.mod);
  15463         if (field_ty.zigTypeTag(mod) == .NoReturn) {
  15464             return Air.Inst.Ref.bool_false;
  15465         }
  15466     }
  15467 
  15468     return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src);
  15469 }
  15470 
  15471 /// Only called for non-equality operators. See also `zirCmpEq`.
  15472 fn zirCmp(
  15473     sema: *Sema,
  15474     block: *Block,
  15475     inst: Zir.Inst.Index,
  15476     op: std.math.CompareOperator,
  15477 ) CompileError!Air.Inst.Ref {
  15478     const tracy = trace(@src());
  15479     defer tracy.end();
  15480 
  15481     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  15482     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  15483     const src: LazySrcLoc = inst_data.src();
  15484     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  15485     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  15486     const lhs = try sema.resolveInst(extra.lhs);
  15487     const rhs = try sema.resolveInst(extra.rhs);
  15488     return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, false);
  15489 }
  15490 
  15491 fn analyzeCmp(
  15492     sema: *Sema,
  15493     block: *Block,
  15494     src: LazySrcLoc,
  15495     lhs: Air.Inst.Ref,
  15496     rhs: Air.Inst.Ref,
  15497     op: std.math.CompareOperator,
  15498     lhs_src: LazySrcLoc,
  15499     rhs_src: LazySrcLoc,
  15500     is_equality_cmp: bool,
  15501 ) CompileError!Air.Inst.Ref {
  15502     const mod = sema.mod;
  15503     const lhs_ty = sema.typeOf(lhs);
  15504     const rhs_ty = sema.typeOf(rhs);
  15505     if (lhs_ty.zigTypeTag(mod) != .Optional and rhs_ty.zigTypeTag(mod) != .Optional) {
  15506         try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  15507     }
  15508 
  15509     if (lhs_ty.zigTypeTag(mod) == .Vector and rhs_ty.zigTypeTag(mod) == .Vector) {
  15510         return sema.cmpVector(block, src, lhs, rhs, op, lhs_src, rhs_src);
  15511     }
  15512     if (lhs_ty.isNumeric(mod) and rhs_ty.isNumeric(mod)) {
  15513         // This operation allows any combination of integer and float types, regardless of the
  15514         // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for
  15515         // numeric types.
  15516         return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src);
  15517     }
  15518     if (is_equality_cmp and lhs_ty.zigTypeTag(mod) == .ErrorUnion and rhs_ty.zigTypeTag(mod) == .ErrorSet) {
  15519         const casted_lhs = try sema.analyzeErrUnionCode(block, lhs_src, lhs);
  15520         return sema.cmpSelf(block, src, casted_lhs, rhs, op, lhs_src, rhs_src);
  15521     }
  15522     if (is_equality_cmp and lhs_ty.zigTypeTag(mod) == .ErrorSet and rhs_ty.zigTypeTag(mod) == .ErrorUnion) {
  15523         const casted_rhs = try sema.analyzeErrUnionCode(block, rhs_src, rhs);
  15524         return sema.cmpSelf(block, src, lhs, casted_rhs, op, lhs_src, rhs_src);
  15525     }
  15526     const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
  15527     const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } });
  15528     if (!resolved_type.isSelfComparable(mod, is_equality_cmp)) {
  15529         return sema.fail(block, src, "operator {s} not allowed for type '{}'", .{
  15530             compareOperatorName(op), resolved_type.fmt(sema.mod),
  15531         });
  15532     }
  15533     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
  15534     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
  15535     return sema.cmpSelf(block, src, casted_lhs, casted_rhs, op, lhs_src, rhs_src);
  15536 }
  15537 
  15538 fn compareOperatorName(comp: std.math.CompareOperator) []const u8 {
  15539     return switch (comp) {
  15540         .lt => "<",
  15541         .lte => "<=",
  15542         .eq => "==",
  15543         .gte => ">=",
  15544         .gt => ">",
  15545         .neq => "!=",
  15546     };
  15547 }
  15548 
  15549 fn cmpSelf(
  15550     sema: *Sema,
  15551     block: *Block,
  15552     src: LazySrcLoc,
  15553     casted_lhs: Air.Inst.Ref,
  15554     casted_rhs: Air.Inst.Ref,
  15555     op: std.math.CompareOperator,
  15556     lhs_src: LazySrcLoc,
  15557     rhs_src: LazySrcLoc,
  15558 ) CompileError!Air.Inst.Ref {
  15559     const mod = sema.mod;
  15560     const resolved_type = sema.typeOf(casted_lhs);
  15561     const runtime_src: LazySrcLoc = src: {
  15562         if (try sema.resolveMaybeUndefVal(casted_lhs)) |lhs_val| {
  15563             if (lhs_val.isUndef(mod)) return sema.addConstUndef(Type.bool);
  15564             if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| {
  15565                 if (rhs_val.isUndef(mod)) return sema.addConstUndef(Type.bool);
  15566 
  15567                 if (resolved_type.zigTypeTag(mod) == .Vector) {
  15568                     const result_ty = try mod.vectorType(.{
  15569                         .len = resolved_type.vectorLen(mod),
  15570                         .child = .bool_type,
  15571                     });
  15572                     const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_type);
  15573                     return sema.addConstant(result_ty, cmp_val);
  15574                 }
  15575 
  15576                 if (try sema.compareAll(lhs_val, op, rhs_val, resolved_type)) {
  15577                     return Air.Inst.Ref.bool_true;
  15578                 } else {
  15579                     return Air.Inst.Ref.bool_false;
  15580                 }
  15581             } else {
  15582                 if (resolved_type.zigTypeTag(mod) == .Bool) {
  15583                     // We can lower bool eq/neq more efficiently.
  15584                     return sema.runtimeBoolCmp(block, src, op, casted_rhs, lhs_val.toBool(), rhs_src);
  15585                 }
  15586                 break :src rhs_src;
  15587             }
  15588         } else {
  15589             // For bools, we still check the other operand, because we can lower
  15590             // bool eq/neq more efficiently.
  15591             if (resolved_type.zigTypeTag(mod) == .Bool) {
  15592                 if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| {
  15593                     if (rhs_val.isUndef(mod)) return sema.addConstUndef(Type.bool);
  15594                     return sema.runtimeBoolCmp(block, src, op, casted_lhs, rhs_val.toBool(), lhs_src);
  15595                 }
  15596             }
  15597             break :src lhs_src;
  15598         }
  15599     };
  15600     try sema.requireRuntimeBlock(block, src, runtime_src);
  15601     if (resolved_type.zigTypeTag(mod) == .Vector) {
  15602         return block.addCmpVector(casted_lhs, casted_rhs, op);
  15603     }
  15604     const tag = Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized);
  15605     return block.addBinOp(tag, casted_lhs, casted_rhs);
  15606 }
  15607 
  15608 /// cmp_eq (x, false) => not(x)
  15609 /// cmp_eq (x, true ) => x
  15610 /// cmp_neq(x, false) => x
  15611 /// cmp_neq(x, true ) => not(x)
  15612 fn runtimeBoolCmp(
  15613     sema: *Sema,
  15614     block: *Block,
  15615     src: LazySrcLoc,
  15616     op: std.math.CompareOperator,
  15617     lhs: Air.Inst.Ref,
  15618     rhs: bool,
  15619     runtime_src: LazySrcLoc,
  15620 ) CompileError!Air.Inst.Ref {
  15621     if ((op == .neq) == rhs) {
  15622         try sema.requireRuntimeBlock(block, src, runtime_src);
  15623         return block.addTyOp(.not, Type.bool, lhs);
  15624     } else {
  15625         return lhs;
  15626     }
  15627 }
  15628 
  15629 fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  15630     const mod = sema.mod;
  15631     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15632     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  15633     const ty = try sema.resolveType(block, operand_src, inst_data.operand);
  15634     switch (ty.zigTypeTag(mod)) {
  15635         .Fn,
  15636         .NoReturn,
  15637         .Undefined,
  15638         .Null,
  15639         .Opaque,
  15640         => return sema.fail(block, operand_src, "no size available for type '{}'", .{ty.fmt(sema.mod)}),
  15641 
  15642         .Type,
  15643         .EnumLiteral,
  15644         .ComptimeFloat,
  15645         .ComptimeInt,
  15646         .Void,
  15647         => return sema.addIntUnsigned(Type.comptime_int, 0),
  15648 
  15649         .Bool,
  15650         .Int,
  15651         .Float,
  15652         .Pointer,
  15653         .Array,
  15654         .Struct,
  15655         .Optional,
  15656         .ErrorUnion,
  15657         .ErrorSet,
  15658         .Enum,
  15659         .Union,
  15660         .Vector,
  15661         .Frame,
  15662         .AnyFrame,
  15663         => {},
  15664     }
  15665     const val = try ty.lazyAbiSize(mod);
  15666     if (val.isLazySize(mod)) {
  15667         try sema.queueFullTypeResolution(ty);
  15668     }
  15669     return sema.addConstant(Type.comptime_int, val);
  15670 }
  15671 
  15672 fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  15673     const mod = sema.mod;
  15674     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15675     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  15676     const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand);
  15677     switch (operand_ty.zigTypeTag(mod)) {
  15678         .Fn,
  15679         .NoReturn,
  15680         .Undefined,
  15681         .Null,
  15682         .Opaque,
  15683         => return sema.fail(block, operand_src, "no size available for type '{}'", .{operand_ty.fmt(sema.mod)}),
  15684 
  15685         .Type,
  15686         .EnumLiteral,
  15687         .ComptimeFloat,
  15688         .ComptimeInt,
  15689         .Void,
  15690         => return sema.addIntUnsigned(Type.comptime_int, 0),
  15691 
  15692         .Bool,
  15693         .Int,
  15694         .Float,
  15695         .Pointer,
  15696         .Array,
  15697         .Struct,
  15698         .Optional,
  15699         .ErrorUnion,
  15700         .ErrorSet,
  15701         .Enum,
  15702         .Union,
  15703         .Vector,
  15704         .Frame,
  15705         .AnyFrame,
  15706         => {},
  15707     }
  15708     const bit_size = try operand_ty.bitSizeAdvanced(mod, sema);
  15709     return sema.addIntUnsigned(Type.comptime_int, bit_size);
  15710 }
  15711 
  15712 fn zirThis(
  15713     sema: *Sema,
  15714     block: *Block,
  15715     extended: Zir.Inst.Extended.InstData,
  15716 ) CompileError!Air.Inst.Ref {
  15717     const mod = sema.mod;
  15718     const this_decl_index = mod.namespaceDeclIndex(block.namespace);
  15719     const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
  15720     return sema.analyzeDeclVal(block, src, this_decl_index);
  15721 }
  15722 
  15723 fn zirClosureCapture(
  15724     sema: *Sema,
  15725     block: *Block,
  15726     inst: Zir.Inst.Index,
  15727 ) CompileError!void {
  15728     // TODO: Compile error when closed over values are modified
  15729     const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
  15730     // Closures are not necessarily constant values. For example, the
  15731     // code might do something like this:
  15732     // fn foo(x: anytype) void { const S = struct {field: @TypeOf(x)}; }
  15733     // ...in which case the closure_capture instruction has access to a runtime
  15734     // value only. In such case we preserve the type and use a dummy runtime value.
  15735     const operand = try sema.resolveInst(inst_data.operand);
  15736     const ty = sema.typeOf(operand);
  15737     const capture: CaptureScope.Capture = blk: {
  15738         if (try sema.resolveMaybeUndefValAllowVariables(operand)) |val| {
  15739             const ip_index = try val.intern(ty, sema.mod);
  15740             break :blk .{ .comptime_val = ip_index };
  15741         }
  15742         break :blk .{ .runtime_val = ty.toIntern() };
  15743     };
  15744     try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, capture);
  15745 }
  15746 
  15747 fn zirClosureGet(
  15748     sema: *Sema,
  15749     block: *Block,
  15750     inst: Zir.Inst.Index,
  15751 ) CompileError!Air.Inst.Ref {
  15752     const mod = sema.mod;
  15753     // TODO CLOSURE: Test this with inline functions
  15754     const inst_data = sema.code.instructions.items(.data)[inst].inst_node;
  15755     var scope: *CaptureScope = mod.declPtr(block.src_decl).src_scope.?;
  15756     // Note: The target closure must be in this scope list.
  15757     // If it's not here, the zir is invalid, or the list is broken.
  15758     const capture = while (true) {
  15759         // Note: We don't need to add a dependency here, because
  15760         // decls always depend on their lexical parents.
  15761 
  15762         // Fail this decl if a scope it depended on failed.
  15763         if (scope.failed()) {
  15764             if (sema.owner_func) |owner_func| {
  15765                 owner_func.state = .dependency_failure;
  15766             } else {
  15767                 sema.owner_decl.analysis = .dependency_failure;
  15768             }
  15769             return error.AnalysisFail;
  15770         }
  15771         if (scope.captures.get(inst_data.inst)) |capture| {
  15772             break capture;
  15773         }
  15774         scope = scope.parent.?;
  15775     };
  15776 
  15777     if (capture == .runtime_val and !block.is_typeof and sema.func_index == .none) {
  15778         const msg = msg: {
  15779             const name = name: {
  15780                 const file = sema.owner_decl.getFileScope(mod);
  15781                 const tree = file.getTree(sema.gpa) catch |err| {
  15782                     // In this case we emit a warning + a less precise source location.
  15783                     log.warn("unable to load {s}: {s}", .{
  15784                         file.sub_file_path, @errorName(err),
  15785                     });
  15786                     break :name null;
  15787                 };
  15788                 const node = sema.owner_decl.relativeToNodeIndex(inst_data.src_node);
  15789                 const token = tree.nodes.items(.main_token)[node];
  15790                 break :name tree.tokenSlice(token);
  15791             };
  15792 
  15793             const msg = if (name) |some|
  15794                 try sema.errMsg(block, inst_data.src(), "'{s}' not accessible outside function scope", .{some})
  15795             else
  15796                 try sema.errMsg(block, inst_data.src(), "variable not accessible outside function scope", .{});
  15797             errdefer msg.destroy(sema.gpa);
  15798 
  15799             // TODO add "declared here" note
  15800             break :msg msg;
  15801         };
  15802         return sema.failWithOwnedErrorMsg(msg);
  15803     }
  15804 
  15805     if (capture == .runtime_val and !block.is_typeof and !block.is_comptime and sema.func_index != .none) {
  15806         const msg = msg: {
  15807             const name = name: {
  15808                 const file = sema.owner_decl.getFileScope(mod);
  15809                 const tree = file.getTree(sema.gpa) catch |err| {
  15810                     // In this case we emit a warning + a less precise source location.
  15811                     log.warn("unable to load {s}: {s}", .{
  15812                         file.sub_file_path, @errorName(err),
  15813                     });
  15814                     break :name null;
  15815                 };
  15816                 const node = sema.owner_decl.relativeToNodeIndex(inst_data.src_node);
  15817                 const token = tree.nodes.items(.main_token)[node];
  15818                 break :name tree.tokenSlice(token);
  15819             };
  15820 
  15821             const msg = if (name) |some|
  15822                 try sema.errMsg(block, inst_data.src(), "'{s}' not accessible from inner function", .{some})
  15823             else
  15824                 try sema.errMsg(block, inst_data.src(), "variable not accessible from inner function", .{});
  15825             errdefer msg.destroy(sema.gpa);
  15826 
  15827             try sema.errNote(block, LazySrcLoc.nodeOffset(0), msg, "crossed function definition here", .{});
  15828 
  15829             // TODO add "declared here" note
  15830             break :msg msg;
  15831         };
  15832         return sema.failWithOwnedErrorMsg(msg);
  15833     }
  15834 
  15835     switch (capture) {
  15836         .runtime_val => |ty_ip_index| {
  15837             assert(block.is_typeof);
  15838             // We need a dummy runtime instruction with the correct type.
  15839             return block.addTy(.alloc, ty_ip_index.toType());
  15840         },
  15841         .comptime_val => |val_ip_index| {
  15842             const ty = mod.intern_pool.typeOf(val_ip_index).toType();
  15843             return sema.addConstant(ty, val_ip_index.toValue());
  15844         },
  15845     }
  15846 }
  15847 
  15848 fn zirRetAddr(
  15849     sema: *Sema,
  15850     block: *Block,
  15851     extended: Zir.Inst.Extended.InstData,
  15852 ) CompileError!Air.Inst.Ref {
  15853     _ = extended;
  15854     if (block.is_comptime) {
  15855         // TODO: we could give a meaningful lazy value here. #14938
  15856         return sema.addIntUnsigned(Type.usize, 0);
  15857     } else {
  15858         return block.addNoOp(.ret_addr);
  15859     }
  15860 }
  15861 
  15862 fn zirFrameAddress(
  15863     sema: *Sema,
  15864     block: *Block,
  15865     extended: Zir.Inst.Extended.InstData,
  15866 ) CompileError!Air.Inst.Ref {
  15867     const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
  15868     try sema.requireRuntimeBlock(block, src, null);
  15869     return try block.addNoOp(.frame_addr);
  15870 }
  15871 
  15872 fn zirBuiltinSrc(
  15873     sema: *Sema,
  15874     block: *Block,
  15875     extended: Zir.Inst.Extended.InstData,
  15876 ) CompileError!Air.Inst.Ref {
  15877     const tracy = trace(@src());
  15878     defer tracy.end();
  15879 
  15880     const mod = sema.mod;
  15881     const extra = sema.code.extraData(Zir.Inst.Src, extended.operand).data;
  15882     const src = LazySrcLoc.nodeOffset(extra.node);
  15883     const func = sema.func orelse return sema.fail(block, src, "@src outside function", .{});
  15884     const fn_owner_decl = mod.declPtr(func.owner_decl);
  15885 
  15886     const func_name_val = blk: {
  15887         var anon_decl = try block.startAnonDecl();
  15888         defer anon_decl.deinit();
  15889         const name = mem.span(fn_owner_decl.name);
  15890         const new_decl_ty = try mod.arrayType(.{
  15891             .len = name.len,
  15892             .child = .u8_type,
  15893             .sentinel = .zero_u8,
  15894         });
  15895         const new_decl = try anon_decl.finish(
  15896             new_decl_ty,
  15897             (try mod.intern(.{ .aggregate = .{
  15898                 .ty = new_decl_ty.toIntern(),
  15899                 .storage = .{ .bytes = name },
  15900             } })).toValue(),
  15901             0, // default alignment
  15902         );
  15903         break :blk try mod.intern(.{ .ptr = .{
  15904             .ty = .slice_const_u8_sentinel_0_type,
  15905             .addr = .{ .decl = new_decl },
  15906             .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
  15907         } });
  15908     };
  15909 
  15910     const file_name_val = blk: {
  15911         var anon_decl = try block.startAnonDecl();
  15912         defer anon_decl.deinit();
  15913         // The compiler must not call realpath anywhere.
  15914         const name = try fn_owner_decl.getFileScope(mod).fullPathZ(anon_decl.arena());
  15915         const new_decl_ty = try mod.arrayType(.{
  15916             .len = name.len,
  15917             .child = .u8_type,
  15918             .sentinel = .zero_u8,
  15919         });
  15920         const new_decl = try anon_decl.finish(
  15921             new_decl_ty,
  15922             (try mod.intern(.{ .aggregate = .{
  15923                 .ty = new_decl_ty.toIntern(),
  15924                 .storage = .{ .bytes = name },
  15925             } })).toValue(),
  15926             0, // default alignment
  15927         );
  15928         break :blk try mod.intern(.{ .ptr = .{
  15929             .ty = .slice_const_u8_sentinel_0_type,
  15930             .addr = .{ .decl = new_decl },
  15931             .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
  15932         } });
  15933     };
  15934 
  15935     const src_loc_ty = try sema.getBuiltinType("SourceLocation");
  15936     const fields = .{
  15937         // file: [:0]const u8,
  15938         file_name_val,
  15939         // fn_name: [:0]const u8,
  15940         func_name_val,
  15941         // line: u32,
  15942         try mod.intern(.{ .runtime_value = .{
  15943             .ty = .u32_type,
  15944             .val = (try mod.intValue(Type.u32, extra.line + 1)).toIntern(),
  15945         } }),
  15946         // column: u32,
  15947         (try mod.intValue(Type.u32, extra.column + 1)).toIntern(),
  15948     };
  15949     return sema.addConstant(src_loc_ty, (try mod.intern(.{ .aggregate = .{
  15950         .ty = src_loc_ty.toIntern(),
  15951         .storage = .{ .elems = &fields },
  15952     } })).toValue());
  15953 }
  15954 
  15955 fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  15956     const mod = sema.mod;
  15957     const gpa = sema.gpa;
  15958     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  15959     const src = inst_data.src();
  15960     const ty = try sema.resolveType(block, src, inst_data.operand);
  15961     const type_info_ty = try sema.getBuiltinType("Type");
  15962     const type_info_tag_ty = type_info_ty.unionTagType(mod).?;
  15963 
  15964     switch (ty.zigTypeTag(mod)) {
  15965         .Type,
  15966         .Void,
  15967         .Bool,
  15968         .NoReturn,
  15969         .ComptimeFloat,
  15970         .ComptimeInt,
  15971         .Undefined,
  15972         .Null,
  15973         .EnumLiteral,
  15974         => |type_info_tag| return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
  15975             .ty = type_info_ty.toIntern(),
  15976             .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(type_info_tag))).toIntern(),
  15977             .val = .void_value,
  15978         } })).toValue()),
  15979         .Fn => {
  15980             // TODO: look into memoizing this result.
  15981             var params_anon_decl = try block.startAnonDecl();
  15982             defer params_anon_decl.deinit();
  15983 
  15984             const fn_info_decl_index = (try sema.namespaceLookup(
  15985                 block,
  15986                 src,
  15987                 type_info_ty.getNamespaceIndex(mod).unwrap().?,
  15988                 "Fn",
  15989             )).?;
  15990             try mod.declareDeclDependency(sema.owner_decl_index, fn_info_decl_index);
  15991             try sema.ensureDeclAnalyzed(fn_info_decl_index);
  15992             const fn_info_decl = mod.declPtr(fn_info_decl_index);
  15993             const fn_info_ty = fn_info_decl.val.toType();
  15994 
  15995             const param_info_decl_index = (try sema.namespaceLookup(
  15996                 block,
  15997                 src,
  15998                 fn_info_ty.getNamespaceIndex(mod).unwrap().?,
  15999                 "Param",
  16000             )).?;
  16001             try mod.declareDeclDependency(sema.owner_decl_index, param_info_decl_index);
  16002             try sema.ensureDeclAnalyzed(param_info_decl_index);
  16003             const param_info_decl = mod.declPtr(param_info_decl_index);
  16004             const param_info_ty = param_info_decl.val.toType();
  16005 
  16006             const param_vals = try sema.arena.alloc(InternPool.Index, mod.typeToFunc(ty).?.param_types.len);
  16007             for (param_vals, 0..) |*param_val, i| {
  16008                 const info = mod.typeToFunc(ty).?;
  16009                 const param_ty = info.param_types[i];
  16010                 const is_generic = param_ty == .generic_poison_type;
  16011                 const param_ty_val = try mod.intern_pool.get(gpa, .{ .opt = .{
  16012                     .ty = try mod.intern_pool.get(gpa, .{ .opt_type = .type_type }),
  16013                     .val = if (is_generic) .none else param_ty,
  16014                 } });
  16015 
  16016                 const is_noalias = blk: {
  16017                     const index = std.math.cast(u5, i) orelse break :blk false;
  16018                     break :blk @truncate(u1, info.noalias_bits >> index) != 0;
  16019                 };
  16020 
  16021                 const param_fields = .{
  16022                     // is_generic: bool,
  16023                     Value.makeBool(is_generic).toIntern(),
  16024                     // is_noalias: bool,
  16025                     Value.makeBool(is_noalias).toIntern(),
  16026                     // type: ?type,
  16027                     param_ty_val,
  16028                 };
  16029                 param_val.* = try mod.intern(.{ .aggregate = .{
  16030                     .ty = param_info_ty.toIntern(),
  16031                     .storage = .{ .elems = &param_fields },
  16032                 } });
  16033             }
  16034 
  16035             const args_val = v: {
  16036                 const new_decl_ty = try mod.arrayType(.{
  16037                     .len = param_vals.len,
  16038                     .child = param_info_ty.toIntern(),
  16039                 });
  16040                 const new_decl = try params_anon_decl.finish(
  16041                     new_decl_ty,
  16042                     (try mod.intern(.{ .aggregate = .{
  16043                         .ty = new_decl_ty.toIntern(),
  16044                         .storage = .{ .elems = param_vals },
  16045                     } })).toValue(),
  16046                     0, // default alignment
  16047                 );
  16048                 break :v try mod.intern(.{ .ptr = .{
  16049                     .ty = (try mod.ptrType(.{
  16050                         .child = param_info_ty.toIntern(),
  16051                         .flags = .{
  16052                             .size = .Slice,
  16053                             .is_const = true,
  16054                         },
  16055                     })).toIntern(),
  16056                     .addr = .{ .decl = new_decl },
  16057                     .len = (try mod.intValue(Type.usize, param_vals.len)).toIntern(),
  16058                 } });
  16059             };
  16060 
  16061             const info = mod.typeToFunc(ty).?;
  16062             const ret_ty_opt = try mod.intern(.{ .opt = .{
  16063                 .ty = try mod.intern_pool.get(gpa, .{ .opt_type = .type_type }),
  16064                 .val = if (info.return_type == .generic_poison_type) .none else info.return_type,
  16065             } });
  16066 
  16067             const callconv_ty = try sema.getBuiltinType("CallingConvention");
  16068 
  16069             const field_values = .{
  16070                 // calling_convention: CallingConvention,
  16071                 (try mod.enumValueFieldIndex(callconv_ty, @enumToInt(info.cc))).toIntern(),
  16072                 // alignment: comptime_int,
  16073                 (try mod.intValue(Type.comptime_int, ty.abiAlignment(mod))).toIntern(),
  16074                 // is_generic: bool,
  16075                 Value.makeBool(info.is_generic).toIntern(),
  16076                 // is_var_args: bool,
  16077                 Value.makeBool(info.is_var_args).toIntern(),
  16078                 // return_type: ?type,
  16079                 ret_ty_opt,
  16080                 // args: []const Fn.Param,
  16081                 args_val,
  16082             };
  16083             return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
  16084                 .ty = type_info_ty.toIntern(),
  16085                 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Fn))).toIntern(),
  16086                 .val = try mod.intern(.{ .aggregate = .{
  16087                     .ty = fn_info_ty.toIntern(),
  16088                     .storage = .{ .elems = &field_values },
  16089                 } }),
  16090             } })).toValue());
  16091         },
  16092         .Int => {
  16093             const int_info_decl_index = (try sema.namespaceLookup(
  16094                 block,
  16095                 src,
  16096                 type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16097                 "Int",
  16098             )).?;
  16099             try mod.declareDeclDependency(sema.owner_decl_index, int_info_decl_index);
  16100             try sema.ensureDeclAnalyzed(int_info_decl_index);
  16101             const int_info_decl = mod.declPtr(int_info_decl_index);
  16102             const int_info_ty = int_info_decl.val.toType();
  16103 
  16104             const signedness_ty = try sema.getBuiltinType("Signedness");
  16105             const info = ty.intInfo(mod);
  16106             const field_values = .{
  16107                 // signedness: Signedness,
  16108                 try (try mod.enumValueFieldIndex(signedness_ty, @enumToInt(info.signedness))).intern(signedness_ty, mod),
  16109                 // bits: u16,
  16110                 (try mod.intValue(Type.u16, info.bits)).toIntern(),
  16111             };
  16112             return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
  16113                 .ty = type_info_ty.toIntern(),
  16114                 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Int))).toIntern(),
  16115                 .val = try mod.intern(.{ .aggregate = .{
  16116                     .ty = int_info_ty.toIntern(),
  16117                     .storage = .{ .elems = &field_values },
  16118                 } }),
  16119             } })).toValue());
  16120         },
  16121         .Float => {
  16122             const float_info_decl_index = (try sema.namespaceLookup(
  16123                 block,
  16124                 src,
  16125                 type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16126                 "Float",
  16127             )).?;
  16128             try mod.declareDeclDependency(sema.owner_decl_index, float_info_decl_index);
  16129             try sema.ensureDeclAnalyzed(float_info_decl_index);
  16130             const float_info_decl = mod.declPtr(float_info_decl_index);
  16131             const float_info_ty = float_info_decl.val.toType();
  16132 
  16133             const field_vals = .{
  16134                 // bits: u16,
  16135                 (try mod.intValue(Type.u16, ty.bitSize(mod))).toIntern(),
  16136             };
  16137             return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
  16138                 .ty = type_info_ty.toIntern(),
  16139                 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Float))).toIntern(),
  16140                 .val = try mod.intern(.{ .aggregate = .{
  16141                     .ty = float_info_ty.toIntern(),
  16142                     .storage = .{ .elems = &field_vals },
  16143                 } }),
  16144             } })).toValue());
  16145         },
  16146         .Pointer => {
  16147             const info = ty.ptrInfo(mod);
  16148             const alignment = if (info.@"align" != 0)
  16149                 try mod.intValue(Type.comptime_int, info.@"align")
  16150             else
  16151                 try info.pointee_type.lazyAbiAlignment(mod);
  16152 
  16153             const addrspace_ty = try sema.getBuiltinType("AddressSpace");
  16154             const pointer_ty = t: {
  16155                 const decl_index = (try sema.namespaceLookup(
  16156                     block,
  16157                     src,
  16158                     (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?,
  16159                     "Pointer",
  16160                 )).?;
  16161                 try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
  16162                 try sema.ensureDeclAnalyzed(decl_index);
  16163                 const decl = mod.declPtr(decl_index);
  16164                 break :t decl.val.toType();
  16165             };
  16166             const ptr_size_ty = t: {
  16167                 const decl_index = (try sema.namespaceLookup(
  16168                     block,
  16169                     src,
  16170                     pointer_ty.getNamespaceIndex(mod).unwrap().?,
  16171                     "Size",
  16172                 )).?;
  16173                 try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
  16174                 try sema.ensureDeclAnalyzed(decl_index);
  16175                 const decl = mod.declPtr(decl_index);
  16176                 break :t decl.val.toType();
  16177             };
  16178 
  16179             const field_values = .{
  16180                 // size: Size,
  16181                 try (try mod.enumValueFieldIndex(ptr_size_ty, @enumToInt(info.size))).intern(ptr_size_ty, mod),
  16182                 // is_const: bool,
  16183                 Value.makeBool(!info.mutable).toIntern(),
  16184                 // is_volatile: bool,
  16185                 Value.makeBool(info.@"volatile").toIntern(),
  16186                 // alignment: comptime_int,
  16187                 alignment.toIntern(),
  16188                 // address_space: AddressSpace
  16189                 try (try mod.enumValueFieldIndex(addrspace_ty, @enumToInt(info.@"addrspace"))).intern(addrspace_ty, mod),
  16190                 // child: type,
  16191                 info.pointee_type.toIntern(),
  16192                 // is_allowzero: bool,
  16193                 Value.makeBool(info.@"allowzero").toIntern(),
  16194                 // sentinel: ?*const anyopaque,
  16195                 (try sema.optRefValue(block, info.pointee_type, info.sentinel)).toIntern(),
  16196             };
  16197             return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
  16198                 .ty = type_info_ty.toIntern(),
  16199                 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Pointer))).toIntern(),
  16200                 .val = try mod.intern(.{ .aggregate = .{
  16201                     .ty = pointer_ty.toIntern(),
  16202                     .storage = .{ .elems = &field_values },
  16203                 } }),
  16204             } })).toValue());
  16205         },
  16206         .Array => {
  16207             const array_field_ty = t: {
  16208                 const array_field_ty_decl_index = (try sema.namespaceLookup(
  16209                     block,
  16210                     src,
  16211                     type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16212                     "Array",
  16213                 )).?;
  16214                 try mod.declareDeclDependency(sema.owner_decl_index, array_field_ty_decl_index);
  16215                 try sema.ensureDeclAnalyzed(array_field_ty_decl_index);
  16216                 const array_field_ty_decl = mod.declPtr(array_field_ty_decl_index);
  16217                 break :t array_field_ty_decl.val.toType();
  16218             };
  16219 
  16220             const info = ty.arrayInfo(mod);
  16221             const field_values = .{
  16222                 // len: comptime_int,
  16223                 (try mod.intValue(Type.comptime_int, info.len)).toIntern(),
  16224                 // child: type,
  16225                 info.elem_type.toIntern(),
  16226                 // sentinel: ?*const anyopaque,
  16227                 (try sema.optRefValue(block, info.elem_type, info.sentinel)).toIntern(),
  16228             };
  16229             return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
  16230                 .ty = type_info_ty.toIntern(),
  16231                 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Array))).toIntern(),
  16232                 .val = try mod.intern(.{ .aggregate = .{
  16233                     .ty = array_field_ty.toIntern(),
  16234                     .storage = .{ .elems = &field_values },
  16235                 } }),
  16236             } })).toValue());
  16237         },
  16238         .Vector => {
  16239             const vector_field_ty = t: {
  16240                 const vector_field_ty_decl_index = (try sema.namespaceLookup(
  16241                     block,
  16242                     src,
  16243                     type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16244                     "Vector",
  16245                 )).?;
  16246                 try mod.declareDeclDependency(sema.owner_decl_index, vector_field_ty_decl_index);
  16247                 try sema.ensureDeclAnalyzed(vector_field_ty_decl_index);
  16248                 const vector_field_ty_decl = mod.declPtr(vector_field_ty_decl_index);
  16249                 break :t vector_field_ty_decl.val.toType();
  16250             };
  16251 
  16252             const info = ty.arrayInfo(mod);
  16253             const field_values = .{
  16254                 // len: comptime_int,
  16255                 (try mod.intValue(Type.comptime_int, info.len)).toIntern(),
  16256                 // child: type,
  16257                 info.elem_type.toIntern(),
  16258             };
  16259             return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
  16260                 .ty = type_info_ty.toIntern(),
  16261                 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Vector))).toIntern(),
  16262                 .val = try mod.intern(.{ .aggregate = .{
  16263                     .ty = vector_field_ty.toIntern(),
  16264                     .storage = .{ .elems = &field_values },
  16265                 } }),
  16266             } })).toValue());
  16267         },
  16268         .Optional => {
  16269             const optional_field_ty = t: {
  16270                 const optional_field_ty_decl_index = (try sema.namespaceLookup(
  16271                     block,
  16272                     src,
  16273                     type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16274                     "Optional",
  16275                 )).?;
  16276                 try mod.declareDeclDependency(sema.owner_decl_index, optional_field_ty_decl_index);
  16277                 try sema.ensureDeclAnalyzed(optional_field_ty_decl_index);
  16278                 const optional_field_ty_decl = mod.declPtr(optional_field_ty_decl_index);
  16279                 break :t optional_field_ty_decl.val.toType();
  16280             };
  16281 
  16282             const field_values = .{
  16283                 // child: type,
  16284                 ty.optionalChild(mod).toIntern(),
  16285             };
  16286             return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
  16287                 .ty = type_info_ty.toIntern(),
  16288                 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Optional))).toIntern(),
  16289                 .val = try mod.intern(.{ .aggregate = .{
  16290                     .ty = optional_field_ty.toIntern(),
  16291                     .storage = .{ .elems = &field_values },
  16292                 } }),
  16293             } })).toValue());
  16294         },
  16295         .ErrorSet => {
  16296             var fields_anon_decl = try block.startAnonDecl();
  16297             defer fields_anon_decl.deinit();
  16298 
  16299             // Get the Error type
  16300             const error_field_ty = t: {
  16301                 const set_field_ty_decl_index = (try sema.namespaceLookup(
  16302                     block,
  16303                     src,
  16304                     type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16305                     "Error",
  16306                 )).?;
  16307                 try mod.declareDeclDependency(sema.owner_decl_index, set_field_ty_decl_index);
  16308                 try sema.ensureDeclAnalyzed(set_field_ty_decl_index);
  16309                 const set_field_ty_decl = mod.declPtr(set_field_ty_decl_index);
  16310                 break :t set_field_ty_decl.val.toType();
  16311             };
  16312 
  16313             try sema.queueFullTypeResolution(error_field_ty);
  16314 
  16315             // If the error set is inferred it must be resolved at this point
  16316             try sema.resolveInferredErrorSetTy(block, src, ty);
  16317 
  16318             // Build our list of Error values
  16319             // Optional value is only null if anyerror
  16320             // Value can be zero-length slice otherwise
  16321             const error_field_vals = if (ty.isAnyError(mod)) null else blk: {
  16322                 const names = ty.errorSetNames(mod);
  16323                 const vals = try sema.arena.alloc(InternPool.Index, names.len);
  16324                 for (vals, names) |*field_val, name_ip| {
  16325                     const name = mod.intern_pool.stringToSlice(name_ip);
  16326                     const name_val = v: {
  16327                         var anon_decl = try block.startAnonDecl();
  16328                         defer anon_decl.deinit();
  16329                         const new_decl_ty = try mod.arrayType(.{
  16330                             .len = name.len,
  16331                             .child = .u8_type,
  16332                         });
  16333                         const new_decl = try anon_decl.finish(
  16334                             new_decl_ty,
  16335                             (try mod.intern(.{ .aggregate = .{
  16336                                 .ty = new_decl_ty.toIntern(),
  16337                                 .storage = .{ .bytes = name },
  16338                             } })).toValue(),
  16339                             0, // default alignment
  16340                         );
  16341                         break :v try mod.intern(.{ .ptr = .{
  16342                             .ty = .slice_const_u8_type,
  16343                             .addr = .{ .decl = new_decl },
  16344                             .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
  16345                         } });
  16346                     };
  16347 
  16348                     const error_field_fields = .{
  16349                         // name: []const u8,
  16350                         name_val,
  16351                     };
  16352                     field_val.* = try mod.intern(.{ .aggregate = .{
  16353                         .ty = error_field_ty.toIntern(),
  16354                         .storage = .{ .elems = &error_field_fields },
  16355                     } });
  16356                 }
  16357 
  16358                 break :blk vals;
  16359             };
  16360 
  16361             // Build our ?[]const Error value
  16362             const slice_errors_ty = try mod.ptrType(.{
  16363                 .child = error_field_ty.toIntern(),
  16364                 .flags = .{
  16365                     .size = .Slice,
  16366                     .is_const = true,
  16367                 },
  16368             });
  16369             const opt_slice_errors_ty = try mod.optionalType(slice_errors_ty.toIntern());
  16370             const errors_payload_val: InternPool.Index = if (error_field_vals) |vals| v: {
  16371                 const array_errors_ty = try mod.arrayType(.{
  16372                     .len = vals.len,
  16373                     .child = error_field_ty.toIntern(),
  16374                     .sentinel = .none,
  16375                 });
  16376                 const new_decl = try fields_anon_decl.finish(
  16377                     array_errors_ty,
  16378                     (try mod.intern(.{ .aggregate = .{
  16379                         .ty = array_errors_ty.toIntern(),
  16380                         .storage = .{ .elems = vals },
  16381                     } })).toValue(),
  16382                     0, // default alignment
  16383                 );
  16384                 break :v try mod.intern(.{ .ptr = .{
  16385                     .ty = slice_errors_ty.toIntern(),
  16386                     .addr = .{ .decl = new_decl },
  16387                     .len = (try mod.intValue(Type.usize, vals.len)).toIntern(),
  16388                 } });
  16389             } else .none;
  16390             const errors_val = try mod.intern(.{ .opt = .{
  16391                 .ty = opt_slice_errors_ty.toIntern(),
  16392                 .val = errors_payload_val,
  16393             } });
  16394 
  16395             // Construct Type{ .ErrorSet = errors_val }
  16396             return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
  16397                 .ty = type_info_ty.toIntern(),
  16398                 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ErrorSet))).toIntern(),
  16399                 .val = errors_val,
  16400             } })).toValue());
  16401         },
  16402         .ErrorUnion => {
  16403             const error_union_field_ty = t: {
  16404                 const error_union_field_ty_decl_index = (try sema.namespaceLookup(
  16405                     block,
  16406                     src,
  16407                     type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16408                     "ErrorUnion",
  16409                 )).?;
  16410                 try mod.declareDeclDependency(sema.owner_decl_index, error_union_field_ty_decl_index);
  16411                 try sema.ensureDeclAnalyzed(error_union_field_ty_decl_index);
  16412                 const error_union_field_ty_decl = mod.declPtr(error_union_field_ty_decl_index);
  16413                 break :t error_union_field_ty_decl.val.toType();
  16414             };
  16415 
  16416             const field_values = .{
  16417                 // error_set: type,
  16418                 ty.errorUnionSet(mod).toIntern(),
  16419                 // payload: type,
  16420                 ty.errorUnionPayload(mod).toIntern(),
  16421             };
  16422             return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
  16423                 .ty = type_info_ty.toIntern(),
  16424                 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ErrorUnion))).toIntern(),
  16425                 .val = try mod.intern(.{ .aggregate = .{
  16426                     .ty = error_union_field_ty.toIntern(),
  16427                     .storage = .{ .elems = &field_values },
  16428                 } }),
  16429             } })).toValue());
  16430         },
  16431         .Enum => {
  16432             // TODO: look into memoizing this result.
  16433             const enum_type = mod.intern_pool.indexToKey(ty.toIntern()).enum_type;
  16434 
  16435             const is_exhaustive = Value.makeBool(enum_type.tag_mode != .nonexhaustive);
  16436 
  16437             var fields_anon_decl = try block.startAnonDecl();
  16438             defer fields_anon_decl.deinit();
  16439 
  16440             const enum_field_ty = t: {
  16441                 const enum_field_ty_decl_index = (try sema.namespaceLookup(
  16442                     block,
  16443                     src,
  16444                     type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16445                     "EnumField",
  16446                 )).?;
  16447                 try mod.declareDeclDependency(sema.owner_decl_index, enum_field_ty_decl_index);
  16448                 try sema.ensureDeclAnalyzed(enum_field_ty_decl_index);
  16449                 const enum_field_ty_decl = mod.declPtr(enum_field_ty_decl_index);
  16450                 break :t enum_field_ty_decl.val.toType();
  16451             };
  16452 
  16453             const enum_field_vals = try sema.arena.alloc(InternPool.Index, enum_type.names.len);
  16454             for (enum_field_vals, 0..) |*field_val, i| {
  16455                 const name_ip = mod.intern_pool.indexToKey(ty.toIntern()).enum_type.names[i];
  16456                 const name = mod.intern_pool.stringToSlice(name_ip);
  16457                 const name_val = v: {
  16458                     var anon_decl = try block.startAnonDecl();
  16459                     defer anon_decl.deinit();
  16460                     const new_decl_ty = try mod.arrayType(.{
  16461                         .len = name.len,
  16462                         .child = .u8_type,
  16463                     });
  16464                     const new_decl = try anon_decl.finish(
  16465                         new_decl_ty,
  16466                         (try mod.intern(.{ .aggregate = .{
  16467                             .ty = new_decl_ty.toIntern(),
  16468                             .storage = .{ .bytes = name },
  16469                         } })).toValue(),
  16470                         0, // default alignment
  16471                     );
  16472                     break :v try mod.intern(.{ .ptr = .{
  16473                         .ty = .slice_const_u8_type,
  16474                         .addr = .{ .decl = new_decl },
  16475                         .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
  16476                     } });
  16477                 };
  16478 
  16479                 const enum_field_fields = .{
  16480                     // name: []const u8,
  16481                     name_val,
  16482                     // value: comptime_int,
  16483                     (try mod.intValue(Type.comptime_int, i)).toIntern(),
  16484                 };
  16485                 field_val.* = try mod.intern(.{ .aggregate = .{
  16486                     .ty = enum_field_ty.toIntern(),
  16487                     .storage = .{ .elems = &enum_field_fields },
  16488                 } });
  16489             }
  16490 
  16491             const fields_val = v: {
  16492                 const fields_array_ty = try mod.arrayType(.{
  16493                     .len = enum_field_vals.len,
  16494                     .child = enum_field_ty.toIntern(),
  16495                     .sentinel = .none,
  16496                 });
  16497                 const new_decl = try fields_anon_decl.finish(
  16498                     fields_array_ty,
  16499                     (try mod.intern(.{ .aggregate = .{
  16500                         .ty = fields_array_ty.toIntern(),
  16501                         .storage = .{ .elems = enum_field_vals },
  16502                     } })).toValue(),
  16503                     0, // default alignment
  16504                 );
  16505                 break :v try mod.intern(.{ .ptr = .{
  16506                     .ty = (try mod.ptrType(.{
  16507                         .child = enum_field_ty.toIntern(),
  16508                         .flags = .{
  16509                             .size = .Slice,
  16510                             .is_const = true,
  16511                         },
  16512                     })).toIntern(),
  16513                     .addr = .{ .decl = new_decl },
  16514                     .len = (try mod.intValue(Type.usize, enum_field_vals.len)).toIntern(),
  16515                 } });
  16516             };
  16517 
  16518             const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, enum_type.namespace);
  16519 
  16520             const type_enum_ty = t: {
  16521                 const type_enum_ty_decl_index = (try sema.namespaceLookup(
  16522                     block,
  16523                     src,
  16524                     type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16525                     "Enum",
  16526                 )).?;
  16527                 try mod.declareDeclDependency(sema.owner_decl_index, type_enum_ty_decl_index);
  16528                 try sema.ensureDeclAnalyzed(type_enum_ty_decl_index);
  16529                 const type_enum_ty_decl = mod.declPtr(type_enum_ty_decl_index);
  16530                 break :t type_enum_ty_decl.val.toType();
  16531             };
  16532 
  16533             const field_values = .{
  16534                 // tag_type: type,
  16535                 enum_type.tag_ty,
  16536                 // fields: []const EnumField,
  16537                 fields_val,
  16538                 // decls: []const Declaration,
  16539                 decls_val,
  16540                 // is_exhaustive: bool,
  16541                 is_exhaustive.toIntern(),
  16542             };
  16543             return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
  16544                 .ty = type_info_ty.toIntern(),
  16545                 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Enum))).toIntern(),
  16546                 .val = try mod.intern(.{ .aggregate = .{
  16547                     .ty = type_enum_ty.toIntern(),
  16548                     .storage = .{ .elems = &field_values },
  16549                 } }),
  16550             } })).toValue());
  16551         },
  16552         .Union => {
  16553             // TODO: look into memoizing this result.
  16554 
  16555             var fields_anon_decl = try block.startAnonDecl();
  16556             defer fields_anon_decl.deinit();
  16557 
  16558             const type_union_ty = t: {
  16559                 const type_union_ty_decl_index = (try sema.namespaceLookup(
  16560                     block,
  16561                     src,
  16562                     type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16563                     "Union",
  16564                 )).?;
  16565                 try mod.declareDeclDependency(sema.owner_decl_index, type_union_ty_decl_index);
  16566                 try sema.ensureDeclAnalyzed(type_union_ty_decl_index);
  16567                 const type_union_ty_decl = mod.declPtr(type_union_ty_decl_index);
  16568                 break :t type_union_ty_decl.val.toType();
  16569             };
  16570 
  16571             const union_field_ty = t: {
  16572                 const union_field_ty_decl_index = (try sema.namespaceLookup(
  16573                     block,
  16574                     src,
  16575                     type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16576                     "UnionField",
  16577                 )).?;
  16578                 try mod.declareDeclDependency(sema.owner_decl_index, union_field_ty_decl_index);
  16579                 try sema.ensureDeclAnalyzed(union_field_ty_decl_index);
  16580                 const union_field_ty_decl = mod.declPtr(union_field_ty_decl_index);
  16581                 break :t union_field_ty_decl.val.toType();
  16582             };
  16583 
  16584             const union_ty = try sema.resolveTypeFields(ty);
  16585             try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
  16586             const layout = union_ty.containerLayout(mod);
  16587 
  16588             const union_fields = union_ty.unionFields(mod);
  16589             const union_field_vals = try gpa.alloc(InternPool.Index, union_fields.count());
  16590             defer gpa.free(union_field_vals);
  16591 
  16592             for (union_field_vals, 0..) |*field_val, i| {
  16593                 const field = union_fields.values()[i];
  16594                 const name = union_fields.keys()[i];
  16595                 const name_val = v: {
  16596                     var anon_decl = try block.startAnonDecl();
  16597                     defer anon_decl.deinit();
  16598                     const new_decl_ty = try mod.arrayType(.{
  16599                         .len = name.len,
  16600                         .child = .u8_type,
  16601                     });
  16602                     const new_decl = try anon_decl.finish(
  16603                         new_decl_ty,
  16604                         (try mod.intern(.{ .aggregate = .{
  16605                             .ty = new_decl_ty.toIntern(),
  16606                             .storage = .{ .bytes = name },
  16607                         } })).toValue(),
  16608                         0, // default alignment
  16609                     );
  16610                     break :v try mod.intern(.{ .ptr = .{
  16611                         .ty = .slice_const_u8_type,
  16612                         .addr = .{ .decl = new_decl },
  16613                         .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
  16614                     } });
  16615                 };
  16616 
  16617                 const alignment = switch (layout) {
  16618                     .Auto, .Extern => try sema.unionFieldAlignment(field),
  16619                     .Packed => 0,
  16620                 };
  16621 
  16622                 const union_field_fields = .{
  16623                     // name: []const u8,
  16624                     name_val,
  16625                     // type: type,
  16626                     field.ty.toIntern(),
  16627                     // alignment: comptime_int,
  16628                     (try mod.intValue(Type.comptime_int, alignment)).toIntern(),
  16629                 };
  16630                 field_val.* = try mod.intern(.{ .aggregate = .{
  16631                     .ty = union_field_ty.toIntern(),
  16632                     .storage = .{ .elems = &union_field_fields },
  16633                 } });
  16634             }
  16635 
  16636             const fields_val = v: {
  16637                 const array_fields_ty = try mod.arrayType(.{
  16638                     .len = union_field_vals.len,
  16639                     .child = union_field_ty.toIntern(),
  16640                     .sentinel = .none,
  16641                 });
  16642                 const new_decl = try fields_anon_decl.finish(
  16643                     array_fields_ty,
  16644                     (try mod.intern(.{ .aggregate = .{
  16645                         .ty = array_fields_ty.toIntern(),
  16646                         .storage = .{ .elems = union_field_vals },
  16647                     } })).toValue(),
  16648                     0, // default alignment
  16649                 );
  16650                 break :v try mod.intern(.{ .ptr = .{
  16651                     .ty = (try mod.ptrType(.{
  16652                         .child = union_field_ty.toIntern(),
  16653                         .flags = .{
  16654                             .size = .Slice,
  16655                             .is_const = true,
  16656                         },
  16657                     })).toIntern(),
  16658                     .addr = .{ .decl = new_decl },
  16659                     .len = (try mod.intValue(Type.usize, union_field_vals.len)).toIntern(),
  16660                 } });
  16661             };
  16662 
  16663             const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespaceIndex(mod));
  16664 
  16665             const enum_tag_ty_val = try mod.intern(.{ .opt = .{
  16666                 .ty = (try mod.optionalType(.type_type)).toIntern(),
  16667                 .val = if (union_ty.unionTagType(mod)) |tag_ty| tag_ty.toIntern() else .none,
  16668             } });
  16669 
  16670             const container_layout_ty = t: {
  16671                 const decl_index = (try sema.namespaceLookup(
  16672                     block,
  16673                     src,
  16674                     (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?,
  16675                     "ContainerLayout",
  16676                 )).?;
  16677                 try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
  16678                 try sema.ensureDeclAnalyzed(decl_index);
  16679                 const decl = mod.declPtr(decl_index);
  16680                 break :t decl.val.toType();
  16681             };
  16682 
  16683             const field_values = .{
  16684                 // layout: ContainerLayout,
  16685                 (try mod.enumValueFieldIndex(container_layout_ty, @enumToInt(layout))).toIntern(),
  16686 
  16687                 // tag_type: ?type,
  16688                 enum_tag_ty_val,
  16689                 // fields: []const UnionField,
  16690                 fields_val,
  16691                 // decls: []const Declaration,
  16692                 decls_val,
  16693             };
  16694             return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
  16695                 .ty = type_info_ty.toIntern(),
  16696                 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Union))).toIntern(),
  16697                 .val = try mod.intern(.{ .aggregate = .{
  16698                     .ty = type_union_ty.toIntern(),
  16699                     .storage = .{ .elems = &field_values },
  16700                 } }),
  16701             } })).toValue());
  16702         },
  16703         .Struct => {
  16704             // TODO: look into memoizing this result.
  16705 
  16706             var fields_anon_decl = try block.startAnonDecl();
  16707             defer fields_anon_decl.deinit();
  16708 
  16709             const type_struct_ty = t: {
  16710                 const type_struct_ty_decl_index = (try sema.namespaceLookup(
  16711                     block,
  16712                     src,
  16713                     type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16714                     "Struct",
  16715                 )).?;
  16716                 try mod.declareDeclDependency(sema.owner_decl_index, type_struct_ty_decl_index);
  16717                 try sema.ensureDeclAnalyzed(type_struct_ty_decl_index);
  16718                 const type_struct_ty_decl = mod.declPtr(type_struct_ty_decl_index);
  16719                 break :t type_struct_ty_decl.val.toType();
  16720             };
  16721 
  16722             const struct_field_ty = t: {
  16723                 const struct_field_ty_decl_index = (try sema.namespaceLookup(
  16724                     block,
  16725                     src,
  16726                     type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16727                     "StructField",
  16728                 )).?;
  16729                 try mod.declareDeclDependency(sema.owner_decl_index, struct_field_ty_decl_index);
  16730                 try sema.ensureDeclAnalyzed(struct_field_ty_decl_index);
  16731                 const struct_field_ty_decl = mod.declPtr(struct_field_ty_decl_index);
  16732                 break :t struct_field_ty_decl.val.toType();
  16733             };
  16734 
  16735             const struct_ty = try sema.resolveTypeFields(ty);
  16736             try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
  16737             const layout = struct_ty.containerLayout(mod);
  16738 
  16739             var struct_field_vals: []InternPool.Index = &.{};
  16740             defer gpa.free(struct_field_vals);
  16741             fv: {
  16742                 const struct_type = switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) {
  16743                     .anon_struct_type => |tuple| {
  16744                         struct_field_vals = try gpa.alloc(InternPool.Index, tuple.types.len);
  16745                         for (struct_field_vals, 0..) |*struct_field_val, i| {
  16746                             const anon_struct_type = mod.intern_pool.indexToKey(struct_ty.toIntern()).anon_struct_type;
  16747                             const field_ty = anon_struct_type.types[i];
  16748                             const field_val = anon_struct_type.values[i];
  16749                             const name_val = v: {
  16750                                 var anon_decl = try block.startAnonDecl();
  16751                                 defer anon_decl.deinit();
  16752                                 const bytes = if (tuple.names.len != 0)
  16753                                     // https://github.com/ziglang/zig/issues/15709
  16754                                     @as([]const u8, mod.intern_pool.stringToSlice(tuple.names[i]))
  16755                                 else
  16756                                     try std.fmt.allocPrint(sema.arena, "{d}", .{i});
  16757                                 const new_decl_ty = try mod.arrayType(.{
  16758                                     .len = bytes.len,
  16759                                     .child = .u8_type,
  16760                                 });
  16761                                 const new_decl = try anon_decl.finish(
  16762                                     new_decl_ty,
  16763                                     (try mod.intern(.{ .aggregate = .{
  16764                                         .ty = new_decl_ty.toIntern(),
  16765                                         .storage = .{ .bytes = bytes },
  16766                                     } })).toValue(),
  16767                                     0, // default alignment
  16768                                 );
  16769                                 break :v try mod.intern(.{ .ptr = .{
  16770                                     .ty = .slice_const_u8_type,
  16771                                     .addr = .{ .decl = new_decl },
  16772                                     .len = (try mod.intValue(Type.usize, bytes.len)).toIntern(),
  16773                                 } });
  16774                             };
  16775 
  16776                             const is_comptime = field_val != .none;
  16777                             const opt_default_val = if (is_comptime) field_val.toValue() else null;
  16778                             const default_val_ptr = try sema.optRefValue(block, field_ty.toType(), opt_default_val);
  16779                             const struct_field_fields = .{
  16780                                 // name: []const u8,
  16781                                 name_val,
  16782                                 // type: type,
  16783                                 field_ty,
  16784                                 // default_value: ?*const anyopaque,
  16785                                 default_val_ptr.toIntern(),
  16786                                 // is_comptime: bool,
  16787                                 Value.makeBool(is_comptime).toIntern(),
  16788                                 // alignment: comptime_int,
  16789                                 (try mod.intValue(Type.comptime_int, field_ty.toType().abiAlignment(mod))).toIntern(),
  16790                             };
  16791                             struct_field_val.* = try mod.intern(.{ .aggregate = .{
  16792                                 .ty = struct_field_ty.toIntern(),
  16793                                 .storage = .{ .elems = &struct_field_fields },
  16794                             } });
  16795                         }
  16796                         break :fv;
  16797                     },
  16798                     .struct_type => |s| s,
  16799                     else => unreachable,
  16800                 };
  16801                 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :fv;
  16802                 struct_field_vals = try gpa.alloc(InternPool.Index, struct_obj.fields.count());
  16803 
  16804                 for (
  16805                     struct_field_vals,
  16806                     struct_obj.fields.keys(),
  16807                     struct_obj.fields.values(),
  16808                 ) |*field_val, name, field| {
  16809                     const name_val = v: {
  16810                         var anon_decl = try block.startAnonDecl();
  16811                         defer anon_decl.deinit();
  16812                         const new_decl_ty = try mod.arrayType(.{
  16813                             .len = name.len,
  16814                             .child = .u8_type,
  16815                         });
  16816                         const new_decl = try anon_decl.finish(
  16817                             new_decl_ty,
  16818                             (try mod.intern(.{ .aggregate = .{
  16819                                 .ty = new_decl_ty.toIntern(),
  16820                                 .storage = .{ .bytes = name },
  16821                             } })).toValue(),
  16822                             0, // default alignment
  16823                         );
  16824                         break :v try mod.intern(.{ .ptr = .{
  16825                             .ty = .slice_const_u8_type,
  16826                             .addr = .{ .decl = new_decl },
  16827                             .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
  16828                         } });
  16829                     };
  16830 
  16831                     const opt_default_val = if (field.default_val.toIntern() == .unreachable_value)
  16832                         null
  16833                     else
  16834                         field.default_val;
  16835                     const default_val_ptr = try sema.optRefValue(block, field.ty, opt_default_val);
  16836                     const alignment = field.alignment(mod, layout);
  16837 
  16838                     const struct_field_fields = .{
  16839                         // name: []const u8,
  16840                         name_val,
  16841                         // type: type,
  16842                         field.ty.toIntern(),
  16843                         // default_value: ?*const anyopaque,
  16844                         default_val_ptr.toIntern(),
  16845                         // is_comptime: bool,
  16846                         Value.makeBool(field.is_comptime).toIntern(),
  16847                         // alignment: comptime_int,
  16848                         (try mod.intValue(Type.comptime_int, alignment)).toIntern(),
  16849                     };
  16850                     field_val.* = try mod.intern(.{ .aggregate = .{
  16851                         .ty = struct_field_ty.toIntern(),
  16852                         .storage = .{ .elems = &struct_field_fields },
  16853                     } });
  16854                 }
  16855             }
  16856 
  16857             const fields_val = v: {
  16858                 const array_fields_ty = try mod.arrayType(.{
  16859                     .len = struct_field_vals.len,
  16860                     .child = struct_field_ty.toIntern(),
  16861                     .sentinel = .none,
  16862                 });
  16863                 const new_decl = try fields_anon_decl.finish(
  16864                     array_fields_ty,
  16865                     (try mod.intern(.{ .aggregate = .{
  16866                         .ty = array_fields_ty.toIntern(),
  16867                         .storage = .{ .elems = struct_field_vals },
  16868                     } })).toValue(),
  16869                     0, // default alignment
  16870                 );
  16871                 break :v try mod.intern(.{ .ptr = .{
  16872                     .ty = (try mod.ptrType(.{
  16873                         .child = struct_field_ty.toIntern(),
  16874                         .flags = .{
  16875                             .size = .Slice,
  16876                             .is_const = true,
  16877                         },
  16878                     })).toIntern(),
  16879                     .addr = .{ .decl = new_decl },
  16880                     .len = (try mod.intValue(Type.usize, struct_field_vals.len)).toIntern(),
  16881                 } });
  16882             };
  16883 
  16884             const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespaceIndex(mod));
  16885 
  16886             const backing_integer_val = try mod.intern(.{ .opt = .{
  16887                 .ty = (try mod.optionalType(.type_type)).toIntern(),
  16888                 .val = if (layout == .Packed) val: {
  16889                     const struct_obj = mod.typeToStruct(struct_ty).?;
  16890                     assert(struct_obj.haveLayout());
  16891                     assert(struct_obj.backing_int_ty.isInt(mod));
  16892                     break :val struct_obj.backing_int_ty.toIntern();
  16893                 } else .none,
  16894             } });
  16895 
  16896             const container_layout_ty = t: {
  16897                 const decl_index = (try sema.namespaceLookup(
  16898                     block,
  16899                     src,
  16900                     (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?,
  16901                     "ContainerLayout",
  16902                 )).?;
  16903                 try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
  16904                 try sema.ensureDeclAnalyzed(decl_index);
  16905                 const decl = mod.declPtr(decl_index);
  16906                 break :t decl.val.toType();
  16907             };
  16908 
  16909             const field_values = [_]InternPool.Index{
  16910                 // layout: ContainerLayout,
  16911                 (try mod.enumValueFieldIndex(container_layout_ty, @enumToInt(layout))).toIntern(),
  16912                 // backing_integer: ?type,
  16913                 backing_integer_val,
  16914                 // fields: []const StructField,
  16915                 fields_val,
  16916                 // decls: []const Declaration,
  16917                 decls_val,
  16918                 // is_tuple: bool,
  16919                 Value.makeBool(struct_ty.isTuple(mod)).toIntern(),
  16920             };
  16921             return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
  16922                 .ty = type_info_ty.toIntern(),
  16923                 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Struct))).toIntern(),
  16924                 .val = try mod.intern(.{ .aggregate = .{
  16925                     .ty = type_struct_ty.toIntern(),
  16926                     .storage = .{ .elems = &field_values },
  16927                 } }),
  16928             } })).toValue());
  16929         },
  16930         .Opaque => {
  16931             // TODO: look into memoizing this result.
  16932 
  16933             const type_opaque_ty = t: {
  16934                 const type_opaque_ty_decl_index = (try sema.namespaceLookup(
  16935                     block,
  16936                     src,
  16937                     type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16938                     "Opaque",
  16939                 )).?;
  16940                 try mod.declareDeclDependency(sema.owner_decl_index, type_opaque_ty_decl_index);
  16941                 try sema.ensureDeclAnalyzed(type_opaque_ty_decl_index);
  16942                 const type_opaque_ty_decl = mod.declPtr(type_opaque_ty_decl_index);
  16943                 break :t type_opaque_ty_decl.val.toType();
  16944             };
  16945 
  16946             const opaque_ty = try sema.resolveTypeFields(ty);
  16947             const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespaceIndex(mod));
  16948 
  16949             const field_values = .{
  16950                 // decls: []const Declaration,
  16951                 decls_val,
  16952             };
  16953             return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
  16954                 .ty = type_info_ty.toIntern(),
  16955                 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Opaque))).toIntern(),
  16956                 .val = try mod.intern(.{ .aggregate = .{
  16957                     .ty = type_opaque_ty.toIntern(),
  16958                     .storage = .{ .elems = &field_values },
  16959                 } }),
  16960             } })).toValue());
  16961         },
  16962         .Frame => return sema.failWithUseOfAsync(block, src),
  16963         .AnyFrame => return sema.failWithUseOfAsync(block, src),
  16964     }
  16965 }
  16966 
  16967 fn typeInfoDecls(
  16968     sema: *Sema,
  16969     block: *Block,
  16970     src: LazySrcLoc,
  16971     type_info_ty: Type,
  16972     opt_namespace: Module.Namespace.OptionalIndex,
  16973 ) CompileError!InternPool.Index {
  16974     const mod = sema.mod;
  16975     var decls_anon_decl = try block.startAnonDecl();
  16976     defer decls_anon_decl.deinit();
  16977 
  16978     const declaration_ty = t: {
  16979         const declaration_ty_decl_index = (try sema.namespaceLookup(
  16980             block,
  16981             src,
  16982             type_info_ty.getNamespaceIndex(mod).unwrap().?,
  16983             "Declaration",
  16984         )).?;
  16985         try mod.declareDeclDependency(sema.owner_decl_index, declaration_ty_decl_index);
  16986         try sema.ensureDeclAnalyzed(declaration_ty_decl_index);
  16987         const declaration_ty_decl = mod.declPtr(declaration_ty_decl_index);
  16988         break :t declaration_ty_decl.val.toType();
  16989     };
  16990     try sema.queueFullTypeResolution(declaration_ty);
  16991 
  16992     var decl_vals = std.ArrayList(InternPool.Index).init(sema.gpa);
  16993     defer decl_vals.deinit();
  16994 
  16995     var seen_namespaces = std.AutoHashMap(*Namespace, void).init(sema.gpa);
  16996     defer seen_namespaces.deinit();
  16997 
  16998     if (opt_namespace.unwrap()) |namespace_index| {
  16999         const namespace = mod.namespacePtr(namespace_index);
  17000         try sema.typeInfoNamespaceDecls(block, namespace, declaration_ty, &decl_vals, &seen_namespaces);
  17001     }
  17002 
  17003     const array_decl_ty = try mod.arrayType(.{
  17004         .len = decl_vals.items.len,
  17005         .child = declaration_ty.toIntern(),
  17006         .sentinel = .none,
  17007     });
  17008     const new_decl = try decls_anon_decl.finish(
  17009         array_decl_ty,
  17010         (try mod.intern(.{ .aggregate = .{
  17011             .ty = array_decl_ty.toIntern(),
  17012             .storage = .{ .elems = decl_vals.items },
  17013         } })).toValue(),
  17014         0, // default alignment
  17015     );
  17016     return try mod.intern(.{ .ptr = .{
  17017         .ty = (try mod.ptrType(.{
  17018             .child = declaration_ty.toIntern(),
  17019             .flags = .{
  17020                 .size = .Slice,
  17021                 .is_const = true,
  17022             },
  17023         })).toIntern(),
  17024         .addr = .{ .decl = new_decl },
  17025         .len = (try mod.intValue(Type.usize, decl_vals.items.len)).toIntern(),
  17026     } });
  17027 }
  17028 
  17029 fn typeInfoNamespaceDecls(
  17030     sema: *Sema,
  17031     block: *Block,
  17032     namespace: *Namespace,
  17033     declaration_ty: Type,
  17034     decl_vals: *std.ArrayList(InternPool.Index),
  17035     seen_namespaces: *std.AutoHashMap(*Namespace, void),
  17036 ) !void {
  17037     const mod = sema.mod;
  17038     const gop = try seen_namespaces.getOrPut(namespace);
  17039     if (gop.found_existing) return;
  17040     const decls = namespace.decls.keys();
  17041     for (decls) |decl_index| {
  17042         const decl = mod.declPtr(decl_index);
  17043         if (decl.kind == .@"usingnamespace") {
  17044             if (decl.analysis == .in_progress) continue;
  17045             try mod.ensureDeclAnalyzed(decl_index);
  17046             const new_ns = decl.val.toType().getNamespace(mod).?;
  17047             try sema.typeInfoNamespaceDecls(block, new_ns, declaration_ty, decl_vals, seen_namespaces);
  17048             continue;
  17049         }
  17050         if (decl.kind != .named) continue;
  17051         const name_val = v: {
  17052             var anon_decl = try block.startAnonDecl();
  17053             defer anon_decl.deinit();
  17054             const name = mem.span(decl.name);
  17055             const new_decl_ty = try mod.arrayType(.{
  17056                 .len = name.len,
  17057                 .child = .u8_type,
  17058             });
  17059             const new_decl = try anon_decl.finish(
  17060                 new_decl_ty,
  17061                 (try mod.intern(.{ .aggregate = .{
  17062                     .ty = new_decl_ty.toIntern(),
  17063                     .storage = .{ .bytes = name },
  17064                 } })).toValue(),
  17065                 0, // default alignment
  17066             );
  17067             break :v try mod.intern(.{ .ptr = .{
  17068                 .ty = .slice_const_u8_type,
  17069                 .addr = .{ .decl = new_decl },
  17070                 .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
  17071             } });
  17072         };
  17073 
  17074         const fields = .{
  17075             //name: []const u8,
  17076             name_val,
  17077             //is_pub: bool,
  17078             Value.makeBool(decl.is_pub).toIntern(),
  17079         };
  17080         try decl_vals.append(try mod.intern(.{ .aggregate = .{
  17081             .ty = declaration_ty.toIntern(),
  17082             .storage = .{ .elems = &fields },
  17083         } }));
  17084     }
  17085 }
  17086 
  17087 fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17088     _ = block;
  17089     const zir_datas = sema.code.instructions.items(.data);
  17090     const inst_data = zir_datas[inst].un_node;
  17091     const operand = try sema.resolveInst(inst_data.operand);
  17092     const operand_ty = sema.typeOf(operand);
  17093     return sema.addType(operand_ty);
  17094 }
  17095 
  17096 fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17097     const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
  17098     const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index);
  17099     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
  17100 
  17101     var child_block: Block = .{
  17102         .parent = block,
  17103         .sema = sema,
  17104         .src_decl = block.src_decl,
  17105         .namespace = block.namespace,
  17106         .wip_capture_scope = block.wip_capture_scope,
  17107         .instructions = .{},
  17108         .inlining = block.inlining,
  17109         .is_comptime = false,
  17110         .is_typeof = true,
  17111         .want_safety = false,
  17112         .error_return_trace_index = block.error_return_trace_index,
  17113     };
  17114     defer child_block.instructions.deinit(sema.gpa);
  17115 
  17116     const operand = try sema.resolveBody(&child_block, body, inst);
  17117     const operand_ty = sema.typeOf(operand);
  17118     if (operand_ty.isGenericPoison()) return error.GenericPoison;
  17119     return sema.addType(operand_ty);
  17120 }
  17121 
  17122 fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17123     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  17124     const src = inst_data.src();
  17125     const operand = try sema.resolveInst(inst_data.operand);
  17126     const operand_ty = sema.typeOf(operand);
  17127     const res_ty = try sema.log2IntType(block, operand_ty, src);
  17128     return sema.addType(res_ty);
  17129 }
  17130 
  17131 fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) CompileError!Type {
  17132     const mod = sema.mod;
  17133     switch (operand.zigTypeTag(mod)) {
  17134         .ComptimeInt => return Type.comptime_int,
  17135         .Int => {
  17136             const bits = operand.bitSize(mod);
  17137             const count = if (bits == 0)
  17138                 0
  17139             else blk: {
  17140                 var count: u16 = 0;
  17141                 var s = bits - 1;
  17142                 while (s != 0) : (s >>= 1) {
  17143                     count += 1;
  17144                 }
  17145                 break :blk count;
  17146             };
  17147             return mod.intType(.unsigned, count);
  17148         },
  17149         .Vector => {
  17150             const elem_ty = operand.elemType2(mod);
  17151             const log2_elem_ty = try sema.log2IntType(block, elem_ty, src);
  17152             return mod.vectorType(.{
  17153                 .len = operand.vectorLen(mod),
  17154                 .child = log2_elem_ty.toIntern(),
  17155             });
  17156         },
  17157         else => {},
  17158     }
  17159     return sema.fail(
  17160         block,
  17161         src,
  17162         "bit shifting operation expected integer type, found '{}'",
  17163         .{operand.fmt(sema.mod)},
  17164     );
  17165 }
  17166 
  17167 fn zirTypeofPeer(
  17168     sema: *Sema,
  17169     block: *Block,
  17170     extended: Zir.Inst.Extended.InstData,
  17171 ) CompileError!Air.Inst.Ref {
  17172     const tracy = trace(@src());
  17173     defer tracy.end();
  17174 
  17175     const extra = sema.code.extraData(Zir.Inst.TypeOfPeer, extended.operand);
  17176     const src = LazySrcLoc.nodeOffset(extra.data.src_node);
  17177     const body = sema.code.extra[extra.data.body_index..][0..extra.data.body_len];
  17178 
  17179     var child_block: Block = .{
  17180         .parent = block,
  17181         .sema = sema,
  17182         .src_decl = block.src_decl,
  17183         .namespace = block.namespace,
  17184         .wip_capture_scope = block.wip_capture_scope,
  17185         .instructions = .{},
  17186         .inlining = block.inlining,
  17187         .is_comptime = false,
  17188         .is_typeof = true,
  17189         .runtime_cond = block.runtime_cond,
  17190         .runtime_loop = block.runtime_loop,
  17191         .runtime_index = block.runtime_index,
  17192     };
  17193     defer child_block.instructions.deinit(sema.gpa);
  17194     // Ignore the result, we only care about the instructions in `args`.
  17195     _ = try sema.analyzeBodyBreak(&child_block, body);
  17196 
  17197     const args = sema.code.refSlice(extra.end, extended.small);
  17198 
  17199     const inst_list = try sema.gpa.alloc(Air.Inst.Ref, args.len);
  17200     defer sema.gpa.free(inst_list);
  17201 
  17202     for (args, 0..) |arg_ref, i| {
  17203         inst_list[i] = try sema.resolveInst(arg_ref);
  17204     }
  17205 
  17206     const result_type = try sema.resolvePeerTypes(block, src, inst_list, .{ .typeof_builtin_call_node_offset = extra.data.src_node });
  17207     return sema.addType(result_type);
  17208 }
  17209 
  17210 fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17211     const tracy = trace(@src());
  17212     defer tracy.end();
  17213 
  17214     const mod = sema.mod;
  17215     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  17216     const src = inst_data.src();
  17217     const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
  17218     const uncasted_operand = try sema.resolveInst(inst_data.operand);
  17219 
  17220     const operand = try sema.coerce(block, Type.bool, uncasted_operand, operand_src);
  17221     if (try sema.resolveMaybeUndefVal(operand)) |val| {
  17222         return if (val.isUndef(mod))
  17223             sema.addConstUndef(Type.bool)
  17224         else if (val.toBool())
  17225             Air.Inst.Ref.bool_false
  17226         else
  17227             Air.Inst.Ref.bool_true;
  17228     }
  17229     try sema.requireRuntimeBlock(block, src, null);
  17230     return block.addTyOp(.not, Type.bool, operand);
  17231 }
  17232 
  17233 fn zirBoolBr(
  17234     sema: *Sema,
  17235     parent_block: *Block,
  17236     inst: Zir.Inst.Index,
  17237     is_bool_or: bool,
  17238 ) CompileError!Air.Inst.Ref {
  17239     const tracy = trace(@src());
  17240     defer tracy.end();
  17241 
  17242     const mod = sema.mod;
  17243     const datas = sema.code.instructions.items(.data);
  17244     const inst_data = datas[inst].bool_br;
  17245     const lhs = try sema.resolveInst(inst_data.lhs);
  17246     const lhs_src = sema.src;
  17247     const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
  17248     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
  17249     const gpa = sema.gpa;
  17250 
  17251     if (try sema.resolveDefinedValue(parent_block, lhs_src, lhs)) |lhs_val| {
  17252         if (is_bool_or and lhs_val.toBool()) {
  17253             return Air.Inst.Ref.bool_true;
  17254         } else if (!is_bool_or and !lhs_val.toBool()) {
  17255             return Air.Inst.Ref.bool_false;
  17256         }
  17257         // comptime-known left-hand side. No need for a block here; the result
  17258         // is simply the rhs expression. Here we rely on there only being 1
  17259         // break instruction (`break_inline`).
  17260         return sema.resolveBody(parent_block, body, inst);
  17261     }
  17262 
  17263     const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
  17264     try sema.air_instructions.append(gpa, .{
  17265         .tag = .block,
  17266         .data = .{ .ty_pl = .{
  17267             .ty = .bool_type,
  17268             .payload = undefined,
  17269         } },
  17270     });
  17271 
  17272     var child_block = parent_block.makeSubBlock();
  17273     child_block.runtime_loop = null;
  17274     child_block.runtime_cond = lhs_src;
  17275     child_block.runtime_index.increment();
  17276     defer child_block.instructions.deinit(gpa);
  17277 
  17278     var then_block = child_block.makeSubBlock();
  17279     defer then_block.instructions.deinit(gpa);
  17280 
  17281     var else_block = child_block.makeSubBlock();
  17282     defer else_block.instructions.deinit(gpa);
  17283 
  17284     const lhs_block = if (is_bool_or) &then_block else &else_block;
  17285     const rhs_block = if (is_bool_or) &else_block else &then_block;
  17286 
  17287     const lhs_result: Air.Inst.Ref = if (is_bool_or) .bool_true else .bool_false;
  17288     _ = try lhs_block.addBr(block_inst, lhs_result);
  17289 
  17290     const rhs_result = try sema.resolveBody(rhs_block, body, inst);
  17291     if (!sema.typeOf(rhs_result).isNoReturn(mod)) {
  17292         _ = try rhs_block.addBr(block_inst, rhs_result);
  17293     }
  17294 
  17295     const result = sema.finishCondBr(parent_block, &child_block, &then_block, &else_block, lhs, block_inst);
  17296     if (!sema.typeOf(rhs_result).isNoReturn(mod)) {
  17297         if (try sema.resolveDefinedValue(rhs_block, sema.src, rhs_result)) |rhs_val| {
  17298             if (is_bool_or and rhs_val.toBool()) {
  17299                 return Air.Inst.Ref.bool_true;
  17300             } else if (!is_bool_or and !rhs_val.toBool()) {
  17301                 return Air.Inst.Ref.bool_false;
  17302             }
  17303         }
  17304     }
  17305 
  17306     return result;
  17307 }
  17308 
  17309 fn finishCondBr(
  17310     sema: *Sema,
  17311     parent_block: *Block,
  17312     child_block: *Block,
  17313     then_block: *Block,
  17314     else_block: *Block,
  17315     cond: Air.Inst.Ref,
  17316     block_inst: Air.Inst.Index,
  17317 ) !Air.Inst.Ref {
  17318     const gpa = sema.gpa;
  17319 
  17320     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
  17321         then_block.instructions.items.len + else_block.instructions.items.len +
  17322         @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1);
  17323 
  17324     const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{
  17325         .then_body_len = @intCast(u32, then_block.instructions.items.len),
  17326         .else_body_len = @intCast(u32, else_block.instructions.items.len),
  17327     });
  17328     sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items);
  17329     sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items);
  17330 
  17331     _ = try child_block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{
  17332         .operand = cond,
  17333         .payload = cond_br_payload,
  17334     } } });
  17335 
  17336     sema.air_instructions.items(.data)[block_inst].ty_pl.payload = sema.addExtraAssumeCapacity(
  17337         Air.Block{ .body_len = @intCast(u32, child_block.instructions.items.len) },
  17338     );
  17339     sema.air_extra.appendSliceAssumeCapacity(child_block.instructions.items);
  17340 
  17341     try parent_block.instructions.append(gpa, block_inst);
  17342     return Air.indexToRef(block_inst);
  17343 }
  17344 
  17345 fn checkNullableType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
  17346     const mod = sema.mod;
  17347     switch (ty.zigTypeTag(mod)) {
  17348         .Optional, .Null, .Undefined => return,
  17349         .Pointer => if (ty.isPtrLikeOptional(mod)) return,
  17350         else => {},
  17351     }
  17352     return sema.failWithExpectedOptionalType(block, src, ty);
  17353 }
  17354 
  17355 fn zirIsNonNull(
  17356     sema: *Sema,
  17357     block: *Block,
  17358     inst: Zir.Inst.Index,
  17359 ) CompileError!Air.Inst.Ref {
  17360     const tracy = trace(@src());
  17361     defer tracy.end();
  17362 
  17363     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  17364     const src = inst_data.src();
  17365     const operand = try sema.resolveInst(inst_data.operand);
  17366     try sema.checkNullableType(block, src, sema.typeOf(operand));
  17367     return sema.analyzeIsNull(block, src, operand, true);
  17368 }
  17369 
  17370 fn zirIsNonNullPtr(
  17371     sema: *Sema,
  17372     block: *Block,
  17373     inst: Zir.Inst.Index,
  17374 ) CompileError!Air.Inst.Ref {
  17375     const tracy = trace(@src());
  17376     defer tracy.end();
  17377 
  17378     const mod = sema.mod;
  17379     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  17380     const src = inst_data.src();
  17381     const ptr = try sema.resolveInst(inst_data.operand);
  17382     try sema.checkNullableType(block, src, sema.typeOf(ptr).elemType2(mod));
  17383     if ((try sema.resolveMaybeUndefVal(ptr)) == null) {
  17384         return block.addUnOp(.is_non_null_ptr, ptr);
  17385     }
  17386     const loaded = try sema.analyzeLoad(block, src, ptr, src);
  17387     return sema.analyzeIsNull(block, src, loaded, true);
  17388 }
  17389 
  17390 fn checkErrorType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
  17391     const mod = sema.mod;
  17392     switch (ty.zigTypeTag(mod)) {
  17393         .ErrorSet, .ErrorUnion, .Undefined => return,
  17394         else => return sema.fail(block, src, "expected error union type, found '{}'", .{
  17395             ty.fmt(sema.mod),
  17396         }),
  17397     }
  17398 }
  17399 
  17400 fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17401     const tracy = trace(@src());
  17402     defer tracy.end();
  17403 
  17404     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  17405     const src = inst_data.src();
  17406     const operand = try sema.resolveInst(inst_data.operand);
  17407     try sema.checkErrorType(block, src, sema.typeOf(operand));
  17408     return sema.analyzeIsNonErr(block, src, operand);
  17409 }
  17410 
  17411 fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17412     const tracy = trace(@src());
  17413     defer tracy.end();
  17414 
  17415     const mod = sema.mod;
  17416     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  17417     const src = inst_data.src();
  17418     const ptr = try sema.resolveInst(inst_data.operand);
  17419     try sema.checkErrorType(block, src, sema.typeOf(ptr).elemType2(mod));
  17420     const loaded = try sema.analyzeLoad(block, src, ptr, src);
  17421     return sema.analyzeIsNonErr(block, src, loaded);
  17422 }
  17423 
  17424 fn zirRetIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17425     const tracy = trace(@src());
  17426     defer tracy.end();
  17427 
  17428     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  17429     const src = inst_data.src();
  17430     const operand = try sema.resolveInst(inst_data.operand);
  17431     return sema.analyzeIsNonErr(block, src, operand);
  17432 }
  17433 
  17434 fn zirCondbr(
  17435     sema: *Sema,
  17436     parent_block: *Block,
  17437     inst: Zir.Inst.Index,
  17438 ) CompileError!Zir.Inst.Index {
  17439     const tracy = trace(@src());
  17440     defer tracy.end();
  17441 
  17442     const mod = sema.mod;
  17443     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  17444     const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
  17445     const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
  17446 
  17447     const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
  17448     const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
  17449 
  17450     const uncasted_cond = try sema.resolveInst(extra.data.condition);
  17451     const cond = try sema.coerce(parent_block, Type.bool, uncasted_cond, cond_src);
  17452 
  17453     if (try sema.resolveDefinedValue(parent_block, cond_src, cond)) |cond_val| {
  17454         const body = if (cond_val.toBool()) then_body else else_body;
  17455 
  17456         try sema.maybeErrorUnwrapCondbr(parent_block, body, extra.data.condition, cond_src);
  17457         // We use `analyzeBodyInner` since we want to propagate any possible
  17458         // `error.ComptimeBreak` to the caller.
  17459         return sema.analyzeBodyInner(parent_block, body);
  17460     }
  17461 
  17462     const gpa = sema.gpa;
  17463 
  17464     // We'll re-use the sub block to save on memory bandwidth, and yank out the
  17465     // instructions array in between using it for the then block and else block.
  17466     var sub_block = parent_block.makeSubBlock();
  17467     sub_block.runtime_loop = null;
  17468     sub_block.runtime_cond = cond_src;
  17469     sub_block.runtime_index.increment();
  17470     defer sub_block.instructions.deinit(gpa);
  17471 
  17472     try sema.analyzeBodyRuntimeBreak(&sub_block, then_body);
  17473     const true_instructions = try sub_block.instructions.toOwnedSlice(gpa);
  17474     defer gpa.free(true_instructions);
  17475 
  17476     const err_cond = blk: {
  17477         const index = Zir.refToIndex(extra.data.condition) orelse break :blk null;
  17478         if (sema.code.instructions.items(.tag)[index] != .is_non_err) break :blk null;
  17479 
  17480         const err_inst_data = sema.code.instructions.items(.data)[index].un_node;
  17481         const err_operand = try sema.resolveInst(err_inst_data.operand);
  17482         const operand_ty = sema.typeOf(err_operand);
  17483         assert(operand_ty.zigTypeTag(mod) == .ErrorUnion);
  17484         const result_ty = operand_ty.errorUnionSet(mod);
  17485         break :blk try sub_block.addTyOp(.unwrap_errunion_err, result_ty, err_operand);
  17486     };
  17487 
  17488     if (err_cond != null and try sema.maybeErrorUnwrap(&sub_block, else_body, err_cond.?)) {
  17489         // nothing to do
  17490     } else {
  17491         try sema.analyzeBodyRuntimeBreak(&sub_block, else_body);
  17492     }
  17493     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
  17494         true_instructions.len + sub_block.instructions.items.len);
  17495     _ = try parent_block.addInst(.{
  17496         .tag = .cond_br,
  17497         .data = .{ .pl_op = .{
  17498             .operand = cond,
  17499             .payload = sema.addExtraAssumeCapacity(Air.CondBr{
  17500                 .then_body_len = @intCast(u32, true_instructions.len),
  17501                 .else_body_len = @intCast(u32, sub_block.instructions.items.len),
  17502             }),
  17503         } },
  17504     });
  17505     sema.air_extra.appendSliceAssumeCapacity(true_instructions);
  17506     sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items);
  17507     return always_noreturn;
  17508 }
  17509 
  17510 fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17511     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  17512     const src = inst_data.src();
  17513     const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  17514     const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
  17515     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
  17516     const err_union = try sema.resolveInst(extra.data.operand);
  17517     const err_union_ty = sema.typeOf(err_union);
  17518     const mod = sema.mod;
  17519     if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) {
  17520         return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{
  17521             err_union_ty.fmt(sema.mod),
  17522         });
  17523     }
  17524     const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
  17525     if (is_non_err != .none) {
  17526         const is_non_err_val = (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)).?;
  17527         if (is_non_err_val.toBool()) {
  17528             return sema.analyzeErrUnionPayload(parent_block, src, err_union_ty, err_union, operand_src, false);
  17529         }
  17530         // We can analyze the body directly in the parent block because we know there are
  17531         // no breaks from the body possible, and that the body is noreturn.
  17532         return sema.resolveBody(parent_block, body, inst);
  17533     }
  17534 
  17535     var sub_block = parent_block.makeSubBlock();
  17536     defer sub_block.instructions.deinit(sema.gpa);
  17537 
  17538     // This body is guaranteed to end with noreturn and has no breaks.
  17539     _ = try sema.analyzeBodyInner(&sub_block, body);
  17540 
  17541     try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Try).Struct.fields.len +
  17542         sub_block.instructions.items.len);
  17543     const try_inst = try parent_block.addInst(.{
  17544         .tag = .@"try",
  17545         .data = .{ .pl_op = .{
  17546             .operand = err_union,
  17547             .payload = sema.addExtraAssumeCapacity(Air.Try{
  17548                 .body_len = @intCast(u32, sub_block.instructions.items.len),
  17549             }),
  17550         } },
  17551     });
  17552     sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items);
  17553     return try_inst;
  17554 }
  17555 
  17556 fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17557     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  17558     const src = inst_data.src();
  17559     const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  17560     const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
  17561     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
  17562     const operand = try sema.resolveInst(extra.data.operand);
  17563     const err_union = try sema.analyzeLoad(parent_block, src, operand, operand_src);
  17564     const err_union_ty = sema.typeOf(err_union);
  17565     const mod = sema.mod;
  17566     if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) {
  17567         return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{
  17568             err_union_ty.fmt(sema.mod),
  17569         });
  17570     }
  17571     const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
  17572     if (is_non_err != .none) {
  17573         const is_non_err_val = (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)).?;
  17574         if (is_non_err_val.toBool()) {
  17575             return sema.analyzeErrUnionPayloadPtr(parent_block, src, operand, false, false);
  17576         }
  17577         // We can analyze the body directly in the parent block because we know there are
  17578         // no breaks from the body possible, and that the body is noreturn.
  17579         return sema.resolveBody(parent_block, body, inst);
  17580     }
  17581 
  17582     var sub_block = parent_block.makeSubBlock();
  17583     defer sub_block.instructions.deinit(sema.gpa);
  17584 
  17585     // This body is guaranteed to end with noreturn and has no breaks.
  17586     _ = try sema.analyzeBodyInner(&sub_block, body);
  17587 
  17588     const operand_ty = sema.typeOf(operand);
  17589     const ptr_info = operand_ty.ptrInfo(mod);
  17590     const res_ty = try Type.ptr(sema.arena, sema.mod, .{
  17591         .pointee_type = err_union_ty.errorUnionPayload(mod),
  17592         .@"addrspace" = ptr_info.@"addrspace",
  17593         .mutable = ptr_info.mutable,
  17594         .@"allowzero" = ptr_info.@"allowzero",
  17595         .@"volatile" = ptr_info.@"volatile",
  17596     });
  17597     const res_ty_ref = try sema.addType(res_ty);
  17598     try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.TryPtr).Struct.fields.len +
  17599         sub_block.instructions.items.len);
  17600     const try_inst = try parent_block.addInst(.{
  17601         .tag = .try_ptr,
  17602         .data = .{ .ty_pl = .{
  17603             .ty = res_ty_ref,
  17604             .payload = sema.addExtraAssumeCapacity(Air.TryPtr{
  17605                 .ptr = operand,
  17606                 .body_len = @intCast(u32, sub_block.instructions.items.len),
  17607             }),
  17608         } },
  17609     });
  17610     sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items);
  17611     return try_inst;
  17612 }
  17613 
  17614 // A `break` statement is inside a runtime condition, but trying to
  17615 // break from an inline loop. In such case we must convert it to
  17616 // a runtime break.
  17617 fn addRuntimeBreak(sema: *Sema, child_block: *Block, break_data: BreakData) !void {
  17618     const gop = sema.inst_map.getOrPutAssumeCapacity(break_data.block_inst);
  17619     const labeled_block = if (!gop.found_existing) blk: {
  17620         try sema.post_hoc_blocks.ensureUnusedCapacity(sema.gpa, 1);
  17621 
  17622         const new_block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
  17623         gop.value_ptr.* = Air.indexToRef(new_block_inst);
  17624         try sema.air_instructions.append(sema.gpa, .{
  17625             .tag = .block,
  17626             .data = undefined,
  17627         });
  17628         const labeled_block = try sema.gpa.create(LabeledBlock);
  17629         labeled_block.* = .{
  17630             .label = .{
  17631                 .zir_block = break_data.block_inst,
  17632                 .merges = .{
  17633                     .src_locs = .{},
  17634                     .results = .{},
  17635                     .br_list = .{},
  17636                     .block_inst = new_block_inst,
  17637                 },
  17638             },
  17639             .block = .{
  17640                 .parent = child_block,
  17641                 .sema = sema,
  17642                 .src_decl = child_block.src_decl,
  17643                 .namespace = child_block.namespace,
  17644                 .wip_capture_scope = child_block.wip_capture_scope,
  17645                 .instructions = .{},
  17646                 .label = &labeled_block.label,
  17647                 .inlining = child_block.inlining,
  17648                 .is_comptime = child_block.is_comptime,
  17649             },
  17650         };
  17651         sema.post_hoc_blocks.putAssumeCapacityNoClobber(new_block_inst, labeled_block);
  17652         break :blk labeled_block;
  17653     } else blk: {
  17654         const new_block_inst = Air.refToIndex(gop.value_ptr.*).?;
  17655         const labeled_block = sema.post_hoc_blocks.get(new_block_inst).?;
  17656         break :blk labeled_block;
  17657     };
  17658 
  17659     const operand = try sema.resolveInst(break_data.operand);
  17660     const br_ref = try child_block.addBr(labeled_block.label.merges.block_inst, operand);
  17661     try labeled_block.label.merges.results.append(sema.gpa, operand);
  17662     try labeled_block.label.merges.br_list.append(sema.gpa, Air.refToIndex(br_ref).?);
  17663     labeled_block.block.runtime_index.increment();
  17664     if (labeled_block.block.runtime_cond == null and labeled_block.block.runtime_loop == null) {
  17665         labeled_block.block.runtime_cond = child_block.runtime_cond orelse child_block.runtime_loop;
  17666         labeled_block.block.runtime_loop = child_block.runtime_loop;
  17667     }
  17668 }
  17669 
  17670 fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
  17671     const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable";
  17672     const src = inst_data.src();
  17673 
  17674     if (block.is_comptime) {
  17675         return sema.fail(block, src, "reached unreachable code", .{});
  17676     }
  17677     // TODO Add compile error for @optimizeFor occurring too late in a scope.
  17678     try block.addUnreachable(true);
  17679     return always_noreturn;
  17680 }
  17681 
  17682 fn zirRetErrValue(
  17683     sema: *Sema,
  17684     block: *Block,
  17685     inst: Zir.Inst.Index,
  17686 ) CompileError!Zir.Inst.Index {
  17687     const mod = sema.mod;
  17688     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
  17689     const err_name = inst_data.get(sema.code);
  17690     const src = inst_data.src();
  17691 
  17692     // Return the error code from the function.
  17693     const kv = try mod.getErrorValue(err_name);
  17694     const error_set_type = try mod.singleErrorSetType(err_name);
  17695     const result_inst = try sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{
  17696         .ty = error_set_type.toIntern(),
  17697         .name = try mod.intern_pool.getOrPutString(sema.gpa, kv.key),
  17698     } })).toValue());
  17699     return sema.analyzeRet(block, result_inst, src);
  17700 }
  17701 
  17702 fn zirRetImplicit(
  17703     sema: *Sema,
  17704     block: *Block,
  17705     inst: Zir.Inst.Index,
  17706 ) CompileError!Zir.Inst.Index {
  17707     const tracy = trace(@src());
  17708     defer tracy.end();
  17709 
  17710     const mod = sema.mod;
  17711     const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
  17712     const operand = try sema.resolveInst(inst_data.operand);
  17713 
  17714     const r_brace_src = inst_data.src();
  17715     const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
  17716     const base_tag = sema.fn_ret_ty.baseZigTypeTag(mod);
  17717     if (base_tag == .NoReturn) {
  17718         const msg = msg: {
  17719             const msg = try sema.errMsg(block, ret_ty_src, "function declared '{}' implicitly returns", .{
  17720                 sema.fn_ret_ty.fmt(mod),
  17721             });
  17722             errdefer msg.destroy(sema.gpa);
  17723             try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{});
  17724             break :msg msg;
  17725         };
  17726         return sema.failWithOwnedErrorMsg(msg);
  17727     } else if (base_tag != .Void) {
  17728         const msg = msg: {
  17729             const msg = try sema.errMsg(block, ret_ty_src, "function with non-void return type '{}' implicitly returns", .{
  17730                 sema.fn_ret_ty.fmt(mod),
  17731             });
  17732             errdefer msg.destroy(sema.gpa);
  17733             try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{});
  17734             break :msg msg;
  17735         };
  17736         return sema.failWithOwnedErrorMsg(msg);
  17737     }
  17738 
  17739     return sema.analyzeRet(block, operand, .unneeded);
  17740 }
  17741 
  17742 fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
  17743     const tracy = trace(@src());
  17744     defer tracy.end();
  17745 
  17746     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  17747     const operand = try sema.resolveInst(inst_data.operand);
  17748     const src = inst_data.src();
  17749 
  17750     return sema.analyzeRet(block, operand, src);
  17751 }
  17752 
  17753 fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
  17754     const tracy = trace(@src());
  17755     defer tracy.end();
  17756 
  17757     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  17758     const src = inst_data.src();
  17759     const ret_ptr = try sema.resolveInst(inst_data.operand);
  17760 
  17761     if (block.is_comptime or block.inlining != null) {
  17762         const operand = try sema.analyzeLoad(block, src, ret_ptr, src);
  17763         return sema.analyzeRet(block, operand, src);
  17764     }
  17765 
  17766     if (sema.wantErrorReturnTracing(sema.fn_ret_ty)) {
  17767         const is_non_err = try sema.analyzePtrIsNonErr(block, src, ret_ptr);
  17768         return sema.retWithErrTracing(block, is_non_err, .ret_load, ret_ptr);
  17769     }
  17770 
  17771     _ = try block.addUnOp(.ret_load, ret_ptr);
  17772     return always_noreturn;
  17773 }
  17774 
  17775 fn retWithErrTracing(
  17776     sema: *Sema,
  17777     block: *Block,
  17778     is_non_err: Air.Inst.Ref,
  17779     ret_tag: Air.Inst.Tag,
  17780     operand: Air.Inst.Ref,
  17781 ) CompileError!Zir.Inst.Index {
  17782     const mod = sema.mod;
  17783     const need_check = switch (is_non_err) {
  17784         .bool_true => {
  17785             _ = try block.addUnOp(ret_tag, operand);
  17786             return always_noreturn;
  17787         },
  17788         .bool_false => false,
  17789         else => true,
  17790     };
  17791     const gpa = sema.gpa;
  17792     const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
  17793     const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
  17794     const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty);
  17795     const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
  17796     const return_err_fn = try sema.getBuiltin("returnError");
  17797     const args: [1]Air.Inst.Ref = .{err_return_trace};
  17798 
  17799     if (!need_check) {
  17800         try sema.callBuiltin(block, return_err_fn, .never_inline, &args);
  17801         _ = try block.addUnOp(ret_tag, operand);
  17802         return always_noreturn;
  17803     }
  17804 
  17805     var then_block = block.makeSubBlock();
  17806     defer then_block.instructions.deinit(gpa);
  17807     _ = try then_block.addUnOp(ret_tag, operand);
  17808 
  17809     var else_block = block.makeSubBlock();
  17810     defer else_block.instructions.deinit(gpa);
  17811     try sema.callBuiltin(&else_block, return_err_fn, .never_inline, &args);
  17812     _ = try else_block.addUnOp(ret_tag, operand);
  17813 
  17814     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
  17815         then_block.instructions.items.len + else_block.instructions.items.len +
  17816         @typeInfo(Air.Block).Struct.fields.len + 1);
  17817 
  17818     const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{
  17819         .then_body_len = @intCast(u32, then_block.instructions.items.len),
  17820         .else_body_len = @intCast(u32, else_block.instructions.items.len),
  17821     });
  17822     sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items);
  17823     sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items);
  17824 
  17825     _ = try block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{
  17826         .operand = is_non_err,
  17827         .payload = cond_br_payload,
  17828     } } });
  17829 
  17830     return always_noreturn;
  17831 }
  17832 
  17833 fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool {
  17834     const mod = sema.mod;
  17835     if (!mod.backendSupportsFeature(.error_return_trace)) return false;
  17836 
  17837     return fn_ret_ty.isError(mod) and
  17838         mod.comp.bin_file.options.error_return_tracing;
  17839 }
  17840 
  17841 fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
  17842     const mod = sema.mod;
  17843     const inst_data = sema.code.instructions.items(.data)[inst].save_err_ret_index;
  17844 
  17845     if (!mod.backendSupportsFeature(.error_return_trace)) return;
  17846     if (!mod.comp.bin_file.options.error_return_tracing) return;
  17847 
  17848     // This is only relevant at runtime.
  17849     if (block.is_comptime or block.is_typeof) return;
  17850 
  17851     const save_index = inst_data.operand == .none or b: {
  17852         const operand = try sema.resolveInst(inst_data.operand);
  17853         const operand_ty = sema.typeOf(operand);
  17854         break :b operand_ty.isError(mod);
  17855     };
  17856 
  17857     if (save_index)
  17858         block.error_return_trace_index = try sema.analyzeSaveErrRetIndex(block);
  17859 }
  17860 
  17861 fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError!void {
  17862     const inst_data = sema.code.instructions.items(.data)[inst].restore_err_ret_index;
  17863     const src = sema.src; // TODO
  17864 
  17865     // This is only relevant at runtime.
  17866     if (start_block.is_comptime or start_block.is_typeof) return;
  17867 
  17868     if (!sema.mod.backendSupportsFeature(.error_return_trace)) return;
  17869     if (!sema.owner_func.?.calls_or_awaits_errorable_fn) return;
  17870     if (!sema.mod.comp.bin_file.options.error_return_tracing) return;
  17871 
  17872     const tracy = trace(@src());
  17873     defer tracy.end();
  17874 
  17875     const saved_index = if (Zir.refToIndexAllowNone(inst_data.block)) |zir_block| b: {
  17876         var block = start_block;
  17877         while (true) {
  17878             if (block.label) |label| {
  17879                 if (label.zir_block == zir_block) {
  17880                     const target_trace_index = if (block.parent) |parent_block| tgt: {
  17881                         break :tgt parent_block.error_return_trace_index;
  17882                     } else sema.error_return_trace_index_on_fn_entry;
  17883 
  17884                     if (start_block.error_return_trace_index != target_trace_index)
  17885                         break :b target_trace_index;
  17886 
  17887                     return; // No need to restore
  17888                 }
  17889             }
  17890             block = block.parent.?;
  17891         }
  17892     } else b: {
  17893         if (start_block.error_return_trace_index != sema.error_return_trace_index_on_fn_entry)
  17894             break :b sema.error_return_trace_index_on_fn_entry;
  17895 
  17896         return; // No need to restore
  17897     };
  17898 
  17899     assert(saved_index != .none); // The .error_return_trace_index field was dropped somewhere
  17900 
  17901     const operand = try sema.resolveInstAllowNone(inst_data.operand);
  17902     return sema.popErrorReturnTrace(start_block, src, operand, saved_index);
  17903 }
  17904 
  17905 fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void {
  17906     const mod = sema.mod;
  17907     const gpa = sema.gpa;
  17908     const ip = &mod.intern_pool;
  17909     assert(sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion);
  17910 
  17911     if (mod.typeToInferredErrorSet(sema.fn_ret_ty.errorUnionSet(mod))) |ies| {
  17912         const op_ty = sema.typeOf(uncasted_operand);
  17913         switch (op_ty.zigTypeTag(mod)) {
  17914             .ErrorSet => try ies.addErrorSet(op_ty, ip, gpa),
  17915             .ErrorUnion => try ies.addErrorSet(op_ty.errorUnionSet(mod), ip, gpa),
  17916             else => {},
  17917         }
  17918     }
  17919 }
  17920 
  17921 fn analyzeRet(
  17922     sema: *Sema,
  17923     block: *Block,
  17924     uncasted_operand: Air.Inst.Ref,
  17925     src: LazySrcLoc,
  17926 ) CompileError!Zir.Inst.Index {
  17927     // Special case for returning an error to an inferred error set; we need to
  17928     // add the error tag to the inferred error set of the in-scope function, so
  17929     // that the coercion below works correctly.
  17930     const mod = sema.mod;
  17931     if (sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion) {
  17932         try sema.addToInferredErrorSet(uncasted_operand);
  17933     }
  17934     const operand = sema.coerceExtra(block, sema.fn_ret_ty, uncasted_operand, src, .{ .is_ret = true }) catch |err| switch (err) {
  17935         error.NotCoercible => unreachable,
  17936         else => |e| return e,
  17937     };
  17938 
  17939     if (block.inlining) |inlining| {
  17940         if (block.is_comptime) {
  17941             _ = try sema.resolveConstMaybeUndefVal(block, src, operand, "value being returned at comptime must be comptime-known");
  17942             inlining.comptime_result = operand;
  17943             return error.ComptimeReturn;
  17944         }
  17945         // We are inlining a function call; rewrite the `ret` as a `break`.
  17946         try inlining.merges.results.append(sema.gpa, operand);
  17947         _ = try block.addBr(inlining.merges.block_inst, operand);
  17948         return always_noreturn;
  17949     } else if (block.is_comptime) {
  17950         return sema.fail(block, src, "function called at runtime cannot return value at comptime", .{});
  17951     }
  17952 
  17953     try sema.resolveTypeLayout(sema.fn_ret_ty);
  17954 
  17955     if (sema.wantErrorReturnTracing(sema.fn_ret_ty)) {
  17956         // Avoid adding a frame to the error return trace in case the value is comptime-known
  17957         // to be not an error.
  17958         const is_non_err = try sema.analyzeIsNonErr(block, src, operand);
  17959         return sema.retWithErrTracing(block, is_non_err, .ret, operand);
  17960     }
  17961 
  17962     _ = try block.addUnOp(.ret, operand);
  17963 
  17964     return always_noreturn;
  17965 }
  17966 
  17967 fn floatOpAllowed(tag: Zir.Inst.Tag) bool {
  17968     // extend this swich as additional operators are implemented
  17969     return switch (tag) {
  17970         .add, .sub, .mul, .div, .div_exact, .div_trunc, .div_floor, .mod, .rem, .mod_rem => true,
  17971         else => false,
  17972     };
  17973 }
  17974 
  17975 fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  17976     const tracy = trace(@src());
  17977     defer tracy.end();
  17978 
  17979     const mod = sema.mod;
  17980     const inst_data = sema.code.instructions.items(.data)[inst].ptr_type;
  17981     const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index);
  17982     const elem_ty_src: LazySrcLoc = .{ .node_offset_ptr_elem = extra.data.src_node };
  17983     const sentinel_src: LazySrcLoc = .{ .node_offset_ptr_sentinel = extra.data.src_node };
  17984     const align_src: LazySrcLoc = .{ .node_offset_ptr_align = extra.data.src_node };
  17985     const addrspace_src: LazySrcLoc = .{ .node_offset_ptr_addrspace = extra.data.src_node };
  17986     const bitoffset_src: LazySrcLoc = .{ .node_offset_ptr_bitoffset = extra.data.src_node };
  17987     const hostsize_src: LazySrcLoc = .{ .node_offset_ptr_hostsize = extra.data.src_node };
  17988 
  17989     const elem_ty = blk: {
  17990         const air_inst = try sema.resolveInst(extra.data.elem_type);
  17991         const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| {
  17992             if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer(mod)) {
  17993                 try sema.errNote(block, elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{});
  17994             }
  17995             return err;
  17996         };
  17997         if (ty.isGenericPoison()) return error.GenericPoison;
  17998         break :blk ty;
  17999     };
  18000 
  18001     if (elem_ty.zigTypeTag(mod) == .NoReturn)
  18002         return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{});
  18003 
  18004     const target = sema.mod.getTarget();
  18005 
  18006     var extra_i = extra.end;
  18007 
  18008     const sentinel = if (inst_data.flags.has_sentinel) blk: {
  18009         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
  18010         extra_i += 1;
  18011         const coerced = try sema.coerce(block, elem_ty, try sema.resolveInst(ref), sentinel_src);
  18012         const val = try sema.resolveConstValue(block, sentinel_src, coerced, "pointer sentinel value must be comptime-known");
  18013         break :blk val.toIntern();
  18014     } else .none;
  18015 
  18016     const abi_align: InternPool.Alignment = if (inst_data.flags.has_align) blk: {
  18017         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
  18018         extra_i += 1;
  18019         const coerced = try sema.coerce(block, Type.u32, try sema.resolveInst(ref), align_src);
  18020         const val = try sema.resolveConstValue(block, align_src, coerced, "pointer alignment must be comptime-known");
  18021         // Check if this happens to be the lazy alignment of our element type, in
  18022         // which case we can make this 0 without resolving it.
  18023         switch (mod.intern_pool.indexToKey(val.toIntern())) {
  18024             .int => |int| switch (int.storage) {
  18025                 .lazy_align => |lazy_ty| if (lazy_ty == elem_ty.toIntern()) break :blk .none,
  18026                 else => {},
  18027             },
  18028             else => {},
  18029         }
  18030         const abi_align = @intCast(u32, (try val.getUnsignedIntAdvanced(mod, sema)).?);
  18031         try sema.validateAlign(block, align_src, abi_align);
  18032         break :blk InternPool.Alignment.fromByteUnits(abi_align);
  18033     } else .none;
  18034 
  18035     const address_space: std.builtin.AddressSpace = if (inst_data.flags.has_addrspace) blk: {
  18036         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
  18037         extra_i += 1;
  18038         break :blk try sema.analyzeAddressSpace(block, addrspace_src, ref, .pointer);
  18039     } else if (elem_ty.zigTypeTag(mod) == .Fn and target.cpu.arch == .avr) .flash else .generic;
  18040 
  18041     const bit_offset = if (inst_data.flags.has_bit_range) blk: {
  18042         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
  18043         extra_i += 1;
  18044         const bit_offset = try sema.resolveInt(block, bitoffset_src, ref, Type.u16, "pointer bit-offset must be comptime-known");
  18045         break :blk @intCast(u16, bit_offset);
  18046     } else 0;
  18047 
  18048     const host_size: u16 = if (inst_data.flags.has_bit_range) blk: {
  18049         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
  18050         extra_i += 1;
  18051         const host_size = try sema.resolveInt(block, hostsize_src, ref, Type.u16, "pointer host size must be comptime-known");
  18052         break :blk @intCast(u16, host_size);
  18053     } else 0;
  18054 
  18055     if (host_size != 0 and bit_offset >= host_size * 8) {
  18056         return sema.fail(block, bitoffset_src, "bit offset starts after end of host integer", .{});
  18057     }
  18058 
  18059     if (elem_ty.zigTypeTag(mod) == .Fn) {
  18060         if (inst_data.size != .One) {
  18061             return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{});
  18062         }
  18063         const fn_align = mod.typeToFunc(elem_ty).?.alignment;
  18064         if (inst_data.flags.has_align and abi_align != .none and fn_align != .none and
  18065             abi_align != fn_align)
  18066         {
  18067             return sema.fail(block, align_src, "function pointer alignment disagrees with function alignment", .{});
  18068         }
  18069     } else if (inst_data.size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) {
  18070         return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{});
  18071     } else if (inst_data.size == .C) {
  18072         if (!try sema.validateExternType(elem_ty, .other)) {
  18073             const msg = msg: {
  18074                 const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)});
  18075                 errdefer msg.destroy(sema.gpa);
  18076 
  18077                 const src_decl = sema.mod.declPtr(block.src_decl);
  18078                 try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src.toSrcLoc(src_decl, mod), elem_ty, .other);
  18079 
  18080                 try sema.addDeclaredHereNote(msg, elem_ty);
  18081                 break :msg msg;
  18082             };
  18083             return sema.failWithOwnedErrorMsg(msg);
  18084         }
  18085         if (elem_ty.zigTypeTag(mod) == .Opaque) {
  18086             return sema.fail(block, elem_ty_src, "C pointers cannot point to opaque types", .{});
  18087         }
  18088     }
  18089 
  18090     const ty = try mod.ptrType(.{
  18091         .child = elem_ty.toIntern(),
  18092         .sentinel = sentinel,
  18093         .flags = .{
  18094             .alignment = abi_align,
  18095             .address_space = address_space,
  18096             .is_const = !inst_data.flags.is_mutable,
  18097             .is_allowzero = inst_data.flags.is_allowzero,
  18098             .is_volatile = inst_data.flags.is_volatile,
  18099             .size = inst_data.size,
  18100         },
  18101         .packed_offset = .{
  18102             .bit_offset = bit_offset,
  18103             .host_size = host_size,
  18104         },
  18105     });
  18106     return sema.addType(ty);
  18107 }
  18108 
  18109 fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  18110     const tracy = trace(@src());
  18111     defer tracy.end();
  18112 
  18113     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  18114     const src = inst_data.src();
  18115     const obj_ty = try sema.resolveType(block, src, inst_data.operand);
  18116     const mod = sema.mod;
  18117 
  18118     switch (obj_ty.zigTypeTag(mod)) {
  18119         .Struct => return sema.structInitEmpty(block, obj_ty, src, src),
  18120         .Array, .Vector => return sema.arrayInitEmpty(block, src, obj_ty),
  18121         .Void => return sema.addConstant(obj_ty, Value.void),
  18122         .Union => return sema.fail(block, src, "union initializer must initialize one field", .{}),
  18123         else => return sema.failWithArrayInitNotSupported(block, src, obj_ty),
  18124     }
  18125 }
  18126 
  18127 fn structInitEmpty(
  18128     sema: *Sema,
  18129     block: *Block,
  18130     obj_ty: Type,
  18131     dest_src: LazySrcLoc,
  18132     init_src: LazySrcLoc,
  18133 ) CompileError!Air.Inst.Ref {
  18134     const mod = sema.mod;
  18135     const gpa = sema.gpa;
  18136     // This logic must be synchronized with that in `zirStructInit`.
  18137     const struct_ty = try sema.resolveTypeFields(obj_ty);
  18138 
  18139     // The init values to use for the struct instance.
  18140     const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount(mod));
  18141     defer gpa.free(field_inits);
  18142     @memset(field_inits, .none);
  18143 
  18144     return sema.finishStructInit(block, init_src, dest_src, field_inits, struct_ty, false);
  18145 }
  18146 
  18147 fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) CompileError!Air.Inst.Ref {
  18148     const mod = sema.mod;
  18149     const arr_len = obj_ty.arrayLen(mod);
  18150     if (arr_len != 0) {
  18151         if (obj_ty.zigTypeTag(mod) == .Array) {
  18152             return sema.fail(block, src, "expected {d} array elements; found 0", .{arr_len});
  18153         } else {
  18154             return sema.fail(block, src, "expected {d} vector elements; found 0", .{arr_len});
  18155         }
  18156     }
  18157     return sema.addConstant(obj_ty, (try mod.intern(.{ .aggregate = .{
  18158         .ty = obj_ty.toIntern(),
  18159         .storage = .{ .elems = &.{} },
  18160     } })).toValue());
  18161 }
  18162 
  18163 fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  18164     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  18165     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  18166     const field_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  18167     const init_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  18168     const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
  18169     const union_ty = try sema.resolveType(block, ty_src, extra.union_type);
  18170     const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "name of field being initialized must be comptime-known");
  18171     const init = try sema.resolveInst(extra.init);
  18172     return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src);
  18173 }
  18174 
  18175 fn unionInit(
  18176     sema: *Sema,
  18177     block: *Block,
  18178     uncasted_init: Air.Inst.Ref,
  18179     init_src: LazySrcLoc,
  18180     union_ty: Type,
  18181     union_ty_src: LazySrcLoc,
  18182     field_name: []const u8,
  18183     field_src: LazySrcLoc,
  18184 ) CompileError!Air.Inst.Ref {
  18185     const mod = sema.mod;
  18186     const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
  18187     const field = union_ty.unionFields(mod).values()[field_index];
  18188     const init = try sema.coerce(block, field.ty, uncasted_init, init_src);
  18189 
  18190     if (try sema.resolveMaybeUndefVal(init)) |init_val| {
  18191         const tag_ty = union_ty.unionTagTypeHypothetical(mod);
  18192         const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?);
  18193         const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
  18194         return sema.addConstant(union_ty, (try mod.intern(.{ .un = .{
  18195             .ty = union_ty.toIntern(),
  18196             .tag = try tag_val.intern(tag_ty, mod),
  18197             .val = try init_val.intern(field.ty, mod),
  18198         } })).toValue());
  18199     }
  18200 
  18201     try sema.requireRuntimeBlock(block, init_src, null);
  18202     _ = union_ty_src;
  18203     try sema.queueFullTypeResolution(union_ty);
  18204     return block.addUnionInit(union_ty, field_index, init);
  18205 }
  18206 
  18207 fn zirStructInit(
  18208     sema: *Sema,
  18209     block: *Block,
  18210     inst: Zir.Inst.Index,
  18211     is_ref: bool,
  18212 ) CompileError!Air.Inst.Ref {
  18213     const gpa = sema.gpa;
  18214     const zir_datas = sema.code.instructions.items(.data);
  18215     const inst_data = zir_datas[inst].pl_node;
  18216     const extra = sema.code.extraData(Zir.Inst.StructInit, inst_data.payload_index);
  18217     const src = inst_data.src();
  18218 
  18219     const mod = sema.mod;
  18220     const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data;
  18221     const first_field_type_data = zir_datas[first_item.field_type].pl_node;
  18222     const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data;
  18223     const resolved_ty = try sema.resolveType(block, src, first_field_type_extra.container_type);
  18224     try sema.resolveTypeLayout(resolved_ty);
  18225 
  18226     if (resolved_ty.zigTypeTag(mod) == .Struct) {
  18227         // This logic must be synchronized with that in `zirStructInitEmpty`.
  18228 
  18229         // Maps field index to field_type index of where it was already initialized.
  18230         // For making sure all fields are accounted for and no fields are duplicated.
  18231         const found_fields = try gpa.alloc(Zir.Inst.Index, resolved_ty.structFieldCount(mod));
  18232         defer gpa.free(found_fields);
  18233 
  18234         // The init values to use for the struct instance.
  18235         const field_inits = try gpa.alloc(Air.Inst.Ref, resolved_ty.structFieldCount(mod));
  18236         defer gpa.free(field_inits);
  18237         @memset(field_inits, .none);
  18238 
  18239         var field_i: u32 = 0;
  18240         var extra_index = extra.end;
  18241 
  18242         const is_packed = resolved_ty.containerLayout(mod) == .Packed;
  18243         while (field_i < extra.data.fields_len) : (field_i += 1) {
  18244             const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index);
  18245             extra_index = item.end;
  18246 
  18247             const field_type_data = zir_datas[item.data.field_type].pl_node;
  18248             const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };
  18249             const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
  18250             const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
  18251             const field_index = if (resolved_ty.isTuple(mod))
  18252                 try sema.tupleFieldIndex(block, resolved_ty, field_name, field_src)
  18253             else
  18254                 try sema.structFieldIndex(block, resolved_ty, field_name, field_src);
  18255             if (field_inits[field_index] != .none) {
  18256                 const other_field_type = found_fields[field_index];
  18257                 const other_field_type_data = zir_datas[other_field_type].pl_node;
  18258                 const other_field_src: LazySrcLoc = .{ .node_offset_initializer = other_field_type_data.src_node };
  18259                 const msg = msg: {
  18260                     const msg = try sema.errMsg(block, field_src, "duplicate field", .{});
  18261                     errdefer msg.destroy(gpa);
  18262                     try sema.errNote(block, other_field_src, msg, "other field here", .{});
  18263                     break :msg msg;
  18264                 };
  18265                 return sema.failWithOwnedErrorMsg(msg);
  18266             }
  18267             found_fields[field_index] = item.data.field_type;
  18268             field_inits[field_index] = try sema.resolveInst(item.data.init);
  18269             if (!is_packed) if (try resolved_ty.structFieldValueComptime(mod, field_index)) |default_value| {
  18270                 const init_val = (try sema.resolveMaybeUndefVal(field_inits[field_index])) orelse {
  18271                     return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known");
  18272                 };
  18273 
  18274                 if (!init_val.eql(default_value, resolved_ty.structFieldType(field_index, mod), sema.mod)) {
  18275                     return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index);
  18276                 }
  18277             };
  18278         }
  18279 
  18280         return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref);
  18281     } else if (resolved_ty.zigTypeTag(mod) == .Union) {
  18282         if (extra.data.fields_len != 1) {
  18283             return sema.fail(block, src, "union initialization expects exactly one field", .{});
  18284         }
  18285 
  18286         const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end);
  18287 
  18288         const field_type_data = zir_datas[item.data.field_type].pl_node;
  18289         const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };
  18290         const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
  18291         const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
  18292         const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
  18293         const tag_ty = resolved_ty.unionTagTypeHypothetical(mod);
  18294         const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?);
  18295         const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
  18296 
  18297         const init_inst = try sema.resolveInst(item.data.init);
  18298         if (try sema.resolveMaybeUndefVal(init_inst)) |val| {
  18299             const field = resolved_ty.unionFields(mod).values()[field_index];
  18300             return sema.addConstantMaybeRef(block, resolved_ty, (try mod.intern(.{ .un = .{
  18301                 .ty = resolved_ty.toIntern(),
  18302                 .tag = try tag_val.intern(tag_ty, mod),
  18303                 .val = try val.intern(field.ty, mod),
  18304             } })).toValue(), is_ref);
  18305         }
  18306 
  18307         if (is_ref) {
  18308             const target = sema.mod.getTarget();
  18309             const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
  18310                 .pointee_type = resolved_ty,
  18311                 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  18312             });
  18313             const alloc = try block.addTy(.alloc, alloc_ty);
  18314             const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true);
  18315             try sema.storePtr(block, src, field_ptr, init_inst);
  18316             const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(mod), tag_val);
  18317             _ = try block.addBinOp(.set_union_tag, alloc, new_tag);
  18318             return sema.makePtrConst(block, alloc);
  18319         }
  18320 
  18321         try sema.requireRuntimeBlock(block, src, null);
  18322         try sema.queueFullTypeResolution(resolved_ty);
  18323         return block.addUnionInit(resolved_ty, field_index, init_inst);
  18324     } else if (resolved_ty.isAnonStruct(mod)) {
  18325         return sema.fail(block, src, "TODO anon struct init validation", .{});
  18326     }
  18327     unreachable;
  18328 }
  18329 
  18330 fn finishStructInit(
  18331     sema: *Sema,
  18332     block: *Block,
  18333     init_src: LazySrcLoc,
  18334     dest_src: LazySrcLoc,
  18335     field_inits: []Air.Inst.Ref,
  18336     struct_ty: Type,
  18337     is_ref: bool,
  18338 ) CompileError!Air.Inst.Ref {
  18339     const mod = sema.mod;
  18340     const gpa = sema.gpa;
  18341 
  18342     var root_msg: ?*Module.ErrorMsg = null;
  18343     errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
  18344 
  18345     switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) {
  18346         .anon_struct_type => |anon_struct| {
  18347             for (anon_struct.types, anon_struct.values, 0..) |field_ty, default_val, i| {
  18348                 if (field_inits[i] != .none) continue;
  18349 
  18350                 if (default_val == .none) {
  18351                     if (anon_struct.names.len == 0) {
  18352                         const template = "missing tuple field with index {d}";
  18353                         if (root_msg) |msg| {
  18354                             try sema.errNote(block, init_src, msg, template, .{i});
  18355                         } else {
  18356                             root_msg = try sema.errMsg(block, init_src, template, .{i});
  18357                         }
  18358                     } else {
  18359                         const field_name = mod.intern_pool.stringToSlice(anon_struct.names[i]);
  18360                         const template = "missing struct field: {s}";
  18361                         const args = .{field_name};
  18362                         if (root_msg) |msg| {
  18363                             try sema.errNote(block, init_src, msg, template, args);
  18364                         } else {
  18365                             root_msg = try sema.errMsg(block, init_src, template, args);
  18366                         }
  18367                     }
  18368                 } else {
  18369                     field_inits[i] = try sema.addConstant(field_ty.toType(), default_val.toValue());
  18370                 }
  18371             }
  18372         },
  18373         .struct_type => |struct_type| {
  18374             const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
  18375             for (struct_obj.fields.values(), 0..) |field, i| {
  18376                 if (field_inits[i] != .none) continue;
  18377 
  18378                 if (field.default_val.toIntern() == .unreachable_value) {
  18379                     const field_name = struct_obj.fields.keys()[i];
  18380                     const template = "missing struct field: {s}";
  18381                     const args = .{field_name};
  18382                     if (root_msg) |msg| {
  18383                         try sema.errNote(block, init_src, msg, template, args);
  18384                     } else {
  18385                         root_msg = try sema.errMsg(block, init_src, template, args);
  18386                     }
  18387                 } else {
  18388                     field_inits[i] = try sema.addConstant(field.ty, field.default_val);
  18389                 }
  18390             }
  18391         },
  18392         else => unreachable,
  18393     }
  18394 
  18395     if (root_msg) |msg| {
  18396         if (mod.typeToStruct(struct_ty)) |struct_obj| {
  18397             const fqn = try struct_obj.getFullyQualifiedName(sema.mod);
  18398             defer gpa.free(fqn);
  18399             try sema.mod.errNoteNonLazy(
  18400                 struct_obj.srcLoc(sema.mod),
  18401                 msg,
  18402                 "struct '{s}' declared here",
  18403                 .{fqn},
  18404             );
  18405         }
  18406         root_msg = null;
  18407         return sema.failWithOwnedErrorMsg(msg);
  18408     }
  18409 
  18410     // Find which field forces the expression to be runtime, if any.
  18411     const opt_runtime_index = for (field_inits, 0..) |field_init, i| {
  18412         if (!(try sema.isComptimeKnown(field_init))) {
  18413             break i;
  18414         }
  18415     } else null;
  18416 
  18417     const runtime_index = opt_runtime_index orelse {
  18418         const elems = try sema.arena.alloc(InternPool.Index, field_inits.len);
  18419         for (elems, field_inits, 0..) |*elem, field_init, field_i| {
  18420             elem.* = try (sema.resolveMaybeUndefVal(field_init) catch unreachable).?
  18421                 .intern(struct_ty.structFieldType(field_i, mod), mod);
  18422         }
  18423         const struct_val = try mod.intern(.{ .aggregate = .{
  18424             .ty = struct_ty.toIntern(),
  18425             .storage = .{ .elems = elems },
  18426         } });
  18427         return sema.addConstantMaybeRef(block, struct_ty, struct_val.toValue(), is_ref);
  18428     };
  18429 
  18430     if (is_ref) {
  18431         try sema.resolveStructLayout(struct_ty);
  18432         const target = sema.mod.getTarget();
  18433         const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
  18434             .pointee_type = struct_ty,
  18435             .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  18436         });
  18437         const alloc = try block.addTy(.alloc, alloc_ty);
  18438         for (field_inits, 0..) |field_init, i_usize| {
  18439             const i = @intCast(u32, i_usize);
  18440             const field_src = dest_src;
  18441             const field_ptr = try sema.structFieldPtrByIndex(block, dest_src, alloc, i, field_src, struct_ty, true);
  18442             try sema.storePtr(block, dest_src, field_ptr, field_init);
  18443         }
  18444 
  18445         return sema.makePtrConst(block, alloc);
  18446     }
  18447 
  18448     sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) {
  18449         error.NeededSourceLocation => {
  18450             const decl = mod.declPtr(block.src_decl);
  18451             const field_src = mod.initSrc(dest_src.node_offset.x, decl, runtime_index);
  18452             try sema.requireRuntimeBlock(block, dest_src, field_src);
  18453             unreachable;
  18454         },
  18455         else => |e| return e,
  18456     };
  18457     try sema.queueFullTypeResolution(struct_ty);
  18458     return block.addAggregateInit(struct_ty, field_inits);
  18459 }
  18460 
  18461 fn zirStructInitAnon(
  18462     sema: *Sema,
  18463     block: *Block,
  18464     inst: Zir.Inst.Index,
  18465     is_ref: bool,
  18466 ) CompileError!Air.Inst.Ref {
  18467     const mod = sema.mod;
  18468     const gpa = sema.gpa;
  18469     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  18470     const src = inst_data.src();
  18471     const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);
  18472     const types = try sema.arena.alloc(InternPool.Index, extra.data.fields_len);
  18473     const values = try sema.arena.alloc(InternPool.Index, types.len);
  18474     var fields = std.AutoArrayHashMap(InternPool.NullTerminatedString, u32).init(sema.arena);
  18475     try fields.ensureUnusedCapacity(types.len);
  18476 
  18477     // Find which field forces the expression to be runtime, if any.
  18478     const opt_runtime_index = rs: {
  18479         var runtime_index: ?usize = null;
  18480         var extra_index = extra.end;
  18481         for (types, 0..) |*field_ty, i_usize| {
  18482             const i = @intCast(u32, i_usize);
  18483             const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
  18484             extra_index = item.end;
  18485 
  18486             const name = sema.code.nullTerminatedString(item.data.field_name);
  18487             const name_ip = try mod.intern_pool.getOrPutString(gpa, name);
  18488             const gop = fields.getOrPutAssumeCapacity(name_ip);
  18489             if (gop.found_existing) {
  18490                 const msg = msg: {
  18491                     const decl = sema.mod.declPtr(block.src_decl);
  18492                     const field_src = mod.initSrc(src.node_offset.x, decl, i);
  18493                     const msg = try sema.errMsg(block, field_src, "duplicate field", .{});
  18494                     errdefer msg.destroy(gpa);
  18495 
  18496                     const prev_source = mod.initSrc(src.node_offset.x, decl, gop.value_ptr.*);
  18497                     try sema.errNote(block, prev_source, msg, "other field here", .{});
  18498                     break :msg msg;
  18499                 };
  18500                 return sema.failWithOwnedErrorMsg(msg);
  18501             }
  18502             gop.value_ptr.* = i;
  18503 
  18504             const init = try sema.resolveInst(item.data.init);
  18505             field_ty.* = sema.typeOf(init).toIntern();
  18506             if (field_ty.toType().zigTypeTag(mod) == .Opaque) {
  18507                 const msg = msg: {
  18508                     const decl = sema.mod.declPtr(block.src_decl);
  18509                     const field_src = mod.initSrc(src.node_offset.x, decl, i);
  18510                     const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
  18511                     errdefer msg.destroy(sema.gpa);
  18512 
  18513                     try sema.addDeclaredHereNote(msg, field_ty.toType());
  18514                     break :msg msg;
  18515                 };
  18516                 return sema.failWithOwnedErrorMsg(msg);
  18517             }
  18518             if (try sema.resolveMaybeUndefVal(init)) |init_val| {
  18519                 values[i] = try init_val.intern(field_ty.toType(), mod);
  18520             } else {
  18521                 values[i] = .none;
  18522                 runtime_index = i;
  18523             }
  18524         }
  18525         break :rs runtime_index;
  18526     };
  18527 
  18528     const tuple_ty = try mod.intern(.{ .anon_struct_type = .{
  18529         .names = fields.keys(),
  18530         .types = types,
  18531         .values = values,
  18532     } });
  18533 
  18534     const runtime_index = opt_runtime_index orelse {
  18535         const tuple_val = try mod.intern(.{ .aggregate = .{
  18536             .ty = tuple_ty,
  18537             .storage = .{ .elems = values },
  18538         } });
  18539         return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref);
  18540     };
  18541 
  18542     sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) {
  18543         error.NeededSourceLocation => {
  18544             const decl = sema.mod.declPtr(block.src_decl);
  18545             const field_src = mod.initSrc(src.node_offset.x, decl, runtime_index);
  18546             try sema.requireRuntimeBlock(block, src, field_src);
  18547             unreachable;
  18548         },
  18549         else => |e| return e,
  18550     };
  18551 
  18552     if (is_ref) {
  18553         const target = sema.mod.getTarget();
  18554         const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
  18555             .pointee_type = tuple_ty.toType(),
  18556             .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  18557         });
  18558         const alloc = try block.addTy(.alloc, alloc_ty);
  18559         var extra_index = extra.end;
  18560         for (types, 0..) |field_ty, i_usize| {
  18561             const i = @intCast(u32, i_usize);
  18562             const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
  18563             extra_index = item.end;
  18564 
  18565             const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
  18566                 .mutable = true,
  18567                 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  18568                 .pointee_type = field_ty.toType(),
  18569             });
  18570             if (values[i] == .none) {
  18571                 const init = try sema.resolveInst(item.data.init);
  18572                 const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty);
  18573                 _ = try block.addBinOp(.store, field_ptr, init);
  18574             }
  18575         }
  18576 
  18577         return sema.makePtrConst(block, alloc);
  18578     }
  18579 
  18580     const element_refs = try sema.arena.alloc(Air.Inst.Ref, types.len);
  18581     var extra_index = extra.end;
  18582     for (types, 0..) |_, i| {
  18583         const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
  18584         extra_index = item.end;
  18585         element_refs[i] = try sema.resolveInst(item.data.init);
  18586     }
  18587 
  18588     return block.addAggregateInit(tuple_ty.toType(), element_refs);
  18589 }
  18590 
  18591 fn zirArrayInit(
  18592     sema: *Sema,
  18593     block: *Block,
  18594     inst: Zir.Inst.Index,
  18595     is_ref: bool,
  18596 ) CompileError!Air.Inst.Ref {
  18597     const mod = sema.mod;
  18598     const gpa = sema.gpa;
  18599     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  18600     const src = inst_data.src();
  18601 
  18602     const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
  18603     const args = sema.code.refSlice(extra.end, extra.data.operands_len);
  18604     assert(args.len >= 2); // array_ty + at least one element
  18605 
  18606     const array_ty = try sema.resolveType(block, src, args[0]);
  18607     const sentinel_val = array_ty.sentinel(mod);
  18608 
  18609     const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @boolToInt(sentinel_val != null));
  18610     defer gpa.free(resolved_args);
  18611     for (args[1..], 0..) |arg, i| {
  18612         const resolved_arg = try sema.resolveInst(arg);
  18613         const elem_ty = if (array_ty.zigTypeTag(mod) == .Struct)
  18614             array_ty.structFieldType(i, mod)
  18615         else
  18616             array_ty.elemType2(mod);
  18617         resolved_args[i] = sema.coerce(block, elem_ty, resolved_arg, .unneeded) catch |err| switch (err) {
  18618             error.NeededSourceLocation => {
  18619                 const decl = sema.mod.declPtr(block.src_decl);
  18620                 const elem_src = mod.initSrc(src.node_offset.x, decl, i);
  18621                 _ = try sema.coerce(block, elem_ty, resolved_arg, elem_src);
  18622                 unreachable;
  18623             },
  18624             else => return err,
  18625         };
  18626     }
  18627 
  18628     if (sentinel_val) |some| {
  18629         resolved_args[resolved_args.len - 1] = try sema.addConstant(array_ty.elemType2(mod), some);
  18630     }
  18631 
  18632     const opt_runtime_index: ?u32 = for (resolved_args, 0..) |arg, i| {
  18633         const comptime_known = try sema.isComptimeKnown(arg);
  18634         if (!comptime_known) break @intCast(u32, i);
  18635     } else null;
  18636 
  18637     const runtime_index = opt_runtime_index orelse {
  18638         const elem_vals = try sema.arena.alloc(InternPool.Index, resolved_args.len);
  18639         for (elem_vals, resolved_args, 0..) |*val, arg, i| {
  18640             const elem_ty = if (array_ty.zigTypeTag(mod) == .Struct)
  18641                 array_ty.structFieldType(i, mod)
  18642             else
  18643                 array_ty.elemType2(mod);
  18644             // We checked that all args are comptime above.
  18645             val.* = try ((sema.resolveMaybeUndefVal(arg) catch unreachable).?).intern(elem_ty, mod);
  18646         }
  18647         return sema.addConstantMaybeRef(block, array_ty, (try mod.intern(.{ .aggregate = .{
  18648             .ty = array_ty.toIntern(),
  18649             .storage = .{ .elems = elem_vals },
  18650         } })).toValue(), is_ref);
  18651     };
  18652 
  18653     sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) {
  18654         error.NeededSourceLocation => {
  18655             const decl = sema.mod.declPtr(block.src_decl);
  18656             const elem_src = mod.initSrc(src.node_offset.x, decl, runtime_index);
  18657             try sema.requireRuntimeBlock(block, src, elem_src);
  18658             unreachable;
  18659         },
  18660         else => return err,
  18661     };
  18662     try sema.queueFullTypeResolution(array_ty);
  18663 
  18664     if (is_ref) {
  18665         const target = sema.mod.getTarget();
  18666         const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
  18667             .pointee_type = array_ty,
  18668             .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  18669         });
  18670         const alloc = try block.addTy(.alloc, alloc_ty);
  18671 
  18672         if (array_ty.isTuple(mod)) {
  18673             for (resolved_args, 0..) |arg, i| {
  18674                 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
  18675                     .mutable = true,
  18676                     .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  18677                     .pointee_type = array_ty.structFieldType(i, mod),
  18678                 });
  18679                 const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);
  18680 
  18681                 const index = try sema.addIntUnsigned(Type.usize, i);
  18682                 const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref);
  18683                 _ = try block.addBinOp(.store, elem_ptr, arg);
  18684             }
  18685             return sema.makePtrConst(block, alloc);
  18686         }
  18687 
  18688         const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
  18689             .mutable = true,
  18690             .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  18691             .pointee_type = array_ty.elemType2(mod),
  18692         });
  18693         const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);
  18694 
  18695         for (resolved_args, 0..) |arg, i| {
  18696             const index = try sema.addIntUnsigned(Type.usize, i);
  18697             const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref);
  18698             _ = try block.addBinOp(.store, elem_ptr, arg);
  18699         }
  18700         return sema.makePtrConst(block, alloc);
  18701     }
  18702 
  18703     return block.addAggregateInit(array_ty, resolved_args);
  18704 }
  18705 
  18706 fn zirArrayInitAnon(
  18707     sema: *Sema,
  18708     block: *Block,
  18709     inst: Zir.Inst.Index,
  18710     is_ref: bool,
  18711 ) CompileError!Air.Inst.Ref {
  18712     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  18713     const src = inst_data.src();
  18714     const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
  18715     const operands = sema.code.refSlice(extra.end, extra.data.operands_len);
  18716     const mod = sema.mod;
  18717 
  18718     const types = try sema.arena.alloc(InternPool.Index, operands.len);
  18719     const values = try sema.arena.alloc(InternPool.Index, operands.len);
  18720 
  18721     const opt_runtime_src = rs: {
  18722         var runtime_src: ?LazySrcLoc = null;
  18723         for (operands, 0..) |operand, i| {
  18724             const operand_src = src; // TODO better source location
  18725             const elem = try sema.resolveInst(operand);
  18726             types[i] = sema.typeOf(elem).toIntern();
  18727             if (types[i].toType().zigTypeTag(mod) == .Opaque) {
  18728                 const msg = msg: {
  18729                     const msg = try sema.errMsg(block, operand_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
  18730                     errdefer msg.destroy(sema.gpa);
  18731 
  18732                     try sema.addDeclaredHereNote(msg, types[i].toType());
  18733                     break :msg msg;
  18734                 };
  18735                 return sema.failWithOwnedErrorMsg(msg);
  18736             }
  18737             if (try sema.resolveMaybeUndefVal(elem)) |val| {
  18738                 values[i] = val.toIntern();
  18739             } else {
  18740                 values[i] = .none;
  18741                 runtime_src = operand_src;
  18742             }
  18743         }
  18744         break :rs runtime_src;
  18745     };
  18746 
  18747     const tuple_ty = try mod.intern(.{ .anon_struct_type = .{
  18748         .types = types,
  18749         .values = values,
  18750         .names = &.{},
  18751     } });
  18752 
  18753     const runtime_src = opt_runtime_src orelse {
  18754         const tuple_val = try mod.intern(.{ .aggregate = .{
  18755             .ty = tuple_ty,
  18756             .storage = .{ .elems = values },
  18757         } });
  18758         return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref);
  18759     };
  18760 
  18761     try sema.requireRuntimeBlock(block, src, runtime_src);
  18762 
  18763     if (is_ref) {
  18764         const target = sema.mod.getTarget();
  18765         const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
  18766             .pointee_type = tuple_ty.toType(),
  18767             .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  18768         });
  18769         const alloc = try block.addTy(.alloc, alloc_ty);
  18770         for (operands, 0..) |operand, i_usize| {
  18771             const i = @intCast(u32, i_usize);
  18772             const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
  18773                 .mutable = true,
  18774                 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
  18775                 .pointee_type = types[i].toType(),
  18776             });
  18777             if (values[i] == .none) {
  18778                 const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty);
  18779                 _ = try block.addBinOp(.store, field_ptr, try sema.resolveInst(operand));
  18780             }
  18781         }
  18782 
  18783         return sema.makePtrConst(block, alloc);
  18784     }
  18785 
  18786     const element_refs = try sema.arena.alloc(Air.Inst.Ref, operands.len);
  18787     for (operands, 0..) |operand, i| {
  18788         element_refs[i] = try sema.resolveInst(operand);
  18789     }
  18790 
  18791     return block.addAggregateInit(tuple_ty.toType(), element_refs);
  18792 }
  18793 
  18794 fn addConstantMaybeRef(
  18795     sema: *Sema,
  18796     block: *Block,
  18797     ty: Type,
  18798     val: Value,
  18799     is_ref: bool,
  18800 ) !Air.Inst.Ref {
  18801     if (!is_ref) return sema.addConstant(ty, val);
  18802 
  18803     var anon_decl = try block.startAnonDecl();
  18804     defer anon_decl.deinit();
  18805     const decl = try anon_decl.finish(
  18806         ty,
  18807         try val.copy(anon_decl.arena()),
  18808         0, // default alignment
  18809     );
  18810     return sema.analyzeDeclRef(decl);
  18811 }
  18812 
  18813 fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  18814     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  18815     const extra = sema.code.extraData(Zir.Inst.FieldTypeRef, inst_data.payload_index).data;
  18816     const ty_src = inst_data.src();
  18817     const field_src = inst_data.src();
  18818     const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);
  18819     const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "field name must be comptime-known");
  18820     return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
  18821 }
  18822 
  18823 fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  18824     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  18825     const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
  18826     const ty_src = inst_data.src();
  18827     const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
  18828     const aggregate_ty = sema.resolveType(block, ty_src, extra.container_type) catch |err| switch (err) {
  18829         // Since this is a ZIR instruction that returns a type, encountering
  18830         // generic poison should not result in a failed compilation, but the
  18831         // generic poison type. This prevents unnecessary failures when
  18832         // constructing types at compile-time.
  18833         error.GenericPoison => return Air.Inst.Ref.generic_poison_type,
  18834         else => |e| return e,
  18835     };
  18836     const field_name = sema.code.nullTerminatedString(extra.name_start);
  18837     return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src);
  18838 }
  18839 
  18840 fn fieldType(
  18841     sema: *Sema,
  18842     block: *Block,
  18843     aggregate_ty: Type,
  18844     field_name: []const u8,
  18845     field_src: LazySrcLoc,
  18846     ty_src: LazySrcLoc,
  18847 ) CompileError!Air.Inst.Ref {
  18848     const mod = sema.mod;
  18849     var cur_ty = aggregate_ty;
  18850     while (true) {
  18851         const resolved_ty = try sema.resolveTypeFields(cur_ty);
  18852         cur_ty = resolved_ty;
  18853         switch (cur_ty.zigTypeTag(mod)) {
  18854             .Struct => switch (mod.intern_pool.indexToKey(cur_ty.toIntern())) {
  18855                 .anon_struct_type => |anon_struct| {
  18856                     const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src);
  18857                     return sema.addType(anon_struct.types[field_index].toType());
  18858                 },
  18859                 .struct_type => |struct_type| {
  18860                     const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
  18861                     const field = struct_obj.fields.get(field_name) orelse
  18862                         return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
  18863                     return sema.addType(field.ty);
  18864                 },
  18865                 else => unreachable,
  18866             },
  18867             .Union => {
  18868                 const union_obj = mod.typeToUnion(cur_ty).?;
  18869                 const field = union_obj.fields.get(field_name) orelse
  18870                     return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
  18871                 return sema.addType(field.ty);
  18872             },
  18873             .Optional => {
  18874                 // Struct/array init through optional requires the child type to not be a pointer.
  18875                 // If the child of .optional is a pointer it'll error on the next loop.
  18876                 cur_ty = mod.intern_pool.indexToKey(cur_ty.toIntern()).opt_type.toType();
  18877                 continue;
  18878             },
  18879             .ErrorUnion => {
  18880                 cur_ty = cur_ty.errorUnionPayload(mod);
  18881                 continue;
  18882             },
  18883             else => {},
  18884         }
  18885         return sema.fail(block, ty_src, "expected struct or union; found '{}'", .{
  18886             resolved_ty.fmt(sema.mod),
  18887         });
  18888     }
  18889 }
  18890 
  18891 fn zirErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
  18892     return sema.getErrorReturnTrace(block);
  18893 }
  18894 
  18895 fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
  18896     const mod = sema.mod;
  18897     const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
  18898     const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
  18899     const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty);
  18900     const opt_ptr_stack_trace_ty = try Type.optional(sema.arena, ptr_stack_trace_ty, mod);
  18901 
  18902     if (sema.owner_func != null and
  18903         sema.owner_func.?.calls_or_awaits_errorable_fn and
  18904         mod.comp.bin_file.options.error_return_tracing and
  18905         mod.backendSupportsFeature(.error_return_trace))
  18906     {
  18907         return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
  18908     }
  18909     return sema.addConstant(opt_ptr_stack_trace_ty, (try mod.intern(.{ .opt = .{
  18910         .ty = opt_ptr_stack_trace_ty.toIntern(),
  18911         .val = .none,
  18912     } })).toValue());
  18913 }
  18914 
  18915 fn zirFrame(
  18916     sema: *Sema,
  18917     block: *Block,
  18918     extended: Zir.Inst.Extended.InstData,
  18919 ) CompileError!Air.Inst.Ref {
  18920     const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
  18921     return sema.failWithUseOfAsync(block, src);
  18922 }
  18923 
  18924 fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  18925     const mod = sema.mod;
  18926     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  18927     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  18928     const ty = try sema.resolveType(block, operand_src, inst_data.operand);
  18929     if (ty.isNoReturn(mod)) {
  18930         return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.mod)});
  18931     }
  18932     const val = try ty.lazyAbiAlignment(mod);
  18933     if (val.isLazyAlign(mod)) {
  18934         try sema.queueFullTypeResolution(ty);
  18935     }
  18936     return sema.addConstant(Type.comptime_int, val);
  18937 }
  18938 
  18939 fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  18940     const mod = sema.mod;
  18941     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  18942     const operand = try sema.resolveInst(inst_data.operand);
  18943     if (try sema.resolveMaybeUndefVal(operand)) |val| {
  18944         if (val.isUndef(mod)) return sema.addConstUndef(Type.u1);
  18945         if (val.toBool()) return sema.addConstant(Type.u1, try mod.intValue(Type.u1, 1));
  18946         return sema.addConstant(Type.u1, try mod.intValue(Type.u1, 0));
  18947     }
  18948     return block.addUnOp(.bool_to_int, operand);
  18949 }
  18950 
  18951 fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  18952     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  18953     const operand = try sema.resolveInst(inst_data.operand);
  18954     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  18955 
  18956     if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {
  18957         const err_name = sema.mod.intern_pool.indexToKey(val.toIntern()).err.name;
  18958         const bytes = sema.mod.intern_pool.stringToSlice(err_name);
  18959         return sema.addStrLit(block, bytes);
  18960     }
  18961 
  18962     // Similar to zirTagName, we have special AIR instruction for the error name in case an optimimzation pass
  18963     // might be able to resolve the result at compile time.
  18964     return block.addUnOp(.error_name, operand);
  18965 }
  18966 
  18967 fn zirUnaryMath(
  18968     sema: *Sema,
  18969     block: *Block,
  18970     inst: Zir.Inst.Index,
  18971     air_tag: Air.Inst.Tag,
  18972     comptime eval: fn (Value, Type, Allocator, *Module) Allocator.Error!Value,
  18973 ) CompileError!Air.Inst.Ref {
  18974     const tracy = trace(@src());
  18975     defer tracy.end();
  18976 
  18977     const mod = sema.mod;
  18978     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  18979     const operand = try sema.resolveInst(inst_data.operand);
  18980     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  18981     const operand_ty = sema.typeOf(operand);
  18982 
  18983     switch (operand_ty.zigTypeTag(mod)) {
  18984         .ComptimeFloat, .Float => {},
  18985         .Vector => {
  18986             const scalar_ty = operand_ty.scalarType(mod);
  18987             switch (scalar_ty.zigTypeTag(mod)) {
  18988                 .ComptimeFloat, .Float => {},
  18989                 else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{scalar_ty.fmt(sema.mod)}),
  18990             }
  18991         },
  18992         else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{operand_ty.fmt(sema.mod)}),
  18993     }
  18994 
  18995     switch (operand_ty.zigTypeTag(mod)) {
  18996         .Vector => {
  18997             const scalar_ty = operand_ty.scalarType(mod);
  18998             const vec_len = operand_ty.vectorLen(mod);
  18999             const result_ty = try mod.vectorType(.{
  19000                 .len = vec_len,
  19001                 .child = scalar_ty.toIntern(),
  19002             });
  19003             if (try sema.resolveMaybeUndefVal(operand)) |val| {
  19004                 if (val.isUndef(mod))
  19005                     return sema.addConstUndef(result_ty);
  19006 
  19007                 const elems = try sema.arena.alloc(InternPool.Index, vec_len);
  19008                 for (elems, 0..) |*elem, i| {
  19009                     const elem_val = try val.elemValue(sema.mod, i);
  19010                     elem.* = try (try eval(elem_val, scalar_ty, sema.arena, sema.mod)).intern(scalar_ty, mod);
  19011                 }
  19012                 return sema.addConstant(result_ty, (try mod.intern(.{ .aggregate = .{
  19013                     .ty = result_ty.toIntern(),
  19014                     .storage = .{ .elems = elems },
  19015                 } })).toValue());
  19016             }
  19017 
  19018             try sema.requireRuntimeBlock(block, operand_src, null);
  19019             return block.addUnOp(air_tag, operand);
  19020         },
  19021         .ComptimeFloat, .Float => {
  19022             if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
  19023                 if (operand_val.isUndef(mod))
  19024                     return sema.addConstUndef(operand_ty);
  19025                 const result_val = try eval(operand_val, operand_ty, sema.arena, sema.mod);
  19026                 return sema.addConstant(operand_ty, result_val);
  19027             }
  19028 
  19029             try sema.requireRuntimeBlock(block, operand_src, null);
  19030             return block.addUnOp(air_tag, operand);
  19031         },
  19032         else => unreachable,
  19033     }
  19034 }
  19035 
  19036 fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  19037     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  19038     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  19039     const src = inst_data.src();
  19040     const operand = try sema.resolveInst(inst_data.operand);
  19041     const operand_ty = sema.typeOf(operand);
  19042     const mod = sema.mod;
  19043 
  19044     try sema.resolveTypeLayout(operand_ty);
  19045     const enum_ty = switch (operand_ty.zigTypeTag(mod)) {
  19046         .EnumLiteral => {
  19047             const val = try sema.resolveConstValue(block, .unneeded, operand, "");
  19048             const tag_name = mod.intern_pool.indexToKey(val.toIntern()).enum_literal;
  19049             const bytes = mod.intern_pool.stringToSlice(tag_name);
  19050             return sema.addStrLit(block, bytes);
  19051         },
  19052         .Enum => operand_ty,
  19053         .Union => operand_ty.unionTagType(mod) orelse {
  19054             const msg = msg: {
  19055                 const msg = try sema.errMsg(block, src, "union '{}' is untagged", .{
  19056                     operand_ty.fmt(sema.mod),
  19057                 });
  19058                 errdefer msg.destroy(sema.gpa);
  19059                 try sema.addDeclaredHereNote(msg, operand_ty);
  19060                 break :msg msg;
  19061             };
  19062             return sema.failWithOwnedErrorMsg(msg);
  19063         },
  19064         else => return sema.fail(block, operand_src, "expected enum or union; found '{}'", .{
  19065             operand_ty.fmt(mod),
  19066         }),
  19067     };
  19068     if (enum_ty.enumFieldCount(mod) == 0) {
  19069         // TODO I don't think this is the correct way to handle this but
  19070         // it prevents a crash.
  19071         return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{}'", .{
  19072             enum_ty.fmt(mod),
  19073         });
  19074     }
  19075     const enum_decl_index = enum_ty.getOwnerDecl(mod);
  19076     const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src);
  19077     if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| {
  19078         const field_index = enum_ty.enumTagFieldIndex(val, mod) orelse {
  19079             const enum_decl = mod.declPtr(enum_decl_index);
  19080             const msg = msg: {
  19081                 const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{s}'", .{
  19082                     val.fmtValue(enum_ty, sema.mod), enum_decl.name,
  19083                 });
  19084                 errdefer msg.destroy(sema.gpa);
  19085                 try mod.errNoteNonLazy(enum_decl.srcLoc(mod), msg, "declared here", .{});
  19086                 break :msg msg;
  19087             };
  19088             return sema.failWithOwnedErrorMsg(msg);
  19089         };
  19090         const field_name = enum_ty.enumFieldName(field_index, mod);
  19091         return sema.addStrLit(block, field_name);
  19092     }
  19093     try sema.requireRuntimeBlock(block, src, operand_src);
  19094     if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) {
  19095         const ok = try block.addUnOp(.is_named_enum_value, casted_operand);
  19096         try sema.addSafetyCheck(block, ok, .invalid_enum_value);
  19097     }
  19098     // In case the value is runtime-known, we have an AIR instruction for this instead
  19099     // of trying to lower it in Sema because an optimization pass may result in the operand
  19100     // being comptime-known, which would let us elide the `tag_name` AIR instruction.
  19101     return block.addUnOp(.tag_name, casted_operand);
  19102 }
  19103 
  19104 fn zirReify(
  19105     sema: *Sema,
  19106     block: *Block,
  19107     extended: Zir.Inst.Extended.InstData,
  19108     inst: Zir.Inst.Index,
  19109 ) CompileError!Air.Inst.Ref {
  19110     const mod = sema.mod;
  19111     const gpa = sema.gpa;
  19112     const name_strategy = @intToEnum(Zir.Inst.NameStrategy, extended.small);
  19113     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  19114     const src = LazySrcLoc.nodeOffset(extra.node);
  19115     const type_info_ty = try sema.getBuiltinType("Type");
  19116     const uncasted_operand = try sema.resolveInst(extra.operand);
  19117     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  19118     const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src);
  19119     const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime-known");
  19120     const union_val = mod.intern_pool.indexToKey(val.toIntern()).un;
  19121     const target = mod.getTarget();
  19122     if (try union_val.val.toValue().anyUndef(mod)) return sema.failWithUseOfUndef(block, src);
  19123     const tag_index = type_info_ty.unionTagFieldIndex(union_val.tag.toValue(), mod).?;
  19124     const ip = &mod.intern_pool;
  19125     switch (@intToEnum(std.builtin.TypeId, tag_index)) {
  19126         .Type => return Air.Inst.Ref.type_type,
  19127         .Void => return Air.Inst.Ref.void_type,
  19128         .Bool => return Air.Inst.Ref.bool_type,
  19129         .NoReturn => return Air.Inst.Ref.noreturn_type,
  19130         .ComptimeFloat => return Air.Inst.Ref.comptime_float_type,
  19131         .ComptimeInt => return Air.Inst.Ref.comptime_int_type,
  19132         .Undefined => return Air.Inst.Ref.undefined_type,
  19133         .Null => return Air.Inst.Ref.null_type,
  19134         .AnyFrame => return sema.failWithUseOfAsync(block, src),
  19135         .EnumLiteral => return Air.Inst.Ref.enum_literal_type,
  19136         .Int => {
  19137             const fields = ip.typeOf(union_val.val).toType().structFields(mod);
  19138             const signedness_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("signedness").?);
  19139             const bits_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("bits").?);
  19140 
  19141             const signedness = mod.toEnum(std.builtin.Signedness, signedness_val);
  19142             const bits = @intCast(u16, bits_val.toUnsignedInt(mod));
  19143             const ty = try mod.intType(signedness, bits);
  19144             return sema.addType(ty);
  19145         },
  19146         .Vector => {
  19147             const fields = ip.typeOf(union_val.val).toType().structFields(mod);
  19148             const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("len").?);
  19149             const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("child").?);
  19150 
  19151             const len = @intCast(u32, len_val.toUnsignedInt(mod));
  19152             const child_ty = child_val.toType();
  19153 
  19154             try sema.checkVectorElemType(block, src, child_ty);
  19155 
  19156             const ty = try mod.vectorType(.{
  19157                 .len = len,
  19158                 .child = child_ty.toIntern(),
  19159             });
  19160             return sema.addType(ty);
  19161         },
  19162         .Float => {
  19163             const fields = ip.typeOf(union_val.val).toType().structFields(mod);
  19164             const bits_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("bits").?);
  19165 
  19166             const bits = @intCast(u16, bits_val.toUnsignedInt(mod));
  19167             const ty = switch (bits) {
  19168                 16 => Type.f16,
  19169                 32 => Type.f32,
  19170                 64 => Type.f64,
  19171                 80 => Type.f80,
  19172                 128 => Type.f128,
  19173                 else => return sema.fail(block, src, "{}-bit float unsupported", .{bits}),
  19174             };
  19175             return sema.addType(ty);
  19176         },
  19177         .Pointer => {
  19178             const fields = ip.typeOf(union_val.val).toType().structFields(mod);
  19179             const size_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("size").?);
  19180             const is_const_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_const").?);
  19181             const is_volatile_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_volatile").?);
  19182             const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("alignment").?);
  19183             const address_space_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("address_space").?);
  19184             const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("child").?);
  19185             const is_allowzero_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_allowzero").?);
  19186             const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("sentinel").?);
  19187 
  19188             if (!try sema.intFitsInType(alignment_val, Type.u32, null)) {
  19189                 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
  19190             }
  19191 
  19192             const abi_align = InternPool.Alignment.fromByteUnits(
  19193                 (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?,
  19194             );
  19195 
  19196             const unresolved_elem_ty = child_val.toType();
  19197             const elem_ty = if (abi_align == .none)
  19198                 unresolved_elem_ty
  19199             else t: {
  19200                 const elem_ty = try sema.resolveTypeFields(unresolved_elem_ty);
  19201                 try sema.resolveTypeLayout(elem_ty);
  19202                 break :t elem_ty;
  19203             };
  19204 
  19205             const ptr_size = mod.toEnum(std.builtin.Type.Pointer.Size, size_val);
  19206 
  19207             const actual_sentinel: InternPool.Index = s: {
  19208                 if (!sentinel_val.isNull(mod)) {
  19209                     if (ptr_size == .One or ptr_size == .C) {
  19210                         return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{});
  19211                     }
  19212                     const sentinel_ptr_val = sentinel_val.optionalValue(mod).?;
  19213                     const ptr_ty = try Type.ptr(sema.arena, mod, .{
  19214                         .@"addrspace" = .generic,
  19215                         .pointee_type = elem_ty,
  19216                     });
  19217                     const sent_val = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?;
  19218                     break :s sent_val.toIntern();
  19219                 }
  19220                 break :s .none;
  19221             };
  19222 
  19223             if (elem_ty.zigTypeTag(mod) == .NoReturn) {
  19224                 return sema.fail(block, src, "pointer to noreturn not allowed", .{});
  19225             } else if (elem_ty.zigTypeTag(mod) == .Fn) {
  19226                 if (ptr_size != .One) {
  19227                     return sema.fail(block, src, "function pointers must be single pointers", .{});
  19228                 }
  19229                 const fn_align = mod.typeToFunc(elem_ty).?.alignment;
  19230                 if (abi_align != .none and fn_align != .none and
  19231                     abi_align != fn_align)
  19232                 {
  19233                     return sema.fail(block, src, "function pointer alignment disagrees with function alignment", .{});
  19234                 }
  19235             } else if (ptr_size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) {
  19236                 return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{});
  19237             } else if (ptr_size == .C) {
  19238                 if (!try sema.validateExternType(elem_ty, .other)) {
  19239                     const msg = msg: {
  19240                         const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(mod)});
  19241                         errdefer msg.destroy(gpa);
  19242 
  19243                         const src_decl = mod.declPtr(block.src_decl);
  19244                         try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), elem_ty, .other);
  19245 
  19246                         try sema.addDeclaredHereNote(msg, elem_ty);
  19247                         break :msg msg;
  19248                     };
  19249                     return sema.failWithOwnedErrorMsg(msg);
  19250                 }
  19251                 if (elem_ty.zigTypeTag(mod) == .Opaque) {
  19252                     return sema.fail(block, src, "C pointers cannot point to opaque types", .{});
  19253                 }
  19254             }
  19255 
  19256             const ty = try mod.ptrType(.{
  19257                 .child = elem_ty.toIntern(),
  19258                 .sentinel = actual_sentinel,
  19259                 .flags = .{
  19260                     .size = ptr_size,
  19261                     .is_const = is_const_val.toBool(),
  19262                     .is_volatile = is_volatile_val.toBool(),
  19263                     .alignment = abi_align,
  19264                     .address_space = mod.toEnum(std.builtin.AddressSpace, address_space_val),
  19265                     .is_allowzero = is_allowzero_val.toBool(),
  19266                 },
  19267             });
  19268             return sema.addType(ty);
  19269         },
  19270         .Array => {
  19271             const fields = ip.typeOf(union_val.val).toType().structFields(mod);
  19272             const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("len").?);
  19273             const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("child").?);
  19274             const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("sentinel").?);
  19275 
  19276             const len = len_val.toUnsignedInt(mod);
  19277             const child_ty = child_val.toType();
  19278             const sentinel = if (sentinel_val.optionalValue(mod)) |p| blk: {
  19279                 const ptr_ty = try Type.ptr(sema.arena, mod, .{
  19280                     .@"addrspace" = .generic,
  19281                     .pointee_type = child_ty,
  19282                 });
  19283                 break :blk (try sema.pointerDeref(block, src, p, ptr_ty)).?;
  19284             } else null;
  19285 
  19286             const ty = try Type.array(sema.arena, len, sentinel, child_ty, mod);
  19287             return sema.addType(ty);
  19288         },
  19289         .Optional => {
  19290             const fields = ip.typeOf(union_val.val).toType().structFields(mod);
  19291             const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("child").?);
  19292 
  19293             const child_ty = child_val.toType();
  19294 
  19295             const ty = try Type.optional(sema.arena, child_ty, mod);
  19296             return sema.addType(ty);
  19297         },
  19298         .ErrorUnion => {
  19299             const fields = ip.typeOf(union_val.val).toType().structFields(mod);
  19300             const error_set_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("error_set").?);
  19301             const payload_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("payload").?);
  19302 
  19303             const error_set_ty = error_set_val.toType();
  19304             const payload_ty = payload_val.toType();
  19305 
  19306             if (error_set_ty.zigTypeTag(mod) != .ErrorSet) {
  19307                 return sema.fail(block, src, "Type.ErrorUnion.error_set must be an error set type", .{});
  19308             }
  19309 
  19310             const ty = try mod.errorUnionType(error_set_ty, payload_ty);
  19311             return sema.addType(ty);
  19312         },
  19313         .ErrorSet => {
  19314             const payload_val = union_val.val.toValue().optionalValue(mod) orelse
  19315                 return sema.addType(Type.anyerror);
  19316 
  19317             const len = try sema.usizeCast(block, src, payload_val.sliceLen(mod));
  19318             var names: Module.Fn.InferredErrorSet.NameMap = .{};
  19319             try names.ensureUnusedCapacity(sema.arena, len);
  19320             for (0..len) |i| {
  19321                 const elem_val = try payload_val.elemValue(mod, i);
  19322                 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
  19323                 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?);
  19324 
  19325                 const name_str = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod);
  19326                 const kv = try mod.getErrorValue(name_str);
  19327                 const name_ip = try mod.intern_pool.getOrPutString(gpa, kv.key);
  19328                 const gop = names.getOrPutAssumeCapacity(name_ip);
  19329                 if (gop.found_existing) {
  19330                     return sema.fail(block, src, "duplicate error '{s}'", .{name_str});
  19331                 }
  19332             }
  19333 
  19334             const ty = try mod.errorSetFromUnsortedNames(names.keys());
  19335             return sema.addType(ty);
  19336         },
  19337         .Struct => {
  19338             const fields = ip.typeOf(union_val.val).toType().structFields(mod);
  19339             const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("layout").?);
  19340             const backing_integer_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("backing_integer").?);
  19341             const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("fields").?);
  19342             const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("decls").?);
  19343             const is_tuple_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_tuple").?);
  19344 
  19345             const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);
  19346 
  19347             // Decls
  19348             if (decls_val.sliceLen(mod) > 0) {
  19349                 return sema.fail(block, src, "reified structs must have no decls", .{});
  19350             }
  19351 
  19352             if (layout != .Packed and !backing_integer_val.isNull(mod)) {
  19353                 return sema.fail(block, src, "non-packed struct does not support backing integer type", .{});
  19354             }
  19355 
  19356             return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool());
  19357         },
  19358         .Enum => {
  19359             const fields = ip.typeOf(union_val.val).toType().structFields(mod);
  19360             const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("tag_type").?);
  19361             const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("fields").?);
  19362             const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("decls").?);
  19363             const is_exhaustive_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_exhaustive").?);
  19364 
  19365             // Decls
  19366             if (decls_val.sliceLen(mod) > 0) {
  19367                 return sema.fail(block, src, "reified enums must have no decls", .{});
  19368             }
  19369 
  19370             const int_tag_ty = tag_type_val.toType();
  19371             if (int_tag_ty.zigTypeTag(mod) != .Int) {
  19372                 return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{});
  19373             }
  19374 
  19375             // Because these things each reference each other, `undefined`
  19376             // placeholders are used before being set after the enum type gains
  19377             // an InternPool index.
  19378 
  19379             const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
  19380                 .ty = Type.type,
  19381                 .val = undefined,
  19382             }, name_strategy, "enum", inst);
  19383             const new_decl = mod.declPtr(new_decl_index);
  19384             new_decl.owns_tv = true;
  19385             errdefer mod.abortAnonDecl(new_decl_index);
  19386 
  19387             // Define our empty enum decl
  19388             const fields_len = @intCast(u32, try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
  19389             const incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{
  19390                 .decl = new_decl_index,
  19391                 .namespace = .none,
  19392                 .fields_len = fields_len,
  19393                 .has_values = true,
  19394                 .tag_mode = if (!is_exhaustive_val.toBool())
  19395                     .nonexhaustive
  19396                 else
  19397                     .explicit,
  19398                 .tag_ty = int_tag_ty.toIntern(),
  19399             });
  19400             errdefer mod.intern_pool.remove(incomplete_enum.index);
  19401 
  19402             new_decl.val = incomplete_enum.index.toValue();
  19403 
  19404             for (0..fields_len) |field_i| {
  19405                 const elem_val = try fields_val.elemValue(mod, field_i);
  19406                 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
  19407                 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?);
  19408                 const value_val = try elem_val.fieldValue(mod, elem_fields.getIndex("value").?);
  19409 
  19410                 const field_name = try name_val.toAllocatedBytes(
  19411                     Type.slice_const_u8,
  19412                     sema.arena,
  19413                     mod,
  19414                 );
  19415                 const field_name_ip = try mod.intern_pool.getOrPutString(gpa, field_name);
  19416 
  19417                 if (!try sema.intFitsInType(value_val, int_tag_ty, null)) {
  19418                     // TODO: better source location
  19419                     return sema.fail(block, src, "field '{s}' with enumeration value '{}' is too large for backing int type '{}'", .{
  19420                         field_name,
  19421                         value_val.fmtValue(Type.comptime_int, mod),
  19422                         int_tag_ty.fmt(mod),
  19423                     });
  19424                 }
  19425 
  19426                 if (try incomplete_enum.addFieldName(&mod.intern_pool, gpa, field_name_ip)) |other_index| {
  19427                     const msg = msg: {
  19428                         const msg = try sema.errMsg(block, src, "duplicate enum field '{s}'", .{field_name});
  19429                         errdefer msg.destroy(gpa);
  19430                         _ = other_index; // TODO: this note is incorrect
  19431                         try sema.errNote(block, src, msg, "other field here", .{});
  19432                         break :msg msg;
  19433                     };
  19434                     return sema.failWithOwnedErrorMsg(msg);
  19435                 }
  19436 
  19437                 if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, (try mod.getCoerced(value_val, int_tag_ty)).toIntern())) |other| {
  19438                     const msg = msg: {
  19439                         const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)});
  19440                         errdefer msg.destroy(gpa);
  19441                         _ = other; // TODO: this note is incorrect
  19442                         try sema.errNote(block, src, msg, "other enum tag value here", .{});
  19443                         break :msg msg;
  19444                     };
  19445                     return sema.failWithOwnedErrorMsg(msg);
  19446                 }
  19447             }
  19448 
  19449             const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
  19450             try mod.finalizeAnonDecl(new_decl_index);
  19451             return decl_val;
  19452         },
  19453         .Opaque => {
  19454             const fields = ip.typeOf(union_val.val).toType().structFields(mod);
  19455             const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("decls").?);
  19456 
  19457             // Decls
  19458             if (decls_val.sliceLen(mod) > 0) {
  19459                 return sema.fail(block, src, "reified opaque must have no decls", .{});
  19460             }
  19461 
  19462             var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
  19463             errdefer new_decl_arena.deinit();
  19464 
  19465             // Because these three things each reference each other,
  19466             // `undefined` placeholders are used in two places before being set
  19467             // after the opaque type gains an InternPool index.
  19468 
  19469             const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
  19470                 .ty = Type.type,
  19471                 .val = undefined,
  19472             }, name_strategy, "opaque", inst);
  19473             const new_decl = mod.declPtr(new_decl_index);
  19474             new_decl.owns_tv = true;
  19475             errdefer mod.abortAnonDecl(new_decl_index);
  19476 
  19477             const new_namespace_index = try mod.createNamespace(.{
  19478                 .parent = block.namespace.toOptional(),
  19479                 .ty = undefined,
  19480                 .file_scope = block.getFileScope(mod),
  19481             });
  19482             const new_namespace = mod.namespacePtr(new_namespace_index);
  19483             errdefer mod.destroyNamespace(new_namespace_index);
  19484 
  19485             const opaque_ty = try mod.intern(.{ .opaque_type = .{
  19486                 .decl = new_decl_index,
  19487                 .namespace = new_namespace_index,
  19488             } });
  19489             errdefer mod.intern_pool.remove(opaque_ty);
  19490 
  19491             new_decl.val = opaque_ty.toValue();
  19492             new_namespace.ty = opaque_ty.toType();
  19493 
  19494             try new_decl.finalizeNewArena(&new_decl_arena);
  19495             const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
  19496             try mod.finalizeAnonDecl(new_decl_index);
  19497             return decl_val;
  19498         },
  19499         .Union => {
  19500             const fields = ip.typeOf(union_val.val).toType().structFields(mod);
  19501             const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("layout").?);
  19502             const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("tag_type").?);
  19503             const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("fields").?);
  19504             const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("decls").?);
  19505 
  19506             // Decls
  19507             if (decls_val.sliceLen(mod) > 0) {
  19508                 return sema.fail(block, src, "reified unions must have no decls", .{});
  19509             }
  19510             const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);
  19511 
  19512             var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
  19513             errdefer new_decl_arena.deinit();
  19514             const new_decl_arena_allocator = new_decl_arena.allocator();
  19515 
  19516             // Because these three things each reference each other, `undefined`
  19517             // placeholders are used before being set after the union type gains an
  19518             // InternPool index.
  19519 
  19520             const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
  19521                 .ty = Type.type,
  19522                 .val = undefined,
  19523             }, name_strategy, "union", inst);
  19524             const new_decl = mod.declPtr(new_decl_index);
  19525             new_decl.owns_tv = true;
  19526             errdefer mod.abortAnonDecl(new_decl_index);
  19527 
  19528             const new_namespace_index = try mod.createNamespace(.{
  19529                 .parent = block.namespace.toOptional(),
  19530                 .ty = undefined,
  19531                 .file_scope = block.getFileScope(mod),
  19532             });
  19533             const new_namespace = mod.namespacePtr(new_namespace_index);
  19534             errdefer mod.destroyNamespace(new_namespace_index);
  19535 
  19536             const union_index = try mod.createUnion(.{
  19537                 .owner_decl = new_decl_index,
  19538                 .tag_ty = Type.null,
  19539                 .fields = .{},
  19540                 .zir_index = inst,
  19541                 .layout = layout,
  19542                 .status = .have_field_types,
  19543                 .namespace = new_namespace_index,
  19544             });
  19545             const union_obj = mod.unionPtr(union_index);
  19546             errdefer mod.destroyUnion(union_index);
  19547 
  19548             const union_ty = try mod.intern_pool.get(gpa, .{ .union_type = .{
  19549                 .index = union_index,
  19550                 .runtime_tag = if (!tag_type_val.isNull(mod))
  19551                     .tagged
  19552                 else if (layout != .Auto)
  19553                     .none
  19554                 else switch (mod.optimizeMode()) {
  19555                     .Debug, .ReleaseSafe => .safety,
  19556                     .ReleaseFast, .ReleaseSmall => .none,
  19557                 },
  19558             } });
  19559             errdefer mod.intern_pool.remove(union_ty);
  19560 
  19561             new_decl.val = union_ty.toValue();
  19562             new_namespace.ty = union_ty.toType();
  19563 
  19564             // Tag type
  19565             const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
  19566             var explicit_tags_seen: []bool = &.{};
  19567             var explicit_enum_info: ?InternPool.Key.EnumType = null;
  19568             var enum_field_names: []InternPool.NullTerminatedString = &.{};
  19569             if (tag_type_val.optionalValue(mod)) |payload_val| {
  19570                 union_obj.tag_ty = payload_val.toType();
  19571 
  19572                 const enum_type = switch (mod.intern_pool.indexToKey(union_obj.tag_ty.toIntern())) {
  19573                     .enum_type => |x| x,
  19574                     else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),
  19575                 };
  19576 
  19577                 explicit_enum_info = enum_type;
  19578                 explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
  19579                 @memset(explicit_tags_seen, false);
  19580             } else {
  19581                 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
  19582             }
  19583 
  19584             // Fields
  19585             try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
  19586 
  19587             for (0..fields_len) |i| {
  19588                 const elem_val = try fields_val.elemValue(mod, i);
  19589                 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
  19590                 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?);
  19591                 const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex("type").?);
  19592                 const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex("alignment").?);
  19593 
  19594                 const field_name = try name_val.toAllocatedBytes(
  19595                     Type.slice_const_u8,
  19596                     new_decl_arena_allocator,
  19597                     mod,
  19598                 );
  19599 
  19600                 const field_name_ip = try mod.intern_pool.getOrPutString(gpa, field_name);
  19601 
  19602                 if (enum_field_names.len != 0) {
  19603                     enum_field_names[i] = field_name_ip;
  19604                 }
  19605 
  19606                 if (explicit_enum_info) |tag_info| {
  19607                     const enum_index = tag_info.nameIndex(&mod.intern_pool, field_name_ip) orelse {
  19608                         const msg = msg: {
  19609                             const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(mod) });
  19610                             errdefer msg.destroy(gpa);
  19611                             try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
  19612                             break :msg msg;
  19613                         };
  19614                         return sema.failWithOwnedErrorMsg(msg);
  19615                     };
  19616                     // No check for duplicate because the check already happened in order
  19617                     // to create the enum type in the first place.
  19618                     assert(!explicit_tags_seen[enum_index]);
  19619                     explicit_tags_seen[enum_index] = true;
  19620                 }
  19621 
  19622                 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
  19623                 if (gop.found_existing) {
  19624                     // TODO: better source location
  19625                     return sema.fail(block, src, "duplicate union field {s}", .{field_name});
  19626                 }
  19627 
  19628                 const field_ty = type_val.toType();
  19629                 gop.value_ptr.* = .{
  19630                     .ty = field_ty,
  19631                     .abi_align = @intCast(u32, (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?),
  19632                 };
  19633 
  19634                 if (field_ty.zigTypeTag(mod) == .Opaque) {
  19635                     const msg = msg: {
  19636                         const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
  19637                         errdefer msg.destroy(gpa);
  19638 
  19639                         try sema.addDeclaredHereNote(msg, field_ty);
  19640                         break :msg msg;
  19641                     };
  19642                     return sema.failWithOwnedErrorMsg(msg);
  19643                 }
  19644                 if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {
  19645                     const msg = msg: {
  19646                         const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
  19647                         errdefer msg.destroy(gpa);
  19648 
  19649                         const src_decl = mod.declPtr(block.src_decl);
  19650                         try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .union_field);
  19651 
  19652                         try sema.addDeclaredHereNote(msg, field_ty);
  19653                         break :msg msg;
  19654                     };
  19655                     return sema.failWithOwnedErrorMsg(msg);
  19656                 } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) {
  19657                     const msg = msg: {
  19658                         const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
  19659                         errdefer msg.destroy(gpa);
  19660 
  19661                         const src_decl = mod.declPtr(block.src_decl);
  19662                         try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty);
  19663 
  19664                         try sema.addDeclaredHereNote(msg, field_ty);
  19665                         break :msg msg;
  19666                     };
  19667                     return sema.failWithOwnedErrorMsg(msg);
  19668                 }
  19669             }
  19670 
  19671             if (explicit_enum_info) |tag_info| {
  19672                 if (tag_info.names.len > fields_len) {
  19673                     const msg = msg: {
  19674                         const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{});
  19675                         errdefer msg.destroy(gpa);
  19676 
  19677                         const enum_ty = union_obj.tag_ty;
  19678                         for (tag_info.names, 0..) |field_name, field_index| {
  19679                             if (explicit_tags_seen[field_index]) continue;
  19680                             try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{
  19681                                 mod.intern_pool.stringToSlice(field_name),
  19682                             });
  19683                         }
  19684                         try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
  19685                         break :msg msg;
  19686                     };
  19687                     return sema.failWithOwnedErrorMsg(msg);
  19688                 }
  19689             } else {
  19690                 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, enum_field_names, null);
  19691             }
  19692 
  19693             try new_decl.finalizeNewArena(&new_decl_arena);
  19694             const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
  19695             try mod.finalizeAnonDecl(new_decl_index);
  19696             return decl_val;
  19697         },
  19698         .Fn => {
  19699             const fields = ip.typeOf(union_val.val).toType().structFields(mod);
  19700             const calling_convention_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("calling_convention").?);
  19701             const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("alignment").?);
  19702             const is_generic_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_generic").?);
  19703             const is_var_args_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_var_args").?);
  19704             const return_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("return_type").?);
  19705             const params_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("params").?);
  19706 
  19707             const is_generic = is_generic_val.toBool();
  19708             if (is_generic) {
  19709                 return sema.fail(block, src, "Type.Fn.is_generic must be false for @Type", .{});
  19710             }
  19711 
  19712             const is_var_args = is_var_args_val.toBool();
  19713             const cc = mod.toEnum(std.builtin.CallingConvention, calling_convention_val);
  19714             if (is_var_args and cc != .C) {
  19715                 return sema.fail(block, src, "varargs functions must have C calling convention", .{});
  19716             }
  19717 
  19718             const alignment = alignment: {
  19719                 if (!try sema.intFitsInType(alignment_val, Type.u32, null)) {
  19720                     return sema.fail(block, src, "alignment must fit in 'u32'", .{});
  19721                 }
  19722                 const alignment = @intCast(u29, alignment_val.toUnsignedInt(mod));
  19723                 if (alignment == target_util.defaultFunctionAlignment(target)) {
  19724                     break :alignment .none;
  19725                 } else {
  19726                     break :alignment InternPool.Alignment.fromByteUnits(alignment);
  19727                 }
  19728             };
  19729             const return_type = return_type_val.optionalValue(mod) orelse
  19730                 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
  19731 
  19732             const args_len = try sema.usizeCast(block, src, params_val.sliceLen(mod));
  19733             const param_types = try sema.arena.alloc(InternPool.Index, args_len);
  19734 
  19735             var noalias_bits: u32 = 0;
  19736             for (param_types, 0..) |*param_type, i| {
  19737                 const elem_val = try params_val.elemValue(mod, i);
  19738                 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
  19739                 const param_is_generic_val = try elem_val.fieldValue(mod, elem_fields.getIndex("is_generic").?);
  19740                 const param_is_noalias_val = try elem_val.fieldValue(mod, elem_fields.getIndex("is_noalias").?);
  19741                 const opt_param_type_val = try elem_val.fieldValue(mod, elem_fields.getIndex("type").?);
  19742 
  19743                 if (param_is_generic_val.toBool()) {
  19744                     return sema.fail(block, src, "Type.Fn.Param.is_generic must be false for @Type", .{});
  19745                 }
  19746 
  19747                 const param_type_val = opt_param_type_val.optionalValue(mod) orelse
  19748                     return sema.fail(block, src, "Type.Fn.Param.arg_type must be non-null for @Type", .{});
  19749                 param_type.* = param_type_val.toIntern();
  19750 
  19751                 if (param_is_noalias_val.toBool()) {
  19752                     if (!param_type.toType().isPtrAtRuntime(mod)) {
  19753                         return sema.fail(block, src, "non-pointer parameter declared noalias", .{});
  19754                     }
  19755                     noalias_bits |= @as(u32, 1) << (std.math.cast(u5, i) orelse
  19756                         return sema.fail(block, src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{}));
  19757                 }
  19758             }
  19759 
  19760             const ty = try mod.funcType(.{
  19761                 .param_types = param_types,
  19762                 .comptime_bits = 0,
  19763                 .noalias_bits = noalias_bits,
  19764                 .return_type = return_type.toIntern(),
  19765                 .alignment = alignment,
  19766                 .cc = cc,
  19767                 .is_var_args = is_var_args,
  19768                 .is_generic = false,
  19769                 .is_noinline = false,
  19770                 .align_is_generic = false,
  19771                 .cc_is_generic = false,
  19772                 .section_is_generic = false,
  19773                 .addrspace_is_generic = false,
  19774             });
  19775             return sema.addType(ty);
  19776         },
  19777         .Frame => return sema.failWithUseOfAsync(block, src),
  19778     }
  19779 }
  19780 
  19781 fn reifyStruct(
  19782     sema: *Sema,
  19783     block: *Block,
  19784     inst: Zir.Inst.Index,
  19785     src: LazySrcLoc,
  19786     layout: std.builtin.Type.ContainerLayout,
  19787     backing_int_val: Value,
  19788     fields_val: Value,
  19789     name_strategy: Zir.Inst.NameStrategy,
  19790     is_tuple: bool,
  19791 ) CompileError!Air.Inst.Ref {
  19792     const mod = sema.mod;
  19793     const gpa = sema.gpa;
  19794 
  19795     var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
  19796     errdefer new_decl_arena.deinit();
  19797     const new_decl_arena_allocator = new_decl_arena.allocator();
  19798 
  19799     // Because these three things each reference each other, `undefined`
  19800     // placeholders are used before being set after the struct type gains an
  19801     // InternPool index.
  19802 
  19803     const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
  19804         .ty = Type.type,
  19805         .val = undefined,
  19806     }, name_strategy, "struct", inst);
  19807     const new_decl = mod.declPtr(new_decl_index);
  19808     new_decl.owns_tv = true;
  19809     errdefer mod.abortAnonDecl(new_decl_index);
  19810 
  19811     const new_namespace_index = try mod.createNamespace(.{
  19812         .parent = block.namespace.toOptional(),
  19813         .ty = undefined,
  19814         .file_scope = block.getFileScope(mod),
  19815     });
  19816     const new_namespace = mod.namespacePtr(new_namespace_index);
  19817     errdefer mod.destroyNamespace(new_namespace_index);
  19818 
  19819     const struct_index = try mod.createStruct(.{
  19820         .owner_decl = new_decl_index,
  19821         .fields = .{},
  19822         .zir_index = inst,
  19823         .layout = layout,
  19824         .status = .have_field_types,
  19825         .known_non_opv = false,
  19826         .is_tuple = is_tuple,
  19827         .namespace = new_namespace_index,
  19828     });
  19829     const struct_obj = mod.structPtr(struct_index);
  19830     errdefer mod.destroyStruct(struct_index);
  19831 
  19832     const struct_ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{
  19833         .index = struct_index.toOptional(),
  19834         .namespace = new_namespace_index.toOptional(),
  19835     } });
  19836     errdefer mod.intern_pool.remove(struct_ty);
  19837 
  19838     new_decl.val = struct_ty.toValue();
  19839     new_namespace.ty = struct_ty.toType();
  19840 
  19841     // Fields
  19842     const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
  19843     try struct_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
  19844     var i: usize = 0;
  19845     while (i < fields_len) : (i += 1) {
  19846         const elem_val = try fields_val.elemValue(mod, i);
  19847         const elem_fields = mod.intern_pool.typeOf(elem_val.toIntern()).toType().structFields(mod);
  19848         const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?);
  19849         const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex("type").?);
  19850         const default_value_val = try elem_val.fieldValue(mod, elem_fields.getIndex("default_value").?);
  19851         const is_comptime_val = try elem_val.fieldValue(mod, elem_fields.getIndex("is_comptime").?);
  19852         const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex("alignment").?);
  19853 
  19854         if (!try sema.intFitsInType(alignment_val, Type.u32, null)) {
  19855             return sema.fail(block, src, "alignment must fit in 'u32'", .{});
  19856         }
  19857         const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?);
  19858 
  19859         if (layout == .Packed) {
  19860             if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
  19861             if (is_comptime_val.toBool()) return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{});
  19862         }
  19863         if (layout == .Extern and is_comptime_val.toBool()) {
  19864             return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{});
  19865         }
  19866 
  19867         const field_name = try name_val.toAllocatedBytes(
  19868             Type.slice_const_u8,
  19869             new_decl_arena_allocator,
  19870             mod,
  19871         );
  19872 
  19873         if (is_tuple) {
  19874             const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch {
  19875                 return sema.fail(
  19876                     block,
  19877                     src,
  19878                     "tuple cannot have non-numeric field '{s}'",
  19879                     .{field_name},
  19880                 );
  19881             };
  19882 
  19883             if (field_index >= fields_len) {
  19884                 return sema.fail(
  19885                     block,
  19886                     src,
  19887                     "tuple field {} exceeds tuple field count",
  19888                     .{field_index},
  19889                 );
  19890             }
  19891         }
  19892         const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
  19893         if (gop.found_existing) {
  19894             // TODO: better source location
  19895             return sema.fail(block, src, "duplicate struct field {s}", .{field_name});
  19896         }
  19897 
  19898         const field_ty = type_val.toType();
  19899         const default_val = if (default_value_val.optionalValue(mod)) |opt_val|
  19900             try sema.pointerDeref(block, src, opt_val, try mod.singleConstPtrType(field_ty)) orelse
  19901                 return sema.failWithNeededComptime(block, src, "struct field default value must be comptime-known")
  19902         else
  19903             Value.@"unreachable";
  19904         if (is_comptime_val.toBool() and default_val.toIntern() == .unreachable_value) {
  19905             return sema.fail(block, src, "comptime field without default initialization value", .{});
  19906         }
  19907 
  19908         gop.value_ptr.* = .{
  19909             .ty = field_ty,
  19910             .abi_align = abi_align,
  19911             .default_val = default_val,
  19912             .is_comptime = is_comptime_val.toBool(),
  19913             .offset = undefined,
  19914         };
  19915 
  19916         if (field_ty.zigTypeTag(mod) == .Opaque) {
  19917             const msg = msg: {
  19918                 const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
  19919                 errdefer msg.destroy(gpa);
  19920 
  19921                 try sema.addDeclaredHereNote(msg, field_ty);
  19922                 break :msg msg;
  19923             };
  19924             return sema.failWithOwnedErrorMsg(msg);
  19925         }
  19926         if (field_ty.zigTypeTag(mod) == .NoReturn) {
  19927             const msg = msg: {
  19928                 const msg = try sema.errMsg(block, src, "struct fields cannot be 'noreturn'", .{});
  19929                 errdefer msg.destroy(gpa);
  19930 
  19931                 try sema.addDeclaredHereNote(msg, field_ty);
  19932                 break :msg msg;
  19933             };
  19934             return sema.failWithOwnedErrorMsg(msg);
  19935         }
  19936         if (struct_obj.layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) {
  19937             const msg = msg: {
  19938                 const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
  19939                 errdefer msg.destroy(gpa);
  19940 
  19941                 const src_decl = sema.mod.declPtr(block.src_decl);
  19942                 try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .struct_field);
  19943 
  19944                 try sema.addDeclaredHereNote(msg, field_ty);
  19945                 break :msg msg;
  19946             };
  19947             return sema.failWithOwnedErrorMsg(msg);
  19948         } else if (struct_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) {
  19949             const msg = msg: {
  19950                 const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
  19951                 errdefer msg.destroy(gpa);
  19952 
  19953                 const src_decl = sema.mod.declPtr(block.src_decl);
  19954                 try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty);
  19955 
  19956                 try sema.addDeclaredHereNote(msg, field_ty);
  19957                 break :msg msg;
  19958             };
  19959             return sema.failWithOwnedErrorMsg(msg);
  19960         }
  19961     }
  19962 
  19963     if (layout == .Packed) {
  19964         struct_obj.status = .layout_wip;
  19965 
  19966         for (struct_obj.fields.values(), 0..) |field, index| {
  19967             sema.resolveTypeLayout(field.ty) catch |err| switch (err) {
  19968                 error.AnalysisFail => {
  19969                     const msg = sema.err orelse return err;
  19970                     try sema.addFieldErrNote(struct_ty.toType(), index, msg, "while checking this field", .{});
  19971                     return err;
  19972                 },
  19973                 else => return err,
  19974             };
  19975         }
  19976 
  19977         var fields_bit_sum: u64 = 0;
  19978         for (struct_obj.fields.values()) |field| {
  19979             fields_bit_sum += field.ty.bitSize(mod);
  19980         }
  19981 
  19982         if (backing_int_val.optionalValue(mod)) |payload| {
  19983             const backing_int_ty = payload.toType();
  19984             try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum);
  19985             struct_obj.backing_int_ty = backing_int_ty;
  19986         } else {
  19987             struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(u16, fields_bit_sum));
  19988         }
  19989 
  19990         struct_obj.status = .have_layout;
  19991     }
  19992 
  19993     try new_decl.finalizeNewArena(&new_decl_arena);
  19994     const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
  19995     try mod.finalizeAnonDecl(new_decl_index);
  19996     return decl_val;
  19997 }
  19998 
  19999 fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
  20000     const mod = sema.mod;
  20001     const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
  20002     const src = LazySrcLoc.nodeOffset(extra.node);
  20003     const addrspace_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  20004     const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  20005 
  20006     const dest_addrspace = try sema.analyzeAddressSpace(block, addrspace_src, extra.lhs, .pointer);
  20007     const ptr = try sema.resolveInst(extra.rhs);
  20008     const ptr_ty = sema.typeOf(ptr);
  20009 
  20010     try sema.checkPtrOperand(block, ptr_src, ptr_ty);
  20011 
  20012     var ptr_info = ptr_ty.ptrInfo(mod);
  20013     const src_addrspace = ptr_info.@"addrspace";
  20014     if (!target_util.addrSpaceCastIsValid(sema.mod.getTarget(), src_addrspace, dest_addrspace)) {
  20015         const msg = msg: {
  20016             const msg = try sema.errMsg(block, src, "invalid address space cast", .{});
  20017             errdefer msg.destroy(sema.gpa);
  20018             try sema.errNote(block, src, msg, "address space '{s}' is not compatible with address space '{s}'", .{ @tagName(src_addrspace), @tagName(dest_addrspace) });
  20019             break :msg msg;
  20020         };
  20021         return sema.failWithOwnedErrorMsg(msg);
  20022     }
  20023 
  20024     ptr_info.@"addrspace" = dest_addrspace;
  20025     const dest_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
  20026     const dest_ty = if (ptr_ty.zigTypeTag(mod) == .Optional)
  20027         try Type.optional(sema.arena, dest_ptr_ty, mod)
  20028     else
  20029         dest_ptr_ty;
  20030 
  20031     try sema.requireRuntimeBlock(block, src, ptr_src);
  20032     // TODO: Address space cast safety?
  20033 
  20034     return block.addInst(.{
  20035         .tag = .addrspace_cast,
  20036         .data = .{ .ty_op = .{
  20037             .ty = try sema.addType(dest_ty),
  20038             .operand = ptr,
  20039         } },
  20040     });
  20041 }
  20042 
  20043 fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
  20044     const va_list_ty = try sema.getBuiltinType("VaList");
  20045     const va_list_ptr = try Type.ptr(sema.arena, sema.mod, .{
  20046         .pointee_type = va_list_ty,
  20047         .mutable = true,
  20048         .@"addrspace" = .generic,
  20049     });
  20050 
  20051     const inst = try sema.resolveInst(zir_ref);
  20052     return sema.coerce(block, va_list_ptr, inst, src);
  20053 }
  20054 
  20055 fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
  20056     const mod = sema.mod;
  20057     const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
  20058     const src = LazySrcLoc.nodeOffset(extra.node);
  20059     const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  20060     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  20061 
  20062     const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.lhs);
  20063     const arg_ty = try sema.resolveType(block, ty_src, extra.rhs);
  20064 
  20065     if (!try sema.validateExternType(arg_ty, .param_ty)) {
  20066         const msg = msg: {
  20067             const msg = try sema.errMsg(block, ty_src, "cannot get '{}' from variadic argument", .{arg_ty.fmt(sema.mod)});
  20068             errdefer msg.destroy(sema.gpa);
  20069 
  20070             const src_decl = sema.mod.declPtr(block.src_decl);
  20071             try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl, mod), arg_ty, .param_ty);
  20072 
  20073             try sema.addDeclaredHereNote(msg, arg_ty);
  20074             break :msg msg;
  20075         };
  20076         return sema.failWithOwnedErrorMsg(msg);
  20077     }
  20078 
  20079     try sema.requireRuntimeBlock(block, src, null);
  20080     return block.addTyOp(.c_va_arg, arg_ty, va_list_ref);
  20081 }
  20082 
  20083 fn zirCVaCopy(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
  20084     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  20085     const src = LazySrcLoc.nodeOffset(extra.node);
  20086     const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  20087 
  20088     const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand);
  20089     const va_list_ty = try sema.getBuiltinType("VaList");
  20090 
  20091     try sema.requireRuntimeBlock(block, src, null);
  20092     return block.addTyOp(.c_va_copy, va_list_ty, va_list_ref);
  20093 }
  20094 
  20095 fn zirCVaEnd(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
  20096     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  20097     const src = LazySrcLoc.nodeOffset(extra.node);
  20098     const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  20099 
  20100     const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand);
  20101 
  20102     try sema.requireRuntimeBlock(block, src, null);
  20103     return block.addUnOp(.c_va_end, va_list_ref);
  20104 }
  20105 
  20106 fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
  20107     const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
  20108 
  20109     const va_list_ty = try sema.getBuiltinType("VaList");
  20110     try sema.requireRuntimeBlock(block, src, null);
  20111     return block.addInst(.{
  20112         .tag = .c_va_start,
  20113         .data = .{ .ty = va_list_ty },
  20114     });
  20115 }
  20116 
  20117 fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20118     const mod = sema.mod;
  20119     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  20120     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  20121     const ty = try sema.resolveType(block, ty_src, inst_data.operand);
  20122 
  20123     var anon_decl = try block.startAnonDecl();
  20124     defer anon_decl.deinit();
  20125 
  20126     const bytes = try ty.nameAllocArena(anon_decl.arena(), mod);
  20127 
  20128     const decl_ty = try mod.arrayType(.{
  20129         .len = bytes.len,
  20130         .child = .u8_type,
  20131         .sentinel = .zero_u8,
  20132     });
  20133     const new_decl = try anon_decl.finish(
  20134         decl_ty,
  20135         (try mod.intern(.{ .aggregate = .{
  20136             .ty = decl_ty.toIntern(),
  20137             .storage = .{ .bytes = bytes },
  20138         } })).toValue(),
  20139         0, // default alignment
  20140     );
  20141 
  20142     return sema.analyzeDeclRef(new_decl);
  20143 }
  20144 
  20145 fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20146     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  20147     const src = inst_data.src();
  20148     return sema.failWithUseOfAsync(block, src);
  20149 }
  20150 
  20151 fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20152     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  20153     const src = inst_data.src();
  20154     return sema.failWithUseOfAsync(block, src);
  20155 }
  20156 
  20157 fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20158     const mod = sema.mod;
  20159     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  20160     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  20161     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  20162     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  20163     const dest_ty = try sema.resolveType(block, ty_src, extra.lhs);
  20164     const operand = try sema.resolveInst(extra.rhs);
  20165     const operand_ty = sema.typeOf(operand);
  20166 
  20167     _ = try sema.checkIntType(block, ty_src, dest_ty);
  20168     try sema.checkFloatType(block, operand_src, operand_ty);
  20169 
  20170     if (try sema.resolveMaybeUndefVal(operand)) |val| {
  20171         const result_val = try sema.floatToInt(block, operand_src, val, operand_ty, dest_ty);
  20172         return sema.addConstant(dest_ty, result_val);
  20173     } else if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
  20174         return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_int' must be comptime-known");
  20175     }
  20176 
  20177     try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
  20178     if (dest_ty.intInfo(mod).bits == 0) {
  20179         if (block.wantSafety()) {
  20180             const ok = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, try sema.addConstant(operand_ty, try mod.intValue(operand_ty, 0)));
  20181             try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds);
  20182         }
  20183         return sema.addConstant(dest_ty, try mod.intValue(dest_ty, 0));
  20184     }
  20185     const result = try block.addTyOp(if (block.float_mode == .Optimized) .float_to_int_optimized else .float_to_int, dest_ty, operand);
  20186     if (block.wantSafety()) {
  20187         const back = try block.addTyOp(.int_to_float, operand_ty, result);
  20188         const diff = try block.addBinOp(.sub, operand, back);
  20189         const ok_pos = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_lt_optimized else .cmp_lt, diff, try sema.addConstant(operand_ty, try mod.floatValue(operand_ty, 1.0)));
  20190         const ok_neg = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_gt_optimized else .cmp_gt, diff, try sema.addConstant(operand_ty, try mod.floatValue(operand_ty, -1.0)));
  20191         const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg);
  20192         try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds);
  20193     }
  20194     return result;
  20195 }
  20196 
  20197 fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20198     const mod = sema.mod;
  20199     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  20200     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  20201     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  20202     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  20203     const dest_ty = try sema.resolveType(block, ty_src, extra.lhs);
  20204     const operand = try sema.resolveInst(extra.rhs);
  20205     const operand_ty = sema.typeOf(operand);
  20206 
  20207     try sema.checkFloatType(block, ty_src, dest_ty);
  20208     _ = try sema.checkIntType(block, operand_src, operand_ty);
  20209 
  20210     if (try sema.resolveMaybeUndefVal(operand)) |val| {
  20211         const result_val = try val.intToFloatAdvanced(sema.arena, operand_ty, dest_ty, sema.mod, sema);
  20212         return sema.addConstant(dest_ty, result_val);
  20213     } else if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {
  20214         return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_float' must be comptime-known");
  20215     }
  20216 
  20217     try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
  20218     return block.addTyOp(.int_to_float, dest_ty, operand);
  20219 }
  20220 
  20221 fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20222     const mod = sema.mod;
  20223     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  20224     const src = inst_data.src();
  20225 
  20226     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  20227 
  20228     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  20229     const operand_res = try sema.resolveInst(extra.rhs);
  20230     const operand_coerced = try sema.coerce(block, Type.usize, operand_res, operand_src);
  20231 
  20232     const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  20233     const ptr_ty = try sema.resolveType(block, src, extra.lhs);
  20234     try sema.checkPtrType(block, type_src, ptr_ty);
  20235     const elem_ty = ptr_ty.elemType2(mod);
  20236     const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema);
  20237 
  20238     if (ptr_ty.isSlice(mod)) {
  20239         const msg = msg: {
  20240             const msg = try sema.errMsg(block, type_src, "integer cannot be converted to slice type '{}'", .{ptr_ty.fmt(sema.mod)});
  20241             errdefer msg.destroy(sema.gpa);
  20242             try sema.errNote(block, type_src, msg, "slice length cannot be inferred from address", .{});
  20243             break :msg msg;
  20244         };
  20245         return sema.failWithOwnedErrorMsg(msg);
  20246     }
  20247 
  20248     if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| {
  20249         const addr = val.toUnsignedInt(mod);
  20250         if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0)
  20251             return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)});
  20252         if (addr != 0 and ptr_align != 0 and addr % ptr_align != 0)
  20253             return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)});
  20254 
  20255         return sema.addConstant(ptr_ty, try mod.ptrIntValue(ptr_ty, addr));
  20256     }
  20257 
  20258     try sema.requireRuntimeBlock(block, src, operand_src);
  20259     if (block.wantSafety() and (try sema.typeHasRuntimeBits(elem_ty) or elem_ty.zigTypeTag(mod) == .Fn)) {
  20260         if (!ptr_ty.isAllowzeroPtr(mod)) {
  20261             const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
  20262             try sema.addSafetyCheck(block, is_non_zero, .cast_to_null);
  20263         }
  20264 
  20265         if (ptr_align > 1) {
  20266             const align_minus_1 = try sema.addConstant(
  20267                 Type.usize,
  20268                 try mod.intValue(Type.usize, ptr_align - 1),
  20269             );
  20270             const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);
  20271             const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
  20272             try sema.addSafetyCheck(block, is_aligned, .incorrect_alignment);
  20273         }
  20274     }
  20275     return block.addBitCast(ptr_ty, operand_coerced);
  20276 }
  20277 
  20278 fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
  20279     const mod = sema.mod;
  20280     const ip = &mod.intern_pool;
  20281     const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
  20282     const src = LazySrcLoc.nodeOffset(extra.node);
  20283     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  20284     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  20285     const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
  20286     const operand = try sema.resolveInst(extra.rhs);
  20287     const operand_ty = sema.typeOf(operand);
  20288     try sema.checkErrorSetType(block, dest_ty_src, dest_ty);
  20289     try sema.checkErrorSetType(block, operand_src, operand_ty);
  20290 
  20291     // operand must be defined since it can be an invalid error value
  20292     const maybe_operand_val = try sema.resolveDefinedValue(block, operand_src, operand);
  20293 
  20294     if (disjoint: {
  20295         // Try avoiding resolving inferred error sets if we can
  20296         if (!dest_ty.isAnyError(mod) and dest_ty.errorSetNames(mod).len == 0) break :disjoint true;
  20297         if (!operand_ty.isAnyError(mod) and operand_ty.errorSetNames(mod).len == 0) break :disjoint true;
  20298         if (dest_ty.isAnyError(mod)) break :disjoint false;
  20299         if (operand_ty.isAnyError(mod)) break :disjoint false;
  20300         for (dest_ty.errorSetNames(mod)) |dest_err_name| {
  20301             if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name))
  20302                 break :disjoint false;
  20303         }
  20304 
  20305         if (!ip.isInferredErrorSetType(dest_ty.toIntern()) and
  20306             !ip.isInferredErrorSetType(operand_ty.toIntern()))
  20307         {
  20308             break :disjoint true;
  20309         }
  20310 
  20311         try sema.resolveInferredErrorSetTy(block, dest_ty_src, dest_ty);
  20312         try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty);
  20313         for (dest_ty.errorSetNames(mod)) |dest_err_name| {
  20314             if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name))
  20315                 break :disjoint false;
  20316         }
  20317 
  20318         break :disjoint true;
  20319     }) {
  20320         const msg = msg: {
  20321             const msg = try sema.errMsg(
  20322                 block,
  20323                 src,
  20324                 "error sets '{}' and '{}' have no common errors",
  20325                 .{ operand_ty.fmt(sema.mod), dest_ty.fmt(sema.mod) },
  20326             );
  20327             errdefer msg.destroy(sema.gpa);
  20328             try sema.addDeclaredHereNote(msg, operand_ty);
  20329             try sema.addDeclaredHereNote(msg, dest_ty);
  20330             break :msg msg;
  20331         };
  20332         return sema.failWithOwnedErrorMsg(msg);
  20333     }
  20334 
  20335     if (maybe_operand_val) |val| {
  20336         if (!dest_ty.isAnyError(mod)) {
  20337             const error_name = mod.intern_pool.stringToSlice(mod.intern_pool.indexToKey(val.toIntern()).err.name);
  20338             if (!dest_ty.errorSetHasField(error_name, mod)) {
  20339                 const msg = msg: {
  20340                     const msg = try sema.errMsg(
  20341                         block,
  20342                         src,
  20343                         "'error.{s}' not a member of error set '{}'",
  20344                         .{ error_name, dest_ty.fmt(sema.mod) },
  20345                     );
  20346                     errdefer msg.destroy(sema.gpa);
  20347                     try sema.addDeclaredHereNote(msg, dest_ty);
  20348                     break :msg msg;
  20349                 };
  20350                 return sema.failWithOwnedErrorMsg(msg);
  20351             }
  20352         }
  20353 
  20354         return sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty));
  20355     }
  20356 
  20357     try sema.requireRuntimeBlock(block, src, operand_src);
  20358     if (block.wantSafety() and !dest_ty.isAnyError(mod) and sema.mod.backendSupportsFeature(.error_set_has_value)) {
  20359         const err_int_inst = try block.addBitCast(Type.err_int, operand);
  20360         const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst);
  20361         try sema.addSafetyCheck(block, ok, .invalid_error_code);
  20362     }
  20363     return block.addBitCast(dest_ty, operand);
  20364 }
  20365 
  20366 fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20367     const mod = sema.mod;
  20368     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  20369     const src = inst_data.src();
  20370     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  20371     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  20372     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  20373     const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
  20374     const operand = try sema.resolveInst(extra.rhs);
  20375     const operand_ty = sema.typeOf(operand);
  20376 
  20377     try sema.checkPtrType(block, dest_ty_src, dest_ty);
  20378     try sema.checkPtrOperand(block, operand_src, operand_ty);
  20379 
  20380     const operand_info = operand_ty.ptrInfo(mod);
  20381     const dest_info = dest_ty.ptrInfo(mod);
  20382     if (!operand_info.mutable and dest_info.mutable) {
  20383         const msg = msg: {
  20384             const msg = try sema.errMsg(block, src, "cast discards const qualifier", .{});
  20385             errdefer msg.destroy(sema.gpa);
  20386 
  20387             try sema.errNote(block, src, msg, "consider using '@constCast'", .{});
  20388             break :msg msg;
  20389         };
  20390         return sema.failWithOwnedErrorMsg(msg);
  20391     }
  20392     if (operand_info.@"volatile" and !dest_info.@"volatile") {
  20393         const msg = msg: {
  20394             const msg = try sema.errMsg(block, src, "cast discards volatile qualifier", .{});
  20395             errdefer msg.destroy(sema.gpa);
  20396 
  20397             try sema.errNote(block, src, msg, "consider using '@volatileCast'", .{});
  20398             break :msg msg;
  20399         };
  20400         return sema.failWithOwnedErrorMsg(msg);
  20401     }
  20402     if (operand_info.@"addrspace" != dest_info.@"addrspace") {
  20403         const msg = msg: {
  20404             const msg = try sema.errMsg(block, src, "cast changes pointer address space", .{});
  20405             errdefer msg.destroy(sema.gpa);
  20406 
  20407             try sema.errNote(block, src, msg, "consider using '@addrSpaceCast'", .{});
  20408             break :msg msg;
  20409         };
  20410         return sema.failWithOwnedErrorMsg(msg);
  20411     }
  20412 
  20413     const dest_is_slice = dest_ty.isSlice(mod);
  20414     const operand_is_slice = operand_ty.isSlice(mod);
  20415     if (dest_is_slice and !operand_is_slice) {
  20416         return sema.fail(block, dest_ty_src, "illegal pointer cast to slice", .{});
  20417     }
  20418     const ptr = if (operand_is_slice and !dest_is_slice)
  20419         try sema.analyzeSlicePtr(block, operand_src, operand, operand_ty)
  20420     else
  20421         operand;
  20422 
  20423     const dest_elem_ty = dest_ty.elemType2(mod);
  20424     try sema.resolveTypeLayout(dest_elem_ty);
  20425     const dest_align = dest_ty.ptrAlignment(mod);
  20426 
  20427     const operand_elem_ty = operand_ty.elemType2(mod);
  20428     try sema.resolveTypeLayout(operand_elem_ty);
  20429     const operand_align = operand_ty.ptrAlignment(mod);
  20430 
  20431     // If the destination is less aligned than the source, preserve the source alignment
  20432     const aligned_dest_ty = if (operand_align <= dest_align) dest_ty else blk: {
  20433         // Unwrap the pointer (or pointer-like optional) type, set alignment, and re-wrap into result
  20434         if (dest_ty.zigTypeTag(mod) == .Optional) {
  20435             var dest_ptr_info = dest_ty.optionalChild(mod).ptrInfo(mod);
  20436             dest_ptr_info.@"align" = operand_align;
  20437             break :blk try Type.optional(sema.arena, try Type.ptr(sema.arena, mod, dest_ptr_info), mod);
  20438         } else {
  20439             var dest_ptr_info = dest_ty.ptrInfo(mod);
  20440             dest_ptr_info.@"align" = operand_align;
  20441             break :blk try Type.ptr(sema.arena, mod, dest_ptr_info);
  20442         }
  20443     };
  20444 
  20445     if (dest_is_slice) {
  20446         const operand_elem_size = operand_elem_ty.abiSize(mod);
  20447         const dest_elem_size = dest_elem_ty.abiSize(mod);
  20448         if (operand_elem_size != dest_elem_size) {
  20449             return sema.fail(block, dest_ty_src, "TODO: implement @ptrCast between slices changing the length", .{});
  20450         }
  20451     }
  20452 
  20453     if (dest_align > operand_align) {
  20454         const msg = msg: {
  20455             const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});
  20456             errdefer msg.destroy(sema.gpa);
  20457 
  20458             try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{
  20459                 operand_ty.fmt(mod), operand_align,
  20460             });
  20461             try sema.errNote(block, dest_ty_src, msg, "'{}' has alignment '{d}'", .{
  20462                 dest_ty.fmt(mod), dest_align,
  20463             });
  20464 
  20465             try sema.errNote(block, src, msg, "consider using '@alignCast'", .{});
  20466             break :msg msg;
  20467         };
  20468         return sema.failWithOwnedErrorMsg(msg);
  20469     }
  20470 
  20471     if (try sema.resolveMaybeUndefVal(ptr)) |operand_val| {
  20472         if (!dest_ty.ptrAllowsZero(mod) and operand_val.isUndef(mod)) {
  20473             return sema.failWithUseOfUndef(block, operand_src);
  20474         }
  20475         if (!dest_ty.ptrAllowsZero(mod) and operand_val.isNull(mod)) {
  20476             return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)});
  20477         }
  20478         return sema.addConstant(aligned_dest_ty, try mod.getCoerced(operand_val, aligned_dest_ty));
  20479     }
  20480 
  20481     try sema.requireRuntimeBlock(block, src, null);
  20482     if (block.wantSafety() and operand_ty.ptrAllowsZero(mod) and !dest_ty.ptrAllowsZero(mod) and
  20483         (try sema.typeHasRuntimeBits(dest_ty.elemType2(mod)) or dest_ty.elemType2(mod).zigTypeTag(mod) == .Fn))
  20484     {
  20485         const ptr_int = try block.addUnOp(.ptrtoint, ptr);
  20486         const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize);
  20487         const ok = if (operand_is_slice) ok: {
  20488             const len = try sema.analyzeSliceLen(block, operand_src, operand);
  20489             const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
  20490             break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);
  20491         } else is_non_zero;
  20492         try sema.addSafetyCheck(block, ok, .cast_to_null);
  20493     }
  20494 
  20495     return block.addBitCast(aligned_dest_ty, ptr);
  20496 }
  20497 
  20498 fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
  20499     const mod = sema.mod;
  20500     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  20501     const src = LazySrcLoc.nodeOffset(extra.node);
  20502     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  20503     const operand = try sema.resolveInst(extra.operand);
  20504     const operand_ty = sema.typeOf(operand);
  20505     try sema.checkPtrOperand(block, operand_src, operand_ty);
  20506 
  20507     var ptr_info = operand_ty.ptrInfo(mod);
  20508     ptr_info.mutable = true;
  20509     const dest_ty = try Type.ptr(sema.arena, mod, ptr_info);
  20510 
  20511     if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
  20512         return sema.addConstant(dest_ty, try mod.getCoerced(operand_val, dest_ty));
  20513     }
  20514 
  20515     try sema.requireRuntimeBlock(block, src, null);
  20516     return block.addBitCast(dest_ty, operand);
  20517 }
  20518 
  20519 fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
  20520     const mod = sema.mod;
  20521     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  20522     const src = LazySrcLoc.nodeOffset(extra.node);
  20523     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  20524     const operand = try sema.resolveInst(extra.operand);
  20525     const operand_ty = sema.typeOf(operand);
  20526     try sema.checkPtrOperand(block, operand_src, operand_ty);
  20527 
  20528     var ptr_info = operand_ty.ptrInfo(mod);
  20529     ptr_info.@"volatile" = false;
  20530     const dest_ty = try Type.ptr(sema.arena, mod, ptr_info);
  20531 
  20532     if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
  20533         return sema.addConstant(dest_ty, operand_val);
  20534     }
  20535 
  20536     try sema.requireRuntimeBlock(block, src, null);
  20537     return block.addBitCast(dest_ty, operand);
  20538 }
  20539 
  20540 fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20541     const mod = sema.mod;
  20542     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  20543     const src = inst_data.src();
  20544     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  20545     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  20546     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  20547     const dest_scalar_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
  20548     const operand = try sema.resolveInst(extra.rhs);
  20549     const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_scalar_ty);
  20550     const operand_ty = sema.typeOf(operand);
  20551     const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
  20552     const is_vector = operand_ty.zigTypeTag(mod) == .Vector;
  20553     const dest_ty = if (is_vector)
  20554         try mod.vectorType(.{
  20555             .len = operand_ty.vectorLen(mod),
  20556             .child = dest_scalar_ty.toIntern(),
  20557         })
  20558     else
  20559         dest_scalar_ty;
  20560 
  20561     if (dest_is_comptime_int) {
  20562         return sema.coerce(block, dest_ty, operand, operand_src);
  20563     }
  20564 
  20565     const dest_info = dest_scalar_ty.intInfo(mod);
  20566 
  20567     if (try sema.typeHasOnePossibleValue(dest_ty)) |val| {
  20568         return sema.addConstant(dest_ty, val);
  20569     }
  20570 
  20571     if (operand_scalar_ty.zigTypeTag(mod) != .ComptimeInt) {
  20572         const operand_info = operand_ty.intInfo(mod);
  20573         if (try sema.typeHasOnePossibleValue(operand_ty)) |val| {
  20574             return sema.addConstant(operand_ty, val);
  20575         }
  20576 
  20577         if (operand_info.signedness != dest_info.signedness) {
  20578             return sema.fail(block, operand_src, "expected {s} integer type, found '{}'", .{
  20579                 @tagName(dest_info.signedness), operand_ty.fmt(mod),
  20580             });
  20581         }
  20582         if (operand_info.bits < dest_info.bits) {
  20583             const msg = msg: {
  20584                 const msg = try sema.errMsg(
  20585                     block,
  20586                     src,
  20587                     "destination type '{}' has more bits than source type '{}'",
  20588                     .{ dest_ty.fmt(mod), operand_ty.fmt(mod) },
  20589                 );
  20590                 errdefer msg.destroy(sema.gpa);
  20591                 try sema.errNote(block, dest_ty_src, msg, "destination type has {d} bits", .{
  20592                     dest_info.bits,
  20593                 });
  20594                 try sema.errNote(block, operand_src, msg, "operand type has {d} bits", .{
  20595                     operand_info.bits,
  20596                 });
  20597                 break :msg msg;
  20598             };
  20599             return sema.failWithOwnedErrorMsg(msg);
  20600         }
  20601     }
  20602 
  20603     if (try sema.resolveMaybeUndefValIntable(operand)) |val| {
  20604         if (val.isUndef(mod)) return sema.addConstUndef(dest_ty);
  20605         if (!is_vector) {
  20606             return sema.addConstant(dest_ty, try mod.getCoerced(
  20607                 try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits, mod),
  20608                 dest_ty,
  20609             ));
  20610         }
  20611         const elems = try sema.arena.alloc(InternPool.Index, operand_ty.vectorLen(mod));
  20612         for (elems, 0..) |*elem, i| {
  20613             const elem_val = try val.elemValue(mod, i);
  20614             elem.* = try (try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits, mod)).intern(dest_scalar_ty, mod);
  20615         }
  20616         return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{
  20617             .ty = dest_ty.toIntern(),
  20618             .storage = .{ .elems = elems },
  20619         } })).toValue());
  20620     }
  20621 
  20622     try sema.requireRuntimeBlock(block, src, operand_src);
  20623     return block.addTyOp(.trunc, dest_ty, operand);
  20624 }
  20625 
  20626 fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20627     const mod = sema.mod;
  20628     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  20629     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  20630     const align_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  20631     const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  20632     const dest_align = try sema.resolveAlign(block, align_src, extra.lhs);
  20633     const ptr = try sema.resolveInst(extra.rhs);
  20634     const ptr_ty = sema.typeOf(ptr);
  20635 
  20636     try sema.checkPtrOperand(block, ptr_src, ptr_ty);
  20637 
  20638     var ptr_info = ptr_ty.ptrInfo(mod);
  20639     ptr_info.@"align" = dest_align;
  20640     var dest_ty = try Type.ptr(sema.arena, mod, ptr_info);
  20641     if (ptr_ty.zigTypeTag(mod) == .Optional) {
  20642         dest_ty = try mod.optionalType(dest_ty.toIntern());
  20643     }
  20644 
  20645     if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |val| {
  20646         if (try val.getUnsignedIntAdvanced(mod, null)) |addr| {
  20647             if (addr % dest_align != 0) {
  20648                 return sema.fail(block, ptr_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align });
  20649             }
  20650         }
  20651         return sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty));
  20652     }
  20653 
  20654     try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
  20655     if (block.wantSafety() and dest_align > 1 and
  20656         try sema.typeHasRuntimeBits(ptr_info.pointee_type))
  20657     {
  20658         const align_minus_1 = try sema.addConstant(
  20659             Type.usize,
  20660             try mod.intValue(Type.usize, dest_align - 1),
  20661         );
  20662         const actual_ptr = if (ptr_ty.isSlice(mod))
  20663             try sema.analyzeSlicePtr(block, ptr_src, ptr, ptr_ty)
  20664         else
  20665             ptr;
  20666         const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr);
  20667         const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);
  20668         const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
  20669         const ok = if (ptr_ty.isSlice(mod)) ok: {
  20670             const len = try sema.analyzeSliceLen(block, ptr_src, ptr);
  20671             const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
  20672             break :ok try block.addBinOp(.bit_or, len_zero, is_aligned);
  20673         } else is_aligned;
  20674         try sema.addSafetyCheck(block, ok, .incorrect_alignment);
  20675     }
  20676     return sema.bitCast(block, dest_ty, ptr, ptr_src, null);
  20677 }
  20678 
  20679 fn zirBitCount(
  20680     sema: *Sema,
  20681     block: *Block,
  20682     inst: Zir.Inst.Index,
  20683     air_tag: Air.Inst.Tag,
  20684     comptime comptimeOp: fn (val: Value, ty: Type, mod: *Module) u64,
  20685 ) CompileError!Air.Inst.Ref {
  20686     const mod = sema.mod;
  20687     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  20688     const src = inst_data.src();
  20689     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  20690     const operand = try sema.resolveInst(inst_data.operand);
  20691     const operand_ty = sema.typeOf(operand);
  20692     _ = try sema.checkIntOrVector(block, operand, operand_src);
  20693     const bits = operand_ty.intInfo(mod).bits;
  20694 
  20695     if (try sema.typeHasOnePossibleValue(operand_ty)) |val| {
  20696         return sema.addConstant(operand_ty, val);
  20697     }
  20698 
  20699     const result_scalar_ty = try mod.smallestUnsignedInt(bits);
  20700     switch (operand_ty.zigTypeTag(mod)) {
  20701         .Vector => {
  20702             const vec_len = operand_ty.vectorLen(mod);
  20703             const result_ty = try mod.vectorType(.{
  20704                 .len = vec_len,
  20705                 .child = result_scalar_ty.toIntern(),
  20706             });
  20707             if (try sema.resolveMaybeUndefVal(operand)) |val| {
  20708                 if (val.isUndef(mod)) return sema.addConstUndef(result_ty);
  20709 
  20710                 const elems = try sema.arena.alloc(InternPool.Index, vec_len);
  20711                 const scalar_ty = operand_ty.scalarType(mod);
  20712                 for (elems, 0..) |*elem, i| {
  20713                     const elem_val = try val.elemValue(mod, i);
  20714                     const count = comptimeOp(elem_val, scalar_ty, mod);
  20715                     elem.* = (try mod.intValue(result_scalar_ty, count)).toIntern();
  20716                 }
  20717                 return sema.addConstant(result_ty, (try mod.intern(.{ .aggregate = .{
  20718                     .ty = result_ty.toIntern(),
  20719                     .storage = .{ .elems = elems },
  20720                 } })).toValue());
  20721             } else {
  20722                 try sema.requireRuntimeBlock(block, src, operand_src);
  20723                 return block.addTyOp(air_tag, result_ty, operand);
  20724             }
  20725         },
  20726         .Int => {
  20727             if (try sema.resolveMaybeUndefLazyVal(operand)) |val| {
  20728                 if (val.isUndef(mod)) return sema.addConstUndef(result_scalar_ty);
  20729                 return sema.addIntUnsigned(result_scalar_ty, comptimeOp(val, operand_ty, mod));
  20730             } else {
  20731                 try sema.requireRuntimeBlock(block, src, operand_src);
  20732                 return block.addTyOp(air_tag, result_scalar_ty, operand);
  20733             }
  20734         },
  20735         else => unreachable,
  20736     }
  20737 }
  20738 
  20739 fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20740     const mod = sema.mod;
  20741     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  20742     const src = inst_data.src();
  20743     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  20744     const operand = try sema.resolveInst(inst_data.operand);
  20745     const operand_ty = sema.typeOf(operand);
  20746     const scalar_ty = try sema.checkIntOrVector(block, operand, operand_src);
  20747     const bits = scalar_ty.intInfo(mod).bits;
  20748     if (bits % 8 != 0) {
  20749         return sema.fail(
  20750             block,
  20751             operand_src,
  20752             "@byteSwap requires the number of bits to be evenly divisible by 8, but {} has {} bits",
  20753             .{ scalar_ty.fmt(mod), bits },
  20754         );
  20755     }
  20756 
  20757     if (try sema.typeHasOnePossibleValue(operand_ty)) |val| {
  20758         return sema.addConstant(operand_ty, val);
  20759     }
  20760 
  20761     switch (operand_ty.zigTypeTag(mod)) {
  20762         .Int => {
  20763             const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| {
  20764                 if (val.isUndef(mod)) return sema.addConstUndef(operand_ty);
  20765                 const result_val = try val.byteSwap(operand_ty, mod, sema.arena);
  20766                 return sema.addConstant(operand_ty, result_val);
  20767             } else operand_src;
  20768 
  20769             try sema.requireRuntimeBlock(block, src, runtime_src);
  20770             return block.addTyOp(.byte_swap, operand_ty, operand);
  20771         },
  20772         .Vector => {
  20773             const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| {
  20774                 if (val.isUndef(mod))
  20775                     return sema.addConstUndef(operand_ty);
  20776 
  20777                 const vec_len = operand_ty.vectorLen(mod);
  20778                 const elems = try sema.arena.alloc(InternPool.Index, vec_len);
  20779                 for (elems, 0..) |*elem, i| {
  20780                     const elem_val = try val.elemValue(mod, i);
  20781                     elem.* = try (try elem_val.byteSwap(scalar_ty, mod, sema.arena)).intern(scalar_ty, mod);
  20782                 }
  20783                 return sema.addConstant(operand_ty, (try mod.intern(.{ .aggregate = .{
  20784                     .ty = operand_ty.toIntern(),
  20785                     .storage = .{ .elems = elems },
  20786                 } })).toValue());
  20787             } else operand_src;
  20788 
  20789             try sema.requireRuntimeBlock(block, src, runtime_src);
  20790             return block.addTyOp(.byte_swap, operand_ty, operand);
  20791         },
  20792         else => unreachable,
  20793     }
  20794 }
  20795 
  20796 fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20797     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  20798     const src = inst_data.src();
  20799     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  20800     const operand = try sema.resolveInst(inst_data.operand);
  20801     const operand_ty = sema.typeOf(operand);
  20802     const scalar_ty = try sema.checkIntOrVector(block, operand, operand_src);
  20803 
  20804     if (try sema.typeHasOnePossibleValue(operand_ty)) |val| {
  20805         return sema.addConstant(operand_ty, val);
  20806     }
  20807 
  20808     const mod = sema.mod;
  20809     switch (operand_ty.zigTypeTag(mod)) {
  20810         .Int => {
  20811             const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| {
  20812                 if (val.isUndef(mod)) return sema.addConstUndef(operand_ty);
  20813                 const result_val = try val.bitReverse(operand_ty, mod, sema.arena);
  20814                 return sema.addConstant(operand_ty, result_val);
  20815             } else operand_src;
  20816 
  20817             try sema.requireRuntimeBlock(block, src, runtime_src);
  20818             return block.addTyOp(.bit_reverse, operand_ty, operand);
  20819         },
  20820         .Vector => {
  20821             const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| {
  20822                 if (val.isUndef(mod))
  20823                     return sema.addConstUndef(operand_ty);
  20824 
  20825                 const vec_len = operand_ty.vectorLen(mod);
  20826                 const elems = try sema.arena.alloc(InternPool.Index, vec_len);
  20827                 for (elems, 0..) |*elem, i| {
  20828                     const elem_val = try val.elemValue(mod, i);
  20829                     elem.* = try (try elem_val.bitReverse(scalar_ty, mod, sema.arena)).intern(scalar_ty, mod);
  20830                 }
  20831                 return sema.addConstant(operand_ty, (try mod.intern(.{ .aggregate = .{
  20832                     .ty = operand_ty.toIntern(),
  20833                     .storage = .{ .elems = elems },
  20834                 } })).toValue());
  20835             } else operand_src;
  20836 
  20837             try sema.requireRuntimeBlock(block, src, runtime_src);
  20838             return block.addTyOp(.bit_reverse, operand_ty, operand);
  20839         },
  20840         else => unreachable,
  20841     }
  20842 }
  20843 
  20844 fn zirBitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20845     const offset = try sema.bitOffsetOf(block, inst);
  20846     return sema.addIntUnsigned(Type.comptime_int, offset);
  20847 }
  20848 
  20849 fn zirOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  20850     const offset = try sema.bitOffsetOf(block, inst);
  20851     // TODO reminder to make this a compile error for packed structs
  20852     return sema.addIntUnsigned(Type.comptime_int, offset / 8);
  20853 }
  20854 
  20855 fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u64 {
  20856     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  20857     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
  20858     sema.src = src;
  20859     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  20860     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  20861     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  20862 
  20863     const ty = try sema.resolveType(block, lhs_src, extra.lhs);
  20864     const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "name of field must be comptime-known");
  20865 
  20866     const mod = sema.mod;
  20867     try sema.resolveTypeLayout(ty);
  20868     switch (ty.zigTypeTag(mod)) {
  20869         .Struct => {},
  20870         else => {
  20871             const msg = msg: {
  20872                 const msg = try sema.errMsg(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(mod)});
  20873                 errdefer msg.destroy(sema.gpa);
  20874                 try sema.addDeclaredHereNote(msg, ty);
  20875                 break :msg msg;
  20876             };
  20877             return sema.failWithOwnedErrorMsg(msg);
  20878         },
  20879     }
  20880 
  20881     const field_index = if (ty.isTuple(mod)) blk: {
  20882         if (mem.eql(u8, field_name, "len")) {
  20883             return sema.fail(block, src, "no offset available for 'len' field of tuple", .{});
  20884         }
  20885         break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src);
  20886     } else try sema.structFieldIndex(block, ty, field_name, rhs_src);
  20887 
  20888     if (ty.structFieldIsComptime(field_index, mod)) {
  20889         return sema.fail(block, src, "no offset available for comptime field", .{});
  20890     }
  20891 
  20892     switch (ty.containerLayout(mod)) {
  20893         .Packed => {
  20894             var bit_sum: u64 = 0;
  20895             const fields = ty.structFields(mod);
  20896             for (fields.values(), 0..) |field, i| {
  20897                 if (i == field_index) {
  20898                     return bit_sum;
  20899                 }
  20900                 bit_sum += field.ty.bitSize(mod);
  20901             } else unreachable;
  20902         },
  20903         else => return ty.structFieldOffset(field_index, mod) * 8,
  20904     }
  20905 }
  20906 
  20907 fn checkNamespaceType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void {
  20908     const mod = sema.mod;
  20909     switch (ty.zigTypeTag(mod)) {
  20910         .Struct, .Enum, .Union, .Opaque => return,
  20911         else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{}'", .{ty.fmt(mod)}),
  20912     }
  20913 }
  20914 
  20915 /// Returns `true` if the type was a comptime_int.
  20916 fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
  20917     const mod = sema.mod;
  20918     switch (try ty.zigTypeTagOrPoison(mod)) {
  20919         .ComptimeInt => return true,
  20920         .Int => return false,
  20921         else => return sema.fail(block, src, "expected integer type, found '{}'", .{ty.fmt(mod)}),
  20922     }
  20923 }
  20924 
  20925 fn checkInvalidPtrArithmetic(
  20926     sema: *Sema,
  20927     block: *Block,
  20928     src: LazySrcLoc,
  20929     ty: Type,
  20930 ) CompileError!void {
  20931     const mod = sema.mod;
  20932     switch (try ty.zigTypeTagOrPoison(mod)) {
  20933         .Pointer => switch (ty.ptrSize(mod)) {
  20934             .One, .Slice => return,
  20935             .Many, .C => return sema.fail(
  20936                 block,
  20937                 src,
  20938                 "invalid pointer arithmetic operator",
  20939                 .{},
  20940             ),
  20941         },
  20942         else => return,
  20943     }
  20944 }
  20945 
  20946 fn checkArithmeticOp(
  20947     sema: *Sema,
  20948     block: *Block,
  20949     src: LazySrcLoc,
  20950     scalar_tag: std.builtin.TypeId,
  20951     lhs_zig_ty_tag: std.builtin.TypeId,
  20952     rhs_zig_ty_tag: std.builtin.TypeId,
  20953     zir_tag: Zir.Inst.Tag,
  20954 ) CompileError!void {
  20955     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
  20956     const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;
  20957 
  20958     if (!is_int and !(is_float and floatOpAllowed(zir_tag))) {
  20959         return sema.fail(block, src, "invalid operands to binary expression: '{s}' and '{s}'", .{
  20960             @tagName(lhs_zig_ty_tag), @tagName(rhs_zig_ty_tag),
  20961         });
  20962     }
  20963 }
  20964 
  20965 fn checkPtrOperand(
  20966     sema: *Sema,
  20967     block: *Block,
  20968     ty_src: LazySrcLoc,
  20969     ty: Type,
  20970 ) CompileError!void {
  20971     const mod = sema.mod;
  20972     switch (ty.zigTypeTag(mod)) {
  20973         .Pointer => return,
  20974         .Fn => {
  20975             const msg = msg: {
  20976                 const msg = try sema.errMsg(
  20977                     block,
  20978                     ty_src,
  20979                     "expected pointer, found '{}'",
  20980                     .{ty.fmt(mod)},
  20981                 );
  20982                 errdefer msg.destroy(sema.gpa);
  20983 
  20984                 try sema.errNote(block, ty_src, msg, "use '&' to obtain a function pointer", .{});
  20985 
  20986                 break :msg msg;
  20987             };
  20988             return sema.failWithOwnedErrorMsg(msg);
  20989         },
  20990         .Optional => if (ty.isPtrLikeOptional(mod)) return,
  20991         else => {},
  20992     }
  20993     return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(mod)});
  20994 }
  20995 
  20996 fn checkPtrType(
  20997     sema: *Sema,
  20998     block: *Block,
  20999     ty_src: LazySrcLoc,
  21000     ty: Type,
  21001 ) CompileError!void {
  21002     const mod = sema.mod;
  21003     switch (ty.zigTypeTag(mod)) {
  21004         .Pointer => return,
  21005         .Fn => {
  21006             const msg = msg: {
  21007                 const msg = try sema.errMsg(
  21008                     block,
  21009                     ty_src,
  21010                     "expected pointer type, found '{}'",
  21011                     .{ty.fmt(mod)},
  21012                 );
  21013                 errdefer msg.destroy(sema.gpa);
  21014 
  21015                 try sema.errNote(block, ty_src, msg, "use '*const ' to make a function pointer type", .{});
  21016 
  21017                 break :msg msg;
  21018             };
  21019             return sema.failWithOwnedErrorMsg(msg);
  21020         },
  21021         .Optional => if (ty.isPtrLikeOptional(mod)) return,
  21022         else => {},
  21023     }
  21024     return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(mod)});
  21025 }
  21026 
  21027 fn checkVectorElemType(
  21028     sema: *Sema,
  21029     block: *Block,
  21030     ty_src: LazySrcLoc,
  21031     ty: Type,
  21032 ) CompileError!void {
  21033     const mod = sema.mod;
  21034     switch (ty.zigTypeTag(mod)) {
  21035         .Int, .Float, .Bool => return,
  21036         else => if (ty.isPtrAtRuntime(mod)) return,
  21037     }
  21038     return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{}'", .{ty.fmt(mod)});
  21039 }
  21040 
  21041 fn checkFloatType(
  21042     sema: *Sema,
  21043     block: *Block,
  21044     ty_src: LazySrcLoc,
  21045     ty: Type,
  21046 ) CompileError!void {
  21047     const mod = sema.mod;
  21048     switch (ty.zigTypeTag(mod)) {
  21049         .ComptimeInt, .ComptimeFloat, .Float => {},
  21050         else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty.fmt(mod)}),
  21051     }
  21052 }
  21053 
  21054 fn checkNumericType(
  21055     sema: *Sema,
  21056     block: *Block,
  21057     ty_src: LazySrcLoc,
  21058     ty: Type,
  21059 ) CompileError!void {
  21060     const mod = sema.mod;
  21061     switch (ty.zigTypeTag(mod)) {
  21062         .ComptimeFloat, .Float, .ComptimeInt, .Int => {},
  21063         .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {
  21064             .ComptimeFloat, .Float, .ComptimeInt, .Int => {},
  21065             else => |t| return sema.fail(block, ty_src, "expected number, found '{}'", .{t}),
  21066         },
  21067         else => return sema.fail(block, ty_src, "expected number, found '{}'", .{ty.fmt(mod)}),
  21068     }
  21069 }
  21070 
  21071 /// Returns the casted pointer.
  21072 fn checkAtomicPtrOperand(
  21073     sema: *Sema,
  21074     block: *Block,
  21075     elem_ty: Type,
  21076     elem_ty_src: LazySrcLoc,
  21077     ptr: Air.Inst.Ref,
  21078     ptr_src: LazySrcLoc,
  21079     ptr_const: bool,
  21080 ) CompileError!Air.Inst.Ref {
  21081     const mod = sema.mod;
  21082     var diag: Module.AtomicPtrAlignmentDiagnostics = .{};
  21083     const alignment = mod.atomicPtrAlignment(elem_ty, &diag) catch |err| switch (err) {
  21084         error.OutOfMemory => return error.OutOfMemory,
  21085         error.FloatTooBig => return sema.fail(
  21086             block,
  21087             elem_ty_src,
  21088             "expected {d}-bit float type or smaller; found {d}-bit float type",
  21089             .{ diag.max_bits, diag.bits },
  21090         ),
  21091         error.IntTooBig => return sema.fail(
  21092             block,
  21093             elem_ty_src,
  21094             "expected {d}-bit integer type or smaller; found {d}-bit integer type",
  21095             .{ diag.max_bits, diag.bits },
  21096         ),
  21097         error.BadType => return sema.fail(
  21098             block,
  21099             elem_ty_src,
  21100             "expected bool, integer, float, enum, or pointer type; found '{}'",
  21101             .{elem_ty.fmt(mod)},
  21102         ),
  21103     };
  21104 
  21105     var wanted_ptr_data: Type.Payload.Pointer.Data = .{
  21106         .pointee_type = elem_ty,
  21107         .@"align" = alignment,
  21108         .@"addrspace" = .generic,
  21109         .mutable = !ptr_const,
  21110     };
  21111 
  21112     const ptr_ty = sema.typeOf(ptr);
  21113     const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison(mod)) {
  21114         .Pointer => ptr_ty.ptrInfo(mod),
  21115         else => {
  21116             const wanted_ptr_ty = try Type.ptr(sema.arena, mod, wanted_ptr_data);
  21117             _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
  21118             unreachable;
  21119         },
  21120     };
  21121 
  21122     wanted_ptr_data.@"addrspace" = ptr_data.@"addrspace";
  21123     wanted_ptr_data.@"allowzero" = ptr_data.@"allowzero";
  21124     wanted_ptr_data.@"volatile" = ptr_data.@"volatile";
  21125 
  21126     const wanted_ptr_ty = try Type.ptr(sema.arena, mod, wanted_ptr_data);
  21127     const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
  21128 
  21129     return casted_ptr;
  21130 }
  21131 
  21132 fn checkPtrIsNotComptimeMutable(
  21133     sema: *Sema,
  21134     block: *Block,
  21135     ptr_val: Value,
  21136     ptr_src: LazySrcLoc,
  21137     operand_src: LazySrcLoc,
  21138 ) CompileError!void {
  21139     _ = operand_src;
  21140     if (ptr_val.isComptimeMutablePtr(sema.mod)) {
  21141         return sema.fail(block, ptr_src, "cannot store runtime value in compile time variable", .{});
  21142     }
  21143 }
  21144 
  21145 fn checkComptimeVarStore(
  21146     sema: *Sema,
  21147     block: *Block,
  21148     src: LazySrcLoc,
  21149     decl_ref_mut: InternPool.Key.Ptr.Addr.MutDecl,
  21150 ) CompileError!void {
  21151     if (@enumToInt(decl_ref_mut.runtime_index) < @enumToInt(block.runtime_index)) {
  21152         if (block.runtime_cond) |cond_src| {
  21153             const msg = msg: {
  21154                 const msg = try sema.errMsg(block, src, "store to comptime variable depends on runtime condition", .{});
  21155                 errdefer msg.destroy(sema.gpa);
  21156                 try sema.errNote(block, cond_src, msg, "runtime condition here", .{});
  21157                 break :msg msg;
  21158             };
  21159             return sema.failWithOwnedErrorMsg(msg);
  21160         }
  21161         if (block.runtime_loop) |loop_src| {
  21162             const msg = msg: {
  21163                 const msg = try sema.errMsg(block, src, "cannot store to comptime variable in non-inline loop", .{});
  21164                 errdefer msg.destroy(sema.gpa);
  21165                 try sema.errNote(block, loop_src, msg, "non-inline loop here", .{});
  21166                 break :msg msg;
  21167             };
  21168             return sema.failWithOwnedErrorMsg(msg);
  21169         }
  21170         unreachable;
  21171     }
  21172 }
  21173 
  21174 fn checkIntOrVector(
  21175     sema: *Sema,
  21176     block: *Block,
  21177     operand: Air.Inst.Ref,
  21178     operand_src: LazySrcLoc,
  21179 ) CompileError!Type {
  21180     const mod = sema.mod;
  21181     const operand_ty = sema.typeOf(operand);
  21182     switch (try operand_ty.zigTypeTagOrPoison(mod)) {
  21183         .Int => return operand_ty,
  21184         .Vector => {
  21185             const elem_ty = operand_ty.childType(mod);
  21186             switch (try elem_ty.zigTypeTagOrPoison(mod)) {
  21187                 .Int => return elem_ty,
  21188                 else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{
  21189                     elem_ty.fmt(mod),
  21190                 }),
  21191             }
  21192         },
  21193         else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{
  21194             operand_ty.fmt(mod),
  21195         }),
  21196     }
  21197 }
  21198 
  21199 fn checkIntOrVectorAllowComptime(
  21200     sema: *Sema,
  21201     block: *Block,
  21202     operand_ty: Type,
  21203     operand_src: LazySrcLoc,
  21204 ) CompileError!Type {
  21205     const mod = sema.mod;
  21206     switch (try operand_ty.zigTypeTagOrPoison(mod)) {
  21207         .Int, .ComptimeInt => return operand_ty,
  21208         .Vector => {
  21209             const elem_ty = operand_ty.childType(mod);
  21210             switch (try elem_ty.zigTypeTagOrPoison(mod)) {
  21211                 .Int, .ComptimeInt => return elem_ty,
  21212                 else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{
  21213                     elem_ty.fmt(mod),
  21214                 }),
  21215             }
  21216         },
  21217         else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{
  21218             operand_ty.fmt(mod),
  21219         }),
  21220     }
  21221 }
  21222 
  21223 fn checkErrorSetType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void {
  21224     const mod = sema.mod;
  21225     switch (ty.zigTypeTag(mod)) {
  21226         .ErrorSet => return,
  21227         else => return sema.fail(block, src, "expected error set type, found '{}'", .{ty.fmt(mod)}),
  21228     }
  21229 }
  21230 
  21231 const SimdBinOp = struct {
  21232     len: ?usize,
  21233     /// Coerced to `result_ty`.
  21234     lhs: Air.Inst.Ref,
  21235     /// Coerced to `result_ty`.
  21236     rhs: Air.Inst.Ref,
  21237     lhs_val: ?Value,
  21238     rhs_val: ?Value,
  21239     /// Only different than `scalar_ty` when it is a vector operation.
  21240     result_ty: Type,
  21241     scalar_ty: Type,
  21242 };
  21243 
  21244 fn checkSimdBinOp(
  21245     sema: *Sema,
  21246     block: *Block,
  21247     src: LazySrcLoc,
  21248     uncasted_lhs: Air.Inst.Ref,
  21249     uncasted_rhs: Air.Inst.Ref,
  21250     lhs_src: LazySrcLoc,
  21251     rhs_src: LazySrcLoc,
  21252 ) CompileError!SimdBinOp {
  21253     const mod = sema.mod;
  21254     const lhs_ty = sema.typeOf(uncasted_lhs);
  21255     const rhs_ty = sema.typeOf(uncasted_rhs);
  21256 
  21257     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  21258     var vec_len: ?usize = if (lhs_ty.zigTypeTag(mod) == .Vector) lhs_ty.vectorLen(mod) else null;
  21259     const result_ty = try sema.resolvePeerTypes(block, src, &.{ uncasted_lhs, uncasted_rhs }, .{
  21260         .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
  21261     });
  21262     const lhs = try sema.coerce(block, result_ty, uncasted_lhs, lhs_src);
  21263     const rhs = try sema.coerce(block, result_ty, uncasted_rhs, rhs_src);
  21264 
  21265     return SimdBinOp{
  21266         .len = vec_len,
  21267         .lhs = lhs,
  21268         .rhs = rhs,
  21269         .lhs_val = try sema.resolveMaybeUndefVal(lhs),
  21270         .rhs_val = try sema.resolveMaybeUndefVal(rhs),
  21271         .result_ty = result_ty,
  21272         .scalar_ty = result_ty.scalarType(mod),
  21273     };
  21274 }
  21275 
  21276 fn checkVectorizableBinaryOperands(
  21277     sema: *Sema,
  21278     block: *Block,
  21279     src: LazySrcLoc,
  21280     lhs_ty: Type,
  21281     rhs_ty: Type,
  21282     lhs_src: LazySrcLoc,
  21283     rhs_src: LazySrcLoc,
  21284 ) CompileError!void {
  21285     const mod = sema.mod;
  21286     const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
  21287     const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
  21288     if (lhs_zig_ty_tag != .Vector and rhs_zig_ty_tag != .Vector) return;
  21289 
  21290     const lhs_is_vector = switch (lhs_zig_ty_tag) {
  21291         .Vector, .Array => true,
  21292         else => false,
  21293     };
  21294     const rhs_is_vector = switch (rhs_zig_ty_tag) {
  21295         .Vector, .Array => true,
  21296         else => false,
  21297     };
  21298 
  21299     if (lhs_is_vector and rhs_is_vector) {
  21300         const lhs_len = lhs_ty.arrayLen(mod);
  21301         const rhs_len = rhs_ty.arrayLen(mod);
  21302         if (lhs_len != rhs_len) {
  21303             const msg = msg: {
  21304                 const msg = try sema.errMsg(block, src, "vector length mismatch", .{});
  21305                 errdefer msg.destroy(sema.gpa);
  21306                 try sema.errNote(block, lhs_src, msg, "length {d} here", .{lhs_len});
  21307                 try sema.errNote(block, rhs_src, msg, "length {d} here", .{rhs_len});
  21308                 break :msg msg;
  21309             };
  21310             return sema.failWithOwnedErrorMsg(msg);
  21311         }
  21312     } else {
  21313         const msg = msg: {
  21314             const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: '{}' and '{}'", .{
  21315                 lhs_ty.fmt(mod), rhs_ty.fmt(mod),
  21316             });
  21317             errdefer msg.destroy(sema.gpa);
  21318             if (lhs_is_vector) {
  21319                 try sema.errNote(block, lhs_src, msg, "vector here", .{});
  21320                 try sema.errNote(block, rhs_src, msg, "scalar here", .{});
  21321             } else {
  21322                 try sema.errNote(block, lhs_src, msg, "scalar here", .{});
  21323                 try sema.errNote(block, rhs_src, msg, "vector here", .{});
  21324             }
  21325             break :msg msg;
  21326         };
  21327         return sema.failWithOwnedErrorMsg(msg);
  21328     }
  21329 }
  21330 
  21331 fn maybeOptionsSrc(sema: *Sema, block: *Block, base_src: LazySrcLoc, wanted: []const u8) LazySrcLoc {
  21332     if (base_src == .unneeded) return .unneeded;
  21333     const mod = sema.mod;
  21334     return mod.optionsSrc(mod.declPtr(block.src_decl), base_src, wanted);
  21335 }
  21336 
  21337 fn resolveExportOptions(
  21338     sema: *Sema,
  21339     block: *Block,
  21340     src: LazySrcLoc,
  21341     zir_ref: Zir.Inst.Ref,
  21342 ) CompileError!std.builtin.ExportOptions {
  21343     const mod = sema.mod;
  21344     const export_options_ty = try sema.getBuiltinType("ExportOptions");
  21345     const air_ref = try sema.resolveInst(zir_ref);
  21346     const options = try sema.coerce(block, export_options_ty, air_ref, src);
  21347 
  21348     const name_src = sema.maybeOptionsSrc(block, src, "name");
  21349     const linkage_src = sema.maybeOptionsSrc(block, src, "linkage");
  21350     const section_src = sema.maybeOptionsSrc(block, src, "section");
  21351     const visibility_src = sema.maybeOptionsSrc(block, src, "visibility");
  21352 
  21353     const name_operand = try sema.fieldVal(block, src, options, "name", name_src);
  21354     const name_val = try sema.resolveConstValue(block, name_src, name_operand, "name of exported value must be comptime-known");
  21355     const name_ty = Type.slice_const_u8;
  21356     const name = try name_val.toAllocatedBytes(name_ty, sema.arena, mod);
  21357 
  21358     const linkage_operand = try sema.fieldVal(block, src, options, "linkage", linkage_src);
  21359     const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_operand, "linkage of exported value must be comptime-known");
  21360     const linkage = mod.toEnum(std.builtin.GlobalLinkage, linkage_val);
  21361 
  21362     const section_operand = try sema.fieldVal(block, src, options, "section", section_src);
  21363     const section_opt_val = try sema.resolveConstValue(block, section_src, section_operand, "linksection of exported value must be comptime-known");
  21364     const section_ty = Type.slice_const_u8;
  21365     const section = if (section_opt_val.optionalValue(mod)) |section_val|
  21366         try section_val.toAllocatedBytes(section_ty, sema.arena, mod)
  21367     else
  21368         null;
  21369 
  21370     const visibility_operand = try sema.fieldVal(block, src, options, "visibility", visibility_src);
  21371     const visibility_val = try sema.resolveConstValue(block, visibility_src, visibility_operand, "visibility of exported value must be comptime-known");
  21372     const visibility = mod.toEnum(std.builtin.SymbolVisibility, visibility_val);
  21373 
  21374     if (name.len < 1) {
  21375         return sema.fail(block, name_src, "exported symbol name cannot be empty", .{});
  21376     }
  21377 
  21378     if (visibility != .default and linkage == .Internal) {
  21379         return sema.fail(block, visibility_src, "symbol '{s}' exported with internal linkage has non-default visibility {s}", .{
  21380             name, @tagName(visibility),
  21381         });
  21382     }
  21383 
  21384     return std.builtin.ExportOptions{
  21385         .name = name,
  21386         .linkage = linkage,
  21387         .section = section,
  21388         .visibility = visibility,
  21389     };
  21390 }
  21391 
  21392 fn resolveBuiltinEnum(
  21393     sema: *Sema,
  21394     block: *Block,
  21395     src: LazySrcLoc,
  21396     zir_ref: Zir.Inst.Ref,
  21397     comptime name: []const u8,
  21398     reason: []const u8,
  21399 ) CompileError!@field(std.builtin, name) {
  21400     const mod = sema.mod;
  21401     const ty = try sema.getBuiltinType(name);
  21402     const air_ref = try sema.resolveInst(zir_ref);
  21403     const coerced = try sema.coerce(block, ty, air_ref, src);
  21404     const val = try sema.resolveConstValue(block, src, coerced, reason);
  21405     return mod.toEnum(@field(std.builtin, name), val);
  21406 }
  21407 
  21408 fn resolveAtomicOrder(
  21409     sema: *Sema,
  21410     block: *Block,
  21411     src: LazySrcLoc,
  21412     zir_ref: Zir.Inst.Ref,
  21413     reason: []const u8,
  21414 ) CompileError!std.builtin.AtomicOrder {
  21415     return sema.resolveBuiltinEnum(block, src, zir_ref, "AtomicOrder", reason);
  21416 }
  21417 
  21418 fn resolveAtomicRmwOp(
  21419     sema: *Sema,
  21420     block: *Block,
  21421     src: LazySrcLoc,
  21422     zir_ref: Zir.Inst.Ref,
  21423 ) CompileError!std.builtin.AtomicRmwOp {
  21424     return sema.resolveBuiltinEnum(block, src, zir_ref, "AtomicRmwOp", "@atomicRmW operation must be comptime-known");
  21425 }
  21426 
  21427 fn zirCmpxchg(
  21428     sema: *Sema,
  21429     block: *Block,
  21430     extended: Zir.Inst.Extended.InstData,
  21431 ) CompileError!Air.Inst.Ref {
  21432     const mod = sema.mod;
  21433     const extra = sema.code.extraData(Zir.Inst.Cmpxchg, extended.operand).data;
  21434     const air_tag: Air.Inst.Tag = switch (extended.small) {
  21435         0 => .cmpxchg_weak,
  21436         1 => .cmpxchg_strong,
  21437         else => unreachable,
  21438     };
  21439     const src = LazySrcLoc.nodeOffset(extra.node);
  21440     // zig fmt: off
  21441     const elem_ty_src      : LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  21442     const ptr_src          : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  21443     const expected_src     : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node };
  21444     const new_value_src    : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = extra.node };
  21445     const success_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg4 = extra.node };
  21446     const failure_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg5 = extra.node };
  21447     // zig fmt: on
  21448     const expected_value = try sema.resolveInst(extra.expected_value);
  21449     const elem_ty = sema.typeOf(expected_value);
  21450     if (elem_ty.zigTypeTag(mod) == .Float) {
  21451         return sema.fail(
  21452             block,
  21453             elem_ty_src,
  21454             "expected bool, integer, enum, or pointer type; found '{}'",
  21455             .{elem_ty.fmt(mod)},
  21456         );
  21457     }
  21458     const uncasted_ptr = try sema.resolveInst(extra.ptr);
  21459     const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
  21460     const new_value = try sema.coerce(block, elem_ty, try sema.resolveInst(extra.new_value), new_value_src);
  21461     const success_order = try sema.resolveAtomicOrder(block, success_order_src, extra.success_order, "atomic order of cmpxchg success must be comptime-known");
  21462     const failure_order = try sema.resolveAtomicOrder(block, failure_order_src, extra.failure_order, "atomic order of cmpxchg failure must be comptime-known");
  21463 
  21464     if (@enumToInt(success_order) < @enumToInt(std.builtin.AtomicOrder.Monotonic)) {
  21465         return sema.fail(block, success_order_src, "success atomic ordering must be Monotonic or stricter", .{});
  21466     }
  21467     if (@enumToInt(failure_order) < @enumToInt(std.builtin.AtomicOrder.Monotonic)) {
  21468         return sema.fail(block, failure_order_src, "failure atomic ordering must be Monotonic or stricter", .{});
  21469     }
  21470     if (@enumToInt(failure_order) > @enumToInt(success_order)) {
  21471         return sema.fail(block, failure_order_src, "failure atomic ordering must be no stricter than success", .{});
  21472     }
  21473     if (failure_order == .Release or failure_order == .AcqRel) {
  21474         return sema.fail(block, failure_order_src, "failure atomic ordering must not be Release or AcqRel", .{});
  21475     }
  21476 
  21477     const result_ty = try Type.optional(sema.arena, elem_ty, mod);
  21478 
  21479     // special case zero bit types
  21480     if ((try sema.typeHasOnePossibleValue(elem_ty)) != null) {
  21481         return sema.addConstant(result_ty, (try mod.intern(.{ .opt = .{
  21482             .ty = result_ty.toIntern(),
  21483             .val = .none,
  21484         } })).toValue());
  21485     }
  21486 
  21487     const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
  21488         if (try sema.resolveMaybeUndefVal(expected_value)) |expected_val| {
  21489             if (try sema.resolveMaybeUndefVal(new_value)) |new_val| {
  21490                 if (expected_val.isUndef(mod) or new_val.isUndef(mod)) {
  21491                     // TODO: this should probably cause the memory stored at the pointer
  21492                     // to become undef as well
  21493                     return sema.addConstUndef(result_ty);
  21494                 }
  21495                 const ptr_ty = sema.typeOf(ptr);
  21496                 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;
  21497                 const result_val = try mod.intern(.{ .opt = .{
  21498                     .ty = result_ty.toIntern(),
  21499                     .val = if (stored_val.eql(expected_val, elem_ty, mod)) blk: {
  21500                         try sema.storePtr(block, src, ptr, new_value);
  21501                         break :blk .none;
  21502                     } else stored_val.toIntern(),
  21503                 } });
  21504                 return sema.addConstant(result_ty, result_val.toValue());
  21505             } else break :rs new_value_src;
  21506         } else break :rs expected_src;
  21507     } else ptr_src;
  21508 
  21509     const flags: u32 = @as(u32, @enumToInt(success_order)) |
  21510         (@as(u32, @enumToInt(failure_order)) << 3);
  21511 
  21512     try sema.requireRuntimeBlock(block, src, runtime_src);
  21513     return block.addInst(.{
  21514         .tag = air_tag,
  21515         .data = .{ .ty_pl = .{
  21516             .ty = try sema.addType(result_ty),
  21517             .payload = try sema.addExtra(Air.Cmpxchg{
  21518                 .ptr = ptr,
  21519                 .expected_value = expected_value,
  21520                 .new_value = new_value,
  21521                 .flags = flags,
  21522             }),
  21523         } },
  21524     });
  21525 }
  21526 
  21527 fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  21528     const mod = sema.mod;
  21529     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  21530     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  21531     const len_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
  21532     const scalar_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
  21533     const len = @intCast(u32, try sema.resolveInt(block, len_src, extra.lhs, Type.u32, "vector splat destination length must be comptime-known"));
  21534     const scalar = try sema.resolveInst(extra.rhs);
  21535     const scalar_ty = sema.typeOf(scalar);
  21536     try sema.checkVectorElemType(block, scalar_src, scalar_ty);
  21537     const vector_ty = try mod.vectorType(.{
  21538         .len = len,
  21539         .child = scalar_ty.toIntern(),
  21540     });
  21541     if (try sema.resolveMaybeUndefVal(scalar)) |scalar_val| {
  21542         if (scalar_val.isUndef(mod)) return sema.addConstUndef(vector_ty);
  21543         return sema.addConstant(vector_ty, try sema.splat(vector_ty, scalar_val));
  21544     }
  21545 
  21546     try sema.requireRuntimeBlock(block, inst_data.src(), scalar_src);
  21547     return block.addTyOp(.splat, vector_ty, scalar);
  21548 }
  21549 
  21550 fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  21551     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  21552     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  21553     const op_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  21554     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  21555     const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, "ReduceOp", "@reduce operation must be comptime-known");
  21556     const operand = try sema.resolveInst(extra.rhs);
  21557     const operand_ty = sema.typeOf(operand);
  21558     const mod = sema.mod;
  21559 
  21560     if (operand_ty.zigTypeTag(mod) != .Vector) {
  21561         return sema.fail(block, operand_src, "expected vector, found '{}'", .{operand_ty.fmt(mod)});
  21562     }
  21563 
  21564     const scalar_ty = operand_ty.childType(mod);
  21565 
  21566     // Type-check depending on operation.
  21567     switch (operation) {
  21568         .And, .Or, .Xor => switch (scalar_ty.zigTypeTag(mod)) {
  21569             .Int, .Bool => {},
  21570             else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found '{}'", .{
  21571                 @tagName(operation), operand_ty.fmt(mod),
  21572             }),
  21573         },
  21574         .Min, .Max, .Add, .Mul => switch (scalar_ty.zigTypeTag(mod)) {
  21575             .Int, .Float => {},
  21576             else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found '{}'", .{
  21577                 @tagName(operation), operand_ty.fmt(mod),
  21578             }),
  21579         },
  21580     }
  21581 
  21582     const vec_len = operand_ty.vectorLen(mod);
  21583     if (vec_len == 0) {
  21584         // TODO re-evaluate if we should introduce a "neutral value" for some operations,
  21585         // e.g. zero for add and one for mul.
  21586         return sema.fail(block, operand_src, "@reduce operation requires a vector with nonzero length", .{});
  21587     }
  21588 
  21589     if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
  21590         if (operand_val.isUndef(mod)) return sema.addConstUndef(scalar_ty);
  21591 
  21592         var accum: Value = try operand_val.elemValue(mod, 0);
  21593         var i: u32 = 1;
  21594         while (i < vec_len) : (i += 1) {
  21595             const elem_val = try operand_val.elemValue(mod, i);
  21596             switch (operation) {
  21597                 .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena, mod),
  21598                 .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena, mod),
  21599                 .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena, mod),
  21600                 .Min => accum = accum.numberMin(elem_val, mod),
  21601                 .Max => accum = accum.numberMax(elem_val, mod),
  21602                 .Add => accum = try sema.numberAddWrapScalar(accum, elem_val, scalar_ty),
  21603                 .Mul => accum = try accum.numberMulWrap(elem_val, scalar_ty, sema.arena, mod),
  21604             }
  21605         }
  21606         return sema.addConstant(scalar_ty, accum);
  21607     }
  21608 
  21609     try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
  21610     return block.addInst(.{
  21611         .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
  21612         .data = .{ .reduce = .{
  21613             .operand = operand,
  21614             .operation = operation,
  21615         } },
  21616     });
  21617 }
  21618 
  21619 fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  21620     const mod = sema.mod;
  21621     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  21622     const extra = sema.code.extraData(Zir.Inst.Shuffle, inst_data.payload_index).data;
  21623     const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  21624     const mask_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
  21625 
  21626     const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
  21627     try sema.checkVectorElemType(block, elem_ty_src, elem_ty);
  21628     var a = try sema.resolveInst(extra.a);
  21629     var b = try sema.resolveInst(extra.b);
  21630     var mask = try sema.resolveInst(extra.mask);
  21631     var mask_ty = sema.typeOf(mask);
  21632 
  21633     const mask_len = switch (sema.typeOf(mask).zigTypeTag(mod)) {
  21634         .Array, .Vector => sema.typeOf(mask).arrayLen(mod),
  21635         else => return sema.fail(block, mask_src, "expected vector or array, found '{}'", .{sema.typeOf(mask).fmt(sema.mod)}),
  21636     };
  21637     mask_ty = try mod.vectorType(.{
  21638         .len = @intCast(u32, mask_len),
  21639         .child = .i32_type,
  21640     });
  21641     mask = try sema.coerce(block, mask_ty, mask, mask_src);
  21642     const mask_val = try sema.resolveConstMaybeUndefVal(block, mask_src, mask, "shuffle mask must be comptime-known");
  21643     return sema.analyzeShuffle(block, inst_data.src_node, elem_ty, a, b, mask_val, @intCast(u32, mask_len));
  21644 }
  21645 
  21646 fn analyzeShuffle(
  21647     sema: *Sema,
  21648     block: *Block,
  21649     src_node: i32,
  21650     elem_ty: Type,
  21651     a_arg: Air.Inst.Ref,
  21652     b_arg: Air.Inst.Ref,
  21653     mask: Value,
  21654     mask_len: u32,
  21655 ) CompileError!Air.Inst.Ref {
  21656     const mod = sema.mod;
  21657     const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = src_node };
  21658     const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = src_node };
  21659     const mask_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = src_node };
  21660     var a = a_arg;
  21661     var b = b_arg;
  21662 
  21663     const res_ty = try mod.vectorType(.{
  21664         .len = mask_len,
  21665         .child = elem_ty.toIntern(),
  21666     });
  21667 
  21668     var maybe_a_len = switch (sema.typeOf(a).zigTypeTag(mod)) {
  21669         .Array, .Vector => sema.typeOf(a).arrayLen(mod),
  21670         .Undefined => null,
  21671         else => return sema.fail(block, a_src, "expected vector or array with element type '{}', found '{}'", .{
  21672             elem_ty.fmt(sema.mod),
  21673             sema.typeOf(a).fmt(sema.mod),
  21674         }),
  21675     };
  21676     var maybe_b_len = switch (sema.typeOf(b).zigTypeTag(mod)) {
  21677         .Array, .Vector => sema.typeOf(b).arrayLen(mod),
  21678         .Undefined => null,
  21679         else => return sema.fail(block, b_src, "expected vector or array with element type '{}', found '{}'", .{
  21680             elem_ty.fmt(sema.mod),
  21681             sema.typeOf(b).fmt(sema.mod),
  21682         }),
  21683     };
  21684     if (maybe_a_len == null and maybe_b_len == null) {
  21685         return sema.addConstUndef(res_ty);
  21686     }
  21687     const a_len = @intCast(u32, maybe_a_len orelse maybe_b_len.?);
  21688     const b_len = @intCast(u32, maybe_b_len orelse a_len);
  21689 
  21690     const a_ty = try mod.vectorType(.{
  21691         .len = a_len,
  21692         .child = elem_ty.toIntern(),
  21693     });
  21694     const b_ty = try mod.vectorType(.{
  21695         .len = b_len,
  21696         .child = elem_ty.toIntern(),
  21697     });
  21698 
  21699     if (maybe_a_len == null) a = try sema.addConstUndef(a_ty) else a = try sema.coerce(block, a_ty, a, a_src);
  21700     if (maybe_b_len == null) b = try sema.addConstUndef(b_ty) else b = try sema.coerce(block, b_ty, b, b_src);
  21701 
  21702     const operand_info = [2]std.meta.Tuple(&.{ u64, LazySrcLoc, Type }){
  21703         .{ a_len, a_src, a_ty },
  21704         .{ b_len, b_src, b_ty },
  21705     };
  21706 
  21707     for (0..@intCast(usize, mask_len)) |i| {
  21708         const elem = try mask.elemValue(sema.mod, i);
  21709         if (elem.isUndef(mod)) continue;
  21710         const int = elem.toSignedInt(mod);
  21711         var unsigned: u32 = undefined;
  21712         var chosen: u32 = undefined;
  21713         if (int >= 0) {
  21714             unsigned = @intCast(u32, int);
  21715             chosen = 0;
  21716         } else {
  21717             unsigned = @intCast(u32, ~int);
  21718             chosen = 1;
  21719         }
  21720         if (unsigned >= operand_info[chosen][0]) {
  21721             const msg = msg: {
  21722                 const msg = try sema.errMsg(block, mask_src, "mask index '{d}' has out-of-bounds selection", .{i});
  21723                 errdefer msg.destroy(sema.gpa);
  21724 
  21725                 try sema.errNote(block, operand_info[chosen][1], msg, "selected index '{d}' out of bounds of '{}'", .{
  21726                     unsigned,
  21727                     operand_info[chosen][2].fmt(sema.mod),
  21728                 });
  21729 
  21730                 if (chosen == 0) {
  21731                     try sema.errNote(block, b_src, msg, "selections from the second vector are specified with negative numbers", .{});
  21732                 }
  21733 
  21734                 break :msg msg;
  21735             };
  21736             return sema.failWithOwnedErrorMsg(msg);
  21737         }
  21738     }
  21739 
  21740     if (try sema.resolveMaybeUndefVal(a)) |a_val| {
  21741         if (try sema.resolveMaybeUndefVal(b)) |b_val| {
  21742             const values = try sema.arena.alloc(InternPool.Index, mask_len);
  21743             for (values, 0..) |*value, i| {
  21744                 const mask_elem_val = try mask.elemValue(sema.mod, i);
  21745                 if (mask_elem_val.isUndef(mod)) {
  21746                     value.* = try mod.intern(.{ .undef = elem_ty.toIntern() });
  21747                     continue;
  21748                 }
  21749                 const int = mask_elem_val.toSignedInt(mod);
  21750                 const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int);
  21751                 values[i] = try (try (if (int >= 0) a_val else b_val).elemValue(mod, unsigned)).intern(elem_ty, mod);
  21752             }
  21753             return sema.addConstant(res_ty, (try mod.intern(.{ .aggregate = .{
  21754                 .ty = res_ty.toIntern(),
  21755                 .storage = .{ .elems = values },
  21756             } })).toValue());
  21757         }
  21758     }
  21759 
  21760     // All static analysis passed, and not comptime.
  21761     // For runtime codegen, vectors a and b must be the same length. Here we
  21762     // recursively @shuffle the smaller vector to append undefined elements
  21763     // to it up to the length of the longer vector. This recursion terminates
  21764     // in 1 call because these calls to analyzeShuffle guarantee a_len == b_len.
  21765     if (a_len != b_len) {
  21766         const min_len = std.math.min(a_len, b_len);
  21767         const max_src = if (a_len > b_len) a_src else b_src;
  21768         const max_len = try sema.usizeCast(block, max_src, std.math.max(a_len, b_len));
  21769 
  21770         const expand_mask_values = try sema.arena.alloc(InternPool.Index, max_len);
  21771         for (@intCast(usize, 0)..@intCast(usize, min_len)) |i| {
  21772             expand_mask_values[i] = (try mod.intValue(Type.comptime_int, i)).toIntern();
  21773         }
  21774         for (@intCast(usize, min_len)..@intCast(usize, max_len)) |i| {
  21775             expand_mask_values[i] = (try mod.intValue(Type.comptime_int, -1)).toIntern();
  21776         }
  21777         const expand_mask = try mod.intern(.{ .aggregate = .{
  21778             .ty = (try mod.vectorType(.{ .len = @intCast(u32, max_len), .child = .comptime_int_type })).toIntern(),
  21779             .storage = .{ .elems = expand_mask_values },
  21780         } });
  21781 
  21782         if (a_len < b_len) {
  21783             const undef = try sema.addConstUndef(a_ty);
  21784             a = try sema.analyzeShuffle(block, src_node, elem_ty, a, undef, expand_mask.toValue(), @intCast(u32, max_len));
  21785         } else {
  21786             const undef = try sema.addConstUndef(b_ty);
  21787             b = try sema.analyzeShuffle(block, src_node, elem_ty, b, undef, expand_mask.toValue(), @intCast(u32, max_len));
  21788         }
  21789     }
  21790 
  21791     return block.addInst(.{
  21792         .tag = .shuffle,
  21793         .data = .{ .ty_pl = .{
  21794             .ty = try sema.addType(res_ty),
  21795             .payload = try block.sema.addExtra(Air.Shuffle{
  21796                 .a = a,
  21797                 .b = b,
  21798                 .mask = mask.toIntern(),
  21799                 .mask_len = mask_len,
  21800             }),
  21801         } },
  21802     });
  21803 }
  21804 
  21805 fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
  21806     const mod = sema.mod;
  21807     const extra = sema.code.extraData(Zir.Inst.Select, extended.operand).data;
  21808 
  21809     const src = LazySrcLoc.nodeOffset(extra.node);
  21810     const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  21811     const pred_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  21812     const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node };
  21813     const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = extra.node };
  21814 
  21815     const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
  21816     try sema.checkVectorElemType(block, elem_ty_src, elem_ty);
  21817     const pred_uncoerced = try sema.resolveInst(extra.pred);
  21818     const pred_ty = sema.typeOf(pred_uncoerced);
  21819 
  21820     const vec_len_u64 = switch (try pred_ty.zigTypeTagOrPoison(mod)) {
  21821         .Vector, .Array => pred_ty.arrayLen(mod),
  21822         else => return sema.fail(block, pred_src, "expected vector or array, found '{}'", .{pred_ty.fmt(mod)}),
  21823     };
  21824     const vec_len = @intCast(u32, try sema.usizeCast(block, pred_src, vec_len_u64));
  21825 
  21826     const bool_vec_ty = try mod.vectorType(.{
  21827         .len = vec_len,
  21828         .child = .bool_type,
  21829     });
  21830     const pred = try sema.coerce(block, bool_vec_ty, pred_uncoerced, pred_src);
  21831 
  21832     const vec_ty = try mod.vectorType(.{
  21833         .len = vec_len,
  21834         .child = elem_ty.toIntern(),
  21835     });
  21836     const a = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.a), a_src);
  21837     const b = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.b), b_src);
  21838 
  21839     const maybe_pred = try sema.resolveMaybeUndefVal(pred);
  21840     const maybe_a = try sema.resolveMaybeUndefVal(a);
  21841     const maybe_b = try sema.resolveMaybeUndefVal(b);
  21842 
  21843     const runtime_src = if (maybe_pred) |pred_val| rs: {
  21844         if (pred_val.isUndef(mod)) return sema.addConstUndef(vec_ty);
  21845 
  21846         if (maybe_a) |a_val| {
  21847             if (a_val.isUndef(mod)) return sema.addConstUndef(vec_ty);
  21848 
  21849             if (maybe_b) |b_val| {
  21850                 if (b_val.isUndef(mod)) return sema.addConstUndef(vec_ty);
  21851 
  21852                 const elems = try sema.gpa.alloc(InternPool.Index, vec_len);
  21853                 for (elems, 0..) |*elem, i| {
  21854                     const pred_elem_val = try pred_val.elemValue(mod, i);
  21855                     const should_choose_a = pred_elem_val.toBool();
  21856                     elem.* = try (try (if (should_choose_a) a_val else b_val).elemValue(mod, i)).intern(elem_ty, mod);
  21857                 }
  21858 
  21859                 return sema.addConstant(vec_ty, (try mod.intern(.{ .aggregate = .{
  21860                     .ty = vec_ty.toIntern(),
  21861                     .storage = .{ .elems = elems },
  21862                 } })).toValue());
  21863             } else {
  21864                 break :rs b_src;
  21865             }
  21866         } else {
  21867             if (maybe_b) |b_val| {
  21868                 if (b_val.isUndef(mod)) return sema.addConstUndef(vec_ty);
  21869             }
  21870             break :rs a_src;
  21871         }
  21872     } else rs: {
  21873         if (maybe_a) |a_val| {
  21874             if (a_val.isUndef(mod)) return sema.addConstUndef(vec_ty);
  21875         }
  21876         if (maybe_b) |b_val| {
  21877             if (b_val.isUndef(mod)) return sema.addConstUndef(vec_ty);
  21878         }
  21879         break :rs pred_src;
  21880     };
  21881 
  21882     try sema.requireRuntimeBlock(block, src, runtime_src);
  21883     return block.addInst(.{
  21884         .tag = .select,
  21885         .data = .{ .pl_op = .{
  21886             .operand = pred,
  21887             .payload = try block.sema.addExtra(Air.Bin{
  21888                 .lhs = a,
  21889                 .rhs = b,
  21890             }),
  21891         } },
  21892     });
  21893 }
  21894 
  21895 fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  21896     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  21897     const extra = sema.code.extraData(Zir.Inst.AtomicLoad, inst_data.payload_index).data;
  21898     // zig fmt: off
  21899     const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  21900     const ptr_src    : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  21901     const order_src  : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  21902     // zig fmt: on
  21903     const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
  21904     const uncasted_ptr = try sema.resolveInst(extra.ptr);
  21905     const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true);
  21906     const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicLoad must be comptime-known");
  21907 
  21908     switch (order) {
  21909         .Release, .AcqRel => {
  21910             return sema.fail(
  21911                 block,
  21912                 order_src,
  21913                 "@atomicLoad atomic ordering must not be Release or AcqRel",
  21914                 .{},
  21915             );
  21916         },
  21917         else => {},
  21918     }
  21919 
  21920     if (try sema.typeHasOnePossibleValue(elem_ty)) |val| {
  21921         return sema.addConstant(elem_ty, val);
  21922     }
  21923 
  21924     if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
  21925         if (try sema.pointerDeref(block, ptr_src, ptr_val, sema.typeOf(ptr))) |elem_val| {
  21926             return sema.addConstant(elem_ty, elem_val);
  21927         }
  21928     }
  21929 
  21930     try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
  21931     return block.addInst(.{
  21932         .tag = .atomic_load,
  21933         .data = .{ .atomic_load = .{
  21934             .ptr = ptr,
  21935             .order = order,
  21936         } },
  21937     });
  21938 }
  21939 
  21940 fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  21941     const mod = sema.mod;
  21942     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  21943     const extra = sema.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data;
  21944     const src = inst_data.src();
  21945     // zig fmt: off
  21946     const elem_ty_src   : LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  21947     const ptr_src       : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  21948     const op_src        : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  21949     const operand_src   : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
  21950     const order_src     : LazySrcLoc = .{ .node_offset_builtin_call_arg4 = inst_data.src_node };
  21951     // zig fmt: on
  21952     const operand = try sema.resolveInst(extra.operand);
  21953     const elem_ty = sema.typeOf(operand);
  21954     const uncasted_ptr = try sema.resolveInst(extra.ptr);
  21955     const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
  21956     const op = try sema.resolveAtomicRmwOp(block, op_src, extra.operation);
  21957 
  21958     switch (elem_ty.zigTypeTag(mod)) {
  21959         .Enum => if (op != .Xchg) {
  21960             return sema.fail(block, op_src, "@atomicRmw with enum only allowed with .Xchg", .{});
  21961         },
  21962         .Bool => if (op != .Xchg) {
  21963             return sema.fail(block, op_src, "@atomicRmw with bool only allowed with .Xchg", .{});
  21964         },
  21965         .Float => switch (op) {
  21966             .Xchg, .Add, .Sub, .Max, .Min => {},
  21967             else => return sema.fail(block, op_src, "@atomicRmw with float only allowed with .Xchg, .Add, .Sub, .Max, and .Min", .{}),
  21968         },
  21969         else => {},
  21970     }
  21971     const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicRmW must be comptime-known");
  21972 
  21973     if (order == .Unordered) {
  21974         return sema.fail(block, order_src, "@atomicRmw atomic ordering must not be Unordered", .{});
  21975     }
  21976 
  21977     // special case zero bit types
  21978     if (try sema.typeHasOnePossibleValue(elem_ty)) |val| {
  21979         return sema.addConstant(elem_ty, val);
  21980     }
  21981 
  21982     const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
  21983         const maybe_operand_val = try sema.resolveMaybeUndefVal(operand);
  21984         const operand_val = maybe_operand_val orelse {
  21985             try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);
  21986             break :rs operand_src;
  21987         };
  21988         if (ptr_val.isComptimeMutablePtr(mod)) {
  21989             const ptr_ty = sema.typeOf(ptr);
  21990             const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;
  21991             const new_val = switch (op) {
  21992                 // zig fmt: off
  21993                 .Xchg => operand_val,
  21994                 .Add  => try sema.numberAddWrapScalar(stored_val, operand_val, elem_ty),
  21995                 .Sub  => try sema.numberSubWrapScalar(stored_val, operand_val, elem_ty),
  21996                 .And  => try                   stored_val.bitwiseAnd   (operand_val, elem_ty, sema.arena, mod),
  21997                 .Nand => try                   stored_val.bitwiseNand  (operand_val, elem_ty, sema.arena, mod),
  21998                 .Or   => try                   stored_val.bitwiseOr    (operand_val, elem_ty, sema.arena, mod),
  21999                 .Xor  => try                   stored_val.bitwiseXor   (operand_val, elem_ty, sema.arena, mod),
  22000                 .Max  =>                       stored_val.numberMax    (operand_val,                      mod),
  22001                 .Min  =>                       stored_val.numberMin    (operand_val,                      mod),
  22002                 // zig fmt: on
  22003             };
  22004             try sema.storePtrVal(block, src, ptr_val, new_val, elem_ty);
  22005             return sema.addConstant(elem_ty, stored_val);
  22006         } else break :rs ptr_src;
  22007     } else ptr_src;
  22008 
  22009     const flags: u32 = @as(u32, @enumToInt(order)) | (@as(u32, @enumToInt(op)) << 3);
  22010 
  22011     try sema.requireRuntimeBlock(block, src, runtime_src);
  22012     return block.addInst(.{
  22013         .tag = .atomic_rmw,
  22014         .data = .{ .pl_op = .{
  22015             .operand = ptr,
  22016             .payload = try sema.addExtra(Air.AtomicRmw{
  22017                 .operand = operand,
  22018                 .flags = flags,
  22019             }),
  22020         } },
  22021     });
  22022 }
  22023 
  22024 fn zirAtomicStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
  22025     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  22026     const extra = sema.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data;
  22027     const src = inst_data.src();
  22028     // zig fmt: off
  22029     const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  22030     const ptr_src       : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  22031     const operand_src   : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  22032     const order_src     : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
  22033     // zig fmt: on
  22034     const operand = try sema.resolveInst(extra.operand);
  22035     const elem_ty = sema.typeOf(operand);
  22036     const uncasted_ptr = try sema.resolveInst(extra.ptr);
  22037     const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
  22038     const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicStore must be comptime-known");
  22039 
  22040     const air_tag: Air.Inst.Tag = switch (order) {
  22041         .Acquire, .AcqRel => {
  22042             return sema.fail(
  22043                 block,
  22044                 order_src,
  22045                 "@atomicStore atomic ordering must not be Acquire or AcqRel",
  22046                 .{},
  22047             );
  22048         },
  22049         .Unordered => .atomic_store_unordered,
  22050         .Monotonic => .atomic_store_monotonic,
  22051         .Release => .atomic_store_release,
  22052         .SeqCst => .atomic_store_seq_cst,
  22053     };
  22054 
  22055     return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag);
  22056 }
  22057 
  22058 fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  22059     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  22060     const extra = sema.code.extraData(Zir.Inst.MulAdd, inst_data.payload_index).data;
  22061     const src = inst_data.src();
  22062 
  22063     const mulend1_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  22064     const mulend2_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  22065     const addend_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
  22066 
  22067     const addend = try sema.resolveInst(extra.addend);
  22068     const ty = sema.typeOf(addend);
  22069     const mulend1 = try sema.coerce(block, ty, try sema.resolveInst(extra.mulend1), mulend1_src);
  22070     const mulend2 = try sema.coerce(block, ty, try sema.resolveInst(extra.mulend2), mulend2_src);
  22071 
  22072     const maybe_mulend1 = try sema.resolveMaybeUndefVal(mulend1);
  22073     const maybe_mulend2 = try sema.resolveMaybeUndefVal(mulend2);
  22074     const maybe_addend = try sema.resolveMaybeUndefVal(addend);
  22075     const mod = sema.mod;
  22076 
  22077     switch (ty.zigTypeTag(mod)) {
  22078         .ComptimeFloat, .Float, .Vector => {},
  22079         else => return sema.fail(block, src, "expected vector of floats or float type, found '{}'", .{ty.fmt(sema.mod)}),
  22080     }
  22081 
  22082     const runtime_src = if (maybe_mulend1) |mulend1_val| rs: {
  22083         if (maybe_mulend2) |mulend2_val| {
  22084             if (mulend2_val.isUndef(mod)) return sema.addConstUndef(ty);
  22085 
  22086             if (maybe_addend) |addend_val| {
  22087                 if (addend_val.isUndef(mod)) return sema.addConstUndef(ty);
  22088                 const result_val = try Value.mulAdd(ty, mulend1_val, mulend2_val, addend_val, sema.arena, sema.mod);
  22089                 return sema.addConstant(ty, result_val);
  22090             } else {
  22091                 break :rs addend_src;
  22092             }
  22093         } else {
  22094             if (maybe_addend) |addend_val| {
  22095                 if (addend_val.isUndef(mod)) return sema.addConstUndef(ty);
  22096             }
  22097             break :rs mulend2_src;
  22098         }
  22099     } else rs: {
  22100         if (maybe_mulend2) |mulend2_val| {
  22101             if (mulend2_val.isUndef(mod)) return sema.addConstUndef(ty);
  22102         }
  22103         if (maybe_addend) |addend_val| {
  22104             if (addend_val.isUndef(mod)) return sema.addConstUndef(ty);
  22105         }
  22106         break :rs mulend1_src;
  22107     };
  22108 
  22109     try sema.requireRuntimeBlock(block, src, runtime_src);
  22110     return block.addInst(.{
  22111         .tag = .mul_add,
  22112         .data = .{ .pl_op = .{
  22113             .operand = addend,
  22114             .payload = try sema.addExtra(Air.Bin{
  22115                 .lhs = mulend1,
  22116                 .rhs = mulend2,
  22117             }),
  22118         } },
  22119     });
  22120 }
  22121 
  22122 fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  22123     const tracy = trace(@src());
  22124     defer tracy.end();
  22125 
  22126     const mod = sema.mod;
  22127     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  22128     const modifier_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  22129     const func_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  22130     const args_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  22131     const call_src = inst_data.src();
  22132 
  22133     const extra = sema.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data;
  22134     var func = try sema.resolveInst(extra.callee);
  22135 
  22136     const modifier_ty = try sema.getBuiltinType("CallModifier");
  22137     const air_ref = try sema.resolveInst(extra.modifier);
  22138     const modifier_ref = try sema.coerce(block, modifier_ty, air_ref, modifier_src);
  22139     const modifier_val = try sema.resolveConstValue(block, modifier_src, modifier_ref, "call modifier must be comptime-known");
  22140     var modifier = mod.toEnum(std.builtin.CallModifier, modifier_val);
  22141     switch (modifier) {
  22142         // These can be upgraded to comptime or nosuspend calls.
  22143         .auto, .never_tail, .no_async => {
  22144             if (block.is_comptime) {
  22145                 if (modifier == .never_tail) {
  22146                     return sema.fail(block, modifier_src, "unable to perform 'never_tail' call at compile-time", .{});
  22147                 }
  22148                 modifier = .compile_time;
  22149             } else if (extra.flags.is_nosuspend) {
  22150                 modifier = .no_async;
  22151             }
  22152         },
  22153         // These can be upgraded to comptime. nosuspend bit can be safely ignored.
  22154         .always_inline, .compile_time => {
  22155             _ = (try sema.resolveDefinedValue(block, func_src, func)) orelse {
  22156                 return sema.fail(block, func_src, "modifier '{s}' requires a comptime-known function", .{@tagName(modifier)});
  22157             };
  22158 
  22159             if (block.is_comptime) {
  22160                 modifier = .compile_time;
  22161             }
  22162         },
  22163         .always_tail => {
  22164             if (block.is_comptime) {
  22165                 modifier = .compile_time;
  22166             }
  22167         },
  22168         .async_kw => {
  22169             if (extra.flags.is_nosuspend) {
  22170                 return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{});
  22171             }
  22172             if (block.is_comptime) {
  22173                 return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used in combination with comptime function call", .{});
  22174             }
  22175         },
  22176         .never_inline => {
  22177             if (block.is_comptime) {
  22178                 return sema.fail(block, modifier_src, "unable to perform 'never_inline' call at compile-time", .{});
  22179             }
  22180         },
  22181     }
  22182 
  22183     const args = try sema.resolveInst(extra.args);
  22184 
  22185     const args_ty = sema.typeOf(args);
  22186     if (!args_ty.isTuple(mod) and args_ty.toIntern() != .empty_struct_type) {
  22187         return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(sema.mod)});
  22188     }
  22189 
  22190     var resolved_args: []Air.Inst.Ref = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount(mod));
  22191     for (resolved_args, 0..) |*resolved, i| {
  22192         resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
  22193     }
  22194 
  22195     const callee_ty = sema.typeOf(func);
  22196     const func_ty = try sema.checkCallArgumentCount(block, func, func_src, callee_ty, resolved_args.len, false);
  22197     const ensure_result_used = extra.flags.ensure_result_used;
  22198     return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null);
  22199 }
  22200 
  22201 fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  22202     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  22203     const extra = sema.code.extraData(Zir.Inst.FieldParentPtr, inst_data.payload_index).data;
  22204     const src = inst_data.src();
  22205     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  22206     const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  22207     const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
  22208 
  22209     const parent_ty = try sema.resolveType(block, ty_src, extra.parent_type);
  22210     const field_name = try sema.resolveConstString(block, name_src, extra.field_name, "field name must be comptime-known");
  22211     const field_ptr = try sema.resolveInst(extra.field_ptr);
  22212     const field_ptr_ty = sema.typeOf(field_ptr);
  22213     const mod = sema.mod;
  22214 
  22215     if (parent_ty.zigTypeTag(mod) != .Struct and parent_ty.zigTypeTag(mod) != .Union) {
  22216         return sema.fail(block, ty_src, "expected struct or union type, found '{}'", .{parent_ty.fmt(sema.mod)});
  22217     }
  22218     try sema.resolveTypeLayout(parent_ty);
  22219 
  22220     const field_index = switch (parent_ty.zigTypeTag(mod)) {
  22221         .Struct => blk: {
  22222             if (parent_ty.isTuple(mod)) {
  22223                 if (mem.eql(u8, field_name, "len")) {
  22224                     return sema.fail(block, src, "cannot get @fieldParentPtr of 'len' field of tuple", .{});
  22225                 }
  22226                 break :blk try sema.tupleFieldIndex(block, parent_ty, field_name, name_src);
  22227             } else {
  22228                 break :blk try sema.structFieldIndex(block, parent_ty, field_name, name_src);
  22229             }
  22230         },
  22231         .Union => try sema.unionFieldIndex(block, parent_ty, field_name, name_src),
  22232         else => unreachable,
  22233     };
  22234 
  22235     if (parent_ty.zigTypeTag(mod) == .Struct and parent_ty.structFieldIsComptime(field_index, mod)) {
  22236         return sema.fail(block, src, "cannot get @fieldParentPtr of a comptime field", .{});
  22237     }
  22238 
  22239     try sema.checkPtrOperand(block, ptr_src, field_ptr_ty);
  22240     const field_ptr_ty_info = field_ptr_ty.ptrInfo(mod);
  22241 
  22242     var ptr_ty_data: Type.Payload.Pointer.Data = .{
  22243         .pointee_type = parent_ty.structFieldType(field_index, mod),
  22244         .mutable = field_ptr_ty_info.mutable,
  22245         .@"addrspace" = field_ptr_ty_info.@"addrspace",
  22246     };
  22247 
  22248     if (parent_ty.containerLayout(mod) == .Packed) {
  22249         return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{});
  22250     } else {
  22251         ptr_ty_data.@"align" = blk: {
  22252             if (mod.typeToStruct(parent_ty)) |struct_obj| {
  22253                 break :blk struct_obj.fields.values()[field_index].abi_align;
  22254             } else if (mod.typeToUnion(parent_ty)) |union_obj| {
  22255                 break :blk union_obj.fields.values()[field_index].abi_align;
  22256             } else {
  22257                 break :blk 0;
  22258             }
  22259         };
  22260     }
  22261 
  22262     const actual_field_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);
  22263     const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, ptr_src);
  22264 
  22265     ptr_ty_data.pointee_type = parent_ty;
  22266     const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);
  22267 
  22268     if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {
  22269         const field = switch (mod.intern_pool.indexToKey(field_ptr_val.toIntern())) {
  22270             .ptr => |ptr| switch (ptr.addr) {
  22271                 .field => |field| field,
  22272                 else => null,
  22273             },
  22274             else => null,
  22275         } orelse return sema.fail(block, ptr_src, "pointer value not based on parent struct", .{});
  22276 
  22277         if (field.index != field_index) {
  22278             const msg = msg: {
  22279                 const msg = try sema.errMsg(
  22280                     block,
  22281                     src,
  22282                     "field '{s}' has index '{d}' but pointer value is index '{d}' of struct '{}'",
  22283                     .{
  22284                         field_name,
  22285                         field_index,
  22286                         field.index,
  22287                         parent_ty.fmt(sema.mod),
  22288                     },
  22289                 );
  22290                 errdefer msg.destroy(sema.gpa);
  22291                 try sema.addDeclaredHereNote(msg, parent_ty);
  22292                 break :msg msg;
  22293             };
  22294             return sema.failWithOwnedErrorMsg(msg);
  22295         }
  22296         return sema.addConstant(result_ptr, field.base.toValue());
  22297     }
  22298 
  22299     try sema.requireRuntimeBlock(block, src, ptr_src);
  22300     try sema.queueFullTypeResolution(result_ptr);
  22301     return block.addInst(.{
  22302         .tag = .field_parent_ptr,
  22303         .data = .{ .ty_pl = .{
  22304             .ty = try sema.addType(result_ptr),
  22305             .payload = try block.sema.addExtra(Air.FieldParentPtr{
  22306                 .field_ptr = casted_field_ptr,
  22307                 .field_index = @intCast(u32, field_index),
  22308             }),
  22309         } },
  22310     });
  22311 }
  22312 
  22313 fn zirMinMax(
  22314     sema: *Sema,
  22315     block: *Block,
  22316     inst: Zir.Inst.Index,
  22317     comptime air_tag: Air.Inst.Tag,
  22318 ) CompileError!Air.Inst.Ref {
  22319     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  22320     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  22321     const src = inst_data.src();
  22322     const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  22323     const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  22324     const lhs = try sema.resolveInst(extra.lhs);
  22325     const rhs = try sema.resolveInst(extra.rhs);
  22326     try sema.checkNumericType(block, lhs_src, sema.typeOf(lhs));
  22327     try sema.checkNumericType(block, rhs_src, sema.typeOf(rhs));
  22328     return sema.analyzeMinMax(block, src, air_tag, &.{ lhs, rhs }, &.{ lhs_src, rhs_src });
  22329 }
  22330 
  22331 fn zirMinMaxMulti(
  22332     sema: *Sema,
  22333     block: *Block,
  22334     extended: Zir.Inst.Extended.InstData,
  22335     comptime air_tag: Air.Inst.Tag,
  22336 ) CompileError!Air.Inst.Ref {
  22337     const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand);
  22338     const src_node = extra.data.src_node;
  22339     const src = LazySrcLoc.nodeOffset(src_node);
  22340     const operands = sema.code.refSlice(extra.end, extended.small);
  22341 
  22342     const air_refs = try sema.arena.alloc(Air.Inst.Ref, operands.len);
  22343     const operand_srcs = try sema.arena.alloc(LazySrcLoc, operands.len);
  22344 
  22345     for (operands, air_refs, operand_srcs, 0..) |zir_ref, *air_ref, *op_src, i| {
  22346         op_src.* = switch (i) {
  22347             0 => .{ .node_offset_builtin_call_arg0 = src_node },
  22348             1 => .{ .node_offset_builtin_call_arg1 = src_node },
  22349             2 => .{ .node_offset_builtin_call_arg2 = src_node },
  22350             3 => .{ .node_offset_builtin_call_arg3 = src_node },
  22351             4 => .{ .node_offset_builtin_call_arg4 = src_node },
  22352             5 => .{ .node_offset_builtin_call_arg5 = src_node },
  22353             else => src, // TODO: better source location
  22354         };
  22355         air_ref.* = try sema.resolveInst(zir_ref);
  22356         try sema.checkNumericType(block, op_src.*, sema.typeOf(air_ref.*));
  22357     }
  22358 
  22359     return sema.analyzeMinMax(block, src, air_tag, air_refs, operand_srcs);
  22360 }
  22361 
  22362 fn analyzeMinMax(
  22363     sema: *Sema,
  22364     block: *Block,
  22365     src: LazySrcLoc,
  22366     comptime air_tag: Air.Inst.Tag,
  22367     operands: []const Air.Inst.Ref,
  22368     operand_srcs: []const LazySrcLoc,
  22369 ) CompileError!Air.Inst.Ref {
  22370     assert(operands.len == operand_srcs.len);
  22371     assert(operands.len > 0);
  22372     const mod = sema.mod;
  22373 
  22374     if (operands.len == 1) return operands[0];
  22375 
  22376     const opFunc = switch (air_tag) {
  22377         .min => Value.numberMin,
  22378         .max => Value.numberMax,
  22379         else => @compileError("unreachable"),
  22380     };
  22381 
  22382     // First, find all comptime-known arguments, and get their min/max
  22383     var runtime_known = try std.DynamicBitSet.initFull(sema.arena, operands.len);
  22384     var cur_minmax: ?Air.Inst.Ref = null;
  22385     var cur_minmax_src: LazySrcLoc = undefined; // defined if cur_minmax not null
  22386     for (operands, operand_srcs, 0..) |operand, operand_src, operand_idx| {
  22387         // Resolve the value now to avoid redundant calls to `checkSimdBinOp` - we'll have to call
  22388         // it in the runtime path anyway since the result type may have been refined
  22389         const uncasted_operand_val = (try sema.resolveMaybeUndefVal(operand)) orelse continue;
  22390         if (cur_minmax) |cur| {
  22391             const simd_op = try sema.checkSimdBinOp(block, src, cur, operand, cur_minmax_src, operand_src);
  22392             const cur_val = simd_op.lhs_val.?; // cur_minmax is comptime-known
  22393             const operand_val = simd_op.rhs_val.?; // we checked the operand was resolvable above
  22394 
  22395             runtime_known.unset(operand_idx);
  22396 
  22397             if (cur_val.isUndef(mod)) continue; // result is also undef
  22398             if (operand_val.isUndef(mod)) {
  22399                 cur_minmax = try sema.addConstUndef(simd_op.result_ty);
  22400                 continue;
  22401             }
  22402 
  22403             const resolved_cur_val = try sema.resolveLazyValue(cur_val);
  22404             const resolved_operand_val = try sema.resolveLazyValue(operand_val);
  22405 
  22406             const vec_len = simd_op.len orelse {
  22407                 const result_val = opFunc(resolved_cur_val, resolved_operand_val, mod);
  22408                 cur_minmax = try sema.addConstant(simd_op.result_ty, result_val);
  22409                 continue;
  22410             };
  22411             const elems = try sema.arena.alloc(InternPool.Index, vec_len);
  22412             for (elems, 0..) |*elem, i| {
  22413                 const lhs_elem_val = try resolved_cur_val.elemValue(mod, i);
  22414                 const rhs_elem_val = try resolved_operand_val.elemValue(mod, i);
  22415                 elem.* = try opFunc(lhs_elem_val, rhs_elem_val, mod).intern(simd_op.scalar_ty, mod);
  22416             }
  22417             cur_minmax = try sema.addConstant(simd_op.result_ty, (try mod.intern(.{ .aggregate = .{
  22418                 .ty = simd_op.result_ty.toIntern(),
  22419                 .storage = .{ .elems = elems },
  22420             } })).toValue());
  22421         } else {
  22422             runtime_known.unset(operand_idx);
  22423             cur_minmax = try sema.addConstant(sema.typeOf(operand), uncasted_operand_val);
  22424             cur_minmax_src = operand_src;
  22425         }
  22426     }
  22427 
  22428     const opt_runtime_idx = runtime_known.findFirstSet();
  22429 
  22430     const comptime_refined_ty: ?Type = if (cur_minmax) |ct_minmax_ref| refined: {
  22431         // Refine the comptime-known result type based on the operation
  22432         const val = (try sema.resolveMaybeUndefVal(ct_minmax_ref)).?;
  22433         const orig_ty = sema.typeOf(ct_minmax_ref);
  22434 
  22435         if (opt_runtime_idx == null and orig_ty.eql(Type.comptime_int, mod)) {
  22436             // If all arguments were `comptime_int`, and there are no runtime args, we'll preserve that type
  22437             break :refined orig_ty;
  22438         }
  22439 
  22440         const refined_ty = if (orig_ty.zigTypeTag(mod) == .Vector) blk: {
  22441             const elem_ty = orig_ty.childType(mod);
  22442             const len = orig_ty.vectorLen(mod);
  22443 
  22444             if (len == 0) break :blk orig_ty;
  22445             if (elem_ty.isAnyFloat()) break :blk orig_ty; // can't refine floats
  22446 
  22447             var cur_min: Value = try val.elemValue(mod, 0);
  22448             var cur_max: Value = cur_min;
  22449             for (1..len) |idx| {
  22450                 const elem_val = try val.elemValue(mod, idx);
  22451                 if (elem_val.isUndef(mod)) break :blk orig_ty; // can't refine undef
  22452                 if (Value.order(elem_val, cur_min, mod).compare(.lt)) cur_min = elem_val;
  22453                 if (Value.order(elem_val, cur_max, mod).compare(.gt)) cur_max = elem_val;
  22454             }
  22455 
  22456             const refined_elem_ty = try mod.intFittingRange(cur_min, cur_max);
  22457             break :blk try mod.vectorType(.{
  22458                 .len = len,
  22459                 .child = refined_elem_ty.toIntern(),
  22460             });
  22461         } else blk: {
  22462             if (orig_ty.isAnyFloat()) break :blk orig_ty; // can't refine floats
  22463             if (val.isUndef(mod)) break :blk orig_ty; // can't refine undef
  22464             break :blk try mod.intFittingRange(val, val);
  22465         };
  22466 
  22467         // Apply the refined type to the current value - this isn't strictly necessary in the
  22468         // runtime case since we'll refine again afterwards, but keeping things as small as possible
  22469         // will allow us to emit more optimal AIR (if all the runtime operands have smaller types
  22470         // than the non-refined comptime type).
  22471         if (!refined_ty.eql(orig_ty, mod)) {
  22472             if (std.debug.runtime_safety) {
  22473                 assert(try sema.intFitsInType(val, refined_ty, null));
  22474             }
  22475             cur_minmax = try sema.addConstant(refined_ty, (try sema.resolveMaybeUndefVal(
  22476                 try sema.coerceInMemory(block, val, orig_ty, refined_ty, src),
  22477             )).?);
  22478         }
  22479 
  22480         break :refined refined_ty;
  22481     } else null;
  22482 
  22483     const runtime_idx = opt_runtime_idx orelse return cur_minmax.?;
  22484     const runtime_src = operand_srcs[runtime_idx];
  22485     try sema.requireRuntimeBlock(block, src, runtime_src);
  22486 
  22487     // Now, iterate over runtime operands, emitting a min/max instruction for each. We'll refine the
  22488     // type again at the end, based on the comptime-known bound.
  22489 
  22490     // If the comptime-known part is undef we can avoid emitting actual instructions later
  22491     const known_undef = if (cur_minmax) |operand| blk: {
  22492         const val = (try sema.resolveMaybeUndefVal(operand)).?;
  22493         break :blk val.isUndef(mod);
  22494     } else false;
  22495 
  22496     if (cur_minmax == null) {
  22497         // No comptime operands - use the first operand as the starting value
  22498         assert(runtime_idx == 0);
  22499         cur_minmax = operands[0];
  22500         cur_minmax_src = runtime_src;
  22501         runtime_known.unset(0); // don't look at this operand in the loop below
  22502     }
  22503 
  22504     var it = runtime_known.iterator(.{});
  22505     while (it.next()) |idx| {
  22506         const lhs = cur_minmax.?;
  22507         const lhs_src = cur_minmax_src;
  22508         const rhs = operands[idx];
  22509         const rhs_src = operand_srcs[idx];
  22510         const simd_op = try sema.checkSimdBinOp(block, src, lhs, rhs, lhs_src, rhs_src);
  22511         if (known_undef) {
  22512             cur_minmax = try sema.addConstant(simd_op.result_ty, Value.undef);
  22513         } else {
  22514             cur_minmax = try block.addBinOp(air_tag, simd_op.lhs, simd_op.rhs);
  22515         }
  22516     }
  22517 
  22518     if (comptime_refined_ty) |comptime_ty| refine: {
  22519         // Finally, refine the type based on the comptime-known bound.
  22520         if (known_undef) break :refine; // can't refine undef
  22521         const unrefined_ty = sema.typeOf(cur_minmax.?);
  22522         const is_vector = unrefined_ty.zigTypeTag(mod) == .Vector;
  22523         const comptime_elem_ty = if (is_vector) comptime_ty.childType(mod) else comptime_ty;
  22524         const unrefined_elem_ty = if (is_vector) unrefined_ty.childType(mod) else unrefined_ty;
  22525 
  22526         if (unrefined_elem_ty.isAnyFloat()) break :refine; // we can't refine floats
  22527 
  22528         // Compute the final bounds based on the runtime type and the comptime-known bound type
  22529         const min_val = switch (air_tag) {
  22530             .min => try unrefined_elem_ty.minInt(mod, unrefined_elem_ty),
  22531             .max => try comptime_elem_ty.minInt(mod, comptime_elem_ty), // @max(ct, rt) >= ct
  22532             else => unreachable,
  22533         };
  22534         const max_val = switch (air_tag) {
  22535             .min => try comptime_elem_ty.maxInt(mod, comptime_elem_ty), // @min(ct, rt) <= ct
  22536             .max => try unrefined_elem_ty.maxInt(mod, unrefined_elem_ty),
  22537             else => unreachable,
  22538         };
  22539 
  22540         // Find the smallest type which can contain these bounds
  22541         const final_elem_ty = try mod.intFittingRange(min_val, max_val);
  22542 
  22543         const final_ty = if (is_vector)
  22544             try mod.vectorType(.{
  22545                 .len = unrefined_ty.vectorLen(mod),
  22546                 .child = final_elem_ty.toIntern(),
  22547             })
  22548         else
  22549             final_elem_ty;
  22550 
  22551         if (!final_ty.eql(unrefined_ty, mod)) {
  22552             // We've reduced the type - cast the result down
  22553             return block.addTyOp(.intcast, final_ty, cur_minmax.?);
  22554         }
  22555     }
  22556 
  22557     return cur_minmax.?;
  22558 }
  22559 
  22560 fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !Air.Inst.Ref {
  22561     const mod = sema.mod;
  22562     const info = sema.typeOf(ptr).ptrInfo(mod);
  22563     if (info.size == .One) {
  22564         // Already an array pointer.
  22565         return ptr;
  22566     }
  22567     const new_ty = try Type.ptr(sema.arena, mod, .{
  22568         .pointee_type = try Type.array(sema.arena, len, info.sentinel, info.pointee_type, mod),
  22569         .sentinel = null,
  22570         .@"align" = info.@"align",
  22571         .@"addrspace" = info.@"addrspace",
  22572         .mutable = info.mutable,
  22573         .@"allowzero" = info.@"allowzero",
  22574         .@"volatile" = info.@"volatile",
  22575         .size = .One,
  22576     });
  22577     if (info.size == .Slice) {
  22578         return block.addTyOp(.slice_ptr, new_ty, ptr);
  22579     }
  22580     return block.addBitCast(new_ty, ptr);
  22581 }
  22582 
  22583 fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
  22584     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  22585     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  22586     const src = inst_data.src();
  22587     const dest_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  22588     const src_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  22589     const dest_ptr = try sema.resolveInst(extra.lhs);
  22590     const src_ptr = try sema.resolveInst(extra.rhs);
  22591     const dest_ty = sema.typeOf(dest_ptr);
  22592     const src_ty = sema.typeOf(src_ptr);
  22593     const dest_len = try indexablePtrLenOrNone(sema, block, dest_src, dest_ptr);
  22594     const src_len = try indexablePtrLenOrNone(sema, block, src_src, src_ptr);
  22595     const target = sema.mod.getTarget();
  22596     const mod = sema.mod;
  22597 
  22598     if (dest_ty.isConstPtr(mod)) {
  22599         return sema.fail(block, dest_src, "cannot memcpy to constant pointer", .{});
  22600     }
  22601 
  22602     if (dest_len == .none and src_len == .none) {
  22603         const msg = msg: {
  22604             const msg = try sema.errMsg(block, src, "unknown @memcpy length", .{});
  22605             errdefer msg.destroy(sema.gpa);
  22606             try sema.errNote(block, dest_src, msg, "destination type '{}' provides no length", .{
  22607                 dest_ty.fmt(sema.mod),
  22608             });
  22609             try sema.errNote(block, src_src, msg, "source type '{}' provides no length", .{
  22610                 src_ty.fmt(sema.mod),
  22611             });
  22612             break :msg msg;
  22613         };
  22614         return sema.failWithOwnedErrorMsg(msg);
  22615     }
  22616 
  22617     var len_val: ?Value = null;
  22618 
  22619     if (dest_len != .none and src_len != .none) check: {
  22620         // If we can check at compile-time, no need for runtime safety.
  22621         if (try sema.resolveDefinedValue(block, dest_src, dest_len)) |dest_len_val| {
  22622             len_val = dest_len_val;
  22623             if (try sema.resolveDefinedValue(block, src_src, src_len)) |src_len_val| {
  22624                 if (!(try sema.valuesEqual(dest_len_val, src_len_val, Type.usize))) {
  22625                     const msg = msg: {
  22626                         const msg = try sema.errMsg(block, src, "non-matching @memcpy lengths", .{});
  22627                         errdefer msg.destroy(sema.gpa);
  22628                         try sema.errNote(block, dest_src, msg, "length {} here", .{
  22629                             dest_len_val.fmtValue(Type.usize, sema.mod),
  22630                         });
  22631                         try sema.errNote(block, src_src, msg, "length {} here", .{
  22632                             src_len_val.fmtValue(Type.usize, sema.mod),
  22633                         });
  22634                         break :msg msg;
  22635                     };
  22636                     return sema.failWithOwnedErrorMsg(msg);
  22637                 }
  22638                 break :check;
  22639             }
  22640         } else if (try sema.resolveDefinedValue(block, src_src, src_len)) |src_len_val| {
  22641             len_val = src_len_val;
  22642         }
  22643 
  22644         if (block.wantSafety()) {
  22645             const ok = try block.addBinOp(.cmp_eq, dest_len, src_len);
  22646             try sema.addSafetyCheck(block, ok, .memcpy_len_mismatch);
  22647         }
  22648     } else if (dest_len != .none) {
  22649         if (try sema.resolveDefinedValue(block, dest_src, dest_len)) |dest_len_val| {
  22650             len_val = dest_len_val;
  22651         }
  22652     } else if (src_len != .none) {
  22653         if (try sema.resolveDefinedValue(block, src_src, src_len)) |src_len_val| {
  22654             len_val = src_len_val;
  22655         }
  22656     }
  22657 
  22658     const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: {
  22659         if (!dest_ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src;
  22660         if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |_| {
  22661             const len_u64 = (try len_val.?.getUnsignedIntAdvanced(mod, sema)).?;
  22662             const len = try sema.usizeCast(block, dest_src, len_u64);
  22663             for (0..len) |i| {
  22664                 const elem_index = try sema.addIntUnsigned(Type.usize, i);
  22665                 const dest_elem_ptr = try sema.elemPtrOneLayerOnly(
  22666                     block,
  22667                     src,
  22668                     dest_ptr,
  22669                     elem_index,
  22670                     src,
  22671                     true, // init
  22672                     false, // oob_safety
  22673                 );
  22674                 const src_elem_ptr = try sema.elemPtrOneLayerOnly(
  22675                     block,
  22676                     src,
  22677                     src_ptr,
  22678                     elem_index,
  22679                     src,
  22680                     false, // init
  22681                     false, // oob_safety
  22682                 );
  22683                 const uncoerced_elem = try sema.analyzeLoad(block, src, src_elem_ptr, src_src);
  22684                 try sema.storePtr2(
  22685                     block,
  22686                     src,
  22687                     dest_elem_ptr,
  22688                     dest_src,
  22689                     uncoerced_elem,
  22690                     src_src,
  22691                     .store,
  22692                 );
  22693             }
  22694             return;
  22695         } else break :rs src_src;
  22696     } else dest_src;
  22697 
  22698     // If in-memory coercion is not allowed, explode this memcpy call into a
  22699     // for loop that copies element-wise.
  22700     // Likewise if this is an iterable rather than a pointer, do the same
  22701     // lowering. The AIR instruction requires pointers with element types of
  22702     // equal ABI size.
  22703 
  22704     if (dest_ty.zigTypeTag(mod) != .Pointer or src_ty.zigTypeTag(mod) != .Pointer) {
  22705         return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the source or destination iterable is a tuple", .{});
  22706     }
  22707 
  22708     const dest_elem_ty = dest_ty.elemType2(mod);
  22709     const src_elem_ty = src_ty.elemType2(mod);
  22710     if (.ok != try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, true, target, dest_src, src_src)) {
  22711         return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the element types have different ABI sizes", .{});
  22712     }
  22713 
  22714     // If the length is comptime-known, then upgrade src and destination types
  22715     // into pointer-to-array. At this point we know they are both pointers
  22716     // already.
  22717     var new_dest_ptr = dest_ptr;
  22718     var new_src_ptr = src_ptr;
  22719     if (len_val) |val| {
  22720         const len = val.toUnsignedInt(mod);
  22721         if (len == 0) {
  22722             // This AIR instruction guarantees length > 0 if it is comptime-known.
  22723             return;
  22724         }
  22725         new_dest_ptr = try upgradeToArrayPtr(sema, block, dest_ptr, len);
  22726         new_src_ptr = try upgradeToArrayPtr(sema, block, src_ptr, len);
  22727     }
  22728 
  22729     if (dest_len != .none) {
  22730         // Change the src from slice to a many pointer, to avoid multiple ptr
  22731         // slice extractions in AIR instructions.
  22732         const new_src_ptr_ty = sema.typeOf(new_src_ptr);
  22733         if (new_src_ptr_ty.isSlice(mod)) {
  22734             new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty);
  22735         }
  22736     } else if (dest_len == .none and len_val == null) {
  22737         // Change the dest to a slice, since its type must have the length.
  22738         const dest_ptr_ptr = try sema.analyzeRef(block, dest_src, new_dest_ptr);
  22739         new_dest_ptr = try sema.analyzeSlice(block, dest_src, dest_ptr_ptr, .zero, src_len, .none, .unneeded, dest_src, dest_src, dest_src, false);
  22740         const new_src_ptr_ty = sema.typeOf(new_src_ptr);
  22741         if (new_src_ptr_ty.isSlice(mod)) {
  22742             new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty);
  22743         }
  22744     }
  22745 
  22746     try sema.requireRuntimeBlock(block, src, runtime_src);
  22747 
  22748     // Aliasing safety check.
  22749     if (block.wantSafety()) {
  22750         const len = if (len_val) |v|
  22751             try sema.addConstant(Type.usize, v)
  22752         else if (dest_len != .none)
  22753             dest_len
  22754         else
  22755             src_len;
  22756 
  22757         // Extract raw pointer from dest slice. The AIR instructions could support them, but
  22758         // it would cause redundant machine code instructions.
  22759         const new_dest_ptr_ty = sema.typeOf(new_dest_ptr);
  22760         const raw_dest_ptr = if (new_dest_ptr_ty.isSlice(mod))
  22761             try sema.analyzeSlicePtr(block, dest_src, new_dest_ptr, new_dest_ptr_ty)
  22762         else if (new_dest_ptr_ty.ptrSize(mod) == .One) ptr: {
  22763             var dest_manyptr_ty_key = mod.intern_pool.indexToKey(new_dest_ptr_ty.toIntern()).ptr_type;
  22764             assert(dest_manyptr_ty_key.flags.size == .One);
  22765             dest_manyptr_ty_key.child = dest_elem_ty.toIntern();
  22766             dest_manyptr_ty_key.flags.size = .Many;
  22767             break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(dest_manyptr_ty_key), new_dest_ptr, dest_src);
  22768         } else new_dest_ptr;
  22769 
  22770         const new_src_ptr_ty = sema.typeOf(new_src_ptr);
  22771         const raw_src_ptr = if (new_src_ptr_ty.isSlice(mod))
  22772             try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty)
  22773         else if (new_src_ptr_ty.ptrSize(mod) == .One) ptr: {
  22774             var src_manyptr_ty_key = mod.intern_pool.indexToKey(new_src_ptr_ty.toIntern()).ptr_type;
  22775             assert(src_manyptr_ty_key.flags.size == .One);
  22776             src_manyptr_ty_key.child = src_elem_ty.toIntern();
  22777             src_manyptr_ty_key.flags.size = .Many;
  22778             break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(src_manyptr_ty_key), new_src_ptr, src_src);
  22779         } else new_src_ptr;
  22780 
  22781         // ok1: dest >= src + len
  22782         // ok2: src >= dest + len
  22783         const src_plus_len = try sema.analyzePtrArithmetic(block, src, raw_src_ptr, len, .ptr_add, src_src, src);
  22784         const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src);
  22785         const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len);
  22786         const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len);
  22787         const ok = try block.addBinOp(.bit_or, ok1, ok2);
  22788         try sema.addSafetyCheck(block, ok, .memcpy_alias);
  22789     }
  22790 
  22791     _ = try block.addInst(.{
  22792         .tag = .memcpy,
  22793         .data = .{ .bin_op = .{
  22794             .lhs = new_dest_ptr,
  22795             .rhs = new_src_ptr,
  22796         } },
  22797     });
  22798 }
  22799 
  22800 fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
  22801     const mod = sema.mod;
  22802     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  22803     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
  22804     const src = inst_data.src();
  22805     const dest_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
  22806     const value_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
  22807     const dest_ptr = try sema.resolveInst(extra.lhs);
  22808     const uncoerced_elem = try sema.resolveInst(extra.rhs);
  22809     const dest_ptr_ty = sema.typeOf(dest_ptr);
  22810     try checkMemOperand(sema, block, dest_src, dest_ptr_ty);
  22811 
  22812     if (dest_ptr_ty.isConstPtr(mod)) {
  22813         return sema.fail(block, dest_src, "cannot memset constant pointer", .{});
  22814     }
  22815 
  22816     const dest_elem_ty = dest_ptr_ty.elemType2(mod);
  22817 
  22818     const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: {
  22819         const len_air_ref = try sema.fieldVal(block, src, dest_ptr, "len", dest_src);
  22820         const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse
  22821             break :rs dest_src;
  22822         const len_u64 = (try len_val.getUnsignedIntAdvanced(mod, sema)).?;
  22823         const len = try sema.usizeCast(block, dest_src, len_u64);
  22824         if (len == 0) {
  22825             // This AIR instruction guarantees length > 0 if it is comptime-known.
  22826             return;
  22827         }
  22828 
  22829         if (!ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src;
  22830         if (try sema.resolveMaybeUndefVal(uncoerced_elem)) |_| {
  22831             for (0..len) |i| {
  22832                 const elem_index = try sema.addIntUnsigned(Type.usize, i);
  22833                 const elem_ptr = try sema.elemPtrOneLayerOnly(
  22834                     block,
  22835                     src,
  22836                     dest_ptr,
  22837                     elem_index,
  22838                     src,
  22839                     true, // init
  22840                     false, // oob_safety
  22841                 );
  22842                 try sema.storePtr2(
  22843                     block,
  22844                     src,
  22845                     elem_ptr,
  22846                     dest_src,
  22847                     uncoerced_elem,
  22848                     value_src,
  22849                     .store,
  22850                 );
  22851             }
  22852             return;
  22853         } else break :rs value_src;
  22854     } else dest_src;
  22855 
  22856     const elem = try sema.coerce(block, dest_elem_ty, uncoerced_elem, value_src);
  22857 
  22858     try sema.requireRuntimeBlock(block, src, runtime_src);
  22859     _ = try block.addInst(.{
  22860         .tag = if (block.wantSafety()) .memset_safe else .memset,
  22861         .data = .{ .bin_op = .{
  22862             .lhs = dest_ptr,
  22863             .rhs = elem,
  22864         } },
  22865     });
  22866 }
  22867 
  22868 fn zirBuiltinAsyncCall(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
  22869     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  22870     const src = LazySrcLoc.nodeOffset(extra.node);
  22871     return sema.failWithUseOfAsync(block, src);
  22872 }
  22873 
  22874 fn zirResume(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  22875     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  22876     const src = inst_data.src();
  22877     return sema.failWithUseOfAsync(block, src);
  22878 }
  22879 
  22880 fn zirAwait(
  22881     sema: *Sema,
  22882     block: *Block,
  22883     inst: Zir.Inst.Index,
  22884 ) CompileError!Air.Inst.Ref {
  22885     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
  22886     const src = inst_data.src();
  22887 
  22888     return sema.failWithUseOfAsync(block, src);
  22889 }
  22890 
  22891 fn zirAwaitNosuspend(
  22892     sema: *Sema,
  22893     block: *Block,
  22894     extended: Zir.Inst.Extended.InstData,
  22895 ) CompileError!Air.Inst.Ref {
  22896     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  22897     const src = LazySrcLoc.nodeOffset(extra.node);
  22898 
  22899     return sema.failWithUseOfAsync(block, src);
  22900 }
  22901 
  22902 fn zirVarExtended(
  22903     sema: *Sema,
  22904     block: *Block,
  22905     extended: Zir.Inst.Extended.InstData,
  22906 ) CompileError!Air.Inst.Ref {
  22907     const mod = sema.mod;
  22908     const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand);
  22909     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 };
  22910     const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 };
  22911     const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small);
  22912 
  22913     var extra_index: usize = extra.end;
  22914 
  22915     const lib_name: ?[]const u8 = if (small.has_lib_name) blk: {
  22916         const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]);
  22917         extra_index += 1;
  22918         break :blk lib_name;
  22919     } else null;
  22920 
  22921     // ZIR supports encoding this information but it is not used; the information
  22922     // is encoded via the Decl entry.
  22923     assert(!small.has_align);
  22924 
  22925     const uncasted_init: Air.Inst.Ref = if (small.has_init) blk: {
  22926         const init_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  22927         extra_index += 1;
  22928         break :blk try sema.resolveInst(init_ref);
  22929     } else .none;
  22930 
  22931     const have_ty = extra.data.var_type != .none;
  22932     const var_ty = if (have_ty)
  22933         try sema.resolveType(block, ty_src, extra.data.var_type)
  22934     else
  22935         sema.typeOf(uncasted_init);
  22936 
  22937     const init_val = if (uncasted_init != .none) blk: {
  22938         const init = if (have_ty)
  22939             try sema.coerce(block, var_ty, uncasted_init, init_src)
  22940         else
  22941             uncasted_init;
  22942 
  22943         break :blk ((try sema.resolveMaybeUndefVal(init)) orelse
  22944             return sema.failWithNeededComptime(block, init_src, "container level variable initializers must be comptime-known")).toIntern();
  22945     } else .none;
  22946 
  22947     try sema.validateVarType(block, ty_src, var_ty, small.is_extern);
  22948 
  22949     return sema.addConstant(var_ty, (try mod.intern(.{ .variable = .{
  22950         .ty = var_ty.toIntern(),
  22951         .init = init_val,
  22952         .decl = sema.owner_decl_index,
  22953         .lib_name = if (lib_name) |lname| (try mod.intern_pool.getOrPutString(
  22954             sema.gpa,
  22955             try sema.handleExternLibName(block, ty_src, lname),
  22956         )).toOptional() else .none,
  22957         .is_extern = small.is_extern,
  22958         .is_threadlocal = small.is_threadlocal,
  22959     } })).toValue());
  22960 }
  22961 
  22962 fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
  22963     const tracy = trace(@src());
  22964     defer tracy.end();
  22965 
  22966     const mod = sema.mod;
  22967     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
  22968     const extra = sema.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
  22969     const target = mod.getTarget();
  22970 
  22971     const align_src: LazySrcLoc = .{ .node_offset_fn_type_align = inst_data.src_node };
  22972     const addrspace_src: LazySrcLoc = .{ .node_offset_fn_type_addrspace = inst_data.src_node };
  22973     const section_src: LazySrcLoc = .{ .node_offset_fn_type_section = inst_data.src_node };
  22974     const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node };
  22975     const ret_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = inst_data.src_node };
  22976     const has_body = extra.data.body_len != 0;
  22977 
  22978     var extra_index: usize = extra.end;
  22979 
  22980     const lib_name: ?[]const u8 = if (extra.data.bits.has_lib_name) blk: {
  22981         const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]);
  22982         extra_index += 1;
  22983         break :blk lib_name;
  22984     } else null;
  22985 
  22986     if (has_body and
  22987         (extra.data.bits.has_align_body or extra.data.bits.has_align_ref) and
  22988         !target_util.supportsFunctionAlignment(target))
  22989     {
  22990         return sema.fail(block, align_src, "target does not support function alignment", .{});
  22991     }
  22992 
  22993     const @"align": ?u32 = if (extra.data.bits.has_align_body) blk: {
  22994         const body_len = sema.code.extra[extra_index];
  22995         extra_index += 1;
  22996         const body = sema.code.extra[extra_index..][0..body_len];
  22997         extra_index += body.len;
  22998 
  22999         const val = try sema.resolveGenericBody(block, align_src, body, inst, Type.u29, "alignment must be comptime-known");
  23000         if (val.isGenericPoison()) {
  23001             break :blk null;
  23002         }
  23003         const alignment = @intCast(u32, val.toUnsignedInt(mod));
  23004         try sema.validateAlign(block, align_src, alignment);
  23005         if (alignment == target_util.defaultFunctionAlignment(target)) {
  23006             break :blk 0;
  23007         } else {
  23008             break :blk alignment;
  23009         }
  23010     } else if (extra.data.bits.has_align_ref) blk: {
  23011         const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  23012         extra_index += 1;
  23013         const align_tv = sema.resolveInstConst(block, align_src, align_ref, "alignment must be comptime-known") catch |err| switch (err) {
  23014             error.GenericPoison => {
  23015                 break :blk null;
  23016             },
  23017             else => |e| return e,
  23018         };
  23019         const alignment = @intCast(u32, align_tv.val.toUnsignedInt(mod));
  23020         try sema.validateAlign(block, align_src, alignment);
  23021         if (alignment == target_util.defaultFunctionAlignment(target)) {
  23022             break :blk 0;
  23023         } else {
  23024             break :blk alignment;
  23025         }
  23026     } else 0;
  23027 
  23028     const @"addrspace": ?std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: {
  23029         const body_len = sema.code.extra[extra_index];
  23030         extra_index += 1;
  23031         const body = sema.code.extra[extra_index..][0..body_len];
  23032         extra_index += body.len;
  23033 
  23034         const addrspace_ty = try sema.getBuiltinType("AddressSpace");
  23035         const val = try sema.resolveGenericBody(block, addrspace_src, body, inst, addrspace_ty, "addrespace must be comptime-known");
  23036         if (val.isGenericPoison()) {
  23037             break :blk null;
  23038         }
  23039         break :blk mod.toEnum(std.builtin.AddressSpace, val);
  23040     } else if (extra.data.bits.has_addrspace_ref) blk: {
  23041         const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  23042         extra_index += 1;
  23043         const addrspace_tv = sema.resolveInstConst(block, addrspace_src, addrspace_ref, "addrespace must be comptime-known") catch |err| switch (err) {
  23044             error.GenericPoison => {
  23045                 break :blk null;
  23046             },
  23047             else => |e| return e,
  23048         };
  23049         break :blk mod.toEnum(std.builtin.AddressSpace, addrspace_tv.val);
  23050     } else target_util.defaultAddressSpace(target, .function);
  23051 
  23052     const @"linksection": FuncLinkSection = if (extra.data.bits.has_section_body) blk: {
  23053         const body_len = sema.code.extra[extra_index];
  23054         extra_index += 1;
  23055         const body = sema.code.extra[extra_index..][0..body_len];
  23056         extra_index += body.len;
  23057 
  23058         const ty = Type.slice_const_u8;
  23059         const val = try sema.resolveGenericBody(block, section_src, body, inst, ty, "linksection must be comptime-known");
  23060         if (val.isGenericPoison()) {
  23061             break :blk FuncLinkSection{ .generic = {} };
  23062         }
  23063         break :blk FuncLinkSection{ .explicit = try val.toAllocatedBytes(ty, sema.arena, sema.mod) };
  23064     } else if (extra.data.bits.has_section_ref) blk: {
  23065         const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  23066         extra_index += 1;
  23067         const section_name = sema.resolveConstString(block, section_src, section_ref, "linksection must be comptime-known") catch |err| switch (err) {
  23068             error.GenericPoison => {
  23069                 break :blk FuncLinkSection{ .generic = {} };
  23070             },
  23071             else => |e| return e,
  23072         };
  23073         break :blk FuncLinkSection{ .explicit = section_name };
  23074     } else FuncLinkSection{ .default = {} };
  23075 
  23076     const cc: ?std.builtin.CallingConvention = if (extra.data.bits.has_cc_body) blk: {
  23077         const body_len = sema.code.extra[extra_index];
  23078         extra_index += 1;
  23079         const body = sema.code.extra[extra_index..][0..body_len];
  23080         extra_index += body.len;
  23081 
  23082         const cc_ty = try sema.getBuiltinType("CallingConvention");
  23083         const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty, "calling convention must be comptime-known");
  23084         if (val.isGenericPoison()) {
  23085             break :blk null;
  23086         }
  23087         break :blk mod.toEnum(std.builtin.CallingConvention, val);
  23088     } else if (extra.data.bits.has_cc_ref) blk: {
  23089         const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  23090         extra_index += 1;
  23091         const cc_tv = sema.resolveInstConst(block, cc_src, cc_ref, "calling convention must be comptime-known") catch |err| switch (err) {
  23092             error.GenericPoison => {
  23093                 break :blk null;
  23094             },
  23095             else => |e| return e,
  23096         };
  23097         break :blk mod.toEnum(std.builtin.CallingConvention, cc_tv.val);
  23098     } else if (sema.owner_decl.is_exported and has_body)
  23099         .C
  23100     else
  23101         .Unspecified;
  23102 
  23103     const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: {
  23104         const body_len = sema.code.extra[extra_index];
  23105         extra_index += 1;
  23106         const body = sema.code.extra[extra_index..][0..body_len];
  23107         extra_index += body.len;
  23108 
  23109         const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type, "return type must be comptime-known");
  23110         const ty = val.toType();
  23111         break :blk ty;
  23112     } else if (extra.data.bits.has_ret_ty_ref) blk: {
  23113         const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
  23114         extra_index += 1;
  23115         const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref, "return type must be comptime-known") catch |err| switch (err) {
  23116             error.GenericPoison => {
  23117                 break :blk Type.generic_poison;
  23118             },
  23119             else => |e| return e,
  23120         };
  23121         const ty = ret_ty_tv.val.toType();
  23122         break :blk ty;
  23123     } else Type.void;
  23124 
  23125     const noalias_bits: u32 = if (extra.data.bits.has_any_noalias) blk: {
  23126         const x = sema.code.extra[extra_index];
  23127         extra_index += 1;
  23128         break :blk x;
  23129     } else 0;
  23130 
  23131     var src_locs: Zir.Inst.Func.SrcLocs = undefined;
  23132     if (has_body) {
  23133         extra_index += extra.data.body_len;
  23134         src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
  23135     }
  23136 
  23137     const is_var_args = extra.data.bits.is_var_args;
  23138     const is_inferred_error = extra.data.bits.is_inferred_error;
  23139     const is_extern = extra.data.bits.is_extern;
  23140     const is_noinline = extra.data.bits.is_noinline;
  23141 
  23142     return sema.funcCommon(
  23143         block,
  23144         inst_data.src_node,
  23145         inst,
  23146         @"align",
  23147         @"addrspace",
  23148         @"linksection",
  23149         cc,
  23150         ret_ty,
  23151         is_var_args,
  23152         is_inferred_error,
  23153         is_extern,
  23154         has_body,
  23155         src_locs,
  23156         lib_name,
  23157         noalias_bits,
  23158         is_noinline,
  23159     );
  23160 }
  23161 
  23162 fn zirCUndef(
  23163     sema: *Sema,
  23164     block: *Block,
  23165     extended: Zir.Inst.Extended.InstData,
  23166 ) CompileError!Air.Inst.Ref {
  23167     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  23168     const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  23169 
  23170     const name = try sema.resolveConstString(block, src, extra.operand, "name of macro being undefined must be comptime-known");
  23171     try block.c_import_buf.?.writer().print("#undef {s}\n", .{name});
  23172     return Air.Inst.Ref.void_value;
  23173 }
  23174 
  23175 fn zirCInclude(
  23176     sema: *Sema,
  23177     block: *Block,
  23178     extended: Zir.Inst.Extended.InstData,
  23179 ) CompileError!Air.Inst.Ref {
  23180     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  23181     const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  23182 
  23183     const name = try sema.resolveConstString(block, src, extra.operand, "path being included must be comptime-known");
  23184     try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name});
  23185     return Air.Inst.Ref.void_value;
  23186 }
  23187 
  23188 fn zirCDefine(
  23189     sema: *Sema,
  23190     block: *Block,
  23191     extended: Zir.Inst.Extended.InstData,
  23192 ) CompileError!Air.Inst.Ref {
  23193     const mod = sema.mod;
  23194     const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
  23195     const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  23196     const val_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  23197 
  23198     const name = try sema.resolveConstString(block, name_src, extra.lhs, "name of macro being undefined must be comptime-known");
  23199     const rhs = try sema.resolveInst(extra.rhs);
  23200     if (sema.typeOf(rhs).zigTypeTag(mod) != .Void) {
  23201         const value = try sema.resolveConstString(block, val_src, extra.rhs, "value of macro being undefined must be comptime-known");
  23202         try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value });
  23203     } else {
  23204         try block.c_import_buf.?.writer().print("#define {s}\n", .{name});
  23205     }
  23206     return Air.Inst.Ref.void_value;
  23207 }
  23208 
  23209 fn zirWasmMemorySize(
  23210     sema: *Sema,
  23211     block: *Block,
  23212     extended: Zir.Inst.Extended.InstData,
  23213 ) CompileError!Air.Inst.Ref {
  23214     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  23215     const index_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  23216     const builtin_src = LazySrcLoc.nodeOffset(extra.node);
  23217     const target = sema.mod.getTarget();
  23218     if (!target.isWasm()) {
  23219         return sema.fail(block, builtin_src, "builtin @wasmMemorySize is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)});
  23220     }
  23221 
  23222     const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.operand, Type.u32, "wasm memory size index must be comptime-known"));
  23223     try sema.requireRuntimeBlock(block, builtin_src, null);
  23224     return block.addInst(.{
  23225         .tag = .wasm_memory_size,
  23226         .data = .{ .pl_op = .{
  23227             .operand = .none,
  23228             .payload = index,
  23229         } },
  23230     });
  23231 }
  23232 
  23233 fn zirWasmMemoryGrow(
  23234     sema: *Sema,
  23235     block: *Block,
  23236     extended: Zir.Inst.Extended.InstData,
  23237 ) CompileError!Air.Inst.Ref {
  23238     const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
  23239     const builtin_src = LazySrcLoc.nodeOffset(extra.node);
  23240     const index_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  23241     const delta_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  23242     const target = sema.mod.getTarget();
  23243     if (!target.isWasm()) {
  23244         return sema.fail(block, builtin_src, "builtin @wasmMemoryGrow is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)});
  23245     }
  23246 
  23247     const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.lhs, Type.u32, "wasm memory size index must be comptime-known"));
  23248     const delta = try sema.coerce(block, Type.u32, try sema.resolveInst(extra.rhs), delta_src);
  23249 
  23250     try sema.requireRuntimeBlock(block, builtin_src, null);
  23251     return block.addInst(.{
  23252         .tag = .wasm_memory_grow,
  23253         .data = .{ .pl_op = .{
  23254             .operand = delta,
  23255             .payload = index,
  23256         } },
  23257     });
  23258 }
  23259 
  23260 fn resolvePrefetchOptions(
  23261     sema: *Sema,
  23262     block: *Block,
  23263     src: LazySrcLoc,
  23264     zir_ref: Zir.Inst.Ref,
  23265 ) CompileError!std.builtin.PrefetchOptions {
  23266     const mod = sema.mod;
  23267     const options_ty = try sema.getBuiltinType("PrefetchOptions");
  23268     const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src);
  23269 
  23270     const rw_src = sema.maybeOptionsSrc(block, src, "rw");
  23271     const locality_src = sema.maybeOptionsSrc(block, src, "locality");
  23272     const cache_src = sema.maybeOptionsSrc(block, src, "cache");
  23273 
  23274     const rw = try sema.fieldVal(block, src, options, "rw", rw_src);
  23275     const rw_val = try sema.resolveConstValue(block, rw_src, rw, "prefetch read/write must be comptime-known");
  23276 
  23277     const locality = try sema.fieldVal(block, src, options, "locality", locality_src);
  23278     const locality_val = try sema.resolveConstValue(block, locality_src, locality, "prefetch locality must be comptime-known");
  23279 
  23280     const cache = try sema.fieldVal(block, src, options, "cache", cache_src);
  23281     const cache_val = try sema.resolveConstValue(block, cache_src, cache, "prefetch cache must be comptime-known");
  23282 
  23283     return std.builtin.PrefetchOptions{
  23284         .rw = mod.toEnum(std.builtin.PrefetchOptions.Rw, rw_val),
  23285         .locality = @intCast(u2, locality_val.toUnsignedInt(mod)),
  23286         .cache = mod.toEnum(std.builtin.PrefetchOptions.Cache, cache_val),
  23287     };
  23288 }
  23289 
  23290 fn zirPrefetch(
  23291     sema: *Sema,
  23292     block: *Block,
  23293     extended: Zir.Inst.Extended.InstData,
  23294 ) CompileError!Air.Inst.Ref {
  23295     const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
  23296     const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  23297     const opts_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  23298     const ptr = try sema.resolveInst(extra.lhs);
  23299     try sema.checkPtrOperand(block, ptr_src, sema.typeOf(ptr));
  23300 
  23301     const options = sema.resolvePrefetchOptions(block, .unneeded, extra.rhs) catch |err| switch (err) {
  23302         error.NeededSourceLocation => {
  23303             _ = try sema.resolvePrefetchOptions(block, opts_src, extra.rhs);
  23304             unreachable;
  23305         },
  23306         else => |e| return e,
  23307     };
  23308 
  23309     if (!block.is_comptime) {
  23310         _ = try block.addInst(.{
  23311             .tag = .prefetch,
  23312             .data = .{ .prefetch = .{
  23313                 .ptr = ptr,
  23314                 .rw = options.rw,
  23315                 .locality = options.locality,
  23316                 .cache = options.cache,
  23317             } },
  23318         });
  23319     }
  23320 
  23321     return Air.Inst.Ref.void_value;
  23322 }
  23323 
  23324 fn resolveExternOptions(
  23325     sema: *Sema,
  23326     block: *Block,
  23327     src: LazySrcLoc,
  23328     zir_ref: Zir.Inst.Ref,
  23329 ) CompileError!std.builtin.ExternOptions {
  23330     const mod = sema.mod;
  23331     const options_inst = try sema.resolveInst(zir_ref);
  23332     const extern_options_ty = try sema.getBuiltinType("ExternOptions");
  23333     const options = try sema.coerce(block, extern_options_ty, options_inst, src);
  23334 
  23335     const name_src = sema.maybeOptionsSrc(block, src, "name");
  23336     const library_src = sema.maybeOptionsSrc(block, src, "library");
  23337     const linkage_src = sema.maybeOptionsSrc(block, src, "linkage");
  23338     const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local");
  23339 
  23340     const name_ref = try sema.fieldVal(block, src, options, "name", name_src);
  23341     const name_val = try sema.resolveConstValue(block, name_src, name_ref, "name of the extern symbol must be comptime-known");
  23342     const name = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod);
  23343 
  23344     const library_name_inst = try sema.fieldVal(block, src, options, "library_name", library_src);
  23345     const library_name_val = try sema.resolveConstValue(block, library_src, library_name_inst, "library in which extern symbol is must be comptime-known");
  23346 
  23347     const linkage_ref = try sema.fieldVal(block, src, options, "linkage", linkage_src);
  23348     const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_ref, "linkage of the extern symbol must be comptime-known");
  23349     const linkage = mod.toEnum(std.builtin.GlobalLinkage, linkage_val);
  23350 
  23351     const is_thread_local = try sema.fieldVal(block, src, options, "is_thread_local", thread_local_src);
  23352     const is_thread_local_val = try sema.resolveConstValue(block, thread_local_src, is_thread_local, "threadlocality of the extern symbol must be comptime-known");
  23353 
  23354     const library_name = if (library_name_val.optionalValue(mod)) |payload| blk: {
  23355         const library_name = try payload.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod);
  23356         if (library_name.len == 0) {
  23357             return sema.fail(block, library_src, "library name cannot be empty", .{});
  23358         }
  23359         break :blk try sema.handleExternLibName(block, library_src, library_name);
  23360     } else null;
  23361 
  23362     if (name.len == 0) {
  23363         return sema.fail(block, name_src, "extern symbol name cannot be empty", .{});
  23364     }
  23365 
  23366     if (linkage != .Weak and linkage != .Strong) {
  23367         return sema.fail(block, linkage_src, "extern symbol must use strong or weak linkage", .{});
  23368     }
  23369 
  23370     return std.builtin.ExternOptions{
  23371         .name = name,
  23372         .library_name = library_name,
  23373         .linkage = linkage,
  23374         .is_thread_local = is_thread_local_val.toBool(),
  23375     };
  23376 }
  23377 
  23378 fn zirBuiltinExtern(
  23379     sema: *Sema,
  23380     block: *Block,
  23381     extended: Zir.Inst.Extended.InstData,
  23382 ) CompileError!Air.Inst.Ref {
  23383     const mod = sema.mod;
  23384     const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
  23385     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  23386     const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
  23387 
  23388     var ty = try sema.resolveType(block, ty_src, extra.lhs);
  23389     if (!ty.isPtrAtRuntime(mod)) {
  23390         return sema.fail(block, ty_src, "expected (optional) pointer", .{});
  23391     }
  23392     if (!try sema.validateExternType(ty.childType(mod), .other)) {
  23393         const msg = msg: {
  23394             const msg = try sema.errMsg(block, ty_src, "extern symbol cannot have type '{}'", .{ty.fmt(mod)});
  23395             errdefer msg.destroy(sema.gpa);
  23396             const src_decl = sema.mod.declPtr(block.src_decl);
  23397             try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl, mod), ty, .other);
  23398             break :msg msg;
  23399         };
  23400         return sema.failWithOwnedErrorMsg(msg);
  23401     }
  23402 
  23403     const options = sema.resolveExternOptions(block, .unneeded, extra.rhs) catch |err| switch (err) {
  23404         error.NeededSourceLocation => {
  23405             _ = try sema.resolveExternOptions(block, options_src, extra.rhs);
  23406             unreachable;
  23407         },
  23408         else => |e| return e,
  23409     };
  23410 
  23411     if (options.linkage == .Weak and !ty.ptrAllowsZero(mod)) {
  23412         ty = try Type.optional(sema.arena, ty, mod);
  23413     }
  23414 
  23415     // TODO check duplicate extern
  23416 
  23417     const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, null);
  23418     errdefer mod.destroyDecl(new_decl_index);
  23419     const new_decl = mod.declPtr(new_decl_index);
  23420     new_decl.name = try sema.gpa.dupeZ(u8, options.name);
  23421 
  23422     {
  23423         const new_var = try mod.intern(.{ .variable = .{
  23424             .ty = ty.toIntern(),
  23425             .init = .none,
  23426             .decl = sema.owner_decl_index,
  23427             .is_extern = true,
  23428             .is_const = true,
  23429             .is_threadlocal = options.is_thread_local,
  23430             .is_weak_linkage = options.linkage == .Weak,
  23431         } });
  23432 
  23433         new_decl.src_line = sema.owner_decl.src_line;
  23434         // We only access this decl through the decl_ref with the correct type created
  23435         // below, so this type doesn't matter
  23436         new_decl.ty = ty;
  23437         new_decl.val = new_var.toValue();
  23438         new_decl.@"align" = 0;
  23439         new_decl.@"linksection" = null;
  23440         new_decl.has_tv = true;
  23441         new_decl.analysis = .complete;
  23442         new_decl.generation = mod.generation;
  23443     }
  23444 
  23445     try mod.declareDeclDependency(sema.owner_decl_index, new_decl_index);
  23446     try sema.ensureDeclAnalyzed(new_decl_index);
  23447 
  23448     return sema.addConstant(ty, try mod.getCoerced((try mod.intern(.{ .ptr = .{
  23449         .ty = switch (mod.intern_pool.indexToKey(ty.toIntern())) {
  23450             .ptr_type => ty.toIntern(),
  23451             .opt_type => |child_type| child_type,
  23452             else => unreachable,
  23453         },
  23454         .addr = .{ .decl = new_decl_index },
  23455     } })).toValue(), ty));
  23456 }
  23457 
  23458 fn zirWorkItem(
  23459     sema: *Sema,
  23460     block: *Block,
  23461     extended: Zir.Inst.Extended.InstData,
  23462     zir_tag: Zir.Inst.Extended,
  23463 ) CompileError!Air.Inst.Ref {
  23464     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
  23465     const dimension_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
  23466     const builtin_src = LazySrcLoc.nodeOffset(extra.node);
  23467     const target = sema.mod.getTarget();
  23468 
  23469     switch (target.cpu.arch) {
  23470         // TODO: Allow for other GPU targets.
  23471         .amdgcn => {},
  23472         else => {
  23473             return sema.fail(block, builtin_src, "builtin only available on GPU targets; targeted architecture is {s}", .{@tagName(target.cpu.arch)});
  23474         },
  23475     }
  23476 
  23477     const dimension = @intCast(u32, try sema.resolveInt(block, dimension_src, extra.operand, Type.u32, "dimension must be comptime-known"));
  23478     try sema.requireRuntimeBlock(block, builtin_src, null);
  23479 
  23480     return block.addInst(.{
  23481         .tag = switch (zir_tag) {
  23482             .work_item_id => .work_item_id,
  23483             .work_group_size => .work_group_size,
  23484             .work_group_id => .work_group_id,
  23485             else => unreachable,
  23486         },
  23487         .data = .{ .pl_op = .{
  23488             .operand = .none,
  23489             .payload = dimension,
  23490         } },
  23491     });
  23492 }
  23493 
  23494 fn zirInComptime(
  23495     sema: *Sema,
  23496     block: *Block,
  23497 ) CompileError!Air.Inst.Ref {
  23498     _ = sema;
  23499     if (block.is_comptime) {
  23500         return Air.Inst.Ref.bool_true;
  23501     } else {
  23502         return Air.Inst.Ref.bool_false;
  23503     }
  23504 }
  23505 
  23506 fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: ?LazySrcLoc) !void {
  23507     if (block.is_comptime) {
  23508         const msg = msg: {
  23509             const msg = try sema.errMsg(block, src, "unable to evaluate comptime expression", .{});
  23510             errdefer msg.destroy(sema.gpa);
  23511 
  23512             if (runtime_src) |some| {
  23513                 try sema.errNote(block, some, msg, "operation is runtime due to this operand", .{});
  23514             }
  23515             if (block.comptime_reason) |some| {
  23516                 try some.explain(sema, msg);
  23517             }
  23518             break :msg msg;
  23519         };
  23520         return sema.failWithOwnedErrorMsg(msg);
  23521     }
  23522 }
  23523 
  23524 /// Emit a compile error if type cannot be used for a runtime variable.
  23525 fn validateVarType(
  23526     sema: *Sema,
  23527     block: *Block,
  23528     src: LazySrcLoc,
  23529     var_ty: Type,
  23530     is_extern: bool,
  23531 ) CompileError!void {
  23532     const mod = sema.mod;
  23533     if (is_extern and !try sema.validateExternType(var_ty, .other)) {
  23534         const msg = msg: {
  23535             const msg = try sema.errMsg(block, src, "extern variable cannot have type '{}'", .{var_ty.fmt(mod)});
  23536             errdefer msg.destroy(sema.gpa);
  23537             const src_decl = mod.declPtr(block.src_decl);
  23538             try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), var_ty, .other);
  23539             break :msg msg;
  23540         };
  23541         return sema.failWithOwnedErrorMsg(msg);
  23542     }
  23543 
  23544     if (try sema.validateRunTimeType(var_ty, is_extern)) return;
  23545 
  23546     const msg = msg: {
  23547         const msg = try sema.errMsg(block, src, "variable of type '{}' must be const or comptime", .{var_ty.fmt(mod)});
  23548         errdefer msg.destroy(sema.gpa);
  23549 
  23550         const src_decl = mod.declPtr(block.src_decl);
  23551         try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), var_ty);
  23552         if (var_ty.zigTypeTag(mod) == .ComptimeInt or var_ty.zigTypeTag(mod) == .ComptimeFloat) {
  23553             try sema.errNote(block, src, msg, "to modify this variable at runtime, it must be given an explicit fixed-size number type", .{});
  23554         }
  23555 
  23556         break :msg msg;
  23557     };
  23558     return sema.failWithOwnedErrorMsg(msg);
  23559 }
  23560 
  23561 fn validateRunTimeType(
  23562     sema: *Sema,
  23563     var_ty: Type,
  23564     is_extern: bool,
  23565 ) CompileError!bool {
  23566     const mod = sema.mod;
  23567     var ty = var_ty;
  23568     while (true) switch (ty.zigTypeTag(mod)) {
  23569         .Bool,
  23570         .Int,
  23571         .Float,
  23572         .ErrorSet,
  23573         .Frame,
  23574         .AnyFrame,
  23575         .Void,
  23576         => return true,
  23577 
  23578         .Enum => return !(try sema.typeRequiresComptime(ty)),
  23579 
  23580         .ComptimeFloat,
  23581         .ComptimeInt,
  23582         .EnumLiteral,
  23583         .NoReturn,
  23584         .Type,
  23585         .Undefined,
  23586         .Null,
  23587         .Fn,
  23588         => return false,
  23589 
  23590         .Pointer => {
  23591             const elem_ty = ty.childType(mod);
  23592             switch (elem_ty.zigTypeTag(mod)) {
  23593                 .Opaque => return true,
  23594                 .Fn => return elem_ty.isFnOrHasRuntimeBits(mod),
  23595                 else => ty = elem_ty,
  23596             }
  23597         },
  23598         .Opaque => return is_extern,
  23599 
  23600         .Optional => {
  23601             const child_ty = ty.optionalChild(mod);
  23602             return sema.validateRunTimeType(child_ty, is_extern);
  23603         },
  23604         .Array, .Vector => ty = ty.childType(mod),
  23605 
  23606         .ErrorUnion => ty = ty.errorUnionPayload(mod),
  23607 
  23608         .Struct, .Union => {
  23609             const resolved_ty = try sema.resolveTypeFields(ty);
  23610             const needs_comptime = try sema.typeRequiresComptime(resolved_ty);
  23611             return !needs_comptime;
  23612         },
  23613     };
  23614 }
  23615 
  23616 const TypeSet = std.AutoHashMapUnmanaged(InternPool.Index, void);
  23617 
  23618 fn explainWhyTypeIsComptime(
  23619     sema: *Sema,
  23620     msg: *Module.ErrorMsg,
  23621     src_loc: Module.SrcLoc,
  23622     ty: Type,
  23623 ) CompileError!void {
  23624     var type_set = TypeSet{};
  23625     defer type_set.deinit(sema.gpa);
  23626 
  23627     try sema.resolveTypeFully(ty);
  23628     return sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty, &type_set);
  23629 }
  23630 
  23631 fn explainWhyTypeIsComptimeInner(
  23632     sema: *Sema,
  23633     msg: *Module.ErrorMsg,
  23634     src_loc: Module.SrcLoc,
  23635     ty: Type,
  23636     type_set: *TypeSet,
  23637 ) CompileError!void {
  23638     const mod = sema.mod;
  23639     switch (ty.zigTypeTag(mod)) {
  23640         .Bool,
  23641         .Int,
  23642         .Float,
  23643         .ErrorSet,
  23644         .Enum,
  23645         .Frame,
  23646         .AnyFrame,
  23647         .Void,
  23648         => return,
  23649 
  23650         .Fn => {
  23651             try mod.errNoteNonLazy(src_loc, msg, "use '*const {}' for a function pointer type", .{
  23652                 ty.fmt(sema.mod),
  23653             });
  23654         },
  23655 
  23656         .Type => {
  23657             try mod.errNoteNonLazy(src_loc, msg, "types are not available at runtime", .{});
  23658         },
  23659 
  23660         .ComptimeFloat,
  23661         .ComptimeInt,
  23662         .EnumLiteral,
  23663         .NoReturn,
  23664         .Undefined,
  23665         .Null,
  23666         => return,
  23667 
  23668         .Opaque => {
  23669             try mod.errNoteNonLazy(src_loc, msg, "opaque type '{}' has undefined size", .{ty.fmt(sema.mod)});
  23670         },
  23671 
  23672         .Array, .Vector => {
  23673             try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.childType(mod), type_set);
  23674         },
  23675         .Pointer => {
  23676             const elem_ty = ty.elemType2(mod);
  23677             if (elem_ty.zigTypeTag(mod) == .Fn) {
  23678                 const fn_info = mod.typeToFunc(elem_ty).?;
  23679                 if (fn_info.is_generic) {
  23680                     try mod.errNoteNonLazy(src_loc, msg, "function is generic", .{});
  23681                 }
  23682                 switch (fn_info.cc) {
  23683                     .Inline => try mod.errNoteNonLazy(src_loc, msg, "function has inline calling convention", .{}),
  23684                     else => {},
  23685                 }
  23686                 if (fn_info.return_type.toType().comptimeOnly(mod)) {
  23687                     try mod.errNoteNonLazy(src_loc, msg, "function has a comptime-only return type", .{});
  23688                 }
  23689                 return;
  23690             }
  23691             try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.childType(mod), type_set);
  23692         },
  23693 
  23694         .Optional => {
  23695             try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.optionalChild(mod), type_set);
  23696         },
  23697         .ErrorUnion => {
  23698             try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.errorUnionPayload(mod), type_set);
  23699         },
  23700 
  23701         .Struct => {
  23702             if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return;
  23703 
  23704             if (mod.typeToStruct(ty)) |struct_obj| {
  23705                 for (struct_obj.fields.values(), 0..) |field, i| {
  23706                     const field_src_loc = mod.fieldSrcLoc(struct_obj.owner_decl, .{
  23707                         .index = i,
  23708                         .range = .type,
  23709                     });
  23710 
  23711                     if (try sema.typeRequiresComptime(field.ty)) {
  23712                         try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{});
  23713                         try sema.explainWhyTypeIsComptimeInner(msg, field_src_loc, field.ty, type_set);
  23714                     }
  23715                 }
  23716             }
  23717             // TODO tuples
  23718         },
  23719 
  23720         .Union => {
  23721             if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return;
  23722 
  23723             if (mod.typeToUnion(ty)) |union_obj| {
  23724                 for (union_obj.fields.values(), 0..) |field, i| {
  23725                     const field_src_loc = mod.fieldSrcLoc(union_obj.owner_decl, .{
  23726                         .index = i,
  23727                         .range = .type,
  23728                     });
  23729 
  23730                     if (try sema.typeRequiresComptime(field.ty)) {
  23731                         try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{});
  23732                         try sema.explainWhyTypeIsComptimeInner(msg, field_src_loc, field.ty, type_set);
  23733                     }
  23734                 }
  23735             }
  23736         },
  23737     }
  23738 }
  23739 
  23740 const ExternPosition = enum {
  23741     ret_ty,
  23742     param_ty,
  23743     union_field,
  23744     struct_field,
  23745     element,
  23746     other,
  23747 };
  23748 
  23749 /// Returns true if `ty` is allowed in extern types.
  23750 /// Does *NOT* require `ty` to be resolved in any way.
  23751 /// Calls `resolveTypeLayout` for packed containers.
  23752 fn validateExternType(
  23753     sema: *Sema,
  23754     ty: Type,
  23755     position: ExternPosition,
  23756 ) !bool {
  23757     const mod = sema.mod;
  23758     switch (ty.zigTypeTag(mod)) {
  23759         .Type,
  23760         .ComptimeFloat,
  23761         .ComptimeInt,
  23762         .EnumLiteral,
  23763         .Undefined,
  23764         .Null,
  23765         .ErrorUnion,
  23766         .ErrorSet,
  23767         .Frame,
  23768         => return false,
  23769         .Void => return position == .union_field or position == .ret_ty,
  23770         .NoReturn => return position == .ret_ty,
  23771         .Opaque,
  23772         .Bool,
  23773         .Float,
  23774         .AnyFrame,
  23775         => return true,
  23776         .Pointer => return !(ty.isSlice(mod) or try sema.typeRequiresComptime(ty)),
  23777         .Int => switch (ty.intInfo(mod).bits) {
  23778             8, 16, 32, 64, 128 => return true,
  23779             else => return false,
  23780         },
  23781         .Fn => {
  23782             if (position != .other) return false;
  23783             const target = sema.mod.getTarget();
  23784             // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI.
  23785             // The goal is to experiment with more integrated CPU/GPU code.
  23786             if (ty.fnCallingConvention(mod) == .Kernel and (target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64)) {
  23787                 return true;
  23788             }
  23789             return !target_util.fnCallConvAllowsZigTypes(target, ty.fnCallingConvention(mod));
  23790         },
  23791         .Enum => {
  23792             return sema.validateExternType(ty.intTagType(mod), position);
  23793         },
  23794         .Struct, .Union => switch (ty.containerLayout(mod)) {
  23795             .Extern => return true,
  23796             .Packed => {
  23797                 const bit_size = try ty.bitSizeAdvanced(mod, sema);
  23798                 switch (bit_size) {
  23799                     8, 16, 32, 64, 128 => return true,
  23800                     else => return false,
  23801                 }
  23802             },
  23803             .Auto => return false,
  23804         },
  23805         .Array => {
  23806             if (position == .ret_ty or position == .param_ty) return false;
  23807             return sema.validateExternType(ty.elemType2(mod), .element);
  23808         },
  23809         .Vector => return sema.validateExternType(ty.elemType2(mod), .element),
  23810         .Optional => return ty.isPtrLikeOptional(mod),
  23811     }
  23812 }
  23813 
  23814 fn explainWhyTypeIsNotExtern(
  23815     sema: *Sema,
  23816     msg: *Module.ErrorMsg,
  23817     src_loc: Module.SrcLoc,
  23818     ty: Type,
  23819     position: ExternPosition,
  23820 ) CompileError!void {
  23821     const mod = sema.mod;
  23822     switch (ty.zigTypeTag(mod)) {
  23823         .Opaque,
  23824         .Bool,
  23825         .Float,
  23826         .AnyFrame,
  23827         => return,
  23828 
  23829         .Type,
  23830         .ComptimeFloat,
  23831         .ComptimeInt,
  23832         .EnumLiteral,
  23833         .Undefined,
  23834         .Null,
  23835         .ErrorUnion,
  23836         .ErrorSet,
  23837         .Frame,
  23838         => return,
  23839 
  23840         .Pointer => {
  23841             if (ty.isSlice(mod)) {
  23842                 try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{});
  23843             } else {
  23844                 const pointee_ty = ty.childType(mod);
  23845                 try mod.errNoteNonLazy(src_loc, msg, "pointer to comptime-only type '{}'", .{pointee_ty.fmt(sema.mod)});
  23846                 try sema.explainWhyTypeIsComptime(msg, src_loc, pointee_ty);
  23847             }
  23848         },
  23849         .Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}),
  23850         .NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
  23851         .Int => if (!std.math.isPowerOfTwo(ty.intInfo(mod).bits)) {
  23852             try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{});
  23853         } else {
  23854             try mod.errNoteNonLazy(src_loc, msg, "only integers with 8, 16, 32, 64 and 128 bits are extern compatible", .{});
  23855         },
  23856         .Fn => {
  23857             if (position != .other) {
  23858                 try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{});
  23859                 try mod.errNoteNonLazy(src_loc, msg, "use '*const ' to make a function pointer type", .{});
  23860                 return;
  23861             }
  23862             switch (ty.fnCallingConvention(mod)) {
  23863                 .Unspecified => try mod.errNoteNonLazy(src_loc, msg, "extern function must specify calling convention", .{}),
  23864                 .Async => try mod.errNoteNonLazy(src_loc, msg, "async function cannot be extern", .{}),
  23865                 .Inline => try mod.errNoteNonLazy(src_loc, msg, "inline function cannot be extern", .{}),
  23866                 else => return,
  23867             }
  23868         },
  23869         .Enum => {
  23870             const tag_ty = ty.intTagType(mod);
  23871             try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)});
  23872             try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position);
  23873         },
  23874         .Struct => try mod.errNoteNonLazy(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}),
  23875         .Union => try mod.errNoteNonLazy(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}),
  23876         .Array => {
  23877             if (position == .ret_ty) {
  23878                 return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a return type", .{});
  23879             } else if (position == .param_ty) {
  23880                 return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a parameter type", .{});
  23881             }
  23882             try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(mod), .element);
  23883         },
  23884         .Vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(mod), .element),
  23885         .Optional => try mod.errNoteNonLazy(src_loc, msg, "only pointer like optionals are extern compatible", .{}),
  23886     }
  23887 }
  23888 
  23889 /// Returns true if `ty` is allowed in packed types.
  23890 /// Does *NOT* require `ty` to be resolved in any way.
  23891 fn validatePackedType(ty: Type, mod: *Module) bool {
  23892     switch (ty.zigTypeTag(mod)) {
  23893         .Type,
  23894         .ComptimeFloat,
  23895         .ComptimeInt,
  23896         .EnumLiteral,
  23897         .Undefined,
  23898         .Null,
  23899         .ErrorUnion,
  23900         .ErrorSet,
  23901         .Frame,
  23902         .NoReturn,
  23903         .Opaque,
  23904         .AnyFrame,
  23905         .Fn,
  23906         .Array,
  23907         => return false,
  23908         .Optional => return ty.isPtrLikeOptional(mod),
  23909         .Void,
  23910         .Bool,
  23911         .Float,
  23912         .Int,
  23913         .Vector,
  23914         .Enum,
  23915         => return true,
  23916         .Pointer => return !ty.isSlice(mod),
  23917         .Struct, .Union => return ty.containerLayout(mod) == .Packed,
  23918     }
  23919 }
  23920 
  23921 fn explainWhyTypeIsNotPacked(
  23922     sema: *Sema,
  23923     msg: *Module.ErrorMsg,
  23924     src_loc: Module.SrcLoc,
  23925     ty: Type,
  23926 ) CompileError!void {
  23927     const mod = sema.mod;
  23928     switch (ty.zigTypeTag(mod)) {
  23929         .Void,
  23930         .Bool,
  23931         .Float,
  23932         .Int,
  23933         .Vector,
  23934         .Enum,
  23935         => return,
  23936         .Type,
  23937         .ComptimeFloat,
  23938         .ComptimeInt,
  23939         .EnumLiteral,
  23940         .Undefined,
  23941         .Null,
  23942         .Frame,
  23943         .NoReturn,
  23944         .Opaque,
  23945         .ErrorUnion,
  23946         .ErrorSet,
  23947         .AnyFrame,
  23948         .Optional,
  23949         .Array,
  23950         => try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{}),
  23951         .Pointer => try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{}),
  23952         .Fn => {
  23953             try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{});
  23954             try mod.errNoteNonLazy(src_loc, msg, "use '*const ' to make a function pointer type", .{});
  23955         },
  23956         .Struct => try mod.errNoteNonLazy(src_loc, msg, "only packed structs layout are allowed in packed types", .{}),
  23957         .Union => try mod.errNoteNonLazy(src_loc, msg, "only packed unions layout are allowed in packed types", .{}),
  23958     }
  23959 }
  23960 
  23961 pub const PanicId = enum {
  23962     unreach,
  23963     unwrap_null,
  23964     cast_to_null,
  23965     incorrect_alignment,
  23966     invalid_error_code,
  23967     cast_truncated_data,
  23968     negative_to_unsigned,
  23969     integer_overflow,
  23970     shl_overflow,
  23971     shr_overflow,
  23972     divide_by_zero,
  23973     exact_division_remainder,
  23974     inactive_union_field,
  23975     integer_part_out_of_bounds,
  23976     corrupt_switch,
  23977     shift_rhs_too_big,
  23978     invalid_enum_value,
  23979     sentinel_mismatch,
  23980     unwrap_error,
  23981     index_out_of_bounds,
  23982     start_index_greater_than_end,
  23983     for_len_mismatch,
  23984     memcpy_len_mismatch,
  23985     memcpy_alias,
  23986     noreturn_returned,
  23987 };
  23988 
  23989 fn addSafetyCheck(
  23990     sema: *Sema,
  23991     parent_block: *Block,
  23992     ok: Air.Inst.Ref,
  23993     panic_id: PanicId,
  23994 ) !void {
  23995     const gpa = sema.gpa;
  23996     assert(!parent_block.is_comptime);
  23997 
  23998     var fail_block: Block = .{
  23999         .parent = parent_block,
  24000         .sema = sema,
  24001         .src_decl = parent_block.src_decl,
  24002         .namespace = parent_block.namespace,
  24003         .wip_capture_scope = parent_block.wip_capture_scope,
  24004         .instructions = .{},
  24005         .inlining = parent_block.inlining,
  24006         .is_comptime = false,
  24007     };
  24008 
  24009     defer fail_block.instructions.deinit(gpa);
  24010 
  24011     try sema.safetyPanic(&fail_block, panic_id);
  24012     try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
  24013 }
  24014 
  24015 fn addSafetyCheckExtra(
  24016     sema: *Sema,
  24017     parent_block: *Block,
  24018     ok: Air.Inst.Ref,
  24019     fail_block: *Block,
  24020 ) !void {
  24021     const gpa = sema.gpa;
  24022 
  24023     try parent_block.instructions.ensureUnusedCapacity(gpa, 1);
  24024 
  24025     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
  24026         1 + // The main block only needs space for the cond_br.
  24027         @typeInfo(Air.CondBr).Struct.fields.len +
  24028         1 + // The ok branch of the cond_br only needs space for the br.
  24029         fail_block.instructions.items.len);
  24030 
  24031     try sema.air_instructions.ensureUnusedCapacity(gpa, 3);
  24032     const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
  24033     const cond_br_inst = block_inst + 1;
  24034     const br_inst = cond_br_inst + 1;
  24035     sema.air_instructions.appendAssumeCapacity(.{
  24036         .tag = .block,
  24037         .data = .{ .ty_pl = .{
  24038             .ty = .void_type,
  24039             .payload = sema.addExtraAssumeCapacity(Air.Block{
  24040                 .body_len = 1,
  24041             }),
  24042         } },
  24043     });
  24044     sema.air_extra.appendAssumeCapacity(cond_br_inst);
  24045 
  24046     sema.air_instructions.appendAssumeCapacity(.{
  24047         .tag = .cond_br,
  24048         .data = .{ .pl_op = .{
  24049             .operand = ok,
  24050             .payload = sema.addExtraAssumeCapacity(Air.CondBr{
  24051                 .then_body_len = 1,
  24052                 .else_body_len = @intCast(u32, fail_block.instructions.items.len),
  24053             }),
  24054         } },
  24055     });
  24056     sema.air_extra.appendAssumeCapacity(br_inst);
  24057     sema.air_extra.appendSliceAssumeCapacity(fail_block.instructions.items);
  24058 
  24059     sema.air_instructions.appendAssumeCapacity(.{
  24060         .tag = .br,
  24061         .data = .{ .br = .{
  24062             .block_inst = block_inst,
  24063             .operand = .void_value,
  24064         } },
  24065     });
  24066 
  24067     parent_block.instructions.appendAssumeCapacity(block_inst);
  24068 }
  24069 
  24070 fn panicWithMsg(
  24071     sema: *Sema,
  24072     block: *Block,
  24073     msg_inst: Air.Inst.Ref,
  24074 ) !void {
  24075     const mod = sema.mod;
  24076 
  24077     if (!mod.backendSupportsFeature(.panic_fn)) {
  24078         _ = try block.addNoOp(.trap);
  24079         return;
  24080     }
  24081     const panic_fn = try sema.getBuiltin("panic");
  24082     const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
  24083     const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
  24084     const target = mod.getTarget();
  24085     const ptr_stack_trace_ty = try mod.ptrType(.{
  24086         .child = stack_trace_ty.toIntern(),
  24087         .flags = .{
  24088             .address_space = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic
  24089         },
  24090     });
  24091     const opt_ptr_stack_trace_ty = try mod.optionalType(ptr_stack_trace_ty.toIntern());
  24092     const null_stack_trace = try sema.addConstant(opt_ptr_stack_trace_ty, (try mod.intern(.{ .opt = .{
  24093         .ty = opt_ptr_stack_trace_ty.toIntern(),
  24094         .val = .none,
  24095     } })).toValue());
  24096 
  24097     const opt_usize_ty = try mod.optionalType(.usize_type);
  24098     const null_ret_addr = try sema.addConstant(opt_usize_ty, (try mod.intern(.{ .opt = .{
  24099         .ty = opt_usize_ty.toIntern(),
  24100         .val = .none,
  24101     } })).toValue());
  24102     try sema.callBuiltin(block, panic_fn, .auto, &.{ msg_inst, null_stack_trace, null_ret_addr });
  24103 }
  24104 
  24105 fn panicUnwrapError(
  24106     sema: *Sema,
  24107     parent_block: *Block,
  24108     operand: Air.Inst.Ref,
  24109     unwrap_err_tag: Air.Inst.Tag,
  24110     is_non_err_tag: Air.Inst.Tag,
  24111 ) !void {
  24112     assert(!parent_block.is_comptime);
  24113     const ok = try parent_block.addUnOp(is_non_err_tag, operand);
  24114     if (!sema.mod.comp.formatted_panics) {
  24115         return sema.addSafetyCheck(parent_block, ok, .unwrap_error);
  24116     }
  24117     const gpa = sema.gpa;
  24118 
  24119     var fail_block: Block = .{
  24120         .parent = parent_block,
  24121         .sema = sema,
  24122         .src_decl = parent_block.src_decl,
  24123         .namespace = parent_block.namespace,
  24124         .wip_capture_scope = parent_block.wip_capture_scope,
  24125         .instructions = .{},
  24126         .inlining = parent_block.inlining,
  24127         .is_comptime = false,
  24128     };
  24129 
  24130     defer fail_block.instructions.deinit(gpa);
  24131 
  24132     {
  24133         if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) {
  24134             _ = try fail_block.addNoOp(.trap);
  24135         } else {
  24136             const panic_fn = try sema.getBuiltin("panicUnwrapError");
  24137             const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand);
  24138             const err_return_trace = try sema.getErrorReturnTrace(&fail_block);
  24139             const args: [2]Air.Inst.Ref = .{ err_return_trace, err };
  24140             try sema.callBuiltin(&fail_block, panic_fn, .auto, &args);
  24141         }
  24142     }
  24143     try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
  24144 }
  24145 
  24146 fn panicIndexOutOfBounds(
  24147     sema: *Sema,
  24148     parent_block: *Block,
  24149     index: Air.Inst.Ref,
  24150     len: Air.Inst.Ref,
  24151     cmp_op: Air.Inst.Tag,
  24152 ) !void {
  24153     assert(!parent_block.is_comptime);
  24154     const ok = try parent_block.addBinOp(cmp_op, index, len);
  24155     if (!sema.mod.comp.formatted_panics) {
  24156         return sema.addSafetyCheck(parent_block, ok, .index_out_of_bounds);
  24157     }
  24158     try sema.safetyCheckFormatted(parent_block, ok, "panicOutOfBounds", &.{ index, len });
  24159 }
  24160 
  24161 fn panicInactiveUnionField(
  24162     sema: *Sema,
  24163     parent_block: *Block,
  24164     active_tag: Air.Inst.Ref,
  24165     wanted_tag: Air.Inst.Ref,
  24166 ) !void {
  24167     assert(!parent_block.is_comptime);
  24168     const ok = try parent_block.addBinOp(.cmp_eq, active_tag, wanted_tag);
  24169     if (!sema.mod.comp.formatted_panics) {
  24170         return sema.addSafetyCheck(parent_block, ok, .inactive_union_field);
  24171     }
  24172     try sema.safetyCheckFormatted(parent_block, ok, "panicInactiveUnionField", &.{ active_tag, wanted_tag });
  24173 }
  24174 
  24175 fn panicSentinelMismatch(
  24176     sema: *Sema,
  24177     parent_block: *Block,
  24178     maybe_sentinel: ?Value,
  24179     sentinel_ty: Type,
  24180     ptr: Air.Inst.Ref,
  24181     sentinel_index: Air.Inst.Ref,
  24182 ) !void {
  24183     assert(!parent_block.is_comptime);
  24184     const mod = sema.mod;
  24185     const expected_sentinel_val = maybe_sentinel orelse return;
  24186     const expected_sentinel = try sema.addConstant(sentinel_ty, expected_sentinel_val);
  24187 
  24188     const ptr_ty = sema.typeOf(ptr);
  24189     const actual_sentinel = if (ptr_ty.isSlice(mod))
  24190         try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index)
  24191     else blk: {
  24192         const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null);
  24193         const sentinel_ptr = try parent_block.addPtrElemPtr(ptr, sentinel_index, elem_ptr_ty);
  24194         break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr);
  24195     };
  24196 
  24197     const ok = if (sentinel_ty.zigTypeTag(mod) == .Vector) ok: {
  24198         const eql =
  24199             try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq);
  24200         break :ok try parent_block.addInst(.{
  24201             .tag = .reduce,
  24202             .data = .{ .reduce = .{
  24203                 .operand = eql,
  24204                 .operation = .And,
  24205             } },
  24206         });
  24207     } else if (sentinel_ty.isSelfComparable(mod, true))
  24208         try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel)
  24209     else {
  24210         const panic_fn = try sema.getBuiltin("checkNonScalarSentinel");
  24211         const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel };
  24212         try sema.callBuiltin(parent_block, panic_fn, .auto, &args);
  24213         return;
  24214     };
  24215 
  24216     if (!sema.mod.comp.formatted_panics) {
  24217         return sema.addSafetyCheck(parent_block, ok, .sentinel_mismatch);
  24218     }
  24219     try sema.safetyCheckFormatted(parent_block, ok, "panicSentinelMismatch", &.{ expected_sentinel, actual_sentinel });
  24220 }
  24221 
  24222 fn safetyCheckFormatted(
  24223     sema: *Sema,
  24224     parent_block: *Block,
  24225     ok: Air.Inst.Ref,
  24226     func: []const u8,
  24227     args: []const Air.Inst.Ref,
  24228 ) CompileError!void {
  24229     assert(sema.mod.comp.formatted_panics);
  24230     const gpa = sema.gpa;
  24231 
  24232     var fail_block: Block = .{
  24233         .parent = parent_block,
  24234         .sema = sema,
  24235         .src_decl = parent_block.src_decl,
  24236         .namespace = parent_block.namespace,
  24237         .wip_capture_scope = parent_block.wip_capture_scope,
  24238         .instructions = .{},
  24239         .inlining = parent_block.inlining,
  24240         .is_comptime = false,
  24241     };
  24242 
  24243     defer fail_block.instructions.deinit(gpa);
  24244 
  24245     if (!sema.mod.backendSupportsFeature(.safety_check_formatted)) {
  24246         _ = try fail_block.addNoOp(.trap);
  24247     } else {
  24248         const panic_fn = try sema.getBuiltin(func);
  24249         try sema.callBuiltin(&fail_block, panic_fn, .auto, args);
  24250     }
  24251     try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
  24252 }
  24253 
  24254 fn safetyPanic(
  24255     sema: *Sema,
  24256     block: *Block,
  24257     panic_id: PanicId,
  24258 ) CompileError!void {
  24259     const mod = sema.mod;
  24260     const panic_messages_ty = try sema.getBuiltinType("panic_messages");
  24261     const msg_decl_index = (try sema.namespaceLookup(
  24262         block,
  24263         sema.src,
  24264         panic_messages_ty.getNamespaceIndex(mod).unwrap().?,
  24265         @tagName(panic_id),
  24266     )).?;
  24267 
  24268     const msg_inst = try sema.analyzeDeclVal(block, sema.src, msg_decl_index);
  24269     try sema.panicWithMsg(block, msg_inst);
  24270 }
  24271 
  24272 fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
  24273     sema.branch_count += 1;
  24274     if (sema.branch_count > sema.branch_quota) {
  24275         const msg = try sema.errMsg(
  24276             block,
  24277             src,
  24278             "evaluation exceeded {d} backwards branches",
  24279             .{sema.branch_quota},
  24280         );
  24281         try sema.errNote(
  24282             block,
  24283             src,
  24284             msg,
  24285             "use @setEvalBranchQuota() to raise the branch limit from {d}",
  24286             .{sema.branch_quota},
  24287         );
  24288         return sema.failWithOwnedErrorMsg(msg);
  24289     }
  24290 }
  24291 
  24292 fn fieldVal(
  24293     sema: *Sema,
  24294     block: *Block,
  24295     src: LazySrcLoc,
  24296     object: Air.Inst.Ref,
  24297     field_name: []const u8,
  24298     field_name_src: LazySrcLoc,
  24299 ) CompileError!Air.Inst.Ref {
  24300     // When editing this function, note that there is corresponding logic to be edited
  24301     // in `fieldPtr`. This function takes a value and returns a value.
  24302 
  24303     const mod = sema.mod;
  24304     const gpa = sema.gpa;
  24305     const ip = &mod.intern_pool;
  24306     const object_src = src; // TODO better source location
  24307     const object_ty = sema.typeOf(object);
  24308 
  24309     // Zig allows dereferencing a single pointer during field lookup. Note that
  24310     // we don't actually need to generate the dereference some field lookups, like the
  24311     // length of arrays and other comptime operations.
  24312     const is_pointer_to = object_ty.isSinglePointer(mod);
  24313 
  24314     const inner_ty = if (is_pointer_to)
  24315         object_ty.childType(mod)
  24316     else
  24317         object_ty;
  24318 
  24319     switch (inner_ty.zigTypeTag(mod)) {
  24320         .Array => {
  24321             if (mem.eql(u8, field_name, "len")) {
  24322                 return sema.addConstant(
  24323                     Type.usize,
  24324                     try mod.intValue(Type.usize, inner_ty.arrayLen(mod)),
  24325                 );
  24326             } else if (mem.eql(u8, field_name, "ptr") and is_pointer_to) {
  24327                 const ptr_info = object_ty.ptrInfo(mod);
  24328                 const result_ty = try Type.ptr(sema.arena, mod, .{
  24329                     .pointee_type = ptr_info.pointee_type.childType(mod),
  24330                     .sentinel = ptr_info.sentinel,
  24331                     .@"align" = ptr_info.@"align",
  24332                     .@"addrspace" = ptr_info.@"addrspace",
  24333                     .bit_offset = ptr_info.bit_offset,
  24334                     .host_size = ptr_info.host_size,
  24335                     .vector_index = ptr_info.vector_index,
  24336                     .@"allowzero" = ptr_info.@"allowzero",
  24337                     .mutable = ptr_info.mutable,
  24338                     .@"volatile" = ptr_info.@"volatile",
  24339                     .size = .Many,
  24340                 });
  24341                 return sema.coerce(block, result_ty, object, src);
  24342             } else {
  24343                 return sema.fail(
  24344                     block,
  24345                     field_name_src,
  24346                     "no member named '{s}' in '{}'",
  24347                     .{ field_name, object_ty.fmt(mod) },
  24348                 );
  24349             }
  24350         },
  24351         .Pointer => {
  24352             const ptr_info = inner_ty.ptrInfo(mod);
  24353             if (ptr_info.size == .Slice) {
  24354                 if (mem.eql(u8, field_name, "ptr")) {
  24355                     const slice = if (is_pointer_to)
  24356                         try sema.analyzeLoad(block, src, object, object_src)
  24357                     else
  24358                         object;
  24359                     return sema.analyzeSlicePtr(block, object_src, slice, inner_ty);
  24360                 } else if (mem.eql(u8, field_name, "len")) {
  24361                     const slice = if (is_pointer_to)
  24362                         try sema.analyzeLoad(block, src, object, object_src)
  24363                     else
  24364                         object;
  24365                     return sema.analyzeSliceLen(block, src, slice);
  24366                 } else {
  24367                     return sema.fail(
  24368                         block,
  24369                         field_name_src,
  24370                         "no member named '{s}' in '{}'",
  24371                         .{ field_name, object_ty.fmt(mod) },
  24372                     );
  24373                 }
  24374             }
  24375         },
  24376         .Type => {
  24377             const dereffed_type = if (is_pointer_to)
  24378                 try sema.analyzeLoad(block, src, object, object_src)
  24379             else
  24380                 object;
  24381 
  24382             const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?;
  24383             const child_type = val.toType();
  24384 
  24385             switch (try child_type.zigTypeTagOrPoison(mod)) {
  24386                 .ErrorSet => {
  24387                     const name = try ip.getOrPutString(gpa, field_name);
  24388                     switch (ip.indexToKey(child_type.toIntern())) {
  24389                         .error_set_type => |error_set_type| blk: {
  24390                             if (error_set_type.nameIndex(ip, name) != null) break :blk;
  24391                             const msg = msg: {
  24392                                 const msg = try sema.errMsg(block, src, "no error named '{s}' in '{}'", .{
  24393                                     field_name, child_type.fmt(mod),
  24394                                 });
  24395                                 errdefer msg.destroy(sema.gpa);
  24396                                 try sema.addDeclaredHereNote(msg, child_type);
  24397                                 break :msg msg;
  24398                             };
  24399                             return sema.failWithOwnedErrorMsg(msg);
  24400                         },
  24401                         .inferred_error_set_type => {
  24402                             return sema.fail(block, src, "TODO handle inferred error sets here", .{});
  24403                         },
  24404                         .simple_type => |t| {
  24405                             assert(t == .anyerror);
  24406                             _ = try mod.getErrorValue(field_name);
  24407                         },
  24408                         else => unreachable,
  24409                     }
  24410 
  24411                     const error_set_type = if (!child_type.isAnyError(mod))
  24412                         child_type
  24413                     else
  24414                         try mod.singleErrorSetTypeNts(name);
  24415                     return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{
  24416                         .ty = error_set_type.toIntern(),
  24417                         .name = name,
  24418                     } })).toValue());
  24419                 },
  24420                 .Union => {
  24421                     if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| {
  24422                         if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| {
  24423                             return inst;
  24424                         }
  24425                     }
  24426                     const union_ty = try sema.resolveTypeFields(child_type);
  24427                     if (union_ty.unionTagType(mod)) |enum_ty| {
  24428                         if (enum_ty.enumFieldIndex(field_name, mod)) |field_index_usize| {
  24429                             const field_index = @intCast(u32, field_index_usize);
  24430                             return sema.addConstant(
  24431                                 enum_ty,
  24432                                 try mod.enumValueFieldIndex(enum_ty, field_index),
  24433                             );
  24434                         }
  24435                     }
  24436                     return sema.failWithBadMemberAccess(block, union_ty, field_name_src, field_name);
  24437                 },
  24438                 .Enum => {
  24439                     if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| {
  24440                         if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| {
  24441                             return inst;
  24442                         }
  24443                     }
  24444                     const field_index_usize = child_type.enumFieldIndex(field_name, mod) orelse
  24445                         return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
  24446                     const field_index = @intCast(u32, field_index_usize);
  24447                     const enum_val = try mod.enumValueFieldIndex(child_type, field_index);
  24448                     return sema.addConstant(child_type, enum_val);
  24449                 },
  24450                 .Struct, .Opaque => {
  24451                     if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| {
  24452                         if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| {
  24453                             return inst;
  24454                         }
  24455                     }
  24456                     return sema.failWithBadMemberAccess(block, child_type, src, field_name);
  24457                 },
  24458                 else => {
  24459                     const msg = msg: {
  24460                         const msg = try sema.errMsg(block, src, "type '{}' has no members", .{child_type.fmt(mod)});
  24461                         errdefer msg.destroy(sema.gpa);
  24462                         if (child_type.isSlice(mod)) try sema.errNote(block, src, msg, "slice values have 'len' and 'ptr' members", .{});
  24463                         if (child_type.zigTypeTag(mod) == .Array) try sema.errNote(block, src, msg, "array values have 'len' member", .{});
  24464                         break :msg msg;
  24465                     };
  24466                     return sema.failWithOwnedErrorMsg(msg);
  24467                 },
  24468             }
  24469         },
  24470         .Struct => if (is_pointer_to) {
  24471             // Avoid loading the entire struct by fetching a pointer and loading that
  24472             const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false);
  24473             return sema.analyzeLoad(block, src, field_ptr, object_src);
  24474         } else {
  24475             return sema.structFieldVal(block, src, object, field_name, field_name_src, inner_ty);
  24476         },
  24477         .Union => if (is_pointer_to) {
  24478             // Avoid loading the entire union by fetching a pointer and loading that
  24479             const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false);
  24480             return sema.analyzeLoad(block, src, field_ptr, object_src);
  24481         } else {
  24482             return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty);
  24483         },
  24484         else => {},
  24485     }
  24486     return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name);
  24487 }
  24488 
  24489 fn fieldPtr(
  24490     sema: *Sema,
  24491     block: *Block,
  24492     src: LazySrcLoc,
  24493     object_ptr: Air.Inst.Ref,
  24494     field_name: []const u8,
  24495     field_name_src: LazySrcLoc,
  24496     initializing: bool,
  24497 ) CompileError!Air.Inst.Ref {
  24498     // When editing this function, note that there is corresponding logic to be edited
  24499     // in `fieldVal`. This function takes a pointer and returns a pointer.
  24500 
  24501     const mod = sema.mod;
  24502     const gpa = sema.gpa;
  24503     const ip = &mod.intern_pool;
  24504     const object_ptr_src = src; // TODO better source location
  24505     const object_ptr_ty = sema.typeOf(object_ptr);
  24506     const object_ty = switch (object_ptr_ty.zigTypeTag(mod)) {
  24507         .Pointer => object_ptr_ty.childType(mod),
  24508         else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty.fmt(mod)}),
  24509     };
  24510 
  24511     // Zig allows dereferencing a single pointer during field lookup. Note that
  24512     // we don't actually need to generate the dereference some field lookups, like the
  24513     // length of arrays and other comptime operations.
  24514     const is_pointer_to = object_ty.isSinglePointer(mod);
  24515 
  24516     const inner_ty = if (is_pointer_to)
  24517         object_ty.childType(mod)
  24518     else
  24519         object_ty;
  24520 
  24521     switch (inner_ty.zigTypeTag(mod)) {
  24522         .Array => {
  24523             if (mem.eql(u8, field_name, "len")) {
  24524                 var anon_decl = try block.startAnonDecl();
  24525                 defer anon_decl.deinit();
  24526                 return sema.analyzeDeclRef(try anon_decl.finish(
  24527                     Type.usize,
  24528                     try mod.intValue(Type.usize, inner_ty.arrayLen(mod)),
  24529                     0, // default alignment
  24530                 ));
  24531             } else {
  24532                 return sema.fail(
  24533                     block,
  24534                     field_name_src,
  24535                     "no member named '{s}' in '{}'",
  24536                     .{ field_name, object_ty.fmt(mod) },
  24537                 );
  24538             }
  24539         },
  24540         .Pointer => if (inner_ty.isSlice(mod)) {
  24541             const inner_ptr = if (is_pointer_to)
  24542                 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
  24543             else
  24544                 object_ptr;
  24545 
  24546             const attr_ptr_ty = if (is_pointer_to) object_ty else object_ptr_ty;
  24547 
  24548             if (mem.eql(u8, field_name, "ptr")) {
  24549                 const slice_ptr_ty = inner_ty.slicePtrFieldType(mod);
  24550 
  24551                 const result_ty = try Type.ptr(sema.arena, mod, .{
  24552                     .pointee_type = slice_ptr_ty,
  24553                     .mutable = attr_ptr_ty.ptrIsMutable(mod),
  24554                     .@"volatile" = attr_ptr_ty.isVolatilePtr(mod),
  24555                     .@"addrspace" = attr_ptr_ty.ptrAddressSpace(mod),
  24556                 });
  24557 
  24558                 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
  24559                     return sema.addConstant(result_ty, (try mod.intern(.{ .ptr = .{
  24560                         .ty = result_ty.toIntern(),
  24561                         .addr = .{ .field = .{
  24562                             .base = val.toIntern(),
  24563                             .index = Value.slice_ptr_index,
  24564                         } },
  24565                     } })).toValue());
  24566                 }
  24567                 try sema.requireRuntimeBlock(block, src, null);
  24568 
  24569                 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
  24570             } else if (mem.eql(u8, field_name, "len")) {
  24571                 const result_ty = try Type.ptr(sema.arena, mod, .{
  24572                     .pointee_type = Type.usize,
  24573                     .mutable = attr_ptr_ty.ptrIsMutable(mod),
  24574                     .@"volatile" = attr_ptr_ty.isVolatilePtr(mod),
  24575                     .@"addrspace" = attr_ptr_ty.ptrAddressSpace(mod),
  24576                 });
  24577 
  24578                 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
  24579                     return sema.addConstant(result_ty, (try mod.intern(.{ .ptr = .{
  24580                         .ty = result_ty.toIntern(),
  24581                         .addr = .{ .field = .{
  24582                             .base = val.toIntern(),
  24583                             .index = Value.slice_len_index,
  24584                         } },
  24585                     } })).toValue());
  24586                 }
  24587                 try sema.requireRuntimeBlock(block, src, null);
  24588 
  24589                 return block.addTyOp(.ptr_slice_len_ptr, result_ty, inner_ptr);
  24590             } else {
  24591                 return sema.fail(
  24592                     block,
  24593                     field_name_src,
  24594                     "no member named '{s}' in '{}'",
  24595                     .{ field_name, object_ty.fmt(mod) },
  24596                 );
  24597             }
  24598         },
  24599         .Type => {
  24600             _ = try sema.resolveConstValue(block, .unneeded, object_ptr, "");
  24601             const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src);
  24602             const inner = if (is_pointer_to)
  24603                 try sema.analyzeLoad(block, src, result, object_ptr_src)
  24604             else
  24605                 result;
  24606 
  24607             const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?;
  24608             const child_type = val.toType();
  24609 
  24610             switch (child_type.zigTypeTag(mod)) {
  24611                 .ErrorSet => {
  24612                     const name = try ip.getOrPutString(gpa, field_name);
  24613                     switch (ip.indexToKey(child_type.toIntern())) {
  24614                         .error_set_type => |error_set_type| blk: {
  24615                             if (error_set_type.nameIndex(ip, name) != null) {
  24616                                 break :blk;
  24617                             }
  24618                             return sema.fail(block, src, "no error named '{s}' in '{}'", .{
  24619                                 field_name, child_type.fmt(mod),
  24620                             });
  24621                         },
  24622                         .inferred_error_set_type => {
  24623                             return sema.fail(block, src, "TODO handle inferred error sets here", .{});
  24624                         },
  24625                         .simple_type => |t| {
  24626                             assert(t == .anyerror);
  24627                             _ = try mod.getErrorValue(field_name);
  24628                         },
  24629                         else => unreachable,
  24630                     }
  24631 
  24632                     var anon_decl = try block.startAnonDecl();
  24633                     defer anon_decl.deinit();
  24634                     const error_set_type = if (!child_type.isAnyError(mod))
  24635                         child_type
  24636                     else
  24637                         try mod.singleErrorSetTypeNts(name);
  24638                     return sema.analyzeDeclRef(try anon_decl.finish(
  24639                         error_set_type,
  24640                         (try mod.intern(.{ .err = .{
  24641                             .ty = error_set_type.toIntern(),
  24642                             .name = name,
  24643                         } })).toValue(),
  24644                         0, // default alignment
  24645                     ));
  24646                 },
  24647                 .Union => {
  24648                     if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| {
  24649                         if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
  24650                             return inst;
  24651                         }
  24652                     }
  24653                     const union_ty = try sema.resolveTypeFields(child_type);
  24654                     if (union_ty.unionTagType(mod)) |enum_ty| {
  24655                         if (enum_ty.enumFieldIndex(field_name, mod)) |field_index| {
  24656                             const field_index_u32 = @intCast(u32, field_index);
  24657                             var anon_decl = try block.startAnonDecl();
  24658                             defer anon_decl.deinit();
  24659                             return sema.analyzeDeclRef(try anon_decl.finish(
  24660                                 enum_ty,
  24661                                 try mod.enumValueFieldIndex(enum_ty, field_index_u32),
  24662                                 0, // default alignment
  24663                             ));
  24664                         }
  24665                     }
  24666                     return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
  24667                 },
  24668                 .Enum => {
  24669                     if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| {
  24670                         if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
  24671                             return inst;
  24672                         }
  24673                     }
  24674                     const field_index = child_type.enumFieldIndex(field_name, mod) orelse {
  24675                         return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
  24676                     };
  24677                     const field_index_u32 = @intCast(u32, field_index);
  24678                     var anon_decl = try block.startAnonDecl();
  24679                     defer anon_decl.deinit();
  24680                     return sema.analyzeDeclRef(try anon_decl.finish(
  24681                         child_type,
  24682                         try mod.enumValueFieldIndex(child_type, field_index_u32),
  24683                         0, // default alignment
  24684                     ));
  24685                 },
  24686                 .Struct, .Opaque => {
  24687                     if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| {
  24688                         if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
  24689                             return inst;
  24690                         }
  24691                     }
  24692                     return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
  24693                 },
  24694                 else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(mod)}),
  24695             }
  24696         },
  24697         .Struct => {
  24698             const inner_ptr = if (is_pointer_to)
  24699                 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
  24700             else
  24701                 object_ptr;
  24702             return sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);
  24703         },
  24704         .Union => {
  24705             const inner_ptr = if (is_pointer_to)
  24706                 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
  24707             else
  24708                 object_ptr;
  24709             return sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);
  24710         },
  24711         else => {},
  24712     }
  24713     return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name);
  24714 }
  24715 
  24716 const ResolvedFieldCallee = union(enum) {
  24717     /// The LHS of the call was an actual field with this value.
  24718     direct: Air.Inst.Ref,
  24719     /// This is a method call, with the function and first argument given.
  24720     method: struct {
  24721         func_inst: Air.Inst.Ref,
  24722         arg0_inst: Air.Inst.Ref,
  24723     },
  24724 };
  24725 
  24726 fn fieldCallBind(
  24727     sema: *Sema,
  24728     block: *Block,
  24729     src: LazySrcLoc,
  24730     raw_ptr: Air.Inst.Ref,
  24731     field_name: []const u8,
  24732     field_name_src: LazySrcLoc,
  24733 ) CompileError!ResolvedFieldCallee {
  24734     // When editing this function, note that there is corresponding logic to be edited
  24735     // in `fieldVal`. This function takes a pointer and returns a pointer.
  24736 
  24737     const mod = sema.mod;
  24738     const raw_ptr_src = src; // TODO better source location
  24739     const raw_ptr_ty = sema.typeOf(raw_ptr);
  24740     const inner_ty = if (raw_ptr_ty.zigTypeTag(mod) == .Pointer and (raw_ptr_ty.ptrSize(mod) == .One or raw_ptr_ty.ptrSize(mod) == .C))
  24741         raw_ptr_ty.childType(mod)
  24742     else
  24743         return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(mod)});
  24744 
  24745     // Optionally dereference a second pointer to get the concrete type.
  24746     const is_double_ptr = inner_ty.zigTypeTag(mod) == .Pointer and inner_ty.ptrSize(mod) == .One;
  24747     const concrete_ty = if (is_double_ptr) inner_ty.childType(mod) else inner_ty;
  24748     const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty;
  24749     const object_ptr = if (is_double_ptr)
  24750         try sema.analyzeLoad(block, src, raw_ptr, src)
  24751     else
  24752         raw_ptr;
  24753 
  24754     find_field: {
  24755         switch (concrete_ty.zigTypeTag(mod)) {
  24756             .Struct => {
  24757                 const struct_ty = try sema.resolveTypeFields(concrete_ty);
  24758                 if (mod.typeToStruct(struct_ty)) |struct_obj| {
  24759                     const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
  24760                         break :find_field;
  24761                     const field_index = @intCast(u32, field_index_usize);
  24762                     const field = struct_obj.fields.values()[field_index];
  24763 
  24764                     return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr);
  24765                 } else if (struct_ty.isTuple(mod)) {
  24766                     if (mem.eql(u8, field_name, "len")) {
  24767                         return .{ .direct = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount(mod)) };
  24768                     }
  24769                     if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {
  24770                         if (field_index >= struct_ty.structFieldCount(mod)) break :find_field;
  24771                         return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(field_index, mod), field_index, object_ptr);
  24772                     } else |_| {}
  24773                 } else {
  24774                     const max = struct_ty.structFieldCount(mod);
  24775                     var i: u32 = 0;
  24776                     while (i < max) : (i += 1) {
  24777                         if (mem.eql(u8, struct_ty.structFieldName(i, mod), field_name)) {
  24778                             return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(i, mod), i, object_ptr);
  24779                         }
  24780                     }
  24781                 }
  24782             },
  24783             .Union => {
  24784                 const union_ty = try sema.resolveTypeFields(concrete_ty);
  24785                 const fields = union_ty.unionFields(mod);
  24786                 const field_index_usize = fields.getIndex(field_name) orelse break :find_field;
  24787                 const field_index = @intCast(u32, field_index_usize);
  24788                 const field = fields.values()[field_index];
  24789 
  24790                 return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr);
  24791             },
  24792             .Type => {
  24793                 const namespace = try sema.analyzeLoad(block, src, object_ptr, src);
  24794                 return .{ .direct = try sema.fieldVal(block, src, namespace, field_name, field_name_src) };
  24795             },
  24796             else => {},
  24797         }
  24798     }
  24799 
  24800     // If we get here, we need to look for a decl in the struct type instead.
  24801     const found_decl = switch (concrete_ty.zigTypeTag(mod)) {
  24802         .Struct, .Opaque, .Union, .Enum => found_decl: {
  24803             if (concrete_ty.getNamespaceIndex(mod).unwrap()) |namespace| {
  24804                 if (try sema.namespaceLookup(block, src, namespace, field_name)) |decl_idx| {
  24805                     try sema.addReferencedBy(block, src, decl_idx);
  24806                     const decl_val = try sema.analyzeDeclVal(block, src, decl_idx);
  24807                     const decl_type = sema.typeOf(decl_val);
  24808                     if (mod.typeToFunc(decl_type)) |func_type| f: {
  24809                         if (func_type.param_types.len == 0) break :f;
  24810 
  24811                         const first_param_type = func_type.param_types[0].toType();
  24812                         // zig fmt: off
  24813                         if (first_param_type.isGenericPoison() or (
  24814                                 first_param_type.zigTypeTag(mod) == .Pointer and
  24815                                 (first_param_type.ptrSize(mod) == .One or
  24816                                 first_param_type.ptrSize(mod) == .C) and
  24817                                 first_param_type.childType(mod).eql(concrete_ty, mod)))
  24818                         {
  24819                         // zig fmt: on
  24820                             // Note that if the param type is generic poison, we know that it must
  24821                             // specifically be `anytype` since it's the first parameter, meaning we
  24822                             // can safely assume it can be a pointer.
  24823                             // TODO: bound fn calls on rvalues should probably
  24824                             // generate a by-value argument somehow.
  24825                             return .{ .method = .{
  24826                                 .func_inst = decl_val,
  24827                                 .arg0_inst = object_ptr,
  24828                             } };
  24829                         } else if (first_param_type.eql(concrete_ty, mod)) {
  24830                             const deref = try sema.analyzeLoad(block, src, object_ptr, src);
  24831                             return .{ .method = .{
  24832                                 .func_inst = decl_val,
  24833                                 .arg0_inst = deref,
  24834                             } };
  24835                         } else if (first_param_type.zigTypeTag(mod) == .Optional) {
  24836                             const child = first_param_type.optionalChild(mod);
  24837                             if (child.eql(concrete_ty, mod)) {
  24838                                 const deref = try sema.analyzeLoad(block, src, object_ptr, src);
  24839                                 return .{ .method = .{
  24840                                     .func_inst = decl_val,
  24841                                     .arg0_inst = deref,
  24842                                 } };
  24843                             } else if (child.zigTypeTag(mod) == .Pointer and
  24844                                 child.ptrSize(mod) == .One and
  24845                                 child.childType(mod).eql(concrete_ty, mod))
  24846                             {
  24847                                 return .{ .method = .{
  24848                                     .func_inst = decl_val,
  24849                                     .arg0_inst = object_ptr,
  24850                                 } };
  24851                             }
  24852                         } else if (first_param_type.zigTypeTag(mod) == .ErrorUnion and
  24853                             first_param_type.errorUnionPayload(mod).eql(concrete_ty, mod))
  24854                         {
  24855                             const deref = try sema.analyzeLoad(block, src, object_ptr, src);
  24856                             return .{ .method = .{
  24857                                 .func_inst = decl_val,
  24858                                 .arg0_inst = deref,
  24859                             } };
  24860                         }
  24861                     }
  24862                     break :found_decl decl_idx;
  24863                 }
  24864             }
  24865             break :found_decl null;
  24866         },
  24867         else => null,
  24868     };
  24869 
  24870     const msg = msg: {
  24871         const msg = try sema.errMsg(block, src, "no field or member function named '{s}' in '{}'", .{ field_name, concrete_ty.fmt(mod) });
  24872         errdefer msg.destroy(sema.gpa);
  24873         try sema.addDeclaredHereNote(msg, concrete_ty);
  24874         if (found_decl) |decl_idx| {
  24875             const decl = mod.declPtr(decl_idx);
  24876             try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "'{s}' is not a member function", .{field_name});
  24877         }
  24878         break :msg msg;
  24879     };
  24880     return sema.failWithOwnedErrorMsg(msg);
  24881 }
  24882 
  24883 fn finishFieldCallBind(
  24884     sema: *Sema,
  24885     block: *Block,
  24886     src: LazySrcLoc,
  24887     ptr_ty: Type,
  24888     field_ty: Type,
  24889     field_index: u32,
  24890     object_ptr: Air.Inst.Ref,
  24891 ) CompileError!ResolvedFieldCallee {
  24892     const mod = sema.mod;
  24893     const arena = sema.arena;
  24894     const ptr_field_ty = try Type.ptr(arena, mod, .{
  24895         .pointee_type = field_ty,
  24896         .mutable = ptr_ty.ptrIsMutable(mod),
  24897         .@"addrspace" = ptr_ty.ptrAddressSpace(mod),
  24898     });
  24899 
  24900     const container_ty = ptr_ty.childType(mod);
  24901     if (container_ty.zigTypeTag(mod) == .Struct) {
  24902         if (try container_ty.structFieldValueComptime(mod, field_index)) |default_val| {
  24903             return .{ .direct = try sema.addConstant(field_ty, default_val) };
  24904         }
  24905     }
  24906 
  24907     if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| {
  24908         const pointer = try sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{
  24909             .ty = ptr_field_ty.toIntern(),
  24910             .addr = .{ .field = .{
  24911                 .base = struct_ptr_val.toIntern(),
  24912                 .index = field_index,
  24913             } },
  24914         } })).toValue());
  24915         return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) };
  24916     }
  24917 
  24918     try sema.requireRuntimeBlock(block, src, null);
  24919     const ptr_inst = try block.addStructFieldPtr(object_ptr, field_index, ptr_field_ty);
  24920     return .{ .direct = try sema.analyzeLoad(block, src, ptr_inst, src) };
  24921 }
  24922 
  24923 fn namespaceLookup(
  24924     sema: *Sema,
  24925     block: *Block,
  24926     src: LazySrcLoc,
  24927     namespace: Namespace.Index,
  24928     decl_name: []const u8,
  24929 ) CompileError!?Decl.Index {
  24930     const mod = sema.mod;
  24931     const gpa = sema.gpa;
  24932     if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| {
  24933         const decl = mod.declPtr(decl_index);
  24934         if (!decl.is_pub and decl.getFileScope(mod) != block.getFileScope(mod)) {
  24935             const msg = msg: {
  24936                 const msg = try sema.errMsg(block, src, "'{s}' is not marked 'pub'", .{
  24937                     decl_name,
  24938                 });
  24939                 errdefer msg.destroy(gpa);
  24940                 try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "declared here", .{});
  24941                 break :msg msg;
  24942             };
  24943             return sema.failWithOwnedErrorMsg(msg);
  24944         }
  24945         return decl_index;
  24946     }
  24947     return null;
  24948 }
  24949 
  24950 fn namespaceLookupRef(
  24951     sema: *Sema,
  24952     block: *Block,
  24953     src: LazySrcLoc,
  24954     namespace: Namespace.Index,
  24955     decl_name: []const u8,
  24956 ) CompileError!?Air.Inst.Ref {
  24957     const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;
  24958     try sema.addReferencedBy(block, src, decl);
  24959     return try sema.analyzeDeclRef(decl);
  24960 }
  24961 
  24962 fn namespaceLookupVal(
  24963     sema: *Sema,
  24964     block: *Block,
  24965     src: LazySrcLoc,
  24966     namespace: Namespace.Index,
  24967     decl_name: []const u8,
  24968 ) CompileError!?Air.Inst.Ref {
  24969     const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;
  24970     return try sema.analyzeDeclVal(block, src, decl);
  24971 }
  24972 
  24973 fn structFieldPtr(
  24974     sema: *Sema,
  24975     block: *Block,
  24976     src: LazySrcLoc,
  24977     struct_ptr: Air.Inst.Ref,
  24978     field_name: []const u8,
  24979     field_name_src: LazySrcLoc,
  24980     unresolved_struct_ty: Type,
  24981     initializing: bool,
  24982 ) CompileError!Air.Inst.Ref {
  24983     const mod = sema.mod;
  24984     assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct);
  24985 
  24986     const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty);
  24987     try sema.resolveStructLayout(struct_ty);
  24988 
  24989     if (struct_ty.isTuple(mod)) {
  24990         if (mem.eql(u8, field_name, "len")) {
  24991             const len_inst = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount(mod));
  24992             return sema.analyzeRef(block, src, len_inst);
  24993         }
  24994         const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src);
  24995         return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing);
  24996     } else if (struct_ty.isAnonStruct(mod)) {
  24997         const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src);
  24998         return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing);
  24999     }
  25000 
  25001     const struct_obj = mod.typeToStruct(struct_ty).?;
  25002 
  25003     const field_index_big = struct_obj.fields.getIndex(field_name) orelse
  25004         return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
  25005     const field_index = @intCast(u32, field_index_big);
  25006 
  25007     return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, field_name_src, struct_ty, initializing);
  25008 }
  25009 
  25010 fn structFieldPtrByIndex(
  25011     sema: *Sema,
  25012     block: *Block,
  25013     src: LazySrcLoc,
  25014     struct_ptr: Air.Inst.Ref,
  25015     field_index: u32,
  25016     field_src: LazySrcLoc,
  25017     struct_ty: Type,
  25018     initializing: bool,
  25019 ) CompileError!Air.Inst.Ref {
  25020     const mod = sema.mod;
  25021     if (struct_ty.isAnonStruct(mod)) {
  25022         return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing);
  25023     }
  25024 
  25025     const struct_obj = mod.typeToStruct(struct_ty).?;
  25026     const field = struct_obj.fields.values()[field_index];
  25027     const struct_ptr_ty = sema.typeOf(struct_ptr);
  25028     const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod);
  25029 
  25030     var ptr_ty_data: Type.Payload.Pointer.Data = .{
  25031         .pointee_type = field.ty,
  25032         .mutable = struct_ptr_ty_info.mutable,
  25033         .@"volatile" = struct_ptr_ty_info.@"volatile",
  25034         .@"addrspace" = struct_ptr_ty_info.@"addrspace",
  25035     };
  25036 
  25037     const target = mod.getTarget();
  25038 
  25039     if (struct_obj.layout == .Packed) {
  25040         comptime assert(Type.packed_struct_layout_version == 2);
  25041 
  25042         var running_bits: u16 = 0;
  25043         for (struct_obj.fields.values(), 0..) |f, i| {
  25044             if (!(try sema.typeHasRuntimeBits(f.ty))) continue;
  25045 
  25046             if (i == field_index) {
  25047                 ptr_ty_data.bit_offset = running_bits;
  25048             }
  25049             running_bits += @intCast(u16, f.ty.bitSize(mod));
  25050         }
  25051         ptr_ty_data.host_size = (running_bits + 7) / 8;
  25052 
  25053         // If this is a packed struct embedded in another one, we need to offset
  25054         // the bits against each other.
  25055         if (struct_ptr_ty_info.host_size != 0) {
  25056             ptr_ty_data.host_size = struct_ptr_ty_info.host_size;
  25057             ptr_ty_data.bit_offset += struct_ptr_ty_info.bit_offset;
  25058         }
  25059 
  25060         const parent_align = if (struct_ptr_ty_info.@"align" != 0)
  25061             struct_ptr_ty_info.@"align"
  25062         else
  25063             struct_ptr_ty_info.pointee_type.abiAlignment(mod);
  25064         ptr_ty_data.@"align" = parent_align;
  25065 
  25066         // If the field happens to be byte-aligned, simplify the pointer type.
  25067         // The pointee type bit size must match its ABI byte size so that loads and stores
  25068         // do not interfere with the surrounding packed bits.
  25069         // We do not attempt this with big-endian targets yet because of nested
  25070         // structs and floats. I need to double-check the desired behavior for big endian
  25071         // targets before adding the necessary complications to this code. This will not
  25072         // cause miscompilations; it only means the field pointer uses bit masking when it
  25073         // might not be strictly necessary.
  25074         if (parent_align != 0 and ptr_ty_data.bit_offset % 8 == 0 and
  25075             target.cpu.arch.endian() == .Little)
  25076         {
  25077             const elem_size_bytes = ptr_ty_data.pointee_type.abiSize(mod);
  25078             const elem_size_bits = ptr_ty_data.pointee_type.bitSize(mod);
  25079             if (elem_size_bytes * 8 == elem_size_bits) {
  25080                 const byte_offset = ptr_ty_data.bit_offset / 8;
  25081                 const new_align = @as(u32, 1) << @intCast(u5, @ctz(byte_offset | parent_align));
  25082                 ptr_ty_data.bit_offset = 0;
  25083                 ptr_ty_data.host_size = 0;
  25084                 ptr_ty_data.@"align" = new_align;
  25085             }
  25086         }
  25087     } else {
  25088         ptr_ty_data.@"align" = field.abi_align;
  25089     }
  25090 
  25091     const ptr_field_ty = try Type.ptr(sema.arena, mod, ptr_ty_data);
  25092 
  25093     if (field.is_comptime) {
  25094         const val = try mod.intern(.{ .ptr = .{
  25095             .ty = ptr_field_ty.toIntern(),
  25096             .addr = .{ .comptime_field = try field.default_val.intern(field.ty, mod) },
  25097         } });
  25098         return sema.addConstant(ptr_field_ty, val.toValue());
  25099     }
  25100 
  25101     if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
  25102         const val = try mod.intern(.{ .ptr = .{
  25103             .ty = ptr_field_ty.toIntern(),
  25104             .addr = .{ .field = .{
  25105                 .base = try struct_ptr_val.intern(struct_ptr_ty, mod),
  25106                 .index = field_index,
  25107             } },
  25108         } });
  25109         return sema.addConstant(ptr_field_ty, val.toValue());
  25110     }
  25111 
  25112     try sema.requireRuntimeBlock(block, src, null);
  25113     return block.addStructFieldPtr(struct_ptr, field_index, ptr_field_ty);
  25114 }
  25115 
  25116 fn structFieldVal(
  25117     sema: *Sema,
  25118     block: *Block,
  25119     src: LazySrcLoc,
  25120     struct_byval: Air.Inst.Ref,
  25121     field_name: []const u8,
  25122     field_name_src: LazySrcLoc,
  25123     unresolved_struct_ty: Type,
  25124 ) CompileError!Air.Inst.Ref {
  25125     const mod = sema.mod;
  25126     assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct);
  25127 
  25128     const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty);
  25129     switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) {
  25130         .struct_type => |struct_type| {
  25131             const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
  25132             if (struct_obj.is_tuple) return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty);
  25133 
  25134             const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
  25135                 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
  25136             const field_index = @intCast(u32, field_index_usize);
  25137             const field = struct_obj.fields.values()[field_index];
  25138 
  25139             if (field.is_comptime) {
  25140                 return sema.addConstant(field.ty, field.default_val);
  25141             }
  25142 
  25143             if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| {
  25144                 if (struct_val.isUndef(mod)) return sema.addConstUndef(field.ty);
  25145                 if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| {
  25146                     return sema.addConstant(field.ty, opv);
  25147                 }
  25148                 return sema.addConstant(field.ty, try struct_val.fieldValue(mod, field_index));
  25149             }
  25150 
  25151             try sema.requireRuntimeBlock(block, src, null);
  25152             return block.addStructFieldVal(struct_byval, field_index, field.ty);
  25153         },
  25154         .anon_struct_type => |anon_struct| {
  25155             if (anon_struct.names.len == 0) {
  25156                 return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty);
  25157             } else {
  25158                 const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src);
  25159                 return sema.tupleFieldValByIndex(block, src, struct_byval, field_index, struct_ty);
  25160             }
  25161         },
  25162         else => unreachable,
  25163     }
  25164 }
  25165 
  25166 fn tupleFieldVal(
  25167     sema: *Sema,
  25168     block: *Block,
  25169     src: LazySrcLoc,
  25170     tuple_byval: Air.Inst.Ref,
  25171     field_name: []const u8,
  25172     field_name_src: LazySrcLoc,
  25173     tuple_ty: Type,
  25174 ) CompileError!Air.Inst.Ref {
  25175     const mod = sema.mod;
  25176     if (mem.eql(u8, field_name, "len")) {
  25177         return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount(mod));
  25178     }
  25179     const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_name_src);
  25180     return sema.tupleFieldValByIndex(block, src, tuple_byval, field_index, tuple_ty);
  25181 }
  25182 
  25183 /// Asserts that `field_name` is not "len".
  25184 fn tupleFieldIndex(
  25185     sema: *Sema,
  25186     block: *Block,
  25187     tuple_ty: Type,
  25188     field_name: []const u8,
  25189     field_name_src: LazySrcLoc,
  25190 ) CompileError!u32 {
  25191     const mod = sema.mod;
  25192     assert(!mem.eql(u8, field_name, "len"));
  25193     if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {
  25194         if (field_index < tuple_ty.structFieldCount(mod)) return field_index;
  25195         return sema.fail(block, field_name_src, "index '{s}' out of bounds of tuple '{}'", .{
  25196             field_name, tuple_ty.fmt(mod),
  25197         });
  25198     } else |_| {}
  25199 
  25200     return sema.fail(block, field_name_src, "no field named '{s}' in tuple '{}'", .{
  25201         field_name, tuple_ty.fmt(mod),
  25202     });
  25203 }
  25204 
  25205 fn tupleFieldValByIndex(
  25206     sema: *Sema,
  25207     block: *Block,
  25208     src: LazySrcLoc,
  25209     tuple_byval: Air.Inst.Ref,
  25210     field_index: u32,
  25211     tuple_ty: Type,
  25212 ) CompileError!Air.Inst.Ref {
  25213     const mod = sema.mod;
  25214     const field_ty = tuple_ty.structFieldType(field_index, mod);
  25215 
  25216     if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_value| {
  25217         return sema.addConstant(field_ty, default_value);
  25218     }
  25219 
  25220     if (try sema.resolveMaybeUndefVal(tuple_byval)) |tuple_val| {
  25221         if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| {
  25222             return sema.addConstant(field_ty, opv);
  25223         }
  25224         return switch (mod.intern_pool.indexToKey(tuple_val.toIntern())) {
  25225             .undef => sema.addConstUndef(field_ty),
  25226             .aggregate => |aggregate| sema.addConstant(field_ty, switch (aggregate.storage) {
  25227                 .bytes => |bytes| try mod.intValue(Type.u8, bytes[0]),
  25228                 .elems => |elems| elems[field_index].toValue(),
  25229                 .repeated_elem => |elem| elem.toValue(),
  25230             }),
  25231             else => unreachable,
  25232         };
  25233     }
  25234 
  25235     if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| {
  25236         return sema.addConstant(field_ty, default_val);
  25237     }
  25238 
  25239     try sema.requireRuntimeBlock(block, src, null);
  25240     return block.addStructFieldVal(tuple_byval, field_index, field_ty);
  25241 }
  25242 
  25243 fn unionFieldPtr(
  25244     sema: *Sema,
  25245     block: *Block,
  25246     src: LazySrcLoc,
  25247     union_ptr: Air.Inst.Ref,
  25248     field_name: []const u8,
  25249     field_name_src: LazySrcLoc,
  25250     unresolved_union_ty: Type,
  25251     initializing: bool,
  25252 ) CompileError!Air.Inst.Ref {
  25253     const arena = sema.arena;
  25254     const mod = sema.mod;
  25255 
  25256     assert(unresolved_union_ty.zigTypeTag(mod) == .Union);
  25257 
  25258     const union_ptr_ty = sema.typeOf(union_ptr);
  25259     const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
  25260     const union_obj = mod.typeToUnion(union_ty).?;
  25261     const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
  25262     const field = union_obj.fields.values()[field_index];
  25263     const ptr_field_ty = try Type.ptr(arena, mod, .{
  25264         .pointee_type = field.ty,
  25265         .mutable = union_ptr_ty.ptrIsMutable(mod),
  25266         .@"volatile" = union_ptr_ty.isVolatilePtr(mod),
  25267         .@"addrspace" = union_ptr_ty.ptrAddressSpace(mod),
  25268     });
  25269     const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name, mod).?);
  25270 
  25271     if (initializing and field.ty.zigTypeTag(mod) == .NoReturn) {
  25272         const msg = msg: {
  25273             const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{});
  25274             errdefer msg.destroy(sema.gpa);
  25275 
  25276             try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name});
  25277             try sema.addDeclaredHereNote(msg, union_ty);
  25278             break :msg msg;
  25279         };
  25280         return sema.failWithOwnedErrorMsg(msg);
  25281     }
  25282 
  25283     if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {
  25284         switch (union_obj.layout) {
  25285             .Auto => if (!initializing) {
  25286                 const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse
  25287                     break :ct;
  25288                 if (union_val.isUndef(mod)) {
  25289                     return sema.failWithUseOfUndef(block, src);
  25290                 }
  25291                 const un = mod.intern_pool.indexToKey(union_val.toIntern()).un;
  25292                 const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index);
  25293                 const tag_matches = un.tag == field_tag.toIntern();
  25294                 if (!tag_matches) {
  25295                     const msg = msg: {
  25296                         const active_index = union_obj.tag_ty.enumTagFieldIndex(un.tag.toValue(), mod).?;
  25297                         const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod);
  25298                         const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
  25299                         errdefer msg.destroy(sema.gpa);
  25300                         try sema.addDeclaredHereNote(msg, union_ty);
  25301                         break :msg msg;
  25302                     };
  25303                     return sema.failWithOwnedErrorMsg(msg);
  25304                 }
  25305             },
  25306             .Packed, .Extern => {},
  25307         }
  25308         return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{
  25309             .ty = ptr_field_ty.toIntern(),
  25310             .addr = .{ .field = .{
  25311                 .base = union_ptr_val.toIntern(),
  25312                 .index = field_index,
  25313             } },
  25314         } })).toValue());
  25315     }
  25316 
  25317     try sema.requireRuntimeBlock(block, src, null);
  25318     if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
  25319         union_ty.unionTagTypeSafety(mod) != null and union_obj.fields.count() > 1)
  25320     {
  25321         const wanted_tag_val = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index);
  25322         const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
  25323         // TODO would it be better if get_union_tag supported pointers to unions?
  25324         const union_val = try block.addTyOp(.load, union_ty, union_ptr);
  25325         const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val);
  25326         try sema.panicInactiveUnionField(block, active_tag, wanted_tag);
  25327     }
  25328     if (field.ty.zigTypeTag(mod) == .NoReturn) {
  25329         _ = try block.addNoOp(.unreach);
  25330         return Air.Inst.Ref.unreachable_value;
  25331     }
  25332     return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);
  25333 }
  25334 
  25335 fn unionFieldVal(
  25336     sema: *Sema,
  25337     block: *Block,
  25338     src: LazySrcLoc,
  25339     union_byval: Air.Inst.Ref,
  25340     field_name: []const u8,
  25341     field_name_src: LazySrcLoc,
  25342     unresolved_union_ty: Type,
  25343 ) CompileError!Air.Inst.Ref {
  25344     const mod = sema.mod;
  25345     assert(unresolved_union_ty.zigTypeTag(mod) == .Union);
  25346 
  25347     const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
  25348     const union_obj = mod.typeToUnion(union_ty).?;
  25349     const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
  25350     const field = union_obj.fields.values()[field_index];
  25351     const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name, mod).?);
  25352 
  25353     if (try sema.resolveMaybeUndefVal(union_byval)) |union_val| {
  25354         if (union_val.isUndef(mod)) return sema.addConstUndef(field.ty);
  25355 
  25356         const un = mod.intern_pool.indexToKey(union_val.toIntern()).un;
  25357         const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index);
  25358         const tag_matches = un.tag == field_tag.toIntern();
  25359         switch (union_obj.layout) {
  25360             .Auto => {
  25361                 if (tag_matches) {
  25362                     return sema.addConstant(field.ty, un.val.toValue());
  25363                 } else {
  25364                     const msg = msg: {
  25365                         const active_index = union_obj.tag_ty.enumTagFieldIndex(un.tag.toValue(), mod).?;
  25366                         const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod);
  25367                         const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
  25368                         errdefer msg.destroy(sema.gpa);
  25369                         try sema.addDeclaredHereNote(msg, union_ty);
  25370                         break :msg msg;
  25371                     };
  25372                     return sema.failWithOwnedErrorMsg(msg);
  25373                 }
  25374             },
  25375             .Packed, .Extern => {
  25376                 if (tag_matches) {
  25377                     return sema.addConstant(field.ty, un.val.toValue());
  25378                 } else {
  25379                     const old_ty = union_ty.unionFieldType(un.tag.toValue(), mod);
  25380                     if (try sema.bitCastVal(block, src, un.val.toValue(), old_ty, field.ty, 0)) |new_val| {
  25381                         return sema.addConstant(field.ty, new_val);
  25382                     }
  25383                 }
  25384             },
  25385         }
  25386     }
  25387 
  25388     try sema.requireRuntimeBlock(block, src, null);
  25389     if (union_obj.layout == .Auto and block.wantSafety() and
  25390         union_ty.unionTagTypeSafety(mod) != null and union_obj.fields.count() > 1)
  25391     {
  25392         const wanted_tag_val = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index);
  25393         const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
  25394         const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval);
  25395         try sema.panicInactiveUnionField(block, active_tag, wanted_tag);
  25396     }
  25397     if (field.ty.zigTypeTag(mod) == .NoReturn) {
  25398         _ = try block.addNoOp(.unreach);
  25399         return Air.Inst.Ref.unreachable_value;
  25400     }
  25401     return block.addStructFieldVal(union_byval, field_index, field.ty);
  25402 }
  25403 
  25404 fn elemPtr(
  25405     sema: *Sema,
  25406     block: *Block,
  25407     src: LazySrcLoc,
  25408     indexable_ptr: Air.Inst.Ref,
  25409     elem_index: Air.Inst.Ref,
  25410     elem_index_src: LazySrcLoc,
  25411     init: bool,
  25412     oob_safety: bool,
  25413 ) CompileError!Air.Inst.Ref {
  25414     const mod = sema.mod;
  25415     const indexable_ptr_src = src; // TODO better source location
  25416     const indexable_ptr_ty = sema.typeOf(indexable_ptr);
  25417 
  25418     const indexable_ty = switch (indexable_ptr_ty.zigTypeTag(mod)) {
  25419         .Pointer => indexable_ptr_ty.childType(mod),
  25420         else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(mod)}),
  25421     };
  25422     try checkIndexable(sema, block, src, indexable_ty);
  25423 
  25424     switch (indexable_ty.zigTypeTag(mod)) {
  25425         .Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety),
  25426         .Struct => {
  25427             // Tuple field access.
  25428             const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known");
  25429             const index = @intCast(u32, index_val.toUnsignedInt(mod));
  25430             return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init);
  25431         },
  25432         else => {
  25433             const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src);
  25434             return elemPtrOneLayerOnly(sema, block, src, indexable, elem_index, elem_index_src, init, oob_safety);
  25435         },
  25436     }
  25437 }
  25438 
  25439 /// Asserts that the type of indexable is pointer.
  25440 fn elemPtrOneLayerOnly(
  25441     sema: *Sema,
  25442     block: *Block,
  25443     src: LazySrcLoc,
  25444     indexable: Air.Inst.Ref,
  25445     elem_index: Air.Inst.Ref,
  25446     elem_index_src: LazySrcLoc,
  25447     init: bool,
  25448     oob_safety: bool,
  25449 ) CompileError!Air.Inst.Ref {
  25450     const indexable_src = src; // TODO better source location
  25451     const indexable_ty = sema.typeOf(indexable);
  25452     const mod = sema.mod;
  25453 
  25454     try checkIndexable(sema, block, src, indexable_ty);
  25455 
  25456     switch (indexable_ty.ptrSize(mod)) {
  25457         .Slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
  25458         .Many, .C => {
  25459             const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable);
  25460             const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
  25461             const runtime_src = rs: {
  25462                 const ptr_val = maybe_ptr_val orelse break :rs indexable_src;
  25463                 const index_val = maybe_index_val orelse break :rs elem_index_src;
  25464                 const index = @intCast(usize, index_val.toUnsignedInt(mod));
  25465                 const result_ty = try sema.elemPtrType(indexable_ty, index);
  25466                 const elem_ptr = try ptr_val.elemPtr(result_ty, index, mod);
  25467                 return sema.addConstant(result_ty, elem_ptr);
  25468             };
  25469             const result_ty = try sema.elemPtrType(indexable_ty, null);
  25470 
  25471             try sema.requireRuntimeBlock(block, src, runtime_src);
  25472             return block.addPtrElemPtr(indexable, elem_index, result_ty);
  25473         },
  25474         .One => {
  25475             assert(indexable_ty.childType(mod).zigTypeTag(mod) == .Array); // Guaranteed by checkIndexable
  25476             return sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety);
  25477         },
  25478     }
  25479 }
  25480 
  25481 fn elemVal(
  25482     sema: *Sema,
  25483     block: *Block,
  25484     src: LazySrcLoc,
  25485     indexable: Air.Inst.Ref,
  25486     elem_index_uncasted: Air.Inst.Ref,
  25487     elem_index_src: LazySrcLoc,
  25488     oob_safety: bool,
  25489 ) CompileError!Air.Inst.Ref {
  25490     const indexable_src = src; // TODO better source location
  25491     const indexable_ty = sema.typeOf(indexable);
  25492     const mod = sema.mod;
  25493 
  25494     try checkIndexable(sema, block, src, indexable_ty);
  25495 
  25496     // TODO in case of a vector of pointers, we need to detect whether the element
  25497     // index is a scalar or vector instead of unconditionally casting to usize.
  25498     const elem_index = try sema.coerce(block, Type.usize, elem_index_uncasted, elem_index_src);
  25499 
  25500     switch (indexable_ty.zigTypeTag(mod)) {
  25501         .Pointer => switch (indexable_ty.ptrSize(mod)) {
  25502             .Slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
  25503             .Many, .C => {
  25504                 const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable);
  25505                 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
  25506 
  25507                 const runtime_src = rs: {
  25508                     const indexable_val = maybe_indexable_val orelse break :rs indexable_src;
  25509                     const index_val = maybe_index_val orelse break :rs elem_index_src;
  25510                     const index = @intCast(usize, index_val.toUnsignedInt(mod));
  25511                     const elem_ty = indexable_ty.elemType2(mod);
  25512                     const many_ptr_ty = try mod.manyConstPtrType(elem_ty);
  25513                     const many_ptr_val = try mod.getCoerced(indexable_val, many_ptr_ty);
  25514                     const elem_ptr_ty = try mod.singleConstPtrType(elem_ty);
  25515                     const elem_ptr_val = try many_ptr_val.elemPtr(elem_ptr_ty, index, mod);
  25516                     if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {
  25517                         return sema.addConstant(elem_ty, try mod.getCoerced(elem_val, elem_ty));
  25518                     }
  25519                     break :rs indexable_src;
  25520                 };
  25521 
  25522                 try sema.requireRuntimeBlock(block, src, runtime_src);
  25523                 return block.addBinOp(.ptr_elem_val, indexable, elem_index);
  25524             },
  25525             .One => {
  25526                 const array_ty = indexable_ty.childType(mod); // Guaranteed by checkIndexable
  25527                 assert(array_ty.zigTypeTag(mod) == .Array);
  25528 
  25529                 if (array_ty.sentinel(mod)) |sentinel| {
  25530                     // index must be defined since it can access out of bounds
  25531                     if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| {
  25532                         const index = @intCast(usize, index_val.toUnsignedInt(mod));
  25533                         if (index == array_ty.arrayLen(mod)) {
  25534                             return sema.addConstant(array_ty.childType(mod), sentinel);
  25535                         }
  25536                     }
  25537                 }
  25538 
  25539                 const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety);
  25540                 return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src);
  25541             },
  25542         },
  25543         .Array => return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
  25544         .Vector => {
  25545             // TODO: If the index is a vector, the result should be a vector.
  25546             return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety);
  25547         },
  25548         .Struct => {
  25549             // Tuple field access.
  25550             const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known");
  25551             const index = @intCast(u32, index_val.toUnsignedInt(mod));
  25552             return sema.tupleField(block, indexable_src, indexable, elem_index_src, index);
  25553         },
  25554         else => unreachable,
  25555     }
  25556 }
  25557 
  25558 fn validateRuntimeElemAccess(
  25559     sema: *Sema,
  25560     block: *Block,
  25561     elem_index_src: LazySrcLoc,
  25562     elem_ty: Type,
  25563     parent_ty: Type,
  25564     parent_src: LazySrcLoc,
  25565 ) CompileError!void {
  25566     const mod = sema.mod;
  25567     const valid_rt = try sema.validateRunTimeType(elem_ty, false);
  25568     if (!valid_rt) {
  25569         const msg = msg: {
  25570             const msg = try sema.errMsg(
  25571                 block,
  25572                 elem_index_src,
  25573                 "values of type '{}' must be comptime-known, but index value is runtime-known",
  25574                 .{parent_ty.fmt(mod)},
  25575             );
  25576             errdefer msg.destroy(sema.gpa);
  25577 
  25578             const src_decl = mod.declPtr(block.src_decl);
  25579             try sema.explainWhyTypeIsComptime(msg, parent_src.toSrcLoc(src_decl, mod), parent_ty);
  25580 
  25581             break :msg msg;
  25582         };
  25583         return sema.failWithOwnedErrorMsg(msg);
  25584     }
  25585 }
  25586 
  25587 fn tupleFieldPtr(
  25588     sema: *Sema,
  25589     block: *Block,
  25590     tuple_ptr_src: LazySrcLoc,
  25591     tuple_ptr: Air.Inst.Ref,
  25592     field_index_src: LazySrcLoc,
  25593     field_index: u32,
  25594     init: bool,
  25595 ) CompileError!Air.Inst.Ref {
  25596     const mod = sema.mod;
  25597     const tuple_ptr_ty = sema.typeOf(tuple_ptr);
  25598     const tuple_ty = tuple_ptr_ty.childType(mod);
  25599     _ = try sema.resolveTypeFields(tuple_ty);
  25600     const field_count = tuple_ty.structFieldCount(mod);
  25601 
  25602     if (field_count == 0) {
  25603         return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{});
  25604     }
  25605 
  25606     if (field_index >= field_count) {
  25607         return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{
  25608             field_index, field_count,
  25609         });
  25610     }
  25611 
  25612     const field_ty = tuple_ty.structFieldType(field_index, mod);
  25613     const ptr_field_ty = try Type.ptr(sema.arena, mod, .{
  25614         .pointee_type = field_ty,
  25615         .mutable = tuple_ptr_ty.ptrIsMutable(mod),
  25616         .@"volatile" = tuple_ptr_ty.isVolatilePtr(mod),
  25617         .@"addrspace" = tuple_ptr_ty.ptrAddressSpace(mod),
  25618     });
  25619 
  25620     if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| {
  25621         return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{
  25622             .ty = ptr_field_ty.toIntern(),
  25623             .addr = .{ .comptime_field = default_val.toIntern() },
  25624         } })).toValue());
  25625     }
  25626 
  25627     if (try sema.resolveMaybeUndefVal(tuple_ptr)) |tuple_ptr_val| {
  25628         return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{
  25629             .ty = ptr_field_ty.toIntern(),
  25630             .addr = .{ .field = .{
  25631                 .base = tuple_ptr_val.toIntern(),
  25632                 .index = field_index,
  25633             } },
  25634         } })).toValue());
  25635     }
  25636 
  25637     if (!init) {
  25638         try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_ptr_src);
  25639     }
  25640 
  25641     try sema.requireRuntimeBlock(block, tuple_ptr_src, null);
  25642     return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty);
  25643 }
  25644 
  25645 fn tupleField(
  25646     sema: *Sema,
  25647     block: *Block,
  25648     tuple_src: LazySrcLoc,
  25649     tuple: Air.Inst.Ref,
  25650     field_index_src: LazySrcLoc,
  25651     field_index: u32,
  25652 ) CompileError!Air.Inst.Ref {
  25653     const mod = sema.mod;
  25654     const tuple_ty = try sema.resolveTypeFields(sema.typeOf(tuple));
  25655     const field_count = tuple_ty.structFieldCount(mod);
  25656 
  25657     if (field_count == 0) {
  25658         return sema.fail(block, tuple_src, "indexing into empty tuple is not allowed", .{});
  25659     }
  25660 
  25661     if (field_index >= field_count) {
  25662         return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{
  25663             field_index, field_count,
  25664         });
  25665     }
  25666 
  25667     const field_ty = tuple_ty.structFieldType(field_index, mod);
  25668 
  25669     if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_value| {
  25670         return sema.addConstant(field_ty, default_value); // comptime field
  25671     }
  25672 
  25673     if (try sema.resolveMaybeUndefVal(tuple)) |tuple_val| {
  25674         if (tuple_val.isUndef(mod)) return sema.addConstUndef(field_ty);
  25675         return sema.addConstant(field_ty, try tuple_val.fieldValue(mod, field_index));
  25676     }
  25677 
  25678     try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
  25679 
  25680     try sema.requireRuntimeBlock(block, tuple_src, null);
  25681     return block.addStructFieldVal(tuple, field_index, field_ty);
  25682 }
  25683 
  25684 fn elemValArray(
  25685     sema: *Sema,
  25686     block: *Block,
  25687     src: LazySrcLoc,
  25688     array_src: LazySrcLoc,
  25689     array: Air.Inst.Ref,
  25690     elem_index_src: LazySrcLoc,
  25691     elem_index: Air.Inst.Ref,
  25692     oob_safety: bool,
  25693 ) CompileError!Air.Inst.Ref {
  25694     const mod = sema.mod;
  25695     const array_ty = sema.typeOf(array);
  25696     const array_sent = array_ty.sentinel(mod);
  25697     const array_len = array_ty.arrayLen(mod);
  25698     const array_len_s = array_len + @boolToInt(array_sent != null);
  25699     const elem_ty = array_ty.childType(mod);
  25700 
  25701     if (array_len_s == 0) {
  25702         return sema.fail(block, array_src, "indexing into empty array is not allowed", .{});
  25703     }
  25704 
  25705     const maybe_undef_array_val = try sema.resolveMaybeUndefVal(array);
  25706     // index must be defined since it can access out of bounds
  25707     const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
  25708 
  25709     if (maybe_index_val) |index_val| {
  25710         const index = @intCast(usize, index_val.toUnsignedInt(mod));
  25711         if (array_sent) |s| {
  25712             if (index == array_len) {
  25713                 return sema.addConstant(elem_ty, s);
  25714             }
  25715         }
  25716         if (index >= array_len_s) {
  25717             const sentinel_label: []const u8 = if (array_sent != null) " +1 (sentinel)" else "";
  25718             return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label });
  25719         }
  25720     }
  25721     if (maybe_undef_array_val) |array_val| {
  25722         if (array_val.isUndef(mod)) {
  25723             return sema.addConstUndef(elem_ty);
  25724         }
  25725         if (maybe_index_val) |index_val| {
  25726             const index = @intCast(usize, index_val.toUnsignedInt(mod));
  25727             const elem_val = try array_val.elemValue(mod, index);
  25728             return sema.addConstant(elem_ty, elem_val);
  25729         }
  25730     }
  25731 
  25732     try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src);
  25733 
  25734     const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src;
  25735     try sema.requireRuntimeBlock(block, src, runtime_src);
  25736     if (oob_safety and block.wantSafety()) {
  25737         // Runtime check is only needed if unable to comptime check
  25738         if (maybe_index_val == null) {
  25739             const len_inst = try sema.addIntUnsigned(Type.usize, array_len);
  25740             const cmp_op: Air.Inst.Tag = if (array_sent != null) .cmp_lte else .cmp_lt;
  25741             try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op);
  25742         }
  25743     }
  25744     return block.addBinOp(.array_elem_val, array, elem_index);
  25745 }
  25746 
  25747 fn elemPtrArray(
  25748     sema: *Sema,
  25749     block: *Block,
  25750     src: LazySrcLoc,
  25751     array_ptr_src: LazySrcLoc,
  25752     array_ptr: Air.Inst.Ref,
  25753     elem_index_src: LazySrcLoc,
  25754     elem_index: Air.Inst.Ref,
  25755     init: bool,
  25756     oob_safety: bool,
  25757 ) CompileError!Air.Inst.Ref {
  25758     const mod = sema.mod;
  25759     const array_ptr_ty = sema.typeOf(array_ptr);
  25760     const array_ty = array_ptr_ty.childType(mod);
  25761     const array_sent = array_ty.sentinel(mod) != null;
  25762     const array_len = array_ty.arrayLen(mod);
  25763     const array_len_s = array_len + @boolToInt(array_sent);
  25764 
  25765     if (array_len_s == 0) {
  25766         return sema.fail(block, array_ptr_src, "indexing into empty array is not allowed", .{});
  25767     }
  25768 
  25769     const maybe_undef_array_ptr_val = try sema.resolveMaybeUndefVal(array_ptr);
  25770     // The index must not be undefined since it can be out of bounds.
  25771     const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
  25772         const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(mod));
  25773         if (index >= array_len_s) {
  25774             const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else "";
  25775             return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label });
  25776         }
  25777         break :o index;
  25778     } else null;
  25779 
  25780     const elem_ptr_ty = try sema.elemPtrType(array_ptr_ty, offset);
  25781 
  25782     if (maybe_undef_array_ptr_val) |array_ptr_val| {
  25783         if (array_ptr_val.isUndef(mod)) {
  25784             return sema.addConstUndef(elem_ptr_ty);
  25785         }
  25786         if (offset) |index| {
  25787             const elem_ptr = try array_ptr_val.elemPtr(elem_ptr_ty, index, mod);
  25788             return sema.addConstant(elem_ptr_ty, elem_ptr);
  25789         }
  25790     }
  25791 
  25792     if (!init) {
  25793         try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(mod), array_ty, array_ptr_src);
  25794     }
  25795 
  25796     const runtime_src = if (maybe_undef_array_ptr_val != null) elem_index_src else array_ptr_src;
  25797     try sema.requireRuntimeBlock(block, src, runtime_src);
  25798 
  25799     // Runtime check is only needed if unable to comptime check.
  25800     if (oob_safety and block.wantSafety() and offset == null) {
  25801         const len_inst = try sema.addIntUnsigned(Type.usize, array_len);
  25802         const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt;
  25803         try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op);
  25804     }
  25805 
  25806     return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty);
  25807 }
  25808 
  25809 fn elemValSlice(
  25810     sema: *Sema,
  25811     block: *Block,
  25812     src: LazySrcLoc,
  25813     slice_src: LazySrcLoc,
  25814     slice: Air.Inst.Ref,
  25815     elem_index_src: LazySrcLoc,
  25816     elem_index: Air.Inst.Ref,
  25817     oob_safety: bool,
  25818 ) CompileError!Air.Inst.Ref {
  25819     const mod = sema.mod;
  25820     const slice_ty = sema.typeOf(slice);
  25821     const slice_sent = slice_ty.sentinel(mod) != null;
  25822     const elem_ty = slice_ty.elemType2(mod);
  25823     var runtime_src = slice_src;
  25824 
  25825     // slice must be defined since it can dereferenced as null
  25826     const maybe_slice_val = try sema.resolveDefinedValue(block, slice_src, slice);
  25827     // index must be defined since it can index out of bounds
  25828     const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
  25829 
  25830     if (maybe_slice_val) |slice_val| {
  25831         runtime_src = elem_index_src;
  25832         const slice_len = slice_val.sliceLen(mod);
  25833         const slice_len_s = slice_len + @boolToInt(slice_sent);
  25834         if (slice_len_s == 0) {
  25835             return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
  25836         }
  25837         if (maybe_index_val) |index_val| {
  25838             const index = @intCast(usize, index_val.toUnsignedInt(mod));
  25839             if (index >= slice_len_s) {
  25840                 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
  25841                 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
  25842             }
  25843             const elem_ptr_ty = try sema.elemPtrType(slice_ty, index);
  25844             const elem_ptr_val = try slice_val.elemPtr(elem_ptr_ty, index, mod);
  25845             if (try sema.pointerDeref(block, slice_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {
  25846                 return sema.addConstant(elem_ty, elem_val);
  25847             }
  25848             runtime_src = slice_src;
  25849         }
  25850     }
  25851 
  25852     try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src);
  25853 
  25854     try sema.requireRuntimeBlock(block, src, runtime_src);
  25855     if (oob_safety and block.wantSafety()) {
  25856         const len_inst = if (maybe_slice_val) |slice_val|
  25857             try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(mod))
  25858         else
  25859             try block.addTyOp(.slice_len, Type.usize, slice);
  25860         const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
  25861         try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op);
  25862     }
  25863     try sema.queueFullTypeResolution(sema.typeOf(slice));
  25864     return block.addBinOp(.slice_elem_val, slice, elem_index);
  25865 }
  25866 
  25867 fn elemPtrSlice(
  25868     sema: *Sema,
  25869     block: *Block,
  25870     src: LazySrcLoc,
  25871     slice_src: LazySrcLoc,
  25872     slice: Air.Inst.Ref,
  25873     elem_index_src: LazySrcLoc,
  25874     elem_index: Air.Inst.Ref,
  25875     oob_safety: bool,
  25876 ) CompileError!Air.Inst.Ref {
  25877     const mod = sema.mod;
  25878     const slice_ty = sema.typeOf(slice);
  25879     const slice_sent = slice_ty.sentinel(mod) != null;
  25880 
  25881     const maybe_undef_slice_val = try sema.resolveMaybeUndefVal(slice);
  25882     // The index must not be undefined since it can be out of bounds.
  25883     const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
  25884         const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(mod));
  25885         break :o index;
  25886     } else null;
  25887 
  25888     const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset);
  25889 
  25890     if (maybe_undef_slice_val) |slice_val| {
  25891         if (slice_val.isUndef(mod)) {
  25892             return sema.addConstUndef(elem_ptr_ty);
  25893         }
  25894         const slice_len = slice_val.sliceLen(mod);
  25895         const slice_len_s = slice_len + @boolToInt(slice_sent);
  25896         if (slice_len_s == 0) {
  25897             return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
  25898         }
  25899         if (offset) |index| {
  25900             if (index >= slice_len_s) {
  25901                 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
  25902                 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
  25903             }
  25904             const elem_ptr_val = try slice_val.elemPtr(elem_ptr_ty, index, mod);
  25905             return sema.addConstant(elem_ptr_ty, elem_ptr_val);
  25906         }
  25907     }
  25908 
  25909     try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ptr_ty, slice_ty, slice_src);
  25910 
  25911     const runtime_src = if (maybe_undef_slice_val != null) elem_index_src else slice_src;
  25912     try sema.requireRuntimeBlock(block, src, runtime_src);
  25913     if (oob_safety and block.wantSafety()) {
  25914         const len_inst = len: {
  25915             if (maybe_undef_slice_val) |slice_val|
  25916                 if (!slice_val.isUndef(mod))
  25917                     break :len try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(mod));
  25918             break :len try block.addTyOp(.slice_len, Type.usize, slice);
  25919         };
  25920         const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
  25921         try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op);
  25922     }
  25923     return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty);
  25924 }
  25925 
  25926 fn coerce(
  25927     sema: *Sema,
  25928     block: *Block,
  25929     dest_ty_unresolved: Type,
  25930     inst: Air.Inst.Ref,
  25931     inst_src: LazySrcLoc,
  25932 ) CompileError!Air.Inst.Ref {
  25933     return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, .{}) catch |err| switch (err) {
  25934         error.NotCoercible => unreachable,
  25935         else => |e| return e,
  25936     };
  25937 }
  25938 
  25939 const CoersionError = CompileError || error{
  25940     /// When coerce is called recursively, this error should be returned instead of using `fail`
  25941     /// to ensure correct types in compile errors.
  25942     NotCoercible,
  25943 };
  25944 
  25945 const CoerceOpts = struct {
  25946     /// Should coerceExtra emit error messages.
  25947     report_err: bool = true,
  25948     /// Ignored if `report_err == false`.
  25949     is_ret: bool = false,
  25950     /// Should coercion to comptime_int ermit an error message.
  25951     no_cast_to_comptime_int: bool = false,
  25952 
  25953     param_src: struct {
  25954         func_inst: Air.Inst.Ref = .none,
  25955         param_i: u32 = undefined,
  25956 
  25957         fn get(info: @This(), sema: *Sema) !?Module.SrcLoc {
  25958             if (info.func_inst == .none) return null;
  25959             const mod = sema.mod;
  25960             const fn_decl = (try sema.funcDeclSrc(info.func_inst)) orelse return null;
  25961             const param_src = Module.paramSrc(0, mod, fn_decl, info.param_i);
  25962             if (param_src == .node_offset_param) {
  25963                 return Module.SrcLoc{
  25964                     .file_scope = fn_decl.getFileScope(mod),
  25965                     .parent_decl_node = fn_decl.src_node,
  25966                     .lazy = LazySrcLoc.nodeOffset(param_src.node_offset_param),
  25967                 };
  25968             }
  25969             return param_src.toSrcLoc(fn_decl, mod);
  25970         }
  25971     } = .{},
  25972 };
  25973 
  25974 fn coerceExtra(
  25975     sema: *Sema,
  25976     block: *Block,
  25977     dest_ty_unresolved: Type,
  25978     inst: Air.Inst.Ref,
  25979     inst_src: LazySrcLoc,
  25980     opts: CoerceOpts,
  25981 ) CoersionError!Air.Inst.Ref {
  25982     if (dest_ty_unresolved.isGenericPoison()) return inst;
  25983     const mod = sema.mod;
  25984     const dest_ty_src = inst_src; // TODO better source location
  25985     const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved);
  25986     const inst_ty = try sema.resolveTypeFields(sema.typeOf(inst));
  25987     const target = mod.getTarget();
  25988     // If the types are the same, we can return the operand.
  25989     if (dest_ty.eql(inst_ty, mod))
  25990         return inst;
  25991 
  25992     const maybe_inst_val = try sema.resolveMaybeUndefVal(inst);
  25993 
  25994     var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
  25995     if (in_memory_result == .ok) {
  25996         if (maybe_inst_val) |val| {
  25997             return sema.coerceInMemory(block, val, inst_ty, dest_ty, dest_ty_src);
  25998         }
  25999         try sema.requireRuntimeBlock(block, inst_src, null);
  26000         return block.addBitCast(dest_ty, inst);
  26001     }
  26002 
  26003     const is_undef = inst_ty.zigTypeTag(mod) == .Undefined;
  26004 
  26005     switch (dest_ty.zigTypeTag(mod)) {
  26006         .Optional => optional: {
  26007             // undefined sets the optional bit also to undefined.
  26008             if (is_undef) {
  26009                 return sema.addConstUndef(dest_ty);
  26010             }
  26011 
  26012             // null to ?T
  26013             if (inst_ty.zigTypeTag(mod) == .Null) {
  26014                 return sema.addConstant(dest_ty, (try mod.intern(.{ .opt = .{
  26015                     .ty = dest_ty.toIntern(),
  26016                     .val = .none,
  26017                 } })).toValue());
  26018             }
  26019 
  26020             // cast from ?*T and ?[*]T to ?*anyopaque
  26021             // but don't do it if the source type is a double pointer
  26022             if (dest_ty.isPtrLikeOptional(mod) and
  26023                 dest_ty.elemType2(mod).toIntern() == .anyopaque_type and
  26024                 inst_ty.isPtrAtRuntime(mod))
  26025             anyopaque_check: {
  26026                 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional;
  26027                 const elem_ty = inst_ty.elemType2(mod);
  26028                 if (elem_ty.zigTypeTag(mod) == .Pointer or elem_ty.isPtrLikeOptional(mod)) {
  26029                     in_memory_result = .{ .double_ptr_to_anyopaque = .{
  26030                         .actual = inst_ty,
  26031                         .wanted = dest_ty,
  26032                     } };
  26033                     break :optional;
  26034                 }
  26035                 // Let the logic below handle wrapping the optional now that
  26036                 // it has been checked to correctly coerce.
  26037                 if (!inst_ty.isPtrLikeOptional(mod)) break :anyopaque_check;
  26038                 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
  26039             }
  26040 
  26041             // T to ?T
  26042             const child_type = dest_ty.optionalChild(mod);
  26043             const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
  26044                 error.NotCoercible => {
  26045                     if (in_memory_result == .no_match) {
  26046                         // Try to give more useful notes
  26047                         in_memory_result = try sema.coerceInMemoryAllowed(block, child_type, inst_ty, false, target, dest_ty_src, inst_src);
  26048                     }
  26049                     break :optional;
  26050                 },
  26051                 else => |e| return e,
  26052             };
  26053             return try sema.wrapOptional(block, dest_ty, intermediate, inst_src);
  26054         },
  26055         .Pointer => pointer: {
  26056             const dest_info = dest_ty.ptrInfo(mod);
  26057 
  26058             // Function body to function pointer.
  26059             if (inst_ty.zigTypeTag(mod) == .Fn) {
  26060                 const fn_val = try sema.resolveConstValue(block, .unneeded, inst, "");
  26061                 const fn_decl = fn_val.pointerDecl(mod).?;
  26062                 const inst_as_ptr = try sema.analyzeDeclRef(fn_decl);
  26063                 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);
  26064             }
  26065 
  26066             // *T to *[1]T
  26067             single_item: {
  26068                 if (dest_info.size != .One) break :single_item;
  26069                 if (!inst_ty.isSinglePointer(mod)) break :single_item;
  26070                 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
  26071                 const ptr_elem_ty = inst_ty.childType(mod);
  26072                 const array_ty = dest_info.pointee_type;
  26073                 if (array_ty.zigTypeTag(mod) != .Array) break :single_item;
  26074                 const array_elem_ty = array_ty.childType(mod);
  26075                 if (array_ty.arrayLen(mod) != 1) break :single_item;
  26076                 const dest_is_mut = dest_info.mutable;
  26077                 switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
  26078                     .ok => {},
  26079                     else => break :single_item,
  26080                 }
  26081                 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
  26082             }
  26083 
  26084             // Coercions where the source is a single pointer to an array.
  26085             src_array_ptr: {
  26086                 if (!inst_ty.isSinglePointer(mod)) break :src_array_ptr;
  26087                 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
  26088                 const array_ty = inst_ty.childType(mod);
  26089                 if (array_ty.zigTypeTag(mod) != .Array) break :src_array_ptr;
  26090                 const array_elem_type = array_ty.childType(mod);
  26091                 const dest_is_mut = dest_info.mutable;
  26092 
  26093                 const dst_elem_type = dest_info.pointee_type;
  26094                 const elem_res = try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src);
  26095                 switch (elem_res) {
  26096                     .ok => {},
  26097                     else => {
  26098                         in_memory_result = .{ .ptr_child = .{
  26099                             .child = try elem_res.dupe(sema.arena),
  26100                             .actual = array_elem_type,
  26101                             .wanted = dst_elem_type,
  26102                         } };
  26103                         break :src_array_ptr;
  26104                     },
  26105                 }
  26106 
  26107                 if (dest_info.sentinel) |dest_sent| {
  26108                     if (array_ty.sentinel(mod)) |inst_sent| {
  26109                         if (!dest_sent.eql(inst_sent, dst_elem_type, mod)) {
  26110                             in_memory_result = .{ .ptr_sentinel = .{
  26111                                 .actual = inst_sent,
  26112                                 .wanted = dest_sent,
  26113                                 .ty = dst_elem_type,
  26114                             } };
  26115                             break :src_array_ptr;
  26116                         }
  26117                     } else {
  26118                         in_memory_result = .{ .ptr_sentinel = .{
  26119                             .actual = Value.@"unreachable",
  26120                             .wanted = dest_sent,
  26121                             .ty = dst_elem_type,
  26122                         } };
  26123                         break :src_array_ptr;
  26124                     }
  26125                 }
  26126 
  26127                 switch (dest_info.size) {
  26128                     .Slice => {
  26129                         // *[N]T to []T
  26130                         return sema.coerceArrayPtrToSlice(block, dest_ty, inst, inst_src);
  26131                     },
  26132                     .C => {
  26133                         // *[N]T to [*c]T
  26134                         return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
  26135                     },
  26136                     .Many => {
  26137                         // *[N]T to [*]T
  26138                         return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
  26139                     },
  26140                     .One => {},
  26141                 }
  26142             }
  26143 
  26144             // coercion from C pointer
  26145             if (inst_ty.isCPtr(mod)) src_c_ptr: {
  26146                 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :src_c_ptr;
  26147                 // In this case we must add a safety check because the C pointer
  26148                 // could be null.
  26149                 const src_elem_ty = inst_ty.childType(mod);
  26150                 const dest_is_mut = dest_info.mutable;
  26151                 const dst_elem_type = dest_info.pointee_type;
  26152                 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
  26153                     .ok => {},
  26154                     else => break :src_c_ptr,
  26155                 }
  26156                 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
  26157             }
  26158 
  26159             // cast from *T and [*]T to *anyopaque
  26160             // but don't do it if the source type is a double pointer
  26161             if (dest_info.pointee_type.toIntern() == .anyopaque_type and inst_ty.zigTypeTag(mod) == .Pointer) to_anyopaque: {
  26162                 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
  26163                 const elem_ty = inst_ty.elemType2(mod);
  26164                 if (elem_ty.zigTypeTag(mod) == .Pointer or elem_ty.isPtrLikeOptional(mod)) {
  26165                     in_memory_result = .{ .double_ptr_to_anyopaque = .{
  26166                         .actual = inst_ty,
  26167                         .wanted = dest_ty,
  26168                     } };
  26169                     break :pointer;
  26170                 }
  26171                 if (dest_ty.isSlice(mod)) break :to_anyopaque;
  26172                 if (inst_ty.isSlice(mod)) {
  26173                     in_memory_result = .{ .slice_to_anyopaque = .{
  26174                         .actual = inst_ty,
  26175                         .wanted = dest_ty,
  26176                     } };
  26177                     break :pointer;
  26178                 }
  26179                 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
  26180             }
  26181 
  26182             switch (dest_info.size) {
  26183                 // coercion to C pointer
  26184                 .C => switch (inst_ty.zigTypeTag(mod)) {
  26185                     .Null => {
  26186                         return sema.addConstant(dest_ty, try mod.getCoerced(Value.null, dest_ty));
  26187                     },
  26188                     .ComptimeInt => {
  26189                         const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
  26190                             error.NotCoercible => break :pointer,
  26191                             else => |e| return e,
  26192                         };
  26193                         return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
  26194                     },
  26195                     .Int => {
  26196                         const ptr_size_ty = switch (inst_ty.intInfo(mod).signedness) {
  26197                             .signed => Type.isize,
  26198                             .unsigned => Type.usize,
  26199                         };
  26200                         const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
  26201                             error.NotCoercible => {
  26202                                 // Try to give more useful notes
  26203                                 in_memory_result = try sema.coerceInMemoryAllowed(block, ptr_size_ty, inst_ty, false, target, dest_ty_src, inst_src);
  26204                                 break :pointer;
  26205                             },
  26206                             else => |e| return e,
  26207                         };
  26208                         return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
  26209                     },
  26210                     .Pointer => p: {
  26211                         if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p;
  26212                         const inst_info = inst_ty.ptrInfo(mod);
  26213                         switch (try sema.coerceInMemoryAllowed(
  26214                             block,
  26215                             dest_info.pointee_type,
  26216                             inst_info.pointee_type,
  26217                             dest_info.mutable,
  26218                             target,
  26219                             dest_ty_src,
  26220                             inst_src,
  26221                         )) {
  26222                             .ok => {},
  26223                             else => break :p,
  26224                         }
  26225                         if (inst_info.size == .Slice) {
  26226                             assert(dest_info.sentinel == null);
  26227                             if (inst_info.sentinel == null or
  26228                                 !inst_info.sentinel.?.eql(try mod.intValue(dest_info.pointee_type, 0), dest_info.pointee_type, mod))
  26229                                 break :p;
  26230 
  26231                             const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty);
  26232                             return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src);
  26233                         }
  26234                         return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
  26235                     },
  26236                     else => {},
  26237                 },
  26238                 .One => switch (dest_info.pointee_type.zigTypeTag(mod)) {
  26239                     .Union => {
  26240                         // pointer to anonymous struct to pointer to union
  26241                         if (inst_ty.isSinglePointer(mod) and
  26242                             inst_ty.childType(mod).isAnonStruct(mod) and
  26243                             sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
  26244                         {
  26245                             return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
  26246                         }
  26247                     },
  26248                     .Struct => {
  26249                         // pointer to anonymous struct to pointer to struct
  26250                         if (inst_ty.isSinglePointer(mod) and
  26251                             inst_ty.childType(mod).isAnonStruct(mod) and
  26252                             sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
  26253                         {
  26254                             return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src) catch |err| switch (err) {
  26255                                 error.NotCoercible => break :pointer,
  26256                                 else => |e| return e,
  26257                             };
  26258                         }
  26259                     },
  26260                     .Array => {
  26261                         // pointer to tuple to pointer to array
  26262                         if (inst_ty.isSinglePointer(mod) and
  26263                             inst_ty.childType(mod).isTuple(mod) and
  26264                             sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
  26265                         {
  26266                             return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
  26267                         }
  26268                     },
  26269                     else => {},
  26270                 },
  26271                 .Slice => to_slice: {
  26272                     if (inst_ty.zigTypeTag(mod) == .Array) {
  26273                         return sema.fail(
  26274                             block,
  26275                             inst_src,
  26276                             "array literal requires address-of operator (&) to coerce to slice type '{}'",
  26277                             .{dest_ty.fmt(mod)},
  26278                         );
  26279                     }
  26280 
  26281                     if (!inst_ty.isSinglePointer(mod)) break :to_slice;
  26282                     const inst_child_ty = inst_ty.childType(mod);
  26283                     if (!inst_child_ty.isTuple(mod)) break :to_slice;
  26284 
  26285                     // empty tuple to zero-length slice
  26286                     // note that this allows coercing to a mutable slice.
  26287                     if (inst_child_ty.structFieldCount(mod) == 0) {
  26288                         // Optional slice is represented with a null pointer so
  26289                         // we use a dummy pointer value with the required alignment.
  26290                         return sema.addConstant(dest_ty, (try mod.intern(.{ .ptr = .{
  26291                             .ty = dest_ty.toIntern(),
  26292                             .addr = .{ .int = (if (dest_info.@"align" != 0)
  26293                                 try mod.intValue(Type.usize, dest_info.@"align")
  26294                             else
  26295                                 try mod.getCoerced(try dest_info.pointee_type.lazyAbiAlignment(mod), Type.usize)).toIntern() },
  26296                             .len = (try mod.intValue(Type.usize, 0)).toIntern(),
  26297                         } })).toValue());
  26298                     }
  26299 
  26300                     // pointer to tuple to slice
  26301                     if (dest_info.mutable) {
  26302                         const err_msg = err_msg: {
  26303                             const err_msg = try sema.errMsg(block, inst_src, "cannot cast pointer to tuple to '{}'", .{dest_ty.fmt(mod)});
  26304                             errdefer err_msg.deinit(sema.gpa);
  26305                             try sema.errNote(block, dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{});
  26306                             break :err_msg err_msg;
  26307                         };
  26308                         return sema.failWithOwnedErrorMsg(err_msg);
  26309                     }
  26310                     return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
  26311                 },
  26312                 .Many => p: {
  26313                     if (!inst_ty.isSlice(mod)) break :p;
  26314                     if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p;
  26315                     const inst_info = inst_ty.ptrInfo(mod);
  26316 
  26317                     switch (try sema.coerceInMemoryAllowed(
  26318                         block,
  26319                         dest_info.pointee_type,
  26320                         inst_info.pointee_type,
  26321                         dest_info.mutable,
  26322                         target,
  26323                         dest_ty_src,
  26324                         inst_src,
  26325                     )) {
  26326                         .ok => {},
  26327                         else => break :p,
  26328                     }
  26329 
  26330                     if (dest_info.sentinel == null or inst_info.sentinel == null or
  26331                         !dest_info.sentinel.?.eql(inst_info.sentinel.?, dest_info.pointee_type, mod))
  26332                         break :p;
  26333 
  26334                     const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty);
  26335                     return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src);
  26336                 },
  26337             }
  26338         },
  26339         .Int, .ComptimeInt => switch (inst_ty.zigTypeTag(mod)) {
  26340             .Float, .ComptimeFloat => float: {
  26341                 if (is_undef) {
  26342                     return sema.addConstUndef(dest_ty);
  26343                 }
  26344                 const val = (try sema.resolveMaybeUndefVal(inst)) orelse {
  26345                     if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
  26346                         if (!opts.report_err) return error.NotCoercible;
  26347                         return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime-known");
  26348                     }
  26349                     break :float;
  26350                 };
  26351 
  26352                 if (val.floatHasFraction(mod)) {
  26353                     return sema.fail(
  26354                         block,
  26355                         inst_src,
  26356                         "fractional component prevents float value '{}' from coercion to type '{}'",
  26357                         .{ val.fmtValue(inst_ty, mod), dest_ty.fmt(mod) },
  26358                     );
  26359                 }
  26360                 const result_val = try sema.floatToInt(block, inst_src, val, inst_ty, dest_ty);
  26361                 return try sema.addConstant(dest_ty, result_val);
  26362             },
  26363             .Int, .ComptimeInt => {
  26364                 if (is_undef) {
  26365                     return sema.addConstUndef(dest_ty);
  26366                 }
  26367                 if (try sema.resolveMaybeUndefVal(inst)) |val| {
  26368                     // comptime-known integer to other number
  26369                     if (!(try sema.intFitsInType(val, dest_ty, null))) {
  26370                         if (!opts.report_err) return error.NotCoercible;
  26371                         return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) });
  26372                     }
  26373                     return try sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty));
  26374                 }
  26375                 if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
  26376                     if (!opts.report_err) return error.NotCoercible;
  26377                     if (opts.no_cast_to_comptime_int) return inst;
  26378                     return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime-known");
  26379                 }
  26380 
  26381                 // integer widening
  26382                 const dst_info = dest_ty.intInfo(mod);
  26383                 const src_info = inst_ty.intInfo(mod);
  26384                 if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or
  26385                     // small enough unsigned ints can get casted to large enough signed ints
  26386                     (dst_info.signedness == .signed and dst_info.bits > src_info.bits))
  26387                 {
  26388                     try sema.requireRuntimeBlock(block, inst_src, null);
  26389                     return block.addTyOp(.intcast, dest_ty, inst);
  26390                 }
  26391             },
  26392             .Undefined => {
  26393                 return sema.addConstUndef(dest_ty);
  26394             },
  26395             else => {},
  26396         },
  26397         .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(mod)) {
  26398             .ComptimeFloat => {
  26399                 const val = try sema.resolveConstValue(block, .unneeded, inst, "");
  26400                 const result_val = try val.floatCast(dest_ty, mod);
  26401                 return try sema.addConstant(dest_ty, result_val);
  26402             },
  26403             .Float => {
  26404                 if (is_undef) {
  26405                     return sema.addConstUndef(dest_ty);
  26406                 }
  26407                 if (try sema.resolveMaybeUndefVal(inst)) |val| {
  26408                     const result_val = try val.floatCast(dest_ty, mod);
  26409                     if (!val.eql(try result_val.floatCast(inst_ty, mod), inst_ty, mod)) {
  26410                         return sema.fail(
  26411                             block,
  26412                             inst_src,
  26413                             "type '{}' cannot represent float value '{}'",
  26414                             .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) },
  26415                         );
  26416                     }
  26417                     return try sema.addConstant(dest_ty, result_val);
  26418                 } else if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {
  26419                     if (!opts.report_err) return error.NotCoercible;
  26420                     return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime-known");
  26421                 }
  26422 
  26423                 // float widening
  26424                 const src_bits = inst_ty.floatBits(target);
  26425                 const dst_bits = dest_ty.floatBits(target);
  26426                 if (dst_bits >= src_bits) {
  26427                     try sema.requireRuntimeBlock(block, inst_src, null);
  26428                     return block.addTyOp(.fpext, dest_ty, inst);
  26429                 }
  26430             },
  26431             .Int, .ComptimeInt => int: {
  26432                 if (is_undef) {
  26433                     return sema.addConstUndef(dest_ty);
  26434                 }
  26435                 const val = (try sema.resolveMaybeUndefVal(inst)) orelse {
  26436                     if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {
  26437                         if (!opts.report_err) return error.NotCoercible;
  26438                         return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime-known");
  26439                     }
  26440                     break :int;
  26441                 };
  26442                 const result_val = try val.intToFloatAdvanced(sema.arena, inst_ty, dest_ty, mod, sema);
  26443                 // TODO implement this compile error
  26444                 //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty);
  26445                 //if (!int_again_val.eql(val, inst_ty, mod)) {
  26446                 //    return sema.fail(
  26447                 //        block,
  26448                 //        inst_src,
  26449                 //        "type '{}' cannot represent integer value '{}'",
  26450                 //        .{ dest_ty.fmt(mod), val },
  26451                 //    );
  26452                 //}
  26453                 return try sema.addConstant(dest_ty, result_val);
  26454             },
  26455             .Undefined => {
  26456                 return sema.addConstUndef(dest_ty);
  26457             },
  26458             else => {},
  26459         },
  26460         .Enum => switch (inst_ty.zigTypeTag(mod)) {
  26461             .EnumLiteral => {
  26462                 // enum literal to enum
  26463                 const val = try sema.resolveConstValue(block, .unneeded, inst, "");
  26464                 const string = mod.intern_pool.indexToKey(val.toIntern()).enum_literal;
  26465                 const bytes = mod.intern_pool.stringToSlice(string);
  26466                 const field_index = dest_ty.enumFieldIndex(bytes, mod) orelse {
  26467                     const msg = msg: {
  26468                         const msg = try sema.errMsg(
  26469                             block,
  26470                             inst_src,
  26471                             "no field named '{s}' in enum '{}'",
  26472                             .{ bytes, dest_ty.fmt(mod) },
  26473                         );
  26474                         errdefer msg.destroy(sema.gpa);
  26475                         try sema.addDeclaredHereNote(msg, dest_ty);
  26476                         break :msg msg;
  26477                     };
  26478                     return sema.failWithOwnedErrorMsg(msg);
  26479                 };
  26480                 return sema.addConstant(
  26481                     dest_ty,
  26482                     try mod.enumValueFieldIndex(dest_ty, @intCast(u32, field_index)),
  26483                 );
  26484             },
  26485             .Union => blk: {
  26486                 // union to its own tag type
  26487                 const union_tag_ty = inst_ty.unionTagType(mod) orelse break :blk;
  26488                 if (union_tag_ty.eql(dest_ty, mod)) {
  26489                     return sema.unionToTag(block, dest_ty, inst, inst_src);
  26490                 }
  26491             },
  26492             .Undefined => {
  26493                 return sema.addConstUndef(dest_ty);
  26494             },
  26495             else => {},
  26496         },
  26497         .ErrorUnion => switch (inst_ty.zigTypeTag(mod)) {
  26498             .ErrorUnion => eu: {
  26499                 if (maybe_inst_val) |inst_val| {
  26500                     switch (inst_val.toIntern()) {
  26501                         .undef => return sema.addConstUndef(dest_ty),
  26502                         else => switch (mod.intern_pool.indexToKey(inst_val.toIntern())) {
  26503                             .error_union => |error_union| switch (error_union.val) {
  26504                                 .err_name => |err_name| {
  26505                                     const error_set_ty = inst_ty.errorUnionSet(mod);
  26506                                     const error_set_val = try sema.addConstant(error_set_ty, (try mod.intern(.{ .err = .{
  26507                                         .ty = error_set_ty.toIntern(),
  26508                                         .name = err_name,
  26509                                     } })).toValue());
  26510                                     return sema.wrapErrorUnionSet(block, dest_ty, error_set_val, inst_src);
  26511                                 },
  26512                                 .payload => |payload| {
  26513                                     const payload_val = try sema.addConstant(
  26514                                         inst_ty.errorUnionPayload(mod),
  26515                                         payload.toValue(),
  26516                                     );
  26517                                     return sema.wrapErrorUnionPayload(block, dest_ty, payload_val, inst_src) catch |err| switch (err) {
  26518                                         error.NotCoercible => break :eu,
  26519                                         else => |e| return e,
  26520                                     };
  26521                                 },
  26522                             },
  26523                             else => unreachable,
  26524                         },
  26525                     }
  26526                 }
  26527             },
  26528             .ErrorSet => {
  26529                 // E to E!T
  26530                 return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);
  26531             },
  26532             .Undefined => {
  26533                 return sema.addConstUndef(dest_ty);
  26534             },
  26535             else => eu: {
  26536                 // T to E!T
  26537                 return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src) catch |err| switch (err) {
  26538                     error.NotCoercible => break :eu,
  26539                     else => |e| return e,
  26540                 };
  26541             },
  26542         },
  26543         .Union => switch (inst_ty.zigTypeTag(mod)) {
  26544             .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src),
  26545             .Struct => {
  26546                 if (inst_ty.isAnonStruct(mod)) {
  26547                     return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);
  26548                 }
  26549             },
  26550             .Undefined => {
  26551                 return sema.addConstUndef(dest_ty);
  26552             },
  26553             else => {},
  26554         },
  26555         .Array => switch (inst_ty.zigTypeTag(mod)) {
  26556             .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
  26557             .Struct => {
  26558                 if (inst == .empty_struct) {
  26559                     return sema.arrayInitEmpty(block, inst_src, dest_ty);
  26560                 }
  26561                 if (inst_ty.isTuple(mod)) {
  26562                     return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
  26563                 }
  26564             },
  26565             .Undefined => {
  26566                 return sema.addConstUndef(dest_ty);
  26567             },
  26568             else => {},
  26569         },
  26570         .Vector => switch (inst_ty.zigTypeTag(mod)) {
  26571             .Array, .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
  26572             .Struct => {
  26573                 if (inst_ty.isTuple(mod)) {
  26574                     return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
  26575                 }
  26576             },
  26577             .Undefined => {
  26578                 return sema.addConstUndef(dest_ty);
  26579             },
  26580             else => {},
  26581         },
  26582         .Struct => blk: {
  26583             if (inst == .empty_struct) {
  26584                 return sema.structInitEmpty(block, dest_ty, dest_ty_src, inst_src);
  26585             }
  26586             if (inst_ty.isTupleOrAnonStruct(mod)) {
  26587                 return sema.coerceTupleToStruct(block, dest_ty, inst, inst_src) catch |err| switch (err) {
  26588                     error.NotCoercible => break :blk,
  26589                     else => |e| return e,
  26590                 };
  26591             }
  26592         },
  26593         else => {},
  26594     }
  26595 
  26596     // undefined to anything. We do this after the big switch above so that
  26597     // special logic has a chance to run first, such as `*[N]T` to `[]T` which
  26598     // should initialize the length field of the slice.
  26599     if (is_undef) {
  26600         return sema.addConstUndef(dest_ty);
  26601     }
  26602 
  26603     if (!opts.report_err) return error.NotCoercible;
  26604 
  26605     if (opts.is_ret and dest_ty.zigTypeTag(mod) == .NoReturn) {
  26606         const msg = msg: {
  26607             const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{});
  26608             errdefer msg.destroy(sema.gpa);
  26609 
  26610             const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
  26611             const src_decl = mod.declPtr(sema.func.?.owner_decl);
  26612             try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "'noreturn' declared here", .{});
  26613             break :msg msg;
  26614         };
  26615         return sema.failWithOwnedErrorMsg(msg);
  26616     }
  26617 
  26618     const msg = msg: {
  26619         const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(mod), inst_ty.fmt(mod) });
  26620         errdefer msg.destroy(sema.gpa);
  26621 
  26622         // E!T to T
  26623         if (inst_ty.zigTypeTag(mod) == .ErrorUnion and
  26624             (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
  26625         {
  26626             try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{});
  26627             try sema.errNote(block, inst_src, msg, "consider using 'try', 'catch', or 'if'", .{});
  26628         }
  26629 
  26630         // ?T to T
  26631         if (inst_ty.zigTypeTag(mod) == .Optional and
  26632             (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
  26633         {
  26634             try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{});
  26635             try sema.errNote(block, inst_src, msg, "consider using '.?', 'orelse', or 'if'", .{});
  26636         }
  26637 
  26638         try in_memory_result.report(sema, block, inst_src, msg);
  26639 
  26640         // Add notes about function return type
  26641         if (opts.is_ret and mod.test_functions.get(sema.func.?.owner_decl) == null) {
  26642             const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
  26643             const src_decl = mod.declPtr(sema.func.?.owner_decl);
  26644             if (inst_ty.isError(mod) and !dest_ty.isError(mod)) {
  26645                 try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function cannot return an error", .{});
  26646             } else {
  26647                 try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function return type declared here", .{});
  26648             }
  26649         }
  26650 
  26651         if (try opts.param_src.get(sema)) |param_src| {
  26652             try mod.errNoteNonLazy(param_src, msg, "parameter type declared here", .{});
  26653         }
  26654 
  26655         // TODO maybe add "cannot store an error in type '{}'" note
  26656 
  26657         break :msg msg;
  26658     };
  26659     return sema.failWithOwnedErrorMsg(msg);
  26660 }
  26661 
  26662 fn coerceInMemory(
  26663     sema: *Sema,
  26664     block: *Block,
  26665     val: Value,
  26666     src_ty: Type,
  26667     dst_ty: Type,
  26668     dst_ty_src: LazySrcLoc,
  26669 ) CompileError!Air.Inst.Ref {
  26670     const mod = sema.mod;
  26671     switch (mod.intern_pool.indexToKey(val.toIntern())) {
  26672         .aggregate => |aggregate| {
  26673             const dst_ty_key = mod.intern_pool.indexToKey(dst_ty.toIntern());
  26674             const dest_len = try sema.usizeCast(
  26675                 block,
  26676                 dst_ty_src,
  26677                 mod.intern_pool.aggregateTypeLen(dst_ty.toIntern()),
  26678             );
  26679             direct: {
  26680                 const src_ty_child = switch (mod.intern_pool.indexToKey(src_ty.toIntern())) {
  26681                     inline .array_type, .vector_type => |seq_type| seq_type.child,
  26682                     .anon_struct_type, .struct_type => break :direct,
  26683                     else => unreachable,
  26684                 };
  26685                 const dst_ty_child = switch (dst_ty_key) {
  26686                     inline .array_type, .vector_type => |seq_type| seq_type.child,
  26687                     .anon_struct_type, .struct_type => break :direct,
  26688                     else => unreachable,
  26689                 };
  26690                 if (src_ty_child != dst_ty_child) break :direct;
  26691                 return try sema.addConstant(dst_ty, (try mod.intern(.{ .aggregate = .{
  26692                     .ty = dst_ty.toIntern(),
  26693                     .storage = switch (aggregate.storage) {
  26694                         .bytes => |bytes| .{ .bytes = bytes[0..dest_len] },
  26695                         .elems => |elems| .{ .elems = elems[0..dest_len] },
  26696                         .repeated_elem => |elem| .{ .repeated_elem = elem },
  26697                     },
  26698                 } })).toValue());
  26699             }
  26700             const dest_elems = try sema.arena.alloc(InternPool.Index, dest_len);
  26701             for (dest_elems, 0..) |*dest_elem, i| {
  26702                 const elem_ty = switch (dst_ty_key) {
  26703                     inline .array_type, .vector_type => |seq_type| seq_type.child,
  26704                     .anon_struct_type => |anon_struct_type| anon_struct_type.types[i],
  26705                     .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?
  26706                         .fields.values()[i].ty.toIntern(),
  26707                     else => unreachable,
  26708                 };
  26709                 dest_elem.* = try mod.intern_pool.getCoerced(mod.gpa, switch (aggregate.storage) {
  26710                     .bytes => |bytes| (try mod.intValue(Type.u8, bytes[i])).toIntern(),
  26711                     .elems => |elems| elems[i],
  26712                     .repeated_elem => |elem| elem,
  26713                 }, elem_ty);
  26714             }
  26715             return sema.addConstant(dst_ty, (try mod.intern(.{ .aggregate = .{
  26716                 .ty = dst_ty.toIntern(),
  26717                 .storage = .{ .elems = dest_elems },
  26718             } })).toValue());
  26719         },
  26720         .float => |float| return sema.addConstant(dst_ty, (try mod.intern(.{ .float = .{
  26721             .ty = dst_ty.toIntern(),
  26722             .storage = float.storage,
  26723         } })).toValue()),
  26724         else => return sema.addConstant(dst_ty, try mod.getCoerced(val, dst_ty)),
  26725     }
  26726 }
  26727 
  26728 const InMemoryCoercionResult = union(enum) {
  26729     ok,
  26730     no_match: Pair,
  26731     int_not_coercible: Int,
  26732     error_union_payload: PairAndChild,
  26733     array_len: IntPair,
  26734     array_sentinel: Sentinel,
  26735     array_elem: PairAndChild,
  26736     vector_len: IntPair,
  26737     vector_elem: PairAndChild,
  26738     optional_shape: Pair,
  26739     optional_child: PairAndChild,
  26740     from_anyerror,
  26741     missing_error: []const InternPool.NullTerminatedString,
  26742     /// true if wanted is var args
  26743     fn_var_args: bool,
  26744     /// true if wanted is generic
  26745     fn_generic: bool,
  26746     fn_param_count: IntPair,
  26747     fn_param_noalias: IntPair,
  26748     fn_param_comptime: ComptimeParam,
  26749     fn_param: Param,
  26750     fn_cc: CC,
  26751     fn_return_type: PairAndChild,
  26752     ptr_child: PairAndChild,
  26753     ptr_addrspace: AddressSpace,
  26754     ptr_sentinel: Sentinel,
  26755     ptr_size: Size,
  26756     ptr_qualifiers: Qualifiers,
  26757     ptr_allowzero: Pair,
  26758     ptr_bit_range: BitRange,
  26759     ptr_alignment: IntPair,
  26760     double_ptr_to_anyopaque: Pair,
  26761     slice_to_anyopaque: Pair,
  26762 
  26763     const Pair = struct {
  26764         actual: Type,
  26765         wanted: Type,
  26766     };
  26767 
  26768     const PairAndChild = struct {
  26769         child: *InMemoryCoercionResult,
  26770         actual: Type,
  26771         wanted: Type,
  26772     };
  26773 
  26774     const Param = struct {
  26775         child: *InMemoryCoercionResult,
  26776         actual: Type,
  26777         wanted: Type,
  26778         index: u64,
  26779     };
  26780 
  26781     const ComptimeParam = struct {
  26782         index: u64,
  26783         wanted: bool,
  26784     };
  26785 
  26786     const Sentinel = struct {
  26787         // unreachable_value indicates no sentinel
  26788         actual: Value,
  26789         wanted: Value,
  26790         ty: Type,
  26791     };
  26792 
  26793     const Int = struct {
  26794         actual_signedness: std.builtin.Signedness,
  26795         wanted_signedness: std.builtin.Signedness,
  26796         actual_bits: u16,
  26797         wanted_bits: u16,
  26798     };
  26799 
  26800     const IntPair = struct {
  26801         actual: u64,
  26802         wanted: u64,
  26803     };
  26804 
  26805     const Size = struct {
  26806         actual: std.builtin.Type.Pointer.Size,
  26807         wanted: std.builtin.Type.Pointer.Size,
  26808     };
  26809 
  26810     const Qualifiers = struct {
  26811         actual_const: bool,
  26812         wanted_const: bool,
  26813         actual_volatile: bool,
  26814         wanted_volatile: bool,
  26815     };
  26816 
  26817     const AddressSpace = struct {
  26818         actual: std.builtin.AddressSpace,
  26819         wanted: std.builtin.AddressSpace,
  26820     };
  26821 
  26822     const CC = struct {
  26823         actual: std.builtin.CallingConvention,
  26824         wanted: std.builtin.CallingConvention,
  26825     };
  26826 
  26827     const BitRange = struct {
  26828         actual_host: u16,
  26829         wanted_host: u16,
  26830         actual_offset: u16,
  26831         wanted_offset: u16,
  26832     };
  26833 
  26834     fn dupe(child: *const InMemoryCoercionResult, arena: Allocator) !*InMemoryCoercionResult {
  26835         const res = try arena.create(InMemoryCoercionResult);
  26836         res.* = child.*;
  26837         return res;
  26838     }
  26839 
  26840     fn report(res: *const InMemoryCoercionResult, sema: *Sema, block: *Block, src: LazySrcLoc, msg: *Module.ErrorMsg) !void {
  26841         const mod = sema.mod;
  26842         var cur = res;
  26843         while (true) switch (cur.*) {
  26844             .ok => unreachable,
  26845             .no_match => |types| {
  26846                 try sema.addDeclaredHereNote(msg, types.wanted);
  26847                 try sema.addDeclaredHereNote(msg, types.actual);
  26848                 break;
  26849             },
  26850             .int_not_coercible => |int| {
  26851                 try sema.errNote(block, src, msg, "{s} {d}-bit int cannot represent all possible {s} {d}-bit values", .{
  26852                     @tagName(int.wanted_signedness), int.wanted_bits, @tagName(int.actual_signedness), int.actual_bits,
  26853                 });
  26854                 break;
  26855             },
  26856             .error_union_payload => |pair| {
  26857                 try sema.errNote(block, src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{
  26858                     pair.actual.fmt(mod), pair.wanted.fmt(mod),
  26859                 });
  26860                 cur = pair.child;
  26861             },
  26862             .array_len => |lens| {
  26863                 try sema.errNote(block, src, msg, "array of length {d} cannot cast into an array of length {d}", .{
  26864                     lens.actual, lens.wanted,
  26865                 });
  26866                 break;
  26867             },
  26868             .array_sentinel => |sentinel| {
  26869                 if (sentinel.actual.toIntern() != .unreachable_value) {
  26870                     try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{
  26871                         sentinel.actual.fmtValue(sentinel.ty, mod), sentinel.wanted.fmtValue(sentinel.ty, mod),
  26872                     });
  26873                 } else {
  26874                     try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{
  26875                         sentinel.wanted.fmtValue(sentinel.ty, mod),
  26876                     });
  26877                 }
  26878                 break;
  26879             },
  26880             .array_elem => |pair| {
  26881                 try sema.errNote(block, src, msg, "array element type '{}' cannot cast into array element type '{}'", .{
  26882                     pair.actual.fmt(mod), pair.wanted.fmt(mod),
  26883                 });
  26884                 cur = pair.child;
  26885             },
  26886             .vector_len => |lens| {
  26887                 try sema.errNote(block, src, msg, "vector of length {d} cannot cast into a vector of length {d}", .{
  26888                     lens.actual, lens.wanted,
  26889                 });
  26890                 break;
  26891             },
  26892             .vector_elem => |pair| {
  26893                 try sema.errNote(block, src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{
  26894                     pair.actual.fmt(mod), pair.wanted.fmt(mod),
  26895                 });
  26896                 cur = pair.child;
  26897             },
  26898             .optional_shape => |pair| {
  26899                 try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{
  26900                     pair.actual.optionalChild(mod).fmt(mod), pair.wanted.optionalChild(mod).fmt(mod),
  26901                 });
  26902                 break;
  26903             },
  26904             .optional_child => |pair| {
  26905                 try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{
  26906                     pair.actual.fmt(mod), pair.wanted.fmt(mod),
  26907                 });
  26908                 cur = pair.child;
  26909             },
  26910             .from_anyerror => {
  26911                 try sema.errNote(block, src, msg, "global error set cannot cast into a smaller set", .{});
  26912                 break;
  26913             },
  26914             .missing_error => |missing_errors| {
  26915                 for (missing_errors) |err_index| {
  26916                     const err = mod.intern_pool.stringToSlice(err_index);
  26917                     try sema.errNote(block, src, msg, "'error.{s}' not a member of destination error set", .{err});
  26918                 }
  26919                 break;
  26920             },
  26921             .fn_var_args => |wanted_var_args| {
  26922                 if (wanted_var_args) {
  26923                     try sema.errNote(block, src, msg, "non-variadic function cannot cast into a variadic function", .{});
  26924                 } else {
  26925                     try sema.errNote(block, src, msg, "variadic function cannot cast into a non-variadic function", .{});
  26926                 }
  26927                 break;
  26928             },
  26929             .fn_generic => |wanted_generic| {
  26930                 if (wanted_generic) {
  26931                     try sema.errNote(block, src, msg, "non-generic function cannot cast into a generic function", .{});
  26932                 } else {
  26933                     try sema.errNote(block, src, msg, "generic function cannot cast into a non-generic function", .{});
  26934                 }
  26935                 break;
  26936             },
  26937             .fn_param_count => |lens| {
  26938                 try sema.errNote(block, src, msg, "function with {d} parameters cannot cast into a function with {d} parameters", .{
  26939                     lens.actual, lens.wanted,
  26940                 });
  26941                 break;
  26942             },
  26943             .fn_param_noalias => |param| {
  26944                 var index: u6 = 0;
  26945                 var actual_noalias = false;
  26946                 while (true) : (index += 1) {
  26947                     const actual = @truncate(u1, param.actual >> index);
  26948                     const wanted = @truncate(u1, param.wanted >> index);
  26949                     if (actual != wanted) {
  26950                         actual_noalias = actual == 1;
  26951                         break;
  26952                     }
  26953                 }
  26954                 if (!actual_noalias) {
  26955                     try sema.errNote(block, src, msg, "regular parameter {d} cannot cast into a noalias parameter", .{index});
  26956                 } else {
  26957                     try sema.errNote(block, src, msg, "noalias parameter {d} cannot cast into a regular parameter", .{index});
  26958                 }
  26959                 break;
  26960             },
  26961             .fn_param_comptime => |param| {
  26962                 if (param.wanted) {
  26963                     try sema.errNote(block, src, msg, "non-comptime parameter {d} cannot cast into a comptime parameter", .{param.index});
  26964                 } else {
  26965                     try sema.errNote(block, src, msg, "comptime parameter {d} cannot cast into a non-comptime parameter", .{param.index});
  26966                 }
  26967                 break;
  26968             },
  26969             .fn_param => |param| {
  26970                 try sema.errNote(block, src, msg, "parameter {d} '{}' cannot cast into '{}'", .{
  26971                     param.index, param.actual.fmt(mod), param.wanted.fmt(mod),
  26972                 });
  26973                 cur = param.child;
  26974             },
  26975             .fn_cc => |cc| {
  26976                 try sema.errNote(block, src, msg, "calling convention '{s}' cannot cast into calling convention '{s}'", .{ @tagName(cc.actual), @tagName(cc.wanted) });
  26977                 break;
  26978             },
  26979             .fn_return_type => |pair| {
  26980                 try sema.errNote(block, src, msg, "return type '{}' cannot cast into return type '{}'", .{
  26981                     pair.actual.fmt(mod), pair.wanted.fmt(mod),
  26982                 });
  26983                 cur = pair.child;
  26984             },
  26985             .ptr_child => |pair| {
  26986                 try sema.errNote(block, src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{
  26987                     pair.actual.fmt(mod), pair.wanted.fmt(mod),
  26988                 });
  26989                 cur = pair.child;
  26990             },
  26991             .ptr_addrspace => |@"addrspace"| {
  26992                 try sema.errNote(block, src, msg, "address space '{s}' cannot cast into address space '{s}'", .{ @tagName(@"addrspace".actual), @tagName(@"addrspace".wanted) });
  26993                 break;
  26994             },
  26995             .ptr_sentinel => |sentinel| {
  26996                 if (sentinel.actual.toIntern() != .unreachable_value) {
  26997                     try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{
  26998                         sentinel.actual.fmtValue(sentinel.ty, mod), sentinel.wanted.fmtValue(sentinel.ty, mod),
  26999                     });
  27000                 } else {
  27001                     try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{
  27002                         sentinel.wanted.fmtValue(sentinel.ty, mod),
  27003                     });
  27004                 }
  27005                 break;
  27006             },
  27007             .ptr_size => |size| {
  27008                 try sema.errNote(block, src, msg, "a {s} pointer cannot cast into a {s} pointer", .{ pointerSizeString(size.actual), pointerSizeString(size.wanted) });
  27009                 break;
  27010             },
  27011             .ptr_qualifiers => |qualifiers| {
  27012                 const ok_const = !qualifiers.actual_const or qualifiers.wanted_const;
  27013                 const ok_volatile = !qualifiers.actual_volatile or qualifiers.wanted_volatile;
  27014                 if (!ok_const) {
  27015                     try sema.errNote(block, src, msg, "cast discards const qualifier", .{});
  27016                 } else if (!ok_volatile) {
  27017                     try sema.errNote(block, src, msg, "cast discards volatile qualifier", .{});
  27018                 }
  27019                 break;
  27020             },
  27021             .ptr_allowzero => |pair| {
  27022                 const wanted_allow_zero = pair.wanted.ptrAllowsZero(mod);
  27023                 const actual_allow_zero = pair.actual.ptrAllowsZero(mod);
  27024                 if (actual_allow_zero and !wanted_allow_zero) {
  27025                     try sema.errNote(block, src, msg, "'{}' could have null values which are illegal in type '{}'", .{
  27026                         pair.actual.fmt(mod), pair.wanted.fmt(mod),
  27027                     });
  27028                 } else {
  27029                     try sema.errNote(block, src, msg, "mutable '{}' allows illegal null values stored to type '{}'", .{
  27030                         pair.actual.fmt(mod), pair.wanted.fmt(mod),
  27031                     });
  27032                 }
  27033                 break;
  27034             },
  27035             .ptr_bit_range => |bit_range| {
  27036                 if (bit_range.actual_host != bit_range.wanted_host) {
  27037                     try sema.errNote(block, src, msg, "pointer host size '{}' cannot cast into pointer host size '{}'", .{
  27038                         bit_range.actual_host, bit_range.wanted_host,
  27039                     });
  27040                 }
  27041                 if (bit_range.actual_offset != bit_range.wanted_offset) {
  27042                     try sema.errNote(block, src, msg, "pointer bit offset '{}' cannot cast into pointer bit offset '{}'", .{
  27043                         bit_range.actual_offset, bit_range.wanted_offset,
  27044                     });
  27045                 }
  27046                 break;
  27047             },
  27048             .ptr_alignment => |pair| {
  27049                 try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{
  27050                     pair.actual, pair.wanted,
  27051                 });
  27052                 break;
  27053             },
  27054             .double_ptr_to_anyopaque => |pair| {
  27055                 try sema.errNote(block, src, msg, "cannot implicitly cast double pointer '{}' to anyopaque pointer '{}'", .{
  27056                     pair.actual.fmt(mod), pair.wanted.fmt(mod),
  27057                 });
  27058                 break;
  27059             },
  27060             .slice_to_anyopaque => |pair| {
  27061                 try sema.errNote(block, src, msg, "cannot implicitly cast slice '{}' to anyopaque pointer '{}'", .{
  27062                     pair.actual.fmt(mod), pair.wanted.fmt(mod),
  27063                 });
  27064                 try sema.errNote(block, src, msg, "consider using '.ptr'", .{});
  27065                 break;
  27066             },
  27067         };
  27068     }
  27069 };
  27070 
  27071 fn pointerSizeString(size: std.builtin.Type.Pointer.Size) []const u8 {
  27072     return switch (size) {
  27073         .One => "single",
  27074         .Many => "many",
  27075         .C => "C",
  27076         .Slice => unreachable,
  27077     };
  27078 }
  27079 
  27080 /// If pointers have the same representation in runtime memory, a bitcast AIR instruction
  27081 /// may be used for the coercion.
  27082 /// * `const` attribute can be gained
  27083 /// * `volatile` attribute can be gained
  27084 /// * `allowzero` attribute can be gained (whether from explicit attribute, C pointer, or optional pointer) but only if !dest_is_mut
  27085 /// * alignment can be decreased
  27086 /// * bit offset attributes must match exactly
  27087 /// * `*`/`[*]` must match exactly, but `[*c]` matches either one
  27088 /// * sentinel-terminated pointers can coerce into `[*]`
  27089 fn coerceInMemoryAllowed(
  27090     sema: *Sema,
  27091     block: *Block,
  27092     dest_ty: Type,
  27093     src_ty: Type,
  27094     dest_is_mut: bool,
  27095     target: std.Target,
  27096     dest_src: LazySrcLoc,
  27097     src_src: LazySrcLoc,
  27098 ) CompileError!InMemoryCoercionResult {
  27099     const mod = sema.mod;
  27100 
  27101     if (dest_ty.eql(src_ty, mod))
  27102         return .ok;
  27103 
  27104     const dest_tag = dest_ty.zigTypeTag(mod);
  27105     const src_tag = src_ty.zigTypeTag(mod);
  27106 
  27107     // Differently-named integers with the same number of bits.
  27108     if (dest_tag == .Int and src_tag == .Int) {
  27109         const dest_info = dest_ty.intInfo(mod);
  27110         const src_info = src_ty.intInfo(mod);
  27111 
  27112         if (dest_info.signedness == src_info.signedness and
  27113             dest_info.bits == src_info.bits)
  27114         {
  27115             return .ok;
  27116         }
  27117 
  27118         if ((src_info.signedness == dest_info.signedness and dest_info.bits < src_info.bits) or
  27119             // small enough unsigned ints can get casted to large enough signed ints
  27120             (dest_info.signedness == .signed and (src_info.signedness == .unsigned or dest_info.bits <= src_info.bits)) or
  27121             (dest_info.signedness == .unsigned and src_info.signedness == .signed))
  27122         {
  27123             return InMemoryCoercionResult{ .int_not_coercible = .{
  27124                 .actual_signedness = src_info.signedness,
  27125                 .wanted_signedness = dest_info.signedness,
  27126                 .actual_bits = src_info.bits,
  27127                 .wanted_bits = dest_info.bits,
  27128             } };
  27129         }
  27130     }
  27131 
  27132     // Differently-named floats with the same number of bits.
  27133     if (dest_tag == .Float and src_tag == .Float) {
  27134         const dest_bits = dest_ty.floatBits(target);
  27135         const src_bits = src_ty.floatBits(target);
  27136         if (dest_bits == src_bits) {
  27137             return .ok;
  27138         }
  27139     }
  27140 
  27141     // Pointers / Pointer-like Optionals
  27142     const maybe_dest_ptr_ty = try sema.typePtrOrOptionalPtrTy(dest_ty);
  27143     const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(src_ty);
  27144     if (maybe_dest_ptr_ty) |dest_ptr_ty| {
  27145         if (maybe_src_ptr_ty) |src_ptr_ty| {
  27146             return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target, dest_src, src_src);
  27147         }
  27148     }
  27149 
  27150     // Slices
  27151     if (dest_ty.isSlice(mod) and src_ty.isSlice(mod)) {
  27152         return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src);
  27153     }
  27154 
  27155     // Functions
  27156     if (dest_tag == .Fn and src_tag == .Fn) {
  27157         return try sema.coerceInMemoryAllowedFns(block, dest_ty, src_ty, target, dest_src, src_src);
  27158     }
  27159 
  27160     // Error Unions
  27161     if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) {
  27162         const dest_payload = dest_ty.errorUnionPayload(mod);
  27163         const src_payload = src_ty.errorUnionPayload(mod);
  27164         const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src);
  27165         if (child != .ok) {
  27166             return InMemoryCoercionResult{ .error_union_payload = .{
  27167                 .child = try child.dupe(sema.arena),
  27168                 .actual = src_payload,
  27169                 .wanted = dest_payload,
  27170             } };
  27171         }
  27172         return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(mod), src_ty.errorUnionSet(mod), dest_is_mut, target, dest_src, src_src);
  27173     }
  27174 
  27175     // Error Sets
  27176     if (dest_tag == .ErrorSet and src_tag == .ErrorSet) {
  27177         return try sema.coerceInMemoryAllowedErrorSets(block, dest_ty, src_ty, dest_src, src_src);
  27178     }
  27179 
  27180     // Arrays
  27181     if (dest_tag == .Array and src_tag == .Array) {
  27182         const dest_info = dest_ty.arrayInfo(mod);
  27183         const src_info = src_ty.arrayInfo(mod);
  27184         if (dest_info.len != src_info.len) {
  27185             return InMemoryCoercionResult{ .array_len = .{
  27186                 .actual = src_info.len,
  27187                 .wanted = dest_info.len,
  27188             } };
  27189         }
  27190 
  27191         const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src);
  27192         if (child != .ok) {
  27193             return InMemoryCoercionResult{ .array_elem = .{
  27194                 .child = try child.dupe(sema.arena),
  27195                 .actual = src_info.elem_type,
  27196                 .wanted = dest_info.elem_type,
  27197             } };
  27198         }
  27199         const ok_sent = dest_info.sentinel == null or
  27200             (src_info.sentinel != null and
  27201             dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, mod));
  27202         if (!ok_sent) {
  27203             return InMemoryCoercionResult{ .array_sentinel = .{
  27204                 .actual = src_info.sentinel orelse Value.@"unreachable",
  27205                 .wanted = dest_info.sentinel orelse Value.@"unreachable",
  27206                 .ty = dest_info.elem_type,
  27207             } };
  27208         }
  27209         return .ok;
  27210     }
  27211 
  27212     // Vectors
  27213     if (dest_tag == .Vector and src_tag == .Vector) {
  27214         const dest_len = dest_ty.vectorLen(mod);
  27215         const src_len = src_ty.vectorLen(mod);
  27216         if (dest_len != src_len) {
  27217             return InMemoryCoercionResult{ .vector_len = .{
  27218                 .actual = src_len,
  27219                 .wanted = dest_len,
  27220             } };
  27221         }
  27222 
  27223         const dest_elem_ty = dest_ty.scalarType(mod);
  27224         const src_elem_ty = src_ty.scalarType(mod);
  27225         const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src);
  27226         if (child != .ok) {
  27227             return InMemoryCoercionResult{ .vector_elem = .{
  27228                 .child = try child.dupe(sema.arena),
  27229                 .actual = src_elem_ty,
  27230                 .wanted = dest_elem_ty,
  27231             } };
  27232         }
  27233 
  27234         return .ok;
  27235     }
  27236 
  27237     // Optionals
  27238     if (dest_tag == .Optional and src_tag == .Optional) {
  27239         if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) {
  27240             return InMemoryCoercionResult{ .optional_shape = .{
  27241                 .actual = src_ty,
  27242                 .wanted = dest_ty,
  27243             } };
  27244         }
  27245         const dest_child_type = dest_ty.optionalChild(mod);
  27246         const src_child_type = src_ty.optionalChild(mod);
  27247 
  27248         const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src);
  27249         if (child != .ok) {
  27250             return InMemoryCoercionResult{ .optional_child = .{
  27251                 .child = try child.dupe(sema.arena),
  27252                 .actual = src_child_type,
  27253                 .wanted = dest_child_type,
  27254             } };
  27255         }
  27256 
  27257         return .ok;
  27258     }
  27259 
  27260     return InMemoryCoercionResult{ .no_match = .{
  27261         .actual = dest_ty,
  27262         .wanted = src_ty,
  27263     } };
  27264 }
  27265 
  27266 fn coerceInMemoryAllowedErrorSets(
  27267     sema: *Sema,
  27268     block: *Block,
  27269     dest_ty: Type,
  27270     src_ty: Type,
  27271     dest_src: LazySrcLoc,
  27272     src_src: LazySrcLoc,
  27273 ) !InMemoryCoercionResult {
  27274     const mod = sema.mod;
  27275     const gpa = sema.gpa;
  27276     const ip = &mod.intern_pool;
  27277 
  27278     // Coercion to `anyerror`. Note that this check can return false negatives
  27279     // in case the error sets did not get resolved.
  27280     if (dest_ty.isAnyError(mod)) {
  27281         return .ok;
  27282     }
  27283 
  27284     if (mod.typeToInferredErrorSetIndex(dest_ty).unwrap()) |dst_ies_index| {
  27285         const dst_ies = mod.inferredErrorSetPtr(dst_ies_index);
  27286         // We will make an effort to return `ok` without resolving either error set, to
  27287         // avoid unnecessary "unable to resolve error set" dependency loop errors.
  27288         switch (src_ty.toIntern()) {
  27289             .anyerror_type => {},
  27290             else => switch (ip.indexToKey(src_ty.toIntern())) {
  27291                 .inferred_error_set_type => |src_index| {
  27292                     // If both are inferred error sets of functions, and
  27293                     // the dest includes the source function, the coercion is OK.
  27294                     // This check is important because it works without forcing a full resolution
  27295                     // of inferred error sets.
  27296                     if (dst_ies.inferred_error_sets.contains(src_index)) {
  27297                         return .ok;
  27298                     }
  27299                 },
  27300                 .error_set_type => |error_set_type| {
  27301                     for (error_set_type.names) |name| {
  27302                         if (!dst_ies.errors.contains(name)) break;
  27303                     } else return .ok;
  27304                 },
  27305                 else => unreachable,
  27306             },
  27307         }
  27308 
  27309         if (dst_ies.func == sema.owner_func_index.unwrap()) {
  27310             // We are trying to coerce an error set to the current function's
  27311             // inferred error set.
  27312             try dst_ies.addErrorSet(src_ty, ip, gpa);
  27313             return .ok;
  27314         }
  27315 
  27316         try sema.resolveInferredErrorSet(block, dest_src, dst_ies_index);
  27317         // isAnyError might have changed from a false negative to a true positive after resolution.
  27318         if (dest_ty.isAnyError(mod)) {
  27319             return .ok;
  27320         }
  27321     }
  27322 
  27323     var missing_error_buf = std.ArrayList(InternPool.NullTerminatedString).init(gpa);
  27324     defer missing_error_buf.deinit();
  27325 
  27326     switch (src_ty.toIntern()) {
  27327         .anyerror_type => switch (ip.indexToKey(dest_ty.toIntern())) {
  27328             .inferred_error_set_type => unreachable, // Caught by dest_ty.isAnyError(mod) above.
  27329             .simple_type => unreachable, // filtered out above
  27330             .error_set_type => return .from_anyerror,
  27331             else => unreachable,
  27332         },
  27333 
  27334         else => switch (ip.indexToKey(src_ty.toIntern())) {
  27335             .inferred_error_set_type => |src_index| {
  27336                 const src_data = mod.inferredErrorSetPtr(src_index);
  27337 
  27338                 try sema.resolveInferredErrorSet(block, src_src, src_index);
  27339                 // src anyerror status might have changed after the resolution.
  27340                 if (src_ty.isAnyError(mod)) {
  27341                     // dest_ty.isAnyError(mod) == true is already checked for at this point.
  27342                     return .from_anyerror;
  27343                 }
  27344 
  27345                 for (src_data.errors.keys()) |key| {
  27346                     if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), key)) {
  27347                         try missing_error_buf.append(key);
  27348                     }
  27349                 }
  27350 
  27351                 if (missing_error_buf.items.len != 0) {
  27352                     return InMemoryCoercionResult{
  27353                         .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items),
  27354                     };
  27355                 }
  27356 
  27357                 return .ok;
  27358             },
  27359             .error_set_type => |error_set_type| {
  27360                 for (error_set_type.names) |name| {
  27361                     if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), name)) {
  27362                         try missing_error_buf.append(name);
  27363                     }
  27364                 }
  27365 
  27366                 if (missing_error_buf.items.len != 0) {
  27367                     return InMemoryCoercionResult{
  27368                         .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items),
  27369                     };
  27370                 }
  27371 
  27372                 return .ok;
  27373             },
  27374             else => unreachable,
  27375         },
  27376     }
  27377 
  27378     unreachable;
  27379 }
  27380 
  27381 fn coerceInMemoryAllowedFns(
  27382     sema: *Sema,
  27383     block: *Block,
  27384     dest_ty: Type,
  27385     src_ty: Type,
  27386     target: std.Target,
  27387     dest_src: LazySrcLoc,
  27388     src_src: LazySrcLoc,
  27389 ) !InMemoryCoercionResult {
  27390     const mod = sema.mod;
  27391 
  27392     {
  27393         const dest_info = mod.typeToFunc(dest_ty).?;
  27394         const src_info = mod.typeToFunc(src_ty).?;
  27395 
  27396         if (dest_info.is_var_args != src_info.is_var_args) {
  27397             return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args };
  27398         }
  27399 
  27400         if (dest_info.is_generic != src_info.is_generic) {
  27401             return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };
  27402         }
  27403 
  27404         if (dest_info.cc != src_info.cc) {
  27405             return InMemoryCoercionResult{ .fn_cc = .{
  27406                 .actual = src_info.cc,
  27407                 .wanted = dest_info.cc,
  27408             } };
  27409         }
  27410 
  27411         if (src_info.return_type != .noreturn_type) {
  27412             const dest_return_type = dest_info.return_type.toType();
  27413             const src_return_type = src_info.return_type.toType();
  27414             const rt = try sema.coerceInMemoryAllowed(block, dest_return_type, src_return_type, false, target, dest_src, src_src);
  27415             if (rt != .ok) {
  27416                 return InMemoryCoercionResult{ .fn_return_type = .{
  27417                     .child = try rt.dupe(sema.arena),
  27418                     .actual = dest_return_type,
  27419                     .wanted = src_return_type,
  27420                 } };
  27421             }
  27422         }
  27423     }
  27424 
  27425     const params_len = params_len: {
  27426         const dest_info = mod.typeToFunc(dest_ty).?;
  27427         const src_info = mod.typeToFunc(src_ty).?;
  27428 
  27429         if (dest_info.param_types.len != src_info.param_types.len) {
  27430             return InMemoryCoercionResult{ .fn_param_count = .{
  27431                 .actual = src_info.param_types.len,
  27432                 .wanted = dest_info.param_types.len,
  27433             } };
  27434         }
  27435 
  27436         if (dest_info.noalias_bits != src_info.noalias_bits) {
  27437             return InMemoryCoercionResult{ .fn_param_noalias = .{
  27438                 .actual = src_info.noalias_bits,
  27439                 .wanted = dest_info.noalias_bits,
  27440             } };
  27441         }
  27442 
  27443         break :params_len dest_info.param_types.len;
  27444     };
  27445 
  27446     for (0..params_len) |param_i| {
  27447         const dest_info = mod.typeToFunc(dest_ty).?;
  27448         const src_info = mod.typeToFunc(src_ty).?;
  27449 
  27450         const dest_param_ty = dest_info.param_types[param_i].toType();
  27451         const src_param_ty = src_info.param_types[param_i].toType();
  27452 
  27453         const param_i_small = @intCast(u5, param_i);
  27454         if (dest_info.paramIsComptime(param_i_small) != src_info.paramIsComptime(param_i_small)) {
  27455             return InMemoryCoercionResult{ .fn_param_comptime = .{
  27456                 .index = param_i,
  27457                 .wanted = dest_info.paramIsComptime(param_i_small),
  27458             } };
  27459         }
  27460 
  27461         // Note: Cast direction is reversed here.
  27462         const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src);
  27463         if (param != .ok) {
  27464             return InMemoryCoercionResult{ .fn_param = .{
  27465                 .child = try param.dupe(sema.arena),
  27466                 .actual = src_param_ty,
  27467                 .wanted = dest_param_ty,
  27468                 .index = param_i,
  27469             } };
  27470         }
  27471     }
  27472 
  27473     return .ok;
  27474 }
  27475 
  27476 fn coerceInMemoryAllowedPtrs(
  27477     sema: *Sema,
  27478     block: *Block,
  27479     dest_ty: Type,
  27480     src_ty: Type,
  27481     dest_ptr_ty: Type,
  27482     src_ptr_ty: Type,
  27483     dest_is_mut: bool,
  27484     target: std.Target,
  27485     dest_src: LazySrcLoc,
  27486     src_src: LazySrcLoc,
  27487 ) !InMemoryCoercionResult {
  27488     const mod = sema.mod;
  27489     const dest_info = dest_ptr_ty.ptrInfo(mod);
  27490     const src_info = src_ptr_ty.ptrInfo(mod);
  27491 
  27492     const ok_ptr_size = src_info.size == dest_info.size or
  27493         src_info.size == .C or dest_info.size == .C;
  27494     if (!ok_ptr_size) {
  27495         return InMemoryCoercionResult{ .ptr_size = .{
  27496             .actual = src_info.size,
  27497             .wanted = dest_info.size,
  27498         } };
  27499     }
  27500 
  27501     const ok_cv_qualifiers =
  27502         (src_info.mutable or !dest_info.mutable) and
  27503         (!src_info.@"volatile" or dest_info.@"volatile");
  27504 
  27505     if (!ok_cv_qualifiers) {
  27506         return InMemoryCoercionResult{ .ptr_qualifiers = .{
  27507             .actual_const = !src_info.mutable,
  27508             .wanted_const = !dest_info.mutable,
  27509             .actual_volatile = src_info.@"volatile",
  27510             .wanted_volatile = dest_info.@"volatile",
  27511         } };
  27512     }
  27513 
  27514     if (dest_info.@"addrspace" != src_info.@"addrspace") {
  27515         return InMemoryCoercionResult{ .ptr_addrspace = .{
  27516             .actual = src_info.@"addrspace",
  27517             .wanted = dest_info.@"addrspace",
  27518         } };
  27519     }
  27520 
  27521     const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src);
  27522     if (child != .ok) {
  27523         return InMemoryCoercionResult{ .ptr_child = .{
  27524             .child = try child.dupe(sema.arena),
  27525             .actual = src_info.pointee_type,
  27526             .wanted = dest_info.pointee_type,
  27527         } };
  27528     }
  27529 
  27530     const dest_allow_zero = dest_ty.ptrAllowsZero(mod);
  27531     const src_allow_zero = src_ty.ptrAllowsZero(mod);
  27532 
  27533     const ok_allows_zero = (dest_allow_zero and
  27534         (src_allow_zero or !dest_is_mut)) or
  27535         (!dest_allow_zero and !src_allow_zero);
  27536     if (!ok_allows_zero) {
  27537         return InMemoryCoercionResult{ .ptr_allowzero = .{
  27538             .actual = src_ty,
  27539             .wanted = dest_ty,
  27540         } };
  27541     }
  27542 
  27543     if (src_info.host_size != dest_info.host_size or
  27544         src_info.bit_offset != dest_info.bit_offset)
  27545     {
  27546         return InMemoryCoercionResult{ .ptr_bit_range = .{
  27547             .actual_host = src_info.host_size,
  27548             .wanted_host = dest_info.host_size,
  27549             .actual_offset = src_info.bit_offset,
  27550             .wanted_offset = dest_info.bit_offset,
  27551         } };
  27552     }
  27553 
  27554     const ok_sent = dest_info.sentinel == null or src_info.size == .C or
  27555         (src_info.sentinel != null and
  27556         dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod));
  27557     if (!ok_sent) {
  27558         return InMemoryCoercionResult{ .ptr_sentinel = .{
  27559             .actual = src_info.sentinel orelse Value.@"unreachable",
  27560             .wanted = dest_info.sentinel orelse Value.@"unreachable",
  27561             .ty = dest_info.pointee_type,
  27562         } };
  27563     }
  27564 
  27565     // If both pointers have alignment 0, it means they both want ABI alignment.
  27566     // In this case, if they share the same child type, no need to resolve
  27567     // pointee type alignment. Otherwise both pointee types must have their alignment
  27568     // resolved and we compare the alignment numerically.
  27569     alignment: {
  27570         if (src_info.@"align" == 0 and dest_info.@"align" == 0 and
  27571             dest_info.pointee_type.eql(src_info.pointee_type, sema.mod))
  27572         {
  27573             break :alignment;
  27574         }
  27575 
  27576         const src_align = if (src_info.@"align" != 0)
  27577             src_info.@"align"
  27578         else
  27579             src_info.pointee_type.abiAlignment(mod);
  27580 
  27581         const dest_align = if (dest_info.@"align" != 0)
  27582             dest_info.@"align"
  27583         else
  27584             dest_info.pointee_type.abiAlignment(mod);
  27585 
  27586         if (dest_align > src_align) {
  27587             return InMemoryCoercionResult{ .ptr_alignment = .{
  27588                 .actual = src_align,
  27589                 .wanted = dest_align,
  27590             } };
  27591         }
  27592 
  27593         break :alignment;
  27594     }
  27595 
  27596     return .ok;
  27597 }
  27598 
  27599 fn coerceVarArgParam(
  27600     sema: *Sema,
  27601     block: *Block,
  27602     inst: Air.Inst.Ref,
  27603     inst_src: LazySrcLoc,
  27604 ) !Air.Inst.Ref {
  27605     if (block.is_typeof) return inst;
  27606 
  27607     const mod = sema.mod;
  27608     const uncasted_ty = sema.typeOf(inst);
  27609     const coerced = switch (uncasted_ty.zigTypeTag(mod)) {
  27610         // TODO consider casting to c_int/f64 if they fit
  27611         .ComptimeInt, .ComptimeFloat => return sema.fail(
  27612             block,
  27613             inst_src,
  27614             "integer and float literals passed to variadic function must be casted to a fixed-size number type",
  27615             .{},
  27616         ),
  27617         .Fn => blk: {
  27618             const fn_val = try sema.resolveConstValue(block, .unneeded, inst, "");
  27619             const fn_decl = fn_val.pointerDecl(mod).?;
  27620             break :blk try sema.analyzeDeclRef(fn_decl);
  27621         },
  27622         .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}),
  27623         .Float => float: {
  27624             const target = sema.mod.getTarget();
  27625             const double_bits = target.c_type_bit_size(.double);
  27626             const inst_bits = uncasted_ty.floatBits(sema.mod.getTarget());
  27627             if (inst_bits >= double_bits) break :float inst;
  27628             switch (double_bits) {
  27629                 32 => break :float try sema.coerce(block, Type.f32, inst, inst_src),
  27630                 64 => break :float try sema.coerce(block, Type.f64, inst, inst_src),
  27631                 else => unreachable,
  27632             }
  27633         },
  27634         else => inst,
  27635     };
  27636 
  27637     const coerced_ty = sema.typeOf(coerced);
  27638     if (!try sema.validateExternType(coerced_ty, .param_ty)) {
  27639         const msg = msg: {
  27640             const msg = try sema.errMsg(block, inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(sema.mod)});
  27641             errdefer msg.destroy(sema.gpa);
  27642 
  27643             const src_decl = sema.mod.declPtr(block.src_decl);
  27644             try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl, mod), coerced_ty, .param_ty);
  27645 
  27646             try sema.addDeclaredHereNote(msg, coerced_ty);
  27647             break :msg msg;
  27648         };
  27649         return sema.failWithOwnedErrorMsg(msg);
  27650     }
  27651     return coerced;
  27652 }
  27653 
  27654 // TODO migrate callsites to use storePtr2 instead.
  27655 fn storePtr(
  27656     sema: *Sema,
  27657     block: *Block,
  27658     src: LazySrcLoc,
  27659     ptr: Air.Inst.Ref,
  27660     uncasted_operand: Air.Inst.Ref,
  27661 ) CompileError!void {
  27662     const air_tag: Air.Inst.Tag = if (block.wantSafety()) .store_safe else .store;
  27663     return sema.storePtr2(block, src, ptr, src, uncasted_operand, src, air_tag);
  27664 }
  27665 
  27666 fn storePtr2(
  27667     sema: *Sema,
  27668     block: *Block,
  27669     src: LazySrcLoc,
  27670     ptr: Air.Inst.Ref,
  27671     ptr_src: LazySrcLoc,
  27672     uncasted_operand: Air.Inst.Ref,
  27673     operand_src: LazySrcLoc,
  27674     air_tag: Air.Inst.Tag,
  27675 ) CompileError!void {
  27676     const mod = sema.mod;
  27677     const ptr_ty = sema.typeOf(ptr);
  27678     if (ptr_ty.isConstPtr(mod))
  27679         return sema.fail(block, ptr_src, "cannot assign to constant", .{});
  27680 
  27681     const elem_ty = ptr_ty.childType(mod);
  27682 
  27683     // To generate better code for tuples, we detect a tuple operand here, and
  27684     // analyze field loads and stores directly. This avoids an extra allocation + memcpy
  27685     // which would occur if we used `coerce`.
  27686     // However, we avoid this mechanism if the destination element type is a tuple,
  27687     // because the regular store will be better for this case.
  27688     // If the destination type is a struct we don't want this mechanism to trigger, because
  27689     // this code does not handle tuple-to-struct coercion which requires dealing with missing
  27690     // fields.
  27691     const operand_ty = sema.typeOf(uncasted_operand);
  27692     if (operand_ty.isTuple(mod) and elem_ty.zigTypeTag(mod) == .Array) {
  27693         const field_count = operand_ty.structFieldCount(mod);
  27694         var i: u32 = 0;
  27695         while (i < field_count) : (i += 1) {
  27696             const elem_src = operand_src; // TODO better source location
  27697             const elem = try sema.tupleField(block, operand_src, uncasted_operand, elem_src, i);
  27698             const elem_index = try sema.addIntUnsigned(Type.usize, i);
  27699             const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src, false, true);
  27700             try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store);
  27701         }
  27702         return;
  27703     }
  27704 
  27705     // TODO do the same thing for anon structs as for tuples above.
  27706     // However, beware of the need to handle missing/extra fields.
  27707 
  27708     const is_ret = air_tag == .ret_ptr;
  27709 
  27710     // Detect if we are storing an array operand to a bitcasted vector pointer.
  27711     // If so, we instead reach through the bitcasted pointer to the vector pointer,
  27712     // bitcast the array operand to a vector, and then lower this as a store of
  27713     // a vector value to a vector pointer. This generally results in better code,
  27714     // as well as working around an LLVM bug:
  27715     // https://github.com/ziglang/zig/issues/11154
  27716     if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| {
  27717         const vector_ty = sema.typeOf(vector_ptr).childType(mod);
  27718         const vector = sema.coerceExtra(block, vector_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) {
  27719             error.NotCoercible => unreachable,
  27720             else => |e| return e,
  27721         };
  27722         try sema.storePtr2(block, src, vector_ptr, ptr_src, vector, operand_src, .store);
  27723         return;
  27724     }
  27725 
  27726     const operand = sema.coerceExtra(block, elem_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) {
  27727         error.NotCoercible => unreachable,
  27728         else => |e| return e,
  27729     };
  27730     const maybe_operand_val = try sema.resolveMaybeUndefVal(operand);
  27731 
  27732     const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
  27733         const operand_val = maybe_operand_val orelse {
  27734             try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);
  27735             break :rs operand_src;
  27736         };
  27737         if (ptr_val.isComptimeMutablePtr(mod)) {
  27738             try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty);
  27739             return;
  27740         } else break :rs ptr_src;
  27741     } else ptr_src;
  27742 
  27743     // We do this after the possible comptime store above, for the case of field_ptr stores
  27744     // to unions because we want the comptime tag to be set, even if the field type is void.
  27745     if ((try sema.typeHasOnePossibleValue(elem_ty)) != null)
  27746         return;
  27747 
  27748     if (air_tag == .bitcast) {
  27749         // `air_tag == .bitcast` is used as a special case for `zirCoerceResultPtr`
  27750         // to avoid calling `requireRuntimeBlock` for the dummy block.
  27751         _ = try block.addBinOp(.store, ptr, operand);
  27752         return;
  27753     }
  27754 
  27755     try sema.requireRuntimeBlock(block, src, runtime_src);
  27756     try sema.queueFullTypeResolution(elem_ty);
  27757 
  27758     if (ptr_ty.ptrInfo(mod).vector_index == .runtime) {
  27759         const ptr_inst = Air.refToIndex(ptr).?;
  27760         const air_tags = sema.air_instructions.items(.tag);
  27761         if (air_tags[ptr_inst] == .ptr_elem_ptr) {
  27762             const ty_pl = sema.air_instructions.items(.data)[ptr_inst].ty_pl;
  27763             const bin_op = sema.getTmpAir().extraData(Air.Bin, ty_pl.payload).data;
  27764             _ = try block.addInst(.{
  27765                 .tag = .vector_store_elem,
  27766                 .data = .{ .vector_store_elem = .{
  27767                     .vector_ptr = bin_op.lhs,
  27768                     .payload = try block.sema.addExtra(Air.Bin{
  27769                         .lhs = bin_op.rhs,
  27770                         .rhs = operand,
  27771                     }),
  27772                 } },
  27773             });
  27774             return;
  27775         }
  27776         return sema.fail(block, ptr_src, "unable to determine vector element index of type '{}'", .{
  27777             ptr_ty.fmt(sema.mod),
  27778         });
  27779     }
  27780 
  27781     if (is_ret) {
  27782         _ = try block.addBinOp(.store, ptr, operand);
  27783     } else {
  27784         _ = try block.addBinOp(air_tag, ptr, operand);
  27785     }
  27786 }
  27787 
  27788 /// Traverse an arbitrary number of bitcasted pointers and return the underyling vector
  27789 /// pointer. Only if the final element type matches the vector element type, and the
  27790 /// lengths match.
  27791 fn obtainBitCastedVectorPtr(sema: *Sema, ptr: Air.Inst.Ref) ?Air.Inst.Ref {
  27792     const mod = sema.mod;
  27793     const array_ty = sema.typeOf(ptr).childType(mod);
  27794     if (array_ty.zigTypeTag(mod) != .Array) return null;
  27795     var ptr_ref = ptr;
  27796     var ptr_inst = Air.refToIndex(ptr_ref) orelse return null;
  27797     const air_datas = sema.air_instructions.items(.data);
  27798     const air_tags = sema.air_instructions.items(.tag);
  27799     const vector_ty = while (air_tags[ptr_inst] == .bitcast) {
  27800         ptr_ref = air_datas[ptr_inst].ty_op.operand;
  27801         if (!sema.isKnownZigType(ptr_ref, .Pointer)) return null;
  27802         const child_ty = sema.typeOf(ptr_ref).childType(mod);
  27803         if (child_ty.zigTypeTag(mod) == .Vector) break child_ty;
  27804         ptr_inst = Air.refToIndex(ptr_ref) orelse return null;
  27805     } else return null;
  27806 
  27807     // We have a pointer-to-array and a pointer-to-vector. If the elements and
  27808     // lengths match, return the result.
  27809     if (array_ty.childType(mod).eql(vector_ty.childType(mod), sema.mod) and
  27810         array_ty.arrayLen(mod) == vector_ty.vectorLen(mod))
  27811     {
  27812         return ptr_ref;
  27813     } else {
  27814         return null;
  27815     }
  27816 }
  27817 
  27818 /// Call when you have Value objects rather than Air instructions, and you want to
  27819 /// assert the store must be done at comptime.
  27820 fn storePtrVal(
  27821     sema: *Sema,
  27822     block: *Block,
  27823     src: LazySrcLoc,
  27824     ptr_val: Value,
  27825     operand_val: Value,
  27826     operand_ty: Type,
  27827 ) !void {
  27828     const mod = sema.mod;
  27829     var mut_kit = try sema.beginComptimePtrMutation(block, src, ptr_val, operand_ty);
  27830     try sema.checkComptimeVarStore(block, src, mut_kit.mut_decl);
  27831 
  27832     switch (mut_kit.pointee) {
  27833         .direct => |val_ptr| {
  27834             if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) {
  27835                 if (!operand_val.eql(val_ptr.*, operand_ty, mod)) {
  27836                     // TODO use failWithInvalidComptimeFieldStore
  27837                     return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{});
  27838                 }
  27839                 return;
  27840             }
  27841             val_ptr.* = (try operand_val.intern(operand_ty, mod)).toValue();
  27842         },
  27843         .reinterpret => |reinterpret| {
  27844             const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod));
  27845             const buffer = try sema.gpa.alloc(u8, abi_size);
  27846             defer sema.gpa.free(buffer);
  27847             reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, mod, buffer) catch |err| switch (err) {
  27848                 error.OutOfMemory => return error.OutOfMemory,
  27849                 error.ReinterpretDeclRef => unreachable,
  27850                 error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already
  27851                 error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(mod)}),
  27852             };
  27853             operand_val.writeToMemory(operand_ty, mod, buffer[reinterpret.byte_offset..]) catch |err| switch (err) {
  27854                 error.OutOfMemory => return error.OutOfMemory,
  27855                 error.ReinterpretDeclRef => unreachable,
  27856                 error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already
  27857                 error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(mod)}),
  27858             };
  27859 
  27860             const arena = mut_kit.beginArena(mod);
  27861             defer mut_kit.finishArena(mod);
  27862 
  27863             reinterpret.val_ptr.* = (try (try Value.readFromMemory(mut_kit.ty, mod, buffer, arena)).intern(mut_kit.ty, mod)).toValue();
  27864         },
  27865         .bad_decl_ty, .bad_ptr_ty => {
  27866             // TODO show the decl declaration site in a note and explain whether the decl
  27867             // or the pointer is the problematic type
  27868             return sema.fail(block, src, "comptime mutation of a reinterpreted pointer requires type '{}' to have a well-defined memory layout", .{mut_kit.ty.fmt(mod)});
  27869         },
  27870     }
  27871 }
  27872 
  27873 const ComptimePtrMutationKit = struct {
  27874     mut_decl: InternPool.Key.Ptr.Addr.MutDecl,
  27875     pointee: union(enum) {
  27876         /// The pointer type matches the actual comptime Value so a direct
  27877         /// modification is possible.
  27878         direct: *Value,
  27879         /// The largest parent Value containing pointee and having a well-defined memory layout.
  27880         /// This is used for bitcasting, if direct dereferencing failed.
  27881         reinterpret: struct {
  27882             val_ptr: *Value,
  27883             byte_offset: usize,
  27884         },
  27885         /// If the root decl could not be used as parent, this means `ty` is the type that
  27886         /// caused that by not having a well-defined layout.
  27887         /// This one means the Decl that owns the value trying to be modified does not
  27888         /// have a well defined memory layout.
  27889         bad_decl_ty,
  27890         /// If the root decl could not be used as parent, this means `ty` is the type that
  27891         /// caused that by not having a well-defined layout.
  27892         /// This one means the pointer type that is being stored through does not
  27893         /// have a well defined memory layout.
  27894         bad_ptr_ty,
  27895     },
  27896     ty: Type,
  27897     decl_arena: std.heap.ArenaAllocator = undefined,
  27898 
  27899     fn beginArena(self: *ComptimePtrMutationKit, mod: *Module) Allocator {
  27900         const decl = mod.declPtr(self.mut_decl.decl);
  27901         return decl.value_arena.?.acquire(mod.gpa, &self.decl_arena);
  27902     }
  27903 
  27904     fn finishArena(self: *ComptimePtrMutationKit, mod: *Module) void {
  27905         const decl = mod.declPtr(self.mut_decl.decl);
  27906         decl.value_arena.?.release(&self.decl_arena);
  27907         self.decl_arena = undefined;
  27908     }
  27909 };
  27910 
  27911 fn beginComptimePtrMutation(
  27912     sema: *Sema,
  27913     block: *Block,
  27914     src: LazySrcLoc,
  27915     ptr_val: Value,
  27916     ptr_elem_ty: Type,
  27917 ) CompileError!ComptimePtrMutationKit {
  27918     const mod = sema.mod;
  27919     const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
  27920     switch (ptr.addr) {
  27921         .decl, .int => unreachable, // isComptimeMutablePtr has been checked already
  27922         .mut_decl => |mut_decl| {
  27923             const decl = mod.declPtr(mut_decl.decl);
  27924             return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl);
  27925         },
  27926         .comptime_field => |comptime_field| {
  27927             const duped = try sema.arena.create(Value);
  27928             duped.* = comptime_field.toValue();
  27929             return sema.beginComptimePtrMutationInner(block, src, mod.intern_pool.typeOf(comptime_field).toType(), duped, ptr_elem_ty, .{
  27930                 .decl = undefined,
  27931                 .runtime_index = .comptime_field_ptr,
  27932             });
  27933         },
  27934         .eu_payload => |eu_ptr| {
  27935             const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod);
  27936             var parent = try sema.beginComptimePtrMutation(block, src, eu_ptr.toValue(), eu_ty);
  27937             switch (parent.pointee) {
  27938                 .direct => |val_ptr| {
  27939                     const payload_ty = parent.ty.errorUnionPayload(mod);
  27940                     if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) {
  27941                         return ComptimePtrMutationKit{
  27942                             .mut_decl = parent.mut_decl,
  27943                             .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data },
  27944                             .ty = payload_ty,
  27945                         };
  27946                     } else {
  27947                         // An error union has been initialized to undefined at comptime and now we
  27948                         // are for the first time setting the payload. We must change the
  27949                         // representation of the error union from `undef` to `opt_payload`.
  27950                         const arena = parent.beginArena(sema.mod);
  27951                         defer parent.finishArena(sema.mod);
  27952 
  27953                         const payload = try arena.create(Value.Payload.SubValue);
  27954                         payload.* = .{
  27955                             .base = .{ .tag = .eu_payload },
  27956                             .data = (try mod.intern(.{ .undef = payload_ty.toIntern() })).toValue(),
  27957                         };
  27958 
  27959                         val_ptr.* = Value.initPayload(&payload.base);
  27960 
  27961                         return ComptimePtrMutationKit{
  27962                             .mut_decl = parent.mut_decl,
  27963                             .pointee = .{ .direct = &payload.data },
  27964                             .ty = payload_ty,
  27965                         };
  27966                     }
  27967                 },
  27968                 .bad_decl_ty, .bad_ptr_ty => return parent,
  27969                 // Even though the parent value type has well-defined memory layout, our
  27970                 // pointer type does not.
  27971                 .reinterpret => return ComptimePtrMutationKit{
  27972                     .mut_decl = parent.mut_decl,
  27973                     .pointee = .bad_ptr_ty,
  27974                     .ty = eu_ty,
  27975                 },
  27976             }
  27977         },
  27978         .opt_payload => |opt_ptr| {
  27979             const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod);
  27980             var parent = try sema.beginComptimePtrMutation(block, src, opt_ptr.toValue(), opt_ty);
  27981             switch (parent.pointee) {
  27982                 .direct => |val_ptr| {
  27983                     const payload_ty = parent.ty.optionalChild(mod);
  27984                     switch (val_ptr.ip_index) {
  27985                         .none => return ComptimePtrMutationKit{
  27986                             .mut_decl = parent.mut_decl,
  27987                             .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data },
  27988                             .ty = payload_ty,
  27989                         },
  27990                         else => {
  27991                             const payload_val = switch (mod.intern_pool.indexToKey(val_ptr.ip_index)) {
  27992                                 .undef => try mod.intern(.{ .undef = payload_ty.toIntern() }),
  27993                                 .opt => |opt| switch (opt.val) {
  27994                                     .none => try mod.intern(.{ .undef = payload_ty.toIntern() }),
  27995                                     else => |payload| payload,
  27996                                 },
  27997                                 else => unreachable,
  27998                             };
  27999 
  28000                             // An optional has been initialized to undefined at comptime and now we
  28001                             // are for the first time setting the payload. We must change the
  28002                             // representation of the optional from `undef` to `opt_payload`.
  28003                             const arena = parent.beginArena(sema.mod);
  28004                             defer parent.finishArena(sema.mod);
  28005 
  28006                             const payload = try arena.create(Value.Payload.SubValue);
  28007                             payload.* = .{
  28008                                 .base = .{ .tag = .opt_payload },
  28009                                 .data = payload_val.toValue(),
  28010                             };
  28011 
  28012                             val_ptr.* = Value.initPayload(&payload.base);
  28013 
  28014                             return ComptimePtrMutationKit{
  28015                                 .mut_decl = parent.mut_decl,
  28016                                 .pointee = .{ .direct = &payload.data },
  28017                                 .ty = payload_ty,
  28018                             };
  28019                         },
  28020                     }
  28021                 },
  28022                 .bad_decl_ty, .bad_ptr_ty => return parent,
  28023                 // Even though the parent value type has well-defined memory layout, our
  28024                 // pointer type does not.
  28025                 .reinterpret => return ComptimePtrMutationKit{
  28026                     .mut_decl = parent.mut_decl,
  28027                     .pointee = .bad_ptr_ty,
  28028                     .ty = opt_ty,
  28029                 },
  28030             }
  28031         },
  28032         .elem => |elem_ptr| {
  28033             const base_elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod);
  28034             var parent = try sema.beginComptimePtrMutation(block, src, elem_ptr.base.toValue(), base_elem_ty);
  28035 
  28036             switch (parent.pointee) {
  28037                 .direct => |val_ptr| switch (parent.ty.zigTypeTag(mod)) {
  28038                     .Array, .Vector => {
  28039                         const check_len = parent.ty.arrayLenIncludingSentinel(mod);
  28040                         if (elem_ptr.index >= check_len) {
  28041                             // TODO have the parent include the decl so we can say "declared here"
  28042                             return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{
  28043                                 elem_ptr.index, check_len,
  28044                             });
  28045                         }
  28046                         const elem_ty = parent.ty.childType(mod);
  28047 
  28048                         // We might have a pointer to multiple elements of the array (e.g. a pointer
  28049                         // to a sub-array). In this case, we just have to reinterpret the relevant
  28050                         // bytes of the whole array rather than any single element.
  28051                         const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty);
  28052                         if (elem_abi_size_u64 < try sema.typeAbiSize(ptr_elem_ty)) {
  28053                             const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
  28054                             return .{
  28055                                 .mut_decl = parent.mut_decl,
  28056                                 .pointee = .{ .reinterpret = .{
  28057                                     .val_ptr = val_ptr,
  28058                                     .byte_offset = elem_abi_size * elem_ptr.index,
  28059                                 } },
  28060                                 .ty = parent.ty,
  28061                             };
  28062                         }
  28063 
  28064                         switch (val_ptr.ip_index) {
  28065                             .none => switch (val_ptr.tag()) {
  28066                                 .bytes => {
  28067                                     // An array is memory-optimized to store a slice of bytes, but we are about
  28068                                     // to modify an individual field and the representation has to change.
  28069                                     // If we wanted to avoid this, there would need to be special detection
  28070                                     // elsewhere to identify when writing a value to an array element that is stored
  28071                                     // using the `bytes` tag, and handle it without making a call to this function.
  28072                                     const arena = parent.beginArena(sema.mod);
  28073                                     defer parent.finishArena(sema.mod);
  28074 
  28075                                     const bytes = val_ptr.castTag(.bytes).?.data;
  28076                                     const dest_len = parent.ty.arrayLenIncludingSentinel(mod);
  28077                                     // bytes.len may be one greater than dest_len because of the case when
  28078                                     // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted.
  28079                                     assert(bytes.len >= dest_len);
  28080                                     const elems = try arena.alloc(Value, @intCast(usize, dest_len));
  28081                                     for (elems, 0..) |*elem, i| {
  28082                                         elem.* = try mod.intValue(elem_ty, bytes[i]);
  28083                                     }
  28084 
  28085                                     val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
  28086 
  28087                                     return beginComptimePtrMutationInner(
  28088                                         sema,
  28089                                         block,
  28090                                         src,
  28091                                         elem_ty,
  28092                                         &elems[elem_ptr.index],
  28093                                         ptr_elem_ty,
  28094                                         parent.mut_decl,
  28095                                     );
  28096                                 },
  28097                                 .repeated => {
  28098                                     // An array is memory-optimized to store only a single element value, and
  28099                                     // that value is understood to be the same for the entire length of the array.
  28100                                     // However, now we want to modify an individual field and so the
  28101                                     // representation has to change.  If we wanted to avoid this, there would
  28102                                     // need to be special detection elsewhere to identify when writing a value to an
  28103                                     // array element that is stored using the `repeated` tag, and handle it
  28104                                     // without making a call to this function.
  28105                                     const arena = parent.beginArena(sema.mod);
  28106                                     defer parent.finishArena(sema.mod);
  28107 
  28108                                     const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena);
  28109                                     const array_len_including_sentinel =
  28110                                         try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));
  28111                                     const elems = try arena.alloc(Value, array_len_including_sentinel);
  28112                                     if (elems.len > 0) elems[0] = repeated_val;
  28113                                     for (elems[1..]) |*elem| {
  28114                                         elem.* = try repeated_val.copy(arena);
  28115                                     }
  28116 
  28117                                     val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
  28118 
  28119                                     return beginComptimePtrMutationInner(
  28120                                         sema,
  28121                                         block,
  28122                                         src,
  28123                                         elem_ty,
  28124                                         &elems[elem_ptr.index],
  28125                                         ptr_elem_ty,
  28126                                         parent.mut_decl,
  28127                                     );
  28128                                 },
  28129 
  28130                                 .aggregate => return beginComptimePtrMutationInner(
  28131                                     sema,
  28132                                     block,
  28133                                     src,
  28134                                     elem_ty,
  28135                                     &val_ptr.castTag(.aggregate).?.data[elem_ptr.index],
  28136                                     ptr_elem_ty,
  28137                                     parent.mut_decl,
  28138                                 ),
  28139 
  28140                                 else => unreachable,
  28141                             },
  28142                             else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) {
  28143                                 .undef => {
  28144                                     // An array has been initialized to undefined at comptime and now we
  28145                                     // are for the first time setting an element. We must change the representation
  28146                                     // of the array from `undef` to `array`.
  28147                                     const arena = parent.beginArena(sema.mod);
  28148                                     defer parent.finishArena(sema.mod);
  28149 
  28150                                     const array_len_including_sentinel =
  28151                                         try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));
  28152                                     const elems = try arena.alloc(Value, array_len_including_sentinel);
  28153                                     @memset(elems, (try mod.intern(.{ .undef = elem_ty.toIntern() })).toValue());
  28154 
  28155                                     val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
  28156 
  28157                                     return beginComptimePtrMutationInner(
  28158                                         sema,
  28159                                         block,
  28160                                         src,
  28161                                         elem_ty,
  28162                                         &elems[elem_ptr.index],
  28163                                         ptr_elem_ty,
  28164                                         parent.mut_decl,
  28165                                     );
  28166                                 },
  28167                                 else => unreachable,
  28168                             },
  28169                         }
  28170                     },
  28171                     else => {
  28172                         if (elem_ptr.index != 0) {
  28173                             // TODO include a "declared here" note for the decl
  28174                             return sema.fail(block, src, "out of bounds comptime store of index {d}", .{
  28175                                 elem_ptr.index,
  28176                             });
  28177                         }
  28178                         return beginComptimePtrMutationInner(
  28179                             sema,
  28180                             block,
  28181                             src,
  28182                             parent.ty,
  28183                             val_ptr,
  28184                             ptr_elem_ty,
  28185                             parent.mut_decl,
  28186                         );
  28187                     },
  28188                 },
  28189                 .reinterpret => |reinterpret| {
  28190                     if (!base_elem_ty.hasWellDefinedLayout(mod)) {
  28191                         // Even though the parent value type has well-defined memory layout, our
  28192                         // pointer type does not.
  28193                         return ComptimePtrMutationKit{
  28194                             .mut_decl = parent.mut_decl,
  28195                             .pointee = .bad_ptr_ty,
  28196                             .ty = base_elem_ty,
  28197                         };
  28198                     }
  28199 
  28200                     const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty);
  28201                     const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
  28202                     return ComptimePtrMutationKit{
  28203                         .mut_decl = parent.mut_decl,
  28204                         .pointee = .{ .reinterpret = .{
  28205                             .val_ptr = reinterpret.val_ptr,
  28206                             .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_ptr.index,
  28207                         } },
  28208                         .ty = parent.ty,
  28209                     };
  28210                 },
  28211                 .bad_decl_ty, .bad_ptr_ty => return parent,
  28212             }
  28213         },
  28214         .field => |field_ptr| {
  28215             const base_child_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod);
  28216             const field_index = @intCast(u32, field_ptr.index);
  28217 
  28218             var parent = try sema.beginComptimePtrMutation(block, src, field_ptr.base.toValue(), base_child_ty);
  28219             switch (parent.pointee) {
  28220                 .direct => |val_ptr| switch (val_ptr.ip_index) {
  28221                     .empty_struct => {
  28222                         const duped = try sema.arena.create(Value);
  28223                         duped.* = val_ptr.*;
  28224                         return beginComptimePtrMutationInner(
  28225                             sema,
  28226                             block,
  28227                             src,
  28228                             parent.ty.structFieldType(field_index, mod),
  28229                             duped,
  28230                             ptr_elem_ty,
  28231                             parent.mut_decl,
  28232                         );
  28233                     },
  28234                     .none => switch (val_ptr.tag()) {
  28235                         .aggregate => return beginComptimePtrMutationInner(
  28236                             sema,
  28237                             block,
  28238                             src,
  28239                             parent.ty.structFieldType(field_index, mod),
  28240                             &val_ptr.castTag(.aggregate).?.data[field_index],
  28241                             ptr_elem_ty,
  28242                             parent.mut_decl,
  28243                         ),
  28244                         .repeated => {
  28245                             const arena = parent.beginArena(sema.mod);
  28246                             defer parent.finishArena(sema.mod);
  28247 
  28248                             const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod));
  28249                             @memset(elems, val_ptr.castTag(.repeated).?.data);
  28250                             val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
  28251 
  28252                             return beginComptimePtrMutationInner(
  28253                                 sema,
  28254                                 block,
  28255                                 src,
  28256                                 parent.ty.structFieldType(field_index, mod),
  28257                                 &elems[field_index],
  28258                                 ptr_elem_ty,
  28259                                 parent.mut_decl,
  28260                             );
  28261                         },
  28262                         .@"union" => {
  28263                             // We need to set the active field of the union.
  28264                             const union_tag_ty = base_child_ty.unionTagTypeHypothetical(mod);
  28265 
  28266                             const payload = &val_ptr.castTag(.@"union").?.data;
  28267                             payload.tag = try mod.enumValueFieldIndex(union_tag_ty, field_index);
  28268 
  28269                             return beginComptimePtrMutationInner(
  28270                                 sema,
  28271                                 block,
  28272                                 src,
  28273                                 parent.ty.structFieldType(field_index, mod),
  28274                                 &payload.val,
  28275                                 ptr_elem_ty,
  28276                                 parent.mut_decl,
  28277                             );
  28278                         },
  28279                         .slice => switch (field_index) {
  28280                             Value.slice_ptr_index => return beginComptimePtrMutationInner(
  28281                                 sema,
  28282                                 block,
  28283                                 src,
  28284                                 parent.ty.slicePtrFieldType(mod),
  28285                                 &val_ptr.castTag(.slice).?.data.ptr,
  28286                                 ptr_elem_ty,
  28287                                 parent.mut_decl,
  28288                             ),
  28289 
  28290                             Value.slice_len_index => return beginComptimePtrMutationInner(
  28291                                 sema,
  28292                                 block,
  28293                                 src,
  28294                                 Type.usize,
  28295                                 &val_ptr.castTag(.slice).?.data.len,
  28296                                 ptr_elem_ty,
  28297                                 parent.mut_decl,
  28298                             ),
  28299 
  28300                             else => unreachable,
  28301                         },
  28302                         else => unreachable,
  28303                     },
  28304                     else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) {
  28305                         .undef => {
  28306                             // A struct or union has been initialized to undefined at comptime and now we
  28307                             // are for the first time setting a field. We must change the representation
  28308                             // of the struct/union from `undef` to `struct`/`union`.
  28309                             const arena = parent.beginArena(sema.mod);
  28310                             defer parent.finishArena(sema.mod);
  28311 
  28312                             switch (parent.ty.zigTypeTag(mod)) {
  28313                                 .Struct => {
  28314                                     const fields = try arena.alloc(Value, parent.ty.structFieldCount(mod));
  28315                                     for (fields, 0..) |*field, i| field.* = (try mod.intern(.{
  28316                                         .undef = parent.ty.structFieldType(i, mod).toIntern(),
  28317                                     })).toValue();
  28318 
  28319                                     val_ptr.* = try Value.Tag.aggregate.create(arena, fields);
  28320 
  28321                                     return beginComptimePtrMutationInner(
  28322                                         sema,
  28323                                         block,
  28324                                         src,
  28325                                         parent.ty.structFieldType(field_index, mod),
  28326                                         &fields[field_index],
  28327                                         ptr_elem_ty,
  28328                                         parent.mut_decl,
  28329                                     );
  28330                                 },
  28331                                 .Union => {
  28332                                     const payload = try arena.create(Value.Payload.Union);
  28333                                     const tag_ty = parent.ty.unionTagTypeHypothetical(mod);
  28334                                     const payload_ty = parent.ty.structFieldType(field_index, mod);
  28335                                     payload.* = .{ .data = .{
  28336                                         .tag = try mod.enumValueFieldIndex(tag_ty, field_index),
  28337                                         .val = (try mod.intern(.{ .undef = payload_ty.toIntern() })).toValue(),
  28338                                     } };
  28339 
  28340                                     val_ptr.* = Value.initPayload(&payload.base);
  28341 
  28342                                     return beginComptimePtrMutationInner(
  28343                                         sema,
  28344                                         block,
  28345                                         src,
  28346                                         payload_ty,
  28347                                         &payload.data.val,
  28348                                         ptr_elem_ty,
  28349                                         parent.mut_decl,
  28350                                     );
  28351                                 },
  28352                                 .Pointer => {
  28353                                     assert(parent.ty.isSlice(mod));
  28354                                     const ptr_ty = parent.ty.slicePtrFieldType(mod);
  28355                                     val_ptr.* = try Value.Tag.slice.create(arena, .{
  28356                                         .ptr = (try mod.intern(.{ .undef = ptr_ty.toIntern() })).toValue(),
  28357                                         .len = (try mod.intern(.{ .undef = .usize_type })).toValue(),
  28358                                     });
  28359 
  28360                                     switch (field_index) {
  28361                                         Value.slice_ptr_index => return beginComptimePtrMutationInner(
  28362                                             sema,
  28363                                             block,
  28364                                             src,
  28365                                             ptr_ty,
  28366                                             &val_ptr.castTag(.slice).?.data.ptr,
  28367                                             ptr_elem_ty,
  28368                                             parent.mut_decl,
  28369                                         ),
  28370                                         Value.slice_len_index => return beginComptimePtrMutationInner(
  28371                                             sema,
  28372                                             block,
  28373                                             src,
  28374                                             Type.usize,
  28375                                             &val_ptr.castTag(.slice).?.data.len,
  28376                                             ptr_elem_ty,
  28377                                             parent.mut_decl,
  28378                                         ),
  28379 
  28380                                         else => unreachable,
  28381                                     }
  28382                                 },
  28383                                 else => unreachable,
  28384                             }
  28385                         },
  28386                         else => unreachable,
  28387                     },
  28388                 },
  28389                 .reinterpret => |reinterpret| {
  28390                     const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod);
  28391                     const field_offset = try sema.usizeCast(block, src, field_offset_u64);
  28392                     return ComptimePtrMutationKit{
  28393                         .mut_decl = parent.mut_decl,
  28394                         .pointee = .{ .reinterpret = .{
  28395                             .val_ptr = reinterpret.val_ptr,
  28396                             .byte_offset = reinterpret.byte_offset + field_offset,
  28397                         } },
  28398                         .ty = parent.ty,
  28399                     };
  28400                 },
  28401                 .bad_decl_ty, .bad_ptr_ty => return parent,
  28402             }
  28403         },
  28404     }
  28405 }
  28406 
  28407 fn beginComptimePtrMutationInner(
  28408     sema: *Sema,
  28409     block: *Block,
  28410     src: LazySrcLoc,
  28411     decl_ty: Type,
  28412     decl_val: *Value,
  28413     ptr_elem_ty: Type,
  28414     mut_decl: InternPool.Key.Ptr.Addr.MutDecl,
  28415 ) CompileError!ComptimePtrMutationKit {
  28416     const mod = sema.mod;
  28417     const target = mod.getTarget();
  28418     const coerce_ok = (try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_ty, true, target, src, src)) == .ok;
  28419 
  28420     const decl = mod.declPtr(mut_decl.decl);
  28421     var decl_arena: std.heap.ArenaAllocator = undefined;
  28422     const allocator = decl.value_arena.?.acquire(sema.gpa, &decl_arena);
  28423     defer decl.value_arena.?.release(&decl_arena);
  28424     decl_val.* = try decl_val.unintern(allocator, mod);
  28425 
  28426     if (coerce_ok) {
  28427         return ComptimePtrMutationKit{
  28428             .mut_decl = mut_decl,
  28429             .pointee = .{ .direct = decl_val },
  28430             .ty = decl_ty,
  28431         };
  28432     }
  28433 
  28434     // Handle the case that the decl is an array and we're actually trying to point to an element.
  28435     if (decl_ty.isArrayOrVector(mod)) {
  28436         const decl_elem_ty = decl_ty.childType(mod);
  28437         if ((try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_elem_ty, true, target, src, src)) == .ok) {
  28438             return ComptimePtrMutationKit{
  28439                 .mut_decl = mut_decl,
  28440                 .pointee = .{ .direct = decl_val },
  28441                 .ty = decl_ty,
  28442             };
  28443         }
  28444     }
  28445 
  28446     if (!decl_ty.hasWellDefinedLayout(mod)) {
  28447         return ComptimePtrMutationKit{
  28448             .mut_decl = mut_decl,
  28449             .pointee = .bad_decl_ty,
  28450             .ty = decl_ty,
  28451         };
  28452     }
  28453     if (!ptr_elem_ty.hasWellDefinedLayout(mod)) {
  28454         return ComptimePtrMutationKit{
  28455             .mut_decl = mut_decl,
  28456             .pointee = .bad_ptr_ty,
  28457             .ty = ptr_elem_ty,
  28458         };
  28459     }
  28460     return ComptimePtrMutationKit{
  28461         .mut_decl = mut_decl,
  28462         .pointee = .{ .reinterpret = .{
  28463             .val_ptr = decl_val,
  28464             .byte_offset = 0,
  28465         } },
  28466         .ty = decl_ty,
  28467     };
  28468 }
  28469 
  28470 const TypedValueAndOffset = struct {
  28471     tv: TypedValue,
  28472     byte_offset: usize,
  28473 };
  28474 
  28475 const ComptimePtrLoadKit = struct {
  28476     /// The Value and Type corresponding to the pointee of the provided pointer.
  28477     /// If a direct dereference is not possible, this is null.
  28478     pointee: ?TypedValue,
  28479     /// The largest parent Value containing `pointee` and having a well-defined memory layout.
  28480     /// This is used for bitcasting, if direct dereferencing failed (i.e. `pointee` is null).
  28481     parent: ?TypedValueAndOffset,
  28482     /// Whether the `pointee` could be mutated by further
  28483     /// semantic analysis and a copy must be performed.
  28484     is_mutable: bool,
  28485     /// If the root decl could not be used as `parent`, this is the type that
  28486     /// caused that by not having a well-defined layout
  28487     ty_without_well_defined_layout: ?Type,
  28488 };
  28489 
  28490 const ComptimePtrLoadError = CompileError || error{
  28491     RuntimeLoad,
  28492 };
  28493 
  28494 /// If `maybe_array_ty` is provided, it will be used to directly dereference an
  28495 /// .elem_ptr of type T to a value of [N]T, if necessary.
  28496 fn beginComptimePtrLoad(
  28497     sema: *Sema,
  28498     block: *Block,
  28499     src: LazySrcLoc,
  28500     ptr_val: Value,
  28501     maybe_array_ty: ?Type,
  28502 ) ComptimePtrLoadError!ComptimePtrLoadKit {
  28503     const mod = sema.mod;
  28504     const target = mod.getTarget();
  28505 
  28506     var deref: ComptimePtrLoadKit = switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {
  28507         .ptr => |ptr| switch (ptr.addr) {
  28508             .decl, .mut_decl => blk: {
  28509                 const decl_index = switch (ptr.addr) {
  28510                     .decl => |decl| decl,
  28511                     .mut_decl => |mut_decl| mut_decl.decl,
  28512                     else => unreachable,
  28513                 };
  28514                 const is_mutable = ptr.addr == .mut_decl;
  28515                 const decl = mod.declPtr(decl_index);
  28516                 const decl_tv = try decl.typedValue();
  28517                 if (decl.val.getVariable(mod) != null) return error.RuntimeLoad;
  28518 
  28519                 const layout_defined = decl.ty.hasWellDefinedLayout(mod);
  28520                 break :blk ComptimePtrLoadKit{
  28521                     .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,
  28522                     .pointee = decl_tv,
  28523                     .is_mutable = is_mutable,
  28524                     .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
  28525                 };
  28526             },
  28527             .int => return error.RuntimeLoad,
  28528             .eu_payload, .opt_payload => |container_ptr| blk: {
  28529                 const container_ty = mod.intern_pool.typeOf(container_ptr).toType().childType(mod);
  28530                 const payload_ty = switch (ptr.addr) {
  28531                     .eu_payload => container_ty.errorUnionPayload(mod),
  28532                     .opt_payload => container_ty.optionalChild(mod),
  28533                     else => unreachable,
  28534                 };
  28535                 var deref = try sema.beginComptimePtrLoad(block, src, container_ptr.toValue(), container_ty);
  28536 
  28537                 // eu_payload and opt_payload never have a well-defined layout
  28538                 if (deref.parent != null) {
  28539                     deref.parent = null;
  28540                     deref.ty_without_well_defined_layout = container_ty;
  28541                 }
  28542 
  28543                 if (deref.pointee) |*tv| {
  28544                     const coerce_in_mem_ok =
  28545                         (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or
  28546                         (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok;
  28547                     if (coerce_in_mem_ok) {
  28548                         const payload_val = switch (tv.val.ip_index) {
  28549                             .none => tv.val.cast(Value.Payload.SubValue).?.data,
  28550                             .null_value => return sema.fail(block, src, "attempt to use null value", .{}),
  28551                             else => switch (mod.intern_pool.indexToKey(tv.val.toIntern())) {
  28552                                 .error_union => |error_union| switch (error_union.val) {
  28553                                     .err_name => |err_name| return sema.fail(block, src, "attempt to unwrap error: {s}", .{mod.intern_pool.stringToSlice(err_name)}),
  28554                                     .payload => |payload| payload,
  28555                                 },
  28556                                 .opt => |opt| switch (opt.val) {
  28557                                     .none => return sema.fail(block, src, "attempt to use null value", .{}),
  28558                                     else => |payload| payload,
  28559                                 },
  28560                                 else => unreachable,
  28561                             }.toValue(),
  28562                         };
  28563                         tv.* = TypedValue{ .ty = payload_ty, .val = payload_val };
  28564                         break :blk deref;
  28565                     }
  28566                 }
  28567                 deref.pointee = null;
  28568                 break :blk deref;
  28569             },
  28570             .comptime_field => |comptime_field| blk: {
  28571                 const field_ty = mod.intern_pool.typeOf(comptime_field).toType();
  28572                 break :blk ComptimePtrLoadKit{
  28573                     .parent = null,
  28574                     .pointee = .{ .ty = field_ty, .val = comptime_field.toValue() },
  28575                     .is_mutable = false,
  28576                     .ty_without_well_defined_layout = field_ty,
  28577                 };
  28578             },
  28579             .elem => |elem_ptr| blk: {
  28580                 const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod);
  28581                 var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.base.toValue(), null);
  28582 
  28583                 // This code assumes that elem_ptrs have been "flattened" in order for direct dereference
  28584                 // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that
  28585                 // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened"
  28586                 switch (mod.intern_pool.indexToKey(elem_ptr.base)) {
  28587                     .ptr => |base_ptr| switch (base_ptr.addr) {
  28588                         .elem => |base_elem| assert(!mod.intern_pool.typeOf(base_elem.base).toType().elemType2(mod).eql(elem_ty, mod)),
  28589                         else => {},
  28590                     },
  28591                     else => {},
  28592                 }
  28593 
  28594                 if (elem_ptr.index != 0) {
  28595                     if (elem_ty.hasWellDefinedLayout(mod)) {
  28596                         if (deref.parent) |*parent| {
  28597                             // Update the byte offset (in-place)
  28598                             const elem_size = try sema.typeAbiSize(elem_ty);
  28599                             const offset = parent.byte_offset + elem_size * elem_ptr.index;
  28600                             parent.byte_offset = try sema.usizeCast(block, src, offset);
  28601                         }
  28602                     } else {
  28603                         deref.parent = null;
  28604                         deref.ty_without_well_defined_layout = elem_ty;
  28605                     }
  28606                 }
  28607 
  28608                 // If we're loading an elem that was derived from a different type
  28609                 // than the true type of the underlying decl, we cannot deref directly
  28610                 const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector(mod)) x: {
  28611                     const deref_elem_ty = deref.pointee.?.ty.childType(mod);
  28612                     break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or
  28613                         (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok;
  28614                 } else false;
  28615                 if (!ty_matches) {
  28616                     deref.pointee = null;
  28617                     break :blk deref;
  28618                 }
  28619 
  28620                 var array_tv = deref.pointee.?;
  28621                 const check_len = array_tv.ty.arrayLenIncludingSentinel(mod);
  28622                 if (maybe_array_ty) |load_ty| {
  28623                     // It's possible that we're loading a [N]T, in which case we'd like to slice
  28624                     // the pointee array directly from our parent array.
  28625                     if (load_ty.isArrayOrVector(mod) and load_ty.childType(mod).eql(elem_ty, mod)) {
  28626                         const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel(mod));
  28627                         deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{
  28628                             .ty = try Type.array(sema.arena, N, null, elem_ty, mod),
  28629                             .val = try array_tv.val.sliceArray(mod, sema.arena, elem_ptr.index, elem_ptr.index + N),
  28630                         } else null;
  28631                         break :blk deref;
  28632                     }
  28633                 }
  28634 
  28635                 if (elem_ptr.index >= check_len) {
  28636                     deref.pointee = null;
  28637                     break :blk deref;
  28638                 }
  28639                 if (elem_ptr.index == check_len - 1) {
  28640                     if (array_tv.ty.sentinel(mod)) |sent| {
  28641                         deref.pointee = TypedValue{
  28642                             .ty = elem_ty,
  28643                             .val = sent,
  28644                         };
  28645                         break :blk deref;
  28646                     }
  28647                 }
  28648                 deref.pointee = TypedValue{
  28649                     .ty = elem_ty,
  28650                     .val = try array_tv.val.elemValue(mod, elem_ptr.index),
  28651                 };
  28652                 break :blk deref;
  28653             },
  28654             .field => |field_ptr| blk: {
  28655                 const field_index = @intCast(u32, field_ptr.index);
  28656                 const container_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod);
  28657                 var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.base.toValue(), container_ty);
  28658 
  28659                 if (container_ty.hasWellDefinedLayout(mod)) {
  28660                     const struct_obj = mod.typeToStruct(container_ty);
  28661                     if (struct_obj != null and struct_obj.?.layout == .Packed) {
  28662                         // packed structs are not byte addressable
  28663                         deref.parent = null;
  28664                     } else if (deref.parent) |*parent| {
  28665                         // Update the byte offset (in-place)
  28666                         try sema.resolveTypeLayout(container_ty);
  28667                         const field_offset = container_ty.structFieldOffset(field_index, mod);
  28668                         parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset);
  28669                     }
  28670                 } else {
  28671                     deref.parent = null;
  28672                     deref.ty_without_well_defined_layout = container_ty;
  28673                 }
  28674 
  28675                 const tv = deref.pointee orelse {
  28676                     deref.pointee = null;
  28677                     break :blk deref;
  28678                 };
  28679                 const coerce_in_mem_ok =
  28680                     (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or
  28681                     (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok;
  28682                 if (!coerce_in_mem_ok) {
  28683                     deref.pointee = null;
  28684                     break :blk deref;
  28685                 }
  28686 
  28687                 if (container_ty.isSlice(mod)) {
  28688                     deref.pointee = switch (field_index) {
  28689                         Value.slice_ptr_index => TypedValue{
  28690                             .ty = container_ty.slicePtrFieldType(mod),
  28691                             .val = tv.val.slicePtr(mod),
  28692                         },
  28693                         Value.slice_len_index => TypedValue{
  28694                             .ty = Type.usize,
  28695                             .val = mod.intern_pool.indexToKey(tv.val.toIntern()).ptr.len.toValue(),
  28696                         },
  28697                         else => unreachable,
  28698                     };
  28699                 } else {
  28700                     const field_ty = container_ty.structFieldType(field_index, mod);
  28701                     deref.pointee = TypedValue{
  28702                         .ty = field_ty,
  28703                         .val = try tv.val.fieldValue(mod, field_index),
  28704                     };
  28705                 }
  28706                 break :blk deref;
  28707             },
  28708         },
  28709         .opt => |opt| switch (opt.val) {
  28710             .none => return sema.fail(block, src, "attempt to use null value", .{}),
  28711             else => |payload| try sema.beginComptimePtrLoad(block, src, payload.toValue(), null),
  28712         },
  28713         else => unreachable,
  28714     };
  28715 
  28716     if (deref.pointee) |tv| {
  28717         if (deref.parent == null and tv.ty.hasWellDefinedLayout(mod)) {
  28718             deref.parent = .{ .tv = tv, .byte_offset = 0 };
  28719         }
  28720     }
  28721     return deref;
  28722 }
  28723 
  28724 fn bitCast(
  28725     sema: *Sema,
  28726     block: *Block,
  28727     dest_ty_unresolved: Type,
  28728     inst: Air.Inst.Ref,
  28729     inst_src: LazySrcLoc,
  28730     operand_src: ?LazySrcLoc,
  28731 ) CompileError!Air.Inst.Ref {
  28732     const mod = sema.mod;
  28733     const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved);
  28734     try sema.resolveTypeLayout(dest_ty);
  28735 
  28736     const old_ty = try sema.resolveTypeFields(sema.typeOf(inst));
  28737     try sema.resolveTypeLayout(old_ty);
  28738 
  28739     const dest_bits = dest_ty.bitSize(mod);
  28740     const old_bits = old_ty.bitSize(mod);
  28741 
  28742     if (old_bits != dest_bits) {
  28743         return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{}' has {d} bits but source type '{}' has {d} bits", .{
  28744             dest_ty.fmt(mod),
  28745             dest_bits,
  28746             old_ty.fmt(mod),
  28747             old_bits,
  28748         });
  28749     }
  28750 
  28751     if (try sema.resolveMaybeUndefVal(inst)) |val| {
  28752         if (try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0)) |result_val| {
  28753             return sema.addConstant(dest_ty, result_val);
  28754         }
  28755     }
  28756     try sema.requireRuntimeBlock(block, inst_src, operand_src);
  28757     return block.addBitCast(dest_ty, inst);
  28758 }
  28759 
  28760 fn bitCastVal(
  28761     sema: *Sema,
  28762     block: *Block,
  28763     src: LazySrcLoc,
  28764     val: Value,
  28765     old_ty: Type,
  28766     new_ty: Type,
  28767     buffer_offset: usize,
  28768 ) !?Value {
  28769     const mod = sema.mod;
  28770     if (old_ty.eql(new_ty, mod)) return val;
  28771 
  28772     // For types with well-defined memory layouts, we serialize them a byte buffer,
  28773     // then deserialize to the new type.
  28774     const abi_size = try sema.usizeCast(block, src, old_ty.abiSize(mod));
  28775     const buffer = try sema.gpa.alloc(u8, abi_size);
  28776     defer sema.gpa.free(buffer);
  28777     val.writeToMemory(old_ty, mod, buffer) catch |err| switch (err) {
  28778         error.OutOfMemory => return error.OutOfMemory,
  28779         error.ReinterpretDeclRef => return null,
  28780         error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already
  28781         error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{old_ty.fmt(mod)}),
  28782     };
  28783     return try Value.readFromMemory(new_ty, mod, buffer[buffer_offset..], sema.arena);
  28784 }
  28785 
  28786 fn coerceArrayPtrToSlice(
  28787     sema: *Sema,
  28788     block: *Block,
  28789     dest_ty: Type,
  28790     inst: Air.Inst.Ref,
  28791     inst_src: LazySrcLoc,
  28792 ) CompileError!Air.Inst.Ref {
  28793     const mod = sema.mod;
  28794     if (try sema.resolveMaybeUndefVal(inst)) |val| {
  28795         const ptr_array_ty = sema.typeOf(inst);
  28796         const array_ty = ptr_array_ty.childType(mod);
  28797         const slice_val = try mod.intern(.{ .ptr = .{
  28798             .ty = dest_ty.toIntern(),
  28799             .addr = switch (mod.intern_pool.indexToKey(val.toIntern())) {
  28800                 .undef => .{ .int = try mod.intern(.{ .undef = .usize_type }) },
  28801                 .ptr => |ptr| ptr.addr,
  28802                 else => unreachable,
  28803             },
  28804             .len = (try mod.intValue(Type.usize, array_ty.arrayLen(mod))).toIntern(),
  28805         } });
  28806         return sema.addConstant(dest_ty, slice_val.toValue());
  28807     }
  28808     try sema.requireRuntimeBlock(block, inst_src, null);
  28809     return block.addTyOp(.array_to_slice, dest_ty, inst);
  28810 }
  28811 
  28812 fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_result: *InMemoryCoercionResult) bool {
  28813     const mod = sema.mod;
  28814     const dest_info = dest_ty.ptrInfo(mod);
  28815     const inst_info = inst_ty.ptrInfo(mod);
  28816     const len0 = (inst_info.pointee_type.zigTypeTag(mod) == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel(mod) == 0 or
  28817         (inst_info.pointee_type.arrayLen(mod) == 0 and dest_info.sentinel == null and dest_info.size != .C and dest_info.size != .Many))) or
  28818         (inst_info.pointee_type.isTuple(mod) and inst_info.pointee_type.structFieldCount(mod) == 0);
  28819 
  28820     const ok_cv_qualifiers =
  28821         ((inst_info.mutable or !dest_info.mutable) or len0) and
  28822         (!inst_info.@"volatile" or dest_info.@"volatile");
  28823 
  28824     if (!ok_cv_qualifiers) {
  28825         in_memory_result.* = .{ .ptr_qualifiers = .{
  28826             .actual_const = !inst_info.mutable,
  28827             .wanted_const = !dest_info.mutable,
  28828             .actual_volatile = inst_info.@"volatile",
  28829             .wanted_volatile = dest_info.@"volatile",
  28830         } };
  28831         return false;
  28832     }
  28833     if (dest_info.@"addrspace" != inst_info.@"addrspace") {
  28834         in_memory_result.* = .{ .ptr_addrspace = .{
  28835             .actual = inst_info.@"addrspace",
  28836             .wanted = dest_info.@"addrspace",
  28837         } };
  28838         return false;
  28839     }
  28840     if (inst_info.@"align" == 0 and dest_info.@"align" == 0) return true;
  28841     if (len0) return true;
  28842 
  28843     const inst_align = if (inst_info.@"align" != 0)
  28844         inst_info.@"align"
  28845     else
  28846         inst_info.pointee_type.abiAlignment(mod);
  28847 
  28848     const dest_align = if (dest_info.@"align" != 0)
  28849         dest_info.@"align"
  28850     else
  28851         dest_info.pointee_type.abiAlignment(mod);
  28852 
  28853     if (dest_align > inst_align) {
  28854         in_memory_result.* = .{ .ptr_alignment = .{
  28855             .actual = inst_align,
  28856             .wanted = dest_align,
  28857         } };
  28858         return false;
  28859     }
  28860     return true;
  28861 }
  28862 
  28863 fn coerceCompatiblePtrs(
  28864     sema: *Sema,
  28865     block: *Block,
  28866     dest_ty: Type,
  28867     inst: Air.Inst.Ref,
  28868     inst_src: LazySrcLoc,
  28869 ) !Air.Inst.Ref {
  28870     const mod = sema.mod;
  28871     const inst_ty = sema.typeOf(inst);
  28872     if (try sema.resolveMaybeUndefVal(inst)) |val| {
  28873         if (!val.isUndef(mod) and val.isNull(mod) and !dest_ty.isAllowzeroPtr(mod)) {
  28874             return sema.fail(block, inst_src, "null pointer casted to type '{}'", .{dest_ty.fmt(sema.mod)});
  28875         }
  28876         // The comptime Value representation is compatible with both types.
  28877         return sema.addConstant(
  28878             dest_ty,
  28879             try mod.getCoerced((try val.intern(inst_ty, mod)).toValue(), dest_ty),
  28880         );
  28881     }
  28882     try sema.requireRuntimeBlock(block, inst_src, null);
  28883     const inst_allows_zero = inst_ty.zigTypeTag(mod) != .Pointer or inst_ty.ptrAllowsZero(mod);
  28884     if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(mod) and
  28885         (try sema.typeHasRuntimeBits(dest_ty.elemType2(mod)) or dest_ty.elemType2(mod).zigTypeTag(mod) == .Fn))
  28886     {
  28887         const actual_ptr = if (inst_ty.isSlice(mod))
  28888             try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty)
  28889         else
  28890             inst;
  28891         const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr);
  28892         const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize);
  28893         const ok = if (inst_ty.isSlice(mod)) ok: {
  28894             const len = try sema.analyzeSliceLen(block, inst_src, inst);
  28895             const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
  28896             break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);
  28897         } else is_non_zero;
  28898         try sema.addSafetyCheck(block, ok, .cast_to_null);
  28899     }
  28900     return sema.bitCast(block, dest_ty, inst, inst_src, null);
  28901 }
  28902 
  28903 fn coerceEnumToUnion(
  28904     sema: *Sema,
  28905     block: *Block,
  28906     union_ty: Type,
  28907     union_ty_src: LazySrcLoc,
  28908     inst: Air.Inst.Ref,
  28909     inst_src: LazySrcLoc,
  28910 ) !Air.Inst.Ref {
  28911     const mod = sema.mod;
  28912     const inst_ty = sema.typeOf(inst);
  28913 
  28914     const tag_ty = union_ty.unionTagType(mod) orelse {
  28915         const msg = msg: {
  28916             const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{
  28917                 union_ty.fmt(sema.mod), inst_ty.fmt(sema.mod),
  28918             });
  28919             errdefer msg.destroy(sema.gpa);
  28920             try sema.errNote(block, union_ty_src, msg, "cannot coerce enum to untagged union", .{});
  28921             try sema.addDeclaredHereNote(msg, union_ty);
  28922             break :msg msg;
  28923         };
  28924         return sema.failWithOwnedErrorMsg(msg);
  28925     };
  28926 
  28927     const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src);
  28928     if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| {
  28929         const field_index = union_ty.unionTagFieldIndex(val, sema.mod) orelse {
  28930             const msg = msg: {
  28931                 const msg = try sema.errMsg(block, inst_src, "union '{}' has no tag with value '{}'", .{
  28932                     union_ty.fmt(sema.mod), val.fmtValue(tag_ty, sema.mod),
  28933                 });
  28934                 errdefer msg.destroy(sema.gpa);
  28935                 try sema.addDeclaredHereNote(msg, union_ty);
  28936                 break :msg msg;
  28937             };
  28938             return sema.failWithOwnedErrorMsg(msg);
  28939         };
  28940 
  28941         const union_obj = mod.typeToUnion(union_ty).?;
  28942         const field = union_obj.fields.values()[field_index];
  28943         const field_ty = try sema.resolveTypeFields(field.ty);
  28944         if (field_ty.zigTypeTag(mod) == .NoReturn) {
  28945             const msg = msg: {
  28946                 const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{});
  28947                 errdefer msg.destroy(sema.gpa);
  28948 
  28949                 const field_name = union_obj.fields.keys()[field_index];
  28950                 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name});
  28951                 try sema.addDeclaredHereNote(msg, union_ty);
  28952                 break :msg msg;
  28953             };
  28954             return sema.failWithOwnedErrorMsg(msg);
  28955         }
  28956         const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse {
  28957             const msg = msg: {
  28958                 const field_name = union_obj.fields.keys()[field_index];
  28959                 const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{s}'", .{
  28960                     inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod), field_ty.fmt(sema.mod), field_name,
  28961                 });
  28962                 errdefer msg.destroy(sema.gpa);
  28963 
  28964                 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name});
  28965                 try sema.addDeclaredHereNote(msg, union_ty);
  28966                 break :msg msg;
  28967             };
  28968             return sema.failWithOwnedErrorMsg(msg);
  28969         };
  28970 
  28971         return sema.addConstant(union_ty, try mod.unionValue(union_ty, val, opv));
  28972     }
  28973 
  28974     try sema.requireRuntimeBlock(block, inst_src, null);
  28975 
  28976     if (tag_ty.isNonexhaustiveEnum(mod)) {
  28977         const msg = msg: {
  28978             const msg = try sema.errMsg(block, inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{
  28979                 union_ty.fmt(sema.mod),
  28980             });
  28981             errdefer msg.destroy(sema.gpa);
  28982             try sema.addDeclaredHereNote(msg, tag_ty);
  28983             break :msg msg;
  28984         };
  28985         return sema.failWithOwnedErrorMsg(msg);
  28986     }
  28987 
  28988     const union_obj = mod.typeToUnion(union_ty).?;
  28989     {
  28990         var msg: ?*Module.ErrorMsg = null;
  28991         errdefer if (msg) |some| some.destroy(sema.gpa);
  28992 
  28993         for (union_obj.fields.values(), 0..) |field, i| {
  28994             if (field.ty.zigTypeTag(mod) == .NoReturn) {
  28995                 const err_msg = msg orelse try sema.errMsg(
  28996                     block,
  28997                     inst_src,
  28998                     "runtime coercion from enum '{}' to union '{}' which has a 'noreturn' field",
  28999                     .{ tag_ty.fmt(sema.mod), union_ty.fmt(sema.mod) },
  29000                 );
  29001                 msg = err_msg;
  29002 
  29003                 try sema.addFieldErrNote(union_ty, i, err_msg, "'noreturn' field here", .{});
  29004             }
  29005         }
  29006         if (msg) |some| {
  29007             msg = null;
  29008             try sema.addDeclaredHereNote(some, union_ty);
  29009             return sema.failWithOwnedErrorMsg(some);
  29010         }
  29011     }
  29012 
  29013     // If the union has all fields 0 bits, the union value is just the enum value.
  29014     if (union_ty.unionHasAllZeroBitFieldTypes(mod)) {
  29015         return block.addBitCast(union_ty, enum_tag);
  29016     }
  29017 
  29018     const msg = msg: {
  29019         const msg = try sema.errMsg(
  29020             block,
  29021             inst_src,
  29022             "runtime coercion from enum '{}' to union '{}' which has non-void fields",
  29023             .{ tag_ty.fmt(sema.mod), union_ty.fmt(sema.mod) },
  29024         );
  29025         errdefer msg.destroy(sema.gpa);
  29026 
  29027         var it = union_obj.fields.iterator();
  29028         var field_index: usize = 0;
  29029         while (it.next()) |field| : (field_index += 1) {
  29030             const field_name = field.key_ptr.*;
  29031             const field_ty = field.value_ptr.ty;
  29032             if (!(try sema.typeHasRuntimeBits(field_ty))) continue;
  29033             try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) });
  29034         }
  29035         try sema.addDeclaredHereNote(msg, union_ty);
  29036         break :msg msg;
  29037     };
  29038     return sema.failWithOwnedErrorMsg(msg);
  29039 }
  29040 
  29041 fn coerceAnonStructToUnion(
  29042     sema: *Sema,
  29043     block: *Block,
  29044     union_ty: Type,
  29045     union_ty_src: LazySrcLoc,
  29046     inst: Air.Inst.Ref,
  29047     inst_src: LazySrcLoc,
  29048 ) !Air.Inst.Ref {
  29049     const mod = sema.mod;
  29050     const inst_ty = sema.typeOf(inst);
  29051     const field_info: union(enum) {
  29052         name: []const u8,
  29053         count: usize,
  29054     } = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) {
  29055         .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 1)
  29056             .{ .name = mod.intern_pool.stringToSlice(anon_struct_type.names[0]) }
  29057         else
  29058             .{ .count = anon_struct_type.names.len },
  29059         .struct_type => |struct_type| name: {
  29060             const field_names = mod.structPtrUnwrap(struct_type.index).?.fields.keys();
  29061             break :name if (field_names.len == 1)
  29062                 .{ .name = field_names[0] }
  29063             else
  29064                 .{ .count = field_names.len };
  29065         },
  29066         else => unreachable,
  29067     };
  29068     switch (field_info) {
  29069         .name => |field_name| {
  29070             const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty);
  29071             return sema.unionInit(block, init, inst_src, union_ty, union_ty_src, field_name, inst_src);
  29072         },
  29073         .count => |field_count| {
  29074             assert(field_count != 1);
  29075             const msg = msg: {
  29076                 const msg = if (field_count > 1) try sema.errMsg(
  29077                     block,
  29078                     inst_src,
  29079                     "cannot initialize multiple union fields at once; unions can only have one active field",
  29080                     .{},
  29081                 ) else try sema.errMsg(
  29082                     block,
  29083                     inst_src,
  29084                     "union initializer must initialize one field",
  29085                     .{},
  29086                 );
  29087                 errdefer msg.destroy(sema.gpa);
  29088 
  29089                 // TODO add notes for where the anon struct was created to point out
  29090                 // the extra fields.
  29091 
  29092                 try sema.addDeclaredHereNote(msg, union_ty);
  29093                 break :msg msg;
  29094             };
  29095             return sema.failWithOwnedErrorMsg(msg);
  29096         },
  29097     }
  29098 }
  29099 
  29100 fn coerceAnonStructToUnionPtrs(
  29101     sema: *Sema,
  29102     block: *Block,
  29103     ptr_union_ty: Type,
  29104     union_ty_src: LazySrcLoc,
  29105     ptr_anon_struct: Air.Inst.Ref,
  29106     anon_struct_src: LazySrcLoc,
  29107 ) !Air.Inst.Ref {
  29108     const mod = sema.mod;
  29109     const union_ty = ptr_union_ty.childType(mod);
  29110     const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src);
  29111     const union_inst = try sema.coerceAnonStructToUnion(block, union_ty, union_ty_src, anon_struct, anon_struct_src);
  29112     return sema.analyzeRef(block, union_ty_src, union_inst);
  29113 }
  29114 
  29115 fn coerceAnonStructToStructPtrs(
  29116     sema: *Sema,
  29117     block: *Block,
  29118     ptr_struct_ty: Type,
  29119     struct_ty_src: LazySrcLoc,
  29120     ptr_anon_struct: Air.Inst.Ref,
  29121     anon_struct_src: LazySrcLoc,
  29122 ) !Air.Inst.Ref {
  29123     const mod = sema.mod;
  29124     const struct_ty = ptr_struct_ty.childType(mod);
  29125     const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src);
  29126     const struct_inst = try sema.coerceTupleToStruct(block, struct_ty, anon_struct, anon_struct_src);
  29127     return sema.analyzeRef(block, struct_ty_src, struct_inst);
  29128 }
  29129 
  29130 /// If the lengths match, coerces element-wise.
  29131 fn coerceArrayLike(
  29132     sema: *Sema,
  29133     block: *Block,
  29134     dest_ty: Type,
  29135     dest_ty_src: LazySrcLoc,
  29136     inst: Air.Inst.Ref,
  29137     inst_src: LazySrcLoc,
  29138 ) !Air.Inst.Ref {
  29139     const mod = sema.mod;
  29140     const inst_ty = sema.typeOf(inst);
  29141     const inst_len = inst_ty.arrayLen(mod);
  29142     const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen(mod));
  29143     const target = mod.getTarget();
  29144 
  29145     if (dest_len != inst_len) {
  29146         const msg = msg: {
  29147             const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{
  29148                 dest_ty.fmt(mod), inst_ty.fmt(mod),
  29149             });
  29150             errdefer msg.destroy(sema.gpa);
  29151             try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len});
  29152             try sema.errNote(block, inst_src, msg, "source has length {d}", .{inst_len});
  29153             break :msg msg;
  29154         };
  29155         return sema.failWithOwnedErrorMsg(msg);
  29156     }
  29157 
  29158     const dest_elem_ty = dest_ty.childType(mod);
  29159     const inst_elem_ty = inst_ty.childType(mod);
  29160     const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_elem_ty, inst_elem_ty, false, target, dest_ty_src, inst_src);
  29161     if (in_memory_result == .ok) {
  29162         if (try sema.resolveMaybeUndefVal(inst)) |inst_val| {
  29163             // These types share the same comptime value representation.
  29164             return sema.coerceInMemory(block, inst_val, inst_ty, dest_ty, dest_ty_src);
  29165         }
  29166         try sema.requireRuntimeBlock(block, inst_src, null);
  29167         return block.addBitCast(dest_ty, inst);
  29168     }
  29169 
  29170     const element_vals = try sema.arena.alloc(InternPool.Index, dest_len);
  29171     const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_len);
  29172     var runtime_src: ?LazySrcLoc = null;
  29173 
  29174     for (element_vals, element_refs, 0..) |*val, *ref, i| {
  29175         const index_ref = try sema.addConstant(Type.usize, try mod.intValue(Type.usize, i));
  29176         const src = inst_src; // TODO better source location
  29177         const elem_src = inst_src; // TODO better source location
  29178         const elem_ref = try sema.elemValArray(block, src, inst_src, inst, elem_src, index_ref, true);
  29179         const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src);
  29180         ref.* = coerced;
  29181         if (runtime_src == null) {
  29182             if (try sema.resolveMaybeUndefVal(coerced)) |elem_val| {
  29183                 val.* = try elem_val.intern(dest_elem_ty, mod);
  29184             } else {
  29185                 runtime_src = elem_src;
  29186             }
  29187         }
  29188     }
  29189 
  29190     if (runtime_src) |rs| {
  29191         try sema.requireRuntimeBlock(block, inst_src, rs);
  29192         return block.addAggregateInit(dest_ty, element_refs);
  29193     }
  29194 
  29195     return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{
  29196         .ty = dest_ty.toIntern(),
  29197         .storage = .{ .elems = element_vals },
  29198     } })).toValue());
  29199 }
  29200 
  29201 /// If the lengths match, coerces element-wise.
  29202 fn coerceTupleToArray(
  29203     sema: *Sema,
  29204     block: *Block,
  29205     dest_ty: Type,
  29206     dest_ty_src: LazySrcLoc,
  29207     inst: Air.Inst.Ref,
  29208     inst_src: LazySrcLoc,
  29209 ) !Air.Inst.Ref {
  29210     const mod = sema.mod;
  29211     const inst_ty = sema.typeOf(inst);
  29212     const inst_len = inst_ty.arrayLen(mod);
  29213     const dest_len = dest_ty.arrayLen(mod);
  29214 
  29215     if (dest_len != inst_len) {
  29216         const msg = msg: {
  29217             const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{
  29218                 dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod),
  29219             });
  29220             errdefer msg.destroy(sema.gpa);
  29221             try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len});
  29222             try sema.errNote(block, inst_src, msg, "source has length {d}", .{inst_len});
  29223             break :msg msg;
  29224         };
  29225         return sema.failWithOwnedErrorMsg(msg);
  29226     }
  29227 
  29228     const dest_elems = try sema.usizeCast(block, dest_ty_src, dest_len);
  29229     const element_vals = try sema.arena.alloc(InternPool.Index, dest_elems);
  29230     const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_elems);
  29231     const dest_elem_ty = dest_ty.childType(mod);
  29232 
  29233     var runtime_src: ?LazySrcLoc = null;
  29234     for (element_vals, element_refs, 0..) |*val, *ref, i_usize| {
  29235         const i = @intCast(u32, i_usize);
  29236         if (i_usize == inst_len) {
  29237             const sentinel_val = dest_ty.sentinel(mod).?;
  29238             val.* = sentinel_val.toIntern();
  29239             ref.* = try sema.addConstant(dest_elem_ty, sentinel_val);
  29240             break;
  29241         }
  29242         const elem_src = inst_src; // TODO better source location
  29243         const elem_ref = try sema.tupleField(block, inst_src, inst, elem_src, i);
  29244         const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src);
  29245         ref.* = coerced;
  29246         if (runtime_src == null) {
  29247             if (try sema.resolveMaybeUndefVal(coerced)) |elem_val| {
  29248                 val.* = try elem_val.intern(dest_elem_ty, mod);
  29249             } else {
  29250                 runtime_src = elem_src;
  29251             }
  29252         }
  29253     }
  29254 
  29255     if (runtime_src) |rs| {
  29256         try sema.requireRuntimeBlock(block, inst_src, rs);
  29257         return block.addAggregateInit(dest_ty, element_refs);
  29258     }
  29259 
  29260     return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{
  29261         .ty = dest_ty.toIntern(),
  29262         .storage = .{ .elems = element_vals },
  29263     } })).toValue());
  29264 }
  29265 
  29266 /// If the lengths match, coerces element-wise.
  29267 fn coerceTupleToSlicePtrs(
  29268     sema: *Sema,
  29269     block: *Block,
  29270     slice_ty: Type,
  29271     slice_ty_src: LazySrcLoc,
  29272     ptr_tuple: Air.Inst.Ref,
  29273     tuple_src: LazySrcLoc,
  29274 ) !Air.Inst.Ref {
  29275     const mod = sema.mod;
  29276     const tuple_ty = sema.typeOf(ptr_tuple).childType(mod);
  29277     const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src);
  29278     const slice_info = slice_ty.ptrInfo(mod);
  29279     const array_ty = try Type.array(sema.arena, tuple_ty.structFieldCount(mod), slice_info.sentinel, slice_info.pointee_type, sema.mod);
  29280     const array_inst = try sema.coerceTupleToArray(block, array_ty, slice_ty_src, tuple, tuple_src);
  29281     if (slice_info.@"align" != 0) {
  29282         return sema.fail(block, slice_ty_src, "TODO: override the alignment of the array decl we create here", .{});
  29283     }
  29284     const ptr_array = try sema.analyzeRef(block, slice_ty_src, array_inst);
  29285     return sema.coerceArrayPtrToSlice(block, slice_ty, ptr_array, slice_ty_src);
  29286 }
  29287 
  29288 /// If the lengths match, coerces element-wise.
  29289 fn coerceTupleToArrayPtrs(
  29290     sema: *Sema,
  29291     block: *Block,
  29292     ptr_array_ty: Type,
  29293     array_ty_src: LazySrcLoc,
  29294     ptr_tuple: Air.Inst.Ref,
  29295     tuple_src: LazySrcLoc,
  29296 ) !Air.Inst.Ref {
  29297     const mod = sema.mod;
  29298     const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src);
  29299     const ptr_info = ptr_array_ty.ptrInfo(mod);
  29300     const array_ty = ptr_info.pointee_type;
  29301     const array_inst = try sema.coerceTupleToArray(block, array_ty, array_ty_src, tuple, tuple_src);
  29302     if (ptr_info.@"align" != 0) {
  29303         return sema.fail(block, array_ty_src, "TODO: override the alignment of the array decl we create here", .{});
  29304     }
  29305     const ptr_array = try sema.analyzeRef(block, array_ty_src, array_inst);
  29306     return ptr_array;
  29307 }
  29308 
  29309 /// Handles both tuples and anon struct literals. Coerces field-wise. Reports
  29310 /// errors for both extra fields and missing fields.
  29311 fn coerceTupleToStruct(
  29312     sema: *Sema,
  29313     block: *Block,
  29314     dest_ty: Type,
  29315     inst: Air.Inst.Ref,
  29316     inst_src: LazySrcLoc,
  29317 ) !Air.Inst.Ref {
  29318     const mod = sema.mod;
  29319     const struct_ty = try sema.resolveTypeFields(dest_ty);
  29320 
  29321     if (struct_ty.isTupleOrAnonStruct(mod)) {
  29322         return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src);
  29323     }
  29324 
  29325     const fields = struct_ty.structFields(mod);
  29326     const field_vals = try sema.arena.alloc(InternPool.Index, fields.count());
  29327     const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len);
  29328     @memset(field_refs, .none);
  29329 
  29330     const inst_ty = sema.typeOf(inst);
  29331     var runtime_src: ?LazySrcLoc = null;
  29332     const field_count = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) {
  29333         .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
  29334         .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj|
  29335             struct_obj.fields.count()
  29336         else
  29337             0,
  29338         else => unreachable,
  29339     };
  29340     for (0..field_count) |field_index_usize| {
  29341         const field_i = @intCast(u32, field_index_usize);
  29342         const field_src = inst_src; // TODO better source location
  29343         // https://github.com/ziglang/zig/issues/15709
  29344         const field_name: []const u8 = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) {
  29345             .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len > 0)
  29346                 mod.intern_pool.stringToSlice(anon_struct_type.names[field_i])
  29347             else
  29348                 try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}),
  29349             .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[field_i],
  29350             else => unreachable,
  29351         };
  29352         const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
  29353         const field = fields.values()[field_index];
  29354         const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i);
  29355         const coerced = try sema.coerce(block, field.ty, elem_ref, field_src);
  29356         field_refs[field_index] = coerced;
  29357         if (field.is_comptime) {
  29358             const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
  29359                 return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known");
  29360             };
  29361 
  29362             if (!init_val.eql(field.default_val, field.ty, sema.mod)) {
  29363                 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);
  29364             }
  29365         }
  29366         if (runtime_src == null) {
  29367             if (try sema.resolveMaybeUndefVal(coerced)) |field_val| {
  29368                 field_vals[field_index] = field_val.toIntern();
  29369             } else {
  29370                 runtime_src = field_src;
  29371             }
  29372         }
  29373     }
  29374 
  29375     // Populate default field values and report errors for missing fields.
  29376     var root_msg: ?*Module.ErrorMsg = null;
  29377     errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
  29378 
  29379     for (field_refs, 0..) |*field_ref, i| {
  29380         if (field_ref.* != .none) continue;
  29381 
  29382         const field_name = fields.keys()[i];
  29383         const field = fields.values()[i];
  29384         const field_src = inst_src; // TODO better source location
  29385         if (field.default_val.toIntern() == .unreachable_value) {
  29386             const template = "missing struct field: {s}";
  29387             const args = .{field_name};
  29388             if (root_msg) |msg| {
  29389                 try sema.errNote(block, field_src, msg, template, args);
  29390             } else {
  29391                 root_msg = try sema.errMsg(block, field_src, template, args);
  29392             }
  29393             continue;
  29394         }
  29395         if (runtime_src == null) {
  29396             field_vals[i] = field.default_val.toIntern();
  29397         } else {
  29398             field_ref.* = try sema.addConstant(field.ty, field.default_val);
  29399         }
  29400     }
  29401 
  29402     if (root_msg) |msg| {
  29403         try sema.addDeclaredHereNote(msg, struct_ty);
  29404         root_msg = null;
  29405         return sema.failWithOwnedErrorMsg(msg);
  29406     }
  29407 
  29408     if (runtime_src) |rs| {
  29409         try sema.requireRuntimeBlock(block, inst_src, rs);
  29410         return block.addAggregateInit(struct_ty, field_refs);
  29411     }
  29412 
  29413     const struct_val = try mod.intern(.{ .aggregate = .{
  29414         .ty = struct_ty.toIntern(),
  29415         .storage = .{ .elems = field_vals },
  29416     } });
  29417     errdefer mod.intern_pool.remove(struct_val);
  29418 
  29419     return sema.addConstant(struct_ty, struct_val.toValue());
  29420 }
  29421 
  29422 fn coerceTupleToTuple(
  29423     sema: *Sema,
  29424     block: *Block,
  29425     tuple_ty: Type,
  29426     inst: Air.Inst.Ref,
  29427     inst_src: LazySrcLoc,
  29428 ) !Air.Inst.Ref {
  29429     const mod = sema.mod;
  29430     const dest_field_count = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) {
  29431         .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
  29432         .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj|
  29433             struct_obj.fields.count()
  29434         else
  29435             0,
  29436         else => unreachable,
  29437     };
  29438     const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count);
  29439     const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len);
  29440     @memset(field_refs, .none);
  29441 
  29442     const inst_ty = sema.typeOf(inst);
  29443     const src_field_count = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) {
  29444         .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
  29445         .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj|
  29446             struct_obj.fields.count()
  29447         else
  29448             0,
  29449         else => unreachable,
  29450     };
  29451     if (src_field_count > dest_field_count) return error.NotCoercible;
  29452 
  29453     var runtime_src: ?LazySrcLoc = null;
  29454     for (0..dest_field_count) |field_index_usize| {
  29455         const field_i = @intCast(u32, field_index_usize);
  29456         const field_src = inst_src; // TODO better source location
  29457         // https://github.com/ziglang/zig/issues/15709
  29458         const field_name: []const u8 = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) {
  29459             .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len > 0)
  29460                 mod.intern_pool.stringToSlice(anon_struct_type.names[field_i])
  29461             else
  29462                 try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}),
  29463             .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[field_i],
  29464             else => unreachable,
  29465         };
  29466 
  29467         if (mem.eql(u8, field_name, "len")) {
  29468             return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{});
  29469         }
  29470 
  29471         const field_ty = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) {
  29472             .anon_struct_type => |anon_struct_type| anon_struct_type.types[field_index_usize].toType(),
  29473             .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].ty,
  29474             else => unreachable,
  29475         };
  29476         const default_val = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) {
  29477             .anon_struct_type => |anon_struct_type| anon_struct_type.values[field_index_usize],
  29478             .struct_type => |struct_type| switch (mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].default_val.toIntern()) {
  29479                 .unreachable_value => .none,
  29480                 else => |default_val| default_val,
  29481             },
  29482             else => unreachable,
  29483         };
  29484 
  29485         const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src);
  29486 
  29487         const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i);
  29488         const coerced = try sema.coerce(block, field_ty, elem_ref, field_src);
  29489         field_refs[field_index] = coerced;
  29490         if (default_val != .none) {
  29491             const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
  29492                 return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known");
  29493             };
  29494 
  29495             if (!init_val.eql(default_val.toValue(), field_ty, sema.mod)) {
  29496                 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);
  29497             }
  29498         }
  29499         if (runtime_src == null) {
  29500             if (try sema.resolveMaybeUndefVal(coerced)) |field_val| {
  29501                 field_vals[field_index] = field_val.toIntern();
  29502             } else {
  29503                 runtime_src = field_src;
  29504             }
  29505         }
  29506     }
  29507 
  29508     // Populate default field values and report errors for missing fields.
  29509     var root_msg: ?*Module.ErrorMsg = null;
  29510     errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
  29511 
  29512     for (field_refs, 0..) |*field_ref, i| {
  29513         if (field_ref.* != .none) continue;
  29514 
  29515         const default_val = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) {
  29516             .anon_struct_type => |anon_struct_type| anon_struct_type.values[i],
  29517             .struct_type => |struct_type| switch (mod.structPtrUnwrap(struct_type.index).?.fields.values()[i].default_val.toIntern()) {
  29518                 .unreachable_value => .none,
  29519                 else => |default_val| default_val,
  29520             },
  29521             else => unreachable,
  29522         };
  29523 
  29524         const field_src = inst_src; // TODO better source location
  29525         if (default_val == .none) {
  29526             if (tuple_ty.isTuple(mod)) {
  29527                 const template = "missing tuple field: {d}";
  29528                 if (root_msg) |msg| {
  29529                     try sema.errNote(block, field_src, msg, template, .{i});
  29530                 } else {
  29531                     root_msg = try sema.errMsg(block, field_src, template, .{i});
  29532                 }
  29533                 continue;
  29534             }
  29535             const template = "missing struct field: {s}";
  29536             const args = .{tuple_ty.structFieldName(i, mod)};
  29537             if (root_msg) |msg| {
  29538                 try sema.errNote(block, field_src, msg, template, args);
  29539             } else {
  29540                 root_msg = try sema.errMsg(block, field_src, template, args);
  29541             }
  29542             continue;
  29543         }
  29544         if (runtime_src == null) {
  29545             field_vals[i] = default_val;
  29546         } else {
  29547             const field_ty = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) {
  29548                 .anon_struct_type => |anon_struct_type| anon_struct_type.types[i].toType(),
  29549                 .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[i].ty,
  29550                 else => unreachable,
  29551             };
  29552             field_ref.* = try sema.addConstant(field_ty, default_val.toValue());
  29553         }
  29554     }
  29555 
  29556     if (root_msg) |msg| {
  29557         try sema.addDeclaredHereNote(msg, tuple_ty);
  29558         root_msg = null;
  29559         return sema.failWithOwnedErrorMsg(msg);
  29560     }
  29561 
  29562     if (runtime_src) |rs| {
  29563         try sema.requireRuntimeBlock(block, inst_src, rs);
  29564         return block.addAggregateInit(tuple_ty, field_refs);
  29565     }
  29566 
  29567     return sema.addConstant(
  29568         tuple_ty,
  29569         (try mod.intern(.{ .aggregate = .{
  29570             .ty = tuple_ty.toIntern(),
  29571             .storage = .{ .elems = field_vals },
  29572         } })).toValue(),
  29573     );
  29574 }
  29575 
  29576 fn analyzeDeclVal(
  29577     sema: *Sema,
  29578     block: *Block,
  29579     src: LazySrcLoc,
  29580     decl_index: Decl.Index,
  29581 ) CompileError!Air.Inst.Ref {
  29582     try sema.addReferencedBy(block, src, decl_index);
  29583     if (sema.decl_val_table.get(decl_index)) |result| {
  29584         return result;
  29585     }
  29586     const decl_ref = try sema.analyzeDeclRefInner(decl_index, false);
  29587     const result = try sema.analyzeLoad(block, src, decl_ref, src);
  29588     if (Air.refToIndex(result)) |index| {
  29589         if (sema.air_instructions.items(.tag)[index] == .interned and !block.is_typeof) {
  29590             try sema.decl_val_table.put(sema.gpa, decl_index, result);
  29591         }
  29592     }
  29593     return result;
  29594 }
  29595 
  29596 fn addReferencedBy(
  29597     sema: *Sema,
  29598     block: *Block,
  29599     src: LazySrcLoc,
  29600     decl_index: Decl.Index,
  29601 ) !void {
  29602     if (sema.mod.comp.reference_trace == @as(u32, 0)) return;
  29603     try sema.mod.reference_table.put(sema.gpa, decl_index, .{
  29604         .referencer = block.src_decl,
  29605         .src = src,
  29606     });
  29607 }
  29608 
  29609 fn ensureDeclAnalyzed(sema: *Sema, decl_index: Decl.Index) CompileError!void {
  29610     const mod = sema.mod;
  29611     const decl = mod.declPtr(decl_index);
  29612     if (decl.analysis == .in_progress) {
  29613         const msg = try Module.ErrorMsg.create(sema.gpa, decl.srcLoc(mod), "dependency loop detected", .{});
  29614         return sema.failWithOwnedErrorMsg(msg);
  29615     }
  29616 
  29617     mod.ensureDeclAnalyzed(decl_index) catch |err| {
  29618         if (sema.owner_func) |owner_func| {
  29619             owner_func.state = .dependency_failure;
  29620         } else {
  29621             sema.owner_decl.analysis = .dependency_failure;
  29622         }
  29623         return err;
  29624     };
  29625 }
  29626 
  29627 fn ensureFuncBodyAnalyzed(sema: *Sema, func: Module.Fn.Index) CompileError!void {
  29628     sema.mod.ensureFuncBodyAnalyzed(func) catch |err| {
  29629         if (sema.owner_func) |owner_func| {
  29630             owner_func.state = .dependency_failure;
  29631         } else {
  29632             sema.owner_decl.analysis = .dependency_failure;
  29633         }
  29634         return err;
  29635     };
  29636 }
  29637 
  29638 fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value {
  29639     const mod = sema.mod;
  29640     var anon_decl = try block.startAnonDecl();
  29641     defer anon_decl.deinit();
  29642     const decl = try anon_decl.finish(
  29643         ty,
  29644         try val.copy(anon_decl.arena()),
  29645         0, // default alignment
  29646     );
  29647     try sema.maybeQueueFuncBodyAnalysis(decl);
  29648     try mod.declareDeclDependency(sema.owner_decl_index, decl);
  29649     const result = try mod.intern(.{ .ptr = .{
  29650         .ty = (try mod.singleConstPtrType(ty)).toIntern(),
  29651         .addr = .{ .decl = decl },
  29652     } });
  29653     return result.toValue();
  29654 }
  29655 
  29656 fn optRefValue(sema: *Sema, block: *Block, ty: Type, opt_val: ?Value) !Value {
  29657     const mod = sema.mod;
  29658     const ptr_anyopaque_ty = try mod.singleConstPtrType(Type.anyopaque);
  29659     return (try mod.intern(.{ .opt = .{
  29660         .ty = (try mod.optionalType(ptr_anyopaque_ty.toIntern())).toIntern(),
  29661         .val = if (opt_val) |val| (try mod.getCoerced(
  29662             try sema.refValue(block, ty, val),
  29663             ptr_anyopaque_ty,
  29664         )).toIntern() else .none,
  29665     } })).toValue();
  29666 }
  29667 
  29668 fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref {
  29669     return sema.analyzeDeclRefInner(decl_index, true);
  29670 }
  29671 
  29672 /// Analyze a reference to the decl at the given index. Ensures the underlying decl is analyzed, but
  29673 /// only triggers analysis for function bodies if `analyze_fn_body` is true. If it's possible for a
  29674 /// decl_ref to end up in runtime code, the function body must be analyzed: `analyzeDeclRef` wraps
  29675 /// this function with `analyze_fn_body` set to true.
  29676 fn analyzeDeclRefInner(sema: *Sema, decl_index: Decl.Index, analyze_fn_body: bool) CompileError!Air.Inst.Ref {
  29677     const mod = sema.mod;
  29678     try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
  29679     try sema.ensureDeclAnalyzed(decl_index);
  29680 
  29681     const decl = mod.declPtr(decl_index);
  29682     const decl_tv = try decl.typedValue();
  29683     const ptr_ty = try mod.ptrType(.{
  29684         .child = decl_tv.ty.toIntern(),
  29685         .flags = .{
  29686             .alignment = InternPool.Alignment.fromByteUnits(decl.@"align"),
  29687             .is_const = if (decl.val.getVariable(mod)) |variable| variable.is_const else true,
  29688             .address_space = decl.@"addrspace",
  29689         },
  29690     });
  29691     if (analyze_fn_body) {
  29692         try sema.maybeQueueFuncBodyAnalysis(decl_index);
  29693     }
  29694     return sema.addConstant(ptr_ty, (try mod.intern(.{ .ptr = .{
  29695         .ty = ptr_ty.toIntern(),
  29696         .addr = .{ .decl = decl_index },
  29697     } })).toValue());
  29698 }
  29699 
  29700 fn maybeQueueFuncBodyAnalysis(sema: *Sema, decl_index: Decl.Index) !void {
  29701     const mod = sema.mod;
  29702     const decl = mod.declPtr(decl_index);
  29703     const tv = try decl.typedValue();
  29704     if (tv.ty.zigTypeTag(mod) != .Fn) return;
  29705     if (!try sema.fnHasRuntimeBits(tv.ty)) return;
  29706     const func_index = mod.intern_pool.indexToFunc(tv.val.toIntern()).unwrap() orelse return; // undef or extern_fn
  29707     try mod.ensureFuncBodyAnalysisQueued(func_index);
  29708 }
  29709 
  29710 fn analyzeRef(
  29711     sema: *Sema,
  29712     block: *Block,
  29713     src: LazySrcLoc,
  29714     operand: Air.Inst.Ref,
  29715 ) CompileError!Air.Inst.Ref {
  29716     const operand_ty = sema.typeOf(operand);
  29717 
  29718     if (try sema.resolveMaybeUndefVal(operand)) |val| {
  29719         switch (sema.mod.intern_pool.indexToKey(val.toIntern())) {
  29720             .extern_func => |extern_func| return sema.analyzeDeclRef(extern_func.decl),
  29721             .func => |func| return sema.analyzeDeclRef(sema.mod.funcPtr(func.index).owner_decl),
  29722             else => {},
  29723         }
  29724         var anon_decl = try block.startAnonDecl();
  29725         defer anon_decl.deinit();
  29726         return sema.analyzeDeclRef(try anon_decl.finish(
  29727             operand_ty,
  29728             try val.copy(anon_decl.arena()),
  29729             0, // default alignment
  29730         ));
  29731     }
  29732 
  29733     try sema.requireRuntimeBlock(block, src, null);
  29734     const address_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);
  29735     const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
  29736         .pointee_type = operand_ty,
  29737         .mutable = false,
  29738         .@"addrspace" = address_space,
  29739     });
  29740     const mut_ptr_type = try Type.ptr(sema.arena, sema.mod, .{
  29741         .pointee_type = operand_ty,
  29742         .@"addrspace" = address_space,
  29743     });
  29744     const alloc = try block.addTy(.alloc, mut_ptr_type);
  29745     try sema.storePtr(block, src, alloc, operand);
  29746 
  29747     // TODO: Replace with sema.coerce when that supports adding pointer constness.
  29748     return sema.bitCast(block, ptr_type, alloc, src, null);
  29749 }
  29750 
  29751 fn analyzeLoad(
  29752     sema: *Sema,
  29753     block: *Block,
  29754     src: LazySrcLoc,
  29755     ptr: Air.Inst.Ref,
  29756     ptr_src: LazySrcLoc,
  29757 ) CompileError!Air.Inst.Ref {
  29758     const mod = sema.mod;
  29759     const ptr_ty = sema.typeOf(ptr);
  29760     const elem_ty = switch (ptr_ty.zigTypeTag(mod)) {
  29761         .Pointer => ptr_ty.childType(mod),
  29762         else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}),
  29763     };
  29764 
  29765     if (try sema.typeHasOnePossibleValue(elem_ty)) |opv| {
  29766         return sema.addConstant(elem_ty, opv);
  29767     }
  29768 
  29769     if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
  29770         if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| {
  29771             return sema.addConstant(elem_ty, try mod.getCoerced(elem_val, elem_ty));
  29772         }
  29773     }
  29774 
  29775     if (ptr_ty.ptrInfo(mod).vector_index == .runtime) {
  29776         const ptr_inst = Air.refToIndex(ptr).?;
  29777         const air_tags = sema.air_instructions.items(.tag);
  29778         if (air_tags[ptr_inst] == .ptr_elem_ptr) {
  29779             const ty_pl = sema.air_instructions.items(.data)[ptr_inst].ty_pl;
  29780             const bin_op = sema.getTmpAir().extraData(Air.Bin, ty_pl.payload).data;
  29781             return block.addBinOp(.ptr_elem_val, bin_op.lhs, bin_op.rhs);
  29782         }
  29783         return sema.fail(block, ptr_src, "unable to determine vector element index of type '{}'", .{
  29784             ptr_ty.fmt(sema.mod),
  29785         });
  29786     }
  29787 
  29788     return block.addTyOp(.load, elem_ty, ptr);
  29789 }
  29790 
  29791 fn analyzeSlicePtr(
  29792     sema: *Sema,
  29793     block: *Block,
  29794     slice_src: LazySrcLoc,
  29795     slice: Air.Inst.Ref,
  29796     slice_ty: Type,
  29797 ) CompileError!Air.Inst.Ref {
  29798     const mod = sema.mod;
  29799     const result_ty = slice_ty.slicePtrFieldType(mod);
  29800     if (try sema.resolveMaybeUndefVal(slice)) |val| {
  29801         if (val.isUndef(mod)) return sema.addConstUndef(result_ty);
  29802         return sema.addConstant(result_ty, val.slicePtr(mod));
  29803     }
  29804     try sema.requireRuntimeBlock(block, slice_src, null);
  29805     return block.addTyOp(.slice_ptr, result_ty, slice);
  29806 }
  29807 
  29808 fn analyzeSliceLen(
  29809     sema: *Sema,
  29810     block: *Block,
  29811     src: LazySrcLoc,
  29812     slice_inst: Air.Inst.Ref,
  29813 ) CompileError!Air.Inst.Ref {
  29814     const mod = sema.mod;
  29815     if (try sema.resolveMaybeUndefVal(slice_inst)) |slice_val| {
  29816         if (slice_val.isUndef(mod)) {
  29817             return sema.addConstUndef(Type.usize);
  29818         }
  29819         return sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod));
  29820     }
  29821     try sema.requireRuntimeBlock(block, src, null);
  29822     return block.addTyOp(.slice_len, Type.usize, slice_inst);
  29823 }
  29824 
  29825 fn analyzeIsNull(
  29826     sema: *Sema,
  29827     block: *Block,
  29828     src: LazySrcLoc,
  29829     operand: Air.Inst.Ref,
  29830     invert_logic: bool,
  29831 ) CompileError!Air.Inst.Ref {
  29832     const mod = sema.mod;
  29833     const result_ty = Type.bool;
  29834     if (try sema.resolveMaybeUndefVal(operand)) |opt_val| {
  29835         if (opt_val.isUndef(mod)) {
  29836             return sema.addConstUndef(result_ty);
  29837         }
  29838         const is_null = opt_val.isNull(mod);
  29839         const bool_value = if (invert_logic) !is_null else is_null;
  29840         if (bool_value) {
  29841             return Air.Inst.Ref.bool_true;
  29842         } else {
  29843             return Air.Inst.Ref.bool_false;
  29844         }
  29845     }
  29846 
  29847     const inverted_non_null_res = if (invert_logic) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false;
  29848     const operand_ty = sema.typeOf(operand);
  29849     if (operand_ty.zigTypeTag(mod) == .Optional and operand_ty.optionalChild(mod).zigTypeTag(mod) == .NoReturn) {
  29850         return inverted_non_null_res;
  29851     }
  29852     if (operand_ty.zigTypeTag(mod) != .Optional and !operand_ty.isPtrLikeOptional(mod)) {
  29853         return inverted_non_null_res;
  29854     }
  29855     try sema.requireRuntimeBlock(block, src, null);
  29856     const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null;
  29857     return block.addUnOp(air_tag, operand);
  29858 }
  29859 
  29860 fn analyzePtrIsNonErrComptimeOnly(
  29861     sema: *Sema,
  29862     block: *Block,
  29863     src: LazySrcLoc,
  29864     operand: Air.Inst.Ref,
  29865 ) CompileError!Air.Inst.Ref {
  29866     const mod = sema.mod;
  29867     const ptr_ty = sema.typeOf(operand);
  29868     assert(ptr_ty.zigTypeTag(mod) == .Pointer);
  29869     const child_ty = ptr_ty.childType(mod);
  29870 
  29871     const child_tag = child_ty.zigTypeTag(mod);
  29872     if (child_tag != .ErrorSet and child_tag != .ErrorUnion) return Air.Inst.Ref.bool_true;
  29873     if (child_tag == .ErrorSet) return Air.Inst.Ref.bool_false;
  29874     assert(child_tag == .ErrorUnion);
  29875 
  29876     _ = block;
  29877     _ = src;
  29878 
  29879     return Air.Inst.Ref.none;
  29880 }
  29881 
  29882 fn analyzeIsNonErrComptimeOnly(
  29883     sema: *Sema,
  29884     block: *Block,
  29885     src: LazySrcLoc,
  29886     operand: Air.Inst.Ref,
  29887 ) CompileError!Air.Inst.Ref {
  29888     const mod = sema.mod;
  29889     const operand_ty = sema.typeOf(operand);
  29890     const ot = operand_ty.zigTypeTag(mod);
  29891     if (ot != .ErrorSet and ot != .ErrorUnion) return Air.Inst.Ref.bool_true;
  29892     if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;
  29893     assert(ot == .ErrorUnion);
  29894 
  29895     const payload_ty = operand_ty.errorUnionPayload(mod);
  29896     if (payload_ty.zigTypeTag(mod) == .NoReturn) {
  29897         return Air.Inst.Ref.bool_false;
  29898     }
  29899 
  29900     if (Air.refToIndex(operand)) |operand_inst| {
  29901         switch (sema.air_instructions.items(.tag)[operand_inst]) {
  29902             .wrap_errunion_payload => return Air.Inst.Ref.bool_true,
  29903             .wrap_errunion_err => return Air.Inst.Ref.bool_false,
  29904             else => {},
  29905         }
  29906     } else if (operand == .undef) {
  29907         return sema.addConstUndef(Type.bool);
  29908     } else {
  29909         // None of the ref tags can be errors.
  29910         return Air.Inst.Ref.bool_true;
  29911     }
  29912 
  29913     const maybe_operand_val = try sema.resolveMaybeUndefVal(operand);
  29914 
  29915     // exception if the error union error set is known to be empty,
  29916     // we allow the comparison but always make it comptime-known.
  29917     const set_ty = operand_ty.errorUnionSet(mod);
  29918     switch (set_ty.toIntern()) {
  29919         .anyerror_type => {},
  29920         else => switch (mod.intern_pool.indexToKey(set_ty.toIntern())) {
  29921             .error_set_type => |error_set_type| {
  29922                 if (error_set_type.names.len == 0) return Air.Inst.Ref.bool_true;
  29923             },
  29924             .inferred_error_set_type => |ies_index| blk: {
  29925                 // If the error set is empty, we must return a comptime true or false.
  29926                 // However we want to avoid unnecessarily resolving an inferred error set
  29927                 // in case it is already non-empty.
  29928                 const ies = mod.inferredErrorSetPtr(ies_index);
  29929                 if (ies.is_anyerror) break :blk;
  29930                 if (ies.errors.count() != 0) break :blk;
  29931                 if (maybe_operand_val == null) {
  29932                     // Try to avoid resolving inferred error set if possible.
  29933                     if (ies.errors.count() != 0) break :blk;
  29934                     if (ies.is_anyerror) break :blk;
  29935                     for (ies.inferred_error_sets.keys()) |other_ies_index| {
  29936                         if (ies_index == other_ies_index) continue;
  29937                         try sema.resolveInferredErrorSet(block, src, other_ies_index);
  29938                         const other_ies = mod.inferredErrorSetPtr(other_ies_index);
  29939                         if (other_ies.is_anyerror) {
  29940                             ies.is_anyerror = true;
  29941                             ies.is_resolved = true;
  29942                             break :blk;
  29943                         }
  29944 
  29945                         if (other_ies.errors.count() != 0) break :blk;
  29946                     }
  29947                     if (ies.func == sema.owner_func_index.unwrap()) {
  29948                         // We're checking the inferred errorset of the current function and none of
  29949                         // its child inferred error sets contained any errors meaning that any value
  29950                         // so far with this type can't contain errors either.
  29951                         return Air.Inst.Ref.bool_true;
  29952                     }
  29953                     try sema.resolveInferredErrorSet(block, src, ies_index);
  29954                     if (ies.is_anyerror) break :blk;
  29955                     if (ies.errors.count() == 0) return Air.Inst.Ref.bool_true;
  29956                 }
  29957             },
  29958             else => unreachable,
  29959         },
  29960     }
  29961 
  29962     if (maybe_operand_val) |err_union| {
  29963         if (err_union.isUndef(mod)) {
  29964             return sema.addConstUndef(Type.bool);
  29965         }
  29966         if (err_union.getError(mod) == null) {
  29967             return Air.Inst.Ref.bool_true;
  29968         } else {
  29969             return Air.Inst.Ref.bool_false;
  29970         }
  29971     }
  29972     return Air.Inst.Ref.none;
  29973 }
  29974 
  29975 fn analyzeIsNonErr(
  29976     sema: *Sema,
  29977     block: *Block,
  29978     src: LazySrcLoc,
  29979     operand: Air.Inst.Ref,
  29980 ) CompileError!Air.Inst.Ref {
  29981     const result = try sema.analyzeIsNonErrComptimeOnly(block, src, operand);
  29982     if (result == .none) {
  29983         try sema.requireRuntimeBlock(block, src, null);
  29984         return block.addUnOp(.is_non_err, operand);
  29985     } else {
  29986         return result;
  29987     }
  29988 }
  29989 
  29990 fn analyzePtrIsNonErr(
  29991     sema: *Sema,
  29992     block: *Block,
  29993     src: LazySrcLoc,
  29994     operand: Air.Inst.Ref,
  29995 ) CompileError!Air.Inst.Ref {
  29996     const result = try sema.analyzePtrIsNonErrComptimeOnly(block, src, operand);
  29997     if (result == .none) {
  29998         try sema.requireRuntimeBlock(block, src, null);
  29999         return block.addUnOp(.is_non_err_ptr, operand);
  30000     } else {
  30001         return result;
  30002     }
  30003 }
  30004 
  30005 fn analyzeSlice(
  30006     sema: *Sema,
  30007     block: *Block,
  30008     src: LazySrcLoc,
  30009     ptr_ptr: Air.Inst.Ref,
  30010     uncasted_start: Air.Inst.Ref,
  30011     uncasted_end_opt: Air.Inst.Ref,
  30012     sentinel_opt: Air.Inst.Ref,
  30013     sentinel_src: LazySrcLoc,
  30014     ptr_src: LazySrcLoc,
  30015     start_src: LazySrcLoc,
  30016     end_src: LazySrcLoc,
  30017     by_length: bool,
  30018 ) CompileError!Air.Inst.Ref {
  30019     const mod = sema.mod;
  30020     // Slice expressions can operate on a variable whose type is an array. This requires
  30021     // the slice operand to be a pointer. In the case of a non-array, it will be a double pointer.
  30022     const ptr_ptr_ty = sema.typeOf(ptr_ptr);
  30023     const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag(mod)) {
  30024         .Pointer => ptr_ptr_ty.childType(mod),
  30025         else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(mod)}),
  30026     };
  30027 
  30028     var array_ty = ptr_ptr_child_ty;
  30029     var slice_ty = ptr_ptr_ty;
  30030     var ptr_or_slice = ptr_ptr;
  30031     var elem_ty: Type = undefined;
  30032     var ptr_sentinel: ?Value = null;
  30033     switch (ptr_ptr_child_ty.zigTypeTag(mod)) {
  30034         .Array => {
  30035             ptr_sentinel = ptr_ptr_child_ty.sentinel(mod);
  30036             elem_ty = ptr_ptr_child_ty.childType(mod);
  30037         },
  30038         .Pointer => switch (ptr_ptr_child_ty.ptrSize(mod)) {
  30039             .One => {
  30040                 const double_child_ty = ptr_ptr_child_ty.childType(mod);
  30041                 if (double_child_ty.zigTypeTag(mod) == .Array) {
  30042                     ptr_sentinel = double_child_ty.sentinel(mod);
  30043                     ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
  30044                     slice_ty = ptr_ptr_child_ty;
  30045                     array_ty = double_child_ty;
  30046                     elem_ty = double_child_ty.childType(mod);
  30047                 } else {
  30048                     return sema.fail(block, src, "slice of single-item pointer", .{});
  30049                 }
  30050             },
  30051             .Many, .C => {
  30052                 ptr_sentinel = ptr_ptr_child_ty.sentinel(mod);
  30053                 ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
  30054                 slice_ty = ptr_ptr_child_ty;
  30055                 array_ty = ptr_ptr_child_ty;
  30056                 elem_ty = ptr_ptr_child_ty.childType(mod);
  30057 
  30058                 if (ptr_ptr_child_ty.ptrSize(mod) == .C) {
  30059                     if (try sema.resolveDefinedValue(block, ptr_src, ptr_or_slice)) |ptr_val| {
  30060                         if (ptr_val.isNull(mod)) {
  30061                             return sema.fail(block, src, "slice of null pointer", .{});
  30062                         }
  30063                     }
  30064                 }
  30065             },
  30066             .Slice => {
  30067                 ptr_sentinel = ptr_ptr_child_ty.sentinel(mod);
  30068                 ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
  30069                 slice_ty = ptr_ptr_child_ty;
  30070                 array_ty = ptr_ptr_child_ty;
  30071                 elem_ty = ptr_ptr_child_ty.childType(mod);
  30072             },
  30073         },
  30074         else => return sema.fail(block, src, "slice of non-array type '{}'", .{ptr_ptr_child_ty.fmt(mod)}),
  30075     }
  30076 
  30077     const ptr = if (slice_ty.isSlice(mod))
  30078         try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty)
  30079     else if (array_ty.zigTypeTag(mod) == .Array) ptr: {
  30080         var manyptr_ty_key = mod.intern_pool.indexToKey(slice_ty.toIntern()).ptr_type;
  30081         assert(manyptr_ty_key.child == array_ty.toIntern());
  30082         assert(manyptr_ty_key.flags.size == .One);
  30083         manyptr_ty_key.child = elem_ty.toIntern();
  30084         manyptr_ty_key.flags.size = .Many;
  30085         break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(manyptr_ty_key), ptr_or_slice, ptr_src);
  30086     } else ptr_or_slice;
  30087 
  30088     const start = try sema.coerce(block, Type.usize, uncasted_start, start_src);
  30089     const new_ptr = try sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src);
  30090     const new_ptr_ty = sema.typeOf(new_ptr);
  30091 
  30092     // true if and only if the end index of the slice, implicitly or explicitly, equals
  30093     // the length of the underlying object being sliced. we might learn the length of the
  30094     // underlying object because it is an array (which has the length in the type), or
  30095     // we might learn of the length because it is a comptime-known slice value.
  30096     var end_is_len = uncasted_end_opt == .none;
  30097     const end = e: {
  30098         if (array_ty.zigTypeTag(mod) == .Array) {
  30099             const len_val = try mod.intValue(Type.usize, array_ty.arrayLen(mod));
  30100 
  30101             if (!end_is_len) {
  30102                 const end = if (by_length) end: {
  30103                     const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
  30104                     const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false);
  30105                     break :end try sema.coerce(block, Type.usize, uncasted_end, end_src);
  30106                 } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
  30107                 if (try sema.resolveMaybeUndefVal(end)) |end_val| {
  30108                     const len_s_val = try mod.intValue(
  30109                         Type.usize,
  30110                         array_ty.arrayLenIncludingSentinel(mod),
  30111                     );
  30112                     if (!(try sema.compareAll(end_val, .lte, len_s_val, Type.usize))) {
  30113                         const sentinel_label: []const u8 = if (array_ty.sentinel(mod) != null)
  30114                             " +1 (sentinel)"
  30115                         else
  30116                             "";
  30117 
  30118                         return sema.fail(
  30119                             block,
  30120                             end_src,
  30121                             "end index {} out of bounds for array of length {}{s}",
  30122                             .{
  30123                                 end_val.fmtValue(Type.usize, mod),
  30124                                 len_val.fmtValue(Type.usize, mod),
  30125                                 sentinel_label,
  30126                             },
  30127                         );
  30128                     }
  30129 
  30130                     // end_is_len is only true if we are NOT using the sentinel
  30131                     // length. For sentinel-length, we don't want the type to
  30132                     // contain the sentinel.
  30133                     if (end_val.eql(len_val, Type.usize, mod)) {
  30134                         end_is_len = true;
  30135                     }
  30136                 }
  30137                 break :e end;
  30138             }
  30139 
  30140             break :e try sema.addConstant(Type.usize, len_val);
  30141         } else if (slice_ty.isSlice(mod)) {
  30142             if (!end_is_len) {
  30143                 const end = if (by_length) end: {
  30144                     const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
  30145                     const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false);
  30146                     break :end try sema.coerce(block, Type.usize, uncasted_end, end_src);
  30147                 } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
  30148                 if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {
  30149                     if (try sema.resolveMaybeUndefVal(ptr_or_slice)) |slice_val| {
  30150                         if (slice_val.isUndef(mod)) {
  30151                             return sema.fail(block, src, "slice of undefined", .{});
  30152                         }
  30153                         const has_sentinel = slice_ty.sentinel(mod) != null;
  30154                         const slice_len = slice_val.sliceLen(mod);
  30155                         const len_plus_sent = slice_len + @boolToInt(has_sentinel);
  30156                         const slice_len_val_with_sentinel = try mod.intValue(Type.usize, len_plus_sent);
  30157                         if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, Type.usize))) {
  30158                             const sentinel_label: []const u8 = if (has_sentinel)
  30159                                 " +1 (sentinel)"
  30160                             else
  30161                                 "";
  30162 
  30163                             return sema.fail(
  30164                                 block,
  30165                                 end_src,
  30166                                 "end index {} out of bounds for slice of length {d}{s}",
  30167                                 .{
  30168                                     end_val.fmtValue(Type.usize, mod),
  30169                                     slice_val.sliceLen(mod),
  30170                                     sentinel_label,
  30171                                 },
  30172                             );
  30173                         }
  30174 
  30175                         // If the slice has a sentinel, we consider end_is_len
  30176                         // is only true if it equals the length WITHOUT the
  30177                         // sentinel, so we don't add a sentinel type.
  30178                         const slice_len_val = try mod.intValue(Type.usize, slice_len);
  30179                         if (end_val.eql(slice_len_val, Type.usize, mod)) {
  30180                             end_is_len = true;
  30181                         }
  30182                     }
  30183                 }
  30184                 break :e end;
  30185             }
  30186             break :e try sema.analyzeSliceLen(block, src, ptr_or_slice);
  30187         }
  30188         if (!end_is_len) {
  30189             if (by_length) {
  30190                 const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
  30191                 const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false);
  30192                 break :e try sema.coerce(block, Type.usize, uncasted_end, end_src);
  30193             } else break :e try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
  30194         }
  30195         return sema.fail(block, src, "slice of pointer must include end value", .{});
  30196     };
  30197 
  30198     const sentinel = s: {
  30199         if (sentinel_opt != .none) {
  30200             const casted = try sema.coerce(block, elem_ty, sentinel_opt, sentinel_src);
  30201             break :s try sema.resolveConstValue(block, sentinel_src, casted, "slice sentinel must be comptime-known");
  30202         }
  30203         // If we are slicing to the end of something that is sentinel-terminated
  30204         // then the resulting slice type is also sentinel-terminated.
  30205         if (end_is_len) {
  30206             if (ptr_sentinel) |sent| {
  30207                 break :s sent;
  30208             }
  30209         }
  30210         break :s null;
  30211     };
  30212     const slice_sentinel = if (sentinel_opt != .none) sentinel else null;
  30213 
  30214     var checked_start_lte_end = by_length;
  30215     var runtime_src: ?LazySrcLoc = null;
  30216 
  30217     // requirement: start <= end
  30218     if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {
  30219         if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| {
  30220             if (!by_length and !(try sema.compareAll(start_val, .lte, end_val, Type.usize))) {
  30221                 return sema.fail(
  30222                     block,
  30223                     start_src,
  30224                     "start index {} is larger than end index {}",
  30225                     .{
  30226                         start_val.fmtValue(Type.usize, mod),
  30227                         end_val.fmtValue(Type.usize, mod),
  30228                     },
  30229                 );
  30230             }
  30231             checked_start_lte_end = true;
  30232             if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: {
  30233                 const expected_sentinel = sentinel orelse break :sentinel_check;
  30234                 const start_int = start_val.getUnsignedInt(mod).?;
  30235                 const end_int = end_val.getUnsignedInt(mod).?;
  30236                 const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int);
  30237 
  30238                 const many_ptr_ty = try mod.manyConstPtrType(elem_ty);
  30239                 const many_ptr_val = try mod.getCoerced(ptr_val, many_ptr_ty);
  30240                 const elem_ptr_ty = try mod.singleConstPtrType(elem_ty);
  30241                 const elem_ptr = try many_ptr_val.elemPtr(elem_ptr_ty, sentinel_index, mod);
  30242                 const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty);
  30243                 const actual_sentinel = switch (res) {
  30244                     .runtime_load => break :sentinel_check,
  30245                     .val => |v| v,
  30246                     .needed_well_defined => |ty| return sema.fail(
  30247                         block,
  30248                         src,
  30249                         "comptime dereference requires '{}' to have a well-defined layout, but it does not.",
  30250                         .{ty.fmt(mod)},
  30251                     ),
  30252                     .out_of_bounds => |ty| return sema.fail(
  30253                         block,
  30254                         end_src,
  30255                         "slice end index {d} exceeds bounds of containing decl of type '{}'",
  30256                         .{ end_int, ty.fmt(mod) },
  30257                     ),
  30258                 };
  30259 
  30260                 if (!actual_sentinel.eql(expected_sentinel, elem_ty, mod)) {
  30261                     const msg = msg: {
  30262                         const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{});
  30263                         errdefer msg.destroy(sema.gpa);
  30264                         try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{
  30265                             expected_sentinel.fmtValue(elem_ty, mod),
  30266                             actual_sentinel.fmtValue(elem_ty, mod),
  30267                         });
  30268 
  30269                         break :msg msg;
  30270                     };
  30271                     return sema.failWithOwnedErrorMsg(msg);
  30272                 }
  30273             } else {
  30274                 runtime_src = ptr_src;
  30275             }
  30276         } else {
  30277             runtime_src = start_src;
  30278         }
  30279     } else {
  30280         runtime_src = end_src;
  30281     }
  30282 
  30283     if (!checked_start_lte_end and block.wantSafety() and !block.is_comptime) {
  30284         // requirement: start <= end
  30285         assert(!block.is_comptime);
  30286         try sema.requireRuntimeBlock(block, src, runtime_src.?);
  30287         const ok = try block.addBinOp(.cmp_lte, start, end);
  30288         if (!sema.mod.comp.formatted_panics) {
  30289             try sema.addSafetyCheck(block, ok, .start_index_greater_than_end);
  30290         } else {
  30291             try sema.safetyCheckFormatted(block, ok, "panicStartGreaterThanEnd", &.{ start, end });
  30292         }
  30293     }
  30294     const new_len = if (by_length)
  30295         try sema.coerce(block, Type.usize, uncasted_end_opt, end_src)
  30296     else
  30297         try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false);
  30298     const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);
  30299 
  30300     const new_ptr_ty_info = new_ptr_ty.ptrInfo(mod);
  30301     const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize(mod) != .C;
  30302 
  30303     if (opt_new_len_val) |new_len_val| {
  30304         const new_len_int = new_len_val.toUnsignedInt(mod);
  30305 
  30306         const return_ty = try Type.ptr(sema.arena, mod, .{
  30307             .pointee_type = try Type.array(sema.arena, new_len_int, sentinel, elem_ty, mod),
  30308             .sentinel = null,
  30309             .@"align" = new_ptr_ty_info.@"align",
  30310             .@"addrspace" = new_ptr_ty_info.@"addrspace",
  30311             .mutable = new_ptr_ty_info.mutable,
  30312             .@"allowzero" = new_allowzero,
  30313             .@"volatile" = new_ptr_ty_info.@"volatile",
  30314             .size = .One,
  30315         });
  30316 
  30317         const opt_new_ptr_val = try sema.resolveMaybeUndefVal(new_ptr);
  30318         const new_ptr_val = opt_new_ptr_val orelse {
  30319             const result = try block.addBitCast(return_ty, new_ptr);
  30320             if (block.wantSafety()) {
  30321                 // requirement: slicing C ptr is non-null
  30322                 if (ptr_ptr_child_ty.isCPtr(mod)) {
  30323                     const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true);
  30324                     try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
  30325                 }
  30326 
  30327                 if (slice_ty.isSlice(mod)) {
  30328                     const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice);
  30329                     const actual_len = if (slice_ty.sentinel(mod) == null)
  30330                         slice_len_inst
  30331                     else
  30332                         try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true);
  30333 
  30334                     const actual_end = if (slice_sentinel != null)
  30335                         try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src, true)
  30336                     else
  30337                         end;
  30338 
  30339                     try sema.panicIndexOutOfBounds(block, actual_end, actual_len, .cmp_lte);
  30340                 }
  30341 
  30342                 // requirement: result[new_len] == slice_sentinel
  30343                 try sema.panicSentinelMismatch(block, slice_sentinel, elem_ty, result, new_len);
  30344             }
  30345             return result;
  30346         };
  30347 
  30348         if (!new_ptr_val.isUndef(mod)) {
  30349             return sema.addConstant(return_ty, try mod.getCoerced(
  30350                 (try new_ptr_val.intern(new_ptr_ty, mod)).toValue(),
  30351                 return_ty,
  30352             ));
  30353         }
  30354 
  30355         // Special case: @as([]i32, undefined)[x..x]
  30356         if (new_len_int == 0) {
  30357             return sema.addConstUndef(return_ty);
  30358         }
  30359 
  30360         return sema.fail(block, src, "non-zero length slice of undefined pointer", .{});
  30361     }
  30362 
  30363     const return_ty = try Type.ptr(sema.arena, mod, .{
  30364         .pointee_type = elem_ty,
  30365         .sentinel = sentinel,
  30366         .@"align" = new_ptr_ty_info.@"align",
  30367         .@"addrspace" = new_ptr_ty_info.@"addrspace",
  30368         .mutable = new_ptr_ty_info.mutable,
  30369         .@"allowzero" = new_allowzero,
  30370         .@"volatile" = new_ptr_ty_info.@"volatile",
  30371         .size = .Slice,
  30372     });
  30373 
  30374     try sema.requireRuntimeBlock(block, src, runtime_src.?);
  30375     if (block.wantSafety()) {
  30376         // requirement: slicing C ptr is non-null
  30377         if (ptr_ptr_child_ty.isCPtr(mod)) {
  30378             const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true);
  30379             try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
  30380         }
  30381 
  30382         // requirement: end <= len
  30383         const opt_len_inst = if (array_ty.zigTypeTag(mod) == .Array)
  30384             try sema.addIntUnsigned(Type.usize, array_ty.arrayLenIncludingSentinel(mod))
  30385         else if (slice_ty.isSlice(mod)) blk: {
  30386             if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| {
  30387                 // we don't need to add one for sentinels because the
  30388                 // underlying value data includes the sentinel
  30389                 break :blk try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(mod));
  30390             }
  30391 
  30392             const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice);
  30393             if (slice_ty.sentinel(mod) == null) break :blk slice_len_inst;
  30394 
  30395             // we have to add one because slice lengths don't include the sentinel
  30396             break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true);
  30397         } else null;
  30398         if (opt_len_inst) |len_inst| {
  30399             const actual_end = if (slice_sentinel != null)
  30400                 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src, true)
  30401             else
  30402                 end;
  30403             try sema.panicIndexOutOfBounds(block, actual_end, len_inst, .cmp_lte);
  30404         }
  30405 
  30406         // requirement: start <= end
  30407         try sema.panicIndexOutOfBounds(block, start, end, .cmp_lte);
  30408     }
  30409     const result = try block.addInst(.{
  30410         .tag = .slice,
  30411         .data = .{ .ty_pl = .{
  30412             .ty = try sema.addType(return_ty),
  30413             .payload = try sema.addExtra(Air.Bin{
  30414                 .lhs = new_ptr,
  30415                 .rhs = new_len,
  30416             }),
  30417         } },
  30418     });
  30419     if (block.wantSafety()) {
  30420         // requirement: result[new_len] == slice_sentinel
  30421         try sema.panicSentinelMismatch(block, slice_sentinel, elem_ty, result, new_len);
  30422     }
  30423     return result;
  30424 }
  30425 
  30426 /// Asserts that lhs and rhs types are both numeric.
  30427 fn cmpNumeric(
  30428     sema: *Sema,
  30429     block: *Block,
  30430     src: LazySrcLoc,
  30431     uncasted_lhs: Air.Inst.Ref,
  30432     uncasted_rhs: Air.Inst.Ref,
  30433     op: std.math.CompareOperator,
  30434     lhs_src: LazySrcLoc,
  30435     rhs_src: LazySrcLoc,
  30436 ) CompileError!Air.Inst.Ref {
  30437     const mod = sema.mod;
  30438     const lhs_ty = sema.typeOf(uncasted_lhs);
  30439     const rhs_ty = sema.typeOf(uncasted_rhs);
  30440 
  30441     assert(lhs_ty.isNumeric(mod));
  30442     assert(rhs_ty.isNumeric(mod));
  30443 
  30444     const lhs_ty_tag = lhs_ty.zigTypeTag(mod);
  30445     const rhs_ty_tag = rhs_ty.zigTypeTag(mod);
  30446     const target = mod.getTarget();
  30447 
  30448     // One exception to heterogeneous comparison: comptime_float needs to
  30449     // coerce to fixed-width float.
  30450 
  30451     const lhs = if (lhs_ty_tag == .ComptimeFloat and rhs_ty_tag == .Float)
  30452         try sema.coerce(block, rhs_ty, uncasted_lhs, lhs_src)
  30453     else
  30454         uncasted_lhs;
  30455 
  30456     const rhs = if (lhs_ty_tag == .Float and rhs_ty_tag == .ComptimeFloat)
  30457         try sema.coerce(block, lhs_ty, uncasted_rhs, rhs_src)
  30458     else
  30459         uncasted_rhs;
  30460 
  30461     const runtime_src: LazySrcLoc = src: {
  30462         if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| {
  30463             if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| {
  30464                 // Compare ints: const vs. undefined (or vice versa)
  30465                 if (!lhs_val.isUndef(mod) and (lhs_ty.isInt(mod) or lhs_ty_tag == .ComptimeInt) and rhs_ty.isInt(mod) and rhs_val.isUndef(mod)) {
  30466                     if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(lhs_val), op, rhs_ty)) |res| {
  30467                         return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false;
  30468                     }
  30469                 } else if (!rhs_val.isUndef(mod) and (rhs_ty.isInt(mod) or rhs_ty_tag == .ComptimeInt) and lhs_ty.isInt(mod) and lhs_val.isUndef(mod)) {
  30470                     if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(rhs_val), op.reverse(), lhs_ty)) |res| {
  30471                         return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false;
  30472                     }
  30473                 }
  30474 
  30475                 if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) {
  30476                     return sema.addConstUndef(Type.bool);
  30477                 }
  30478                 if (lhs_val.isNan(mod) or rhs_val.isNan(mod)) {
  30479                     if (op == std.math.CompareOperator.neq) {
  30480                         return Air.Inst.Ref.bool_true;
  30481                     } else {
  30482                         return Air.Inst.Ref.bool_false;
  30483                     }
  30484                 }
  30485                 if (try Value.compareHeteroAdvanced(lhs_val, op, rhs_val, mod, sema)) {
  30486                     return Air.Inst.Ref.bool_true;
  30487                 } else {
  30488                     return Air.Inst.Ref.bool_false;
  30489                 }
  30490             } else {
  30491                 if (!lhs_val.isUndef(mod) and (lhs_ty.isInt(mod) or lhs_ty_tag == .ComptimeInt) and rhs_ty.isInt(mod)) {
  30492                     // Compare ints: const vs. var
  30493                     if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(lhs_val), op, rhs_ty)) |res| {
  30494                         return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false;
  30495                     }
  30496                 }
  30497                 break :src rhs_src;
  30498             }
  30499         } else {
  30500             if (try sema.resolveMaybeUndefLazyVal(rhs)) |rhs_val| {
  30501                 if (!rhs_val.isUndef(mod) and (rhs_ty.isInt(mod) or rhs_ty_tag == .ComptimeInt) and lhs_ty.isInt(mod)) {
  30502                     // Compare ints: var vs. const
  30503                     if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(rhs_val), op.reverse(), lhs_ty)) |res| {
  30504                         return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false;
  30505                     }
  30506                 }
  30507             }
  30508             break :src lhs_src;
  30509         }
  30510     };
  30511 
  30512     // TODO handle comparisons against lazy zero values
  30513     // Some values can be compared against zero without being runtime-known or without forcing
  30514     // a full resolution of their value, for example `@sizeOf(@Frame(function))` is known to
  30515     // always be nonzero, and we benefit from not forcing the full evaluation and stack frame layout
  30516     // of this function if we don't need to.
  30517     try sema.requireRuntimeBlock(block, src, runtime_src);
  30518 
  30519     // For floats, emit a float comparison instruction.
  30520     const lhs_is_float = switch (lhs_ty_tag) {
  30521         .Float, .ComptimeFloat => true,
  30522         else => false,
  30523     };
  30524     const rhs_is_float = switch (rhs_ty_tag) {
  30525         .Float, .ComptimeFloat => true,
  30526         else => false,
  30527     };
  30528 
  30529     if (lhs_is_float and rhs_is_float) {
  30530         // Smaller fixed-width floats coerce to larger fixed-width floats.
  30531         // comptime_float coerces to fixed-width float.
  30532         const dest_ty = x: {
  30533             if (lhs_ty_tag == .ComptimeFloat) {
  30534                 break :x rhs_ty;
  30535             } else if (rhs_ty_tag == .ComptimeFloat) {
  30536                 break :x lhs_ty;
  30537             }
  30538             if (lhs_ty.floatBits(target) >= rhs_ty.floatBits(target)) {
  30539                 break :x lhs_ty;
  30540             } else {
  30541                 break :x rhs_ty;
  30542             }
  30543         };
  30544         const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src);
  30545         const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src);
  30546         return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs);
  30547     }
  30548     // For mixed unsigned integer sizes, implicit cast both operands to the larger integer.
  30549     // For mixed signed and unsigned integers, implicit cast both operands to a signed
  30550     // integer with + 1 bit.
  30551     // For mixed floats and integers, extract the integer part from the float, cast that to
  30552     // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
  30553     // add/subtract 1.
  30554     const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val|
  30555         !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema))
  30556     else
  30557         (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt(mod));
  30558     const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val|
  30559         !(try rhs_val.compareAllWithZeroAdvanced(.gte, sema))
  30560     else
  30561         (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt(mod));
  30562     const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
  30563 
  30564     var dest_float_type: ?Type = null;
  30565 
  30566     var lhs_bits: usize = undefined;
  30567     if (try sema.resolveMaybeUndefLazyVal(lhs)) |lhs_val| {
  30568         if (lhs_val.isUndef(mod))
  30569             return sema.addConstUndef(Type.bool);
  30570         if (lhs_val.isNan(mod)) switch (op) {
  30571             .neq => return Air.Inst.Ref.bool_true,
  30572             else => return Air.Inst.Ref.bool_false,
  30573         };
  30574         if (lhs_val.isInf(mod)) switch (op) {
  30575             .neq => return Air.Inst.Ref.bool_true,
  30576             .eq => return Air.Inst.Ref.bool_false,
  30577             .gt, .gte => return if (lhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true,
  30578             .lt, .lte => return if (lhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false,
  30579         };
  30580         if (!rhs_is_signed) {
  30581             switch (lhs_val.orderAgainstZero(mod)) {
  30582                 .gt => {},
  30583                 .eq => switch (op) { // LHS = 0, RHS is unsigned
  30584                     .lte => return Air.Inst.Ref.bool_true,
  30585                     .gt => return Air.Inst.Ref.bool_false,
  30586                     else => {},
  30587                 },
  30588                 .lt => switch (op) { // LHS < 0, RHS is unsigned
  30589                     .neq, .lt, .lte => return Air.Inst.Ref.bool_true,
  30590                     .eq, .gt, .gte => return Air.Inst.Ref.bool_false,
  30591                 },
  30592             }
  30593         }
  30594         if (lhs_is_float) {
  30595             if (lhs_val.floatHasFraction(mod)) {
  30596                 switch (op) {
  30597                     .eq => return Air.Inst.Ref.bool_false,
  30598                     .neq => return Air.Inst.Ref.bool_true,
  30599                     else => {},
  30600                 }
  30601             }
  30602 
  30603             var bigint = try float128IntPartToBigInt(sema.gpa, lhs_val.toFloat(f128, mod));
  30604             defer bigint.deinit();
  30605             if (lhs_val.floatHasFraction(mod)) {
  30606                 if (lhs_is_signed) {
  30607                     try bigint.addScalar(&bigint, -1);
  30608                 } else {
  30609                     try bigint.addScalar(&bigint, 1);
  30610                 }
  30611             }
  30612             lhs_bits = bigint.toConst().bitCountTwosComp();
  30613         } else {
  30614             lhs_bits = lhs_val.intBitCountTwosComp(mod);
  30615         }
  30616         lhs_bits += @boolToInt(!lhs_is_signed and dest_int_is_signed);
  30617     } else if (lhs_is_float) {
  30618         dest_float_type = lhs_ty;
  30619     } else {
  30620         const int_info = lhs_ty.intInfo(mod);
  30621         lhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed);
  30622     }
  30623 
  30624     var rhs_bits: usize = undefined;
  30625     if (try sema.resolveMaybeUndefLazyVal(rhs)) |rhs_val| {
  30626         if (rhs_val.isUndef(mod))
  30627             return sema.addConstUndef(Type.bool);
  30628         if (rhs_val.isNan(mod)) switch (op) {
  30629             .neq => return Air.Inst.Ref.bool_true,
  30630             else => return Air.Inst.Ref.bool_false,
  30631         };
  30632         if (rhs_val.isInf(mod)) switch (op) {
  30633             .neq => return Air.Inst.Ref.bool_true,
  30634             .eq => return Air.Inst.Ref.bool_false,
  30635             .gt, .gte => return if (rhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false,
  30636             .lt, .lte => return if (rhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true,
  30637         };
  30638         if (!lhs_is_signed) {
  30639             switch (rhs_val.orderAgainstZero(mod)) {
  30640                 .gt => {},
  30641                 .eq => switch (op) { // RHS = 0, LHS is unsigned
  30642                     .gte => return Air.Inst.Ref.bool_true,
  30643                     .lt => return Air.Inst.Ref.bool_false,
  30644                     else => {},
  30645                 },
  30646                 .lt => switch (op) { // RHS < 0, LHS is unsigned
  30647                     .neq, .gt, .gte => return Air.Inst.Ref.bool_true,
  30648                     .eq, .lt, .lte => return Air.Inst.Ref.bool_false,
  30649                 },
  30650             }
  30651         }
  30652         if (rhs_is_float) {
  30653             if (rhs_val.floatHasFraction(mod)) {
  30654                 switch (op) {
  30655                     .eq => return Air.Inst.Ref.bool_false,
  30656                     .neq => return Air.Inst.Ref.bool_true,
  30657                     else => {},
  30658                 }
  30659             }
  30660 
  30661             var bigint = try float128IntPartToBigInt(sema.gpa, rhs_val.toFloat(f128, mod));
  30662             defer bigint.deinit();
  30663             if (rhs_val.floatHasFraction(mod)) {
  30664                 if (rhs_is_signed) {
  30665                     try bigint.addScalar(&bigint, -1);
  30666                 } else {
  30667                     try bigint.addScalar(&bigint, 1);
  30668                 }
  30669             }
  30670             rhs_bits = bigint.toConst().bitCountTwosComp();
  30671         } else {
  30672             rhs_bits = rhs_val.intBitCountTwosComp(mod);
  30673         }
  30674         rhs_bits += @boolToInt(!rhs_is_signed and dest_int_is_signed);
  30675     } else if (rhs_is_float) {
  30676         dest_float_type = rhs_ty;
  30677     } else {
  30678         const int_info = rhs_ty.intInfo(mod);
  30679         rhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed);
  30680     }
  30681 
  30682     const dest_ty = if (dest_float_type) |ft| ft else blk: {
  30683         const max_bits = std.math.max(lhs_bits, rhs_bits);
  30684         const casted_bits = std.math.cast(u16, max_bits) orelse return sema.fail(block, src, "{d} exceeds maximum integer bit count", .{max_bits});
  30685         const signedness: std.builtin.Signedness = if (dest_int_is_signed) .signed else .unsigned;
  30686         break :blk try mod.intType(signedness, casted_bits);
  30687     };
  30688     const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src);
  30689     const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src);
  30690 
  30691     return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs);
  30692 }
  30693 
  30694 /// Asserts that LHS value is an int or comptime int and not undefined, and
  30695 /// that RHS type is an int. Given a const LHS and an unknown RHS, attempt to
  30696 /// determine whether `op` has a guaranteed result.
  30697 /// If it cannot be determined, returns null.
  30698 /// Otherwise returns a bool for the guaranteed comparison operation.
  30699 fn compareIntsOnlyPossibleResult(
  30700     sema: *Sema,
  30701     lhs_val: Value,
  30702     op: std.math.CompareOperator,
  30703     rhs_ty: Type,
  30704 ) Allocator.Error!?bool {
  30705     const mod = sema.mod;
  30706     const rhs_info = rhs_ty.intInfo(mod);
  30707     const vs_zero = lhs_val.orderAgainstZeroAdvanced(mod, sema) catch unreachable;
  30708     const is_zero = vs_zero == .eq;
  30709     const is_negative = vs_zero == .lt;
  30710     const is_positive = vs_zero == .gt;
  30711 
  30712     // Anything vs. zero-sized type has guaranteed outcome.
  30713     if (rhs_info.bits == 0) return switch (op) {
  30714         .eq, .lte, .gte => is_zero,
  30715         .neq, .lt, .gt => !is_zero,
  30716     };
  30717 
  30718     // Special case for i1, which can only be 0 or -1.
  30719     // Zero and positive ints have guaranteed outcome.
  30720     if (rhs_info.bits == 1 and rhs_info.signedness == .signed) {
  30721         if (is_positive) return switch (op) {
  30722             .gt, .gte, .neq => true,
  30723             .lt, .lte, .eq => false,
  30724         };
  30725         if (is_zero) return switch (op) {
  30726             .gte => true,
  30727             .lt => false,
  30728             .gt, .lte, .eq, .neq => null,
  30729         };
  30730     }
  30731 
  30732     // Negative vs. unsigned has guaranteed outcome.
  30733     if (rhs_info.signedness == .unsigned and is_negative) return switch (op) {
  30734         .eq, .gt, .gte => false,
  30735         .neq, .lt, .lte => true,
  30736     };
  30737 
  30738     const sign_adj = @boolToInt(!is_negative and rhs_info.signedness == .signed);
  30739     const req_bits = lhs_val.intBitCountTwosComp(mod) + sign_adj;
  30740 
  30741     // No sized type can have more than 65535 bits.
  30742     // The RHS type operand is either a runtime value or sized (but undefined) constant.
  30743     if (req_bits > 65535) return switch (op) {
  30744         .lt, .lte => is_negative,
  30745         .gt, .gte => is_positive,
  30746         .eq => false,
  30747         .neq => true,
  30748     };
  30749     const fits = req_bits <= rhs_info.bits;
  30750 
  30751     // Oversized int has guaranteed outcome.
  30752     switch (op) {
  30753         .eq => return if (!fits) false else null,
  30754         .neq => return if (!fits) true else null,
  30755         .lt, .lte => if (!fits) return is_negative,
  30756         .gt, .gte => if (!fits) return !is_negative,
  30757     }
  30758 
  30759     // For any other comparison, we need to know if the LHS value is
  30760     // equal to the maximum or minimum possible value of the RHS type.
  30761     const edge: struct { min: bool, max: bool } = edge: {
  30762         if (is_zero and rhs_info.signedness == .unsigned) break :edge .{
  30763             .min = true,
  30764             .max = false,
  30765         };
  30766 
  30767         if (req_bits != rhs_info.bits) break :edge .{
  30768             .min = false,
  30769             .max = false,
  30770         };
  30771 
  30772         const ty = try mod.intType(
  30773             if (is_negative) .signed else .unsigned,
  30774             @intCast(u16, req_bits),
  30775         );
  30776         const pop_count = lhs_val.popCount(ty, mod);
  30777 
  30778         if (is_negative) {
  30779             break :edge .{
  30780                 .min = pop_count == 1,
  30781                 .max = false,
  30782             };
  30783         } else {
  30784             break :edge .{
  30785                 .min = false,
  30786                 .max = pop_count == req_bits - sign_adj,
  30787             };
  30788         }
  30789     };
  30790 
  30791     assert(fits);
  30792     return switch (op) {
  30793         .lt => if (edge.max) false else null,
  30794         .lte => if (edge.min) true else null,
  30795         .gt => if (edge.min) false else null,
  30796         .gte => if (edge.max) true else null,
  30797         .eq, .neq => unreachable,
  30798     };
  30799 }
  30800 
  30801 /// Asserts that lhs and rhs types are both vectors.
  30802 fn cmpVector(
  30803     sema: *Sema,
  30804     block: *Block,
  30805     src: LazySrcLoc,
  30806     lhs: Air.Inst.Ref,
  30807     rhs: Air.Inst.Ref,
  30808     op: std.math.CompareOperator,
  30809     lhs_src: LazySrcLoc,
  30810     rhs_src: LazySrcLoc,
  30811 ) CompileError!Air.Inst.Ref {
  30812     const mod = sema.mod;
  30813     const lhs_ty = sema.typeOf(lhs);
  30814     const rhs_ty = sema.typeOf(rhs);
  30815     assert(lhs_ty.zigTypeTag(mod) == .Vector);
  30816     assert(rhs_ty.zigTypeTag(mod) == .Vector);
  30817     try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
  30818 
  30819     const resolved_ty = try sema.resolvePeerTypes(block, src, &.{ lhs, rhs }, .{ .override = &.{ lhs_src, rhs_src } });
  30820     const casted_lhs = try sema.coerce(block, resolved_ty, lhs, lhs_src);
  30821     const casted_rhs = try sema.coerce(block, resolved_ty, rhs, rhs_src);
  30822 
  30823     const result_ty = try mod.vectorType(.{
  30824         .len = lhs_ty.vectorLen(mod),
  30825         .child = .bool_type,
  30826     });
  30827 
  30828     const runtime_src: LazySrcLoc = src: {
  30829         if (try sema.resolveMaybeUndefVal(casted_lhs)) |lhs_val| {
  30830             if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| {
  30831                 if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) {
  30832                     return sema.addConstUndef(result_ty);
  30833                 }
  30834                 const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_ty);
  30835                 return sema.addConstant(result_ty, cmp_val);
  30836             } else {
  30837                 break :src rhs_src;
  30838             }
  30839         } else {
  30840             break :src lhs_src;
  30841         }
  30842     };
  30843 
  30844     try sema.requireRuntimeBlock(block, src, runtime_src);
  30845     return block.addCmpVector(casted_lhs, casted_rhs, op);
  30846 }
  30847 
  30848 fn wrapOptional(
  30849     sema: *Sema,
  30850     block: *Block,
  30851     dest_ty: Type,
  30852     inst: Air.Inst.Ref,
  30853     inst_src: LazySrcLoc,
  30854 ) !Air.Inst.Ref {
  30855     if (try sema.resolveMaybeUndefVal(inst)) |val| {
  30856         return sema.addConstant(dest_ty, (try sema.mod.intern(.{ .opt = .{
  30857             .ty = dest_ty.toIntern(),
  30858             .val = val.toIntern(),
  30859         } })).toValue());
  30860     }
  30861 
  30862     try sema.requireRuntimeBlock(block, inst_src, null);
  30863     return block.addTyOp(.wrap_optional, dest_ty, inst);
  30864 }
  30865 
  30866 fn wrapErrorUnionPayload(
  30867     sema: *Sema,
  30868     block: *Block,
  30869     dest_ty: Type,
  30870     inst: Air.Inst.Ref,
  30871     inst_src: LazySrcLoc,
  30872 ) !Air.Inst.Ref {
  30873     const mod = sema.mod;
  30874     const dest_payload_ty = dest_ty.errorUnionPayload(mod);
  30875     const coerced = try sema.coerceExtra(block, dest_payload_ty, inst, inst_src, .{ .report_err = false });
  30876     if (try sema.resolveMaybeUndefVal(coerced)) |val| {
  30877         return sema.addConstant(dest_ty, (try mod.intern(.{ .error_union = .{
  30878             .ty = dest_ty.toIntern(),
  30879             .val = .{ .payload = try val.intern(dest_payload_ty, mod) },
  30880         } })).toValue());
  30881     }
  30882     try sema.requireRuntimeBlock(block, inst_src, null);
  30883     try sema.queueFullTypeResolution(dest_payload_ty);
  30884     return block.addTyOp(.wrap_errunion_payload, dest_ty, coerced);
  30885 }
  30886 
  30887 fn wrapErrorUnionSet(
  30888     sema: *Sema,
  30889     block: *Block,
  30890     dest_ty: Type,
  30891     inst: Air.Inst.Ref,
  30892     inst_src: LazySrcLoc,
  30893 ) !Air.Inst.Ref {
  30894     const mod = sema.mod;
  30895     const ip = &mod.intern_pool;
  30896     const inst_ty = sema.typeOf(inst);
  30897     const dest_err_set_ty = dest_ty.errorUnionSet(mod);
  30898     if (try sema.resolveMaybeUndefVal(inst)) |val| {
  30899         switch (dest_err_set_ty.toIntern()) {
  30900             .anyerror_type => {},
  30901             else => switch (ip.indexToKey(dest_err_set_ty.toIntern())) {
  30902                 .error_set_type => |error_set_type| ok: {
  30903                     const expected_name = mod.intern_pool.indexToKey(val.toIntern()).err.name;
  30904                     if (error_set_type.nameIndex(ip, expected_name) != null) break :ok;
  30905                     return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
  30906                 },
  30907                 .inferred_error_set_type => |ies_index| ok: {
  30908                     const ies = mod.inferredErrorSetPtr(ies_index);
  30909                     const expected_name = mod.intern_pool.indexToKey(val.toIntern()).err.name;
  30910 
  30911                     // We carefully do this in an order that avoids unnecessarily
  30912                     // resolving the destination error set type.
  30913                     if (ies.is_anyerror) break :ok;
  30914 
  30915                     if (ies.errors.contains(expected_name)) break :ok;
  30916                     if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) break :ok;
  30917 
  30918                     return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
  30919                 },
  30920                 else => unreachable,
  30921             },
  30922         }
  30923         return sema.addConstant(dest_ty, (try mod.intern(.{ .error_union = .{
  30924             .ty = dest_ty.toIntern(),
  30925             .val = .{
  30926                 .err_name = mod.intern_pool.indexToKey(try val.intern(dest_err_set_ty, mod)).err.name,
  30927             },
  30928         } })).toValue());
  30929     }
  30930 
  30931     try sema.requireRuntimeBlock(block, inst_src, null);
  30932     const coerced = try sema.coerce(block, dest_err_set_ty, inst, inst_src);
  30933     return block.addTyOp(.wrap_errunion_err, dest_ty, coerced);
  30934 }
  30935 
  30936 fn unionToTag(
  30937     sema: *Sema,
  30938     block: *Block,
  30939     enum_ty: Type,
  30940     un: Air.Inst.Ref,
  30941     un_src: LazySrcLoc,
  30942 ) !Air.Inst.Ref {
  30943     const mod = sema.mod;
  30944     if ((try sema.typeHasOnePossibleValue(enum_ty))) |opv| {
  30945         return sema.addConstant(enum_ty, opv);
  30946     }
  30947     if (try sema.resolveMaybeUndefVal(un)) |un_val| {
  30948         return sema.addConstant(enum_ty, un_val.unionTag(mod));
  30949     }
  30950     try sema.requireRuntimeBlock(block, un_src, null);
  30951     return block.addTyOp(.get_union_tag, enum_ty, un);
  30952 }
  30953 
  30954 fn resolvePeerTypes(
  30955     sema: *Sema,
  30956     block: *Block,
  30957     src: LazySrcLoc,
  30958     instructions: []const Air.Inst.Ref,
  30959     candidate_srcs: Module.PeerTypeCandidateSrc,
  30960 ) !Type {
  30961     const mod = sema.mod;
  30962     switch (instructions.len) {
  30963         0 => return Type.noreturn,
  30964         1 => return sema.typeOf(instructions[0]),
  30965         else => {},
  30966     }
  30967 
  30968     const target = mod.getTarget();
  30969 
  30970     var chosen = instructions[0];
  30971     // If this is non-null then it does the following thing, depending on the chosen zigTypeTag(mod).
  30972     //  * ErrorSet: this is an override
  30973     //  * ErrorUnion: this is an override of the error set only
  30974     //  * other: at the end we make an ErrorUnion with the other thing and this
  30975     var err_set_ty: ?Type = null;
  30976     var any_are_null = false;
  30977     var seen_const = false;
  30978     var convert_to_slice = false;
  30979     var chosen_i: usize = 0;
  30980     for (instructions[1..], 0..) |candidate, candidate_i| {
  30981         const candidate_ty = sema.typeOf(candidate);
  30982         const chosen_ty = sema.typeOf(chosen);
  30983 
  30984         const candidate_ty_tag = try candidate_ty.zigTypeTagOrPoison(mod);
  30985         const chosen_ty_tag = try chosen_ty.zigTypeTagOrPoison(mod);
  30986 
  30987         // If the candidate can coerce into our chosen type, we're done.
  30988         // If the chosen type can coerce into the candidate, use that.
  30989         if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) {
  30990             continue;
  30991         }
  30992         if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) {
  30993             chosen = candidate;
  30994             chosen_i = candidate_i + 1;
  30995             continue;
  30996         }
  30997 
  30998         switch (candidate_ty_tag) {
  30999             .NoReturn, .Undefined => continue,
  31000 
  31001             .Null => {
  31002                 any_are_null = true;
  31003                 continue;
  31004             },
  31005 
  31006             .Int => switch (chosen_ty_tag) {
  31007                 .ComptimeInt => {
  31008                     chosen = candidate;
  31009                     chosen_i = candidate_i + 1;
  31010                     continue;
  31011                 },
  31012                 .Int => {
  31013                     const chosen_info = chosen_ty.intInfo(mod);
  31014                     const candidate_info = candidate_ty.intInfo(mod);
  31015 
  31016                     if (chosen_info.bits < candidate_info.bits) {
  31017                         chosen = candidate;
  31018                         chosen_i = candidate_i + 1;
  31019                     }
  31020                     continue;
  31021                 },
  31022                 .Pointer => if (chosen_ty.ptrSize(mod) == .C) continue,
  31023                 else => {},
  31024             },
  31025             .ComptimeInt => switch (chosen_ty_tag) {
  31026                 .Int, .Float, .ComptimeFloat => continue,
  31027                 .Pointer => if (chosen_ty.ptrSize(mod) == .C) continue,
  31028                 else => {},
  31029             },
  31030             .Float => switch (chosen_ty_tag) {
  31031                 .Float => {
  31032                     if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) {
  31033                         chosen = candidate;
  31034                         chosen_i = candidate_i + 1;
  31035                     }
  31036                     continue;
  31037                 },
  31038                 .ComptimeFloat, .ComptimeInt => {
  31039                     chosen = candidate;
  31040                     chosen_i = candidate_i + 1;
  31041                     continue;
  31042                 },
  31043                 else => {},
  31044             },
  31045             .ComptimeFloat => switch (chosen_ty_tag) {
  31046                 .Float => continue,
  31047                 .ComptimeInt => {
  31048                     chosen = candidate;
  31049                     chosen_i = candidate_i + 1;
  31050                     continue;
  31051                 },
  31052                 else => {},
  31053             },
  31054             .Enum => switch (chosen_ty_tag) {
  31055                 .EnumLiteral => {
  31056                     chosen = candidate;
  31057                     chosen_i = candidate_i + 1;
  31058                     continue;
  31059                 },
  31060                 .Union => continue,
  31061                 else => {},
  31062             },
  31063             .EnumLiteral => switch (chosen_ty_tag) {
  31064                 .Enum, .Union => continue,
  31065                 else => {},
  31066             },
  31067             .Union => switch (chosen_ty_tag) {
  31068                 .Enum, .EnumLiteral => {
  31069                     chosen = candidate;
  31070                     chosen_i = candidate_i + 1;
  31071                     continue;
  31072                 },
  31073                 else => {},
  31074             },
  31075             .ErrorSet => switch (chosen_ty_tag) {
  31076                 .ErrorSet => {
  31077                     // If chosen is superset of candidate, keep it.
  31078                     // If candidate is superset of chosen, switch it.
  31079                     // If neither is a superset, merge errors.
  31080                     const chosen_set_ty = err_set_ty orelse chosen_ty;
  31081 
  31082                     if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) {
  31083                         continue;
  31084                     }
  31085                     if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) {
  31086                         err_set_ty = null;
  31087                         chosen = candidate;
  31088                         chosen_i = candidate_i + 1;
  31089                         continue;
  31090                     }
  31091 
  31092                     err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_ty);
  31093                     continue;
  31094                 },
  31095                 .ErrorUnion => {
  31096                     const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(mod);
  31097 
  31098                     if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) {
  31099                         continue;
  31100                     }
  31101                     if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) {
  31102                         err_set_ty = candidate_ty;
  31103                         continue;
  31104                     }
  31105 
  31106                     err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_ty);
  31107                     continue;
  31108                 },
  31109                 else => {
  31110                     if (err_set_ty) |chosen_set_ty| {
  31111                         if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) {
  31112                             continue;
  31113                         }
  31114                         if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) {
  31115                             err_set_ty = candidate_ty;
  31116                             continue;
  31117                         }
  31118 
  31119                         err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_ty);
  31120                         continue;
  31121                     } else {
  31122                         err_set_ty = candidate_ty;
  31123                         continue;
  31124                     }
  31125                 },
  31126             },
  31127             .ErrorUnion => switch (chosen_ty_tag) {
  31128                 .ErrorSet => {
  31129                     const chosen_set_ty = err_set_ty orelse chosen_ty;
  31130                     const candidate_set_ty = candidate_ty.errorUnionSet(mod);
  31131 
  31132                     if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) {
  31133                         err_set_ty = chosen_set_ty;
  31134                     } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) {
  31135                         err_set_ty = null;
  31136                     } else {
  31137                         err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_set_ty);
  31138                     }
  31139                     chosen = candidate;
  31140                     chosen_i = candidate_i + 1;
  31141                     continue;
  31142                 },
  31143 
  31144                 .ErrorUnion => {
  31145                     const chosen_payload_ty = chosen_ty.errorUnionPayload(mod);
  31146                     const candidate_payload_ty = candidate_ty.errorUnionPayload(mod);
  31147 
  31148                     const coerce_chosen = (try sema.coerceInMemoryAllowed(block, chosen_payload_ty, candidate_payload_ty, false, target, src, src)) == .ok;
  31149                     const coerce_candidate = (try sema.coerceInMemoryAllowed(block, candidate_payload_ty, chosen_payload_ty, false, target, src, src)) == .ok;
  31150 
  31151                     if (coerce_chosen or coerce_candidate) {
  31152                         // If we can coerce to the candidate, we switch to that
  31153                         // type. This is the same logic as the bare (non-union)
  31154                         // coercion check we do at the top of this func.
  31155                         if (coerce_candidate) {
  31156                             chosen = candidate;
  31157                             chosen_i = candidate_i + 1;
  31158                         }
  31159 
  31160                         const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(mod);
  31161                         const candidate_set_ty = candidate_ty.errorUnionSet(mod);
  31162 
  31163                         if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) {
  31164                             err_set_ty = chosen_set_ty;
  31165                         } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) {
  31166                             err_set_ty = candidate_set_ty;
  31167                         } else {
  31168                             err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_set_ty);
  31169                         }
  31170                         continue;
  31171                     }
  31172                 },
  31173 
  31174                 else => {
  31175                     if (err_set_ty) |chosen_set_ty| {
  31176                         const candidate_set_ty = candidate_ty.errorUnionSet(mod);
  31177                         if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) {
  31178                             err_set_ty = chosen_set_ty;
  31179                         } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) {
  31180                             err_set_ty = null;
  31181                         } else {
  31182                             err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_set_ty);
  31183                         }
  31184                     }
  31185                     seen_const = seen_const or chosen_ty.isConstPtr(mod);
  31186                     chosen = candidate;
  31187                     chosen_i = candidate_i + 1;
  31188                     continue;
  31189                 },
  31190             },
  31191             .Pointer => {
  31192                 const cand_info = candidate_ty.ptrInfo(mod);
  31193                 switch (chosen_ty_tag) {
  31194                     .Pointer => {
  31195                         const chosen_info = chosen_ty.ptrInfo(mod);
  31196 
  31197                         seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable;
  31198 
  31199                         // *[N]T to [*]T
  31200                         // *[N]T to []T
  31201                         if ((cand_info.size == .Many or cand_info.size == .Slice) and
  31202                             chosen_info.size == .One and
  31203                             chosen_info.pointee_type.zigTypeTag(mod) == .Array)
  31204                         {
  31205                             // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T`
  31206                             convert_to_slice = false;
  31207                             chosen = candidate;
  31208                             chosen_i = candidate_i + 1;
  31209                             continue;
  31210                         }
  31211                         if (cand_info.size == .One and
  31212                             cand_info.pointee_type.zigTypeTag(mod) == .Array and
  31213                             (chosen_info.size == .Many or chosen_info.size == .Slice))
  31214                         {
  31215                             // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T`
  31216                             convert_to_slice = false;
  31217                             continue;
  31218                         }
  31219 
  31220                         // *[N]T and *[M]T
  31221                         // Verify both are single-pointers to arrays.
  31222                         // Keep the one whose element type can be coerced into.
  31223                         if (chosen_info.size == .One and
  31224                             cand_info.size == .One and
  31225                             chosen_info.pointee_type.zigTypeTag(mod) == .Array and
  31226                             cand_info.pointee_type.zigTypeTag(mod) == .Array)
  31227                         {
  31228                             const chosen_elem_ty = chosen_info.pointee_type.childType(mod);
  31229                             const cand_elem_ty = cand_info.pointee_type.childType(mod);
  31230 
  31231                             const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_elem_ty, cand_elem_ty, chosen_info.mutable, target, src, src);
  31232                             if (chosen_ok) {
  31233                                 convert_to_slice = true;
  31234                                 continue;
  31235                             }
  31236 
  31237                             const cand_ok = .ok == try sema.coerceInMemoryAllowed(block, cand_elem_ty, chosen_elem_ty, cand_info.mutable, target, src, src);
  31238                             if (cand_ok) {
  31239                                 convert_to_slice = true;
  31240                                 chosen = candidate;
  31241                                 chosen_i = candidate_i + 1;
  31242                                 continue;
  31243                             }
  31244 
  31245                             // They're both bad. Report error.
  31246                             // In the future we probably want to use the
  31247                             // coerceInMemoryAllowed error reporting mechanism,
  31248                             // however, for now we just fall through for the
  31249                             // "incompatible types" error below.
  31250                         }
  31251 
  31252                         // [*c]T and any other pointer size
  31253                         // Whichever element type can coerce to the other one, is
  31254                         // the one we will keep. If they're both OK then we keep the
  31255                         // C pointer since it matches both single and many pointers.
  31256                         if (cand_info.size == .C or chosen_info.size == .C) {
  31257                             const cand_ok = .ok == try sema.coerceInMemoryAllowed(block, cand_info.pointee_type, chosen_info.pointee_type, cand_info.mutable, target, src, src);
  31258                             const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_info.pointee_type, cand_info.pointee_type, chosen_info.mutable, target, src, src);
  31259 
  31260                             if (cand_ok) {
  31261                                 if (chosen_ok) {
  31262                                     if (chosen_info.size == .C) {
  31263                                         continue;
  31264                                     } else {
  31265                                         chosen = candidate;
  31266                                         chosen_i = candidate_i + 1;
  31267                                         continue;
  31268                                     }
  31269                                 } else {
  31270                                     chosen = candidate;
  31271                                     chosen_i = candidate_i + 1;
  31272                                     continue;
  31273                                 }
  31274                             } else {
  31275                                 if (chosen_ok) {
  31276                                     continue;
  31277                                 } else {
  31278                                     // They're both bad. Report error.
  31279                                     // In the future we probably want to use the
  31280                                     // coerceInMemoryAllowed error reporting mechanism,
  31281                                     // however, for now we just fall through for the
  31282                                     // "incompatible types" error below.
  31283                                 }
  31284                             }
  31285                         }
  31286                     },
  31287                     .Int, .ComptimeInt => {
  31288                         if (cand_info.size == .C) {
  31289                             chosen = candidate;
  31290                             chosen_i = candidate_i + 1;
  31291                             continue;
  31292                         }
  31293                     },
  31294                     .Optional => {
  31295                         const chosen_ptr_ty = chosen_ty.optionalChild(mod);
  31296                         if (chosen_ptr_ty.zigTypeTag(mod) == .Pointer) {
  31297                             const chosen_info = chosen_ptr_ty.ptrInfo(mod);
  31298 
  31299                             seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable;
  31300 
  31301                             // *[N]T to ?![*]T
  31302                             // *[N]T to ?![]T
  31303                             if (cand_info.size == .One and
  31304                                 cand_info.pointee_type.zigTypeTag(mod) == .Array and
  31305                                 (chosen_info.size == .Many or chosen_info.size == .Slice))
  31306                             {
  31307                                 continue;
  31308                             }
  31309                         }
  31310                     },
  31311                     .ErrorUnion => {
  31312                         const chosen_ptr_ty = chosen_ty.errorUnionPayload(mod);
  31313                         if (chosen_ptr_ty.zigTypeTag(mod) == .Pointer) {
  31314                             const chosen_info = chosen_ptr_ty.ptrInfo(mod);
  31315 
  31316                             seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable;
  31317 
  31318                             // *[N]T to E![*]T
  31319                             // *[N]T to E![]T
  31320                             if (cand_info.size == .One and
  31321                                 cand_info.pointee_type.zigTypeTag(mod) == .Array and
  31322                                 (chosen_info.size == .Many or chosen_info.size == .Slice))
  31323                             {
  31324                                 continue;
  31325                             }
  31326                         }
  31327                     },
  31328                     .Fn => {
  31329                         if (!cand_info.mutable and cand_info.pointee_type.zigTypeTag(mod) == .Fn and .ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty, cand_info.pointee_type, target, src, src)) {
  31330                             chosen = candidate;
  31331                             chosen_i = candidate_i + 1;
  31332                             continue;
  31333                         }
  31334                     },
  31335                     else => {},
  31336                 }
  31337             },
  31338             .Optional => {
  31339                 const opt_child_ty = candidate_ty.optionalChild(mod);
  31340                 if ((try sema.coerceInMemoryAllowed(block, chosen_ty, opt_child_ty, false, target, src, src)) == .ok) {
  31341                     seen_const = seen_const or opt_child_ty.isConstPtr(mod);
  31342                     any_are_null = true;
  31343                     continue;
  31344                 }
  31345 
  31346                 seen_const = seen_const or chosen_ty.isConstPtr(mod);
  31347                 any_are_null = false;
  31348                 chosen = candidate;
  31349                 chosen_i = candidate_i + 1;
  31350                 continue;
  31351             },
  31352             .Vector => switch (chosen_ty_tag) {
  31353                 .Vector => {
  31354                     const chosen_len = chosen_ty.vectorLen(mod);
  31355                     const candidate_len = candidate_ty.vectorLen(mod);
  31356                     if (chosen_len != candidate_len)
  31357                         continue;
  31358 
  31359                     const chosen_child_ty = chosen_ty.childType(mod);
  31360                     const candidate_child_ty = candidate_ty.childType(mod);
  31361                     if (chosen_child_ty.zigTypeTag(mod) == .Int and candidate_child_ty.zigTypeTag(mod) == .Int) {
  31362                         const chosen_info = chosen_child_ty.intInfo(mod);
  31363                         const candidate_info = candidate_child_ty.intInfo(mod);
  31364                         if (chosen_info.bits < candidate_info.bits) {
  31365                             chosen = candidate;
  31366                             chosen_i = candidate_i + 1;
  31367                         }
  31368                         continue;
  31369                     }
  31370                     if (chosen_child_ty.zigTypeTag(mod) == .Float and candidate_child_ty.zigTypeTag(mod) == .Float) {
  31371                         if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) {
  31372                             chosen = candidate;
  31373                             chosen_i = candidate_i + 1;
  31374                         }
  31375                         continue;
  31376                     }
  31377                 },
  31378                 .Array => {
  31379                     chosen = candidate;
  31380                     chosen_i = candidate_i + 1;
  31381                     continue;
  31382                 },
  31383                 else => {},
  31384             },
  31385             .Array => switch (chosen_ty_tag) {
  31386                 .Vector => continue,
  31387                 else => {},
  31388             },
  31389             .Fn => if (chosen_ty.isSinglePointer(mod) and chosen_ty.isConstPtr(mod) and chosen_ty.childType(mod).zigTypeTag(mod) == .Fn) {
  31390                 if (.ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty.childType(mod), candidate_ty, target, src, src)) {
  31391                     continue;
  31392                 }
  31393             },
  31394             else => {},
  31395         }
  31396 
  31397         switch (chosen_ty_tag) {
  31398             .NoReturn, .Undefined => {
  31399                 chosen = candidate;
  31400                 chosen_i = candidate_i + 1;
  31401                 continue;
  31402             },
  31403             .Null => {
  31404                 any_are_null = true;
  31405                 chosen = candidate;
  31406                 chosen_i = candidate_i + 1;
  31407                 continue;
  31408             },
  31409             .Optional => {
  31410                 const opt_child_ty = chosen_ty.optionalChild(mod);
  31411                 if ((try sema.coerceInMemoryAllowed(block, opt_child_ty, candidate_ty, false, target, src, src)) == .ok) {
  31412                     continue;
  31413                 }
  31414                 if ((try sema.coerceInMemoryAllowed(block, candidate_ty, opt_child_ty, false, target, src, src)) == .ok) {
  31415                     any_are_null = true;
  31416                     chosen = candidate;
  31417                     chosen_i = candidate_i + 1;
  31418                     continue;
  31419                 }
  31420             },
  31421             .ErrorUnion => {
  31422                 const payload_ty = chosen_ty.errorUnionPayload(mod);
  31423                 if ((try sema.coerceInMemoryAllowed(block, payload_ty, candidate_ty, false, target, src, src)) == .ok) {
  31424                     continue;
  31425                 }
  31426             },
  31427             .ErrorSet => {
  31428                 chosen = candidate;
  31429                 chosen_i = candidate_i + 1;
  31430                 if (err_set_ty) |chosen_set_ty| {
  31431                     if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, chosen_ty, src, src)) {
  31432                         continue;
  31433                     }
  31434                     if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_ty, chosen_set_ty, src, src)) {
  31435                         err_set_ty = chosen_ty;
  31436                         continue;
  31437                     }
  31438 
  31439                     err_set_ty = try sema.errorSetMerge(chosen_set_ty, chosen_ty);
  31440                     continue;
  31441                 } else {
  31442                     err_set_ty = chosen_ty;
  31443                     continue;
  31444                 }
  31445             },
  31446             else => {},
  31447         }
  31448 
  31449         // At this point, we hit a compile error. We need to recover
  31450         // the source locations.
  31451         const chosen_src = candidate_srcs.resolve(
  31452             mod,
  31453             mod.declPtr(block.src_decl),
  31454             chosen_i,
  31455         );
  31456         const candidate_src = candidate_srcs.resolve(
  31457             mod,
  31458             mod.declPtr(block.src_decl),
  31459             candidate_i + 1,
  31460         );
  31461 
  31462         const msg = msg: {
  31463             const msg = try sema.errMsg(block, src, "incompatible types: '{}' and '{}'", .{
  31464                 chosen_ty.fmt(mod),
  31465                 candidate_ty.fmt(mod),
  31466             });
  31467             errdefer msg.destroy(sema.gpa);
  31468 
  31469             if (chosen_src) |src_loc|
  31470                 try sema.errNote(block, src_loc, msg, "type '{}' here", .{chosen_ty.fmt(mod)});
  31471 
  31472             if (candidate_src) |src_loc|
  31473                 try sema.errNote(block, src_loc, msg, "type '{}' here", .{candidate_ty.fmt(mod)});
  31474 
  31475             break :msg msg;
  31476         };
  31477         return sema.failWithOwnedErrorMsg(msg);
  31478     }
  31479 
  31480     const chosen_ty = sema.typeOf(chosen);
  31481 
  31482     if (convert_to_slice) {
  31483         // turn *[N]T => []T
  31484         const chosen_child_ty = chosen_ty.childType(mod);
  31485         var info = chosen_ty.ptrInfo(mod);
  31486         info.sentinel = chosen_child_ty.sentinel(mod);
  31487         info.size = .Slice;
  31488         info.mutable = !(seen_const or chosen_child_ty.isConstPtr(mod));
  31489         info.pointee_type = chosen_child_ty.elemType2(mod);
  31490 
  31491         const new_ptr_ty = try Type.ptr(sema.arena, mod, info);
  31492         const opt_ptr_ty = if (any_are_null)
  31493             try Type.optional(sema.arena, new_ptr_ty, mod)
  31494         else
  31495             new_ptr_ty;
  31496         const set_ty = err_set_ty orelse return opt_ptr_ty;
  31497         return try mod.errorUnionType(set_ty, opt_ptr_ty);
  31498     }
  31499 
  31500     if (seen_const) {
  31501         // turn []T => []const T
  31502         switch (chosen_ty.zigTypeTag(mod)) {
  31503             .ErrorUnion => {
  31504                 const ptr_ty = chosen_ty.errorUnionPayload(mod);
  31505                 var info = ptr_ty.ptrInfo(mod);
  31506                 info.mutable = false;
  31507                 const new_ptr_ty = try Type.ptr(sema.arena, mod, info);
  31508                 const opt_ptr_ty = if (any_are_null)
  31509                     try Type.optional(sema.arena, new_ptr_ty, mod)
  31510                 else
  31511                     new_ptr_ty;
  31512                 const set_ty = err_set_ty orelse chosen_ty.errorUnionSet(mod);
  31513                 return try mod.errorUnionType(set_ty, opt_ptr_ty);
  31514             },
  31515             .Pointer => {
  31516                 var info = chosen_ty.ptrInfo(mod);
  31517                 info.mutable = false;
  31518                 const new_ptr_ty = try Type.ptr(sema.arena, mod, info);
  31519                 const opt_ptr_ty = if (any_are_null)
  31520                     try Type.optional(sema.arena, new_ptr_ty, mod)
  31521                 else
  31522                     new_ptr_ty;
  31523                 const set_ty = err_set_ty orelse return opt_ptr_ty;
  31524                 return try mod.errorUnionType(set_ty, opt_ptr_ty);
  31525             },
  31526             else => return chosen_ty,
  31527         }
  31528     }
  31529 
  31530     if (any_are_null) {
  31531         const opt_ty = switch (chosen_ty.zigTypeTag(mod)) {
  31532             .Null, .Optional => chosen_ty,
  31533             else => try Type.optional(sema.arena, chosen_ty, mod),
  31534         };
  31535         const set_ty = err_set_ty orelse return opt_ty;
  31536         return try mod.errorUnionType(set_ty, opt_ty);
  31537     }
  31538 
  31539     if (err_set_ty) |ty| switch (chosen_ty.zigTypeTag(mod)) {
  31540         .ErrorSet => return ty,
  31541         .ErrorUnion => {
  31542             const payload_ty = chosen_ty.errorUnionPayload(mod);
  31543             return try mod.errorUnionType(ty, payload_ty);
  31544         },
  31545         else => return try mod.errorUnionType(ty, chosen_ty),
  31546     };
  31547 
  31548     return chosen_ty;
  31549 }
  31550 
  31551 pub fn resolveFnTypes(sema: *Sema, fn_info: InternPool.Key.FuncType) CompileError!void {
  31552     const mod = sema.mod;
  31553     try sema.resolveTypeFully(fn_info.return_type.toType());
  31554 
  31555     if (mod.comp.bin_file.options.error_return_tracing and fn_info.return_type.toType().isError(mod)) {
  31556         // Ensure the type exists so that backends can assume that.
  31557         _ = try sema.getBuiltinType("StackTrace");
  31558     }
  31559 
  31560     for (fn_info.param_types) |param_ty| {
  31561         try sema.resolveTypeFully(param_ty.toType());
  31562     }
  31563 }
  31564 
  31565 /// Make it so that calling hash() and eql() on `val` will not assert due
  31566 /// to a type not having its layout resolved.
  31567 fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
  31568     const mod = sema.mod;
  31569     switch (mod.intern_pool.indexToKey(val.toIntern())) {
  31570         .int => |int| switch (int.storage) {
  31571             .u64, .i64, .big_int => return val,
  31572             .lazy_align, .lazy_size => return (try mod.intern(.{ .int = .{
  31573                 .ty = int.ty,
  31574                 .storage = .{ .u64 = (try val.getUnsignedIntAdvanced(mod, sema)).? },
  31575             } })).toValue(),
  31576         },
  31577         .ptr => |ptr| {
  31578             const resolved_len = switch (ptr.len) {
  31579                 .none => .none,
  31580                 else => (try sema.resolveLazyValue(ptr.len.toValue())).toIntern(),
  31581             };
  31582             switch (ptr.addr) {
  31583                 .decl, .mut_decl => return if (resolved_len == ptr.len)
  31584                     val
  31585                 else
  31586                     (try mod.intern(.{ .ptr = .{
  31587                         .ty = ptr.ty,
  31588                         .addr = switch (ptr.addr) {
  31589                             .decl => |decl| .{ .decl = decl },
  31590                             .mut_decl => |mut_decl| .{ .mut_decl = mut_decl },
  31591                             else => unreachable,
  31592                         },
  31593                         .len = resolved_len,
  31594                     } })).toValue(),
  31595                 .comptime_field => |field_val| {
  31596                     const resolved_field_val =
  31597                         (try sema.resolveLazyValue(field_val.toValue())).toIntern();
  31598                     return if (resolved_field_val == field_val and resolved_len == ptr.len)
  31599                         val
  31600                     else
  31601                         (try mod.intern(.{ .ptr = .{
  31602                             .ty = ptr.ty,
  31603                             .addr = .{ .comptime_field = resolved_field_val },
  31604                             .len = resolved_len,
  31605                         } })).toValue();
  31606                 },
  31607                 .int => |int| {
  31608                     const resolved_int = (try sema.resolveLazyValue(int.toValue())).toIntern();
  31609                     return if (resolved_int == int and resolved_len == ptr.len)
  31610                         val
  31611                     else
  31612                         (try mod.intern(.{ .ptr = .{
  31613                             .ty = ptr.ty,
  31614                             .addr = .{ .int = resolved_int },
  31615                             .len = resolved_len,
  31616                         } })).toValue();
  31617                 },
  31618                 .eu_payload, .opt_payload => |base| {
  31619                     const resolved_base = (try sema.resolveLazyValue(base.toValue())).toIntern();
  31620                     return if (resolved_base == base and resolved_len == ptr.len)
  31621                         val
  31622                     else
  31623                         (try mod.intern(.{ .ptr = .{
  31624                             .ty = ptr.ty,
  31625                             .addr = switch (ptr.addr) {
  31626                                 .eu_payload => .{ .eu_payload = resolved_base },
  31627                                 .opt_payload => .{ .opt_payload = resolved_base },
  31628                                 else => unreachable,
  31629                             },
  31630                             .len = ptr.len,
  31631                         } })).toValue();
  31632                 },
  31633                 .elem, .field => |base_index| {
  31634                     const resolved_base = (try sema.resolveLazyValue(base_index.base.toValue())).toIntern();
  31635                     return if (resolved_base == base_index.base and resolved_len == ptr.len)
  31636                         val
  31637                     else
  31638                         (try mod.intern(.{ .ptr = .{
  31639                             .ty = ptr.ty,
  31640                             .addr = switch (ptr.addr) {
  31641                                 .elem => .{ .elem = .{
  31642                                     .base = resolved_base,
  31643                                     .index = base_index.index,
  31644                                 } },
  31645                                 .field => .{ .field = .{
  31646                                     .base = resolved_base,
  31647                                     .index = base_index.index,
  31648                                 } },
  31649                                 else => unreachable,
  31650                             },
  31651                             .len = ptr.len,
  31652                         } })).toValue();
  31653                 },
  31654             }
  31655         },
  31656         .aggregate => |aggregate| switch (aggregate.storage) {
  31657             .bytes => return val,
  31658             .elems => |elems| {
  31659                 var resolved_elems: []InternPool.Index = &.{};
  31660                 for (elems, 0..) |elem, i| {
  31661                     const resolved_elem = (try sema.resolveLazyValue(elem.toValue())).toIntern();
  31662                     if (resolved_elems.len == 0 and resolved_elem != elem) {
  31663                         resolved_elems = try sema.arena.alloc(InternPool.Index, elems.len);
  31664                         @memcpy(resolved_elems[0..i], elems[0..i]);
  31665                     }
  31666                     if (resolved_elems.len > 0) resolved_elems[i] = resolved_elem;
  31667                 }
  31668                 return if (resolved_elems.len == 0) val else (try mod.intern(.{ .aggregate = .{
  31669                     .ty = aggregate.ty,
  31670                     .storage = .{ .elems = resolved_elems },
  31671                 } })).toValue();
  31672             },
  31673             .repeated_elem => |elem| {
  31674                 const resolved_elem = (try sema.resolveLazyValue(elem.toValue())).toIntern();
  31675                 return if (resolved_elem == elem) val else (try mod.intern(.{ .aggregate = .{
  31676                     .ty = aggregate.ty,
  31677                     .storage = .{ .repeated_elem = resolved_elem },
  31678                 } })).toValue();
  31679             },
  31680         },
  31681         .un => |un| {
  31682             const resolved_tag = (try sema.resolveLazyValue(un.tag.toValue())).toIntern();
  31683             const resolved_val = (try sema.resolveLazyValue(un.val.toValue())).toIntern();
  31684             return if (resolved_tag == un.tag and resolved_val == un.val)
  31685                 val
  31686             else
  31687                 (try mod.intern(.{ .un = .{
  31688                     .ty = un.ty,
  31689                     .tag = resolved_tag,
  31690                     .val = resolved_val,
  31691                 } })).toValue();
  31692         },
  31693         else => return val,
  31694     }
  31695 }
  31696 
  31697 pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {
  31698     const mod = sema.mod;
  31699     switch (ty.zigTypeTag(mod)) {
  31700         .Struct => return sema.resolveStructLayout(ty),
  31701         .Union => return sema.resolveUnionLayout(ty),
  31702         .Array => {
  31703             if (ty.arrayLenIncludingSentinel(mod) == 0) return;
  31704             const elem_ty = ty.childType(mod);
  31705             return sema.resolveTypeLayout(elem_ty);
  31706         },
  31707         .Optional => {
  31708             const payload_ty = ty.optionalChild(mod);
  31709             // In case of querying the ABI alignment of this optional, we will ask
  31710             // for hasRuntimeBits() of the payload type, so we need "requires comptime"
  31711             // to be known already before this function returns.
  31712             _ = try sema.typeRequiresComptime(payload_ty);
  31713             return sema.resolveTypeLayout(payload_ty);
  31714         },
  31715         .ErrorUnion => {
  31716             const payload_ty = ty.errorUnionPayload(mod);
  31717             return sema.resolveTypeLayout(payload_ty);
  31718         },
  31719         .Fn => {
  31720             const info = mod.typeToFunc(ty).?;
  31721             if (info.is_generic) {
  31722                 // Resolving of generic function types is deferred to when
  31723                 // the function is instantiated.
  31724                 return;
  31725             }
  31726             for (info.param_types) |param_ty| {
  31727                 try sema.resolveTypeLayout(param_ty.toType());
  31728             }
  31729             try sema.resolveTypeLayout(info.return_type.toType());
  31730         },
  31731         else => {},
  31732     }
  31733 }
  31734 
  31735 fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
  31736     const mod = sema.mod;
  31737     const resolved_ty = try sema.resolveTypeFields(ty);
  31738     if (mod.typeToStruct(resolved_ty)) |struct_obj| {
  31739         switch (struct_obj.status) {
  31740             .none, .have_field_types => {},
  31741             .field_types_wip, .layout_wip => {
  31742                 const msg = try Module.ErrorMsg.create(
  31743                     sema.gpa,
  31744                     struct_obj.srcLoc(mod),
  31745                     "struct '{}' depends on itself",
  31746                     .{ty.fmt(mod)},
  31747                 );
  31748                 return sema.failWithOwnedErrorMsg(msg);
  31749             },
  31750             .have_layout, .fully_resolved_wip, .fully_resolved => return,
  31751         }
  31752         const prev_status = struct_obj.status;
  31753         errdefer if (struct_obj.status == .layout_wip) {
  31754             struct_obj.status = prev_status;
  31755         };
  31756 
  31757         struct_obj.status = .layout_wip;
  31758         for (struct_obj.fields.values(), 0..) |field, i| {
  31759             sema.resolveTypeLayout(field.ty) catch |err| switch (err) {
  31760                 error.AnalysisFail => {
  31761                     const msg = sema.err orelse return err;
  31762                     try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});
  31763                     return err;
  31764                 },
  31765                 else => return err,
  31766             };
  31767         }
  31768 
  31769         if (struct_obj.layout == .Packed) {
  31770             try semaBackingIntType(mod, struct_obj);
  31771         }
  31772 
  31773         struct_obj.status = .have_layout;
  31774         _ = try sema.resolveTypeRequiresComptime(resolved_ty);
  31775 
  31776         if (struct_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(resolved_ty))) {
  31777             const msg = try Module.ErrorMsg.create(
  31778                 sema.gpa,
  31779                 struct_obj.srcLoc(mod),
  31780                 "struct layout depends on it having runtime bits",
  31781                 .{},
  31782             );
  31783             return sema.failWithOwnedErrorMsg(msg);
  31784         }
  31785 
  31786         if (struct_obj.layout == .Auto and mod.backendSupportsFeature(.field_reordering)) {
  31787             const optimized_order = if (struct_obj.owner_decl == sema.owner_decl_index)
  31788                 try sema.perm_arena.alloc(u32, struct_obj.fields.count())
  31789             else blk: {
  31790                 const decl = mod.declPtr(struct_obj.owner_decl);
  31791                 var decl_arena: std.heap.ArenaAllocator = undefined;
  31792                 const decl_arena_allocator = decl.value_arena.?.acquire(sema.gpa, &decl_arena);
  31793                 defer decl.value_arena.?.release(&decl_arena);
  31794                 break :blk try decl_arena_allocator.alloc(u32, struct_obj.fields.count());
  31795             };
  31796 
  31797             for (struct_obj.fields.values(), 0..) |field, i| {
  31798                 optimized_order[i] = if (try sema.typeHasRuntimeBits(field.ty))
  31799                     @intCast(u32, i)
  31800                 else
  31801                     Module.Struct.omitted_field;
  31802             }
  31803 
  31804             const AlignSortContext = struct {
  31805                 struct_obj: *Module.Struct,
  31806                 sema: *Sema,
  31807 
  31808                 fn lessThan(ctx: @This(), a: u32, b: u32) bool {
  31809                     const m = ctx.sema.mod;
  31810                     if (a == Module.Struct.omitted_field) return false;
  31811                     if (b == Module.Struct.omitted_field) return true;
  31812                     return ctx.struct_obj.fields.values()[a].ty.abiAlignment(m) >
  31813                         ctx.struct_obj.fields.values()[b].ty.abiAlignment(m);
  31814                 }
  31815             };
  31816             mem.sort(u32, optimized_order, AlignSortContext{
  31817                 .struct_obj = struct_obj,
  31818                 .sema = sema,
  31819             }, AlignSortContext.lessThan);
  31820             struct_obj.optimized_order = optimized_order.ptr;
  31821         }
  31822     }
  31823     // otherwise it's a tuple; no need to resolve anything
  31824 }
  31825 
  31826 fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
  31827     const gpa = mod.gpa;
  31828 
  31829     var fields_bit_sum: u64 = 0;
  31830     for (struct_obj.fields.values()) |field| {
  31831         fields_bit_sum += field.ty.bitSize(mod);
  31832     }
  31833 
  31834     const decl_index = struct_obj.owner_decl;
  31835     const decl = mod.declPtr(decl_index);
  31836     var decl_arena: std.heap.ArenaAllocator = undefined;
  31837     const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena);
  31838     defer decl.value_arena.?.release(&decl_arena);
  31839 
  31840     const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir;
  31841     const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
  31842     assert(extended.opcode == .struct_decl);
  31843     const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
  31844 
  31845     if (small.has_backing_int) {
  31846         var extra_index: usize = extended.operand;
  31847         extra_index += @boolToInt(small.has_src_node);
  31848         extra_index += @boolToInt(small.has_fields_len);
  31849         extra_index += @boolToInt(small.has_decls_len);
  31850 
  31851         const backing_int_body_len = zir.extra[extra_index];
  31852         extra_index += 1;
  31853 
  31854         var analysis_arena = std.heap.ArenaAllocator.init(gpa);
  31855         defer analysis_arena.deinit();
  31856 
  31857         var sema: Sema = .{ .mod = mod, .gpa = gpa, .arena = analysis_arena.allocator(), .perm_arena = decl_arena_allocator, .code = zir, .owner_decl = decl, .owner_decl_index = decl_index, .func = null, .func_index = .none, .fn_ret_ty = Type.void, .owner_func = null, .owner_func_index = .none };
  31858         defer sema.deinit();
  31859 
  31860         var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope);
  31861         defer wip_captures.deinit();
  31862 
  31863         var block: Block = .{
  31864             .parent = null,
  31865             .sema = &sema,
  31866             .src_decl = decl_index,
  31867             .namespace = struct_obj.namespace,
  31868             .wip_capture_scope = wip_captures.scope,
  31869             .instructions = .{},
  31870             .inlining = null,
  31871             .is_comptime = true,
  31872         };
  31873         defer {
  31874             assert(block.instructions.items.len == 0);
  31875             block.params.deinit(gpa);
  31876         }
  31877 
  31878         const backing_int_src: LazySrcLoc = .{ .node_offset_container_tag = 0 };
  31879         const backing_int_ty = blk: {
  31880             if (backing_int_body_len == 0) {
  31881                 const backing_int_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
  31882                 break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref);
  31883             } else {
  31884                 const body = zir.extra[extra_index..][0..backing_int_body_len];
  31885                 const ty_ref = try sema.resolveBody(&block, body, struct_obj.zir_index);
  31886                 break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref);
  31887             }
  31888         };
  31889 
  31890         try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum);
  31891         struct_obj.backing_int_ty = backing_int_ty;
  31892         try wip_captures.finalize();
  31893     } else {
  31894         if (fields_bit_sum > std.math.maxInt(u16)) {
  31895             var sema: Sema = .{
  31896                 .mod = mod,
  31897                 .gpa = gpa,
  31898                 .arena = undefined,
  31899                 .perm_arena = decl_arena_allocator,
  31900                 .code = zir,
  31901                 .owner_decl = decl,
  31902                 .owner_decl_index = decl_index,
  31903                 .func = null,
  31904                 .func_index = .none,
  31905                 .fn_ret_ty = Type.void,
  31906                 .owner_func = null,
  31907                 .owner_func_index = .none,
  31908             };
  31909             defer sema.deinit();
  31910 
  31911             var block: Block = .{
  31912                 .parent = null,
  31913                 .sema = &sema,
  31914                 .src_decl = decl_index,
  31915                 .namespace = struct_obj.namespace,
  31916                 .wip_capture_scope = undefined,
  31917                 .instructions = .{},
  31918                 .inlining = null,
  31919                 .is_comptime = true,
  31920             };
  31921             return sema.fail(&block, LazySrcLoc.nodeOffset(0), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum});
  31922         }
  31923         struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(u16, fields_bit_sum));
  31924     }
  31925 }
  31926 
  31927 fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {
  31928     const mod = sema.mod;
  31929 
  31930     if (!backing_int_ty.isInt(mod)) {
  31931         return sema.fail(block, src, "expected backing integer type, found '{}'", .{backing_int_ty.fmt(sema.mod)});
  31932     }
  31933     if (backing_int_ty.bitSize(mod) != fields_bit_sum) {
  31934         return sema.fail(
  31935             block,
  31936             src,
  31937             "backing integer type '{}' has bit size {} but the struct fields have a total bit size of {}",
  31938             .{ backing_int_ty.fmt(sema.mod), backing_int_ty.bitSize(mod), fields_bit_sum },
  31939         );
  31940     }
  31941 }
  31942 
  31943 fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
  31944     const mod = sema.mod;
  31945     if (!ty.isIndexable(mod)) {
  31946         const msg = msg: {
  31947             const msg = try sema.errMsg(block, src, "type '{}' does not support indexing", .{ty.fmt(sema.mod)});
  31948             errdefer msg.destroy(sema.gpa);
  31949             try sema.errNote(block, src, msg, "operand must be an array, slice, tuple, or vector", .{});
  31950             break :msg msg;
  31951         };
  31952         return sema.failWithOwnedErrorMsg(msg);
  31953     }
  31954 }
  31955 
  31956 fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
  31957     const mod = sema.mod;
  31958     if (ty.zigTypeTag(mod) == .Pointer) {
  31959         switch (ty.ptrSize(mod)) {
  31960             .Slice, .Many, .C => return,
  31961             .One => {
  31962                 const elem_ty = ty.childType(mod);
  31963                 if (elem_ty.zigTypeTag(mod) == .Array) return;
  31964                 // TODO https://github.com/ziglang/zig/issues/15479
  31965                 // if (elem_ty.isTuple()) return;
  31966             },
  31967         }
  31968     }
  31969     const msg = msg: {
  31970         const msg = try sema.errMsg(block, src, "type '{}' is not an indexable pointer", .{ty.fmt(sema.mod)});
  31971         errdefer msg.destroy(sema.gpa);
  31972         try sema.errNote(block, src, msg, "operand must be a slice, a many pointer or a pointer to an array", .{});
  31973         break :msg msg;
  31974     };
  31975     return sema.failWithOwnedErrorMsg(msg);
  31976 }
  31977 
  31978 fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
  31979     const mod = sema.mod;
  31980     const resolved_ty = try sema.resolveTypeFields(ty);
  31981     const union_obj = mod.typeToUnion(resolved_ty).?;
  31982     switch (union_obj.status) {
  31983         .none, .have_field_types => {},
  31984         .field_types_wip, .layout_wip => {
  31985             const msg = try Module.ErrorMsg.create(
  31986                 sema.gpa,
  31987                 union_obj.srcLoc(sema.mod),
  31988                 "union '{}' depends on itself",
  31989                 .{ty.fmt(sema.mod)},
  31990             );
  31991             return sema.failWithOwnedErrorMsg(msg);
  31992         },
  31993         .have_layout, .fully_resolved_wip, .fully_resolved => return,
  31994     }
  31995     const prev_status = union_obj.status;
  31996     errdefer if (union_obj.status == .layout_wip) {
  31997         union_obj.status = prev_status;
  31998     };
  31999 
  32000     union_obj.status = .layout_wip;
  32001     for (union_obj.fields.values(), 0..) |field, i| {
  32002         sema.resolveTypeLayout(field.ty) catch |err| switch (err) {
  32003             error.AnalysisFail => {
  32004                 const msg = sema.err orelse return err;
  32005                 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});
  32006                 return err;
  32007             },
  32008             else => return err,
  32009         };
  32010     }
  32011     union_obj.status = .have_layout;
  32012     _ = try sema.resolveTypeRequiresComptime(resolved_ty);
  32013 
  32014     if (union_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(resolved_ty))) {
  32015         const msg = try Module.ErrorMsg.create(
  32016             sema.gpa,
  32017             union_obj.srcLoc(sema.mod),
  32018             "union layout depends on it having runtime bits",
  32019             .{},
  32020         );
  32021         return sema.failWithOwnedErrorMsg(msg);
  32022     }
  32023 }
  32024 
  32025 // In case of querying the ABI alignment of this struct, we will ask
  32026 // for hasRuntimeBits() of each field, so we need "requires comptime"
  32027 // to be known already before this function returns.
  32028 pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
  32029     const mod = sema.mod;
  32030 
  32031     return switch (ty.toIntern()) {
  32032         .empty_struct_type => false,
  32033         else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
  32034             .int_type => false,
  32035             .ptr_type => |ptr_type| {
  32036                 const child_ty = ptr_type.child.toType();
  32037                 if (child_ty.zigTypeTag(mod) == .Fn) {
  32038                     return mod.typeToFunc(child_ty).?.is_generic;
  32039                 } else {
  32040                     return sema.resolveTypeRequiresComptime(child_ty);
  32041                 }
  32042             },
  32043             .anyframe_type => |child| {
  32044                 if (child == .none) return false;
  32045                 return sema.resolveTypeRequiresComptime(child.toType());
  32046             },
  32047             .array_type => |array_type| return sema.resolveTypeRequiresComptime(array_type.child.toType()),
  32048             .vector_type => |vector_type| return sema.resolveTypeRequiresComptime(vector_type.child.toType()),
  32049             .opt_type => |child| return sema.resolveTypeRequiresComptime(child.toType()),
  32050             .error_union_type => |error_union_type| return sema.resolveTypeRequiresComptime(error_union_type.payload_type.toType()),
  32051             .error_set_type, .inferred_error_set_type => false,
  32052 
  32053             .func_type => true,
  32054 
  32055             .simple_type => |t| switch (t) {
  32056                 .f16,
  32057                 .f32,
  32058                 .f64,
  32059                 .f80,
  32060                 .f128,
  32061                 .usize,
  32062                 .isize,
  32063                 .c_char,
  32064                 .c_short,
  32065                 .c_ushort,
  32066                 .c_int,
  32067                 .c_uint,
  32068                 .c_long,
  32069                 .c_ulong,
  32070                 .c_longlong,
  32071                 .c_ulonglong,
  32072                 .c_longdouble,
  32073                 .anyopaque,
  32074                 .bool,
  32075                 .void,
  32076                 .anyerror,
  32077                 .noreturn,
  32078                 .generic_poison,
  32079                 .atomic_order,
  32080                 .atomic_rmw_op,
  32081                 .calling_convention,
  32082                 .address_space,
  32083                 .float_mode,
  32084                 .reduce_op,
  32085                 .call_modifier,
  32086                 .prefetch_options,
  32087                 .export_options,
  32088                 .extern_options,
  32089                 => false,
  32090 
  32091                 .type,
  32092                 .comptime_int,
  32093                 .comptime_float,
  32094                 .null,
  32095                 .undefined,
  32096                 .enum_literal,
  32097                 .type_info,
  32098                 => true,
  32099             },
  32100             .struct_type => |struct_type| {
  32101                 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;
  32102                 switch (struct_obj.requires_comptime) {
  32103                     .no, .wip => return false,
  32104                     .yes => return true,
  32105                     .unknown => {
  32106                         var requires_comptime = false;
  32107                         struct_obj.requires_comptime = .wip;
  32108                         for (struct_obj.fields.values()) |field| {
  32109                             if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true;
  32110                         }
  32111                         if (requires_comptime) {
  32112                             struct_obj.requires_comptime = .yes;
  32113                         } else {
  32114                             struct_obj.requires_comptime = .no;
  32115                         }
  32116                         return requires_comptime;
  32117                     },
  32118                 }
  32119             },
  32120 
  32121             .anon_struct_type => |tuple| {
  32122                 for (tuple.types, tuple.values) |field_ty, field_val| {
  32123                     const have_comptime_val = field_val != .none;
  32124                     if (!have_comptime_val and try sema.resolveTypeRequiresComptime(field_ty.toType())) {
  32125                         return true;
  32126                     }
  32127                 }
  32128                 return false;
  32129             },
  32130 
  32131             .union_type => |union_type| {
  32132                 const union_obj = mod.unionPtr(union_type.index);
  32133                 switch (union_obj.requires_comptime) {
  32134                     .no, .wip => return false,
  32135                     .yes => return true,
  32136                     .unknown => {
  32137                         var requires_comptime = false;
  32138                         union_obj.requires_comptime = .wip;
  32139                         for (union_obj.fields.values()) |field| {
  32140                             if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true;
  32141                         }
  32142                         if (requires_comptime) {
  32143                             union_obj.requires_comptime = .yes;
  32144                         } else {
  32145                             union_obj.requires_comptime = .no;
  32146                         }
  32147                         return requires_comptime;
  32148                     },
  32149                 }
  32150             },
  32151 
  32152             .opaque_type => false,
  32153 
  32154             .enum_type => |enum_type| try sema.resolveTypeRequiresComptime(enum_type.tag_ty.toType()),
  32155 
  32156             // values, not types
  32157             .undef,
  32158             .runtime_value,
  32159             .simple_value,
  32160             .variable,
  32161             .extern_func,
  32162             .func,
  32163             .int,
  32164             .err,
  32165             .error_union,
  32166             .enum_literal,
  32167             .enum_tag,
  32168             .empty_enum_value,
  32169             .float,
  32170             .ptr,
  32171             .opt,
  32172             .aggregate,
  32173             .un,
  32174             // memoization, not types
  32175             .memoized_call,
  32176             => unreachable,
  32177         },
  32178     };
  32179 }
  32180 
  32181 /// Returns `error.AnalysisFail` if any of the types (recursively) failed to
  32182 /// be resolved.
  32183 pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void {
  32184     const mod = sema.mod;
  32185     switch (ty.zigTypeTag(mod)) {
  32186         .Pointer => {
  32187             const child_ty = try sema.resolveTypeFields(ty.childType(mod));
  32188             return sema.resolveTypeFully(child_ty);
  32189         },
  32190         .Struct => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
  32191             .struct_type => return sema.resolveStructFully(ty),
  32192             .anon_struct_type => |tuple| {
  32193                 for (tuple.types) |field_ty| {
  32194                     try sema.resolveTypeFully(field_ty.toType());
  32195                 }
  32196             },
  32197             else => {},
  32198         },
  32199         .Union => return sema.resolveUnionFully(ty),
  32200         .Array => return sema.resolveTypeFully(ty.childType(mod)),
  32201         .Optional => {
  32202             return sema.resolveTypeFully(ty.optionalChild(mod));
  32203         },
  32204         .ErrorUnion => return sema.resolveTypeFully(ty.errorUnionPayload(mod)),
  32205         .Fn => {
  32206             const info = mod.typeToFunc(ty).?;
  32207             if (info.is_generic) {
  32208                 // Resolving of generic function types is deferred to when
  32209                 // the function is instantiated.
  32210                 return;
  32211             }
  32212             for (info.param_types) |param_ty| {
  32213                 try sema.resolveTypeFully(param_ty.toType());
  32214             }
  32215             try sema.resolveTypeFully(info.return_type.toType());
  32216         },
  32217         else => {},
  32218     }
  32219 }
  32220 
  32221 fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void {
  32222     try sema.resolveStructLayout(ty);
  32223 
  32224     const mod = sema.mod;
  32225     const resolved_ty = try sema.resolveTypeFields(ty);
  32226     const struct_obj = mod.typeToStruct(resolved_ty).?;
  32227 
  32228     switch (struct_obj.status) {
  32229         .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
  32230         .fully_resolved_wip, .fully_resolved => return,
  32231     }
  32232 
  32233     {
  32234         // After we have resolve struct layout we have to go over the fields again to
  32235         // make sure pointer fields get their child types resolved as well.
  32236         // See also similar code for unions.
  32237         const prev_status = struct_obj.status;
  32238         errdefer struct_obj.status = prev_status;
  32239 
  32240         struct_obj.status = .fully_resolved_wip;
  32241         for (struct_obj.fields.values()) |field| {
  32242             try sema.resolveTypeFully(field.ty);
  32243         }
  32244         struct_obj.status = .fully_resolved;
  32245     }
  32246 
  32247     // And let's not forget comptime-only status.
  32248     _ = try sema.typeRequiresComptime(ty);
  32249 }
  32250 
  32251 fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
  32252     try sema.resolveUnionLayout(ty);
  32253 
  32254     const mod = sema.mod;
  32255     const resolved_ty = try sema.resolveTypeFields(ty);
  32256     const union_obj = mod.typeToUnion(resolved_ty).?;
  32257     switch (union_obj.status) {
  32258         .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
  32259         .fully_resolved_wip, .fully_resolved => return,
  32260     }
  32261 
  32262     {
  32263         // After we have resolve union layout we have to go over the fields again to
  32264         // make sure pointer fields get their child types resolved as well.
  32265         // See also similar code for structs.
  32266         const prev_status = union_obj.status;
  32267         errdefer union_obj.status = prev_status;
  32268 
  32269         union_obj.status = .fully_resolved_wip;
  32270         for (union_obj.fields.values()) |field| {
  32271             try sema.resolveTypeFully(field.ty);
  32272         }
  32273         union_obj.status = .fully_resolved;
  32274     }
  32275 
  32276     // And let's not forget comptime-only status.
  32277     _ = try sema.typeRequiresComptime(ty);
  32278 }
  32279 
  32280 pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type {
  32281     const mod = sema.mod;
  32282 
  32283     switch (ty.toIntern()) {
  32284         .var_args_param_type => unreachable,
  32285 
  32286         .none => unreachable,
  32287 
  32288         .u1_type,
  32289         .u8_type,
  32290         .i8_type,
  32291         .u16_type,
  32292         .i16_type,
  32293         .u29_type,
  32294         .u32_type,
  32295         .i32_type,
  32296         .u64_type,
  32297         .i64_type,
  32298         .u80_type,
  32299         .u128_type,
  32300         .i128_type,
  32301         .usize_type,
  32302         .isize_type,
  32303         .c_char_type,
  32304         .c_short_type,
  32305         .c_ushort_type,
  32306         .c_int_type,
  32307         .c_uint_type,
  32308         .c_long_type,
  32309         .c_ulong_type,
  32310         .c_longlong_type,
  32311         .c_ulonglong_type,
  32312         .c_longdouble_type,
  32313         .f16_type,
  32314         .f32_type,
  32315         .f64_type,
  32316         .f80_type,
  32317         .f128_type,
  32318         .anyopaque_type,
  32319         .bool_type,
  32320         .void_type,
  32321         .type_type,
  32322         .anyerror_type,
  32323         .comptime_int_type,
  32324         .comptime_float_type,
  32325         .noreturn_type,
  32326         .anyframe_type,
  32327         .null_type,
  32328         .undefined_type,
  32329         .enum_literal_type,
  32330         .manyptr_u8_type,
  32331         .manyptr_const_u8_type,
  32332         .manyptr_const_u8_sentinel_0_type,
  32333         .single_const_pointer_to_comptime_int_type,
  32334         .slice_const_u8_type,
  32335         .slice_const_u8_sentinel_0_type,
  32336         .anyerror_void_error_union_type,
  32337         .generic_poison_type,
  32338         .empty_struct_type,
  32339         => return ty,
  32340 
  32341         .undef => unreachable,
  32342         .zero => unreachable,
  32343         .zero_usize => unreachable,
  32344         .zero_u8 => unreachable,
  32345         .one => unreachable,
  32346         .one_usize => unreachable,
  32347         .one_u8 => unreachable,
  32348         .four_u8 => unreachable,
  32349         .negative_one => unreachable,
  32350         .calling_convention_c => unreachable,
  32351         .calling_convention_inline => unreachable,
  32352         .void_value => unreachable,
  32353         .unreachable_value => unreachable,
  32354         .null_value => unreachable,
  32355         .bool_true => unreachable,
  32356         .bool_false => unreachable,
  32357         .empty_struct => unreachable,
  32358         .generic_poison => unreachable,
  32359 
  32360         .type_info_type => return sema.getBuiltinType("Type"),
  32361         .extern_options_type => return sema.getBuiltinType("ExternOptions"),
  32362         .export_options_type => return sema.getBuiltinType("ExportOptions"),
  32363         .atomic_order_type => return sema.getBuiltinType("AtomicOrder"),
  32364         .atomic_rmw_op_type => return sema.getBuiltinType("AtomicRmwOp"),
  32365         .calling_convention_type => return sema.getBuiltinType("CallingConvention"),
  32366         .address_space_type => return sema.getBuiltinType("AddressSpace"),
  32367         .float_mode_type => return sema.getBuiltinType("FloatMode"),
  32368         .reduce_op_type => return sema.getBuiltinType("ReduceOp"),
  32369         .call_modifier_type => return sema.getBuiltinType("CallModifier"),
  32370         .prefetch_options_type => return sema.getBuiltinType("PrefetchOptions"),
  32371 
  32372         _ => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
  32373             .struct_type => |struct_type| {
  32374                 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return ty;
  32375                 try sema.resolveTypeFieldsStruct(ty, struct_obj);
  32376                 return ty;
  32377             },
  32378             .union_type => |union_type| {
  32379                 const union_obj = mod.unionPtr(union_type.index);
  32380                 try sema.resolveTypeFieldsUnion(ty, union_obj);
  32381                 return ty;
  32382             },
  32383 
  32384             else => return ty,
  32385         },
  32386     }
  32387 }
  32388 
  32389 fn resolveTypeFieldsStruct(
  32390     sema: *Sema,
  32391     ty: Type,
  32392     struct_obj: *Module.Struct,
  32393 ) CompileError!void {
  32394     switch (sema.mod.declPtr(struct_obj.owner_decl).analysis) {
  32395         .file_failure,
  32396         .dependency_failure,
  32397         .sema_failure,
  32398         .sema_failure_retryable,
  32399         => {
  32400             sema.owner_decl.analysis = .dependency_failure;
  32401             sema.owner_decl.generation = sema.mod.generation;
  32402             return error.AnalysisFail;
  32403         },
  32404         else => {},
  32405     }
  32406     switch (struct_obj.status) {
  32407         .none => {},
  32408         .field_types_wip => {
  32409             const msg = try Module.ErrorMsg.create(
  32410                 sema.gpa,
  32411                 struct_obj.srcLoc(sema.mod),
  32412                 "struct '{}' depends on itself",
  32413                 .{ty.fmt(sema.mod)},
  32414             );
  32415             return sema.failWithOwnedErrorMsg(msg);
  32416         },
  32417         .have_field_types,
  32418         .have_layout,
  32419         .layout_wip,
  32420         .fully_resolved_wip,
  32421         .fully_resolved,
  32422         => return,
  32423     }
  32424 
  32425     struct_obj.status = .field_types_wip;
  32426     errdefer struct_obj.status = .none;
  32427     try semaStructFields(sema.mod, struct_obj);
  32428 }
  32429 
  32430 fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_obj: *Module.Union) CompileError!void {
  32431     switch (sema.mod.declPtr(union_obj.owner_decl).analysis) {
  32432         .file_failure,
  32433         .dependency_failure,
  32434         .sema_failure,
  32435         .sema_failure_retryable,
  32436         => {
  32437             sema.owner_decl.analysis = .dependency_failure;
  32438             sema.owner_decl.generation = sema.mod.generation;
  32439             return error.AnalysisFail;
  32440         },
  32441         else => {},
  32442     }
  32443     switch (union_obj.status) {
  32444         .none => {},
  32445         .field_types_wip => {
  32446             const msg = try Module.ErrorMsg.create(
  32447                 sema.gpa,
  32448                 union_obj.srcLoc(sema.mod),
  32449                 "union '{}' depends on itself",
  32450                 .{ty.fmt(sema.mod)},
  32451             );
  32452             return sema.failWithOwnedErrorMsg(msg);
  32453         },
  32454         .have_field_types,
  32455         .have_layout,
  32456         .layout_wip,
  32457         .fully_resolved_wip,
  32458         .fully_resolved,
  32459         => return,
  32460     }
  32461 
  32462     union_obj.status = .field_types_wip;
  32463     errdefer union_obj.status = .none;
  32464     try semaUnionFields(sema.mod, union_obj);
  32465     union_obj.status = .have_field_types;
  32466 }
  32467 
  32468 fn resolveInferredErrorSet(
  32469     sema: *Sema,
  32470     block: *Block,
  32471     src: LazySrcLoc,
  32472     ies_index: Module.Fn.InferredErrorSet.Index,
  32473 ) CompileError!void {
  32474     const mod = sema.mod;
  32475     const ies = mod.inferredErrorSetPtr(ies_index);
  32476 
  32477     if (ies.is_resolved) return;
  32478 
  32479     const func = mod.funcPtr(ies.func);
  32480     if (func.state == .in_progress) {
  32481         return sema.fail(block, src, "unable to resolve inferred error set", .{});
  32482     }
  32483 
  32484     // In order to ensure that all dependencies are properly added to the set, we
  32485     // need to ensure the function body is analyzed of the inferred error set.
  32486     // However, in the case of comptime/inline function calls with inferred error sets,
  32487     // each call gets a new InferredErrorSet object, which contains the same
  32488     // `Module.Fn.Index`. Not only is the function not relevant to the inferred error set
  32489     // in this case, it may be a generic function which would cause an assertion failure
  32490     // if we called `ensureFuncBodyAnalyzed` on it here.
  32491     const ies_func_owner_decl = mod.declPtr(func.owner_decl);
  32492     const ies_func_info = mod.typeToFunc(ies_func_owner_decl.ty).?;
  32493     // if ies declared by a inline function with generic return type, the return_type should be generic_poison,
  32494     // because inline function does not create a new declaration, and the ies has been filled with analyzeCall,
  32495     // so here we can simply skip this case.
  32496     if (ies_func_info.return_type == .generic_poison_type) {
  32497         assert(ies_func_info.cc == .Inline);
  32498     } else if (mod.typeToInferredErrorSet(ies_func_info.return_type.toType().errorUnionSet(mod)).? == ies) {
  32499         if (ies_func_info.is_generic) {
  32500             const msg = msg: {
  32501                 const msg = try sema.errMsg(block, src, "unable to resolve inferred error set of generic function", .{});
  32502                 errdefer msg.destroy(sema.gpa);
  32503 
  32504                 try sema.mod.errNoteNonLazy(ies_func_owner_decl.srcLoc(mod), msg, "generic function declared here", .{});
  32505                 break :msg msg;
  32506             };
  32507             return sema.failWithOwnedErrorMsg(msg);
  32508         }
  32509         // In this case we are dealing with the actual InferredErrorSet object that
  32510         // corresponds to the function, not one created to track an inline/comptime call.
  32511         try sema.ensureFuncBodyAnalyzed(ies.func);
  32512     }
  32513 
  32514     ies.is_resolved = true;
  32515 
  32516     for (ies.inferred_error_sets.keys()) |other_ies_index| {
  32517         if (ies_index == other_ies_index) continue;
  32518         try sema.resolveInferredErrorSet(block, src, other_ies_index);
  32519 
  32520         const other_ies = mod.inferredErrorSetPtr(other_ies_index);
  32521         for (other_ies.errors.keys()) |key| {
  32522             try ies.errors.put(sema.gpa, key, {});
  32523         }
  32524         if (other_ies.is_anyerror)
  32525             ies.is_anyerror = true;
  32526     }
  32527 }
  32528 
  32529 fn resolveInferredErrorSetTy(
  32530     sema: *Sema,
  32531     block: *Block,
  32532     src: LazySrcLoc,
  32533     ty: Type,
  32534 ) CompileError!void {
  32535     const mod = sema.mod;
  32536     if (mod.typeToInferredErrorSetIndex(ty).unwrap()) |ies_index| {
  32537         try sema.resolveInferredErrorSet(block, src, ies_index);
  32538     }
  32539 }
  32540 
  32541 fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
  32542     const gpa = mod.gpa;
  32543     const decl_index = struct_obj.owner_decl;
  32544     const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir;
  32545     const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
  32546     assert(extended.opcode == .struct_decl);
  32547     const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
  32548     var extra_index: usize = extended.operand;
  32549 
  32550     const src = LazySrcLoc.nodeOffset(0);
  32551     extra_index += @boolToInt(small.has_src_node);
  32552 
  32553     const fields_len = if (small.has_fields_len) blk: {
  32554         const fields_len = zir.extra[extra_index];
  32555         extra_index += 1;
  32556         break :blk fields_len;
  32557     } else 0;
  32558 
  32559     const decls_len = if (small.has_decls_len) decls_len: {
  32560         const decls_len = zir.extra[extra_index];
  32561         extra_index += 1;
  32562         break :decls_len decls_len;
  32563     } else 0;
  32564 
  32565     // The backing integer cannot be handled until `resolveStructLayout()`.
  32566     if (small.has_backing_int) {
  32567         const backing_int_body_len = zir.extra[extra_index];
  32568         extra_index += 1; // backing_int_body_len
  32569         if (backing_int_body_len == 0) {
  32570             extra_index += 1; // backing_int_ref
  32571         } else {
  32572             extra_index += backing_int_body_len; // backing_int_body_inst
  32573         }
  32574     }
  32575 
  32576     // Skip over decls.
  32577     var decls_it = zir.declIteratorInner(extra_index, decls_len);
  32578     while (decls_it.next()) |_| {}
  32579     extra_index = decls_it.extra_index;
  32580 
  32581     if (fields_len == 0) {
  32582         if (struct_obj.layout == .Packed) {
  32583             try semaBackingIntType(mod, struct_obj);
  32584         }
  32585         struct_obj.status = .have_layout;
  32586         return;
  32587     }
  32588 
  32589     const decl = mod.declPtr(decl_index);
  32590     var decl_arena: std.heap.ArenaAllocator = undefined;
  32591     const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena);
  32592     defer decl.value_arena.?.release(&decl_arena);
  32593 
  32594     var analysis_arena = std.heap.ArenaAllocator.init(gpa);
  32595     defer analysis_arena.deinit();
  32596 
  32597     var sema: Sema = .{
  32598         .mod = mod,
  32599         .gpa = gpa,
  32600         .arena = analysis_arena.allocator(),
  32601         .perm_arena = decl_arena_allocator,
  32602         .code = zir,
  32603         .owner_decl = decl,
  32604         .owner_decl_index = decl_index,
  32605         .func = null,
  32606         .func_index = .none,
  32607         .fn_ret_ty = Type.void,
  32608         .owner_func = null,
  32609         .owner_func_index = .none,
  32610     };
  32611     defer sema.deinit();
  32612 
  32613     var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope);
  32614     defer wip_captures.deinit();
  32615 
  32616     var block_scope: Block = .{
  32617         .parent = null,
  32618         .sema = &sema,
  32619         .src_decl = decl_index,
  32620         .namespace = struct_obj.namespace,
  32621         .wip_capture_scope = wip_captures.scope,
  32622         .instructions = .{},
  32623         .inlining = null,
  32624         .is_comptime = true,
  32625     };
  32626     defer {
  32627         assert(block_scope.instructions.items.len == 0);
  32628         block_scope.params.deinit(gpa);
  32629     }
  32630 
  32631     struct_obj.fields = .{};
  32632     try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
  32633 
  32634     const Field = struct {
  32635         type_body_len: u32 = 0,
  32636         align_body_len: u32 = 0,
  32637         init_body_len: u32 = 0,
  32638         type_ref: Zir.Inst.Ref = .none,
  32639     };
  32640     const fields = try sema.arena.alloc(Field, fields_len);
  32641     var any_inits = false;
  32642 
  32643     {
  32644         const bits_per_field = 4;
  32645         const fields_per_u32 = 32 / bits_per_field;
  32646         const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
  32647         const flags_index = extra_index;
  32648         var bit_bag_index: usize = flags_index;
  32649         extra_index += bit_bags_count;
  32650         var cur_bit_bag: u32 = undefined;
  32651         var field_i: u32 = 0;
  32652         while (field_i < fields_len) : (field_i += 1) {
  32653             if (field_i % fields_per_u32 == 0) {
  32654                 cur_bit_bag = zir.extra[bit_bag_index];
  32655                 bit_bag_index += 1;
  32656             }
  32657             const has_align = @truncate(u1, cur_bit_bag) != 0;
  32658             cur_bit_bag >>= 1;
  32659             const has_init = @truncate(u1, cur_bit_bag) != 0;
  32660             cur_bit_bag >>= 1;
  32661             const is_comptime = @truncate(u1, cur_bit_bag) != 0;
  32662             cur_bit_bag >>= 1;
  32663             const has_type_body = @truncate(u1, cur_bit_bag) != 0;
  32664             cur_bit_bag >>= 1;
  32665 
  32666             var field_name_zir: ?[:0]const u8 = null;
  32667             if (!small.is_tuple) {
  32668                 field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
  32669                 extra_index += 1;
  32670             }
  32671             extra_index += 1; // doc_comment
  32672 
  32673             fields[field_i] = .{};
  32674 
  32675             if (has_type_body) {
  32676                 fields[field_i].type_body_len = zir.extra[extra_index];
  32677             } else {
  32678                 fields[field_i].type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
  32679             }
  32680             extra_index += 1;
  32681 
  32682             // This string needs to outlive the ZIR code.
  32683             const field_name = if (field_name_zir) |some|
  32684                 try decl_arena_allocator.dupe(u8, some)
  32685             else
  32686                 try std.fmt.allocPrint(decl_arena_allocator, "{d}", .{field_i});
  32687 
  32688             const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
  32689             if (gop.found_existing) {
  32690                 const msg = msg: {
  32691                     const field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = field_i }).lazy;
  32692                     const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name});
  32693                     errdefer msg.destroy(gpa);
  32694 
  32695                     const prev_field_index = struct_obj.fields.getIndex(field_name).?;
  32696                     const prev_field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = prev_field_index });
  32697                     try mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{});
  32698                     try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
  32699                     break :msg msg;
  32700                 };
  32701                 return sema.failWithOwnedErrorMsg(msg);
  32702             }
  32703             gop.value_ptr.* = .{
  32704                 .ty = Type.noreturn,
  32705                 .abi_align = 0,
  32706                 .default_val = Value.@"unreachable",
  32707                 .is_comptime = is_comptime,
  32708                 .offset = undefined,
  32709             };
  32710 
  32711             if (has_align) {
  32712                 fields[field_i].align_body_len = zir.extra[extra_index];
  32713                 extra_index += 1;
  32714             }
  32715             if (has_init) {
  32716                 fields[field_i].init_body_len = zir.extra[extra_index];
  32717                 extra_index += 1;
  32718                 any_inits = true;
  32719             }
  32720         }
  32721     }
  32722 
  32723     // Next we do only types and alignments, saving the inits for a second pass,
  32724     // so that init values may depend on type layout.
  32725     const bodies_index = extra_index;
  32726 
  32727     for (fields, 0..) |zir_field, field_i| {
  32728         const field_ty: Type = ty: {
  32729             if (zir_field.type_ref != .none) {
  32730                 break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) {
  32731                     error.NeededSourceLocation => {
  32732                         const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
  32733                             .index = field_i,
  32734                             .range = .type,
  32735                         }).lazy;
  32736                         _ = try sema.resolveType(&block_scope, ty_src, zir_field.type_ref);
  32737                         unreachable;
  32738                     },
  32739                     else => |e| return e,
  32740                 };
  32741             }
  32742             assert(zir_field.type_body_len != 0);
  32743             const body = zir.extra[extra_index..][0..zir_field.type_body_len];
  32744             extra_index += body.len;
  32745             const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
  32746             break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) {
  32747                 error.NeededSourceLocation => {
  32748                     const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
  32749                         .index = field_i,
  32750                         .range = .type,
  32751                     }).lazy;
  32752                     _ = try sema.analyzeAsType(&block_scope, ty_src, ty_ref);
  32753                     unreachable;
  32754                 },
  32755                 else => |e| return e,
  32756             };
  32757         };
  32758         if (field_ty.isGenericPoison()) {
  32759             return error.GenericPoison;
  32760         }
  32761 
  32762         const field = &struct_obj.fields.values()[field_i];
  32763         field.ty = field_ty;
  32764 
  32765         if (field_ty.zigTypeTag(mod) == .Opaque) {
  32766             const msg = msg: {
  32767                 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
  32768                     .index = field_i,
  32769                     .range = .type,
  32770                 }).lazy;
  32771                 const msg = try sema.errMsg(&block_scope, ty_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
  32772                 errdefer msg.destroy(sema.gpa);
  32773 
  32774                 try sema.addDeclaredHereNote(msg, field_ty);
  32775                 break :msg msg;
  32776             };
  32777             return sema.failWithOwnedErrorMsg(msg);
  32778         }
  32779         if (field_ty.zigTypeTag(mod) == .NoReturn) {
  32780             const msg = msg: {
  32781                 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
  32782                     .index = field_i,
  32783                     .range = .type,
  32784                 }).lazy;
  32785                 const msg = try sema.errMsg(&block_scope, ty_src, "struct fields cannot be 'noreturn'", .{});
  32786                 errdefer msg.destroy(sema.gpa);
  32787 
  32788                 try sema.addDeclaredHereNote(msg, field_ty);
  32789                 break :msg msg;
  32790             };
  32791             return sema.failWithOwnedErrorMsg(msg);
  32792         }
  32793         if (struct_obj.layout == .Extern and !try sema.validateExternType(field.ty, .struct_field)) {
  32794             const msg = msg: {
  32795                 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
  32796                     .index = field_i,
  32797                     .range = .type,
  32798                 });
  32799                 const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)});
  32800                 errdefer msg.destroy(sema.gpa);
  32801 
  32802                 try sema.explainWhyTypeIsNotExtern(msg, ty_src, field.ty, .struct_field);
  32803 
  32804                 try sema.addDeclaredHereNote(msg, field.ty);
  32805                 break :msg msg;
  32806             };
  32807             return sema.failWithOwnedErrorMsg(msg);
  32808         } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty, mod))) {
  32809             const msg = msg: {
  32810                 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
  32811                     .index = field_i,
  32812                     .range = .type,
  32813                 });
  32814                 const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)});
  32815                 errdefer msg.destroy(sema.gpa);
  32816 
  32817                 try sema.explainWhyTypeIsNotPacked(msg, ty_src, field.ty);
  32818 
  32819                 try sema.addDeclaredHereNote(msg, field.ty);
  32820                 break :msg msg;
  32821             };
  32822             return sema.failWithOwnedErrorMsg(msg);
  32823         }
  32824 
  32825         if (zir_field.align_body_len > 0) {
  32826             const body = zir.extra[extra_index..][0..zir_field.align_body_len];
  32827             extra_index += body.len;
  32828             const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
  32829             field.abi_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {
  32830                 error.NeededSourceLocation => {
  32831                     const align_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
  32832                         .index = field_i,
  32833                         .range = .alignment,
  32834                     }).lazy;
  32835                     _ = try sema.analyzeAsAlign(&block_scope, align_src, align_ref);
  32836                     unreachable;
  32837                 },
  32838                 else => |e| return e,
  32839             };
  32840         }
  32841 
  32842         extra_index += zir_field.init_body_len;
  32843     }
  32844 
  32845     struct_obj.status = .have_field_types;
  32846 
  32847     if (any_inits) {
  32848         extra_index = bodies_index;
  32849         for (fields, 0..) |zir_field, field_i| {
  32850             extra_index += zir_field.type_body_len;
  32851             extra_index += zir_field.align_body_len;
  32852             if (zir_field.init_body_len > 0) {
  32853                 const body = zir.extra[extra_index..][0..zir_field.init_body_len];
  32854                 extra_index += body.len;
  32855                 const init = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
  32856                 const field = &struct_obj.fields.values()[field_i];
  32857                 const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) {
  32858                     error.NeededSourceLocation => {
  32859                         const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
  32860                             .index = field_i,
  32861                             .range = .value,
  32862                         }).lazy;
  32863                         _ = try sema.coerce(&block_scope, field.ty, init, init_src);
  32864                         unreachable;
  32865                     },
  32866                     else => |e| return e,
  32867                 };
  32868                 const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
  32869                     const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
  32870                         .index = field_i,
  32871                         .range = .value,
  32872                     }).lazy;
  32873                     return sema.failWithNeededComptime(&block_scope, init_src, "struct field default value must be comptime-known");
  32874                 };
  32875                 field.default_val = try default_val.copy(decl_arena_allocator);
  32876             }
  32877         }
  32878     }
  32879     try wip_captures.finalize();
  32880 
  32881     struct_obj.have_field_inits = true;
  32882 }
  32883 
  32884 fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
  32885     const tracy = trace(@src());
  32886     defer tracy.end();
  32887 
  32888     const gpa = mod.gpa;
  32889     const decl_index = union_obj.owner_decl;
  32890     const zir = mod.namespacePtr(union_obj.namespace).file_scope.zir;
  32891     const extended = zir.instructions.items(.data)[union_obj.zir_index].extended;
  32892     assert(extended.opcode == .union_decl);
  32893     const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
  32894     var extra_index: usize = extended.operand;
  32895 
  32896     const src = LazySrcLoc.nodeOffset(0);
  32897     extra_index += @boolToInt(small.has_src_node);
  32898 
  32899     const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: {
  32900         const ty_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
  32901         extra_index += 1;
  32902         break :blk ty_ref;
  32903     } else .none;
  32904 
  32905     const body_len = if (small.has_body_len) blk: {
  32906         const body_len = zir.extra[extra_index];
  32907         extra_index += 1;
  32908         break :blk body_len;
  32909     } else 0;
  32910 
  32911     const fields_len = if (small.has_fields_len) blk: {
  32912         const fields_len = zir.extra[extra_index];
  32913         extra_index += 1;
  32914         break :blk fields_len;
  32915     } else 0;
  32916 
  32917     const decls_len = if (small.has_decls_len) decls_len: {
  32918         const decls_len = zir.extra[extra_index];
  32919         extra_index += 1;
  32920         break :decls_len decls_len;
  32921     } else 0;
  32922 
  32923     // Skip over decls.
  32924     var decls_it = zir.declIteratorInner(extra_index, decls_len);
  32925     while (decls_it.next()) |_| {}
  32926     extra_index = decls_it.extra_index;
  32927 
  32928     const body = zir.extra[extra_index..][0..body_len];
  32929     extra_index += body.len;
  32930 
  32931     const decl = mod.declPtr(decl_index);
  32932     var decl_arena: std.heap.ArenaAllocator = undefined;
  32933     const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena);
  32934     defer decl.value_arena.?.release(&decl_arena);
  32935 
  32936     var analysis_arena = std.heap.ArenaAllocator.init(gpa);
  32937     defer analysis_arena.deinit();
  32938 
  32939     var sema: Sema = .{
  32940         .mod = mod,
  32941         .gpa = gpa,
  32942         .arena = analysis_arena.allocator(),
  32943         .perm_arena = decl_arena_allocator,
  32944         .code = zir,
  32945         .owner_decl = decl,
  32946         .owner_decl_index = decl_index,
  32947         .func = null,
  32948         .func_index = .none,
  32949         .fn_ret_ty = Type.void,
  32950         .owner_func = null,
  32951         .owner_func_index = .none,
  32952     };
  32953     defer sema.deinit();
  32954 
  32955     var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope);
  32956     defer wip_captures.deinit();
  32957 
  32958     var block_scope: Block = .{
  32959         .parent = null,
  32960         .sema = &sema,
  32961         .src_decl = decl_index,
  32962         .namespace = union_obj.namespace,
  32963         .wip_capture_scope = wip_captures.scope,
  32964         .instructions = .{},
  32965         .inlining = null,
  32966         .is_comptime = true,
  32967     };
  32968     defer {
  32969         assert(block_scope.instructions.items.len == 0);
  32970         block_scope.params.deinit(gpa);
  32971     }
  32972 
  32973     if (body.len != 0) {
  32974         try sema.analyzeBody(&block_scope, body);
  32975     }
  32976 
  32977     try wip_captures.finalize();
  32978 
  32979     try union_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
  32980 
  32981     var int_tag_ty: Type = undefined;
  32982     var enum_field_names: []InternPool.NullTerminatedString = &.{};
  32983     var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{};
  32984     var explicit_tags_seen: []bool = &.{};
  32985     var explicit_enum_info: ?InternPool.Key.EnumType = null;
  32986     if (tag_type_ref != .none) {
  32987         const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x };
  32988         const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref);
  32989         if (small.auto_enum_tag) {
  32990             // The provided type is an integer type and we must construct the enum tag type here.
  32991             int_tag_ty = provided_ty;
  32992             if (int_tag_ty.zigTypeTag(mod) != .Int and int_tag_ty.zigTypeTag(mod) != .ComptimeInt) {
  32993                 return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{}'", .{int_tag_ty.fmt(mod)});
  32994             }
  32995 
  32996             if (fields_len > 0) {
  32997                 const field_count_val = try mod.intValue(int_tag_ty, fields_len - 1);
  32998                 if (!(try sema.intFitsInType(field_count_val, int_tag_ty, null))) {
  32999                     const msg = msg: {
  33000                         const msg = try sema.errMsg(&block_scope, tag_ty_src, "specified integer tag type cannot represent every field", .{});
  33001                         errdefer msg.destroy(sema.gpa);
  33002                         try sema.errNote(&block_scope, tag_ty_src, msg, "type '{}' cannot fit values in range 0...{d}", .{
  33003                             int_tag_ty.fmt(mod),
  33004                             fields_len - 1,
  33005                         });
  33006                         break :msg msg;
  33007                     };
  33008                     return sema.failWithOwnedErrorMsg(msg);
  33009                 }
  33010                 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
  33011                 try enum_field_vals.ensureTotalCapacity(sema.arena, fields_len);
  33012             }
  33013         } else {
  33014             // The provided type is the enum tag type.
  33015             union_obj.tag_ty = provided_ty;
  33016             const enum_type = switch (mod.intern_pool.indexToKey(union_obj.tag_ty.toIntern())) {
  33017                 .enum_type => |x| x,
  33018                 else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(mod)}),
  33019             };
  33020             // The fields of the union must match the enum exactly.
  33021             // A flag per field is used to check for missing and extraneous fields.
  33022             explicit_enum_info = enum_type;
  33023             explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
  33024             @memset(explicit_tags_seen, false);
  33025         }
  33026     } else {
  33027         // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis
  33028         // purposes, we still auto-generate an enum tag type the same way. That the union is
  33029         // untagged is represented by the Type tag (union vs union_tagged).
  33030         enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
  33031     }
  33032 
  33033     const bits_per_field = 4;
  33034     const fields_per_u32 = 32 / bits_per_field;
  33035     const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
  33036     var bit_bag_index: usize = extra_index;
  33037     extra_index += bit_bags_count;
  33038     var cur_bit_bag: u32 = undefined;
  33039     var field_i: u32 = 0;
  33040     var last_tag_val: ?Value = null;
  33041     while (field_i < fields_len) : (field_i += 1) {
  33042         if (field_i % fields_per_u32 == 0) {
  33043             cur_bit_bag = zir.extra[bit_bag_index];
  33044             bit_bag_index += 1;
  33045         }
  33046         const has_type = @truncate(u1, cur_bit_bag) != 0;
  33047         cur_bit_bag >>= 1;
  33048         const has_align = @truncate(u1, cur_bit_bag) != 0;
  33049         cur_bit_bag >>= 1;
  33050         const has_tag = @truncate(u1, cur_bit_bag) != 0;
  33051         cur_bit_bag >>= 1;
  33052         const unused = @truncate(u1, cur_bit_bag) != 0;
  33053         cur_bit_bag >>= 1;
  33054         _ = unused;
  33055 
  33056         const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
  33057         extra_index += 1;
  33058 
  33059         // doc_comment
  33060         extra_index += 1;
  33061 
  33062         const field_type_ref: Zir.Inst.Ref = if (has_type) blk: {
  33063             const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
  33064             extra_index += 1;
  33065             break :blk field_type_ref;
  33066         } else .none;
  33067 
  33068         const align_ref: Zir.Inst.Ref = if (has_align) blk: {
  33069             const align_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
  33070             extra_index += 1;
  33071             break :blk align_ref;
  33072         } else .none;
  33073 
  33074         const tag_ref: Air.Inst.Ref = if (has_tag) blk: {
  33075             const tag_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
  33076             extra_index += 1;
  33077             break :blk try sema.resolveInst(tag_ref);
  33078         } else .none;
  33079 
  33080         if (enum_field_vals.capacity() > 0) {
  33081             const enum_tag_val = if (tag_ref != .none) blk: {
  33082                 const val = sema.semaUnionFieldVal(&block_scope, .unneeded, int_tag_ty, tag_ref) catch |err| switch (err) {
  33083                     error.NeededSourceLocation => {
  33084                         const val_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
  33085                             .index = field_i,
  33086                             .range = .value,
  33087                         }).lazy;
  33088                         _ = try sema.semaUnionFieldVal(&block_scope, val_src, int_tag_ty, tag_ref);
  33089                         unreachable;
  33090                     },
  33091                     else => |e| return e,
  33092                 };
  33093                 last_tag_val = val;
  33094 
  33095                 break :blk val;
  33096             } else blk: {
  33097                 const val = if (last_tag_val) |val|
  33098                     try sema.intAdd(val, Value.one_comptime_int, int_tag_ty)
  33099                 else
  33100                     try mod.intValue(int_tag_ty, 0);
  33101                 last_tag_val = val;
  33102 
  33103                 break :blk val;
  33104             };
  33105             const gop = enum_field_vals.getOrPutAssumeCapacity(enum_tag_val.toIntern());
  33106             if (gop.found_existing) {
  33107                 const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy;
  33108                 const other_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = gop.index }).lazy;
  33109                 const msg = msg: {
  33110                     const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{enum_tag_val.fmtValue(int_tag_ty, mod)});
  33111                     errdefer msg.destroy(gpa);
  33112                     try sema.errNote(&block_scope, other_field_src, msg, "other occurrence here", .{});
  33113                     break :msg msg;
  33114                 };
  33115                 return sema.failWithOwnedErrorMsg(msg);
  33116             }
  33117         }
  33118 
  33119         // This string needs to outlive the ZIR code.
  33120         const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
  33121         const field_name_ip = try mod.intern_pool.getOrPutString(gpa, field_name);
  33122         if (enum_field_names.len != 0) {
  33123             enum_field_names[field_i] = field_name_ip;
  33124         }
  33125 
  33126         const field_ty: Type = if (!has_type)
  33127             Type.void
  33128         else if (field_type_ref == .none)
  33129             Type.noreturn
  33130         else
  33131             sema.resolveType(&block_scope, .unneeded, field_type_ref) catch |err| switch (err) {
  33132                 error.NeededSourceLocation => {
  33133                     const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
  33134                         .index = field_i,
  33135                         .range = .type,
  33136                     }).lazy;
  33137                     _ = try sema.resolveType(&block_scope, ty_src, field_type_ref);
  33138                     unreachable;
  33139                 },
  33140                 else => |e| return e,
  33141             };
  33142 
  33143         if (field_ty.isGenericPoison()) {
  33144             return error.GenericPoison;
  33145         }
  33146 
  33147         const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
  33148         if (gop.found_existing) {
  33149             const msg = msg: {
  33150                 const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy;
  33151                 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name});
  33152                 errdefer msg.destroy(gpa);
  33153 
  33154                 const prev_field_index = union_obj.fields.getIndex(field_name).?;
  33155                 const prev_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = prev_field_index }).lazy;
  33156                 try mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl, mod), msg, "other field here", .{});
  33157                 try sema.errNote(&block_scope, src, msg, "union declared here", .{});
  33158                 break :msg msg;
  33159             };
  33160             return sema.failWithOwnedErrorMsg(msg);
  33161         }
  33162 
  33163         if (explicit_enum_info) |tag_info| {
  33164             const enum_index = tag_info.nameIndex(&mod.intern_pool, field_name_ip) orelse {
  33165                 const msg = msg: {
  33166                     const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
  33167                         .index = field_i,
  33168                         .range = .type,
  33169                     }).lazy;
  33170                     const msg = try sema.errMsg(&block_scope, ty_src, "no field named '{s}' in enum '{}'", .{
  33171                         field_name, union_obj.tag_ty.fmt(mod),
  33172                     });
  33173                     errdefer msg.destroy(sema.gpa);
  33174                     try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
  33175                     break :msg msg;
  33176                 };
  33177                 return sema.failWithOwnedErrorMsg(msg);
  33178             };
  33179             // No check for duplicate because the check already happened in order
  33180             // to create the enum type in the first place.
  33181             assert(!explicit_tags_seen[enum_index]);
  33182             explicit_tags_seen[enum_index] = true;
  33183         }
  33184 
  33185         if (field_ty.zigTypeTag(mod) == .Opaque) {
  33186             const msg = msg: {
  33187                 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
  33188                     .index = field_i,
  33189                     .range = .type,
  33190                 }).lazy;
  33191                 const msg = try sema.errMsg(&block_scope, ty_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
  33192                 errdefer msg.destroy(sema.gpa);
  33193 
  33194                 try sema.addDeclaredHereNote(msg, field_ty);
  33195                 break :msg msg;
  33196             };
  33197             return sema.failWithOwnedErrorMsg(msg);
  33198         }
  33199         if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {
  33200             const msg = msg: {
  33201                 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
  33202                     .index = field_i,
  33203                     .range = .type,
  33204                 });
  33205                 const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
  33206                 errdefer msg.destroy(sema.gpa);
  33207 
  33208                 try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .union_field);
  33209 
  33210                 try sema.addDeclaredHereNote(msg, field_ty);
  33211                 break :msg msg;
  33212             };
  33213             return sema.failWithOwnedErrorMsg(msg);
  33214         } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) {
  33215             const msg = msg: {
  33216                 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
  33217                     .index = field_i,
  33218                     .range = .type,
  33219                 });
  33220                 const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
  33221                 errdefer msg.destroy(sema.gpa);
  33222 
  33223                 try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty);
  33224 
  33225                 try sema.addDeclaredHereNote(msg, field_ty);
  33226                 break :msg msg;
  33227             };
  33228             return sema.failWithOwnedErrorMsg(msg);
  33229         }
  33230 
  33231         gop.value_ptr.* = .{
  33232             .ty = field_ty,
  33233             .abi_align = 0,
  33234         };
  33235 
  33236         if (align_ref != .none) {
  33237             gop.value_ptr.abi_align = sema.resolveAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {
  33238                 error.NeededSourceLocation => {
  33239                     const align_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
  33240                         .index = field_i,
  33241                         .range = .alignment,
  33242                     }).lazy;
  33243                     _ = try sema.resolveAlign(&block_scope, align_src, align_ref);
  33244                     unreachable;
  33245                 },
  33246                 else => |e| return e,
  33247             };
  33248         } else {
  33249             gop.value_ptr.abi_align = 0;
  33250         }
  33251     }
  33252 
  33253     if (explicit_enum_info) |tag_info| {
  33254         if (tag_info.names.len > fields_len) {
  33255             const msg = msg: {
  33256                 const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{});
  33257                 errdefer msg.destroy(sema.gpa);
  33258 
  33259                 const enum_ty = union_obj.tag_ty;
  33260                 for (tag_info.names, 0..) |field_name, field_index| {
  33261                     if (explicit_tags_seen[field_index]) continue;
  33262                     try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{
  33263                         mod.intern_pool.stringToSlice(field_name),
  33264                     });
  33265                 }
  33266                 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
  33267                 break :msg msg;
  33268             };
  33269             return sema.failWithOwnedErrorMsg(msg);
  33270         }
  33271     } else if (enum_field_vals.count() > 0) {
  33272         union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), union_obj);
  33273     } else {
  33274         union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_obj);
  33275     }
  33276 }
  33277 
  33278 fn semaUnionFieldVal(sema: *Sema, block: *Block, src: LazySrcLoc, int_tag_ty: Type, tag_ref: Air.Inst.Ref) CompileError!Value {
  33279     const coerced = try sema.coerce(block, int_tag_ty, tag_ref, src);
  33280     return sema.resolveConstValue(block, src, coerced, "enum tag value must be comptime-known");
  33281 }
  33282 
  33283 fn generateUnionTagTypeNumbered(
  33284     sema: *Sema,
  33285     block: *Block,
  33286     enum_field_names: []const InternPool.NullTerminatedString,
  33287     enum_field_vals: []const InternPool.Index,
  33288     union_obj: *Module.Union,
  33289 ) !Type {
  33290     const mod = sema.mod;
  33291 
  33292     const src_decl = mod.declPtr(block.src_decl);
  33293     const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
  33294     errdefer mod.destroyDecl(new_decl_index);
  33295     const name = name: {
  33296         const fqn = try union_obj.getFullyQualifiedName(mod);
  33297         defer sema.gpa.free(fqn);
  33298         break :name try std.fmt.allocPrintZ(sema.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn});
  33299     };
  33300     try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{
  33301         .ty = Type.type,
  33302         .val = undefined,
  33303     }, name);
  33304     errdefer mod.abortAnonDecl(new_decl_index);
  33305 
  33306     const new_decl = mod.declPtr(new_decl_index);
  33307     new_decl.name_fully_qualified = true;
  33308     new_decl.owns_tv = true;
  33309     new_decl.name_fully_qualified = true;
  33310 
  33311     const enum_ty = try mod.intern(.{ .enum_type = .{
  33312         .decl = new_decl_index,
  33313         .namespace = .none,
  33314         .tag_ty = if (enum_field_vals.len == 0)
  33315             (try mod.intType(.unsigned, 0)).toIntern()
  33316         else
  33317             mod.intern_pool.typeOf(enum_field_vals[0]),
  33318         .names = enum_field_names,
  33319         .values = enum_field_vals,
  33320         .tag_mode = .explicit,
  33321     } });
  33322 
  33323     new_decl.val = enum_ty.toValue();
  33324 
  33325     try mod.finalizeAnonDecl(new_decl_index);
  33326     return enum_ty.toType();
  33327 }
  33328 
  33329 fn generateUnionTagTypeSimple(
  33330     sema: *Sema,
  33331     block: *Block,
  33332     enum_field_names: []const InternPool.NullTerminatedString,
  33333     maybe_union_obj: ?*Module.Union,
  33334 ) !Type {
  33335     const mod = sema.mod;
  33336 
  33337     const new_decl_index = new_decl_index: {
  33338         const union_obj = maybe_union_obj orelse {
  33339             break :new_decl_index try mod.createAnonymousDecl(block, .{
  33340                 .ty = Type.type,
  33341                 .val = undefined,
  33342             });
  33343         };
  33344         const src_decl = mod.declPtr(block.src_decl);
  33345         const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
  33346         errdefer mod.destroyDecl(new_decl_index);
  33347         const name = name: {
  33348             const fqn = try union_obj.getFullyQualifiedName(mod);
  33349             defer sema.gpa.free(fqn);
  33350             break :name try std.fmt.allocPrintZ(sema.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn});
  33351         };
  33352         try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{
  33353             .ty = Type.type,
  33354             .val = undefined,
  33355         }, name);
  33356         mod.declPtr(new_decl_index).name_fully_qualified = true;
  33357         break :new_decl_index new_decl_index;
  33358     };
  33359     errdefer mod.abortAnonDecl(new_decl_index);
  33360 
  33361     const enum_ty = try mod.intern(.{ .enum_type = .{
  33362         .decl = new_decl_index,
  33363         .namespace = .none,
  33364         .tag_ty = if (enum_field_names.len == 0)
  33365             (try mod.intType(.unsigned, 0)).toIntern()
  33366         else
  33367             (try mod.smallestUnsignedInt(enum_field_names.len - 1)).toIntern(),
  33368         .names = enum_field_names,
  33369         .values = &.{},
  33370         .tag_mode = .auto,
  33371     } });
  33372 
  33373     const new_decl = mod.declPtr(new_decl_index);
  33374     new_decl.owns_tv = true;
  33375     new_decl.val = enum_ty.toValue();
  33376 
  33377     try mod.finalizeAnonDecl(new_decl_index);
  33378     return enum_ty.toType();
  33379 }
  33380 
  33381 fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
  33382     var wip_captures = try WipCaptureScope.init(sema.gpa, sema.owner_decl.src_scope);
  33383     defer wip_captures.deinit();
  33384 
  33385     var block: Block = .{
  33386         .parent = null,
  33387         .sema = sema,
  33388         .src_decl = sema.owner_decl_index,
  33389         .namespace = sema.owner_decl.src_namespace,
  33390         .wip_capture_scope = wip_captures.scope,
  33391         .instructions = .{},
  33392         .inlining = null,
  33393         .is_comptime = true,
  33394     };
  33395     defer {
  33396         block.instructions.deinit(sema.gpa);
  33397         block.params.deinit(sema.gpa);
  33398     }
  33399     const src = LazySrcLoc.nodeOffset(0);
  33400 
  33401     const mod = sema.mod;
  33402     const std_pkg = mod.main_pkg.table.get("std").?;
  33403     const std_file = (mod.importPkg(std_pkg) catch unreachable).file;
  33404     const opt_builtin_inst = (try sema.namespaceLookupRef(
  33405         &block,
  33406         src,
  33407         mod.declPtr(std_file.root_decl.unwrap().?).src_namespace,
  33408         "builtin",
  33409     )) orelse @panic("lib/std.zig is corrupt and missing 'builtin'");
  33410     const builtin_inst = try sema.analyzeLoad(&block, src, opt_builtin_inst, src);
  33411     const builtin_ty = sema.analyzeAsType(&block, src, builtin_inst) catch |err| switch (err) {
  33412         error.AnalysisFail => std.debug.panic("std.builtin is corrupt", .{}),
  33413         else => |e| return e,
  33414     };
  33415     const opt_ty_decl = (try sema.namespaceLookup(
  33416         &block,
  33417         src,
  33418         builtin_ty.getNamespaceIndex(mod).unwrap().?,
  33419         name,
  33420     )) orelse std.debug.panic("lib/std/builtin.zig is corrupt and missing '{s}'", .{name});
  33421     return sema.analyzeDeclVal(&block, src, opt_ty_decl);
  33422 }
  33423 
  33424 fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
  33425     const ty_inst = try sema.getBuiltin(name);
  33426 
  33427     var wip_captures = try WipCaptureScope.init(sema.gpa, sema.owner_decl.src_scope);
  33428     defer wip_captures.deinit();
  33429 
  33430     var block: Block = .{
  33431         .parent = null,
  33432         .sema = sema,
  33433         .src_decl = sema.owner_decl_index,
  33434         .namespace = sema.owner_decl.src_namespace,
  33435         .wip_capture_scope = wip_captures.scope,
  33436         .instructions = .{},
  33437         .inlining = null,
  33438         .is_comptime = true,
  33439     };
  33440     defer {
  33441         block.instructions.deinit(sema.gpa);
  33442         block.params.deinit(sema.gpa);
  33443     }
  33444     const src = LazySrcLoc.nodeOffset(0);
  33445 
  33446     const result_ty = sema.analyzeAsType(&block, src, ty_inst) catch |err| switch (err) {
  33447         error.AnalysisFail => std.debug.panic("std.builtin.{s} is corrupt", .{name}),
  33448         else => |e| return e,
  33449     };
  33450     try sema.resolveTypeFully(result_ty); // Should not fail
  33451     return result_ty;
  33452 }
  33453 
  33454 /// There is another implementation of this in `Type.onePossibleValue`. This one
  33455 /// in `Sema` is for calling during semantic analysis, and performs field resolution
  33456 /// to get the answer. The one in `Type` is for calling during codegen and asserts
  33457 /// that the types are already resolved.
  33458 /// TODO assert the return value matches `ty.onePossibleValue`
  33459 pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
  33460     const mod = sema.mod;
  33461     return switch (ty.toIntern()) {
  33462         .empty_struct_type => Value.empty_struct,
  33463         else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
  33464             .int_type => |int_type| {
  33465                 if (int_type.bits == 0) {
  33466                     return try mod.intValue(ty, 0);
  33467                 } else {
  33468                     return null;
  33469                 }
  33470             },
  33471 
  33472             .ptr_type,
  33473             .error_union_type,
  33474             .func_type,
  33475             .anyframe_type,
  33476             .error_set_type,
  33477             .inferred_error_set_type,
  33478             => null,
  33479 
  33480             inline .array_type, .vector_type => |seq_type, seq_tag| {
  33481                 const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none;
  33482                 if (seq_type.len + @boolToInt(has_sentinel) == 0) return (try mod.intern(.{ .aggregate = .{
  33483                     .ty = ty.toIntern(),
  33484                     .storage = .{ .elems = &.{} },
  33485                 } })).toValue();
  33486 
  33487                 if (try sema.typeHasOnePossibleValue(seq_type.child.toType())) |opv| {
  33488                     return (try mod.intern(.{ .aggregate = .{
  33489                         .ty = ty.toIntern(),
  33490                         .storage = .{ .repeated_elem = opv.toIntern() },
  33491                     } })).toValue();
  33492                 }
  33493                 return null;
  33494             },
  33495             .opt_type => |child| {
  33496                 if (child == .noreturn_type) {
  33497                     return try mod.nullValue(ty);
  33498                 } else {
  33499                     return null;
  33500                 }
  33501             },
  33502 
  33503             .simple_type => |t| switch (t) {
  33504                 .f16,
  33505                 .f32,
  33506                 .f64,
  33507                 .f80,
  33508                 .f128,
  33509                 .usize,
  33510                 .isize,
  33511                 .c_char,
  33512                 .c_short,
  33513                 .c_ushort,
  33514                 .c_int,
  33515                 .c_uint,
  33516                 .c_long,
  33517                 .c_ulong,
  33518                 .c_longlong,
  33519                 .c_ulonglong,
  33520                 .c_longdouble,
  33521                 .anyopaque,
  33522                 .bool,
  33523                 .type,
  33524                 .anyerror,
  33525                 .comptime_int,
  33526                 .comptime_float,
  33527                 .enum_literal,
  33528                 .atomic_order,
  33529                 .atomic_rmw_op,
  33530                 .calling_convention,
  33531                 .address_space,
  33532                 .float_mode,
  33533                 .reduce_op,
  33534                 .call_modifier,
  33535                 .prefetch_options,
  33536                 .export_options,
  33537                 .extern_options,
  33538                 .type_info,
  33539                 => null,
  33540 
  33541                 .void => Value.void,
  33542                 .noreturn => Value.@"unreachable",
  33543                 .null => Value.null,
  33544                 .undefined => Value.undef,
  33545 
  33546                 .generic_poison => return error.GenericPoison,
  33547             },
  33548             .struct_type => |struct_type| {
  33549                 const resolved_ty = try sema.resolveTypeFields(ty);
  33550                 if (mod.structPtrUnwrap(struct_type.index)) |s| {
  33551                     const field_vals = try sema.arena.alloc(InternPool.Index, s.fields.count());
  33552                     for (field_vals, s.fields.values(), 0..) |*field_val, field, i| {
  33553                         if (field.is_comptime) {
  33554                             field_val.* = try field.default_val.intern(field.ty, mod);
  33555                             continue;
  33556                         }
  33557                         if (field.ty.eql(resolved_ty, sema.mod)) {
  33558                             const msg = try Module.ErrorMsg.create(
  33559                                 sema.gpa,
  33560                                 s.srcLoc(sema.mod),
  33561                                 "struct '{}' depends on itself",
  33562                                 .{ty.fmt(sema.mod)},
  33563                             );
  33564                             try sema.addFieldErrNote(resolved_ty, i, msg, "while checking this field", .{});
  33565                             return sema.failWithOwnedErrorMsg(msg);
  33566                         }
  33567                         if (try sema.typeHasOnePossibleValue(field.ty)) |field_opv| {
  33568                             field_val.* = try field_opv.intern(field.ty, mod);
  33569                         } else return null;
  33570                     }
  33571 
  33572                     // In this case the struct has no runtime-known fields and
  33573                     // therefore has one possible value.
  33574                     return (try mod.intern(.{ .aggregate = .{
  33575                         .ty = ty.toIntern(),
  33576                         .storage = .{ .elems = field_vals },
  33577                     } })).toValue();
  33578                 }
  33579 
  33580                 // In this case the struct has no fields at all and
  33581                 // therefore has one possible value.
  33582                 return (try mod.intern(.{ .aggregate = .{
  33583                     .ty = ty.toIntern(),
  33584                     .storage = .{ .elems = &.{} },
  33585                 } })).toValue();
  33586             },
  33587 
  33588             .anon_struct_type => |tuple| {
  33589                 for (tuple.values) |val| {
  33590                     if (val == .none) return null;
  33591                 }
  33592                 // In this case the struct has all comptime-known fields and
  33593                 // therefore has one possible value.
  33594                 return (try mod.intern(.{ .aggregate = .{
  33595                     .ty = ty.toIntern(),
  33596                     .storage = .{ .elems = tuple.values },
  33597                 } })).toValue();
  33598             },
  33599 
  33600             .union_type => |union_type| {
  33601                 const resolved_ty = try sema.resolveTypeFields(ty);
  33602                 const union_obj = mod.unionPtr(union_type.index);
  33603                 const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse
  33604                     return null;
  33605                 const fields = union_obj.fields.values();
  33606                 if (fields.len == 0) {
  33607                     const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
  33608                     return only.toValue();
  33609                 }
  33610                 const only_field = fields[0];
  33611                 if (only_field.ty.eql(resolved_ty, sema.mod)) {
  33612                     const msg = try Module.ErrorMsg.create(
  33613                         sema.gpa,
  33614                         union_obj.srcLoc(sema.mod),
  33615                         "union '{}' depends on itself",
  33616                         .{ty.fmt(sema.mod)},
  33617                     );
  33618                     try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{});
  33619                     return sema.failWithOwnedErrorMsg(msg);
  33620                 }
  33621                 const val_val = (try sema.typeHasOnePossibleValue(only_field.ty)) orelse
  33622                     return null;
  33623                 const only = try mod.intern(.{ .un = .{
  33624                     .ty = resolved_ty.toIntern(),
  33625                     .tag = tag_val.toIntern(),
  33626                     .val = val_val.toIntern(),
  33627                 } });
  33628                 return only.toValue();
  33629             },
  33630             .opaque_type => null,
  33631             .enum_type => |enum_type| switch (enum_type.tag_mode) {
  33632                 .nonexhaustive => {
  33633                     if (enum_type.tag_ty == .comptime_int_type) return null;
  33634 
  33635                     if (try sema.typeHasOnePossibleValue(enum_type.tag_ty.toType())) |int_opv| {
  33636                         const only = try mod.intern(.{ .enum_tag = .{
  33637                             .ty = ty.toIntern(),
  33638                             .int = int_opv.toIntern(),
  33639                         } });
  33640                         return only.toValue();
  33641                     }
  33642 
  33643                     return null;
  33644                 },
  33645                 .auto, .explicit => {
  33646                     if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null;
  33647 
  33648                     switch (enum_type.names.len) {
  33649                         0 => {
  33650                             const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
  33651                             return only.toValue();
  33652                         },
  33653                         1 => return try mod.getCoerced((if (enum_type.values.len == 0)
  33654                             try mod.intern(.{ .int = .{
  33655                                 .ty = enum_type.tag_ty,
  33656                                 .storage = .{ .u64 = 0 },
  33657                             } })
  33658                         else
  33659                             enum_type.values[0]).toValue(), ty),
  33660                         else => return null,
  33661                     }
  33662                 },
  33663             },
  33664 
  33665             // values, not types
  33666             .undef,
  33667             .runtime_value,
  33668             .simple_value,
  33669             .variable,
  33670             .extern_func,
  33671             .func,
  33672             .int,
  33673             .err,
  33674             .error_union,
  33675             .enum_literal,
  33676             .enum_tag,
  33677             .empty_enum_value,
  33678             .float,
  33679             .ptr,
  33680             .opt,
  33681             .aggregate,
  33682             .un,
  33683             // memoization, not types
  33684             .memoized_call,
  33685             => unreachable,
  33686         },
  33687     };
  33688 }
  33689 
  33690 /// Returns the type of the AIR instruction.
  33691 fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type {
  33692     return sema.getTmpAir().typeOf(inst, &sema.mod.intern_pool);
  33693 }
  33694 
  33695 pub fn getTmpAir(sema: Sema) Air {
  33696     return .{
  33697         .instructions = sema.air_instructions.slice(),
  33698         .extra = sema.air_extra.items,
  33699     };
  33700 }
  33701 
  33702 pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
  33703     if (@enumToInt(ty.toIntern()) < Air.ref_start_index)
  33704         return @intToEnum(Air.Inst.Ref, @enumToInt(ty.toIntern()));
  33705     try sema.air_instructions.append(sema.gpa, .{
  33706         .tag = .interned,
  33707         .data = .{ .interned = ty.toIntern() },
  33708     });
  33709     return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
  33710 }
  33711 
  33712 fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref {
  33713     const mod = sema.mod;
  33714     return sema.addConstant(ty, try mod.intValue(ty, int));
  33715 }
  33716 
  33717 fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {
  33718     return sema.addConstant(ty, (try sema.mod.intern(.{ .undef = ty.toIntern() })).toValue());
  33719 }
  33720 
  33721 pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref {
  33722     const mod = sema.mod;
  33723     const gpa = sema.gpa;
  33724 
  33725     // This assertion can be removed when the `ty` parameter is removed from
  33726     // this function thanks to the InternPool transition being complete.
  33727     if (std.debug.runtime_safety) {
  33728         const val_ty = mod.intern_pool.typeOf(val.toIntern());
  33729         if (ty.toIntern() != val_ty) {
  33730             std.debug.panic("addConstant type mismatch: '{}' vs '{}'\n", .{
  33731                 ty.fmt(mod), val_ty.toType().fmt(mod),
  33732             });
  33733         }
  33734     }
  33735     if (@enumToInt(val.toIntern()) < Air.ref_start_index)
  33736         return @intToEnum(Air.Inst.Ref, @enumToInt(val.toIntern()));
  33737     try sema.air_instructions.append(gpa, .{
  33738         .tag = .interned,
  33739         .data = .{ .interned = val.toIntern() },
  33740     });
  33741     return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
  33742 }
  33743 
  33744 pub fn addExtra(sema: *Sema, extra: anytype) Allocator.Error!u32 {
  33745     const fields = std.meta.fields(@TypeOf(extra));
  33746     try sema.air_extra.ensureUnusedCapacity(sema.gpa, fields.len);
  33747     return sema.addExtraAssumeCapacity(extra);
  33748 }
  33749 
  33750 pub fn addExtraAssumeCapacity(sema: *Sema, extra: anytype) u32 {
  33751     const fields = std.meta.fields(@TypeOf(extra));
  33752     const result = @intCast(u32, sema.air_extra.items.len);
  33753     inline for (fields) |field| {
  33754         sema.air_extra.appendAssumeCapacity(switch (field.type) {
  33755             u32 => @field(extra, field.name),
  33756             Air.Inst.Ref => @enumToInt(@field(extra, field.name)),
  33757             i32 => @bitCast(u32, @field(extra, field.name)),
  33758             InternPool.Index => @enumToInt(@field(extra, field.name)),
  33759             else => @compileError("bad field type: " ++ @typeName(field.type)),
  33760         });
  33761     }
  33762     return result;
  33763 }
  33764 
  33765 fn appendRefsAssumeCapacity(sema: *Sema, refs: []const Air.Inst.Ref) void {
  33766     const coerced = @ptrCast([]const u32, refs);
  33767     sema.air_extra.appendSliceAssumeCapacity(coerced);
  33768 }
  33769 
  33770 fn getBreakBlock(sema: *Sema, inst_index: Air.Inst.Index) ?Air.Inst.Index {
  33771     const air_datas = sema.air_instructions.items(.data);
  33772     const air_tags = sema.air_instructions.items(.tag);
  33773     switch (air_tags[inst_index]) {
  33774         .br => return air_datas[inst_index].br.block_inst,
  33775         else => return null,
  33776     }
  33777 }
  33778 
  33779 fn isComptimeKnown(
  33780     sema: *Sema,
  33781     inst: Air.Inst.Ref,
  33782 ) !bool {
  33783     return (try sema.resolveMaybeUndefVal(inst)) != null;
  33784 }
  33785 
  33786 fn analyzeComptimeAlloc(
  33787     sema: *Sema,
  33788     block: *Block,
  33789     var_type: Type,
  33790     alignment: u32,
  33791 ) CompileError!Air.Inst.Ref {
  33792     // Needed to make an anon decl with type `var_type` (the `finish()` call below).
  33793     _ = try sema.typeHasOnePossibleValue(var_type);
  33794 
  33795     const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
  33796         .pointee_type = var_type,
  33797         .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant),
  33798         .@"align" = alignment,
  33799     });
  33800 
  33801     var anon_decl = try block.startAnonDecl();
  33802     defer anon_decl.deinit();
  33803 
  33804     const decl_index = try anon_decl.finish(
  33805         var_type,
  33806         // There will be stores before the first load, but they may be to sub-elements or
  33807         // sub-fields. So we need to initialize with undef to allow the mechanism to expand
  33808         // into fields/elements and have those overridden with stored values.
  33809         (try sema.mod.intern(.{ .undef = var_type.toIntern() })).toValue(),
  33810         alignment,
  33811     );
  33812     const decl = sema.mod.declPtr(decl_index);
  33813     decl.@"align" = alignment;
  33814 
  33815     try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index);
  33816     return sema.addConstant(ptr_type, (try sema.mod.intern(.{ .ptr = .{
  33817         .ty = ptr_type.toIntern(),
  33818         .addr = .{ .mut_decl = .{
  33819             .decl = decl_index,
  33820             .runtime_index = block.runtime_index,
  33821         } },
  33822     } })).toValue());
  33823 }
  33824 
  33825 /// The places where a user can specify an address space attribute
  33826 pub const AddressSpaceContext = enum {
  33827     /// A function is specified to be placed in a certain address space.
  33828     function,
  33829 
  33830     /// A (global) variable is specified to be placed in a certain address space.
  33831     /// In contrast to .constant, these values (and thus the address space they will be
  33832     /// placed in) are required to be mutable.
  33833     variable,
  33834 
  33835     /// A (global) constant value is specified to be placed in a certain address space.
  33836     /// In contrast to .variable, values placed in this address space are not required to be mutable.
  33837     constant,
  33838 
  33839     /// A pointer is ascripted to point into a certain address space.
  33840     pointer,
  33841 };
  33842 
  33843 pub fn analyzeAddressSpace(
  33844     sema: *Sema,
  33845     block: *Block,
  33846     src: LazySrcLoc,
  33847     zir_ref: Zir.Inst.Ref,
  33848     ctx: AddressSpaceContext,
  33849 ) !std.builtin.AddressSpace {
  33850     const mod = sema.mod;
  33851     const addrspace_tv = try sema.resolveInstConst(block, src, zir_ref, "addresspace must be comptime-known");
  33852     const address_space = mod.toEnum(std.builtin.AddressSpace, addrspace_tv.val);
  33853     const target = sema.mod.getTarget();
  33854     const arch = target.cpu.arch;
  33855 
  33856     const is_nv = arch == .nvptx or arch == .nvptx64;
  33857     const is_amd = arch == .amdgcn;
  33858     const is_spirv = arch == .spirv32 or arch == .spirv64;
  33859     const is_gpu = is_nv or is_amd or is_spirv;
  33860 
  33861     const supported = switch (address_space) {
  33862         // TODO: on spir-v only when os is opencl.
  33863         .generic => true,
  33864         .gs, .fs, .ss => (arch == .x86 or arch == .x86_64) and ctx == .pointer,
  33865         // TODO: check that .shared and .local are left uninitialized
  33866         .param => is_nv,
  33867         .global, .shared, .local => is_gpu,
  33868         .constant => is_gpu and (ctx == .constant),
  33869         // TODO this should also check how many flash banks the cpu has
  33870         .flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr,
  33871     };
  33872 
  33873     if (!supported) {
  33874         // TODO error messages could be made more elaborate here
  33875         const entity = switch (ctx) {
  33876             .function => "functions",
  33877             .variable => "mutable values",
  33878             .constant => "constant values",
  33879             .pointer => "pointers",
  33880         };
  33881         return sema.fail(
  33882             block,
  33883             src,
  33884             "{s} with address space '{s}' are not supported on {s}",
  33885             .{ entity, @tagName(address_space), arch.genericName() },
  33886         );
  33887     }
  33888 
  33889     return address_space;
  33890 }
  33891 
  33892 /// Asserts the value is a pointer and dereferences it.
  33893 /// Returns `null` if the pointer contents cannot be loaded at comptime.
  33894 fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value {
  33895     const mod = sema.mod;
  33896     const load_ty = ptr_ty.childType(mod);
  33897     const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty);
  33898     switch (res) {
  33899         .runtime_load => return null,
  33900         .val => |v| return v,
  33901         .needed_well_defined => |ty| return sema.fail(
  33902             block,
  33903             src,
  33904             "comptime dereference requires '{}' to have a well-defined layout, but it does not.",
  33905             .{ty.fmt(sema.mod)},
  33906         ),
  33907         .out_of_bounds => |ty| return sema.fail(
  33908             block,
  33909             src,
  33910             "dereference of '{}' exceeds bounds of containing decl of type '{}'",
  33911             .{ ptr_ty.fmt(sema.mod), ty.fmt(sema.mod) },
  33912         ),
  33913     }
  33914 }
  33915 
  33916 const DerefResult = union(enum) {
  33917     runtime_load,
  33918     val: Value,
  33919     needed_well_defined: Type,
  33920     out_of_bounds: Type,
  33921 };
  33922 
  33923 fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type) CompileError!DerefResult {
  33924     const mod = sema.mod;
  33925     const target = mod.getTarget();
  33926     const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) {
  33927         error.RuntimeLoad => return DerefResult{ .runtime_load = {} },
  33928         else => |e| return e,
  33929     };
  33930 
  33931     if (deref.pointee) |tv| {
  33932         const coerce_in_mem_ok =
  33933             (try sema.coerceInMemoryAllowed(block, load_ty, tv.ty, false, target, src, src)) == .ok or
  33934             (try sema.coerceInMemoryAllowed(block, tv.ty, load_ty, false, target, src, src)) == .ok;
  33935         if (coerce_in_mem_ok) {
  33936             // We have a Value that lines up in virtual memory exactly with what we want to load,
  33937             // and it is in-memory coercible to load_ty. It may be returned without modifications.
  33938             // Move mutable decl values to the InternPool and assert other decls are already in the InternPool.
  33939             return .{ .val = (if (deref.is_mutable) try tv.val.intern(tv.ty, mod) else tv.val.toIntern()).toValue() };
  33940         }
  33941     }
  33942 
  33943     // The type is not in-memory coercible or the direct dereference failed, so it must
  33944     // be bitcast according to the pointer type we are performing the load through.
  33945     if (!load_ty.hasWellDefinedLayout(mod)) {
  33946         return DerefResult{ .needed_well_defined = load_ty };
  33947     }
  33948 
  33949     const load_sz = try sema.typeAbiSize(load_ty);
  33950 
  33951     // Try the smaller bit-cast first, since that's more efficient than using the larger `parent`
  33952     if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(tv.ty))
  33953         return DerefResult{ .val = (try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0)) orelse return .runtime_load };
  33954 
  33955     // If that fails, try to bit-cast from the largest parent value with a well-defined layout
  33956     if (deref.parent) |parent| if (load_sz + parent.byte_offset <= try sema.typeAbiSize(parent.tv.ty))
  33957         return DerefResult{ .val = (try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset)) orelse return .runtime_load };
  33958 
  33959     if (deref.ty_without_well_defined_layout) |bad_ty| {
  33960         // We got no parent for bit-casting, or the parent we got was too small. Either way, the problem
  33961         // is that some type we encountered when de-referencing does not have a well-defined layout.
  33962         return DerefResult{ .needed_well_defined = bad_ty };
  33963     } else {
  33964         // If all encountered types had well-defined layouts, the parent is the root decl and it just
  33965         // wasn't big enough for the load.
  33966         return DerefResult{ .out_of_bounds = deref.parent.?.tv.ty };
  33967     }
  33968 }
  33969 
  33970 /// Used to convert a u64 value to a usize value, emitting a compile error if the number
  33971 /// is too big to fit.
  33972 fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError!usize {
  33973     if (@bitSizeOf(u64) <= @bitSizeOf(usize)) return int;
  33974     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});
  33975 }
  33976 
  33977 /// For pointer-like optionals, it returns the pointer type. For pointers,
  33978 /// the type is returned unmodified.
  33979 /// This can return `error.AnalysisFail` because it sometimes requires resolving whether
  33980 /// a type has zero bits, which can cause a "foo depends on itself" compile error.
  33981 /// This logic must be kept in sync with `Type.isPtrLikeOptional`.
  33982 fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type {
  33983     const mod = sema.mod;
  33984     return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
  33985         .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
  33986             .One, .Many, .C => ty,
  33987             .Slice => null,
  33988         },
  33989         .opt_type => |opt_child| switch (mod.intern_pool.indexToKey(opt_child)) {
  33990             .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
  33991                 .Slice, .C => null,
  33992                 .Many, .One => {
  33993                     if (ptr_type.flags.is_allowzero) return null;
  33994 
  33995                     // optionals of zero sized types behave like bools, not pointers
  33996                     const payload_ty = opt_child.toType();
  33997                     if ((try sema.typeHasOnePossibleValue(payload_ty)) != null) {
  33998                         return null;
  33999                     }
  34000 
  34001                     return payload_ty;
  34002                 },
  34003             },
  34004             else => null,
  34005         },
  34006         else => null,
  34007     };
  34008 }
  34009 
  34010 /// `generic_poison` will return false.
  34011 /// This function returns false negatives when structs and unions are having their
  34012 /// field types resolved.
  34013 /// TODO assert the return value matches `ty.comptimeOnly`
  34014 /// TODO merge these implementations together with the "advanced"/opt_sema pattern seen
  34015 /// elsewhere in value.zig
  34016 pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
  34017     const mod = sema.mod;
  34018     return switch (ty.toIntern()) {
  34019         .empty_struct_type => false,
  34020 
  34021         else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
  34022             .int_type => return false,
  34023             .ptr_type => |ptr_type| {
  34024                 const child_ty = ptr_type.child.toType();
  34025                 if (child_ty.zigTypeTag(mod) == .Fn) {
  34026                     return mod.typeToFunc(child_ty).?.is_generic;
  34027                 } else {
  34028                     return sema.typeRequiresComptime(child_ty);
  34029                 }
  34030             },
  34031             .anyframe_type => |child| {
  34032                 if (child == .none) return false;
  34033                 return sema.typeRequiresComptime(child.toType());
  34034             },
  34035             .array_type => |array_type| return sema.typeRequiresComptime(array_type.child.toType()),
  34036             .vector_type => |vector_type| return sema.typeRequiresComptime(vector_type.child.toType()),
  34037             .opt_type => |child| return sema.typeRequiresComptime(child.toType()),
  34038 
  34039             .error_union_type => |error_union_type| {
  34040                 return sema.typeRequiresComptime(error_union_type.payload_type.toType());
  34041             },
  34042 
  34043             .error_set_type, .inferred_error_set_type => false,
  34044 
  34045             .func_type => true,
  34046 
  34047             .simple_type => |t| return switch (t) {
  34048                 .f16,
  34049                 .f32,
  34050                 .f64,
  34051                 .f80,
  34052                 .f128,
  34053                 .usize,
  34054                 .isize,
  34055                 .c_char,
  34056                 .c_short,
  34057                 .c_ushort,
  34058                 .c_int,
  34059                 .c_uint,
  34060                 .c_long,
  34061                 .c_ulong,
  34062                 .c_longlong,
  34063                 .c_ulonglong,
  34064                 .c_longdouble,
  34065                 .anyopaque,
  34066                 .bool,
  34067                 .void,
  34068                 .anyerror,
  34069                 .noreturn,
  34070                 .generic_poison,
  34071                 .atomic_order,
  34072                 .atomic_rmw_op,
  34073                 .calling_convention,
  34074                 .address_space,
  34075                 .float_mode,
  34076                 .reduce_op,
  34077                 .call_modifier,
  34078                 .prefetch_options,
  34079                 .export_options,
  34080                 .extern_options,
  34081                 => false,
  34082 
  34083                 .type,
  34084                 .comptime_int,
  34085                 .comptime_float,
  34086                 .null,
  34087                 .undefined,
  34088                 .enum_literal,
  34089                 .type_info,
  34090                 => true,
  34091             },
  34092             .struct_type => |struct_type| {
  34093                 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;
  34094                 switch (struct_obj.requires_comptime) {
  34095                     .no, .wip => return false,
  34096                     .yes => return true,
  34097                     .unknown => {
  34098                         if (struct_obj.status == .field_types_wip)
  34099                             return false;
  34100 
  34101                         try sema.resolveTypeFieldsStruct(ty, struct_obj);
  34102 
  34103                         struct_obj.requires_comptime = .wip;
  34104                         for (struct_obj.fields.values()) |field| {
  34105                             if (field.is_comptime) continue;
  34106                             if (try sema.typeRequiresComptime(field.ty)) {
  34107                                 struct_obj.requires_comptime = .yes;
  34108                                 return true;
  34109                             }
  34110                         }
  34111                         struct_obj.requires_comptime = .no;
  34112                         return false;
  34113                     },
  34114                 }
  34115             },
  34116             .anon_struct_type => |tuple| {
  34117                 for (tuple.types, tuple.values) |field_ty, val| {
  34118                     const have_comptime_val = val != .none;
  34119                     if (!have_comptime_val and try sema.typeRequiresComptime(field_ty.toType())) {
  34120                         return true;
  34121                     }
  34122                 }
  34123                 return false;
  34124             },
  34125 
  34126             .union_type => |union_type| {
  34127                 const union_obj = mod.unionPtr(union_type.index);
  34128                 switch (union_obj.requires_comptime) {
  34129                     .no, .wip => return false,
  34130                     .yes => return true,
  34131                     .unknown => {
  34132                         if (union_obj.status == .field_types_wip)
  34133                             return false;
  34134 
  34135                         try sema.resolveTypeFieldsUnion(ty, union_obj);
  34136 
  34137                         union_obj.requires_comptime = .wip;
  34138                         for (union_obj.fields.values()) |field| {
  34139                             if (try sema.typeRequiresComptime(field.ty)) {
  34140                                 union_obj.requires_comptime = .yes;
  34141                                 return true;
  34142                             }
  34143                         }
  34144                         union_obj.requires_comptime = .no;
  34145                         return false;
  34146                     },
  34147                 }
  34148             },
  34149 
  34150             .opaque_type => false,
  34151             .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()),
  34152 
  34153             // values, not types
  34154             .undef,
  34155             .runtime_value,
  34156             .simple_value,
  34157             .variable,
  34158             .extern_func,
  34159             .func,
  34160             .int,
  34161             .err,
  34162             .error_union,
  34163             .enum_literal,
  34164             .enum_tag,
  34165             .empty_enum_value,
  34166             .float,
  34167             .ptr,
  34168             .opt,
  34169             .aggregate,
  34170             .un,
  34171             // memoization, not types
  34172             .memoized_call,
  34173             => unreachable,
  34174         },
  34175     };
  34176 }
  34177 
  34178 pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
  34179     const mod = sema.mod;
  34180     return ty.hasRuntimeBitsAdvanced(mod, false, .{ .sema = sema }) catch |err| switch (err) {
  34181         error.NeedLazy => unreachable,
  34182         else => |e| return e,
  34183     };
  34184 }
  34185 
  34186 fn typeAbiSize(sema: *Sema, ty: Type) !u64 {
  34187     try sema.resolveTypeLayout(ty);
  34188     return ty.abiSize(sema.mod);
  34189 }
  34190 
  34191 fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!u32 {
  34192     return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar;
  34193 }
  34194 
  34195 /// Not valid to call for packed unions.
  34196 /// Keep implementation in sync with `Module.Union.Field.normalAlignment`.
  34197 fn unionFieldAlignment(sema: *Sema, field: Module.Union.Field) !u32 {
  34198     const mod = sema.mod;
  34199     if (field.ty.zigTypeTag(mod) == .NoReturn) {
  34200         return @as(u32, 0);
  34201     } else if (field.abi_align == 0) {
  34202         return sema.typeAbiAlignment(field.ty);
  34203     } else {
  34204         return field.abi_align;
  34205     }
  34206 }
  34207 
  34208 /// Synchronize logic with `Type.isFnOrHasRuntimeBits`.
  34209 pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
  34210     const mod = sema.mod;
  34211     const fn_info = mod.typeToFunc(ty).?;
  34212     if (fn_info.is_generic) return false;
  34213     if (fn_info.is_var_args) return true;
  34214     switch (fn_info.cc) {
  34215         // If there was a comptime calling convention, it should also return false here.
  34216         .Inline => return false,
  34217         else => {},
  34218     }
  34219     if (try sema.typeRequiresComptime(fn_info.return_type.toType())) {
  34220         return false;
  34221     }
  34222     return true;
  34223 }
  34224 
  34225 fn unionFieldIndex(
  34226     sema: *Sema,
  34227     block: *Block,
  34228     unresolved_union_ty: Type,
  34229     field_name: []const u8,
  34230     field_src: LazySrcLoc,
  34231 ) !u32 {
  34232     const mod = sema.mod;
  34233     const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
  34234     const union_obj = mod.typeToUnion(union_ty).?;
  34235     const field_index_usize = union_obj.fields.getIndex(field_name) orelse
  34236         return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
  34237     return @intCast(u32, field_index_usize);
  34238 }
  34239 
  34240 fn structFieldIndex(
  34241     sema: *Sema,
  34242     block: *Block,
  34243     unresolved_struct_ty: Type,
  34244     field_name: []const u8,
  34245     field_src: LazySrcLoc,
  34246 ) !u32 {
  34247     const mod = sema.mod;
  34248     const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty);
  34249     if (struct_ty.isAnonStruct(mod)) {
  34250         return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src);
  34251     } else {
  34252         const struct_obj = mod.typeToStruct(struct_ty).?;
  34253         const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
  34254             return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
  34255         return @intCast(u32, field_index_usize);
  34256     }
  34257 }
  34258 
  34259 fn anonStructFieldIndex(
  34260     sema: *Sema,
  34261     block: *Block,
  34262     struct_ty: Type,
  34263     field_name: []const u8,
  34264     field_src: LazySrcLoc,
  34265 ) !u32 {
  34266     const mod = sema.mod;
  34267     switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) {
  34268         .anon_struct_type => |anon_struct_type| for (anon_struct_type.names, 0..) |name, i| {
  34269             if (mem.eql(u8, mod.intern_pool.stringToSlice(name), field_name)) {
  34270                 return @intCast(u32, i);
  34271             }
  34272         },
  34273         .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| {
  34274             for (struct_obj.fields.keys(), 0..) |name, i| {
  34275                 if (mem.eql(u8, name, field_name)) {
  34276                     return @intCast(u32, i);
  34277                 }
  34278             }
  34279         },
  34280         else => unreachable,
  34281     }
  34282     return sema.fail(block, field_src, "no field named '{s}' in anonymous struct '{}'", .{
  34283         field_name, struct_ty.fmt(sema.mod),
  34284     });
  34285 }
  34286 
  34287 fn queueFullTypeResolution(sema: *Sema, ty: Type) !void {
  34288     try sema.types_to_resolve.put(sema.gpa, ty.toIntern(), {});
  34289 }
  34290 
  34291 fn intAdd(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value {
  34292     const mod = sema.mod;
  34293     if (ty.zigTypeTag(mod) == .Vector) {
  34294         const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod));
  34295         const scalar_ty = ty.scalarType(mod);
  34296         for (result_data, 0..) |*scalar, i| {
  34297             const lhs_elem = try lhs.elemValue(mod, i);
  34298             const rhs_elem = try rhs.elemValue(mod, i);
  34299             scalar.* = try (try sema.intAddScalar(lhs_elem, rhs_elem, scalar_ty)).intern(scalar_ty, mod);
  34300         }
  34301         return (try mod.intern(.{ .aggregate = .{
  34302             .ty = ty.toIntern(),
  34303             .storage = .{ .elems = result_data },
  34304         } })).toValue();
  34305     }
  34306     return sema.intAddScalar(lhs, rhs, ty);
  34307 }
  34308 
  34309 fn intAddScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) !Value {
  34310     const mod = sema.mod;
  34311     // TODO is this a performance issue? maybe we should try the operation without
  34312     // resorting to BigInt first.
  34313     var lhs_space: Value.BigIntSpace = undefined;
  34314     var rhs_space: Value.BigIntSpace = undefined;
  34315     const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
  34316     const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
  34317     const limbs = try sema.arena.alloc(
  34318         std.math.big.Limb,
  34319         std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
  34320     );
  34321     var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
  34322     result_bigint.add(lhs_bigint, rhs_bigint);
  34323     if (scalar_ty.toIntern() != .comptime_int_type) {
  34324         const int_info = scalar_ty.intInfo(mod);
  34325         result_bigint.truncate(result_bigint.toConst(), int_info.signedness, int_info.bits);
  34326     }
  34327     return mod.intValue_big(scalar_ty, result_bigint.toConst());
  34328 }
  34329 
  34330 /// Supports both floats and ints; handles undefined.
  34331 fn numberAddWrapScalar(
  34332     sema: *Sema,
  34333     lhs: Value,
  34334     rhs: Value,
  34335     ty: Type,
  34336 ) !Value {
  34337     const mod = sema.mod;
  34338     if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.undef;
  34339 
  34340     if (ty.zigTypeTag(mod) == .ComptimeInt) {
  34341         return sema.intAdd(lhs, rhs, ty);
  34342     }
  34343 
  34344     if (ty.isAnyFloat()) {
  34345         return Value.floatAdd(lhs, rhs, ty, sema.arena, mod);
  34346     }
  34347 
  34348     const overflow_result = try sema.intAddWithOverflow(lhs, rhs, ty);
  34349     return overflow_result.wrapped_result;
  34350 }
  34351 
  34352 fn intSub(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value {
  34353     const mod = sema.mod;
  34354     if (ty.zigTypeTag(mod) == .Vector) {
  34355         const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod));
  34356         const scalar_ty = ty.scalarType(mod);
  34357         for (result_data, 0..) |*scalar, i| {
  34358             const lhs_elem = try lhs.elemValue(sema.mod, i);
  34359             const rhs_elem = try rhs.elemValue(sema.mod, i);
  34360             scalar.* = try (try sema.intSubScalar(lhs_elem, rhs_elem, scalar_ty)).intern(scalar_ty, mod);
  34361         }
  34362         return (try mod.intern(.{ .aggregate = .{
  34363             .ty = ty.toIntern(),
  34364             .storage = .{ .elems = result_data },
  34365         } })).toValue();
  34366     }
  34367     return sema.intSubScalar(lhs, rhs, ty);
  34368 }
  34369 
  34370 fn intSubScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) !Value {
  34371     const mod = sema.mod;
  34372     // TODO is this a performance issue? maybe we should try the operation without
  34373     // resorting to BigInt first.
  34374     var lhs_space: Value.BigIntSpace = undefined;
  34375     var rhs_space: Value.BigIntSpace = undefined;
  34376     const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
  34377     const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
  34378     const limbs = try sema.arena.alloc(
  34379         std.math.big.Limb,
  34380         std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
  34381     );
  34382     var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
  34383     result_bigint.sub(lhs_bigint, rhs_bigint);
  34384     return mod.intValue_big(scalar_ty, result_bigint.toConst());
  34385 }
  34386 
  34387 /// Supports both floats and ints; handles undefined.
  34388 fn numberSubWrapScalar(
  34389     sema: *Sema,
  34390     lhs: Value,
  34391     rhs: Value,
  34392     ty: Type,
  34393 ) !Value {
  34394     const mod = sema.mod;
  34395     if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.undef;
  34396 
  34397     if (ty.zigTypeTag(mod) == .ComptimeInt) {
  34398         return sema.intSub(lhs, rhs, ty);
  34399     }
  34400 
  34401     if (ty.isAnyFloat()) {
  34402         return Value.floatSub(lhs, rhs, ty, sema.arena, mod);
  34403     }
  34404 
  34405     const overflow_result = try sema.intSubWithOverflow(lhs, rhs, ty);
  34406     return overflow_result.wrapped_result;
  34407 }
  34408 
  34409 fn intSubWithOverflow(
  34410     sema: *Sema,
  34411     lhs: Value,
  34412     rhs: Value,
  34413     ty: Type,
  34414 ) !Value.OverflowArithmeticResult {
  34415     const mod = sema.mod;
  34416     if (ty.zigTypeTag(mod) == .Vector) {
  34417         const vec_len = ty.vectorLen(mod);
  34418         const overflowed_data = try sema.arena.alloc(InternPool.Index, vec_len);
  34419         const result_data = try sema.arena.alloc(InternPool.Index, vec_len);
  34420         const scalar_ty = ty.scalarType(mod);
  34421         for (overflowed_data, result_data, 0..) |*of, *scalar, i| {
  34422             const lhs_elem = try lhs.elemValue(sema.mod, i);
  34423             const rhs_elem = try rhs.elemValue(sema.mod, i);
  34424             const of_math_result = try sema.intSubWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty);
  34425             of.* = try of_math_result.overflow_bit.intern(Type.u1, mod);
  34426             scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod);
  34427         }
  34428         return Value.OverflowArithmeticResult{
  34429             .overflow_bit = (try mod.intern(.{ .aggregate = .{
  34430                 .ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(),
  34431                 .storage = .{ .elems = overflowed_data },
  34432             } })).toValue(),
  34433             .wrapped_result = (try mod.intern(.{ .aggregate = .{
  34434                 .ty = ty.toIntern(),
  34435                 .storage = .{ .elems = result_data },
  34436             } })).toValue(),
  34437         };
  34438     }
  34439     return sema.intSubWithOverflowScalar(lhs, rhs, ty);
  34440 }
  34441 
  34442 fn intSubWithOverflowScalar(
  34443     sema: *Sema,
  34444     lhs: Value,
  34445     rhs: Value,
  34446     ty: Type,
  34447 ) !Value.OverflowArithmeticResult {
  34448     const mod = sema.mod;
  34449     const info = ty.intInfo(mod);
  34450 
  34451     var lhs_space: Value.BigIntSpace = undefined;
  34452     var rhs_space: Value.BigIntSpace = undefined;
  34453     const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
  34454     const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
  34455     const limbs = try sema.arena.alloc(
  34456         std.math.big.Limb,
  34457         std.math.big.int.calcTwosCompLimbCount(info.bits),
  34458     );
  34459     var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
  34460     const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
  34461     const wrapped_result = try mod.intValue_big(ty, result_bigint.toConst());
  34462     return Value.OverflowArithmeticResult{
  34463         .overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)),
  34464         .wrapped_result = wrapped_result,
  34465     };
  34466 }
  34467 
  34468 fn floatToInt(
  34469     sema: *Sema,
  34470     block: *Block,
  34471     src: LazySrcLoc,
  34472     val: Value,
  34473     float_ty: Type,
  34474     int_ty: Type,
  34475 ) CompileError!Value {
  34476     const mod = sema.mod;
  34477     if (float_ty.zigTypeTag(mod) == .Vector) {
  34478         const elem_ty = float_ty.scalarType(mod);
  34479         const result_data = try sema.arena.alloc(InternPool.Index, float_ty.vectorLen(mod));
  34480         const scalar_ty = int_ty.scalarType(mod);
  34481         for (result_data, 0..) |*scalar, i| {
  34482             const elem_val = try val.elemValue(sema.mod, i);
  34483             scalar.* = try (try sema.floatToIntScalar(block, src, elem_val, elem_ty, int_ty.scalarType(mod))).intern(scalar_ty, mod);
  34484         }
  34485         return (try mod.intern(.{ .aggregate = .{
  34486             .ty = int_ty.toIntern(),
  34487             .storage = .{ .elems = result_data },
  34488         } })).toValue();
  34489     }
  34490     return sema.floatToIntScalar(block, src, val, float_ty, int_ty);
  34491 }
  34492 
  34493 // float is expected to be finite and non-NaN
  34494 fn float128IntPartToBigInt(
  34495     arena: Allocator,
  34496     float: f128,
  34497 ) !std.math.big.int.Managed {
  34498     const is_negative = std.math.signbit(float);
  34499     const floored = @floor(@fabs(float));
  34500 
  34501     var rational = try std.math.big.Rational.init(arena);
  34502     defer rational.q.deinit();
  34503     rational.setFloat(f128, floored) catch |err| switch (err) {
  34504         error.NonFiniteFloat => unreachable,
  34505         error.OutOfMemory => return error.OutOfMemory,
  34506     };
  34507 
  34508     // The float is reduced in rational.setFloat, so we assert that denominator is equal to one
  34509     const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true };
  34510     assert(rational.q.toConst().eqAbs(big_one));
  34511 
  34512     if (is_negative) {
  34513         rational.negate();
  34514     }
  34515     return rational.p;
  34516 }
  34517 
  34518 fn floatToIntScalar(
  34519     sema: *Sema,
  34520     block: *Block,
  34521     src: LazySrcLoc,
  34522     val: Value,
  34523     float_ty: Type,
  34524     int_ty: Type,
  34525 ) CompileError!Value {
  34526     const mod = sema.mod;
  34527 
  34528     const float = val.toFloat(f128, mod);
  34529     if (std.math.isNan(float)) {
  34530         return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{
  34531             int_ty.fmt(sema.mod),
  34532         });
  34533     }
  34534     if (std.math.isInf(float)) {
  34535         return sema.fail(block, src, "float value Inf cannot be stored in integer type '{}'", .{
  34536             int_ty.fmt(sema.mod),
  34537         });
  34538     }
  34539 
  34540     var big_int = try float128IntPartToBigInt(sema.arena, float);
  34541     defer big_int.deinit();
  34542 
  34543     const result = try mod.intValue_big(int_ty, big_int.toConst());
  34544 
  34545     if (!(try sema.intFitsInType(result, int_ty, null))) {
  34546         return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{
  34547             val.fmtValue(float_ty, sema.mod), int_ty.fmt(sema.mod),
  34548         });
  34549     }
  34550     return result;
  34551 }
  34552 
  34553 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
  34554 /// Vectors are also accepted. Vector results are reduced with AND.
  34555 ///
  34556 /// If provided, `vector_index` reports the first element that failed the range check.
  34557 fn intFitsInType(
  34558     sema: *Sema,
  34559     val: Value,
  34560     ty: Type,
  34561     vector_index: ?*usize,
  34562 ) CompileError!bool {
  34563     const mod = sema.mod;
  34564     if (ty.toIntern() == .comptime_int_type) return true;
  34565     const info = ty.intInfo(mod);
  34566     switch (val.toIntern()) {
  34567         .zero_usize, .zero_u8 => return true,
  34568         else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
  34569             .undef => return true,
  34570             .variable, .extern_func, .func, .ptr => {
  34571                 const target = mod.getTarget();
  34572                 const ptr_bits = target.ptrBitWidth();
  34573                 return switch (info.signedness) {
  34574                     .signed => info.bits > ptr_bits,
  34575                     .unsigned => info.bits >= ptr_bits,
  34576                 };
  34577             },
  34578             .int => |int| switch (int.storage) {
  34579                 .u64, .i64, .big_int => {
  34580                     var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
  34581                     const big_int = int.storage.toBigInt(&buffer);
  34582                     return big_int.fitsInTwosComp(info.signedness, info.bits);
  34583                 },
  34584                 .lazy_align => |lazy_ty| {
  34585                     const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed);
  34586                     // If it is u16 or bigger we know the alignment fits without resolving it.
  34587                     if (info.bits >= max_needed_bits) return true;
  34588                     const x = try sema.typeAbiAlignment(lazy_ty.toType());
  34589                     if (x == 0) return true;
  34590                     const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
  34591                     return info.bits >= actual_needed_bits;
  34592                 },
  34593                 .lazy_size => |lazy_ty| {
  34594                     const max_needed_bits = @as(u16, 64) + @boolToInt(info.signedness == .signed);
  34595                     // If it is u64 or bigger we know the size fits without resolving it.
  34596                     if (info.bits >= max_needed_bits) return true;
  34597                     const x = try sema.typeAbiSize(lazy_ty.toType());
  34598                     if (x == 0) return true;
  34599                     const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
  34600                     return info.bits >= actual_needed_bits;
  34601                 },
  34602             },
  34603             .aggregate => |aggregate| {
  34604                 assert(ty.zigTypeTag(mod) == .Vector);
  34605                 return switch (aggregate.storage) {
  34606                     .bytes => |bytes| for (bytes, 0..) |byte, i| {
  34607                         if (byte == 0) continue;
  34608                         const actual_needed_bits = std.math.log2(byte) + 1 + @boolToInt(info.signedness == .signed);
  34609                         if (info.bits >= actual_needed_bits) continue;
  34610                         if (vector_index) |vi| vi.* = i;
  34611                         break false;
  34612                     } else true,
  34613                     .elems, .repeated_elem => for (switch (aggregate.storage) {
  34614                         .bytes => unreachable,
  34615                         .elems => |elems| elems,
  34616                         .repeated_elem => |elem| @as(*const [1]InternPool.Index, &elem),
  34617                     }, 0..) |elem, i| {
  34618                         if (try sema.intFitsInType(elem.toValue(), ty.scalarType(mod), null)) continue;
  34619                         if (vector_index) |vi| vi.* = i;
  34620                         break false;
  34621                     } else true,
  34622                 };
  34623             },
  34624             else => unreachable,
  34625         },
  34626     }
  34627 }
  34628 
  34629 fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {
  34630     const mod = sema.mod;
  34631     if (!(try int_val.compareAllWithZeroAdvanced(.gte, sema))) return false;
  34632     const end_val = try mod.intValue(tag_ty, end);
  34633     if (!(try sema.compareAll(int_val, .lt, end_val, tag_ty))) return false;
  34634     return true;
  34635 }
  34636 
  34637 /// Asserts the type is an enum.
  34638 fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {
  34639     const mod = sema.mod;
  34640     const enum_type = mod.intern_pool.indexToKey(ty.toIntern()).enum_type;
  34641     assert(enum_type.tag_mode != .nonexhaustive);
  34642     // The `tagValueIndex` function call below relies on the type being the integer tag type.
  34643     // `getCoerced` assumes the value will fit the new type.
  34644     if (!(try sema.intFitsInType(int, enum_type.tag_ty.toType(), null))) return false;
  34645     const int_coerced = try mod.getCoerced(int, enum_type.tag_ty.toType());
  34646 
  34647     return enum_type.tagValueIndex(&mod.intern_pool, int_coerced.toIntern()) != null;
  34648 }
  34649 
  34650 fn intAddWithOverflow(
  34651     sema: *Sema,
  34652     lhs: Value,
  34653     rhs: Value,
  34654     ty: Type,
  34655 ) !Value.OverflowArithmeticResult {
  34656     const mod = sema.mod;
  34657     if (ty.zigTypeTag(mod) == .Vector) {
  34658         const vec_len = ty.vectorLen(mod);
  34659         const overflowed_data = try sema.arena.alloc(InternPool.Index, vec_len);
  34660         const result_data = try sema.arena.alloc(InternPool.Index, vec_len);
  34661         const scalar_ty = ty.scalarType(mod);
  34662         for (overflowed_data, result_data, 0..) |*of, *scalar, i| {
  34663             const lhs_elem = try lhs.elemValue(sema.mod, i);
  34664             const rhs_elem = try rhs.elemValue(sema.mod, i);
  34665             const of_math_result = try sema.intAddWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty);
  34666             of.* = try of_math_result.overflow_bit.intern(Type.u1, mod);
  34667             scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod);
  34668         }
  34669         return Value.OverflowArithmeticResult{
  34670             .overflow_bit = (try mod.intern(.{ .aggregate = .{
  34671                 .ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(),
  34672                 .storage = .{ .elems = overflowed_data },
  34673             } })).toValue(),
  34674             .wrapped_result = (try mod.intern(.{ .aggregate = .{
  34675                 .ty = ty.toIntern(),
  34676                 .storage = .{ .elems = result_data },
  34677             } })).toValue(),
  34678         };
  34679     }
  34680     return sema.intAddWithOverflowScalar(lhs, rhs, ty);
  34681 }
  34682 
  34683 fn intAddWithOverflowScalar(
  34684     sema: *Sema,
  34685     lhs: Value,
  34686     rhs: Value,
  34687     ty: Type,
  34688 ) !Value.OverflowArithmeticResult {
  34689     const mod = sema.mod;
  34690     const info = ty.intInfo(mod);
  34691 
  34692     var lhs_space: Value.BigIntSpace = undefined;
  34693     var rhs_space: Value.BigIntSpace = undefined;
  34694     const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
  34695     const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
  34696     const limbs = try sema.arena.alloc(
  34697         std.math.big.Limb,
  34698         std.math.big.int.calcTwosCompLimbCount(info.bits),
  34699     );
  34700     var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
  34701     const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
  34702     const result = try mod.intValue_big(ty, result_bigint.toConst());
  34703     return Value.OverflowArithmeticResult{
  34704         .overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)),
  34705         .wrapped_result = result,
  34706     };
  34707 }
  34708 
  34709 /// Asserts the values are comparable. Both operands have type `ty`.
  34710 /// For vectors, returns true if the comparison is true for ALL elements.
  34711 ///
  34712 /// Note that `!compareAll(.eq, ...) != compareAll(.neq, ...)`
  34713 fn compareAll(
  34714     sema: *Sema,
  34715     lhs: Value,
  34716     op: std.math.CompareOperator,
  34717     rhs: Value,
  34718     ty: Type,
  34719 ) CompileError!bool {
  34720     const mod = sema.mod;
  34721     if (ty.zigTypeTag(mod) == .Vector) {
  34722         var i: usize = 0;
  34723         while (i < ty.vectorLen(mod)) : (i += 1) {
  34724             const lhs_elem = try lhs.elemValue(sema.mod, i);
  34725             const rhs_elem = try rhs.elemValue(sema.mod, i);
  34726             if (!(try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(mod)))) {
  34727                 return false;
  34728             }
  34729         }
  34730         return true;
  34731     }
  34732     return sema.compareScalar(lhs, op, rhs, ty);
  34733 }
  34734 
  34735 /// Asserts the values are comparable. Both operands have type `ty`.
  34736 fn compareScalar(
  34737     sema: *Sema,
  34738     lhs: Value,
  34739     op: std.math.CompareOperator,
  34740     rhs: Value,
  34741     ty: Type,
  34742 ) CompileError!bool {
  34743     const mod = sema.mod;
  34744     const coerced_lhs = try mod.getCoerced(lhs, ty);
  34745     const coerced_rhs = try mod.getCoerced(rhs, ty);
  34746     switch (op) {
  34747         .eq => return sema.valuesEqual(coerced_lhs, coerced_rhs, ty),
  34748         .neq => return !(try sema.valuesEqual(coerced_lhs, coerced_rhs, ty)),
  34749         else => return Value.compareHeteroAdvanced(coerced_lhs, op, coerced_rhs, mod, sema),
  34750     }
  34751 }
  34752 
  34753 fn valuesEqual(
  34754     sema: *Sema,
  34755     lhs: Value,
  34756     rhs: Value,
  34757     ty: Type,
  34758 ) CompileError!bool {
  34759     return Value.eqlAdvanced(lhs, ty, rhs, ty, sema.mod, sema);
  34760 }
  34761 
  34762 /// Asserts the values are comparable vectors of type `ty`.
  34763 fn compareVector(
  34764     sema: *Sema,
  34765     lhs: Value,
  34766     op: std.math.CompareOperator,
  34767     rhs: Value,
  34768     ty: Type,
  34769 ) !Value {
  34770     const mod = sema.mod;
  34771     assert(ty.zigTypeTag(mod) == .Vector);
  34772     const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod));
  34773     for (result_data, 0..) |*scalar, i| {
  34774         const lhs_elem = try lhs.elemValue(sema.mod, i);
  34775         const rhs_elem = try rhs.elemValue(sema.mod, i);
  34776         const res_bool = try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(mod));
  34777         scalar.* = try Value.makeBool(res_bool).intern(Type.bool, mod);
  34778     }
  34779     return (try mod.intern(.{ .aggregate = .{
  34780         .ty = (try mod.vectorType(.{ .len = ty.vectorLen(mod), .child = .bool_type })).toIntern(),
  34781         .storage = .{ .elems = result_data },
  34782     } })).toValue();
  34783 }
  34784 
  34785 /// Returns the type of a pointer to an element.
  34786 /// Asserts that the type is a pointer, and that the element type is indexable.
  34787 /// For *[N]T, return *T
  34788 /// For [*]T, returns *T
  34789 /// For []T, returns *T
  34790 /// Handles const-ness and address spaces in particular.
  34791 /// This code is duplicated in `analyzePtrArithmetic`.
  34792 fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
  34793     const mod = sema.mod;
  34794     const ptr_info = ptr_ty.ptrInfo(mod);
  34795     const elem_ty = ptr_ty.elemType2(mod);
  34796     const allow_zero = ptr_info.@"allowzero" and (offset orelse 0) == 0;
  34797     const parent_ty = ptr_ty.childType(mod);
  34798 
  34799     const VI = Type.Payload.Pointer.Data.VectorIndex;
  34800 
  34801     const vector_info: struct {
  34802         host_size: u16 = 0,
  34803         alignment: u32 = 0,
  34804         vector_index: VI = .none,
  34805     } = if (parent_ty.isVector(mod) and ptr_info.size == .One) blk: {
  34806         const elem_bits = elem_ty.bitSize(mod);
  34807         if (elem_bits == 0) break :blk .{};
  34808         const is_packed = elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits);
  34809         if (!is_packed) break :blk .{};
  34810 
  34811         break :blk .{
  34812             .host_size = @intCast(u16, parent_ty.arrayLen(mod)),
  34813             .alignment = @intCast(u16, parent_ty.abiAlignment(mod)),
  34814             .vector_index = if (offset) |some| @intToEnum(VI, some) else .runtime,
  34815         };
  34816     } else .{};
  34817 
  34818     const alignment: u32 = a: {
  34819         // Calculate the new pointer alignment.
  34820         if (ptr_info.@"align" == 0) {
  34821             if (vector_info.alignment != 0) break :a vector_info.alignment;
  34822             // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness.
  34823             break :a 0;
  34824         }
  34825         // If the addend is not a comptime-known value we can still count on
  34826         // it being a multiple of the type size.
  34827         const elem_size = try sema.typeAbiSize(elem_ty);
  34828         const addend = if (offset) |off| elem_size * off else elem_size;
  34829 
  34830         // The resulting pointer is aligned to the lcd between the offset (an
  34831         // arbitrary number) and the alignment factor (always a power of two,
  34832         // non zero).
  34833         const new_align = @as(u32, 1) << @intCast(u5, @ctz(addend | ptr_info.@"align"));
  34834         break :a new_align;
  34835     };
  34836     return try Type.ptr(sema.arena, sema.mod, .{
  34837         .pointee_type = elem_ty,
  34838         .mutable = ptr_info.mutable,
  34839         .@"addrspace" = ptr_info.@"addrspace",
  34840         .@"allowzero" = allow_zero,
  34841         .@"volatile" = ptr_info.@"volatile",
  34842         .@"align" = alignment,
  34843         .host_size = vector_info.host_size,
  34844         .vector_index = vector_info.vector_index,
  34845     });
  34846 }
  34847 
  34848 /// Merge lhs with rhs.
  34849 /// Asserts that lhs and rhs are both error sets and are resolved.
  34850 fn errorSetMerge(sema: *Sema, lhs: Type, rhs: Type) !Type {
  34851     const mod = sema.mod;
  34852     const arena = sema.arena;
  34853     const lhs_names = lhs.errorSetNames(mod);
  34854     const rhs_names = rhs.errorSetNames(mod);
  34855     var names: Module.Fn.InferredErrorSet.NameMap = .{};
  34856     try names.ensureUnusedCapacity(arena, lhs_names.len);
  34857 
  34858     for (lhs_names) |name| {
  34859         names.putAssumeCapacityNoClobber(name, {});
  34860     }
  34861     for (rhs_names) |name| {
  34862         try names.put(arena, name, {});
  34863     }
  34864 
  34865     return mod.errorSetFromUnsortedNames(names.keys());
  34866 }
  34867 
  34868 /// Avoids crashing the compiler when asking if inferred allocations are noreturn.
  34869 fn isNoReturn(sema: *Sema, ref: Air.Inst.Ref) bool {
  34870     if (ref == .unreachable_value) return true;
  34871     if (Air.refToIndex(ref)) |inst| switch (sema.air_instructions.items(.tag)[inst]) {
  34872         .inferred_alloc, .inferred_alloc_comptime => return false,
  34873         else => {},
  34874     };
  34875     return sema.typeOf(ref).isNoReturn(sema.mod);
  34876 }
  34877 
  34878 /// Avoids crashing the compiler when asking if inferred allocations are known to be a certain zig type.
  34879 fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool {
  34880     if (Air.refToIndex(ref)) |inst| switch (sema.air_instructions.items(.tag)[inst]) {
  34881         .inferred_alloc, .inferred_alloc_comptime => return false,
  34882         else => {},
  34883     };
  34884     return sema.typeOf(ref).zigTypeTag(sema.mod) == tag;
  34885 }