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 }