zig

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

blob 8a12fbcd (196678B) - Raw


      1 //! Semantic analysis of ZIR instructions.
      2 //! Shared to every Block. Stored on the stack.
      3 //! State used for compiling a `zir.Code` into TZIR.
      4 //! Transforms untyped ZIR instructions into semantically-analyzed TZIR 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 arena allocator of the Decl.
     12 arena: *Allocator,
     13 code: zir.Code,
     14 /// Maps ZIR to TZIR.
     15 inst_map: []*Inst,
     16 /// When analyzing an inline function call, owner_decl is the Decl of the caller
     17 /// and `src_decl` of `Scope.Block` is the `Decl` of the callee.
     18 /// This `Decl` owns the arena memory of this `Sema`.
     19 owner_decl: *Decl,
     20 /// For an inline or comptime function call, this will be the root parent function
     21 /// which contains the callsite. Corresponds to `owner_decl`.
     22 owner_func: ?*Module.Fn,
     23 /// The function this ZIR code is the body of, according to the source code.
     24 /// This starts out the same as `owner_func` and then diverges in the case of
     25 /// an inline or comptime function call.
     26 func: ?*Module.Fn,
     27 /// For now, TZIR requires arg instructions to be the first N instructions in the
     28 /// TZIR code. We store references here for the purpose of `resolveInst`.
     29 /// This can get reworked with TZIR memory layout changes, into simply:
     30 /// > Denormalized data to make `resolveInst` faster. This is 0 if not inside a function,
     31 /// > otherwise it is the number of parameters of the function.
     32 /// > param_count: u32
     33 param_inst_list: []const *ir.Inst,
     34 branch_quota: u32 = 1000,
     35 branch_count: u32 = 0,
     36 /// This field is updated when a new source location becomes active, so that
     37 /// instructions which do not have explicitly mapped source locations still have
     38 /// access to the source location set by the previous instruction which did
     39 /// contain a mapped source location.
     40 src: LazySrcLoc = .{ .token_offset = 0 },
     41 
     42 const std = @import("std");
     43 const mem = std.mem;
     44 const Allocator = std.mem.Allocator;
     45 const assert = std.debug.assert;
     46 const log = std.log.scoped(.sema);
     47 
     48 const Sema = @This();
     49 const Value = @import("value.zig").Value;
     50 const Type = @import("type.zig").Type;
     51 const TypedValue = @import("TypedValue.zig");
     52 const ir = @import("ir.zig");
     53 const zir = @import("zir.zig");
     54 const Module = @import("Module.zig");
     55 const Inst = ir.Inst;
     56 const Body = ir.Body;
     57 const trace = @import("tracy.zig").trace;
     58 const Scope = Module.Scope;
     59 const InnerError = Module.InnerError;
     60 const Decl = Module.Decl;
     61 const LazySrcLoc = Module.LazySrcLoc;
     62 const RangeSet = @import("RangeSet.zig");
     63 const AstGen = @import("AstGen.zig");
     64 
     65 pub fn root(sema: *Sema, root_block: *Scope.Block) !zir.Inst.Index {
     66     const inst_data = sema.code.instructions.items(.data)[0].pl_node;
     67     const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);
     68     const root_body = sema.code.extra[extra.end..][0..extra.data.body_len];
     69     return sema.analyzeBody(root_block, root_body);
     70 }
     71 
     72 pub fn rootAsRef(sema: *Sema, root_block: *Scope.Block) !zir.Inst.Ref {
     73     const break_inst = try sema.root(root_block);
     74     return sema.code.instructions.items(.data)[break_inst].@"break".operand;
     75 }
     76 
     77 /// Assumes that `root_block` ends with `break_inline`.
     78 pub fn rootAsType(sema: *Sema, root_block: *Scope.Block) !Type {
     79     const zir_inst_ref = try sema.rootAsRef(root_block);
     80     // Source location is unneeded because resolveConstValue must have already
     81     // been successfully called when coercing the value to a type, from the
     82     // result location.
     83     return sema.resolveType(root_block, .unneeded, zir_inst_ref);
     84 }
     85 
     86 /// Returns only the result from the body that is specified.
     87 /// Only appropriate to call when it is determined at comptime that this body
     88 /// has no peers.
     89 fn resolveBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Index) InnerError!*Inst {
     90     const break_inst = try sema.analyzeBody(block, body);
     91     const operand_ref = sema.code.instructions.items(.data)[break_inst].@"break".operand;
     92     return sema.resolveInst(operand_ref);
     93 }
     94 
     95 /// ZIR instructions which are always `noreturn` return this. This matches the
     96 /// return type of `analyzeBody` so that we can tail call them.
     97 /// Only appropriate to return when the instruction is known to be NoReturn
     98 /// solely based on the ZIR tag.
     99 const always_noreturn: InnerError!zir.Inst.Index = @as(zir.Inst.Index, undefined);
    100 
    101 /// This function is the main loop of `Sema` and it can be used in two different ways:
    102 /// * The traditional way where there are N breaks out of the block and peer type
    103 ///   resolution is done on the break operands. In this case, the `zir.Inst.Index`
    104 ///   part of the return value will be `undefined`, and callsites should ignore it,
    105 ///   finding the block result value via the block scope.
    106 /// * The "flat" way. There is only 1 break out of the block, and it is with a `break_inline`
    107 ///   instruction. In this case, the `zir.Inst.Index` part of the return value will be
    108 ///   the break instruction. This communicates both which block the break applies to, as
    109 ///   well as the operand. No block scope needs to be created for this strategy.
    110 pub fn analyzeBody(
    111     sema: *Sema,
    112     block: *Scope.Block,
    113     body: []const zir.Inst.Index,
    114 ) InnerError!zir.Inst.Index {
    115     // No tracy calls here, to avoid interfering with the tail call mechanism.
    116 
    117     const map = block.sema.inst_map;
    118     const tags = block.sema.code.instructions.items(.tag);
    119     const datas = block.sema.code.instructions.items(.data);
    120 
    121     // We use a while(true) loop here to avoid a redundant way of breaking out of
    122     // the loop. The only way to break out of the loop is with a `noreturn`
    123     // instruction.
    124     // TODO: As an optimization, make sure the codegen for these switch prongs
    125     // directly jump to the next one, rather than detouring through the loop
    126     // continue expression. Related: https://github.com/ziglang/zig/issues/8220
    127     var i: usize = 0;
    128     while (true) : (i += 1) {
    129         const inst = body[i];
    130         map[inst] = switch (tags[inst]) {
    131             .elided => continue,
    132 
    133             .add => try sema.zirArithmetic(block, inst),
    134             .addwrap => try sema.zirArithmetic(block, inst),
    135             .alloc => try sema.zirAlloc(block, inst),
    136             .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
    137             .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
    138             .alloc_mut => try sema.zirAllocMut(block, inst),
    139             .array_cat => try sema.zirArrayCat(block, inst),
    140             .array_mul => try sema.zirArrayMul(block, inst),
    141             .array_type => try sema.zirArrayType(block, inst),
    142             .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
    143             .as => try sema.zirAs(block, inst),
    144             .as_node => try sema.zirAsNode(block, inst),
    145             .@"asm" => try sema.zirAsm(block, inst, false),
    146             .asm_volatile => try sema.zirAsm(block, inst, true),
    147             .bit_and => try sema.zirBitwise(block, inst, .bit_and),
    148             .bit_not => try sema.zirBitNot(block, inst),
    149             .bit_or => try sema.zirBitwise(block, inst, .bit_or),
    150             .bitcast => try sema.zirBitcast(block, inst),
    151             .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),
    152             .block => try sema.zirBlock(block, inst),
    153             .bool_not => try sema.zirBoolNot(block, inst),
    154             .bool_and => try sema.zirBoolOp(block, inst, false),
    155             .bool_or => try sema.zirBoolOp(block, inst, true),
    156             .bool_br_and => try sema.zirBoolBr(block, inst, false),
    157             .bool_br_or => try sema.zirBoolBr(block, inst, true),
    158             .call => try sema.zirCall(block, inst, .auto, false),
    159             .call_chkused => try sema.zirCall(block, inst, .auto, true),
    160             .call_compile_time => try sema.zirCall(block, inst, .compile_time, false),
    161             .call_none => try sema.zirCallNone(block, inst, false),
    162             .call_none_chkused => try sema.zirCallNone(block, inst, true),
    163             .cmp_eq => try sema.zirCmp(block, inst, .eq),
    164             .cmp_gt => try sema.zirCmp(block, inst, .gt),
    165             .cmp_gte => try sema.zirCmp(block, inst, .gte),
    166             .cmp_lt => try sema.zirCmp(block, inst, .lt),
    167             .cmp_lte => try sema.zirCmp(block, inst, .lte),
    168             .cmp_neq => try sema.zirCmp(block, inst, .neq),
    169             .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
    170             .@"const" => try sema.zirConst(block, inst),
    171             .decl_ref => try sema.zirDeclRef(block, inst),
    172             .decl_val => try sema.zirDeclVal(block, inst),
    173             .load => try sema.zirLoad(block, inst),
    174             .div => try sema.zirArithmetic(block, inst),
    175             .elem_ptr => try sema.zirElemPtr(block, inst),
    176             .elem_ptr_node => try sema.zirElemPtrNode(block, inst),
    177             .elem_val => try sema.zirElemVal(block, inst),
    178             .elem_val_node => try sema.zirElemValNode(block, inst),
    179             .enum_literal => try sema.zirEnumLiteral(block, inst),
    180             .enum_literal_small => try sema.zirEnumLiteralSmall(block, inst),
    181             .err_union_code => try sema.zirErrUnionCode(block, inst),
    182             .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),
    183             .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),
    184             .err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true),
    185             .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false),
    186             .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false),
    187             .error_union_type => try sema.zirErrorUnionType(block, inst),
    188             .error_value => try sema.zirErrorValue(block, inst),
    189             .error_to_int => try sema.zirErrorToInt(block, inst),
    190             .int_to_error => try sema.zirIntToError(block, inst),
    191             .field_ptr => try sema.zirFieldPtr(block, inst),
    192             .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
    193             .field_val => try sema.zirFieldVal(block, inst),
    194             .field_val_named => try sema.zirFieldValNamed(block, inst),
    195             .floatcast => try sema.zirFloatcast(block, inst),
    196             .fn_type => try sema.zirFnType(block, inst, false),
    197             .fn_type_cc => try sema.zirFnTypeCc(block, inst, false),
    198             .fn_type_cc_var_args => try sema.zirFnTypeCc(block, inst, true),
    199             .fn_type_var_args => try sema.zirFnType(block, inst, true),
    200             .import => try sema.zirImport(block, inst),
    201             .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
    202             .int => try sema.zirInt(block, inst),
    203             .int_type => try sema.zirIntType(block, inst),
    204             .intcast => try sema.zirIntcast(block, inst),
    205             .is_err => try sema.zirIsErr(block, inst),
    206             .is_err_ptr => try sema.zirIsErrPtr(block, inst),
    207             .is_non_null => try sema.zirIsNull(block, inst, true),
    208             .is_non_null_ptr => try sema.zirIsNullPtr(block, inst, true),
    209             .is_null => try sema.zirIsNull(block, inst, false),
    210             .is_null_ptr => try sema.zirIsNullPtr(block, inst, false),
    211             .loop => try sema.zirLoop(block, inst),
    212             .merge_error_sets => try sema.zirMergeErrorSets(block, inst),
    213             .mod_rem => try sema.zirArithmetic(block, inst),
    214             .mul => try sema.zirArithmetic(block, inst),
    215             .mulwrap => try sema.zirArithmetic(block, inst),
    216             .negate => try sema.zirNegate(block, inst, .sub),
    217             .negate_wrap => try sema.zirNegate(block, inst, .subwrap),
    218             .optional_payload_safe => try sema.zirOptionalPayload(block, inst, true),
    219             .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true),
    220             .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),
    221             .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
    222             .optional_type => try sema.zirOptionalType(block, inst),
    223             .optional_type_from_ptr_elem => try sema.zirOptionalTypeFromPtrElem(block, inst),
    224             .param_type => try sema.zirParamType(block, inst),
    225             .ptr_type => try sema.zirPtrType(block, inst),
    226             .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
    227             .ptrtoint => try sema.zirPtrtoint(block, inst),
    228             .ref => try sema.zirRef(block, inst),
    229             .ret_ptr => try sema.zirRetPtr(block, inst),
    230             .ret_type => try sema.zirRetType(block, inst),
    231             .shl => try sema.zirShl(block, inst),
    232             .shr => try sema.zirShr(block, inst),
    233             .slice_end => try sema.zirSliceEnd(block, inst),
    234             .slice_sentinel => try sema.zirSliceSentinel(block, inst),
    235             .slice_start => try sema.zirSliceStart(block, inst),
    236             .str => try sema.zirStr(block, inst),
    237             .sub => try sema.zirArithmetic(block, inst),
    238             .subwrap => try sema.zirArithmetic(block, inst),
    239             .switch_block => try sema.zirSwitchBlock(block, inst, false, .none),
    240             .switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none),
    241             .switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"),
    242             .switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"),
    243             .switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under),
    244             .switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under),
    245             .switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none),
    246             .switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none),
    247             .switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"),
    248             .switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"),
    249             .switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under),
    250             .switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under),
    251             .switch_capture => try sema.zirSwitchCapture(block, inst, false, false),
    252             .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true),
    253             .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false),
    254             .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
    255             .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
    256             .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
    257             .typeof => try sema.zirTypeof(block, inst),
    258             .typeof_elem => try sema.zirTypeofElem(block, inst),
    259             .typeof_peer => try sema.zirTypeofPeer(block, inst),
    260             .xor => try sema.zirBitwise(block, inst, .xor),
    261 
    262             // Instructions that we know to *always* be noreturn based solely on their tag.
    263             // These functions match the return type of analyzeBody so that we can
    264             // tail call them here.
    265             .condbr => return sema.zirCondbr(block, inst),
    266             .@"break" => return sema.zirBreak(block, inst),
    267             .break_inline => return inst,
    268             .compile_error => return sema.zirCompileError(block, inst),
    269             .ret_coerce => return sema.zirRetTok(block, inst, true),
    270             .ret_node => return sema.zirRetNode(block, inst),
    271             .ret_tok => return sema.zirRetTok(block, inst, false),
    272             .@"unreachable" => return sema.zirUnreachable(block, inst),
    273             .repeat => return sema.zirRepeat(block, inst),
    274 
    275             // Instructions that we know can *never* be noreturn based solely on
    276             // their tag. We avoid needlessly checking if they are noreturn and
    277             // continue the loop.
    278             // We also know that they cannot be referenced later, so we avoid
    279             // putting them into the map.
    280             .breakpoint => {
    281                 try sema.zirBreakpoint(block, inst);
    282                 continue;
    283             },
    284             .dbg_stmt_node => {
    285                 try sema.zirDbgStmtNode(block, inst);
    286                 continue;
    287             },
    288             .ensure_err_payload_void => {
    289                 try sema.zirEnsureErrPayloadVoid(block, inst);
    290                 continue;
    291             },
    292             .ensure_result_non_error => {
    293                 try sema.zirEnsureResultNonError(block, inst);
    294                 continue;
    295             },
    296             .ensure_result_used => {
    297                 try sema.zirEnsureResultUsed(block, inst);
    298                 continue;
    299             },
    300             .compile_log => {
    301                 try sema.zirCompileLog(block, inst);
    302                 continue;
    303             },
    304             .set_eval_branch_quota => {
    305                 try sema.zirSetEvalBranchQuota(block, inst);
    306                 continue;
    307             },
    308             .store => {
    309                 try sema.zirStore(block, inst);
    310                 continue;
    311             },
    312             .store_node => {
    313                 try sema.zirStoreNode(block, inst);
    314                 continue;
    315             },
    316             .store_to_block_ptr => {
    317                 try sema.zirStoreToBlockPtr(block, inst);
    318                 continue;
    319             },
    320             .store_to_inferred_ptr => {
    321                 try sema.zirStoreToInferredPtr(block, inst);
    322                 continue;
    323             },
    324             .resolve_inferred_alloc => {
    325                 try sema.zirResolveInferredAlloc(block, inst);
    326                 continue;
    327             },
    328 
    329             // Special case instructions to handle comptime control flow.
    330             .repeat_inline => {
    331                 // Send comptime control flow back to the beginning of this block.
    332                 const src: LazySrcLoc = .{ .node_offset = datas[inst].node };
    333                 try sema.emitBackwardBranch(block, src);
    334                 i = 0;
    335                 continue;
    336             },
    337             .block_inline => blk: {
    338                 // Directly analyze the block body without introducing a new block.
    339                 const inst_data = datas[inst].pl_node;
    340                 const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);
    341                 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
    342                 const break_inst = try sema.analyzeBody(block, inline_body);
    343                 const break_data = datas[break_inst].@"break";
    344                 if (inst == break_data.block_inst) {
    345                     break :blk try sema.resolveInst(break_data.operand);
    346                 } else {
    347                     return break_inst;
    348                 }
    349             },
    350             .condbr_inline => blk: {
    351                 const inst_data = datas[inst].pl_node;
    352                 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
    353                 const extra = sema.code.extraData(zir.Inst.CondBr, inst_data.payload_index);
    354                 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
    355                 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
    356                 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);
    357                 const inline_body = if (cond.val.toBool()) then_body else else_body;
    358                 const break_inst = try sema.analyzeBody(block, inline_body);
    359                 const break_data = datas[break_inst].@"break";
    360                 if (inst == break_data.block_inst) {
    361                     break :blk try sema.resolveInst(break_data.operand);
    362                 } else {
    363                     return break_inst;
    364                 }
    365             },
    366         };
    367         if (map[inst].ty.isNoReturn())
    368             return always_noreturn;
    369     }
    370 }
    371 
    372 /// TODO when we rework TZIR memory layout, this function will no longer have a possible error.
    373 pub fn resolveInst(sema: *Sema, zir_ref: zir.Inst.Ref) error{OutOfMemory}!*ir.Inst {
    374     var i: usize = @enumToInt(zir_ref);
    375 
    376     // First section of indexes correspond to a set number of constant values.
    377     if (i < zir.Inst.Ref.typed_value_map.len) {
    378         // TODO when we rework TZIR memory layout, this function can be as simple as:
    379         // if (zir_ref < zir.const_inst_list.len + sema.param_count)
    380         //     return zir_ref;
    381         // Until then we allocate memory for a new, mutable `ir.Inst` to match what
    382         // TZIR expects.
    383         return sema.mod.constInst(sema.arena, .unneeded, zir.Inst.Ref.typed_value_map[i]);
    384     }
    385     i -= zir.Inst.Ref.typed_value_map.len;
    386 
    387     // Next section of indexes correspond to function parameters, if any.
    388     if (i < sema.param_inst_list.len) {
    389         return sema.param_inst_list[i];
    390     }
    391     i -= sema.param_inst_list.len;
    392 
    393     // Finally, the last section of indexes refers to the map of ZIR=>TZIR.
    394     return sema.inst_map[i];
    395 }
    396 
    397 fn resolveConstString(
    398     sema: *Sema,
    399     block: *Scope.Block,
    400     src: LazySrcLoc,
    401     zir_ref: zir.Inst.Ref,
    402 ) ![]u8 {
    403     const tzir_inst = try sema.resolveInst(zir_ref);
    404     const wanted_type = Type.initTag(.const_slice_u8);
    405     const coerced_inst = try sema.coerce(block, wanted_type, tzir_inst, src);
    406     const val = try sema.resolveConstValue(block, src, coerced_inst);
    407     return val.toAllocatedBytes(sema.arena);
    408 }
    409 
    410 fn resolveType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, zir_ref: zir.Inst.Ref) !Type {
    411     const tzir_inst = try sema.resolveInst(zir_ref);
    412     const wanted_type = Type.initTag(.@"type");
    413     const coerced_inst = try sema.coerce(block, wanted_type, tzir_inst, src);
    414     const val = try sema.resolveConstValue(block, src, coerced_inst);
    415     return val.toType(sema.arena);
    416 }
    417 
    418 fn resolveConstValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !Value {
    419     return (try sema.resolveDefinedValue(block, src, base)) orelse
    420         return sema.failWithNeededComptime(block, src);
    421 }
    422 
    423 fn resolveDefinedValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !?Value {
    424     if (base.value()) |val| {
    425         if (val.isUndef()) {
    426             return sema.failWithUseOfUndef(block, src);
    427         }
    428         return val;
    429     }
    430     return null;
    431 }
    432 
    433 fn failWithNeededComptime(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) InnerError {
    434     return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{});
    435 }
    436 
    437 fn failWithUseOfUndef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) InnerError {
    438     return sema.mod.fail(&block.base, src, "use of undefined value here causes undefined behavior", .{});
    439 }
    440 
    441 /// Appropriate to call when the coercion has already been done by result
    442 /// location semantics. Asserts the value fits in the provided `Int` type.
    443 /// Only supports `Int` types 64 bits or less.
    444 fn resolveAlreadyCoercedInt(
    445     sema: *Sema,
    446     block: *Scope.Block,
    447     src: LazySrcLoc,
    448     zir_ref: zir.Inst.Ref,
    449     comptime Int: type,
    450 ) !Int {
    451     comptime assert(@typeInfo(Int).Int.bits <= 64);
    452     const tzir_inst = try sema.resolveInst(zir_ref);
    453     const val = try sema.resolveConstValue(block, src, tzir_inst);
    454     switch (@typeInfo(Int).Int.signedness) {
    455         .signed => return @intCast(Int, val.toSignedInt()),
    456         .unsigned => return @intCast(Int, val.toUnsignedInt()),
    457     }
    458 }
    459 
    460 fn resolveInt(
    461     sema: *Sema,
    462     block: *Scope.Block,
    463     src: LazySrcLoc,
    464     zir_ref: zir.Inst.Ref,
    465     dest_type: Type,
    466 ) !u64 {
    467     const tzir_inst = try sema.resolveInst(zir_ref);
    468     const coerced = try sema.coerce(block, dest_type, tzir_inst, src);
    469     const val = try sema.resolveConstValue(block, src, coerced);
    470 
    471     return val.toUnsignedInt();
    472 }
    473 
    474 fn resolveInstConst(
    475     sema: *Sema,
    476     block: *Scope.Block,
    477     src: LazySrcLoc,
    478     zir_ref: zir.Inst.Ref,
    479 ) InnerError!TypedValue {
    480     const tzir_inst = try sema.resolveInst(zir_ref);
    481     const val = try sema.resolveConstValue(block, src, tzir_inst);
    482     return TypedValue{
    483         .ty = tzir_inst.ty,
    484         .val = val,
    485     };
    486 }
    487 
    488 fn zirConst(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
    489     const tracy = trace(@src());
    490     defer tracy.end();
    491 
    492     const tv_ptr = sema.code.instructions.items(.data)[inst].@"const";
    493     // Move the TypedValue from old memory to new memory. This allows freeing the ZIR instructions
    494     // after analysis. This happens, for example, with variable declaration initialization
    495     // expressions.
    496     const typed_value_copy = try tv_ptr.copy(sema.arena);
    497     return sema.mod.constInst(sema.arena, .unneeded, typed_value_copy);
    498 }
    499 
    500 fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
    501     const tracy = trace(@src());
    502     defer tracy.end();
    503     return sema.mod.fail(&block.base, sema.src, "TODO implement zir_sema.zirBitcastResultPtr", .{});
    504 }
    505 
    506 fn zirCoerceResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
    507     const tracy = trace(@src());
    508     defer tracy.end();
    509     return sema.mod.fail(&block.base, sema.src, "TODO implement zirCoerceResultPtr", .{});
    510 }
    511 
    512 fn zirRetPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
    513     const tracy = trace(@src());
    514     defer tracy.end();
    515 
    516     const src: LazySrcLoc = .unneeded;
    517     try sema.requireFunctionBlock(block, src);
    518     const fn_ty = sema.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
    519     const ret_type = fn_ty.fnReturnType();
    520     const ptr_type = try sema.mod.simplePtrType(sema.arena, ret_type, true, .One);
    521     return block.addNoOp(src, ptr_type, .alloc);
    522 }
    523 
    524 fn zirRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
    525     const tracy = trace(@src());
    526     defer tracy.end();
    527 
    528     const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
    529     const operand = try sema.resolveInst(inst_data.operand);
    530     return sema.analyzeRef(block, inst_data.src(), operand);
    531 }
    532 
    533 fn zirRetType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
    534     const tracy = trace(@src());
    535     defer tracy.end();
    536 
    537     const src: LazySrcLoc = .unneeded;
    538     try sema.requireFunctionBlock(block, src);
    539     const fn_ty = sema.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
    540     const ret_type = fn_ty.fnReturnType();
    541     return sema.mod.constType(sema.arena, src, ret_type);
    542 }
    543 
    544 fn zirEnsureResultUsed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
    545     const tracy = trace(@src());
    546     defer tracy.end();
    547 
    548     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
    549     const operand = try sema.resolveInst(inst_data.operand);
    550     const src = inst_data.src();
    551 
    552     return sema.ensureResultUsed(block, operand, src);
    553 }
    554 
    555 fn ensureResultUsed(
    556     sema: *Sema,
    557     block: *Scope.Block,
    558     operand: *Inst,
    559     src: LazySrcLoc,
    560 ) InnerError!void {
    561     switch (operand.ty.zigTypeTag()) {
    562         .Void, .NoReturn => return,
    563         else => return sema.mod.fail(&block.base, src, "expression value is ignored", .{}),
    564     }
    565 }
    566 
    567 fn zirEnsureResultNonError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
    568     const tracy = trace(@src());
    569     defer tracy.end();
    570 
    571     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
    572     const operand = try sema.resolveInst(inst_data.operand);
    573     const src = inst_data.src();
    574     switch (operand.ty.zigTypeTag()) {
    575         .ErrorSet, .ErrorUnion => return sema.mod.fail(&block.base, src, "error is discarded", .{}),
    576         else => return,
    577     }
    578 }
    579 
    580 fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
    581     const tracy = trace(@src());
    582     defer tracy.end();
    583 
    584     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
    585     const src = inst_data.src();
    586     const array_ptr = try sema.resolveInst(inst_data.operand);
    587 
    588     const elem_ty = array_ptr.ty.elemType();
    589     if (!elem_ty.isIndexable()) {
    590         const cond_src: LazySrcLoc = .{ .node_offset_for_cond = inst_data.src_node };
    591         const msg = msg: {
    592             const msg = try sema.mod.errMsg(
    593                 &block.base,
    594                 cond_src,
    595                 "type '{}' does not support indexing",
    596                 .{elem_ty},
    597             );
    598             errdefer msg.destroy(sema.gpa);
    599             try sema.mod.errNote(
    600                 &block.base,
    601                 cond_src,
    602                 msg,
    603                 "for loop operand must be an array, slice, tuple, or vector",
    604                 .{},
    605             );
    606             break :msg msg;
    607         };
    608         return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
    609     }
    610     const result_ptr = try sema.namedFieldPtr(block, src, array_ptr, "len", src);
    611     return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);
    612 }
    613 
    614 fn zirAlloc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
    615     const tracy = trace(@src());
    616     defer tracy.end();
    617 
    618     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
    619     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
    620     const var_decl_src = inst_data.src();
    621     const var_type = try sema.resolveType(block, ty_src, inst_data.operand);
    622     const ptr_type = try sema.mod.simplePtrType(sema.arena, var_type, true, .One);
    623     try sema.requireRuntimeBlock(block, var_decl_src);
    624     return block.addNoOp(var_decl_src, ptr_type, .alloc);
    625 }
    626 
    627 fn zirAllocMut(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
    628     const tracy = trace(@src());
    629     defer tracy.end();
    630 
    631     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
    632     const var_decl_src = inst_data.src();
    633     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
    634     const var_type = try sema.resolveType(block, ty_src, inst_data.operand);
    635     try sema.validateVarType(block, ty_src, var_type);
    636     const ptr_type = try sema.mod.simplePtrType(sema.arena, var_type, true, .One);
    637     try sema.requireRuntimeBlock(block, var_decl_src);
    638     return block.addNoOp(var_decl_src, ptr_type, .alloc);
    639 }
    640 
    641 fn zirAllocInferred(
    642     sema: *Sema,
    643     block: *Scope.Block,
    644     inst: zir.Inst.Index,
    645     inferred_alloc_ty: Type,
    646 ) InnerError!*Inst {
    647     const tracy = trace(@src());
    648     defer tracy.end();
    649 
    650     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
    651     const src = inst_data.src();
    652 
    653     const val_payload = try sema.arena.create(Value.Payload.InferredAlloc);
    654     val_payload.* = .{
    655         .data = .{},
    656     };
    657     // `Module.constInst` does not add the instruction to the block because it is
    658     // not needed in the case of constant values. However here, we plan to "downgrade"
    659     // to a normal instruction when we hit `resolve_inferred_alloc`. So we append
    660     // to the block even though it is currently a `.constant`.
    661     const result = try sema.mod.constInst(sema.arena, src, .{
    662         .ty = inferred_alloc_ty,
    663         .val = Value.initPayload(&val_payload.base),
    664     });
    665     try sema.requireFunctionBlock(block, src);
    666     try block.instructions.append(sema.gpa, result);
    667     return result;
    668 }
    669 
    670 fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
    671     const tracy = trace(@src());
    672     defer tracy.end();
    673 
    674     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
    675     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
    676     const ptr = try sema.resolveInst(inst_data.operand);
    677     const ptr_val = ptr.castTag(.constant).?.val;
    678     const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
    679     const peer_inst_list = inferred_alloc.data.stored_inst_list.items;
    680     const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list);
    681     const var_is_mut = switch (ptr.ty.tag()) {
    682         .inferred_alloc_const => false,
    683         .inferred_alloc_mut => true,
    684         else => unreachable,
    685     };
    686     if (var_is_mut) {
    687         try sema.validateVarType(block, ty_src, final_elem_ty);
    688     }
    689     const final_ptr_ty = try sema.mod.simplePtrType(sema.arena, final_elem_ty, true, .One);
    690 
    691     // Change it to a normal alloc.
    692     ptr.ty = final_ptr_ty;
    693     ptr.tag = .alloc;
    694 }
    695 
    696 fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
    697     const tracy = trace(@src());
    698     defer tracy.end();
    699 
    700     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
    701     const ptr = try sema.resolveInst(bin_inst.lhs);
    702     const value = try sema.resolveInst(bin_inst.rhs);
    703     const ptr_ty = try sema.mod.simplePtrType(sema.arena, value.ty, true, .One);
    704     // TODO detect when this store should be done at compile-time. For example,
    705     // if expressions should force it when the condition is compile-time known.
    706     const src: LazySrcLoc = .unneeded;
    707     try sema.requireRuntimeBlock(block, src);
    708     const bitcasted_ptr = try block.addUnOp(src, ptr_ty, .bitcast, ptr);
    709     return sema.storePtr(block, src, bitcasted_ptr, value);
    710 }
    711 
    712 fn zirStoreToInferredPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
    713     const tracy = trace(@src());
    714     defer tracy.end();
    715 
    716     const src: LazySrcLoc = .unneeded;
    717     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
    718     const ptr = try sema.resolveInst(bin_inst.lhs);
    719     const value = try sema.resolveInst(bin_inst.rhs);
    720     const inferred_alloc = ptr.castTag(.constant).?.val.castTag(.inferred_alloc).?;
    721     // Add the stored instruction to the set we will use to resolve peer types
    722     // for the inferred allocation.
    723     try inferred_alloc.data.stored_inst_list.append(sema.arena, value);
    724     // Create a runtime bitcast instruction with exactly the type the pointer wants.
    725     const ptr_ty = try sema.mod.simplePtrType(sema.arena, value.ty, true, .One);
    726     try sema.requireRuntimeBlock(block, src);
    727     const bitcasted_ptr = try block.addUnOp(src, ptr_ty, .bitcast, ptr);
    728     return sema.storePtr(block, src, bitcasted_ptr, value);
    729 }
    730 
    731 fn zirSetEvalBranchQuota(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
    732     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
    733     const src = inst_data.src();
    734     try sema.requireFunctionBlock(block, src);
    735     const quota = try sema.resolveAlreadyCoercedInt(block, src, inst_data.operand, u32);
    736     if (sema.branch_quota < quota)
    737         sema.branch_quota = quota;
    738 }
    739 
    740 fn zirStore(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
    741     const tracy = trace(@src());
    742     defer tracy.end();
    743 
    744     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
    745     const ptr = try sema.resolveInst(bin_inst.lhs);
    746     const value = try sema.resolveInst(bin_inst.rhs);
    747     return sema.storePtr(block, sema.src, ptr, value);
    748 }
    749 
    750 fn zirStoreNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
    751     const tracy = trace(@src());
    752     defer tracy.end();
    753 
    754     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
    755     const src = inst_data.src();
    756     const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
    757     const ptr = try sema.resolveInst(extra.lhs);
    758     const value = try sema.resolveInst(extra.rhs);
    759     return sema.storePtr(block, src, ptr, value);
    760 }
    761 
    762 fn zirParamType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
    763     const tracy = trace(@src());
    764     defer tracy.end();
    765 
    766     const src: LazySrcLoc = .unneeded;
    767     const inst_data = sema.code.instructions.items(.data)[inst].param_type;
    768     const fn_inst = try sema.resolveInst(inst_data.callee);
    769     const param_index = inst_data.param_index;
    770 
    771     const fn_ty: Type = switch (fn_inst.ty.zigTypeTag()) {
    772         .Fn => fn_inst.ty,
    773         .BoundFn => {
    774             return sema.mod.fail(&block.base, fn_inst.src, "TODO implement zirParamType for method call syntax", .{});
    775         },
    776         else => {
    777             return sema.mod.fail(&block.base, fn_inst.src, "expected function, found '{}'", .{fn_inst.ty});
    778         },
    779     };
    780 
    781     const param_count = fn_ty.fnParamLen();
    782     if (param_index >= param_count) {
    783         if (fn_ty.fnIsVarArgs()) {
    784             return sema.mod.constType(sema.arena, src, Type.initTag(.var_args_param));
    785         }
    786         return sema.mod.fail(&block.base, src, "arg index {d} out of bounds; '{}' has {d} argument(s)", .{
    787             param_index,
    788             fn_ty,
    789             param_count,
    790         });
    791     }
    792 
    793     // TODO support generic functions
    794     const param_type = fn_ty.fnParamType(param_index);
    795     return sema.mod.constType(sema.arena, src, param_type);
    796 }
    797 
    798 fn zirStr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
    799     const tracy = trace(@src());
    800     defer tracy.end();
    801 
    802     const zir_bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code);
    803 
    804     // `zir_bytes` references memory inside the ZIR module, which can get deallocated
    805     // after semantic analysis is complete, for example in the case of the initialization
    806     // expression of a variable declaration. We need the memory to be in the new
    807     // anonymous Decl's arena.
    808 
    809     var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
    810     errdefer new_decl_arena.deinit();
    811 
    812     const bytes = try new_decl_arena.allocator.dupe(u8, zir_bytes);
    813 
    814     const decl_ty = try Type.Tag.array_u8_sentinel_0.create(&new_decl_arena.allocator, bytes.len);
    815     const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, bytes);
    816 
    817     const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
    818         .ty = decl_ty,
    819         .val = decl_val,
    820     });
    821     return sema.analyzeDeclRef(block, .unneeded, new_decl);
    822 }
    823 
    824 fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
    825     const tracy = trace(@src());
    826     defer tracy.end();
    827 
    828     const int = sema.code.instructions.items(.data)[inst].int;
    829     return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int);
    830 }
    831 
    832 fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
    833     const tracy = trace(@src());
    834     defer tracy.end();
    835 
    836     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
    837     const src = inst_data.src();
    838     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
    839     const msg = try sema.resolveConstString(block, operand_src, inst_data.operand);
    840     return sema.mod.fail(&block.base, src, "{s}", .{msg});
    841 }
    842 
    843 fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
    844     var managed = sema.mod.compile_log_text.toManaged(sema.gpa);
    845     defer sema.mod.compile_log_text = managed.moveToUnmanaged();
    846     const writer = managed.writer();
    847 
    848     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
    849     const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index);
    850     const args = sema.code.refSlice(extra.end, extra.data.operands_len);
    851 
    852     for (args) |arg_ref, i| {
    853         if (i != 0) try writer.print(", ", .{});
    854 
    855         const arg = try sema.resolveInst(arg_ref);
    856         if (arg.value()) |val| {
    857             try writer.print("@as({}, {})", .{ arg.ty, val });
    858         } else {
    859             try writer.print("@as({}, [runtime value])", .{arg.ty});
    860         }
    861     }
    862     try writer.print("\n", .{});
    863 
    864     const gop = try sema.mod.compile_log_decls.getOrPut(sema.gpa, sema.owner_decl);
    865     if (!gop.found_existing) {
    866         gop.entry.value = inst_data.src().toSrcLoc(&block.base);
    867     }
    868 }
    869 
    870 fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
    871     const tracy = trace(@src());
    872     defer tracy.end();
    873 
    874     const src_node = sema.code.instructions.items(.data)[inst].node;
    875     const src: LazySrcLoc = .{ .node_offset = src_node };
    876     try sema.requireRuntimeBlock(block, src);
    877     return always_noreturn;
    878 }
    879 
    880 fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
    881     const tracy = trace(@src());
    882     defer tracy.end();
    883 
    884     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
    885     const src = inst_data.src();
    886     const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);
    887     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
    888 
    889     // TZIR expects a block outside the loop block too.
    890     const block_inst = try sema.arena.create(Inst.Block);
    891     block_inst.* = .{
    892         .base = .{
    893             .tag = Inst.Block.base_tag,
    894             .ty = undefined,
    895             .src = src,
    896         },
    897         .body = undefined,
    898     };
    899 
    900     var child_block = parent_block.makeSubBlock();
    901     child_block.label = Scope.Block.Label{
    902         .zir_block = inst,
    903         .merges = .{
    904             .results = .{},
    905             .br_list = .{},
    906             .block_inst = block_inst,
    907         },
    908     };
    909     const merges = &child_block.label.?.merges;
    910 
    911     defer child_block.instructions.deinit(sema.gpa);
    912     defer merges.results.deinit(sema.gpa);
    913     defer merges.br_list.deinit(sema.gpa);
    914 
    915     // Reserve space for a Loop instruction so that generated Break instructions can
    916     // point to it, even if it doesn't end up getting used because the code ends up being
    917     // comptime evaluated.
    918     const loop_inst = try sema.arena.create(Inst.Loop);
    919     loop_inst.* = .{
    920         .base = .{
    921             .tag = Inst.Loop.base_tag,
    922             .ty = Type.initTag(.noreturn),
    923             .src = src,
    924         },
    925         .body = undefined,
    926     };
    927 
    928     var loop_block = child_block.makeSubBlock();
    929     defer loop_block.instructions.deinit(sema.gpa);
    930 
    931     _ = try sema.analyzeBody(&loop_block, body);
    932 
    933     // Loop repetition is implied so the last instruction may or may not be a noreturn instruction.
    934 
    935     try child_block.instructions.append(sema.gpa, &loop_inst.base);
    936     loop_inst.body = .{ .instructions = try sema.arena.dupe(*Inst, loop_block.instructions.items) };
    937 
    938     return sema.analyzeBlockBody(parent_block, src, &child_block, merges);
    939 }
    940 
    941 fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
    942     const tracy = trace(@src());
    943     defer tracy.end();
    944 
    945     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
    946     const src = inst_data.src();
    947     const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);
    948     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
    949 
    950     // Reserve space for a Block instruction so that generated Break instructions can
    951     // point to it, even if it doesn't end up getting used because the code ends up being
    952     // comptime evaluated.
    953     const block_inst = try sema.arena.create(Inst.Block);
    954     block_inst.* = .{
    955         .base = .{
    956             .tag = Inst.Block.base_tag,
    957             .ty = undefined, // Set after analysis.
    958             .src = src,
    959         },
    960         .body = undefined,
    961     };
    962 
    963     var child_block: Scope.Block = .{
    964         .parent = parent_block,
    965         .sema = sema,
    966         .src_decl = parent_block.src_decl,
    967         .instructions = .{},
    968         // TODO @as here is working around a stage1 miscompilation bug :(
    969         .label = @as(?Scope.Block.Label, Scope.Block.Label{
    970             .zir_block = inst,
    971             .merges = .{
    972                 .results = .{},
    973                 .br_list = .{},
    974                 .block_inst = block_inst,
    975             },
    976         }),
    977         .inlining = parent_block.inlining,
    978         .is_comptime = parent_block.is_comptime,
    979     };
    980     const merges = &child_block.label.?.merges;
    981 
    982     defer child_block.instructions.deinit(sema.gpa);
    983     defer merges.results.deinit(sema.gpa);
    984     defer merges.br_list.deinit(sema.gpa);
    985 
    986     _ = try sema.analyzeBody(&child_block, body);
    987 
    988     return sema.analyzeBlockBody(parent_block, src, &child_block, merges);
    989 }
    990 
    991 fn analyzeBlockBody(
    992     sema: *Sema,
    993     parent_block: *Scope.Block,
    994     src: LazySrcLoc,
    995     child_block: *Scope.Block,
    996     merges: *Scope.Block.Merges,
    997 ) InnerError!*Inst {
    998     const tracy = trace(@src());
    999     defer tracy.end();
   1000 
   1001     // Blocks must terminate with noreturn instruction.
   1002     assert(child_block.instructions.items.len != 0);
   1003     assert(child_block.instructions.items[child_block.instructions.items.len - 1].ty.isNoReturn());
   1004 
   1005     if (merges.results.items.len == 0) {
   1006         // No need for a block instruction. We can put the new instructions
   1007         // directly into the parent block.
   1008         const copied_instructions = try sema.arena.dupe(*Inst, child_block.instructions.items);
   1009         try parent_block.instructions.appendSlice(sema.gpa, copied_instructions);
   1010         return copied_instructions[copied_instructions.len - 1];
   1011     }
   1012     if (merges.results.items.len == 1) {
   1013         const last_inst_index = child_block.instructions.items.len - 1;
   1014         const last_inst = child_block.instructions.items[last_inst_index];
   1015         if (last_inst.breakBlock()) |br_block| {
   1016             if (br_block == merges.block_inst) {
   1017                 // No need for a block instruction. We can put the new instructions directly
   1018                 // into the parent block. Here we omit the break instruction.
   1019                 const copied_instructions = try sema.arena.dupe(*Inst, child_block.instructions.items[0..last_inst_index]);
   1020                 try parent_block.instructions.appendSlice(sema.gpa, copied_instructions);
   1021                 return merges.results.items[0];
   1022             }
   1023         }
   1024     }
   1025     // It is impossible to have the number of results be > 1 in a comptime scope.
   1026     assert(!child_block.is_comptime); // Should already got a compile error in the condbr condition.
   1027 
   1028     // Need to set the type and emit the Block instruction. This allows machine code generation
   1029     // to emit a jump instruction to after the block when it encounters the break.
   1030     try parent_block.instructions.append(sema.gpa, &merges.block_inst.base);
   1031     const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items);
   1032     merges.block_inst.base.ty = resolved_ty;
   1033     merges.block_inst.body = .{
   1034         .instructions = try sema.arena.dupe(*Inst, child_block.instructions.items),
   1035     };
   1036     // Now that the block has its type resolved, we need to go back into all the break
   1037     // instructions, and insert type coercion on the operands.
   1038     for (merges.br_list.items) |br| {
   1039         if (br.operand.ty.eql(resolved_ty)) {
   1040             // No type coercion needed.
   1041             continue;
   1042         }
   1043         var coerce_block = parent_block.makeSubBlock();
   1044         defer coerce_block.instructions.deinit(sema.gpa);
   1045         const coerced_operand = try sema.coerce(&coerce_block, resolved_ty, br.operand, br.operand.src);
   1046         // If no instructions were produced, such as in the case of a coercion of a
   1047         // constant value to a new type, we can simply point the br operand to it.
   1048         if (coerce_block.instructions.items.len == 0) {
   1049             br.operand = coerced_operand;
   1050             continue;
   1051         }
   1052         assert(coerce_block.instructions.items[coerce_block.instructions.items.len - 1] == coerced_operand);
   1053         // Here we depend on the br instruction having been over-allocated (if necessary)
   1054         // inside zirBreak so that it can be converted into a br_block_flat instruction.
   1055         const br_src = br.base.src;
   1056         const br_ty = br.base.ty;
   1057         const br_block_flat = @ptrCast(*Inst.BrBlockFlat, br);
   1058         br_block_flat.* = .{
   1059             .base = .{
   1060                 .src = br_src,
   1061                 .ty = br_ty,
   1062                 .tag = .br_block_flat,
   1063             },
   1064             .block = merges.block_inst,
   1065             .body = .{
   1066                 .instructions = try sema.arena.dupe(*Inst, coerce_block.instructions.items),
   1067             },
   1068         };
   1069     }
   1070     return &merges.block_inst.base;
   1071 }
   1072 
   1073 fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
   1074     const tracy = trace(@src());
   1075     defer tracy.end();
   1076 
   1077     const src_node = sema.code.instructions.items(.data)[inst].node;
   1078     const src: LazySrcLoc = .{ .node_offset = src_node };
   1079     try sema.requireRuntimeBlock(block, src);
   1080     _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint);
   1081 }
   1082 
   1083 fn zirBreak(sema: *Sema, start_block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
   1084     const tracy = trace(@src());
   1085     defer tracy.end();
   1086 
   1087     const inst_data = sema.code.instructions.items(.data)[inst].@"break";
   1088     const src = sema.src;
   1089     const operand = try sema.resolveInst(inst_data.operand);
   1090     const zir_block = inst_data.block_inst;
   1091 
   1092     var block = start_block;
   1093     while (true) {
   1094         if (block.label) |*label| {
   1095             if (label.zir_block == zir_block) {
   1096                 // Here we add a br instruction, but we over-allocate a little bit
   1097                 // (if necessary) to make it possible to convert the instruction into
   1098                 // a br_block_flat instruction later.
   1099                 const br = @ptrCast(*Inst.Br, try sema.arena.alignedAlloc(
   1100                     u8,
   1101                     Inst.convertable_br_align,
   1102                     Inst.convertable_br_size,
   1103                 ));
   1104                 br.* = .{
   1105                     .base = .{
   1106                         .tag = .br,
   1107                         .ty = Type.initTag(.noreturn),
   1108                         .src = src,
   1109                     },
   1110                     .operand = operand,
   1111                     .block = label.merges.block_inst,
   1112                 };
   1113                 try start_block.instructions.append(sema.gpa, &br.base);
   1114                 try label.merges.results.append(sema.gpa, operand);
   1115                 try label.merges.br_list.append(sema.gpa, br);
   1116                 return inst;
   1117             }
   1118         }
   1119         block = block.parent.?;
   1120     }
   1121 }
   1122 
   1123 fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
   1124     const tracy = trace(@src());
   1125     defer tracy.end();
   1126 
   1127     // We do not set sema.src here because dbg_stmt instructions are only emitted for
   1128     // ZIR code that possibly will need to generate runtime code. So error messages
   1129     // and other source locations must not rely on sema.src being set from dbg_stmt
   1130     // instructions.
   1131     if (block.is_comptime) return;
   1132 
   1133     const src_node = sema.code.instructions.items(.data)[inst].node;
   1134     const src: LazySrcLoc = .{ .node_offset = src_node };
   1135 
   1136     const src_loc = src.toSrcLoc(&block.base);
   1137     const abs_byte_off = try src_loc.byteOffset();
   1138     _ = try block.addDbgStmt(src, abs_byte_off);
   1139 }
   1140 
   1141 fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1142     const tracy = trace(@src());
   1143     defer tracy.end();
   1144 
   1145     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1146     const src = inst_data.src();
   1147     const decl = sema.code.decls[inst_data.payload_index];
   1148     return sema.analyzeDeclRef(block, src, decl);
   1149 }
   1150 
   1151 fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1152     const tracy = trace(@src());
   1153     defer tracy.end();
   1154 
   1155     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1156     const src = inst_data.src();
   1157     const decl = sema.code.decls[inst_data.payload_index];
   1158     return sema.analyzeDeclVal(block, src, decl);
   1159 }
   1160 
   1161 fn zirCallNone(
   1162     sema: *Sema,
   1163     block: *Scope.Block,
   1164     inst: zir.Inst.Index,
   1165     ensure_result_used: bool,
   1166 ) InnerError!*Inst {
   1167     const tracy = trace(@src());
   1168     defer tracy.end();
   1169 
   1170     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   1171     const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
   1172 
   1173     return sema.analyzeCall(block, inst_data.operand, func_src, inst_data.src(), .auto, ensure_result_used, &.{});
   1174 }
   1175 
   1176 fn zirCall(
   1177     sema: *Sema,
   1178     block: *Scope.Block,
   1179     inst: zir.Inst.Index,
   1180     modifier: std.builtin.CallOptions.Modifier,
   1181     ensure_result_used: bool,
   1182 ) InnerError!*Inst {
   1183     const tracy = trace(@src());
   1184     defer tracy.end();
   1185 
   1186     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1187     const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
   1188     const call_src = inst_data.src();
   1189     const extra = sema.code.extraData(zir.Inst.Call, inst_data.payload_index);
   1190     const args = sema.code.refSlice(extra.end, extra.data.args_len);
   1191 
   1192     return sema.analyzeCall(block, extra.data.callee, func_src, call_src, modifier, ensure_result_used, args);
   1193 }
   1194 
   1195 fn analyzeCall(
   1196     sema: *Sema,
   1197     block: *Scope.Block,
   1198     zir_func: zir.Inst.Ref,
   1199     func_src: LazySrcLoc,
   1200     call_src: LazySrcLoc,
   1201     modifier: std.builtin.CallOptions.Modifier,
   1202     ensure_result_used: bool,
   1203     zir_args: []const zir.Inst.Ref,
   1204 ) InnerError!*ir.Inst {
   1205     const func = try sema.resolveInst(zir_func);
   1206 
   1207     if (func.ty.zigTypeTag() != .Fn)
   1208         return sema.mod.fail(&block.base, func_src, "type '{}' not a function", .{func.ty});
   1209 
   1210     const cc = func.ty.fnCallingConvention();
   1211     if (cc == .Naked) {
   1212         // TODO add error note: declared here
   1213         return sema.mod.fail(
   1214             &block.base,
   1215             func_src,
   1216             "unable to call function with naked calling convention",
   1217             .{},
   1218         );
   1219     }
   1220     const fn_params_len = func.ty.fnParamLen();
   1221     if (func.ty.fnIsVarArgs()) {
   1222         assert(cc == .C);
   1223         if (zir_args.len < fn_params_len) {
   1224             // TODO add error note: declared here
   1225             return sema.mod.fail(
   1226                 &block.base,
   1227                 func_src,
   1228                 "expected at least {d} argument(s), found {d}",
   1229                 .{ fn_params_len, zir_args.len },
   1230             );
   1231         }
   1232     } else if (fn_params_len != zir_args.len) {
   1233         // TODO add error note: declared here
   1234         return sema.mod.fail(
   1235             &block.base,
   1236             func_src,
   1237             "expected {d} argument(s), found {d}",
   1238             .{ fn_params_len, zir_args.len },
   1239         );
   1240     }
   1241 
   1242     if (modifier == .compile_time) {
   1243         return sema.mod.fail(&block.base, call_src, "TODO implement comptime function calls", .{});
   1244     }
   1245     if (modifier != .auto) {
   1246         return sema.mod.fail(&block.base, call_src, "TODO implement call with modifier {}", .{modifier});
   1247     }
   1248 
   1249     // TODO handle function calls of generic functions
   1250     const casted_args = try sema.arena.alloc(*Inst, zir_args.len);
   1251     for (zir_args) |zir_arg, i| {
   1252         // the args are already casted to the result of a param type instruction.
   1253         casted_args[i] = try sema.resolveInst(zir_arg);
   1254     }
   1255 
   1256     const ret_type = func.ty.fnReturnType();
   1257 
   1258     const is_comptime_call = block.is_comptime or modifier == .compile_time;
   1259     const is_inline_call = is_comptime_call or modifier == .always_inline or
   1260         func.ty.fnCallingConvention() == .Inline;
   1261     const result: *Inst = if (is_inline_call) res: {
   1262         const func_val = try sema.resolveConstValue(block, func_src, func);
   1263         const module_fn = switch (func_val.tag()) {
   1264             .function => func_val.castTag(.function).?.data,
   1265             .extern_fn => return sema.mod.fail(&block.base, call_src, "{s} call of extern function", .{
   1266                 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
   1267             }),
   1268             else => unreachable,
   1269         };
   1270 
   1271         // Analyze the ZIR. The same ZIR gets analyzed into a runtime function
   1272         // or an inlined call depending on what union tag the `label` field is
   1273         // set to in the `Scope.Block`.
   1274         // This block instruction will be used to capture the return value from the
   1275         // inlined function.
   1276         const block_inst = try sema.arena.create(Inst.Block);
   1277         block_inst.* = .{
   1278             .base = .{
   1279                 .tag = Inst.Block.base_tag,
   1280                 .ty = ret_type,
   1281                 .src = call_src,
   1282             },
   1283             .body = undefined,
   1284         };
   1285         // This one is shared among sub-blocks within the same callee, but not
   1286         // shared among the entire inline/comptime call stack.
   1287         var inlining: Scope.Block.Inlining = .{
   1288             .merges = .{
   1289                 .results = .{},
   1290                 .br_list = .{},
   1291                 .block_inst = block_inst,
   1292             },
   1293         };
   1294         var inline_sema: Sema = .{
   1295             .mod = sema.mod,
   1296             .gpa = sema.mod.gpa,
   1297             .arena = sema.arena,
   1298             .code = module_fn.zir,
   1299             .inst_map = try sema.gpa.alloc(*ir.Inst, module_fn.zir.instructions.len),
   1300             .owner_decl = sema.owner_decl,
   1301             .owner_func = sema.owner_func,
   1302             .func = module_fn,
   1303             .param_inst_list = casted_args,
   1304             .branch_quota = sema.branch_quota,
   1305             .branch_count = sema.branch_count,
   1306         };
   1307         defer sema.gpa.free(inline_sema.inst_map);
   1308 
   1309         var child_block: Scope.Block = .{
   1310             .parent = null,
   1311             .sema = &inline_sema,
   1312             .src_decl = module_fn.owner_decl,
   1313             .instructions = .{},
   1314             .label = null,
   1315             .inlining = &inlining,
   1316             .is_comptime = is_comptime_call,
   1317         };
   1318 
   1319         const merges = &child_block.inlining.?.merges;
   1320 
   1321         defer child_block.instructions.deinit(sema.gpa);
   1322         defer merges.results.deinit(sema.gpa);
   1323         defer merges.br_list.deinit(sema.gpa);
   1324 
   1325         try inline_sema.emitBackwardBranch(&child_block, call_src);
   1326 
   1327         // This will have return instructions analyzed as break instructions to
   1328         // the block_inst above.
   1329         _ = try inline_sema.root(&child_block);
   1330 
   1331         const result = try inline_sema.analyzeBlockBody(block, call_src, &child_block, merges);
   1332 
   1333         sema.branch_quota = inline_sema.branch_quota;
   1334         sema.branch_count = inline_sema.branch_count;
   1335 
   1336         break :res result;
   1337     } else res: {
   1338         try sema.requireRuntimeBlock(block, call_src);
   1339         break :res try block.addCall(call_src, ret_type, func, casted_args);
   1340     };
   1341 
   1342     if (ensure_result_used) {
   1343         try sema.ensureResultUsed(block, result, call_src);
   1344     }
   1345     return result;
   1346 }
   1347 
   1348 fn zirIntType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1349     const tracy = trace(@src());
   1350     defer tracy.end();
   1351 
   1352     const int_type = sema.code.instructions.items(.data)[inst].int_type;
   1353     const src = int_type.src();
   1354     const ty = try Module.makeIntType(sema.arena, int_type.signedness, int_type.bit_count);
   1355 
   1356     return sema.mod.constType(sema.arena, src, ty);
   1357 }
   1358 
   1359 fn zirOptionalType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1360     const tracy = trace(@src());
   1361     defer tracy.end();
   1362 
   1363     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   1364     const src = inst_data.src();
   1365     const child_type = try sema.resolveType(block, src, inst_data.operand);
   1366     const opt_type = try sema.mod.optionalType(sema.arena, child_type);
   1367 
   1368     return sema.mod.constType(sema.arena, src, opt_type);
   1369 }
   1370 
   1371 fn zirOptionalTypeFromPtrElem(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1372     const tracy = trace(@src());
   1373     defer tracy.end();
   1374 
   1375     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   1376     const ptr = try sema.resolveInst(inst_data.operand);
   1377     const elem_ty = ptr.ty.elemType();
   1378     const opt_ty = try sema.mod.optionalType(sema.arena, elem_ty);
   1379 
   1380     return sema.mod.constType(sema.arena, inst_data.src(), opt_ty);
   1381 }
   1382 
   1383 fn zirArrayType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1384     const tracy = trace(@src());
   1385     defer tracy.end();
   1386 
   1387     // TODO these should be lazily evaluated
   1388     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
   1389     const len = try sema.resolveInstConst(block, .unneeded, bin_inst.lhs);
   1390     const elem_type = try sema.resolveType(block, .unneeded, bin_inst.rhs);
   1391     const array_ty = try sema.mod.arrayType(sema.arena, len.val.toUnsignedInt(), null, elem_type);
   1392 
   1393     return sema.mod.constType(sema.arena, .unneeded, array_ty);
   1394 }
   1395 
   1396 fn zirArrayTypeSentinel(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1397     const tracy = trace(@src());
   1398     defer tracy.end();
   1399 
   1400     // TODO these should be lazily evaluated
   1401     const inst_data = sema.code.instructions.items(.data)[inst].array_type_sentinel;
   1402     const len = try sema.resolveInstConst(block, .unneeded, inst_data.len);
   1403     const extra = sema.code.extraData(zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data;
   1404     const sentinel = try sema.resolveInstConst(block, .unneeded, extra.sentinel);
   1405     const elem_type = try sema.resolveType(block, .unneeded, extra.elem_type);
   1406     const array_ty = try sema.mod.arrayType(sema.arena, len.val.toUnsignedInt(), sentinel.val, elem_type);
   1407 
   1408     return sema.mod.constType(sema.arena, .unneeded, array_ty);
   1409 }
   1410 
   1411 fn zirErrorUnionType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1412     const tracy = trace(@src());
   1413     defer tracy.end();
   1414 
   1415     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1416     const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
   1417     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
   1418     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   1419     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
   1420     const error_union = try sema.resolveType(block, lhs_src, extra.lhs);
   1421     const payload = try sema.resolveType(block, rhs_src, extra.rhs);
   1422 
   1423     if (error_union.zigTypeTag() != .ErrorSet) {
   1424         return sema.mod.fail(&block.base, lhs_src, "expected error set type, found {}", .{
   1425             error_union.elemType(),
   1426         });
   1427     }
   1428     const err_union_ty = try sema.mod.errorUnionType(sema.arena, error_union, payload);
   1429     return sema.mod.constType(sema.arena, src, err_union_ty);
   1430 }
   1431 
   1432 fn zirErrorValue(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1433     const tracy = trace(@src());
   1434     defer tracy.end();
   1435 
   1436     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
   1437     const src = inst_data.src();
   1438 
   1439     // Create an anonymous error set type with only this error value, and return the value.
   1440     const entry = try sema.mod.getErrorValue(inst_data.get(sema.code));
   1441     const result_type = try Type.Tag.error_set_single.create(sema.arena, entry.key);
   1442     return sema.mod.constInst(sema.arena, src, .{
   1443         .ty = result_type,
   1444         .val = try Value.Tag.@"error".create(sema.arena, .{
   1445             .name = entry.key,
   1446         }),
   1447     });
   1448 }
   1449 
   1450 fn zirErrorToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1451     const tracy = trace(@src());
   1452     defer tracy.end();
   1453 
   1454     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   1455     const src = inst_data.src();
   1456     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   1457     const op = try sema.resolveInst(inst_data.operand);
   1458     const op_coerced = try sema.coerce(block, Type.initTag(.anyerror), op, operand_src);
   1459 
   1460     if (op_coerced.value()) |val| {
   1461         const payload = try sema.arena.create(Value.Payload.U64);
   1462         payload.* = .{
   1463             .base = .{ .tag = .int_u64 },
   1464             .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value,
   1465         };
   1466         return sema.mod.constInst(sema.arena, src, .{
   1467             .ty = Type.initTag(.u16),
   1468             .val = Value.initPayload(&payload.base),
   1469         });
   1470     }
   1471 
   1472     try sema.requireRuntimeBlock(block, src);
   1473     return block.addUnOp(src, Type.initTag(.u16), .error_to_int, op_coerced);
   1474 }
   1475 
   1476 fn zirIntToError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1477     const tracy = trace(@src());
   1478     defer tracy.end();
   1479 
   1480     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   1481     const src = inst_data.src();
   1482     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   1483 
   1484     const op = try sema.resolveInst(inst_data.operand);
   1485 
   1486     if (try sema.resolveDefinedValue(block, operand_src, op)) |value| {
   1487         const int = value.toUnsignedInt();
   1488         if (int > sema.mod.global_error_set.count() or int == 0)
   1489             return sema.mod.fail(&block.base, operand_src, "integer value {d} represents no error", .{int});
   1490         const payload = try sema.arena.create(Value.Payload.Error);
   1491         payload.* = .{
   1492             .base = .{ .tag = .@"error" },
   1493             .data = .{ .name = sema.mod.error_name_list.items[int] },
   1494         };
   1495         return sema.mod.constInst(sema.arena, src, .{
   1496             .ty = Type.initTag(.anyerror),
   1497             .val = Value.initPayload(&payload.base),
   1498         });
   1499     }
   1500     try sema.requireRuntimeBlock(block, src);
   1501     if (block.wantSafety()) {
   1502         return sema.mod.fail(&block.base, src, "TODO: get max errors in compilation", .{});
   1503         // const is_gt_max = @panic("TODO get max errors in compilation");
   1504         // try sema.addSafetyCheck(block, is_gt_max, .invalid_error_code);
   1505     }
   1506     return block.addUnOp(src, Type.initTag(.anyerror), .int_to_error, op);
   1507 }
   1508 
   1509 fn zirMergeErrorSets(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1510     const tracy = trace(@src());
   1511     defer tracy.end();
   1512 
   1513     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1514     const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
   1515     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
   1516     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   1517     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
   1518     const lhs_ty = try sema.resolveType(block, lhs_src, extra.lhs);
   1519     const rhs_ty = try sema.resolveType(block, rhs_src, extra.rhs);
   1520     if (rhs_ty.zigTypeTag() != .ErrorSet)
   1521         return sema.mod.fail(&block.base, rhs_src, "expected error set type, found {}", .{rhs_ty});
   1522     if (lhs_ty.zigTypeTag() != .ErrorSet)
   1523         return sema.mod.fail(&block.base, lhs_src, "expected error set type, found {}", .{lhs_ty});
   1524 
   1525     // Anything merged with anyerror is anyerror.
   1526     if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror) {
   1527         return sema.mod.constInst(sema.arena, src, .{
   1528             .ty = Type.initTag(.type),
   1529             .val = Value.initTag(.anyerror_type),
   1530         });
   1531     }
   1532     // When we support inferred error sets, we'll want to use a data structure that can
   1533     // represent a merged set of errors without forcing them to be resolved here. Until then
   1534     // we re-use the same data structure that is used for explicit error set declarations.
   1535     var set: std.StringHashMapUnmanaged(void) = .{};
   1536     defer set.deinit(sema.gpa);
   1537 
   1538     switch (lhs_ty.tag()) {
   1539         .error_set_single => {
   1540             const name = lhs_ty.castTag(.error_set_single).?.data;
   1541             try set.put(sema.gpa, name, {});
   1542         },
   1543         .error_set => {
   1544             const lhs_set = lhs_ty.castTag(.error_set).?.data;
   1545             try set.ensureCapacity(sema.gpa, set.count() + lhs_set.names_len);
   1546             for (lhs_set.names_ptr[0..lhs_set.names_len]) |name| {
   1547                 set.putAssumeCapacityNoClobber(name, {});
   1548             }
   1549         },
   1550         else => unreachable,
   1551     }
   1552     switch (rhs_ty.tag()) {
   1553         .error_set_single => {
   1554             const name = rhs_ty.castTag(.error_set_single).?.data;
   1555             try set.put(sema.gpa, name, {});
   1556         },
   1557         .error_set => {
   1558             const rhs_set = rhs_ty.castTag(.error_set).?.data;
   1559             try set.ensureCapacity(sema.gpa, set.count() + rhs_set.names_len);
   1560             for (rhs_set.names_ptr[0..rhs_set.names_len]) |name| {
   1561                 set.putAssumeCapacity(name, {});
   1562             }
   1563         },
   1564         else => unreachable,
   1565     }
   1566 
   1567     const new_names = try sema.arena.alloc([]const u8, set.count());
   1568     var it = set.iterator();
   1569     var i: usize = 0;
   1570     while (it.next()) |entry| : (i += 1) {
   1571         new_names[i] = entry.key;
   1572     }
   1573 
   1574     const new_error_set = try sema.arena.create(Module.ErrorSet);
   1575     new_error_set.* = .{
   1576         .owner_decl = sema.owner_decl,
   1577         .node_offset = inst_data.src_node,
   1578         .names_ptr = new_names.ptr,
   1579         .names_len = @intCast(u32, new_names.len),
   1580     };
   1581     const error_set_ty = try Type.Tag.error_set.create(sema.arena, new_error_set);
   1582     return sema.mod.constInst(sema.arena, src, .{
   1583         .ty = Type.initTag(.type),
   1584         .val = try Value.Tag.ty.create(sema.arena, error_set_ty),
   1585     });
   1586 }
   1587 
   1588 fn zirEnumLiteral(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1589     const tracy = trace(@src());
   1590     defer tracy.end();
   1591 
   1592     const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
   1593     const src = inst_data.src();
   1594     const duped_name = try sema.arena.dupe(u8, inst_data.get(sema.code));
   1595     return sema.mod.constInst(sema.arena, src, .{
   1596         .ty = Type.initTag(.enum_literal),
   1597         .val = try Value.Tag.enum_literal.create(sema.arena, duped_name),
   1598     });
   1599 }
   1600 
   1601 fn zirEnumLiteralSmall(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1602     const tracy = trace(@src());
   1603     defer tracy.end();
   1604 
   1605     const name = sema.code.instructions.items(.data)[inst].small_str.get();
   1606     const src: LazySrcLoc = .unneeded;
   1607     const duped_name = try sema.arena.dupe(u8, name);
   1608     return sema.mod.constInst(sema.arena, src, .{
   1609         .ty = Type.initTag(.enum_literal),
   1610         .val = try Value.Tag.enum_literal.create(sema.arena, duped_name),
   1611     });
   1612 }
   1613 
   1614 /// Pointer in, pointer out.
   1615 fn zirOptionalPayloadPtr(
   1616     sema: *Sema,
   1617     block: *Scope.Block,
   1618     inst: zir.Inst.Index,
   1619     safety_check: bool,
   1620 ) InnerError!*Inst {
   1621     const tracy = trace(@src());
   1622     defer tracy.end();
   1623 
   1624     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   1625     const optional_ptr = try sema.resolveInst(inst_data.operand);
   1626     assert(optional_ptr.ty.zigTypeTag() == .Pointer);
   1627     const src = inst_data.src();
   1628 
   1629     const opt_type = optional_ptr.ty.elemType();
   1630     if (opt_type.zigTypeTag() != .Optional) {
   1631         return sema.mod.fail(&block.base, src, "expected optional type, found {}", .{opt_type});
   1632     }
   1633 
   1634     const child_type = try opt_type.optionalChildAlloc(sema.arena);
   1635     const child_pointer = try sema.mod.simplePtrType(sema.arena, child_type, !optional_ptr.ty.isConstPtr(), .One);
   1636 
   1637     if (optional_ptr.value()) |pointer_val| {
   1638         const val = try pointer_val.pointerDeref(sema.arena);
   1639         if (val.isNull()) {
   1640             return sema.mod.fail(&block.base, src, "unable to unwrap null", .{});
   1641         }
   1642         // The same Value represents the pointer to the optional and the payload.
   1643         return sema.mod.constInst(sema.arena, src, .{
   1644             .ty = child_pointer,
   1645             .val = pointer_val,
   1646         });
   1647     }
   1648 
   1649     try sema.requireRuntimeBlock(block, src);
   1650     if (safety_check and block.wantSafety()) {
   1651         const is_non_null = try block.addUnOp(src, Type.initTag(.bool), .is_non_null_ptr, optional_ptr);
   1652         try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
   1653     }
   1654     return block.addUnOp(src, child_pointer, .optional_payload_ptr, optional_ptr);
   1655 }
   1656 
   1657 /// Value in, value out.
   1658 fn zirOptionalPayload(
   1659     sema: *Sema,
   1660     block: *Scope.Block,
   1661     inst: zir.Inst.Index,
   1662     safety_check: bool,
   1663 ) InnerError!*Inst {
   1664     const tracy = trace(@src());
   1665     defer tracy.end();
   1666 
   1667     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   1668     const src = inst_data.src();
   1669     const operand = try sema.resolveInst(inst_data.operand);
   1670     const opt_type = operand.ty;
   1671     if (opt_type.zigTypeTag() != .Optional) {
   1672         return sema.mod.fail(&block.base, src, "expected optional type, found {}", .{opt_type});
   1673     }
   1674 
   1675     const child_type = try opt_type.optionalChildAlloc(sema.arena);
   1676 
   1677     if (operand.value()) |val| {
   1678         if (val.isNull()) {
   1679             return sema.mod.fail(&block.base, src, "unable to unwrap null", .{});
   1680         }
   1681         return sema.mod.constInst(sema.arena, src, .{
   1682             .ty = child_type,
   1683             .val = val,
   1684         });
   1685     }
   1686 
   1687     try sema.requireRuntimeBlock(block, src);
   1688     if (safety_check and block.wantSafety()) {
   1689         const is_non_null = try block.addUnOp(src, Type.initTag(.bool), .is_non_null, operand);
   1690         try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
   1691     }
   1692     return block.addUnOp(src, child_type, .optional_payload, operand);
   1693 }
   1694 
   1695 /// Value in, value out
   1696 fn zirErrUnionPayload(
   1697     sema: *Sema,
   1698     block: *Scope.Block,
   1699     inst: zir.Inst.Index,
   1700     safety_check: bool,
   1701 ) InnerError!*Inst {
   1702     const tracy = trace(@src());
   1703     defer tracy.end();
   1704 
   1705     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   1706     const src = inst_data.src();
   1707     const operand = try sema.resolveInst(inst_data.operand);
   1708     if (operand.ty.zigTypeTag() != .ErrorUnion)
   1709         return sema.mod.fail(&block.base, operand.src, "expected error union type, found '{}'", .{operand.ty});
   1710 
   1711     if (operand.value()) |val| {
   1712         if (val.getError()) |name| {
   1713             return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});
   1714         }
   1715         const data = val.castTag(.error_union).?.data;
   1716         return sema.mod.constInst(sema.arena, src, .{
   1717             .ty = operand.ty.castTag(.error_union).?.data.payload,
   1718             .val = data,
   1719         });
   1720     }
   1721     try sema.requireRuntimeBlock(block, src);
   1722     if (safety_check and block.wantSafety()) {
   1723         const is_non_err = try block.addUnOp(src, Type.initTag(.bool), .is_err, operand);
   1724         try sema.addSafetyCheck(block, is_non_err, .unwrap_errunion);
   1725     }
   1726     return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_payload, operand);
   1727 }
   1728 
   1729 /// Pointer in, pointer out.
   1730 fn zirErrUnionPayloadPtr(
   1731     sema: *Sema,
   1732     block: *Scope.Block,
   1733     inst: zir.Inst.Index,
   1734     safety_check: bool,
   1735 ) InnerError!*Inst {
   1736     const tracy = trace(@src());
   1737     defer tracy.end();
   1738 
   1739     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   1740     const src = inst_data.src();
   1741     const operand = try sema.resolveInst(inst_data.operand);
   1742     assert(operand.ty.zigTypeTag() == .Pointer);
   1743 
   1744     if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)
   1745         return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand.ty.elemType()});
   1746 
   1747     const operand_pointer_ty = try sema.mod.simplePtrType(sema.arena, operand.ty.elemType().castTag(.error_union).?.data.payload, !operand.ty.isConstPtr(), .One);
   1748 
   1749     if (operand.value()) |pointer_val| {
   1750         const val = try pointer_val.pointerDeref(sema.arena);
   1751         if (val.getError()) |name| {
   1752             return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});
   1753         }
   1754         const data = val.castTag(.error_union).?.data;
   1755         // The same Value represents the pointer to the error union and the payload.
   1756         return sema.mod.constInst(sema.arena, src, .{
   1757             .ty = operand_pointer_ty,
   1758             .val = try Value.Tag.ref_val.create(
   1759                 sema.arena,
   1760                 data,
   1761             ),
   1762         });
   1763     }
   1764 
   1765     try sema.requireRuntimeBlock(block, src);
   1766     if (safety_check and block.wantSafety()) {
   1767         const is_non_err = try block.addUnOp(src, Type.initTag(.bool), .is_err, operand);
   1768         try sema.addSafetyCheck(block, is_non_err, .unwrap_errunion);
   1769     }
   1770     return block.addUnOp(src, operand_pointer_ty, .unwrap_errunion_payload_ptr, operand);
   1771 }
   1772 
   1773 /// Value in, value out
   1774 fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1775     const tracy = trace(@src());
   1776     defer tracy.end();
   1777 
   1778     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   1779     const src = inst_data.src();
   1780     const operand = try sema.resolveInst(inst_data.operand);
   1781     if (operand.ty.zigTypeTag() != .ErrorUnion)
   1782         return sema.mod.fail(&block.base, src, "expected error union type, found '{}'", .{operand.ty});
   1783 
   1784     if (operand.value()) |val| {
   1785         assert(val.getError() != null);
   1786         const data = val.castTag(.error_union).?.data;
   1787         return sema.mod.constInst(sema.arena, src, .{
   1788             .ty = operand.ty.castTag(.error_union).?.data.error_set,
   1789             .val = data,
   1790         });
   1791     }
   1792 
   1793     try sema.requireRuntimeBlock(block, src);
   1794     return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err, operand);
   1795 }
   1796 
   1797 /// Pointer in, value out
   1798 fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1799     const tracy = trace(@src());
   1800     defer tracy.end();
   1801 
   1802     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   1803     const src = inst_data.src();
   1804     const operand = try sema.resolveInst(inst_data.operand);
   1805     assert(operand.ty.zigTypeTag() == .Pointer);
   1806 
   1807     if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)
   1808         return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand.ty.elemType()});
   1809 
   1810     if (operand.value()) |pointer_val| {
   1811         const val = try pointer_val.pointerDeref(sema.arena);
   1812         assert(val.getError() != null);
   1813         const data = val.castTag(.error_union).?.data;
   1814         return sema.mod.constInst(sema.arena, src, .{
   1815             .ty = operand.ty.elemType().castTag(.error_union).?.data.error_set,
   1816             .val = data,
   1817         });
   1818     }
   1819 
   1820     try sema.requireRuntimeBlock(block, src);
   1821     return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err_ptr, operand);
   1822 }
   1823 
   1824 fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
   1825     const tracy = trace(@src());
   1826     defer tracy.end();
   1827 
   1828     const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
   1829     const src = inst_data.src();
   1830     const operand = try sema.resolveInst(inst_data.operand);
   1831     if (operand.ty.zigTypeTag() != .ErrorUnion)
   1832         return sema.mod.fail(&block.base, src, "expected error union type, found '{}'", .{operand.ty});
   1833     if (operand.ty.castTag(.error_union).?.data.payload.zigTypeTag() != .Void) {
   1834         return sema.mod.fail(&block.base, src, "expression value is ignored", .{});
   1835     }
   1836 }
   1837 
   1838 fn zirFnType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index, var_args: bool) InnerError!*Inst {
   1839     const tracy = trace(@src());
   1840     defer tracy.end();
   1841 
   1842     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1843     const src = inst_data.src();
   1844     const extra = sema.code.extraData(zir.Inst.FnType, inst_data.payload_index);
   1845     const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);
   1846 
   1847     return sema.fnTypeCommon(
   1848         block,
   1849         inst_data.src_node,
   1850         param_types,
   1851         extra.data.return_type,
   1852         .Unspecified,
   1853         var_args,
   1854     );
   1855 }
   1856 
   1857 fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index, var_args: bool) InnerError!*Inst {
   1858     const tracy = trace(@src());
   1859     defer tracy.end();
   1860 
   1861     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1862     const src = inst_data.src();
   1863     const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node };
   1864     const extra = sema.code.extraData(zir.Inst.FnTypeCc, inst_data.payload_index);
   1865     const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);
   1866 
   1867     const cc_tv = try sema.resolveInstConst(block, cc_src, extra.data.cc);
   1868     // TODO once we're capable of importing and analyzing decls from
   1869     // std.builtin, this needs to change
   1870     const cc_str = cc_tv.val.castTag(.enum_literal).?.data;
   1871     const cc = std.meta.stringToEnum(std.builtin.CallingConvention, cc_str) orelse
   1872         return sema.mod.fail(&block.base, cc_src, "Unknown calling convention {s}", .{cc_str});
   1873     return sema.fnTypeCommon(
   1874         block,
   1875         inst_data.src_node,
   1876         param_types,
   1877         extra.data.return_type,
   1878         cc,
   1879         var_args,
   1880     );
   1881 }
   1882 
   1883 fn fnTypeCommon(
   1884     sema: *Sema,
   1885     block: *Scope.Block,
   1886     src_node_offset: i32,
   1887     zir_param_types: []const zir.Inst.Ref,
   1888     zir_return_type: zir.Inst.Ref,
   1889     cc: std.builtin.CallingConvention,
   1890     var_args: bool,
   1891 ) InnerError!*Inst {
   1892     const src: LazySrcLoc = .{ .node_offset = src_node_offset };
   1893     const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
   1894     const return_type = try sema.resolveType(block, ret_ty_src, zir_return_type);
   1895 
   1896     // Hot path for some common function types.
   1897     if (zir_param_types.len == 0 and !var_args) {
   1898         if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
   1899             return sema.mod.constType(sema.arena, src, Type.initTag(.fn_noreturn_no_args));
   1900         }
   1901 
   1902         if (return_type.zigTypeTag() == .Void and cc == .Unspecified) {
   1903             return sema.mod.constType(sema.arena, src, Type.initTag(.fn_void_no_args));
   1904         }
   1905 
   1906         if (return_type.zigTypeTag() == .NoReturn and cc == .Naked) {
   1907             return sema.mod.constType(sema.arena, src, Type.initTag(.fn_naked_noreturn_no_args));
   1908         }
   1909 
   1910         if (return_type.zigTypeTag() == .Void and cc == .C) {
   1911             return sema.mod.constType(sema.arena, src, Type.initTag(.fn_ccc_void_no_args));
   1912         }
   1913     }
   1914 
   1915     const param_types = try sema.arena.alloc(Type, zir_param_types.len);
   1916     for (zir_param_types) |param_type, i| {
   1917         // TODO make a compile error from `resolveType` report the source location
   1918         // of the specific parameter. Will need to take a similar strategy as
   1919         // `resolveSwitchItemVal` to avoid resolving the source location unless
   1920         // we actually need to report an error.
   1921         param_types[i] = try sema.resolveType(block, src, param_type);
   1922     }
   1923 
   1924     const fn_ty = try Type.Tag.function.create(sema.arena, .{
   1925         .param_types = param_types,
   1926         .return_type = return_type,
   1927         .cc = cc,
   1928         .is_var_args = var_args,
   1929     });
   1930     return sema.mod.constType(sema.arena, src, fn_ty);
   1931 }
   1932 
   1933 fn zirAs(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1934     const tracy = trace(@src());
   1935     defer tracy.end();
   1936 
   1937     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
   1938     return sema.analyzeAs(block, .unneeded, bin_inst.lhs, bin_inst.rhs);
   1939 }
   1940 
   1941 fn zirAsNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1942     const tracy = trace(@src());
   1943     defer tracy.end();
   1944 
   1945     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1946     const src = inst_data.src();
   1947     const extra = sema.code.extraData(zir.Inst.As, inst_data.payload_index).data;
   1948     return sema.analyzeAs(block, src, extra.dest_type, extra.operand);
   1949 }
   1950 
   1951 fn analyzeAs(
   1952     sema: *Sema,
   1953     block: *Scope.Block,
   1954     src: LazySrcLoc,
   1955     zir_dest_type: zir.Inst.Ref,
   1956     zir_operand: zir.Inst.Ref,
   1957 ) InnerError!*Inst {
   1958     const dest_type = try sema.resolveType(block, src, zir_dest_type);
   1959     const operand = try sema.resolveInst(zir_operand);
   1960     return sema.coerce(block, dest_type, operand, src);
   1961 }
   1962 
   1963 fn zirPtrtoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1964     const tracy = trace(@src());
   1965     defer tracy.end();
   1966 
   1967     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   1968     const ptr = try sema.resolveInst(inst_data.operand);
   1969     if (ptr.ty.zigTypeTag() != .Pointer) {
   1970         const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   1971         return sema.mod.fail(&block.base, ptr_src, "expected pointer, found '{}'", .{ptr.ty});
   1972     }
   1973     // TODO handle known-pointer-address
   1974     const src = inst_data.src();
   1975     try sema.requireRuntimeBlock(block, src);
   1976     const ty = Type.initTag(.usize);
   1977     return block.addUnOp(src, ty, .ptrtoint, ptr);
   1978 }
   1979 
   1980 fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1981     const tracy = trace(@src());
   1982     defer tracy.end();
   1983 
   1984     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   1985     const src = inst_data.src();
   1986     const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
   1987     const extra = sema.code.extraData(zir.Inst.Field, inst_data.payload_index).data;
   1988     const field_name = sema.code.nullTerminatedString(extra.field_name_start);
   1989     const object = try sema.resolveInst(extra.lhs);
   1990     const object_ptr = try sema.analyzeRef(block, src, object);
   1991     const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
   1992     return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);
   1993 }
   1994 
   1995 fn zirFieldPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   1996     const tracy = trace(@src());
   1997     defer tracy.end();
   1998 
   1999     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2000     const src = inst_data.src();
   2001     const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
   2002     const extra = sema.code.extraData(zir.Inst.Field, inst_data.payload_index).data;
   2003     const field_name = sema.code.nullTerminatedString(extra.field_name_start);
   2004     const object_ptr = try sema.resolveInst(extra.lhs);
   2005     return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
   2006 }
   2007 
   2008 fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   2009     const tracy = trace(@src());
   2010     defer tracy.end();
   2011 
   2012     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2013     const src = inst_data.src();
   2014     const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   2015     const extra = sema.code.extraData(zir.Inst.FieldNamed, inst_data.payload_index).data;
   2016     const object = try sema.resolveInst(extra.lhs);
   2017     const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
   2018     const object_ptr = try sema.analyzeRef(block, src, object);
   2019     const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
   2020     return sema.analyzeLoad(block, src, result_ptr, src);
   2021 }
   2022 
   2023 fn zirFieldPtrNamed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   2024     const tracy = trace(@src());
   2025     defer tracy.end();
   2026 
   2027     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2028     const src = inst_data.src();
   2029     const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   2030     const extra = sema.code.extraData(zir.Inst.FieldNamed, inst_data.payload_index).data;
   2031     const object_ptr = try sema.resolveInst(extra.lhs);
   2032     const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
   2033     return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
   2034 }
   2035 
   2036 fn zirIntcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   2037     const tracy = trace(@src());
   2038     defer tracy.end();
   2039 
   2040     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2041     const src = inst_data.src();
   2042     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   2043     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   2044     const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
   2045 
   2046     const dest_type = try sema.resolveType(block, dest_ty_src, extra.lhs);
   2047     const operand = try sema.resolveInst(extra.rhs);
   2048 
   2049     const dest_is_comptime_int = switch (dest_type.zigTypeTag()) {
   2050         .ComptimeInt => true,
   2051         .Int => false,
   2052         else => return sema.mod.fail(
   2053             &block.base,
   2054             dest_ty_src,
   2055             "expected integer type, found '{}'",
   2056             .{dest_type},
   2057         ),
   2058     };
   2059 
   2060     switch (operand.ty.zigTypeTag()) {
   2061         .ComptimeInt, .Int => {},
   2062         else => return sema.mod.fail(
   2063             &block.base,
   2064             operand_src,
   2065             "expected integer type, found '{}'",
   2066             .{operand.ty},
   2067         ),
   2068     }
   2069 
   2070     if (operand.value() != null) {
   2071         return sema.coerce(block, dest_type, operand, operand_src);
   2072     } else if (dest_is_comptime_int) {
   2073         return sema.mod.fail(&block.base, src, "unable to cast runtime value to 'comptime_int'", .{});
   2074     }
   2075 
   2076     return sema.mod.fail(&block.base, src, "TODO implement analyze widen or shorten int", .{});
   2077 }
   2078 
   2079 fn zirBitcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   2080     const tracy = trace(@src());
   2081     defer tracy.end();
   2082 
   2083     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2084     const src = inst_data.src();
   2085     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   2086     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   2087     const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
   2088 
   2089     const dest_type = try sema.resolveType(block, dest_ty_src, extra.lhs);
   2090     const operand = try sema.resolveInst(extra.rhs);
   2091     return sema.bitcast(block, dest_type, operand);
   2092 }
   2093 
   2094 fn zirFloatcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   2095     const tracy = trace(@src());
   2096     defer tracy.end();
   2097 
   2098     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2099     const src = inst_data.src();
   2100     const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   2101     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
   2102     const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
   2103 
   2104     const dest_type = try sema.resolveType(block, dest_ty_src, extra.lhs);
   2105     const operand = try sema.resolveInst(extra.rhs);
   2106 
   2107     const dest_is_comptime_float = switch (dest_type.zigTypeTag()) {
   2108         .ComptimeFloat => true,
   2109         .Float => false,
   2110         else => return sema.mod.fail(
   2111             &block.base,
   2112             dest_ty_src,
   2113             "expected float type, found '{}'",
   2114             .{dest_type},
   2115         ),
   2116     };
   2117 
   2118     switch (operand.ty.zigTypeTag()) {
   2119         .ComptimeFloat, .Float, .ComptimeInt => {},
   2120         else => return sema.mod.fail(
   2121             &block.base,
   2122             operand_src,
   2123             "expected float type, found '{}'",
   2124             .{operand.ty},
   2125         ),
   2126     }
   2127 
   2128     if (operand.value() != null) {
   2129         return sema.coerce(block, dest_type, operand, operand_src);
   2130     } else if (dest_is_comptime_float) {
   2131         return sema.mod.fail(&block.base, src, "unable to cast runtime value to 'comptime_float'", .{});
   2132     }
   2133 
   2134     return sema.mod.fail(&block.base, src, "TODO implement analyze widen or shorten float", .{});
   2135 }
   2136 
   2137 fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   2138     const tracy = trace(@src());
   2139     defer tracy.end();
   2140 
   2141     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
   2142     const array = try sema.resolveInst(bin_inst.lhs);
   2143     const array_ptr = try sema.analyzeRef(block, sema.src, array);
   2144     const elem_index = try sema.resolveInst(bin_inst.rhs);
   2145     const result_ptr = try sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src);
   2146     return sema.analyzeLoad(block, sema.src, result_ptr, sema.src);
   2147 }
   2148 
   2149 fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   2150     const tracy = trace(@src());
   2151     defer tracy.end();
   2152 
   2153     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2154     const src = inst_data.src();
   2155     const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
   2156     const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
   2157     const array = try sema.resolveInst(extra.lhs);
   2158     const array_ptr = try sema.analyzeRef(block, src, array);
   2159     const elem_index = try sema.resolveInst(extra.rhs);
   2160     const result_ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
   2161     return sema.analyzeLoad(block, src, result_ptr, src);
   2162 }
   2163 
   2164 fn zirElemPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   2165     const tracy = trace(@src());
   2166     defer tracy.end();
   2167 
   2168     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
   2169     const array_ptr = try sema.resolveInst(bin_inst.lhs);
   2170     const elem_index = try sema.resolveInst(bin_inst.rhs);
   2171     return sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src);
   2172 }
   2173 
   2174 fn zirElemPtrNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   2175     const tracy = trace(@src());
   2176     defer tracy.end();
   2177 
   2178     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2179     const src = inst_data.src();
   2180     const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
   2181     const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
   2182     const array_ptr = try sema.resolveInst(extra.lhs);
   2183     const elem_index = try sema.resolveInst(extra.rhs);
   2184     return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
   2185 }
   2186 
   2187 fn zirSliceStart(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   2188     const tracy = trace(@src());
   2189     defer tracy.end();
   2190 
   2191     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2192     const src = inst_data.src();
   2193     const extra = sema.code.extraData(zir.Inst.SliceStart, inst_data.payload_index).data;
   2194     const array_ptr = try sema.resolveInst(extra.lhs);
   2195     const start = try sema.resolveInst(extra.start);
   2196 
   2197     return sema.analyzeSlice(block, src, array_ptr, start, null, null, .unneeded);
   2198 }
   2199 
   2200 fn zirSliceEnd(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   2201     const tracy = trace(@src());
   2202     defer tracy.end();
   2203 
   2204     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2205     const src = inst_data.src();
   2206     const extra = sema.code.extraData(zir.Inst.SliceEnd, inst_data.payload_index).data;
   2207     const array_ptr = try sema.resolveInst(extra.lhs);
   2208     const start = try sema.resolveInst(extra.start);
   2209     const end = try sema.resolveInst(extra.end);
   2210 
   2211     return sema.analyzeSlice(block, src, array_ptr, start, end, null, .unneeded);
   2212 }
   2213 
   2214 fn zirSliceSentinel(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   2215     const tracy = trace(@src());
   2216     defer tracy.end();
   2217 
   2218     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2219     const src = inst_data.src();
   2220     const sentinel_src: LazySrcLoc = .{ .node_offset_slice_sentinel = inst_data.src_node };
   2221     const extra = sema.code.extraData(zir.Inst.SliceSentinel, inst_data.payload_index).data;
   2222     const array_ptr = try sema.resolveInst(extra.lhs);
   2223     const start = try sema.resolveInst(extra.start);
   2224     const end = try sema.resolveInst(extra.end);
   2225     const sentinel = try sema.resolveInst(extra.sentinel);
   2226 
   2227     return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src);
   2228 }
   2229 
   2230 fn zirSwitchCapture(
   2231     sema: *Sema,
   2232     block: *Scope.Block,
   2233     inst: zir.Inst.Index,
   2234     is_multi: bool,
   2235     is_ref: bool,
   2236 ) InnerError!*Inst {
   2237     const tracy = trace(@src());
   2238     defer tracy.end();
   2239 
   2240     const zir_datas = sema.code.instructions.items(.data);
   2241     const capture_info = zir_datas[inst].switch_capture;
   2242     const switch_info = zir_datas[capture_info.switch_inst].pl_node;
   2243     const src = switch_info.src();
   2244 
   2245     return sema.mod.fail(&block.base, src, "TODO implement Sema for zirSwitchCapture", .{});
   2246 }
   2247 
   2248 fn zirSwitchCaptureElse(
   2249     sema: *Sema,
   2250     block: *Scope.Block,
   2251     inst: zir.Inst.Index,
   2252     is_ref: bool,
   2253 ) InnerError!*Inst {
   2254     const tracy = trace(@src());
   2255     defer tracy.end();
   2256 
   2257     const zir_datas = sema.code.instructions.items(.data);
   2258     const capture_info = zir_datas[inst].switch_capture;
   2259     const switch_info = zir_datas[capture_info.switch_inst].pl_node;
   2260     const src = switch_info.src();
   2261 
   2262     return sema.mod.fail(&block.base, src, "TODO implement Sema for zirSwitchCaptureElse", .{});
   2263 }
   2264 
   2265 fn zirSwitchBlock(
   2266     sema: *Sema,
   2267     block: *Scope.Block,
   2268     inst: zir.Inst.Index,
   2269     is_ref: bool,
   2270     special_prong: zir.SpecialProng,
   2271 ) InnerError!*Inst {
   2272     const tracy = trace(@src());
   2273     defer tracy.end();
   2274 
   2275     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2276     const src = inst_data.src();
   2277     const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node };
   2278     const extra = sema.code.extraData(zir.Inst.SwitchBlock, inst_data.payload_index);
   2279 
   2280     const operand_ptr = try sema.resolveInst(extra.data.operand);
   2281     const operand = if (is_ref)
   2282         try sema.analyzeLoad(block, src, operand_ptr, operand_src)
   2283     else
   2284         operand_ptr;
   2285 
   2286     return sema.analyzeSwitch(
   2287         block,
   2288         operand,
   2289         extra.end,
   2290         special_prong,
   2291         extra.data.cases_len,
   2292         0,
   2293         inst,
   2294         inst_data.src_node,
   2295     );
   2296 }
   2297 
   2298 fn zirSwitchBlockMulti(
   2299     sema: *Sema,
   2300     block: *Scope.Block,
   2301     inst: zir.Inst.Index,
   2302     is_ref: bool,
   2303     special_prong: zir.SpecialProng,
   2304 ) InnerError!*Inst {
   2305     const tracy = trace(@src());
   2306     defer tracy.end();
   2307 
   2308     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   2309     const src = inst_data.src();
   2310     const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node };
   2311     const extra = sema.code.extraData(zir.Inst.SwitchBlockMulti, inst_data.payload_index);
   2312 
   2313     const operand_ptr = try sema.resolveInst(extra.data.operand);
   2314     const operand = if (is_ref)
   2315         try sema.analyzeLoad(block, src, operand_ptr, operand_src)
   2316     else
   2317         operand_ptr;
   2318 
   2319     return sema.analyzeSwitch(
   2320         block,
   2321         operand,
   2322         extra.end,
   2323         special_prong,
   2324         extra.data.scalar_cases_len,
   2325         extra.data.multi_cases_len,
   2326         inst,
   2327         inst_data.src_node,
   2328     );
   2329 }
   2330 
   2331 fn analyzeSwitch(
   2332     sema: *Sema,
   2333     block: *Scope.Block,
   2334     operand: *Inst,
   2335     extra_end: usize,
   2336     special_prong: zir.SpecialProng,
   2337     scalar_cases_len: usize,
   2338     multi_cases_len: usize,
   2339     switch_inst: zir.Inst.Index,
   2340     src_node_offset: i32,
   2341 ) InnerError!*Inst {
   2342     const gpa = sema.gpa;
   2343     const special: struct { body: []const zir.Inst.Index, end: usize } = switch (special_prong) {
   2344         .none => .{ .body = &.{}, .end = extra_end },
   2345         .under, .@"else" => blk: {
   2346             const body_len = sema.code.extra[extra_end];
   2347             const extra_body_start = extra_end + 1;
   2348             break :blk .{
   2349                 .body = sema.code.extra[extra_body_start..][0..body_len],
   2350                 .end = extra_body_start + body_len,
   2351             };
   2352         },
   2353     };
   2354 
   2355     const src: LazySrcLoc = .{ .node_offset = src_node_offset };
   2356     const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset };
   2357     const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };
   2358 
   2359     // Validate usage of '_' prongs.
   2360     if (special_prong == .under and !operand.ty.isExhaustiveEnum()) {
   2361         const msg = msg: {
   2362             const msg = try sema.mod.errMsg(
   2363                 &block.base,
   2364                 src,
   2365                 "'_' prong only allowed when switching on non-exhaustive enums",
   2366                 .{},
   2367             );
   2368             errdefer msg.destroy(gpa);
   2369             try sema.mod.errNote(
   2370                 &block.base,
   2371                 special_prong_src,
   2372                 msg,
   2373                 "'_' prong here",
   2374                 .{},
   2375             );
   2376             break :msg msg;
   2377         };
   2378         return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
   2379     }
   2380 
   2381     // Validate for duplicate items, missing else prong, and invalid range.
   2382     switch (operand.ty.zigTypeTag()) {
   2383         .Enum => return sema.mod.fail(&block.base, src, "TODO validate switch .Enum", .{}),
   2384         .ErrorSet => return sema.mod.fail(&block.base, src, "TODO validate switch .ErrorSet", .{}),
   2385         .Union => return sema.mod.fail(&block.base, src, "TODO validate switch .Union", .{}),
   2386         .Int, .ComptimeInt => {
   2387             var range_set = RangeSet.init(gpa);
   2388             defer range_set.deinit();
   2389 
   2390             var extra_index: usize = special.end;
   2391             {
   2392                 var scalar_i: u32 = 0;
   2393                 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   2394                     const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
   2395                     extra_index += 1;
   2396                     const body_len = sema.code.extra[extra_index];
   2397                     extra_index += 1;
   2398                     const body = sema.code.extra[extra_index..][0..body_len];
   2399                     extra_index += body_len;
   2400 
   2401                     try sema.validateSwitchItem(
   2402                         block,
   2403                         &range_set,
   2404                         item_ref,
   2405                         src_node_offset,
   2406                         .{ .scalar = scalar_i },
   2407                     );
   2408                 }
   2409             }
   2410             {
   2411                 var multi_i: u32 = 0;
   2412                 while (multi_i < multi_cases_len) : (multi_i += 1) {
   2413                     const items_len = sema.code.extra[extra_index];
   2414                     extra_index += 1;
   2415                     const ranges_len = sema.code.extra[extra_index];
   2416                     extra_index += 1;
   2417                     const body_len = sema.code.extra[extra_index];
   2418                     extra_index += 1;
   2419                     const items = sema.code.refSlice(extra_index, items_len);
   2420                     extra_index += items_len;
   2421 
   2422                     for (items) |item_ref, item_i| {
   2423                         try sema.validateSwitchItem(
   2424                             block,
   2425                             &range_set,
   2426                             item_ref,
   2427                             src_node_offset,
   2428                             .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
   2429                         );
   2430                     }
   2431 
   2432                     var range_i: u32 = 0;
   2433                     while (range_i < ranges_len) : (range_i += 1) {
   2434                         const item_first = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
   2435                         extra_index += 1;
   2436                         const item_last = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
   2437                         extra_index += 1;
   2438 
   2439                         try sema.validateSwitchRange(
   2440                             block,
   2441                             &range_set,
   2442                             item_first,
   2443                             item_last,
   2444                             src_node_offset,
   2445                             .{ .range = .{ .prong = multi_i, .item = range_i } },
   2446                         );
   2447                     }
   2448 
   2449                     extra_index += body_len;
   2450                 }
   2451             }
   2452 
   2453             check_range: {
   2454                 if (operand.ty.zigTypeTag() == .Int) {
   2455                     var arena = std.heap.ArenaAllocator.init(gpa);
   2456                     defer arena.deinit();
   2457 
   2458                     const min_int = try operand.ty.minInt(&arena, sema.mod.getTarget());
   2459                     const max_int = try operand.ty.maxInt(&arena, sema.mod.getTarget());
   2460                     if (try range_set.spans(min_int, max_int)) {
   2461                         if (special_prong == .@"else") {
   2462                             return sema.mod.fail(
   2463                                 &block.base,
   2464                                 special_prong_src,
   2465                                 "unreachable else prong; all cases already handled",
   2466                                 .{},
   2467                             );
   2468                         }
   2469                         break :check_range;
   2470                     }
   2471                 }
   2472                 if (special_prong != .@"else") {
   2473                     return sema.mod.fail(
   2474                         &block.base,
   2475                         src,
   2476                         "switch must handle all possibilities",
   2477                         .{},
   2478                     );
   2479                 }
   2480             }
   2481         },
   2482         .Bool => {
   2483             var true_count: u8 = 0;
   2484             var false_count: u8 = 0;
   2485 
   2486             var extra_index: usize = special.end;
   2487             {
   2488                 var scalar_i: u32 = 0;
   2489                 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   2490                     const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
   2491                     extra_index += 1;
   2492                     const body_len = sema.code.extra[extra_index];
   2493                     extra_index += 1;
   2494                     const body = sema.code.extra[extra_index..][0..body_len];
   2495                     extra_index += body_len;
   2496 
   2497                     try sema.validateSwitchItemBool(
   2498                         block,
   2499                         &true_count,
   2500                         &false_count,
   2501                         item_ref,
   2502                         src_node_offset,
   2503                         .{ .scalar = scalar_i },
   2504                     );
   2505                 }
   2506             }
   2507             {
   2508                 var multi_i: u32 = 0;
   2509                 while (multi_i < multi_cases_len) : (multi_i += 1) {
   2510                     const items_len = sema.code.extra[extra_index];
   2511                     extra_index += 1;
   2512                     const ranges_len = sema.code.extra[extra_index];
   2513                     extra_index += 1;
   2514                     const body_len = sema.code.extra[extra_index];
   2515                     extra_index += 1;
   2516                     const items = sema.code.refSlice(extra_index, items_len);
   2517                     extra_index += items_len + body_len;
   2518 
   2519                     for (items) |item_ref, item_i| {
   2520                         try sema.validateSwitchItemBool(
   2521                             block,
   2522                             &true_count,
   2523                             &false_count,
   2524                             item_ref,
   2525                             src_node_offset,
   2526                             .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
   2527                         );
   2528                     }
   2529 
   2530                     try sema.validateSwitchNoRange(block, ranges_len, operand.ty, src_node_offset);
   2531                 }
   2532             }
   2533             switch (special_prong) {
   2534                 .@"else" => {
   2535                     if (true_count + false_count == 2) {
   2536                         return sema.mod.fail(
   2537                             &block.base,
   2538                             src,
   2539                             "unreachable else prong; all cases already handled",
   2540                             .{},
   2541                         );
   2542                     }
   2543                 },
   2544                 .under, .none => {
   2545                     if (true_count + false_count < 2) {
   2546                         return sema.mod.fail(
   2547                             &block.base,
   2548                             src,
   2549                             "switch must handle all possibilities",
   2550                             .{},
   2551                         );
   2552                     }
   2553                 },
   2554             }
   2555         },
   2556         .EnumLiteral, .Void, .Fn, .Pointer, .Type => {
   2557             if (special_prong != .@"else") {
   2558                 return sema.mod.fail(
   2559                     &block.base,
   2560                     src,
   2561                     "else prong required when switching on type '{}'",
   2562                     .{operand.ty},
   2563                 );
   2564             }
   2565 
   2566             var seen_values = ValueSrcMap.init(gpa);
   2567             defer seen_values.deinit();
   2568 
   2569             var extra_index: usize = special.end;
   2570             {
   2571                 var scalar_i: u32 = 0;
   2572                 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   2573                     const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
   2574                     extra_index += 1;
   2575                     const body_len = sema.code.extra[extra_index];
   2576                     extra_index += 1;
   2577                     const body = sema.code.extra[extra_index..][0..body_len];
   2578                     extra_index += body_len;
   2579 
   2580                     try sema.validateSwitchItemSparse(
   2581                         block,
   2582                         &seen_values,
   2583                         item_ref,
   2584                         src_node_offset,
   2585                         .{ .scalar = scalar_i },
   2586                     );
   2587                 }
   2588             }
   2589             {
   2590                 var multi_i: u32 = 0;
   2591                 while (multi_i < multi_cases_len) : (multi_i += 1) {
   2592                     const items_len = sema.code.extra[extra_index];
   2593                     extra_index += 1;
   2594                     const ranges_len = sema.code.extra[extra_index];
   2595                     extra_index += 1;
   2596                     const body_len = sema.code.extra[extra_index];
   2597                     extra_index += 1;
   2598                     const items = sema.code.refSlice(extra_index, items_len);
   2599                     extra_index += items_len + body_len;
   2600 
   2601                     for (items) |item_ref, item_i| {
   2602                         try sema.validateSwitchItemSparse(
   2603                             block,
   2604                             &seen_values,
   2605                             item_ref,
   2606                             src_node_offset,
   2607                             .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
   2608                         );
   2609                     }
   2610 
   2611                     try sema.validateSwitchNoRange(block, ranges_len, operand.ty, src_node_offset);
   2612                 }
   2613             }
   2614         },
   2615 
   2616         .ErrorUnion,
   2617         .NoReturn,
   2618         .Array,
   2619         .Struct,
   2620         .Undefined,
   2621         .Null,
   2622         .Optional,
   2623         .BoundFn,
   2624         .Opaque,
   2625         .Vector,
   2626         .Frame,
   2627         .AnyFrame,
   2628         .ComptimeFloat,
   2629         .Float,
   2630         => return sema.mod.fail(&block.base, operand_src, "invalid switch operand type '{}'", .{
   2631             operand.ty,
   2632         }),
   2633     }
   2634 
   2635     if (try sema.resolveDefinedValue(block, src, operand)) |operand_val| {
   2636         var extra_index: usize = special.end;
   2637         {
   2638             var scalar_i: usize = 0;
   2639             while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   2640                 const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
   2641                 extra_index += 1;
   2642                 const body_len = sema.code.extra[extra_index];
   2643                 extra_index += 1;
   2644                 const body = sema.code.extra[extra_index..][0..body_len];
   2645                 extra_index += body_len;
   2646 
   2647                 // Validation above ensured these will succeed.
   2648                 const item = sema.resolveInst(item_ref) catch unreachable;
   2649                 const item_val = sema.resolveConstValue(block, .unneeded, item) catch unreachable;
   2650                 if (operand_val.eql(item_val)) {
   2651                     return sema.resolveBody(block, body);
   2652                 }
   2653             }
   2654         }
   2655         {
   2656             var multi_i: usize = 0;
   2657             while (multi_i < multi_cases_len) : (multi_i += 1) {
   2658                 const items_len = sema.code.extra[extra_index];
   2659                 extra_index += 1;
   2660                 const ranges_len = sema.code.extra[extra_index];
   2661                 extra_index += 1;
   2662                 const body_len = sema.code.extra[extra_index];
   2663                 extra_index += 1;
   2664                 const items = sema.code.refSlice(extra_index, items_len);
   2665                 extra_index += items_len;
   2666                 const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..body_len];
   2667 
   2668                 for (items) |item_ref| {
   2669                     // Validation above ensured these will succeed.
   2670                     const item = sema.resolveInst(item_ref) catch unreachable;
   2671                     const item_val = sema.resolveConstValue(block, item.src, item) catch unreachable;
   2672                     if (operand_val.eql(item_val)) {
   2673                         return sema.resolveBody(block, body);
   2674                     }
   2675                 }
   2676 
   2677                 var range_i: usize = 0;
   2678                 while (range_i < ranges_len) : (range_i += 1) {
   2679                     const item_first = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
   2680                     extra_index += 1;
   2681                     const item_last = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
   2682                     extra_index += 1;
   2683 
   2684                     // Validation above ensured these will succeed.
   2685                     const first_tv = sema.resolveInstConst(block, .unneeded, item_first) catch unreachable;
   2686                     const last_tv = sema.resolveInstConst(block, .unneeded, item_last) catch unreachable;
   2687                     if (Value.compare(operand_val, .gte, first_tv.val) and
   2688                         Value.compare(operand_val, .lte, last_tv.val))
   2689                     {
   2690                         return sema.resolveBody(block, body);
   2691                     }
   2692                 }
   2693 
   2694                 extra_index += body_len;
   2695             }
   2696         }
   2697         return sema.resolveBody(block, special.body);
   2698     }
   2699 
   2700     if (scalar_cases_len + multi_cases_len == 0) {
   2701         return sema.resolveBody(block, special.body);
   2702     }
   2703 
   2704     try sema.requireRuntimeBlock(block, src);
   2705 
   2706     const block_inst = try sema.arena.create(Inst.Block);
   2707     block_inst.* = .{
   2708         .base = .{
   2709             .tag = Inst.Block.base_tag,
   2710             .ty = undefined, // Set after analysis.
   2711             .src = src,
   2712         },
   2713         .body = undefined,
   2714     };
   2715 
   2716     var child_block: Scope.Block = .{
   2717         .parent = block,
   2718         .sema = sema,
   2719         .src_decl = block.src_decl,
   2720         .instructions = .{},
   2721         // TODO @as here is working around a stage1 miscompilation bug :(
   2722         .label = @as(?Scope.Block.Label, Scope.Block.Label{
   2723             .zir_block = switch_inst,
   2724             .merges = .{
   2725                 .results = .{},
   2726                 .br_list = .{},
   2727                 .block_inst = block_inst,
   2728             },
   2729         }),
   2730         .inlining = block.inlining,
   2731         .is_comptime = block.is_comptime,
   2732     };
   2733     const merges = &child_block.label.?.merges;
   2734     defer child_block.instructions.deinit(gpa);
   2735     defer merges.results.deinit(gpa);
   2736     defer merges.br_list.deinit(gpa);
   2737 
   2738     // TODO when reworking TZIR memory layout make multi cases get generated as cases,
   2739     // not as part of the "else" block.
   2740     const cases = try sema.arena.alloc(Inst.SwitchBr.Case, scalar_cases_len);
   2741 
   2742     var case_block = child_block.makeSubBlock();
   2743     defer case_block.instructions.deinit(gpa);
   2744 
   2745     var extra_index: usize = special.end;
   2746 
   2747     var scalar_i: usize = 0;
   2748     while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   2749         const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
   2750         extra_index += 1;
   2751         const body_len = sema.code.extra[extra_index];
   2752         extra_index += 1;
   2753         const body = sema.code.extra[extra_index..][0..body_len];
   2754         extra_index += body_len;
   2755 
   2756         case_block.instructions.shrinkRetainingCapacity(0);
   2757         // We validate these above; these two calls are guaranteed to succeed.
   2758         const item = sema.resolveInst(item_ref) catch unreachable;
   2759         const item_val = sema.resolveConstValue(&case_block, .unneeded, item) catch unreachable;
   2760 
   2761         _ = try sema.analyzeBody(&case_block, body);
   2762 
   2763         cases[scalar_i] = .{
   2764             .item = item_val,
   2765             .body = .{ .instructions = try sema.arena.dupe(*Inst, case_block.instructions.items) },
   2766         };
   2767     }
   2768 
   2769     var first_else_body: Body = undefined;
   2770     var prev_condbr: ?*Inst.CondBr = null;
   2771 
   2772     var multi_i: usize = 0;
   2773     while (multi_i < multi_cases_len) : (multi_i += 1) {
   2774         const items_len = sema.code.extra[extra_index];
   2775         extra_index += 1;
   2776         const ranges_len = sema.code.extra[extra_index];
   2777         extra_index += 1;
   2778         const body_len = sema.code.extra[extra_index];
   2779         extra_index += 1;
   2780         const items = sema.code.refSlice(extra_index, items_len);
   2781         extra_index += items_len;
   2782 
   2783         case_block.instructions.shrinkRetainingCapacity(0);
   2784 
   2785         var any_ok: ?*Inst = null;
   2786         const bool_ty = comptime Type.initTag(.bool);
   2787 
   2788         for (items) |item_ref| {
   2789             const item = try sema.resolveInst(item_ref);
   2790             _ = try sema.resolveConstValue(&child_block, item.src, item);
   2791 
   2792             const cmp_ok = try case_block.addBinOp(item.src, bool_ty, .cmp_eq, operand, item);
   2793             if (any_ok) |some| {
   2794                 any_ok = try case_block.addBinOp(item.src, bool_ty, .bool_or, some, cmp_ok);
   2795             } else {
   2796                 any_ok = cmp_ok;
   2797             }
   2798         }
   2799 
   2800         var range_i: usize = 0;
   2801         while (range_i < ranges_len) : (range_i += 1) {
   2802             const first_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
   2803             extra_index += 1;
   2804             const last_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
   2805             extra_index += 1;
   2806 
   2807             const item_first = try sema.resolveInst(first_ref);
   2808             const item_last = try sema.resolveInst(last_ref);
   2809 
   2810             _ = try sema.resolveConstValue(&child_block, item_first.src, item_first);
   2811             _ = try sema.resolveConstValue(&child_block, item_last.src, item_last);
   2812 
   2813             const range_src = item_first.src;
   2814 
   2815             // operand >= first and operand <= last
   2816             const range_first_ok = try case_block.addBinOp(
   2817                 item_first.src,
   2818                 bool_ty,
   2819                 .cmp_gte,
   2820                 operand,
   2821                 item_first,
   2822             );
   2823             const range_last_ok = try case_block.addBinOp(
   2824                 item_last.src,
   2825                 bool_ty,
   2826                 .cmp_lte,
   2827                 operand,
   2828                 item_last,
   2829             );
   2830             const range_ok = try case_block.addBinOp(
   2831                 range_src,
   2832                 bool_ty,
   2833                 .bool_and,
   2834                 range_first_ok,
   2835                 range_last_ok,
   2836             );
   2837             if (any_ok) |some| {
   2838                 any_ok = try case_block.addBinOp(range_src, bool_ty, .bool_or, some, range_ok);
   2839             } else {
   2840                 any_ok = range_ok;
   2841             }
   2842         }
   2843 
   2844         const new_condbr = try sema.arena.create(Inst.CondBr);
   2845         new_condbr.* = .{
   2846             .base = .{
   2847                 .tag = .condbr,
   2848                 .ty = Type.initTag(.noreturn),
   2849                 .src = src,
   2850             },
   2851             .condition = any_ok.?,
   2852             .then_body = undefined,
   2853             .else_body = undefined,
   2854         };
   2855         try case_block.instructions.append(gpa, &new_condbr.base);
   2856 
   2857         const cond_body: Body = .{
   2858             .instructions = try sema.arena.dupe(*Inst, case_block.instructions.items),
   2859         };
   2860 
   2861         case_block.instructions.shrinkRetainingCapacity(0);
   2862         const body = sema.code.extra[extra_index..][0..body_len];
   2863         extra_index += body_len;
   2864         _ = try sema.analyzeBody(&case_block, body);
   2865         new_condbr.then_body = .{
   2866             .instructions = try sema.arena.dupe(*Inst, case_block.instructions.items),
   2867         };
   2868         if (prev_condbr) |condbr| {
   2869             condbr.else_body = cond_body;
   2870         } else {
   2871             first_else_body = cond_body;
   2872         }
   2873         prev_condbr = new_condbr;
   2874     }
   2875 
   2876     const final_else_body: Body = blk: {
   2877         if (special.body.len != 0) {
   2878             case_block.instructions.shrinkRetainingCapacity(0);
   2879             _ = try sema.analyzeBody(&case_block, special.body);
   2880             const else_body: Body = .{
   2881                 .instructions = try sema.arena.dupe(*Inst, case_block.instructions.items),
   2882             };
   2883             if (prev_condbr) |condbr| {
   2884                 condbr.else_body = else_body;
   2885                 break :blk first_else_body;
   2886             } else {
   2887                 break :blk else_body;
   2888             }
   2889         } else {
   2890             break :blk .{ .instructions = &.{} };
   2891         }
   2892     };
   2893 
   2894     _ = try child_block.addSwitchBr(src, operand, cases, final_else_body);
   2895     return sema.analyzeBlockBody(block, src, &child_block, merges);
   2896 }
   2897 
   2898 fn resolveSwitchItemVal(
   2899     sema: *Sema,
   2900     block: *Scope.Block,
   2901     item_ref: zir.Inst.Ref,
   2902     switch_node_offset: i32,
   2903     switch_prong_src: AstGen.SwitchProngSrc,
   2904     range_expand: AstGen.SwitchProngSrc.RangeExpand,
   2905 ) InnerError!Value {
   2906     const item = try sema.resolveInst(item_ref);
   2907     // We have to avoid the other helper functions here because we cannot construct a LazySrcLoc
   2908     // because we only have the switch AST node. Only if we know for sure we need to report
   2909     // a compile error do we resolve the full source locations.
   2910     if (item.value()) |val| {
   2911         if (val.isUndef()) {
   2912             const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);
   2913             return sema.failWithUseOfUndef(block, src);
   2914         }
   2915         return val;
   2916     }
   2917     const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);
   2918     return sema.failWithNeededComptime(block, src);
   2919 }
   2920 
   2921 fn validateSwitchRange(
   2922     sema: *Sema,
   2923     block: *Scope.Block,
   2924     range_set: *RangeSet,
   2925     first_ref: zir.Inst.Ref,
   2926     last_ref: zir.Inst.Ref,
   2927     src_node_offset: i32,
   2928     switch_prong_src: AstGen.SwitchProngSrc,
   2929 ) InnerError!void {
   2930     const first_val = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first);
   2931     const last_val = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last);
   2932     const maybe_prev_src = try range_set.add(first_val, last_val, switch_prong_src);
   2933     return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
   2934 }
   2935 
   2936 fn validateSwitchItem(
   2937     sema: *Sema,
   2938     block: *Scope.Block,
   2939     range_set: *RangeSet,
   2940     item_ref: zir.Inst.Ref,
   2941     src_node_offset: i32,
   2942     switch_prong_src: AstGen.SwitchProngSrc,
   2943 ) InnerError!void {
   2944     const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
   2945     const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src);
   2946     return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
   2947 }
   2948 
   2949 fn validateSwitchDupe(
   2950     sema: *Sema,
   2951     block: *Scope.Block,
   2952     maybe_prev_src: ?AstGen.SwitchProngSrc,
   2953     switch_prong_src: AstGen.SwitchProngSrc,
   2954     src_node_offset: i32,
   2955 ) InnerError!void {
   2956     const prev_prong_src = maybe_prev_src orelse return;
   2957     const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none);
   2958     const prev_src = prev_prong_src.resolve(block.src_decl, src_node_offset, .none);
   2959     const msg = msg: {
   2960         const msg = try sema.mod.errMsg(
   2961             &block.base,
   2962             src,
   2963             "duplicate switch value",
   2964             .{},
   2965         );
   2966         errdefer msg.destroy(sema.gpa);
   2967         try sema.mod.errNote(
   2968             &block.base,
   2969             prev_src,
   2970             msg,
   2971             "previous value here",
   2972             .{},
   2973         );
   2974         break :msg msg;
   2975     };
   2976     return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
   2977 }
   2978 
   2979 fn validateSwitchItemBool(
   2980     sema: *Sema,
   2981     block: *Scope.Block,
   2982     true_count: *u8,
   2983     false_count: *u8,
   2984     item_ref: zir.Inst.Ref,
   2985     src_node_offset: i32,
   2986     switch_prong_src: AstGen.SwitchProngSrc,
   2987 ) InnerError!void {
   2988     const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
   2989     if (item_val.toBool()) {
   2990         true_count.* += 1;
   2991     } else {
   2992         false_count.* += 1;
   2993     }
   2994     if (true_count.* + false_count.* > 2) {
   2995         const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none);
   2996         return sema.mod.fail(&block.base, src, "duplicate switch value", .{});
   2997     }
   2998 }
   2999 
   3000 const ValueSrcMap = std.HashMap(Value, AstGen.SwitchProngSrc, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage);
   3001 
   3002 fn validateSwitchItemSparse(
   3003     sema: *Sema,
   3004     block: *Scope.Block,
   3005     seen_values: *ValueSrcMap,
   3006     item_ref: zir.Inst.Ref,
   3007     src_node_offset: i32,
   3008     switch_prong_src: AstGen.SwitchProngSrc,
   3009 ) InnerError!void {
   3010     const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
   3011     const entry = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return;
   3012     return sema.validateSwitchDupe(block, entry.value, switch_prong_src, src_node_offset);
   3013 }
   3014 
   3015 fn validateSwitchNoRange(
   3016     sema: *Sema,
   3017     block: *Scope.Block,
   3018     ranges_len: u32,
   3019     operand_ty: Type,
   3020     src_node_offset: i32,
   3021 ) InnerError!void {
   3022     if (ranges_len == 0)
   3023         return;
   3024 
   3025     const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };
   3026     const range_src: LazySrcLoc = .{ .node_offset_switch_range = src_node_offset };
   3027 
   3028     const msg = msg: {
   3029         const msg = try sema.mod.errMsg(
   3030             &block.base,
   3031             operand_src,
   3032             "ranges not allowed when switching on type '{}'",
   3033             .{operand_ty},
   3034         );
   3035         errdefer msg.destroy(sema.gpa);
   3036         try sema.mod.errNote(
   3037             &block.base,
   3038             range_src,
   3039             msg,
   3040             "range here",
   3041             .{},
   3042         );
   3043         break :msg msg;
   3044     };
   3045     return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
   3046 }
   3047 
   3048 fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3049     const tracy = trace(@src());
   3050     defer tracy.end();
   3051 
   3052     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3053     const src = inst_data.src();
   3054     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
   3055     const operand = try sema.resolveConstString(block, operand_src, inst_data.operand);
   3056 
   3057     const file_scope = sema.analyzeImport(block, src, operand) catch |err| switch (err) {
   3058         error.ImportOutsidePkgPath => {
   3059             return sema.mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand});
   3060         },
   3061         error.FileNotFound => {
   3062             return sema.mod.fail(&block.base, src, "unable to find '{s}'", .{operand});
   3063         },
   3064         else => {
   3065             // TODO: make sure this gets retried and not cached
   3066             return sema.mod.fail(&block.base, src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
   3067         },
   3068     };
   3069     return sema.mod.constType(sema.arena, src, file_scope.root_container.ty);
   3070 }
   3071 
   3072 fn zirShl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3073     const tracy = trace(@src());
   3074     defer tracy.end();
   3075     return sema.mod.fail(&block.base, sema.src, "TODO implement zirShl", .{});
   3076 }
   3077 
   3078 fn zirShr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3079     const tracy = trace(@src());
   3080     defer tracy.end();
   3081     return sema.mod.fail(&block.base, sema.src, "TODO implement zirShr", .{});
   3082 }
   3083 
   3084 fn zirBitwise(
   3085     sema: *Sema,
   3086     block: *Scope.Block,
   3087     inst: zir.Inst.Index,
   3088     ir_tag: ir.Inst.Tag,
   3089 ) InnerError!*Inst {
   3090     const tracy = trace(@src());
   3091     defer tracy.end();
   3092 
   3093     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   3094     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
   3095     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   3096     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
   3097     const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
   3098     const lhs = try sema.resolveInst(extra.lhs);
   3099     const rhs = try sema.resolveInst(extra.rhs);
   3100 
   3101     const instructions = &[_]*Inst{ lhs, rhs };
   3102     const resolved_type = try sema.resolvePeerTypes(block, src, instructions);
   3103     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
   3104     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
   3105 
   3106     const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
   3107         resolved_type.elemType()
   3108     else
   3109         resolved_type;
   3110 
   3111     const scalar_tag = scalar_type.zigTypeTag();
   3112 
   3113     if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) {
   3114         if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
   3115             return sema.mod.fail(&block.base, src, "vector length mismatch: {d} and {d}", .{
   3116                 lhs.ty.arrayLen(),
   3117                 rhs.ty.arrayLen(),
   3118             });
   3119         }
   3120         return sema.mod.fail(&block.base, src, "TODO implement support for vectors in zirBitwise", .{});
   3121     } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
   3122         return sema.mod.fail(&block.base, src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
   3123             lhs.ty,
   3124             rhs.ty,
   3125         });
   3126     }
   3127 
   3128     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
   3129 
   3130     if (!is_int) {
   3131         return sema.mod.fail(&block.base, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) });
   3132     }
   3133 
   3134     if (casted_lhs.value()) |lhs_val| {
   3135         if (casted_rhs.value()) |rhs_val| {
   3136             if (lhs_val.isUndef() or rhs_val.isUndef()) {
   3137                 return sema.mod.constInst(sema.arena, src, .{
   3138                     .ty = resolved_type,
   3139                     .val = Value.initTag(.undef),
   3140                 });
   3141             }
   3142             return sema.mod.fail(&block.base, src, "TODO implement comptime bitwise operations", .{});
   3143         }
   3144     }
   3145 
   3146     try sema.requireRuntimeBlock(block, src);
   3147     return block.addBinOp(src, scalar_type, ir_tag, casted_lhs, casted_rhs);
   3148 }
   3149 
   3150 fn zirBitNot(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3151     const tracy = trace(@src());
   3152     defer tracy.end();
   3153     return sema.mod.fail(&block.base, sema.src, "TODO implement zirBitNot", .{});
   3154 }
   3155 
   3156 fn zirArrayCat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3157     const tracy = trace(@src());
   3158     defer tracy.end();
   3159     return sema.mod.fail(&block.base, sema.src, "TODO implement zirArrayCat", .{});
   3160 }
   3161 
   3162 fn zirArrayMul(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3163     const tracy = trace(@src());
   3164     defer tracy.end();
   3165     return sema.mod.fail(&block.base, sema.src, "TODO implement zirArrayMul", .{});
   3166 }
   3167 
   3168 fn zirNegate(
   3169     sema: *Sema,
   3170     block: *Scope.Block,
   3171     inst: zir.Inst.Index,
   3172     tag_override: zir.Inst.Tag,
   3173 ) InnerError!*Inst {
   3174     const tracy = trace(@src());
   3175     defer tracy.end();
   3176 
   3177     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3178     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
   3179     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   3180     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
   3181     const lhs = try sema.resolveInst(.zero);
   3182     const rhs = try sema.resolveInst(inst_data.operand);
   3183 
   3184     return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src);
   3185 }
   3186 
   3187 fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3188     const tracy = trace(@src());
   3189     defer tracy.end();
   3190 
   3191     const tag_override = block.sema.code.instructions.items(.tag)[inst];
   3192     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   3193     const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
   3194     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
   3195     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
   3196     const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
   3197     const lhs = try sema.resolveInst(extra.lhs);
   3198     const rhs = try sema.resolveInst(extra.rhs);
   3199 
   3200     return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src);
   3201 }
   3202 
   3203 fn analyzeArithmetic(
   3204     sema: *Sema,
   3205     block: *Scope.Block,
   3206     zir_tag: zir.Inst.Tag,
   3207     lhs: *Inst,
   3208     rhs: *Inst,
   3209     src: LazySrcLoc,
   3210     lhs_src: LazySrcLoc,
   3211     rhs_src: LazySrcLoc,
   3212 ) InnerError!*Inst {
   3213     const instructions = &[_]*Inst{ lhs, rhs };
   3214     const resolved_type = try sema.resolvePeerTypes(block, src, instructions);
   3215     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
   3216     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
   3217 
   3218     const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
   3219         resolved_type.elemType()
   3220     else
   3221         resolved_type;
   3222 
   3223     const scalar_tag = scalar_type.zigTypeTag();
   3224 
   3225     if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) {
   3226         if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
   3227             return sema.mod.fail(&block.base, src, "vector length mismatch: {d} and {d}", .{
   3228                 lhs.ty.arrayLen(),
   3229                 rhs.ty.arrayLen(),
   3230             });
   3231         }
   3232         return sema.mod.fail(&block.base, src, "TODO implement support for vectors in zirBinOp", .{});
   3233     } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
   3234         return sema.mod.fail(&block.base, src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
   3235             lhs.ty,
   3236             rhs.ty,
   3237         });
   3238     }
   3239 
   3240     const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
   3241     const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;
   3242 
   3243     if (!is_int and !(is_float and floatOpAllowed(zir_tag))) {
   3244         return sema.mod.fail(&block.base, src, "invalid operands to binary expression: '{s}' and '{s}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) });
   3245     }
   3246 
   3247     if (casted_lhs.value()) |lhs_val| {
   3248         if (casted_rhs.value()) |rhs_val| {
   3249             if (lhs_val.isUndef() or rhs_val.isUndef()) {
   3250                 return sema.mod.constInst(sema.arena, src, .{
   3251                     .ty = resolved_type,
   3252                     .val = Value.initTag(.undef),
   3253                 });
   3254             }
   3255             // incase rhs is 0, simply return lhs without doing any calculations
   3256             // TODO Once division is implemented we should throw an error when dividing by 0.
   3257             if (rhs_val.compareWithZero(.eq)) {
   3258                 return sema.mod.constInst(sema.arena, src, .{
   3259                     .ty = scalar_type,
   3260                     .val = lhs_val,
   3261                 });
   3262             }
   3263 
   3264             const value = switch (zir_tag) {
   3265                 .add => blk: {
   3266                     const val = if (is_int)
   3267                         try Module.intAdd(sema.arena, lhs_val, rhs_val)
   3268                     else
   3269                         try Module.floatAdd(sema.arena, scalar_type, src, lhs_val, rhs_val);
   3270                     break :blk val;
   3271                 },
   3272                 .sub => blk: {
   3273                     const val = if (is_int)
   3274                         try Module.intSub(sema.arena, lhs_val, rhs_val)
   3275                     else
   3276                         try Module.floatSub(sema.arena, scalar_type, src, lhs_val, rhs_val);
   3277                     break :blk val;
   3278                 },
   3279                 else => return sema.mod.fail(&block.base, src, "TODO Implement arithmetic operand '{s}'", .{@tagName(zir_tag)}),
   3280             };
   3281 
   3282             log.debug("{s}({}, {}) result: {}", .{ @tagName(zir_tag), lhs_val, rhs_val, value });
   3283 
   3284             return sema.mod.constInst(sema.arena, src, .{
   3285                 .ty = scalar_type,
   3286                 .val = value,
   3287             });
   3288         }
   3289     }
   3290 
   3291     try sema.requireRuntimeBlock(block, src);
   3292     const ir_tag: Inst.Tag = switch (zir_tag) {
   3293         .add => .add,
   3294         .addwrap => .addwrap,
   3295         .sub => .sub,
   3296         .subwrap => .subwrap,
   3297         .mul => .mul,
   3298         .mulwrap => .mulwrap,
   3299         else => return sema.mod.fail(&block.base, src, "TODO implement arithmetic for operand '{s}''", .{@tagName(zir_tag)}),
   3300     };
   3301 
   3302     return block.addBinOp(src, scalar_type, ir_tag, casted_lhs, casted_rhs);
   3303 }
   3304 
   3305 fn zirLoad(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3306     const tracy = trace(@src());
   3307     defer tracy.end();
   3308 
   3309     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3310     const src = inst_data.src();
   3311     const ptr_src: LazySrcLoc = .{ .node_offset_deref_ptr = inst_data.src_node };
   3312     const ptr = try sema.resolveInst(inst_data.operand);
   3313     return sema.analyzeLoad(block, src, ptr, ptr_src);
   3314 }
   3315 
   3316 fn zirAsm(
   3317     sema: *Sema,
   3318     block: *Scope.Block,
   3319     inst: zir.Inst.Index,
   3320     is_volatile: bool,
   3321 ) InnerError!*Inst {
   3322     const tracy = trace(@src());
   3323     defer tracy.end();
   3324 
   3325     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   3326     const src = inst_data.src();
   3327     const asm_source_src: LazySrcLoc = .{ .node_offset_asm_source = inst_data.src_node };
   3328     const ret_ty_src: LazySrcLoc = .{ .node_offset_asm_ret_ty = inst_data.src_node };
   3329     const extra = sema.code.extraData(zir.Inst.Asm, inst_data.payload_index);
   3330     const return_type = try sema.resolveType(block, ret_ty_src, extra.data.return_type);
   3331     const asm_source = try sema.resolveConstString(block, asm_source_src, extra.data.asm_source);
   3332 
   3333     var extra_i = extra.end;
   3334     const Output = struct { name: []const u8, inst: *Inst };
   3335     const output: ?Output = if (extra.data.output != .none) blk: {
   3336         const name = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
   3337         extra_i += 1;
   3338         break :blk Output{
   3339             .name = name,
   3340             .inst = try sema.resolveInst(extra.data.output),
   3341         };
   3342     } else null;
   3343 
   3344     const args = try sema.arena.alloc(*Inst, extra.data.args_len);
   3345     const inputs = try sema.arena.alloc([]const u8, extra.data.args_len);
   3346     const clobbers = try sema.arena.alloc([]const u8, extra.data.clobbers_len);
   3347 
   3348     for (args) |*arg| {
   3349         arg.* = try sema.resolveInst(@intToEnum(zir.Inst.Ref, sema.code.extra[extra_i]));
   3350         extra_i += 1;
   3351     }
   3352     for (inputs) |*name| {
   3353         name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
   3354         extra_i += 1;
   3355     }
   3356     for (clobbers) |*name| {
   3357         name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
   3358         extra_i += 1;
   3359     }
   3360 
   3361     try sema.requireRuntimeBlock(block, src);
   3362     const asm_tzir = try sema.arena.create(Inst.Assembly);
   3363     asm_tzir.* = .{
   3364         .base = .{
   3365             .tag = .assembly,
   3366             .ty = return_type,
   3367             .src = src,
   3368         },
   3369         .asm_source = asm_source,
   3370         .is_volatile = is_volatile,
   3371         .output = if (output) |o| o.inst else null,
   3372         .output_name = if (output) |o| o.name else null,
   3373         .inputs = inputs,
   3374         .clobbers = clobbers,
   3375         .args = args,
   3376     };
   3377     try block.instructions.append(sema.gpa, &asm_tzir.base);
   3378     return &asm_tzir.base;
   3379 }
   3380 
   3381 fn zirCmp(
   3382     sema: *Sema,
   3383     block: *Scope.Block,
   3384     inst: zir.Inst.Index,
   3385     op: std.math.CompareOperator,
   3386 ) InnerError!*Inst {
   3387     const tracy = trace(@src());
   3388     defer tracy.end();
   3389 
   3390     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   3391     const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
   3392     const src: LazySrcLoc = inst_data.src();
   3393     const lhs = try sema.resolveInst(extra.lhs);
   3394     const rhs = try sema.resolveInst(extra.rhs);
   3395 
   3396     const is_equality_cmp = switch (op) {
   3397         .eq, .neq => true,
   3398         else => false,
   3399     };
   3400     const lhs_ty_tag = lhs.ty.zigTypeTag();
   3401     const rhs_ty_tag = rhs.ty.zigTypeTag();
   3402     if (is_equality_cmp and lhs_ty_tag == .Null and rhs_ty_tag == .Null) {
   3403         // null == null, null != null
   3404         return sema.mod.constBool(sema.arena, src, op == .eq);
   3405     } else if (is_equality_cmp and
   3406         ((lhs_ty_tag == .Null and rhs_ty_tag == .Optional) or
   3407         rhs_ty_tag == .Null and lhs_ty_tag == .Optional))
   3408     {
   3409         // comparing null with optionals
   3410         const opt_operand = if (lhs_ty_tag == .Optional) lhs else rhs;
   3411         return sema.analyzeIsNull(block, src, opt_operand, op == .neq);
   3412     } else if (is_equality_cmp and
   3413         ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))
   3414     {
   3415         return sema.mod.fail(&block.base, src, "TODO implement C pointer cmp", .{});
   3416     } else if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {
   3417         const non_null_type = if (lhs_ty_tag == .Null) rhs.ty else lhs.ty;
   3418         return sema.mod.fail(&block.base, src, "comparison of '{}' with null", .{non_null_type});
   3419     } else if (is_equality_cmp and
   3420         ((lhs_ty_tag == .EnumLiteral and rhs_ty_tag == .Union) or
   3421         (rhs_ty_tag == .EnumLiteral and lhs_ty_tag == .Union)))
   3422     {
   3423         return sema.mod.fail(&block.base, src, "TODO implement equality comparison between a union's tag value and an enum literal", .{});
   3424     } else if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {
   3425         if (!is_equality_cmp) {
   3426             return sema.mod.fail(&block.base, src, "{s} operator not allowed for errors", .{@tagName(op)});
   3427         }
   3428         if (rhs.value()) |rval| {
   3429             if (lhs.value()) |lval| {
   3430                 // TODO optimisation oppurtunity: evaluate if std.mem.eql is faster with the names, or calling to Module.getErrorValue to get the values and then compare them is faster
   3431                 return sema.mod.constBool(sema.arena, src, std.mem.eql(u8, lval.castTag(.@"error").?.data.name, rval.castTag(.@"error").?.data.name) == (op == .eq));
   3432             }
   3433         }
   3434         try sema.requireRuntimeBlock(block, src);
   3435         return block.addBinOp(src, Type.initTag(.bool), if (op == .eq) .cmp_eq else .cmp_neq, lhs, rhs);
   3436     } else if (lhs.ty.isNumeric() and rhs.ty.isNumeric()) {
   3437         // This operation allows any combination of integer and float types, regardless of the
   3438         // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for
   3439         // numeric types.
   3440         return sema.cmpNumeric(block, src, lhs, rhs, op);
   3441     } else if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {
   3442         if (!is_equality_cmp) {
   3443             return sema.mod.fail(&block.base, src, "{s} operator not allowed for types", .{@tagName(op)});
   3444         }
   3445         return sema.mod.constBool(sema.arena, src, lhs.value().?.eql(rhs.value().?) == (op == .eq));
   3446     }
   3447     return sema.mod.fail(&block.base, src, "TODO implement more cmp analysis", .{});
   3448 }
   3449 
   3450 fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3451     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3452     const src = inst_data.src();
   3453     const operand = try sema.resolveInst(inst_data.operand);
   3454     return sema.mod.constType(sema.arena, src, operand.ty);
   3455 }
   3456 
   3457 fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3458     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3459     const src = inst_data.src();
   3460     const operand_ptr = try sema.resolveInst(inst_data.operand);
   3461     const elem_ty = operand_ptr.ty.elemType();
   3462     return sema.mod.constType(sema.arena, src, elem_ty);
   3463 }
   3464 
   3465 fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3466     const tracy = trace(@src());
   3467     defer tracy.end();
   3468 
   3469     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   3470     const src = inst_data.src();
   3471     const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index);
   3472     const args = sema.code.refSlice(extra.end, extra.data.operands_len);
   3473 
   3474     const inst_list = try sema.gpa.alloc(*ir.Inst, extra.data.operands_len);
   3475     defer sema.gpa.free(inst_list);
   3476 
   3477     for (args) |arg_ref, i| {
   3478         inst_list[i] = try sema.resolveInst(arg_ref);
   3479     }
   3480 
   3481     const result_type = try sema.resolvePeerTypes(block, src, inst_list);
   3482     return sema.mod.constType(sema.arena, src, result_type);
   3483 }
   3484 
   3485 fn zirBoolNot(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3486     const tracy = trace(@src());
   3487     defer tracy.end();
   3488 
   3489     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3490     const src = inst_data.src();
   3491     const uncasted_operand = try sema.resolveInst(inst_data.operand);
   3492 
   3493     const bool_type = Type.initTag(.bool);
   3494     const operand = try sema.coerce(block, bool_type, uncasted_operand, uncasted_operand.src);
   3495     if (try sema.resolveDefinedValue(block, src, operand)) |val| {
   3496         return sema.mod.constBool(sema.arena, src, !val.toBool());
   3497     }
   3498     try sema.requireRuntimeBlock(block, src);
   3499     return block.addUnOp(src, bool_type, .not, operand);
   3500 }
   3501 
   3502 fn zirBoolOp(
   3503     sema: *Sema,
   3504     block: *Scope.Block,
   3505     inst: zir.Inst.Index,
   3506     comptime is_bool_or: bool,
   3507 ) InnerError!*Inst {
   3508     const tracy = trace(@src());
   3509     defer tracy.end();
   3510 
   3511     const src: LazySrcLoc = .unneeded;
   3512     const bool_type = Type.initTag(.bool);
   3513     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
   3514     const uncasted_lhs = try sema.resolveInst(bin_inst.lhs);
   3515     const lhs = try sema.coerce(block, bool_type, uncasted_lhs, uncasted_lhs.src);
   3516     const uncasted_rhs = try sema.resolveInst(bin_inst.rhs);
   3517     const rhs = try sema.coerce(block, bool_type, uncasted_rhs, uncasted_rhs.src);
   3518 
   3519     if (lhs.value()) |lhs_val| {
   3520         if (rhs.value()) |rhs_val| {
   3521             if (is_bool_or) {
   3522                 return sema.mod.constBool(sema.arena, src, lhs_val.toBool() or rhs_val.toBool());
   3523             } else {
   3524                 return sema.mod.constBool(sema.arena, src, lhs_val.toBool() and rhs_val.toBool());
   3525             }
   3526         }
   3527     }
   3528     try sema.requireRuntimeBlock(block, src);
   3529     const tag: ir.Inst.Tag = if (is_bool_or) .bool_or else .bool_and;
   3530     return block.addBinOp(src, bool_type, tag, lhs, rhs);
   3531 }
   3532 
   3533 fn zirBoolBr(
   3534     sema: *Sema,
   3535     parent_block: *Scope.Block,
   3536     inst: zir.Inst.Index,
   3537     is_bool_or: bool,
   3538 ) InnerError!*Inst {
   3539     const tracy = trace(@src());
   3540     defer tracy.end();
   3541 
   3542     const datas = sema.code.instructions.items(.data);
   3543     const inst_data = datas[inst].bool_br;
   3544     const src: LazySrcLoc = .unneeded;
   3545     const lhs = try sema.resolveInst(inst_data.lhs);
   3546     const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);
   3547     const body = sema.code.extra[extra.end..][0..extra.data.body_len];
   3548 
   3549     if (try sema.resolveDefinedValue(parent_block, src, lhs)) |lhs_val| {
   3550         if (lhs_val.toBool() == is_bool_or) {
   3551             return sema.mod.constBool(sema.arena, src, is_bool_or);
   3552         }
   3553         // comptime-known left-hand side. No need for a block here; the result
   3554         // is simply the rhs expression. Here we rely on there only being 1
   3555         // break instruction (`break_inline`).
   3556         return sema.resolveBody(parent_block, body);
   3557     }
   3558 
   3559     const block_inst = try sema.arena.create(Inst.Block);
   3560     block_inst.* = .{
   3561         .base = .{
   3562             .tag = Inst.Block.base_tag,
   3563             .ty = Type.initTag(.bool),
   3564             .src = src,
   3565         },
   3566         .body = undefined,
   3567     };
   3568 
   3569     var child_block = parent_block.makeSubBlock();
   3570     defer child_block.instructions.deinit(sema.gpa);
   3571 
   3572     var then_block = child_block.makeSubBlock();
   3573     defer then_block.instructions.deinit(sema.gpa);
   3574 
   3575     var else_block = child_block.makeSubBlock();
   3576     defer else_block.instructions.deinit(sema.gpa);
   3577 
   3578     const lhs_block = if (is_bool_or) &then_block else &else_block;
   3579     const rhs_block = if (is_bool_or) &else_block else &then_block;
   3580 
   3581     const lhs_result = try sema.mod.constInst(sema.arena, src, .{
   3582         .ty = Type.initTag(.bool),
   3583         .val = if (is_bool_or) Value.initTag(.bool_true) else Value.initTag(.bool_false),
   3584     });
   3585     _ = try lhs_block.addBr(src, block_inst, lhs_result);
   3586 
   3587     const rhs_result = try sema.resolveBody(rhs_block, body);
   3588     _ = try rhs_block.addBr(src, block_inst, rhs_result);
   3589 
   3590     const tzir_then_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, then_block.instructions.items) };
   3591     const tzir_else_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, rhs_block.instructions.items) };
   3592     _ = try child_block.addCondBr(src, lhs, tzir_then_body, tzir_else_body);
   3593 
   3594     block_inst.body = .{
   3595         .instructions = try sema.arena.dupe(*Inst, child_block.instructions.items),
   3596     };
   3597     try parent_block.instructions.append(sema.gpa, &block_inst.base);
   3598     return &block_inst.base;
   3599 }
   3600 
   3601 fn zirIsNull(
   3602     sema: *Sema,
   3603     block: *Scope.Block,
   3604     inst: zir.Inst.Index,
   3605     invert_logic: bool,
   3606 ) InnerError!*Inst {
   3607     const tracy = trace(@src());
   3608     defer tracy.end();
   3609 
   3610     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3611     const src = inst_data.src();
   3612     const operand = try sema.resolveInst(inst_data.operand);
   3613     return sema.analyzeIsNull(block, src, operand, invert_logic);
   3614 }
   3615 
   3616 fn zirIsNullPtr(
   3617     sema: *Sema,
   3618     block: *Scope.Block,
   3619     inst: zir.Inst.Index,
   3620     invert_logic: bool,
   3621 ) InnerError!*Inst {
   3622     const tracy = trace(@src());
   3623     defer tracy.end();
   3624 
   3625     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3626     const src = inst_data.src();
   3627     const ptr = try sema.resolveInst(inst_data.operand);
   3628     const loaded = try sema.analyzeLoad(block, src, ptr, src);
   3629     return sema.analyzeIsNull(block, src, loaded, invert_logic);
   3630 }
   3631 
   3632 fn zirIsErr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3633     const tracy = trace(@src());
   3634     defer tracy.end();
   3635 
   3636     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3637     const operand = try sema.resolveInst(inst_data.operand);
   3638     return sema.analyzeIsErr(block, inst_data.src(), operand);
   3639 }
   3640 
   3641 fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3642     const tracy = trace(@src());
   3643     defer tracy.end();
   3644 
   3645     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3646     const src = inst_data.src();
   3647     const ptr = try sema.resolveInst(inst_data.operand);
   3648     const loaded = try sema.analyzeLoad(block, src, ptr, src);
   3649     return sema.analyzeIsErr(block, src, loaded);
   3650 }
   3651 
   3652 fn zirCondbr(
   3653     sema: *Sema,
   3654     parent_block: *Scope.Block,
   3655     inst: zir.Inst.Index,
   3656 ) InnerError!zir.Inst.Index {
   3657     const tracy = trace(@src());
   3658     defer tracy.end();
   3659 
   3660     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
   3661     const src = inst_data.src();
   3662     const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
   3663     const extra = sema.code.extraData(zir.Inst.CondBr, inst_data.payload_index);
   3664 
   3665     const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
   3666     const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
   3667 
   3668     const uncasted_cond = try sema.resolveInst(extra.data.condition);
   3669     const cond = try sema.coerce(parent_block, Type.initTag(.bool), uncasted_cond, cond_src);
   3670 
   3671     if (try sema.resolveDefinedValue(parent_block, src, cond)) |cond_val| {
   3672         const body = if (cond_val.toBool()) then_body else else_body;
   3673         _ = try sema.analyzeBody(parent_block, body);
   3674         return always_noreturn;
   3675     }
   3676 
   3677     var sub_block = parent_block.makeSubBlock();
   3678     defer sub_block.instructions.deinit(sema.gpa);
   3679 
   3680     _ = try sema.analyzeBody(&sub_block, then_body);
   3681     const tzir_then_body: ir.Body = .{
   3682         .instructions = try sema.arena.dupe(*Inst, sub_block.instructions.items),
   3683     };
   3684 
   3685     sub_block.instructions.shrinkRetainingCapacity(0);
   3686 
   3687     _ = try sema.analyzeBody(&sub_block, else_body);
   3688     const tzir_else_body: ir.Body = .{
   3689         .instructions = try sema.arena.dupe(*Inst, sub_block.instructions.items),
   3690     };
   3691 
   3692     _ = try parent_block.addCondBr(src, cond, tzir_then_body, tzir_else_body);
   3693     return always_noreturn;
   3694 }
   3695 
   3696 fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
   3697     const tracy = trace(@src());
   3698     defer tracy.end();
   3699 
   3700     const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable";
   3701     const src = inst_data.src();
   3702     const safety_check = inst_data.safety;
   3703     try sema.requireRuntimeBlock(block, src);
   3704     // TODO Add compile error for @optimizeFor occurring too late in a scope.
   3705     if (safety_check and block.wantSafety()) {
   3706         return sema.safetyPanic(block, src, .unreach);
   3707     } else {
   3708         _ = try block.addNoOp(src, Type.initTag(.noreturn), .unreach);
   3709         return always_noreturn;
   3710     }
   3711 }
   3712 
   3713 fn zirRetTok(
   3714     sema: *Sema,
   3715     block: *Scope.Block,
   3716     inst: zir.Inst.Index,
   3717     need_coercion: bool,
   3718 ) InnerError!zir.Inst.Index {
   3719     const tracy = trace(@src());
   3720     defer tracy.end();
   3721 
   3722     const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
   3723     const operand = try sema.resolveInst(inst_data.operand);
   3724     const src = inst_data.src();
   3725 
   3726     return sema.analyzeRet(block, operand, src, need_coercion);
   3727 }
   3728 
   3729 fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
   3730     const tracy = trace(@src());
   3731     defer tracy.end();
   3732 
   3733     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
   3734     const operand = try sema.resolveInst(inst_data.operand);
   3735     const src = inst_data.src();
   3736 
   3737     return sema.analyzeRet(block, operand, src, false);
   3738 }
   3739 
   3740 fn analyzeRet(
   3741     sema: *Sema,
   3742     block: *Scope.Block,
   3743     operand: *Inst,
   3744     src: LazySrcLoc,
   3745     need_coercion: bool,
   3746 ) InnerError!zir.Inst.Index {
   3747     if (block.inlining) |inlining| {
   3748         // We are inlining a function call; rewrite the `ret` as a `break`.
   3749         try inlining.merges.results.append(sema.gpa, operand);
   3750         _ = try block.addBr(src, inlining.merges.block_inst, operand);
   3751         return always_noreturn;
   3752     }
   3753 
   3754     if (need_coercion) {
   3755         if (sema.func) |func| {
   3756             const fn_ty = func.owner_decl.typed_value.most_recent.typed_value.ty;
   3757             const fn_ret_ty = fn_ty.fnReturnType();
   3758             const casted_operand = try sema.coerce(block, fn_ret_ty, operand, src);
   3759             if (fn_ret_ty.zigTypeTag() == .Void)
   3760                 _ = try block.addNoOp(src, Type.initTag(.noreturn), .retvoid)
   3761             else
   3762                 _ = try block.addUnOp(src, Type.initTag(.noreturn), .ret, casted_operand);
   3763             return always_noreturn;
   3764         }
   3765     }
   3766     _ = try block.addUnOp(src, Type.initTag(.noreturn), .ret, operand);
   3767     return always_noreturn;
   3768 }
   3769 
   3770 fn floatOpAllowed(tag: zir.Inst.Tag) bool {
   3771     // extend this swich as additional operators are implemented
   3772     return switch (tag) {
   3773         .add, .sub => true,
   3774         else => false,
   3775     };
   3776 }
   3777 
   3778 fn zirPtrTypeSimple(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3779     const tracy = trace(@src());
   3780     defer tracy.end();
   3781 
   3782     const inst_data = sema.code.instructions.items(.data)[inst].ptr_type_simple;
   3783     const elem_type = try sema.resolveType(block, .unneeded, inst_data.elem_type);
   3784     const ty = try sema.mod.ptrType(
   3785         sema.arena,
   3786         elem_type,
   3787         null,
   3788         0,
   3789         0,
   3790         0,
   3791         inst_data.is_mutable,
   3792         inst_data.is_allowzero,
   3793         inst_data.is_volatile,
   3794         inst_data.size,
   3795     );
   3796     return sema.mod.constType(sema.arena, .unneeded, ty);
   3797 }
   3798 
   3799 fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
   3800     const tracy = trace(@src());
   3801     defer tracy.end();
   3802 
   3803     const src: LazySrcLoc = .unneeded;
   3804     const inst_data = sema.code.instructions.items(.data)[inst].ptr_type;
   3805     const extra = sema.code.extraData(zir.Inst.PtrType, inst_data.payload_index);
   3806 
   3807     var extra_i = extra.end;
   3808 
   3809     const sentinel = if (inst_data.flags.has_sentinel) blk: {
   3810         const ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_i]);
   3811         extra_i += 1;
   3812         break :blk (try sema.resolveInstConst(block, .unneeded, ref)).val;
   3813     } else null;
   3814 
   3815     const abi_align = if (inst_data.flags.has_align) blk: {
   3816         const ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_i]);
   3817         extra_i += 1;
   3818         break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u32);
   3819     } else 0;
   3820 
   3821     const bit_start = if (inst_data.flags.has_bit_range) blk: {
   3822         const ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_i]);
   3823         extra_i += 1;
   3824         break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u16);
   3825     } else 0;
   3826 
   3827     const bit_end = if (inst_data.flags.has_bit_range) blk: {
   3828         const ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_i]);
   3829         extra_i += 1;
   3830         break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u16);
   3831     } else 0;
   3832 
   3833     if (bit_end != 0 and bit_start >= bit_end * 8)
   3834         return sema.mod.fail(&block.base, src, "bit offset starts after end of host integer", .{});
   3835 
   3836     const elem_type = try sema.resolveType(block, .unneeded, extra.data.elem_type);
   3837 
   3838     const ty = try sema.mod.ptrType(
   3839         sema.arena,
   3840         elem_type,
   3841         sentinel,
   3842         abi_align,
   3843         bit_start,
   3844         bit_end,
   3845         inst_data.flags.is_mutable,
   3846         inst_data.flags.is_allowzero,
   3847         inst_data.flags.is_volatile,
   3848         inst_data.size,
   3849     );
   3850     return sema.mod.constType(sema.arena, src, ty);
   3851 }
   3852 
   3853 fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
   3854     if (sema.func == null) {
   3855         return sema.mod.fail(&block.base, src, "instruction illegal outside function body", .{});
   3856     }
   3857 }
   3858 
   3859 fn requireRuntimeBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
   3860     if (block.is_comptime) {
   3861         return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{});
   3862     }
   3863     try sema.requireFunctionBlock(block, src);
   3864 }
   3865 
   3866 fn validateVarType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) !void {
   3867     if (!ty.isValidVarType(false)) {
   3868         return sema.mod.fail(&block.base, src, "variable of type '{}' must be const or comptime", .{ty});
   3869     }
   3870 }
   3871 
   3872 pub const PanicId = enum {
   3873     unreach,
   3874     unwrap_null,
   3875     unwrap_errunion,
   3876     invalid_error_code,
   3877 };
   3878 
   3879 fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id: PanicId) !void {
   3880     const block_inst = try sema.arena.create(Inst.Block);
   3881     block_inst.* = .{
   3882         .base = .{
   3883             .tag = Inst.Block.base_tag,
   3884             .ty = Type.initTag(.void),
   3885             .src = ok.src,
   3886         },
   3887         .body = .{
   3888             .instructions = try sema.arena.alloc(*Inst, 1), // Only need space for the condbr.
   3889         },
   3890     };
   3891 
   3892     const ok_body: ir.Body = .{
   3893         .instructions = try sema.arena.alloc(*Inst, 1), // Only need space for the br_void.
   3894     };
   3895     const br_void = try sema.arena.create(Inst.BrVoid);
   3896     br_void.* = .{
   3897         .base = .{
   3898             .tag = .br_void,
   3899             .ty = Type.initTag(.noreturn),
   3900             .src = ok.src,
   3901         },
   3902         .block = block_inst,
   3903     };
   3904     ok_body.instructions[0] = &br_void.base;
   3905 
   3906     var fail_block: Scope.Block = .{
   3907         .parent = parent_block,
   3908         .sema = sema,
   3909         .src_decl = parent_block.src_decl,
   3910         .instructions = .{},
   3911         .inlining = parent_block.inlining,
   3912         .is_comptime = parent_block.is_comptime,
   3913     };
   3914 
   3915     defer fail_block.instructions.deinit(sema.gpa);
   3916 
   3917     _ = try sema.safetyPanic(&fail_block, ok.src, panic_id);
   3918 
   3919     const fail_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, fail_block.instructions.items) };
   3920 
   3921     const condbr = try sema.arena.create(Inst.CondBr);
   3922     condbr.* = .{
   3923         .base = .{
   3924             .tag = .condbr,
   3925             .ty = Type.initTag(.noreturn),
   3926             .src = ok.src,
   3927         },
   3928         .condition = ok,
   3929         .then_body = ok_body,
   3930         .else_body = fail_body,
   3931     };
   3932     block_inst.body.instructions[0] = &condbr.base;
   3933 
   3934     try parent_block.instructions.append(sema.gpa, &block_inst.base);
   3935 }
   3936 
   3937 fn safetyPanic(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, panic_id: PanicId) !zir.Inst.Index {
   3938     // TODO Once we have a panic function to call, call it here instead of breakpoint.
   3939     _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint);
   3940     _ = try block.addNoOp(src, Type.initTag(.noreturn), .unreach);
   3941     return always_noreturn;
   3942 }
   3943 
   3944 fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
   3945     sema.branch_count += 1;
   3946     if (sema.branch_count > sema.branch_quota) {
   3947         // TODO show the "called from here" stack
   3948         return sema.mod.fail(&block.base, src, "evaluation exceeded {d} backwards branches", .{sema.branch_quota});
   3949     }
   3950 }
   3951 
   3952 fn namedFieldPtr(
   3953     sema: *Sema,
   3954     block: *Scope.Block,
   3955     src: LazySrcLoc,
   3956     object_ptr: *Inst,
   3957     field_name: []const u8,
   3958     field_name_src: LazySrcLoc,
   3959 ) InnerError!*Inst {
   3960     const elem_ty = switch (object_ptr.ty.zigTypeTag()) {
   3961         .Pointer => object_ptr.ty.elemType(),
   3962         else => return sema.mod.fail(&block.base, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),
   3963     };
   3964     switch (elem_ty.zigTypeTag()) {
   3965         .Array => {
   3966             if (mem.eql(u8, field_name, "len")) {
   3967                 return sema.mod.constInst(sema.arena, src, .{
   3968                     .ty = Type.initTag(.single_const_pointer_to_comptime_int),
   3969                     .val = try Value.Tag.ref_val.create(
   3970                         sema.arena,
   3971                         try Value.Tag.int_u64.create(sema.arena, elem_ty.arrayLen()),
   3972                     ),
   3973                 });
   3974             } else {
   3975                 return sema.mod.fail(
   3976                     &block.base,
   3977                     field_name_src,
   3978                     "no member named '{s}' in '{}'",
   3979                     .{ field_name, elem_ty },
   3980                 );
   3981             }
   3982         },
   3983         .Pointer => {
   3984             const ptr_child = elem_ty.elemType();
   3985             switch (ptr_child.zigTypeTag()) {
   3986                 .Array => {
   3987                     if (mem.eql(u8, field_name, "len")) {
   3988                         return sema.mod.constInst(sema.arena, src, .{
   3989                             .ty = Type.initTag(.single_const_pointer_to_comptime_int),
   3990                             .val = try Value.Tag.ref_val.create(
   3991                                 sema.arena,
   3992                                 try Value.Tag.int_u64.create(sema.arena, ptr_child.arrayLen()),
   3993                             ),
   3994                         });
   3995                     } else {
   3996                         return sema.mod.fail(
   3997                             &block.base,
   3998                             field_name_src,
   3999                             "no member named '{s}' in '{}'",
   4000                             .{ field_name, elem_ty },
   4001                         );
   4002                     }
   4003                 },
   4004                 else => {},
   4005             }
   4006         },
   4007         .Type => {
   4008             _ = try sema.resolveConstValue(block, object_ptr.src, object_ptr);
   4009             const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr.src);
   4010             const val = result.value().?;
   4011             const child_type = try val.toType(sema.arena);
   4012             switch (child_type.zigTypeTag()) {
   4013                 .ErrorSet => {
   4014                     // TODO resolve inferred error sets
   4015                     const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {
   4016                         const error_set = payload.data;
   4017                         // TODO this is O(N). I'm putting off solving this until we solve inferred
   4018                         // error sets at the same time.
   4019                         const names = error_set.names_ptr[0..error_set.names_len];
   4020                         for (names) |name| {
   4021                             if (mem.eql(u8, field_name, name)) {
   4022                                 break :blk name;
   4023                             }
   4024                         }
   4025                         return sema.mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{
   4026                             field_name,
   4027                             child_type,
   4028                         });
   4029                     } else (try sema.mod.getErrorValue(field_name)).key;
   4030 
   4031                     return sema.mod.constInst(sema.arena, src, .{
   4032                         .ty = try sema.mod.simplePtrType(sema.arena, child_type, false, .One),
   4033                         .val = try Value.Tag.ref_val.create(
   4034                             sema.arena,
   4035                             try Value.Tag.@"error".create(sema.arena, .{
   4036                                 .name = name,
   4037                             }),
   4038                         ),
   4039                     });
   4040                 },
   4041                 .Struct => {
   4042                     const container_scope = child_type.getContainerScope();
   4043                     if (sema.mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
   4044                         // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
   4045                         return sema.analyzeDeclRef(block, src, decl);
   4046                     }
   4047 
   4048                     if (container_scope.file_scope == sema.mod.root_scope) {
   4049                         return sema.mod.fail(&block.base, src, "root source file has no member called '{s}'", .{field_name});
   4050                     } else {
   4051                         return sema.mod.fail(&block.base, src, "container '{}' has no member called '{s}'", .{ child_type, field_name });
   4052                     }
   4053                 },
   4054                 else => return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{child_type}),
   4055             }
   4056         },
   4057         else => {},
   4058     }
   4059     return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});
   4060 }
   4061 
   4062 fn elemPtr(
   4063     sema: *Sema,
   4064     block: *Scope.Block,
   4065     src: LazySrcLoc,
   4066     array_ptr: *Inst,
   4067     elem_index: *Inst,
   4068     elem_index_src: LazySrcLoc,
   4069 ) InnerError!*Inst {
   4070     const elem_ty = switch (array_ptr.ty.zigTypeTag()) {
   4071         .Pointer => array_ptr.ty.elemType(),
   4072         else => return sema.mod.fail(&block.base, array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}),
   4073     };
   4074     if (!elem_ty.isIndexable()) {
   4075         return sema.mod.fail(&block.base, src, "array access of non-array type '{}'", .{elem_ty});
   4076     }
   4077 
   4078     if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) {
   4079         // we have to deref the ptr operand to get the actual array pointer
   4080         const array_ptr_deref = try sema.analyzeLoad(block, src, array_ptr, array_ptr.src);
   4081         if (array_ptr_deref.value()) |array_ptr_val| {
   4082             if (elem_index.value()) |index_val| {
   4083                 // Both array pointer and index are compile-time known.
   4084                 const index_u64 = index_val.toUnsignedInt();
   4085                 // @intCast here because it would have been impossible to construct a value that
   4086                 // required a larger index.
   4087                 const elem_ptr = try array_ptr_val.elemPtr(sema.arena, @intCast(usize, index_u64));
   4088                 const pointee_type = elem_ty.elemType().elemType();
   4089 
   4090                 return sema.mod.constInst(sema.arena, src, .{
   4091                     .ty = try Type.Tag.single_const_pointer.create(sema.arena, pointee_type),
   4092                     .val = elem_ptr,
   4093                 });
   4094             }
   4095         }
   4096     }
   4097 
   4098     return sema.mod.fail(&block.base, src, "TODO implement more analyze elemptr", .{});
   4099 }
   4100 
   4101 fn coerce(
   4102     sema: *Sema,
   4103     block: *Scope.Block,
   4104     dest_type: Type,
   4105     inst: *Inst,
   4106     inst_src: LazySrcLoc,
   4107 ) InnerError!*Inst {
   4108     if (dest_type.tag() == .var_args_param) {
   4109         return sema.coerceVarArgParam(block, inst);
   4110     }
   4111     // If the types are the same, we can return the operand.
   4112     if (dest_type.eql(inst.ty))
   4113         return inst;
   4114 
   4115     const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);
   4116     if (in_memory_result == .ok) {
   4117         return sema.bitcast(block, dest_type, inst);
   4118     }
   4119 
   4120     // undefined to anything
   4121     if (inst.value()) |val| {
   4122         if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) {
   4123             return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = val });
   4124         }
   4125     }
   4126     assert(inst.ty.zigTypeTag() != .Undefined);
   4127 
   4128     // T to E!T or E to E!T
   4129     if (dest_type.tag() == .error_union) {
   4130         return try sema.wrapErrorUnion(block, dest_type, inst);
   4131     }
   4132 
   4133     // comptime known number to other number
   4134     if (try sema.coerceNum(block, dest_type, inst)) |some|
   4135         return some;
   4136 
   4137     const target = sema.mod.getTarget();
   4138 
   4139     switch (dest_type.zigTypeTag()) {
   4140         .Optional => {
   4141             // null to ?T
   4142             if (inst.ty.zigTypeTag() == .Null) {
   4143                 return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) });
   4144             }
   4145 
   4146             // T to ?T
   4147             var buf: Type.Payload.ElemType = undefined;
   4148             const child_type = dest_type.optionalChild(&buf);
   4149             if (child_type.eql(inst.ty)) {
   4150                 return sema.wrapOptional(block, dest_type, inst);
   4151             } else if (try sema.coerceNum(block, child_type, inst)) |some| {
   4152                 return sema.wrapOptional(block, dest_type, some);
   4153             }
   4154         },
   4155         .Pointer => {
   4156             // Coercions where the source is a single pointer to an array.
   4157             src_array_ptr: {
   4158                 if (!inst.ty.isSinglePointer()) break :src_array_ptr;
   4159                 const array_type = inst.ty.elemType();
   4160                 if (array_type.zigTypeTag() != .Array) break :src_array_ptr;
   4161                 const array_elem_type = array_type.elemType();
   4162                 if (inst.ty.isConstPtr() and !dest_type.isConstPtr()) break :src_array_ptr;
   4163                 if (inst.ty.isVolatilePtr() and !dest_type.isVolatilePtr()) break :src_array_ptr;
   4164 
   4165                 const dst_elem_type = dest_type.elemType();
   4166                 switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type)) {
   4167                     .ok => {},
   4168                     .no_match => break :src_array_ptr,
   4169                 }
   4170 
   4171                 switch (dest_type.ptrSize()) {
   4172                     .Slice => {
   4173                         // *[N]T to []T
   4174                         return sema.coerceArrayPtrToSlice(block, dest_type, inst);
   4175                     },
   4176                     .C => {
   4177                         // *[N]T to [*c]T
   4178                         return sema.coerceArrayPtrToMany(block, dest_type, inst);
   4179                     },
   4180                     .Many => {
   4181                         // *[N]T to [*]T
   4182                         // *[N:s]T to [*:s]T
   4183                         const src_sentinel = array_type.sentinel();
   4184                         const dst_sentinel = dest_type.sentinel();
   4185                         if (src_sentinel == null and dst_sentinel == null)
   4186                             return sema.coerceArrayPtrToMany(block, dest_type, inst);
   4187 
   4188                         if (src_sentinel) |src_s| {
   4189                             if (dst_sentinel) |dst_s| {
   4190                                 if (src_s.eql(dst_s)) {
   4191                                     return sema.coerceArrayPtrToMany(block, dest_type, inst);
   4192                                 }
   4193                             }
   4194                         }
   4195                     },
   4196                     .One => {},
   4197                 }
   4198             }
   4199         },
   4200         .Int => {
   4201             // integer widening
   4202             if (inst.ty.zigTypeTag() == .Int) {
   4203                 assert(inst.value() == null); // handled above
   4204 
   4205                 const dst_info = dest_type.intInfo(target);
   4206                 const src_info = inst.ty.intInfo(target);
   4207                 if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or
   4208                     // small enough unsigned ints can get casted to large enough signed ints
   4209                     (src_info.signedness == .signed and dst_info.signedness == .unsigned and dst_info.bits > src_info.bits))
   4210                 {
   4211                     try sema.requireRuntimeBlock(block, inst_src);
   4212                     return block.addUnOp(inst_src, dest_type, .intcast, inst);
   4213                 }
   4214             }
   4215         },
   4216         .Float => {
   4217             // float widening
   4218             if (inst.ty.zigTypeTag() == .Float) {
   4219                 assert(inst.value() == null); // handled above
   4220 
   4221                 const src_bits = inst.ty.floatBits(target);
   4222                 const dst_bits = dest_type.floatBits(target);
   4223                 if (dst_bits >= src_bits) {
   4224                     try sema.requireRuntimeBlock(block, inst_src);
   4225                     return block.addUnOp(inst_src, dest_type, .floatcast, inst);
   4226                 }
   4227             }
   4228         },
   4229         else => {},
   4230     }
   4231 
   4232     return sema.mod.fail(&block.base, inst_src, "expected {}, found {}", .{ dest_type, inst.ty });
   4233 }
   4234 
   4235 const InMemoryCoercionResult = enum {
   4236     ok,
   4237     no_match,
   4238 };
   4239 
   4240 fn coerceInMemoryAllowed(dest_type: Type, src_type: Type) InMemoryCoercionResult {
   4241     if (dest_type.eql(src_type))
   4242         return .ok;
   4243 
   4244     // TODO: implement more of this function
   4245 
   4246     return .no_match;
   4247 }
   4248 
   4249 fn coerceNum(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) InnerError!?*Inst {
   4250     const val = inst.value() orelse return null;
   4251     const src_zig_tag = inst.ty.zigTypeTag();
   4252     const dst_zig_tag = dest_type.zigTypeTag();
   4253 
   4254     const target = sema.mod.getTarget();
   4255 
   4256     if (dst_zig_tag == .ComptimeInt or dst_zig_tag == .Int) {
   4257         if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
   4258             if (val.floatHasFraction()) {
   4259                 return sema.mod.fail(&block.base, inst.src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst.ty });
   4260             }
   4261             return sema.mod.fail(&block.base, inst.src, "TODO float to int", .{});
   4262         } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
   4263             if (!val.intFitsInType(dest_type, target)) {
   4264                 return sema.mod.fail(&block.base, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
   4265             }
   4266             return sema.mod.constInst(sema.arena, inst.src, .{ .ty = dest_type, .val = val });
   4267         }
   4268     } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
   4269         if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
   4270             const res = val.floatCast(sema.arena, dest_type, target) catch |err| switch (err) {
   4271                 error.Overflow => return sema.mod.fail(
   4272                     &block.base,
   4273                     inst.src,
   4274                     "cast of value {} to type '{}' loses information",
   4275                     .{ val, dest_type },
   4276                 ),
   4277                 error.OutOfMemory => return error.OutOfMemory,
   4278             };
   4279             return sema.mod.constInst(sema.arena, inst.src, .{ .ty = dest_type, .val = res });
   4280         } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
   4281             return sema.mod.fail(&block.base, inst.src, "TODO int to float", .{});
   4282         }
   4283     }
   4284     return null;
   4285 }
   4286 
   4287 fn coerceVarArgParam(sema: *Sema, block: *Scope.Block, inst: *Inst) !*Inst {
   4288     switch (inst.ty.zigTypeTag()) {
   4289         .ComptimeInt, .ComptimeFloat => return sema.mod.fail(&block.base, inst.src, "integer and float literals in var args function must be casted", .{}),
   4290         else => {},
   4291     }
   4292     // TODO implement more of this function.
   4293     return inst;
   4294 }
   4295 
   4296 fn storePtr(
   4297     sema: *Sema,
   4298     block: *Scope.Block,
   4299     src: LazySrcLoc,
   4300     ptr: *Inst,
   4301     uncasted_value: *Inst,
   4302 ) !void {
   4303     if (ptr.ty.isConstPtr())
   4304         return sema.mod.fail(&block.base, src, "cannot assign to constant", .{});
   4305 
   4306     const elem_ty = ptr.ty.elemType();
   4307     const value = try sema.coerce(block, elem_ty, uncasted_value, src);
   4308     if (elem_ty.onePossibleValue() != null)
   4309         return;
   4310 
   4311     // TODO handle comptime pointer writes
   4312     // TODO handle if the element type requires comptime
   4313 
   4314     try sema.requireRuntimeBlock(block, src);
   4315     _ = try block.addBinOp(src, Type.initTag(.void), .store, ptr, value);
   4316 }
   4317 
   4318 fn bitcast(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {
   4319     if (inst.value()) |val| {
   4320         // Keep the comptime Value representation; take the new type.
   4321         return sema.mod.constInst(sema.arena, inst.src, .{ .ty = dest_type, .val = val });
   4322     }
   4323     // TODO validate the type size and other compile errors
   4324     try sema.requireRuntimeBlock(block, inst.src);
   4325     return block.addUnOp(inst.src, dest_type, .bitcast, inst);
   4326 }
   4327 
   4328 fn coerceArrayPtrToSlice(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {
   4329     if (inst.value()) |val| {
   4330         // The comptime Value representation is compatible with both types.
   4331         return sema.mod.constInst(sema.arena, inst.src, .{ .ty = dest_type, .val = val });
   4332     }
   4333     return sema.mod.fail(&block.base, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});
   4334 }
   4335 
   4336 fn coerceArrayPtrToMany(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {
   4337     if (inst.value()) |val| {
   4338         // The comptime Value representation is compatible with both types.
   4339         return sema.mod.constInst(sema.arena, inst.src, .{ .ty = dest_type, .val = val });
   4340     }
   4341     return sema.mod.fail(&block.base, inst.src, "TODO implement coerceArrayPtrToMany runtime instruction", .{});
   4342 }
   4343 
   4344 fn analyzeDeclVal(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst {
   4345     const decl_ref = try sema.analyzeDeclRef(block, src, decl);
   4346     return sema.analyzeLoad(block, src, decl_ref, src);
   4347 }
   4348 
   4349 fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst {
   4350     try sema.mod.declareDeclDependency(sema.owner_decl, decl);
   4351     sema.mod.ensureDeclAnalyzed(decl) catch |err| {
   4352         if (sema.func) |func| {
   4353             func.state = .dependency_failure;
   4354         } else {
   4355             sema.owner_decl.analysis = .dependency_failure;
   4356         }
   4357         return err;
   4358     };
   4359 
   4360     const decl_tv = try decl.typedValue();
   4361     if (decl_tv.val.tag() == .variable) {
   4362         return sema.analyzeVarRef(block, src, decl_tv);
   4363     }
   4364     return sema.mod.constInst(sema.arena, src, .{
   4365         .ty = try sema.mod.simplePtrType(sema.arena, decl_tv.ty, false, .One),
   4366         .val = try Value.Tag.decl_ref.create(sema.arena, decl),
   4367     });
   4368 }
   4369 
   4370 fn analyzeVarRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, tv: TypedValue) InnerError!*Inst {
   4371     const variable = tv.val.castTag(.variable).?.data;
   4372 
   4373     const ty = try sema.mod.simplePtrType(sema.arena, tv.ty, variable.is_mutable, .One);
   4374     if (!variable.is_mutable and !variable.is_extern) {
   4375         return sema.mod.constInst(sema.arena, src, .{
   4376             .ty = ty,
   4377             .val = try Value.Tag.ref_val.create(sema.arena, variable.init),
   4378         });
   4379     }
   4380 
   4381     try sema.requireRuntimeBlock(block, src);
   4382     const inst = try sema.arena.create(Inst.VarPtr);
   4383     inst.* = .{
   4384         .base = .{
   4385             .tag = .varptr,
   4386             .ty = ty,
   4387             .src = src,
   4388         },
   4389         .variable = variable,
   4390     };
   4391     try block.instructions.append(sema.gpa, &inst.base);
   4392     return &inst.base;
   4393 }
   4394 
   4395 fn analyzeRef(
   4396     sema: *Sema,
   4397     block: *Scope.Block,
   4398     src: LazySrcLoc,
   4399     operand: *Inst,
   4400 ) InnerError!*Inst {
   4401     const ptr_type = try sema.mod.simplePtrType(sema.arena, operand.ty, false, .One);
   4402 
   4403     if (operand.value()) |val| {
   4404         return sema.mod.constInst(sema.arena, src, .{
   4405             .ty = ptr_type,
   4406             .val = try Value.Tag.ref_val.create(sema.arena, val),
   4407         });
   4408     }
   4409 
   4410     try sema.requireRuntimeBlock(block, src);
   4411     return block.addUnOp(src, ptr_type, .ref, operand);
   4412 }
   4413 
   4414 fn analyzeLoad(
   4415     sema: *Sema,
   4416     block: *Scope.Block,
   4417     src: LazySrcLoc,
   4418     ptr: *Inst,
   4419     ptr_src: LazySrcLoc,
   4420 ) InnerError!*Inst {
   4421     const elem_ty = switch (ptr.ty.zigTypeTag()) {
   4422         .Pointer => ptr.ty.elemType(),
   4423         else => return sema.mod.fail(&block.base, ptr_src, "expected pointer, found '{}'", .{ptr.ty}),
   4424     };
   4425     if (ptr.value()) |val| {
   4426         return sema.mod.constInst(sema.arena, src, .{
   4427             .ty = elem_ty,
   4428             .val = try val.pointerDeref(sema.arena),
   4429         });
   4430     }
   4431 
   4432     try sema.requireRuntimeBlock(block, src);
   4433     return block.addUnOp(src, elem_ty, .load, ptr);
   4434 }
   4435 
   4436 fn analyzeIsNull(
   4437     sema: *Sema,
   4438     block: *Scope.Block,
   4439     src: LazySrcLoc,
   4440     operand: *Inst,
   4441     invert_logic: bool,
   4442 ) InnerError!*Inst {
   4443     if (operand.value()) |opt_val| {
   4444         const is_null = opt_val.isNull();
   4445         const bool_value = if (invert_logic) !is_null else is_null;
   4446         return sema.mod.constBool(sema.arena, src, bool_value);
   4447     }
   4448     try sema.requireRuntimeBlock(block, src);
   4449     const inst_tag: Inst.Tag = if (invert_logic) .is_non_null else .is_null;
   4450     return block.addUnOp(src, Type.initTag(.bool), inst_tag, operand);
   4451 }
   4452 
   4453 fn analyzeIsErr(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, operand: *Inst) InnerError!*Inst {
   4454     const ot = operand.ty.zigTypeTag();
   4455     if (ot != .ErrorSet and ot != .ErrorUnion) return sema.mod.constBool(sema.arena, src, false);
   4456     if (ot == .ErrorSet) return sema.mod.constBool(sema.arena, src, true);
   4457     assert(ot == .ErrorUnion);
   4458     if (operand.value()) |err_union| {
   4459         return sema.mod.constBool(sema.arena, src, err_union.getError() != null);
   4460     }
   4461     try sema.requireRuntimeBlock(block, src);
   4462     return block.addUnOp(src, Type.initTag(.bool), .is_err, operand);
   4463 }
   4464 
   4465 fn analyzeSlice(
   4466     sema: *Sema,
   4467     block: *Scope.Block,
   4468     src: LazySrcLoc,
   4469     array_ptr: *Inst,
   4470     start: *Inst,
   4471     end_opt: ?*Inst,
   4472     sentinel_opt: ?*Inst,
   4473     sentinel_src: LazySrcLoc,
   4474 ) InnerError!*Inst {
   4475     const ptr_child = switch (array_ptr.ty.zigTypeTag()) {
   4476         .Pointer => array_ptr.ty.elemType(),
   4477         else => return sema.mod.fail(&block.base, src, "expected pointer, found '{}'", .{array_ptr.ty}),
   4478     };
   4479 
   4480     var array_type = ptr_child;
   4481     const elem_type = switch (ptr_child.zigTypeTag()) {
   4482         .Array => ptr_child.elemType(),
   4483         .Pointer => blk: {
   4484             if (ptr_child.isSinglePointer()) {
   4485                 if (ptr_child.elemType().zigTypeTag() == .Array) {
   4486                     array_type = ptr_child.elemType();
   4487                     break :blk ptr_child.elemType().elemType();
   4488                 }
   4489 
   4490                 return sema.mod.fail(&block.base, src, "slice of single-item pointer", .{});
   4491             }
   4492             break :blk ptr_child.elemType();
   4493         },
   4494         else => return sema.mod.fail(&block.base, src, "slice of non-array type '{}'", .{ptr_child}),
   4495     };
   4496 
   4497     const slice_sentinel = if (sentinel_opt) |sentinel| blk: {
   4498         const casted = try sema.coerce(block, elem_type, sentinel, sentinel.src);
   4499         break :blk try sema.resolveConstValue(block, sentinel_src, casted);
   4500     } else null;
   4501 
   4502     var return_ptr_size: std.builtin.TypeInfo.Pointer.Size = .Slice;
   4503     var return_elem_type = elem_type;
   4504     if (end_opt) |end| {
   4505         if (end.value()) |end_val| {
   4506             if (start.value()) |start_val| {
   4507                 const start_u64 = start_val.toUnsignedInt();
   4508                 const end_u64 = end_val.toUnsignedInt();
   4509                 if (start_u64 > end_u64) {
   4510                     return sema.mod.fail(&block.base, src, "out of bounds slice", .{});
   4511                 }
   4512 
   4513                 const len = end_u64 - start_u64;
   4514                 const array_sentinel = if (array_type.zigTypeTag() == .Array and end_u64 == array_type.arrayLen())
   4515                     array_type.sentinel()
   4516                 else
   4517                     slice_sentinel;
   4518                 return_elem_type = try sema.mod.arrayType(sema.arena, len, array_sentinel, elem_type);
   4519                 return_ptr_size = .One;
   4520             }
   4521         }
   4522     }
   4523     const return_type = try sema.mod.ptrType(
   4524         sema.arena,
   4525         return_elem_type,
   4526         if (end_opt == null) slice_sentinel else null,
   4527         0, // TODO alignment
   4528         0,
   4529         0,
   4530         !ptr_child.isConstPtr(),
   4531         ptr_child.isAllowzeroPtr(),
   4532         ptr_child.isVolatilePtr(),
   4533         return_ptr_size,
   4534     );
   4535 
   4536     return sema.mod.fail(&block.base, src, "TODO implement analysis of slice", .{});
   4537 }
   4538 
   4539 fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_string: []const u8) !*Scope.File {
   4540     const cur_pkg = block.getFileScope().pkg;
   4541     const cur_pkg_dir_path = cur_pkg.root_src_directory.path orelse ".";
   4542     const found_pkg = cur_pkg.table.get(target_string);
   4543 
   4544     const resolved_path = if (found_pkg) |pkg|
   4545         try std.fs.path.resolve(sema.gpa, &[_][]const u8{ pkg.root_src_directory.path orelse ".", pkg.root_src_path })
   4546     else
   4547         try std.fs.path.resolve(sema.gpa, &[_][]const u8{ cur_pkg_dir_path, target_string });
   4548     errdefer sema.gpa.free(resolved_path);
   4549 
   4550     if (sema.mod.import_table.get(resolved_path)) |some| {
   4551         sema.gpa.free(resolved_path);
   4552         return some;
   4553     }
   4554 
   4555     if (found_pkg == null) {
   4556         const resolved_root_path = try std.fs.path.resolve(sema.gpa, &[_][]const u8{cur_pkg_dir_path});
   4557         defer sema.gpa.free(resolved_root_path);
   4558 
   4559         if (!mem.startsWith(u8, resolved_path, resolved_root_path)) {
   4560             return error.ImportOutsidePkgPath;
   4561         }
   4562     }
   4563 
   4564     // TODO Scope.Container arena for ty and sub_file_path
   4565     const file_scope = try sema.gpa.create(Scope.File);
   4566     errdefer sema.gpa.destroy(file_scope);
   4567     const struct_ty = try Type.Tag.empty_struct.create(sema.gpa, &file_scope.root_container);
   4568     errdefer sema.gpa.destroy(struct_ty.castTag(.empty_struct).?);
   4569 
   4570     file_scope.* = .{
   4571         .sub_file_path = resolved_path,
   4572         .source = .{ .unloaded = {} },
   4573         .tree = undefined,
   4574         .status = .never_loaded,
   4575         .pkg = found_pkg orelse cur_pkg,
   4576         .root_container = .{
   4577             .file_scope = file_scope,
   4578             .decls = .{},
   4579             .ty = struct_ty,
   4580         },
   4581     };
   4582     sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
   4583         error.AnalysisFail => {
   4584             assert(sema.mod.comp.totalErrorCount() != 0);
   4585         },
   4586         else => |e| return e,
   4587     };
   4588     try sema.mod.import_table.put(sema.gpa, file_scope.sub_file_path, file_scope);
   4589     return file_scope;
   4590 }
   4591 
   4592 /// Asserts that lhs and rhs types are both numeric.
   4593 fn cmpNumeric(
   4594     sema: *Sema,
   4595     block: *Scope.Block,
   4596     src: LazySrcLoc,
   4597     lhs: *Inst,
   4598     rhs: *Inst,
   4599     op: std.math.CompareOperator,
   4600 ) InnerError!*Inst {
   4601     assert(lhs.ty.isNumeric());
   4602     assert(rhs.ty.isNumeric());
   4603 
   4604     const lhs_ty_tag = lhs.ty.zigTypeTag();
   4605     const rhs_ty_tag = rhs.ty.zigTypeTag();
   4606 
   4607     if (lhs_ty_tag == .Vector and rhs_ty_tag == .Vector) {
   4608         if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
   4609             return sema.mod.fail(&block.base, src, "vector length mismatch: {d} and {d}", .{
   4610                 lhs.ty.arrayLen(),
   4611                 rhs.ty.arrayLen(),
   4612             });
   4613         }
   4614         return sema.mod.fail(&block.base, src, "TODO implement support for vectors in cmpNumeric", .{});
   4615     } else if (lhs_ty_tag == .Vector or rhs_ty_tag == .Vector) {
   4616         return sema.mod.fail(&block.base, src, "mixed scalar and vector operands to comparison operator: '{}' and '{}'", .{
   4617             lhs.ty,
   4618             rhs.ty,
   4619         });
   4620     }
   4621 
   4622     if (lhs.value()) |lhs_val| {
   4623         if (rhs.value()) |rhs_val| {
   4624             return sema.mod.constBool(sema.arena, src, Value.compare(lhs_val, op, rhs_val));
   4625         }
   4626     }
   4627 
   4628     // TODO handle comparisons against lazy zero values
   4629     // Some values can be compared against zero without being runtime known or without forcing
   4630     // a full resolution of their value, for example `@sizeOf(@Frame(function))` is known to
   4631     // always be nonzero, and we benefit from not forcing the full evaluation and stack frame layout
   4632     // of this function if we don't need to.
   4633 
   4634     // It must be a runtime comparison.
   4635     try sema.requireRuntimeBlock(block, src);
   4636     // For floats, emit a float comparison instruction.
   4637     const lhs_is_float = switch (lhs_ty_tag) {
   4638         .Float, .ComptimeFloat => true,
   4639         else => false,
   4640     };
   4641     const rhs_is_float = switch (rhs_ty_tag) {
   4642         .Float, .ComptimeFloat => true,
   4643         else => false,
   4644     };
   4645     const target = sema.mod.getTarget();
   4646     if (lhs_is_float and rhs_is_float) {
   4647         // Implicit cast the smaller one to the larger one.
   4648         const dest_type = x: {
   4649             if (lhs_ty_tag == .ComptimeFloat) {
   4650                 break :x rhs.ty;
   4651             } else if (rhs_ty_tag == .ComptimeFloat) {
   4652                 break :x lhs.ty;
   4653             }
   4654             if (lhs.ty.floatBits(target) >= rhs.ty.floatBits(target)) {
   4655                 break :x lhs.ty;
   4656             } else {
   4657                 break :x rhs.ty;
   4658             }
   4659         };
   4660         const casted_lhs = try sema.coerce(block, dest_type, lhs, lhs.src);
   4661         const casted_rhs = try sema.coerce(block, dest_type, rhs, rhs.src);
   4662         return block.addBinOp(src, dest_type, Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
   4663     }
   4664     // For mixed unsigned integer sizes, implicit cast both operands to the larger integer.
   4665     // For mixed signed and unsigned integers, implicit cast both operands to a signed
   4666     // integer with + 1 bit.
   4667     // For mixed floats and integers, extract the integer part from the float, cast that to
   4668     // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
   4669     // add/subtract 1.
   4670     const lhs_is_signed = if (lhs.value()) |lhs_val|
   4671         lhs_val.compareWithZero(.lt)
   4672     else
   4673         (lhs.ty.isFloat() or lhs.ty.isSignedInt());
   4674     const rhs_is_signed = if (rhs.value()) |rhs_val|
   4675         rhs_val.compareWithZero(.lt)
   4676     else
   4677         (rhs.ty.isFloat() or rhs.ty.isSignedInt());
   4678     const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
   4679 
   4680     var dest_float_type: ?Type = null;
   4681 
   4682     var lhs_bits: usize = undefined;
   4683     if (lhs.value()) |lhs_val| {
   4684         if (lhs_val.isUndef())
   4685             return sema.mod.constUndef(sema.arena, src, Type.initTag(.bool));
   4686         const is_unsigned = if (lhs_is_float) x: {
   4687             var bigint_space: Value.BigIntSpace = undefined;
   4688             var bigint = try lhs_val.toBigInt(&bigint_space).toManaged(sema.gpa);
   4689             defer bigint.deinit();
   4690             const zcmp = lhs_val.orderAgainstZero();
   4691             if (lhs_val.floatHasFraction()) {
   4692                 switch (op) {
   4693                     .eq => return sema.mod.constBool(sema.arena, src, false),
   4694                     .neq => return sema.mod.constBool(sema.arena, src, true),
   4695                     else => {},
   4696                 }
   4697                 if (zcmp == .lt) {
   4698                     try bigint.addScalar(bigint.toConst(), -1);
   4699                 } else {
   4700                     try bigint.addScalar(bigint.toConst(), 1);
   4701                 }
   4702             }
   4703             lhs_bits = bigint.toConst().bitCountTwosComp();
   4704             break :x (zcmp != .lt);
   4705         } else x: {
   4706             lhs_bits = lhs_val.intBitCountTwosComp();
   4707             break :x (lhs_val.orderAgainstZero() != .lt);
   4708         };
   4709         lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
   4710     } else if (lhs_is_float) {
   4711         dest_float_type = lhs.ty;
   4712     } else {
   4713         const int_info = lhs.ty.intInfo(target);
   4714         lhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed);
   4715     }
   4716 
   4717     var rhs_bits: usize = undefined;
   4718     if (rhs.value()) |rhs_val| {
   4719         if (rhs_val.isUndef())
   4720             return sema.mod.constUndef(sema.arena, src, Type.initTag(.bool));
   4721         const is_unsigned = if (rhs_is_float) x: {
   4722             var bigint_space: Value.BigIntSpace = undefined;
   4723             var bigint = try rhs_val.toBigInt(&bigint_space).toManaged(sema.gpa);
   4724             defer bigint.deinit();
   4725             const zcmp = rhs_val.orderAgainstZero();
   4726             if (rhs_val.floatHasFraction()) {
   4727                 switch (op) {
   4728                     .eq => return sema.mod.constBool(sema.arena, src, false),
   4729                     .neq => return sema.mod.constBool(sema.arena, src, true),
   4730                     else => {},
   4731                 }
   4732                 if (zcmp == .lt) {
   4733                     try bigint.addScalar(bigint.toConst(), -1);
   4734                 } else {
   4735                     try bigint.addScalar(bigint.toConst(), 1);
   4736                 }
   4737             }
   4738             rhs_bits = bigint.toConst().bitCountTwosComp();
   4739             break :x (zcmp != .lt);
   4740         } else x: {
   4741             rhs_bits = rhs_val.intBitCountTwosComp();
   4742             break :x (rhs_val.orderAgainstZero() != .lt);
   4743         };
   4744         rhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
   4745     } else if (rhs_is_float) {
   4746         dest_float_type = rhs.ty;
   4747     } else {
   4748         const int_info = rhs.ty.intInfo(target);
   4749         rhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed);
   4750     }
   4751 
   4752     const dest_type = if (dest_float_type) |ft| ft else blk: {
   4753         const max_bits = std.math.max(lhs_bits, rhs_bits);
   4754         const casted_bits = std.math.cast(u16, max_bits) catch |err| switch (err) {
   4755             error.Overflow => return sema.mod.fail(&block.base, src, "{d} exceeds maximum integer bit count", .{max_bits}),
   4756         };
   4757         const signedness: std.builtin.Signedness = if (dest_int_is_signed) .signed else .unsigned;
   4758         break :blk try Module.makeIntType(sema.arena, signedness, casted_bits);
   4759     };
   4760     const casted_lhs = try sema.coerce(block, dest_type, lhs, lhs.src);
   4761     const casted_rhs = try sema.coerce(block, dest_type, rhs, rhs.src);
   4762 
   4763     return block.addBinOp(src, Type.initTag(.bool), Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
   4764 }
   4765 
   4766 fn wrapOptional(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {
   4767     if (inst.value()) |val| {
   4768         return sema.mod.constInst(sema.arena, inst.src, .{ .ty = dest_type, .val = val });
   4769     }
   4770 
   4771     try sema.requireRuntimeBlock(block, inst.src);
   4772     return block.addUnOp(inst.src, dest_type, .wrap_optional, inst);
   4773 }
   4774 
   4775 fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {
   4776     // TODO deal with inferred error sets
   4777     const err_union = dest_type.castTag(.error_union).?;
   4778     if (inst.value()) |val| {
   4779         const to_wrap = if (inst.ty.zigTypeTag() != .ErrorSet) blk: {
   4780             _ = try sema.coerce(block, err_union.data.payload, inst, inst.src);
   4781             break :blk val;
   4782         } else switch (err_union.data.error_set.tag()) {
   4783             .anyerror => val,
   4784             .error_set_single => blk: {
   4785                 const expected_name = val.castTag(.@"error").?.data.name;
   4786                 const n = err_union.data.error_set.castTag(.error_set_single).?.data;
   4787                 if (!mem.eql(u8, expected_name, n)) {
   4788                     return sema.mod.fail(
   4789                         &block.base,
   4790                         inst.src,
   4791                         "expected type '{}', found type '{}'",
   4792                         .{ err_union.data.error_set, inst.ty },
   4793                     );
   4794                 }
   4795                 break :blk val;
   4796             },
   4797             .error_set => blk: {
   4798                 const expected_name = val.castTag(.@"error").?.data.name;
   4799                 const error_set = err_union.data.error_set.castTag(.error_set).?.data;
   4800                 const names = error_set.names_ptr[0..error_set.names_len];
   4801                 // TODO this is O(N). I'm putting off solving this until we solve inferred
   4802                 // error sets at the same time.
   4803                 const found = for (names) |name| {
   4804                     if (mem.eql(u8, expected_name, name)) break true;
   4805                 } else false;
   4806                 if (!found) {
   4807                     return sema.mod.fail(
   4808                         &block.base,
   4809                         inst.src,
   4810                         "expected type '{}', found type '{}'",
   4811                         .{ err_union.data.error_set, inst.ty },
   4812                     );
   4813                 }
   4814                 break :blk val;
   4815             },
   4816             else => unreachable,
   4817         };
   4818 
   4819         return sema.mod.constInst(sema.arena, inst.src, .{
   4820             .ty = dest_type,
   4821             // creating a SubValue for the error_union payload
   4822             .val = try Value.Tag.error_union.create(
   4823                 sema.arena,
   4824                 to_wrap,
   4825             ),
   4826         });
   4827     }
   4828 
   4829     try sema.requireRuntimeBlock(block, inst.src);
   4830 
   4831     // we are coercing from E to E!T
   4832     if (inst.ty.zigTypeTag() == .ErrorSet) {
   4833         var coerced = try sema.coerce(block, err_union.data.error_set, inst, inst.src);
   4834         return block.addUnOp(inst.src, dest_type, .wrap_errunion_err, coerced);
   4835     } else {
   4836         var coerced = try sema.coerce(block, err_union.data.payload, inst, inst.src);
   4837         return block.addUnOp(inst.src, dest_type, .wrap_errunion_payload, coerced);
   4838     }
   4839 }
   4840 
   4841 fn resolvePeerTypes(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, instructions: []*Inst) !Type {
   4842     if (instructions.len == 0)
   4843         return Type.initTag(.noreturn);
   4844 
   4845     if (instructions.len == 1)
   4846         return instructions[0].ty;
   4847 
   4848     const target = sema.mod.getTarget();
   4849 
   4850     var chosen = instructions[0];
   4851     for (instructions[1..]) |candidate| {
   4852         if (candidate.ty.eql(chosen.ty))
   4853             continue;
   4854         if (candidate.ty.zigTypeTag() == .NoReturn)
   4855             continue;
   4856         if (chosen.ty.zigTypeTag() == .NoReturn) {
   4857             chosen = candidate;
   4858             continue;
   4859         }
   4860         if (candidate.ty.zigTypeTag() == .Undefined)
   4861             continue;
   4862         if (chosen.ty.zigTypeTag() == .Undefined) {
   4863             chosen = candidate;
   4864             continue;
   4865         }
   4866         if (chosen.ty.isInt() and
   4867             candidate.ty.isInt() and
   4868             chosen.ty.isSignedInt() == candidate.ty.isSignedInt())
   4869         {
   4870             if (chosen.ty.intInfo(target).bits < candidate.ty.intInfo(target).bits) {
   4871                 chosen = candidate;
   4872             }
   4873             continue;
   4874         }
   4875         if (chosen.ty.isFloat() and candidate.ty.isFloat()) {
   4876             if (chosen.ty.floatBits(target) < candidate.ty.floatBits(target)) {
   4877                 chosen = candidate;
   4878             }
   4879             continue;
   4880         }
   4881 
   4882         if (chosen.ty.zigTypeTag() == .ComptimeInt and candidate.ty.isInt()) {
   4883             chosen = candidate;
   4884             continue;
   4885         }
   4886 
   4887         if (chosen.ty.isInt() and candidate.ty.zigTypeTag() == .ComptimeInt) {
   4888             continue;
   4889         }
   4890 
   4891         // TODO error notes pointing out each type
   4892         return sema.mod.fail(&block.base, src, "incompatible types: '{}' and '{}'", .{ chosen.ty, candidate.ty });
   4893     }
   4894 
   4895     return chosen.ty;
   4896 }