blob 385ea7e9 (1487359B) - Raw
1 //! Semantic analysis of ZIR instructions. 2 //! Shared to every Block. Stored on the stack. 3 //! State used for compiling a ZIR into AIR. 4 //! Transforms untyped ZIR instructions into semantically-analyzed AIR instructions. 5 //! Does type checking, comptime control flow, and safety-check generation. 6 //! This is the the heart of the Zig compiler. 7 8 mod: *Module, 9 /// Alias to `mod.gpa`. 10 gpa: Allocator, 11 /// Points to the temporary arena allocator of the Sema. 12 /// This arena will be cleared when the sema is destroyed. 13 arena: Allocator, 14 /// Points to the arena allocator for the owner_decl. 15 /// This arena will persist until the decl is invalidated. 16 perm_arena: Allocator, 17 code: Zir, 18 air_instructions: std.MultiArrayList(Air.Inst) = .{}, 19 air_extra: std.ArrayListUnmanaged(u32) = .{}, 20 /// Maps ZIR to AIR. 21 inst_map: InstMap = .{}, 22 /// When analyzing an inline function call, owner_decl is the Decl of the caller 23 /// and `src_decl` of `Block` is the `Decl` of the callee. 24 /// This `Decl` owns the arena memory of this `Sema`. 25 owner_decl: *Decl, 26 owner_decl_index: Decl.Index, 27 /// For an inline or comptime function call, this will be the root parent function 28 /// which contains the callsite. Corresponds to `owner_decl`. 29 owner_func: ?*Module.Fn, 30 owner_func_index: Module.Fn.OptionalIndex, 31 /// The function this ZIR code is the body of, according to the source code. 32 /// This starts out the same as `owner_func` and then diverges in the case of 33 /// an inline or comptime function call. 34 func: ?*Module.Fn, 35 func_index: Module.Fn.OptionalIndex, 36 /// Used to restore the error return trace when returning a non-error from a function. 37 error_return_trace_index_on_fn_entry: Air.Inst.Ref = .none, 38 /// When semantic analysis needs to know the return type of the function whose body 39 /// is being analyzed, this `Type` should be used instead of going through `func`. 40 /// This will correctly handle the case of a comptime/inline function call of a 41 /// generic function which uses a type expression for the return type. 42 /// The type will be `void` in the case that `func` is `null`. 43 fn_ret_ty: Type, 44 branch_quota: u32 = default_branch_quota, 45 branch_count: u32 = 0, 46 /// Populated when returning `error.ComptimeBreak`. Used to communicate the 47 /// break instruction up the stack to find the corresponding Block. 48 comptime_break_inst: Zir.Inst.Index = undefined, 49 /// This field is updated when a new source location becomes active, so that 50 /// instructions which do not have explicitly mapped source locations still have 51 /// access to the source location set by the previous instruction which did 52 /// contain a mapped source location. 53 src: LazySrcLoc = .{ .token_offset = 0 }, 54 decl_val_table: std.AutoHashMapUnmanaged(Decl.Index, Air.Inst.Ref) = .{}, 55 /// When doing a generic function instantiation, this array collects a 56 /// `Value` object for each parameter that is comptime-known and thus elided 57 /// from the generated function. This memory is allocated by a parent `Sema` and 58 /// owned by the values arena of the Sema owner_decl. 59 comptime_args: []TypedValue = &.{}, 60 /// Marks the function instruction that `comptime_args` applies to so that we 61 /// don't accidentally apply it to a function prototype which is used in the 62 /// type expression of a generic function parameter. 63 comptime_args_fn_inst: Zir.Inst.Index = 0, 64 /// When `comptime_args` is provided, this field is also provided. It was used as 65 /// the key in the `monomorphed_funcs` set. The `func` instruction is supposed 66 /// to use this instead of allocating a fresh one. This avoids an unnecessary 67 /// extra hash table lookup in the `monomorphed_funcs` set. 68 /// Sema will set this to null when it takes ownership. 69 preallocated_new_func: Module.Fn.OptionalIndex = .none, 70 /// The key is types that must be fully resolved prior to machine code 71 /// generation pass. Types are added to this set when resolving them 72 /// immediately could cause a dependency loop, but they do need to be resolved 73 /// before machine code generation passes process the AIR. 74 /// It would work fine if this were an array list instead of an array hash map. 75 /// I chose array hash map with the intention to save time by omitting 76 /// duplicates. 77 types_to_resolve: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{}, 78 /// These are lazily created runtime blocks from block_inline instructions. 79 /// They are created when an break_inline passes through a runtime condition, because 80 /// Sema must convert comptime control flow to runtime control flow, which means 81 /// breaking from a block. 82 post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{}, 83 /// Populated with the last compile error created. 84 err: ?*Module.ErrorMsg = null, 85 /// True when analyzing a generic instantiation. Used to suppress some errors. 86 is_generic_instantiation: bool = false, 87 /// Set to true when analyzing a func type instruction so that nested generic 88 /// function types will emit generic poison instead of a partial type. 89 no_partial_func_ty: bool = false, 90 91 /// The temporary arena is used for the memory of the `InferredAlloc` values 92 /// here so the values can be dropped without any cleanup. 93 unresolved_inferred_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, InferredAlloc) = .{}, 94 95 const std = @import("std"); 96 const math = std.math; 97 const mem = std.mem; 98 const Allocator = mem.Allocator; 99 const assert = std.debug.assert; 100 const log = std.log.scoped(.sema); 101 102 const Sema = @This(); 103 const Value = @import("value.zig").Value; 104 const Type = @import("type.zig").Type; 105 const TypedValue = @import("TypedValue.zig"); 106 const Air = @import("Air.zig"); 107 const Zir = @import("Zir.zig"); 108 const Module = @import("Module.zig"); 109 const trace = @import("tracy.zig").trace; 110 const Namespace = Module.Namespace; 111 const CompileError = Module.CompileError; 112 const SemaError = Module.SemaError; 113 const Decl = Module.Decl; 114 const CaptureScope = Module.CaptureScope; 115 const WipCaptureScope = Module.WipCaptureScope; 116 const LazySrcLoc = Module.LazySrcLoc; 117 const RangeSet = @import("RangeSet.zig"); 118 const target_util = @import("target.zig"); 119 const Package = @import("Package.zig"); 120 const crash_report = @import("crash_report.zig"); 121 const build_options = @import("build_options"); 122 const Compilation = @import("Compilation.zig"); 123 const InternPool = @import("InternPool.zig"); 124 125 pub const default_branch_quota = 1000; 126 pub const default_reference_trace_len = 2; 127 128 /// Stores the mapping from `Zir.Inst.Index -> Air.Inst.Ref`, which is used by sema to resolve 129 /// instructions during analysis. 130 /// Instead of a hash table approach, InstMap is simply a slice that is indexed into using the 131 /// zir instruction index and a start offset. An index is not pressent in the map if the value 132 /// at the index is `Air.Inst.Ref.none`. 133 /// `ensureSpaceForInstructions` can be called to force InstMap to have a mapped range that 134 /// includes all instructions in a slice. After calling this function, `putAssumeCapacity*` can 135 /// be called safely for any of the instructions passed in. 136 pub const InstMap = struct { 137 items: []Air.Inst.Ref = &[_]Air.Inst.Ref{}, 138 start: Zir.Inst.Index = 0, 139 140 pub fn deinit(map: InstMap, allocator: mem.Allocator) void { 141 allocator.free(map.items); 142 } 143 144 pub fn get(map: InstMap, key: Zir.Inst.Index) ?Air.Inst.Ref { 145 if (!map.contains(key)) return null; 146 return map.items[key - map.start]; 147 } 148 149 pub fn putAssumeCapacity( 150 map: *InstMap, 151 key: Zir.Inst.Index, 152 ref: Air.Inst.Ref, 153 ) void { 154 map.items[key - map.start] = ref; 155 } 156 157 pub fn putAssumeCapacityNoClobber( 158 map: *InstMap, 159 key: Zir.Inst.Index, 160 ref: Air.Inst.Ref, 161 ) void { 162 assert(!map.contains(key)); 163 map.putAssumeCapacity(key, ref); 164 } 165 166 pub const GetOrPutResult = struct { 167 value_ptr: *Air.Inst.Ref, 168 found_existing: bool, 169 }; 170 171 pub fn getOrPutAssumeCapacity( 172 map: *InstMap, 173 key: Zir.Inst.Index, 174 ) GetOrPutResult { 175 const index = key - map.start; 176 return GetOrPutResult{ 177 .value_ptr = &map.items[index], 178 .found_existing = map.items[index] != .none, 179 }; 180 } 181 182 pub fn remove(map: InstMap, key: Zir.Inst.Index) bool { 183 if (!map.contains(key)) return false; 184 map.items[key - map.start] = .none; 185 return true; 186 } 187 188 pub fn contains(map: InstMap, key: Zir.Inst.Index) bool { 189 return map.items[key - map.start] != .none; 190 } 191 192 pub fn ensureSpaceForInstructions( 193 map: *InstMap, 194 allocator: mem.Allocator, 195 insts: []const Zir.Inst.Index, 196 ) !void { 197 const min_max = mem.minMax(Zir.Inst.Index, insts); 198 const start = min_max.min; 199 const end = min_max.max; 200 if (map.start <= start and end < map.items.len + map.start) 201 return; 202 203 const old_start = if (map.items.len == 0) start else map.start; 204 var better_capacity = map.items.len; 205 var better_start = old_start; 206 while (true) { 207 const extra_capacity = better_capacity / 2 + 16; 208 better_capacity += extra_capacity; 209 better_start -|= @intCast(Zir.Inst.Index, extra_capacity / 2); 210 if (better_start <= start and end < better_capacity + better_start) 211 break; 212 } 213 214 const start_diff = old_start - better_start; 215 const new_items = try allocator.alloc(Air.Inst.Ref, better_capacity); 216 @memset(new_items[0..start_diff], .none); 217 @memcpy(new_items[start_diff..][0..map.items.len], map.items); 218 @memset(new_items[start_diff + map.items.len ..], .none); 219 220 allocator.free(map.items); 221 map.items = new_items; 222 map.start = @intCast(Zir.Inst.Index, better_start); 223 } 224 }; 225 226 /// This is the context needed to semantically analyze ZIR instructions and 227 /// produce AIR instructions. 228 /// This is a temporary structure stored on the stack; references to it are valid only 229 /// during semantic analysis of the block. 230 pub const Block = struct { 231 parent: ?*Block, 232 /// Shared among all child blocks. 233 sema: *Sema, 234 /// The namespace to use for lookups from this source block 235 /// When analyzing fields, this is different from src_decl.src_namespace. 236 namespace: Namespace.Index, 237 /// The AIR instructions generated for this block. 238 instructions: std.ArrayListUnmanaged(Air.Inst.Index), 239 // `param` instructions are collected here to be used by the `func` instruction. 240 params: std.ArrayListUnmanaged(Param) = .{}, 241 242 wip_capture_scope: *CaptureScope, 243 244 label: ?*Label = null, 245 inlining: ?*Inlining, 246 /// If runtime_index is not 0 then one of these is guaranteed to be non null. 247 runtime_cond: ?LazySrcLoc = null, 248 runtime_loop: ?LazySrcLoc = null, 249 /// This Decl is the Decl according to the Zig source code corresponding to this Block. 250 /// This can vary during inline or comptime function calls. See `Sema.owner_decl` 251 /// for the one that will be the same for all Block instances. 252 src_decl: Decl.Index, 253 /// Non zero if a non-inline loop or a runtime conditional have been encountered. 254 /// Stores to comptime variables are only allowed when var.runtime_index <= runtime_index. 255 runtime_index: Value.RuntimeIndex = .zero, 256 inline_block: Zir.Inst.Index = 0, 257 258 comptime_reason: ?*const ComptimeReason = null, 259 // TODO is_comptime and comptime_reason should probably be merged together. 260 is_comptime: bool, 261 is_typeof: bool = false, 262 263 /// Keep track of the active error return trace index around blocks so that we can correctly 264 /// pop the error trace upon block exit. 265 error_return_trace_index: Air.Inst.Ref = .none, 266 267 /// when null, it is determined by build mode, changed by @setRuntimeSafety 268 want_safety: ?bool = null, 269 270 /// What mode to generate float operations in, set by @setFloatMode 271 float_mode: std.builtin.FloatMode = .Strict, 272 273 c_import_buf: ?*std.ArrayList(u8) = null, 274 275 /// type of `err` in `else => |err|` 276 switch_else_err_ty: ?Type = null, 277 278 /// Value for switch_capture in an inline case 279 inline_case_capture: Air.Inst.Ref = .none, 280 281 const ComptimeReason = union(enum) { 282 c_import: struct { 283 block: *Block, 284 src: LazySrcLoc, 285 }, 286 comptime_ret_ty: struct { 287 block: *Block, 288 func: Air.Inst.Ref, 289 func_src: LazySrcLoc, 290 return_ty: Type, 291 }, 292 293 fn explain(cr: ComptimeReason, sema: *Sema, msg: ?*Module.ErrorMsg) !void { 294 const parent = msg orelse return; 295 const mod = sema.mod; 296 const prefix = "expression is evaluated at comptime because "; 297 switch (cr) { 298 .c_import => |ci| { 299 try sema.errNote(ci.block, ci.src, parent, prefix ++ "it is inside a @cImport", .{}); 300 }, 301 .comptime_ret_ty => |rt| { 302 const src_loc = if (try sema.funcDeclSrc(rt.func)) |fn_decl| blk: { 303 var src_loc = fn_decl.srcLoc(mod); 304 src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 }; 305 break :blk src_loc; 306 } else blk: { 307 const src_decl = sema.mod.declPtr(rt.block.src_decl); 308 break :blk rt.func_src.toSrcLoc(src_decl, mod); 309 }; 310 if (rt.return_ty.isGenericPoison()) { 311 return sema.mod.errNoteNonLazy(src_loc, parent, prefix ++ "the generic function was instantiated with a comptime-only return type", .{}); 312 } 313 try sema.mod.errNoteNonLazy( 314 src_loc, 315 parent, 316 prefix ++ "the function returns a comptime-only type '{}'", 317 .{rt.return_ty.fmt(sema.mod)}, 318 ); 319 try sema.explainWhyTypeIsComptime(parent, src_loc, rt.return_ty); 320 }, 321 } 322 } 323 }; 324 325 const Param = struct { 326 /// `noreturn` means `anytype`. 327 ty: Type, 328 is_comptime: bool, 329 name: []const u8, 330 }; 331 332 /// This `Block` maps a block ZIR instruction to the corresponding 333 /// AIR instruction for break instruction analysis. 334 pub const Label = struct { 335 zir_block: Zir.Inst.Index, 336 merges: Merges, 337 }; 338 339 /// This `Block` indicates that an inline function call is happening 340 /// and return instructions should be analyzed as a break instruction 341 /// to this AIR block instruction. 342 /// It is shared among all the blocks in an inline or comptime called 343 /// function. 344 pub const Inlining = struct { 345 func: ?*Module.Fn, 346 comptime_result: Air.Inst.Ref, 347 merges: Merges, 348 }; 349 350 pub const Merges = struct { 351 block_inst: Air.Inst.Index, 352 /// Separate array list from break_inst_list so that it can be passed directly 353 /// to resolvePeerTypes. 354 results: std.ArrayListUnmanaged(Air.Inst.Ref), 355 /// Keeps track of the break instructions so that the operand can be replaced 356 /// if we need to add type coercion at the end of block analysis. 357 /// Same indexes, capacity, length as `results`. 358 br_list: std.ArrayListUnmanaged(Air.Inst.Index), 359 /// Keeps the source location of the rhs operand of the break instruction, 360 /// to enable more precise compile errors. 361 /// Same indexes, capacity, length as `results`. 362 src_locs: std.ArrayListUnmanaged(?LazySrcLoc), 363 364 pub fn deinit(merges: *@This(), allocator: mem.Allocator) void { 365 merges.results.deinit(allocator); 366 merges.br_list.deinit(allocator); 367 merges.src_locs.deinit(allocator); 368 } 369 }; 370 371 /// For debugging purposes. 372 pub fn dump(block: *Block, mod: Module) void { 373 Zir.dumpBlock(mod, block); 374 } 375 376 pub fn makeSubBlock(parent: *Block) Block { 377 return .{ 378 .parent = parent, 379 .sema = parent.sema, 380 .src_decl = parent.src_decl, 381 .namespace = parent.namespace, 382 .instructions = .{}, 383 .wip_capture_scope = parent.wip_capture_scope, 384 .label = null, 385 .inlining = parent.inlining, 386 .is_comptime = parent.is_comptime, 387 .comptime_reason = parent.comptime_reason, 388 .is_typeof = parent.is_typeof, 389 .runtime_cond = parent.runtime_cond, 390 .runtime_loop = parent.runtime_loop, 391 .runtime_index = parent.runtime_index, 392 .want_safety = parent.want_safety, 393 .float_mode = parent.float_mode, 394 .c_import_buf = parent.c_import_buf, 395 .switch_else_err_ty = parent.switch_else_err_ty, 396 .error_return_trace_index = parent.error_return_trace_index, 397 }; 398 } 399 400 pub fn wantSafety(block: *const Block) bool { 401 return block.want_safety orelse switch (block.sema.mod.optimizeMode()) { 402 .Debug => true, 403 .ReleaseSafe => true, 404 .ReleaseFast => false, 405 .ReleaseSmall => false, 406 }; 407 } 408 409 pub fn getFileScope(block: *Block, mod: *Module) *Module.File { 410 return mod.namespacePtr(block.namespace).file_scope; 411 } 412 413 fn addTy( 414 block: *Block, 415 tag: Air.Inst.Tag, 416 ty: Type, 417 ) error{OutOfMemory}!Air.Inst.Ref { 418 return block.addInst(.{ 419 .tag = tag, 420 .data = .{ .ty = ty }, 421 }); 422 } 423 424 fn addTyOp( 425 block: *Block, 426 tag: Air.Inst.Tag, 427 ty: Type, 428 operand: Air.Inst.Ref, 429 ) error{OutOfMemory}!Air.Inst.Ref { 430 return block.addInst(.{ 431 .tag = tag, 432 .data = .{ .ty_op = .{ 433 .ty = try block.sema.addType(ty), 434 .operand = operand, 435 } }, 436 }); 437 } 438 439 fn addBitCast(block: *Block, ty: Type, operand: Air.Inst.Ref) Allocator.Error!Air.Inst.Ref { 440 return block.addInst(.{ 441 .tag = .bitcast, 442 .data = .{ .ty_op = .{ 443 .ty = try block.sema.addType(ty), 444 .operand = operand, 445 } }, 446 }); 447 } 448 449 fn addNoOp(block: *Block, tag: Air.Inst.Tag) error{OutOfMemory}!Air.Inst.Ref { 450 return block.addInst(.{ 451 .tag = tag, 452 .data = .{ .no_op = {} }, 453 }); 454 } 455 456 fn addUnOp( 457 block: *Block, 458 tag: Air.Inst.Tag, 459 operand: Air.Inst.Ref, 460 ) error{OutOfMemory}!Air.Inst.Ref { 461 return block.addInst(.{ 462 .tag = tag, 463 .data = .{ .un_op = operand }, 464 }); 465 } 466 467 fn addBr( 468 block: *Block, 469 target_block: Air.Inst.Index, 470 operand: Air.Inst.Ref, 471 ) error{OutOfMemory}!Air.Inst.Ref { 472 return block.addInst(.{ 473 .tag = .br, 474 .data = .{ .br = .{ 475 .block_inst = target_block, 476 .operand = operand, 477 } }, 478 }); 479 } 480 481 fn addBinOp( 482 block: *Block, 483 tag: Air.Inst.Tag, 484 lhs: Air.Inst.Ref, 485 rhs: Air.Inst.Ref, 486 ) error{OutOfMemory}!Air.Inst.Ref { 487 return block.addInst(.{ 488 .tag = tag, 489 .data = .{ .bin_op = .{ 490 .lhs = lhs, 491 .rhs = rhs, 492 } }, 493 }); 494 } 495 496 fn addStructFieldPtr( 497 block: *Block, 498 struct_ptr: Air.Inst.Ref, 499 field_index: u32, 500 ptr_field_ty: Type, 501 ) !Air.Inst.Ref { 502 const ty = try block.sema.addType(ptr_field_ty); 503 const tag: Air.Inst.Tag = switch (field_index) { 504 0 => .struct_field_ptr_index_0, 505 1 => .struct_field_ptr_index_1, 506 2 => .struct_field_ptr_index_2, 507 3 => .struct_field_ptr_index_3, 508 else => { 509 return block.addInst(.{ 510 .tag = .struct_field_ptr, 511 .data = .{ .ty_pl = .{ 512 .ty = ty, 513 .payload = try block.sema.addExtra(Air.StructField{ 514 .struct_operand = struct_ptr, 515 .field_index = field_index, 516 }), 517 } }, 518 }); 519 }, 520 }; 521 return block.addInst(.{ 522 .tag = tag, 523 .data = .{ .ty_op = .{ 524 .ty = ty, 525 .operand = struct_ptr, 526 } }, 527 }); 528 } 529 530 fn addStructFieldVal( 531 block: *Block, 532 struct_val: Air.Inst.Ref, 533 field_index: u32, 534 field_ty: Type, 535 ) !Air.Inst.Ref { 536 return block.addInst(.{ 537 .tag = .struct_field_val, 538 .data = .{ .ty_pl = .{ 539 .ty = try block.sema.addType(field_ty), 540 .payload = try block.sema.addExtra(Air.StructField{ 541 .struct_operand = struct_val, 542 .field_index = field_index, 543 }), 544 } }, 545 }); 546 } 547 548 fn addSliceElemPtr( 549 block: *Block, 550 slice: Air.Inst.Ref, 551 elem_index: Air.Inst.Ref, 552 elem_ptr_ty: Type, 553 ) !Air.Inst.Ref { 554 return block.addInst(.{ 555 .tag = .slice_elem_ptr, 556 .data = .{ .ty_pl = .{ 557 .ty = try block.sema.addType(elem_ptr_ty), 558 .payload = try block.sema.addExtra(Air.Bin{ 559 .lhs = slice, 560 .rhs = elem_index, 561 }), 562 } }, 563 }); 564 } 565 566 fn addPtrElemPtr( 567 block: *Block, 568 array_ptr: Air.Inst.Ref, 569 elem_index: Air.Inst.Ref, 570 elem_ptr_ty: Type, 571 ) !Air.Inst.Ref { 572 const ty_ref = try block.sema.addType(elem_ptr_ty); 573 return block.addPtrElemPtrTypeRef(array_ptr, elem_index, ty_ref); 574 } 575 576 fn addPtrElemPtrTypeRef( 577 block: *Block, 578 array_ptr: Air.Inst.Ref, 579 elem_index: Air.Inst.Ref, 580 elem_ptr_ty: Air.Inst.Ref, 581 ) !Air.Inst.Ref { 582 return block.addInst(.{ 583 .tag = .ptr_elem_ptr, 584 .data = .{ .ty_pl = .{ 585 .ty = elem_ptr_ty, 586 .payload = try block.sema.addExtra(Air.Bin{ 587 .lhs = array_ptr, 588 .rhs = elem_index, 589 }), 590 } }, 591 }); 592 } 593 594 fn addCmpVector(block: *Block, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref, cmp_op: std.math.CompareOperator) !Air.Inst.Ref { 595 const sema = block.sema; 596 const mod = sema.mod; 597 return block.addInst(.{ 598 .tag = if (block.float_mode == .Optimized) .cmp_vector_optimized else .cmp_vector, 599 .data = .{ .ty_pl = .{ 600 .ty = try sema.addType( 601 try mod.vectorType(.{ 602 .len = sema.typeOf(lhs).vectorLen(mod), 603 .child = .bool_type, 604 }), 605 ), 606 .payload = try sema.addExtra(Air.VectorCmp{ 607 .lhs = lhs, 608 .rhs = rhs, 609 .op = Air.VectorCmp.encodeOp(cmp_op), 610 }), 611 } }, 612 }); 613 } 614 615 fn addAggregateInit( 616 block: *Block, 617 aggregate_ty: Type, 618 elements: []const Air.Inst.Ref, 619 ) !Air.Inst.Ref { 620 const sema = block.sema; 621 const ty_ref = try sema.addType(aggregate_ty); 622 try sema.air_extra.ensureUnusedCapacity(sema.gpa, elements.len); 623 const extra_index = @intCast(u32, sema.air_extra.items.len); 624 sema.appendRefsAssumeCapacity(elements); 625 626 return block.addInst(.{ 627 .tag = .aggregate_init, 628 .data = .{ .ty_pl = .{ 629 .ty = ty_ref, 630 .payload = extra_index, 631 } }, 632 }); 633 } 634 635 fn addUnionInit( 636 block: *Block, 637 union_ty: Type, 638 field_index: u32, 639 init: Air.Inst.Ref, 640 ) !Air.Inst.Ref { 641 return block.addInst(.{ 642 .tag = .union_init, 643 .data = .{ .ty_pl = .{ 644 .ty = try block.sema.addType(union_ty), 645 .payload = try block.sema.addExtra(Air.UnionInit{ 646 .field_index = field_index, 647 .init = init, 648 }), 649 } }, 650 }); 651 } 652 653 pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref { 654 return Air.indexToRef(try block.addInstAsIndex(inst)); 655 } 656 657 pub fn addInstAsIndex(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Index { 658 const sema = block.sema; 659 const gpa = sema.gpa; 660 661 try sema.air_instructions.ensureUnusedCapacity(gpa, 1); 662 try block.instructions.ensureUnusedCapacity(gpa, 1); 663 664 const result_index = @intCast(Air.Inst.Index, sema.air_instructions.len); 665 sema.air_instructions.appendAssumeCapacity(inst); 666 block.instructions.appendAssumeCapacity(result_index); 667 return result_index; 668 } 669 670 /// Insert an instruction into the block at `index`. Moves all following 671 /// instructions forward in the block to make room. Operation is O(N). 672 pub fn insertInst(block: *Block, index: Air.Inst.Index, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref { 673 return Air.indexToRef(try block.insertInstAsIndex(index, inst)); 674 } 675 676 pub fn insertInstAsIndex(block: *Block, index: Air.Inst.Index, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Index { 677 const sema = block.sema; 678 const gpa = sema.gpa; 679 680 try sema.air_instructions.ensureUnusedCapacity(gpa, 1); 681 682 const result_index = @intCast(Air.Inst.Index, sema.air_instructions.len); 683 sema.air_instructions.appendAssumeCapacity(inst); 684 685 try block.instructions.insert(gpa, index, result_index); 686 return result_index; 687 } 688 689 fn addUnreachable(block: *Block, safety_check: bool) !void { 690 if (safety_check and block.wantSafety()) { 691 try block.sema.safetyPanic(block, .unreach); 692 } else { 693 _ = try block.addNoOp(.unreach); 694 } 695 } 696 697 pub fn startAnonDecl(block: *Block) !WipAnonDecl { 698 return WipAnonDecl{ 699 .block = block, 700 .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa), 701 .finished = false, 702 }; 703 } 704 705 pub const WipAnonDecl = struct { 706 block: *Block, 707 new_decl_arena: std.heap.ArenaAllocator, 708 finished: bool, 709 710 pub fn arena(wad: *WipAnonDecl) Allocator { 711 return wad.new_decl_arena.allocator(); 712 } 713 714 pub fn deinit(wad: *WipAnonDecl) void { 715 if (!wad.finished) { 716 wad.new_decl_arena.deinit(); 717 } 718 wad.* = undefined; 719 } 720 721 /// `alignment` value of 0 means to use ABI alignment. 722 pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value, alignment: u64) !Decl.Index { 723 const sema = wad.block.sema; 724 // Do this ahead of time because `createAnonymousDecl` depends on calling 725 // `type.hasRuntimeBits()`. 726 _ = try sema.typeHasRuntimeBits(ty); 727 const new_decl_index = try sema.mod.createAnonymousDecl(wad.block, .{ 728 .ty = ty, 729 .val = val, 730 }); 731 const new_decl = sema.mod.declPtr(new_decl_index); 732 // TODO: migrate Decl alignment to use `InternPool.Alignment` 733 new_decl.@"align" = @intCast(u32, alignment); 734 errdefer sema.mod.abortAnonDecl(new_decl_index); 735 try new_decl.finalizeNewArena(&wad.new_decl_arena); 736 wad.finished = true; 737 try sema.mod.finalizeAnonDecl(new_decl_index); 738 return new_decl_index; 739 } 740 }; 741 }; 742 743 const LabeledBlock = struct { 744 block: Block, 745 label: Block.Label, 746 747 fn destroy(lb: *LabeledBlock, gpa: Allocator) void { 748 lb.block.instructions.deinit(gpa); 749 lb.label.merges.deinit(gpa); 750 gpa.destroy(lb); 751 } 752 }; 753 754 /// The value stored in the inferred allocation. This will go into 755 /// peer type resolution. This is stored in a separate list so that 756 /// the items are contiguous in memory and thus can be passed to 757 /// `Module.resolvePeerTypes`. 758 const InferredAlloc = struct { 759 prongs: std.MultiArrayList(struct { 760 /// The dummy instruction used as a peer to resolve the type. 761 /// Although this has a redundant type with placeholder, this is 762 /// needed in addition because it may be a constant value, which 763 /// affects peer type resolution. 764 stored_inst: Air.Inst.Ref, 765 /// The bitcast instruction used as a placeholder when the 766 /// new result pointer type is not yet known. 767 placeholder: Air.Inst.Index, 768 }) = .{}, 769 }; 770 771 pub fn deinit(sema: *Sema) void { 772 const gpa = sema.gpa; 773 sema.air_instructions.deinit(gpa); 774 sema.air_extra.deinit(gpa); 775 sema.inst_map.deinit(gpa); 776 sema.decl_val_table.deinit(gpa); 777 sema.types_to_resolve.deinit(gpa); 778 { 779 var it = sema.post_hoc_blocks.iterator(); 780 while (it.next()) |entry| { 781 const labeled_block = entry.value_ptr.*; 782 labeled_block.destroy(gpa); 783 } 784 sema.post_hoc_blocks.deinit(gpa); 785 } 786 sema.unresolved_inferred_allocs.deinit(gpa); 787 sema.* = undefined; 788 } 789 790 /// Returns only the result from the body that is specified. 791 /// Only appropriate to call when it is determined at comptime that this body 792 /// has no peers. 793 fn resolveBody( 794 sema: *Sema, 795 block: *Block, 796 body: []const Zir.Inst.Index, 797 /// This is the instruction that a break instruction within `body` can 798 /// use to return from the body. 799 body_inst: Zir.Inst.Index, 800 ) CompileError!Air.Inst.Ref { 801 const break_data = (try sema.analyzeBodyBreak(block, body)) orelse 802 return Air.Inst.Ref.unreachable_value; 803 // For comptime control flow, we need to detect when `analyzeBody` reports 804 // that we need to break from an outer block. In such case we 805 // use Zig's error mechanism to send control flow up the stack until 806 // we find the corresponding block to this break. 807 if (block.is_comptime and break_data.block_inst != body_inst) { 808 sema.comptime_break_inst = break_data.inst; 809 return error.ComptimeBreak; 810 } 811 return try sema.resolveInst(break_data.operand); 812 } 813 814 fn analyzeBodyRuntimeBreak(sema: *Sema, block: *Block, body: []const Zir.Inst.Index) !void { 815 _ = sema.analyzeBodyInner(block, body) catch |err| switch (err) { 816 error.ComptimeBreak => { 817 const zir_datas = sema.code.instructions.items(.data); 818 const break_data = zir_datas[sema.comptime_break_inst].@"break"; 819 const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data; 820 try sema.addRuntimeBreak(block, .{ 821 .block_inst = extra.block_inst, 822 .operand = break_data.operand, 823 .inst = sema.comptime_break_inst, 824 }); 825 }, 826 else => |e| return e, 827 }; 828 } 829 830 pub fn analyzeBody( 831 sema: *Sema, 832 block: *Block, 833 body: []const Zir.Inst.Index, 834 ) !void { 835 _ = sema.analyzeBodyInner(block, body) catch |err| switch (err) { 836 error.ComptimeBreak => unreachable, // unexpected comptime control flow 837 else => |e| return e, 838 }; 839 } 840 841 const BreakData = struct { 842 block_inst: Zir.Inst.Index, 843 operand: Zir.Inst.Ref, 844 inst: Zir.Inst.Index, 845 }; 846 847 pub fn analyzeBodyBreak( 848 sema: *Sema, 849 block: *Block, 850 body: []const Zir.Inst.Index, 851 ) CompileError!?BreakData { 852 const break_inst = sema.analyzeBodyInner(block, body) catch |err| switch (err) { 853 error.ComptimeBreak => sema.comptime_break_inst, 854 else => |e| return e, 855 }; 856 if (block.instructions.items.len != 0 and 857 sema.isNoReturn(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1]))) 858 return null; 859 const break_data = sema.code.instructions.items(.data)[break_inst].@"break"; 860 const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data; 861 return BreakData{ 862 .block_inst = extra.block_inst, 863 .operand = break_data.operand, 864 .inst = break_inst, 865 }; 866 } 867 868 /// ZIR instructions which are always `noreturn` return this. This matches the 869 /// return type of `analyzeBody` so that we can tail call them. 870 /// Only appropriate to return when the instruction is known to be NoReturn 871 /// solely based on the ZIR tag. 872 const always_noreturn: CompileError!Zir.Inst.Index = @as(Zir.Inst.Index, undefined); 873 874 /// This function is the main loop of `Sema` and it can be used in two different ways: 875 /// * The traditional way where there are N breaks out of the block and peer type 876 /// resolution is done on the break operands. In this case, the `Zir.Inst.Index` 877 /// part of the return value will be `undefined`, and callsites should ignore it, 878 /// finding the block result value via the block scope. 879 /// * The "flat" way. There is only 1 break out of the block, and it is with a `break_inline` 880 /// instruction. In this case, the `Zir.Inst.Index` part of the return value will be 881 /// the break instruction. This communicates both which block the break applies to, as 882 /// well as the operand. No block scope needs to be created for this strategy. 883 fn analyzeBodyInner( 884 sema: *Sema, 885 block: *Block, 886 body: []const Zir.Inst.Index, 887 ) CompileError!Zir.Inst.Index { 888 // No tracy calls here, to avoid interfering with the tail call mechanism. 889 890 try sema.inst_map.ensureSpaceForInstructions(sema.gpa, body); 891 892 // Most of the time, we don't need to construct a new capture scope for a 893 // block. However, successive iterations of comptime loops can capture 894 // different values for the same Zir.Inst.Index, so in those cases, we will 895 // have to create nested capture scopes; see the `.repeat` case below. 896 const parent_capture_scope = block.wip_capture_scope; 897 parent_capture_scope.incRef(); 898 var wip_captures: WipCaptureScope = .{ 899 .scope = parent_capture_scope, 900 .gpa = sema.gpa, 901 .finalized = true, // don't finalize the parent scope 902 }; 903 defer wip_captures.deinit(); 904 905 const mod = sema.mod; 906 const map = &sema.inst_map; 907 const tags = sema.code.instructions.items(.tag); 908 const datas = sema.code.instructions.items(.data); 909 910 var orig_captures: usize = parent_capture_scope.captures.count(); 911 912 var crash_info = crash_report.prepAnalyzeBody(sema, block, body); 913 crash_info.push(); 914 defer crash_info.pop(); 915 916 var dbg_block_begins: u32 = 0; 917 918 // We use a while (true) loop here to avoid a redundant way of breaking out of 919 // the loop. The only way to break out of the loop is with a `noreturn` 920 // instruction. 921 var i: usize = 0; 922 const result = while (true) { 923 crash_info.setBodyIndex(i); 924 const inst = body[i]; 925 std.log.scoped(.sema_zir).debug("sema ZIR {s} %{d}", .{ 926 mod.namespacePtr(mod.declPtr(block.src_decl).src_namespace).file_scope.sub_file_path, inst, 927 }); 928 const air_inst: Air.Inst.Ref = switch (tags[inst]) { 929 // zig fmt: off 930 .alloc => try sema.zirAlloc(block, inst), 931 .alloc_inferred => try sema.zirAllocInferred(block, inst, true), 932 .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, false), 933 .alloc_inferred_comptime => try sema.zirAllocInferredComptime(inst, true), 934 .alloc_inferred_comptime_mut => try sema.zirAllocInferredComptime(inst, false), 935 .alloc_mut => try sema.zirAllocMut(block, inst), 936 .alloc_comptime_mut => try sema.zirAllocComptime(block, inst), 937 .make_ptr_const => try sema.zirMakePtrConst(block, inst), 938 .anyframe_type => try sema.zirAnyframeType(block, inst), 939 .array_cat => try sema.zirArrayCat(block, inst), 940 .array_mul => try sema.zirArrayMul(block, inst), 941 .array_type => try sema.zirArrayType(block, inst), 942 .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst), 943 .vector_type => try sema.zirVectorType(block, inst), 944 .as => try sema.zirAs(block, inst), 945 .as_node => try sema.zirAsNode(block, inst), 946 .as_shift_operand => try sema.zirAsShiftOperand(block, inst), 947 .bit_and => try sema.zirBitwise(block, inst, .bit_and), 948 .bit_not => try sema.zirBitNot(block, inst), 949 .bit_or => try sema.zirBitwise(block, inst, .bit_or), 950 .bitcast => try sema.zirBitcast(block, inst), 951 .suspend_block => try sema.zirSuspendBlock(block, inst), 952 .bool_not => try sema.zirBoolNot(block, inst), 953 .bool_br_and => try sema.zirBoolBr(block, inst, false), 954 .bool_br_or => try sema.zirBoolBr(block, inst, true), 955 .c_import => try sema.zirCImport(block, inst), 956 .call => try sema.zirCall(block, inst, .direct), 957 .field_call => try sema.zirCall(block, inst, .field), 958 .closure_get => try sema.zirClosureGet(block, inst), 959 .cmp_lt => try sema.zirCmp(block, inst, .lt), 960 .cmp_lte => try sema.zirCmp(block, inst, .lte), 961 .cmp_eq => try sema.zirCmpEq(block, inst, .eq, Air.Inst.Tag.fromCmpOp(.eq, block.float_mode == .Optimized)), 962 .cmp_gte => try sema.zirCmp(block, inst, .gte), 963 .cmp_gt => try sema.zirCmp(block, inst, .gt), 964 .cmp_neq => try sema.zirCmpEq(block, inst, .neq, Air.Inst.Tag.fromCmpOp(.neq, block.float_mode == .Optimized)), 965 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst), 966 .decl_ref => try sema.zirDeclRef(block, inst), 967 .decl_val => try sema.zirDeclVal(block, inst), 968 .load => try sema.zirLoad(block, inst), 969 .elem_ptr => try sema.zirElemPtr(block, inst), 970 .elem_ptr_node => try sema.zirElemPtrNode(block, inst), 971 .elem_ptr_imm => try sema.zirElemPtrImm(block, inst), 972 .elem_val => try sema.zirElemVal(block, inst), 973 .elem_val_node => try sema.zirElemValNode(block, inst), 974 .elem_type_index => try sema.zirElemTypeIndex(block, inst), 975 .enum_literal => try sema.zirEnumLiteral(block, inst), 976 .enum_to_int => try sema.zirEnumToInt(block, inst), 977 .int_to_enum => try sema.zirIntToEnum(block, inst), 978 .err_union_code => try sema.zirErrUnionCode(block, inst), 979 .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst), 980 .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst), 981 .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst), 982 .error_union_type => try sema.zirErrorUnionType(block, inst), 983 .error_value => try sema.zirErrorValue(block, inst), 984 .field_ptr => try sema.zirFieldPtr(block, inst, false), 985 .field_ptr_init => try sema.zirFieldPtr(block, inst, true), 986 .field_ptr_named => try sema.zirFieldPtrNamed(block, inst), 987 .field_val => try sema.zirFieldVal(block, inst), 988 .field_val_named => try sema.zirFieldValNamed(block, inst), 989 .func => try sema.zirFunc(block, inst, false), 990 .func_inferred => try sema.zirFunc(block, inst, true), 991 .func_fancy => try sema.zirFuncFancy(block, inst), 992 .import => try sema.zirImport(block, inst), 993 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst), 994 .int => try sema.zirInt(block, inst), 995 .int_big => try sema.zirIntBig(block, inst), 996 .float => try sema.zirFloat(block, inst), 997 .float128 => try sema.zirFloat128(block, inst), 998 .int_type => try sema.zirIntType(inst), 999 .is_non_err => try sema.zirIsNonErr(block, inst), 1000 .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst), 1001 .ret_is_non_err => try sema.zirRetIsNonErr(block, inst), 1002 .is_non_null => try sema.zirIsNonNull(block, inst), 1003 .is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst), 1004 .merge_error_sets => try sema.zirMergeErrorSets(block, inst), 1005 .negate => try sema.zirNegate(block, inst), 1006 .negate_wrap => try sema.zirNegateWrap(block, inst), 1007 .optional_payload_safe => try sema.zirOptionalPayload(block, inst, true), 1008 .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true), 1009 .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false), 1010 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false), 1011 .optional_type => try sema.zirOptionalType(block, inst), 1012 .ptr_type => try sema.zirPtrType(block, inst), 1013 .ref => try sema.zirRef(block, inst), 1014 .ret_err_value_code => try sema.zirRetErrValueCode(inst), 1015 .shr => try sema.zirShr(block, inst, .shr), 1016 .shr_exact => try sema.zirShr(block, inst, .shr_exact), 1017 .slice_end => try sema.zirSliceEnd(block, inst), 1018 .slice_sentinel => try sema.zirSliceSentinel(block, inst), 1019 .slice_start => try sema.zirSliceStart(block, inst), 1020 .slice_length => try sema.zirSliceLength(block, inst), 1021 .str => try sema.zirStr(block, inst), 1022 .switch_block => try sema.zirSwitchBlock(block, inst), 1023 .switch_cond => try sema.zirSwitchCond(block, inst, false), 1024 .switch_cond_ref => try sema.zirSwitchCond(block, inst, true), 1025 .switch_capture => try sema.zirSwitchCapture(block, inst, false, false), 1026 .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), 1027 .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), 1028 .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true), 1029 .switch_capture_tag => try sema.zirSwitchCaptureTag(block, inst), 1030 .type_info => try sema.zirTypeInfo(block, inst), 1031 .size_of => try sema.zirSizeOf(block, inst), 1032 .bit_size_of => try sema.zirBitSizeOf(block, inst), 1033 .typeof => try sema.zirTypeof(block, inst), 1034 .typeof_builtin => try sema.zirTypeofBuiltin(block, inst), 1035 .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst), 1036 .xor => try sema.zirBitwise(block, inst, .xor), 1037 .struct_init_empty => try sema.zirStructInitEmpty(block, inst), 1038 .struct_init => try sema.zirStructInit(block, inst, false), 1039 .struct_init_ref => try sema.zirStructInit(block, inst, true), 1040 .struct_init_anon => try sema.zirStructInitAnon(block, inst, false), 1041 .struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true), 1042 .array_init => try sema.zirArrayInit(block, inst, false), 1043 .array_init_ref => try sema.zirArrayInit(block, inst, true), 1044 .array_init_anon => try sema.zirArrayInitAnon(block, inst, false), 1045 .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true), 1046 .union_init => try sema.zirUnionInit(block, inst), 1047 .field_type => try sema.zirFieldType(block, inst), 1048 .field_type_ref => try sema.zirFieldTypeRef(block, inst), 1049 .ptr_to_int => try sema.zirPtrToInt(block, inst), 1050 .align_of => try sema.zirAlignOf(block, inst), 1051 .bool_to_int => try sema.zirBoolToInt(block, inst), 1052 .embed_file => try sema.zirEmbedFile(block, inst), 1053 .error_name => try sema.zirErrorName(block, inst), 1054 .tag_name => try sema.zirTagName(block, inst), 1055 .type_name => try sema.zirTypeName(block, inst), 1056 .frame_type => try sema.zirFrameType(block, inst), 1057 .frame_size => try sema.zirFrameSize(block, inst), 1058 .float_to_int => try sema.zirFloatToInt(block, inst), 1059 .int_to_float => try sema.zirIntToFloat(block, inst), 1060 .int_to_ptr => try sema.zirIntToPtr(block, inst), 1061 .float_cast => try sema.zirFloatCast(block, inst), 1062 .int_cast => try sema.zirIntCast(block, inst), 1063 .ptr_cast => try sema.zirPtrCast(block, inst), 1064 .truncate => try sema.zirTruncate(block, inst), 1065 .align_cast => try sema.zirAlignCast(block, inst), 1066 .has_decl => try sema.zirHasDecl(block, inst), 1067 .has_field => try sema.zirHasField(block, inst), 1068 .byte_swap => try sema.zirByteSwap(block, inst), 1069 .bit_reverse => try sema.zirBitReverse(block, inst), 1070 .bit_offset_of => try sema.zirBitOffsetOf(block, inst), 1071 .offset_of => try sema.zirOffsetOf(block, inst), 1072 .splat => try sema.zirSplat(block, inst), 1073 .reduce => try sema.zirReduce(block, inst), 1074 .shuffle => try sema.zirShuffle(block, inst), 1075 .atomic_load => try sema.zirAtomicLoad(block, inst), 1076 .atomic_rmw => try sema.zirAtomicRmw(block, inst), 1077 .mul_add => try sema.zirMulAdd(block, inst), 1078 .builtin_call => try sema.zirBuiltinCall(block, inst), 1079 .field_parent_ptr => try sema.zirFieldParentPtr(block, inst), 1080 .@"resume" => try sema.zirResume(block, inst), 1081 .@"await" => try sema.zirAwait(block, inst), 1082 .array_base_ptr => try sema.zirArrayBasePtr(block, inst), 1083 .field_base_ptr => try sema.zirFieldBasePtr(block, inst), 1084 .for_len => try sema.zirForLen(block, inst), 1085 1086 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz), 1087 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz), 1088 .pop_count => try sema.zirBitCount(block, inst, .popcount, Value.popCount), 1089 1090 .sqrt => try sema.zirUnaryMath(block, inst, .sqrt, Value.sqrt), 1091 .sin => try sema.zirUnaryMath(block, inst, .sin, Value.sin), 1092 .cos => try sema.zirUnaryMath(block, inst, .cos, Value.cos), 1093 .tan => try sema.zirUnaryMath(block, inst, .tan, Value.tan), 1094 .exp => try sema.zirUnaryMath(block, inst, .exp, Value.exp), 1095 .exp2 => try sema.zirUnaryMath(block, inst, .exp2, Value.exp2), 1096 .log => try sema.zirUnaryMath(block, inst, .log, Value.log), 1097 .log2 => try sema.zirUnaryMath(block, inst, .log2, Value.log2), 1098 .log10 => try sema.zirUnaryMath(block, inst, .log10, Value.log10), 1099 .fabs => try sema.zirUnaryMath(block, inst, .fabs, Value.fabs), 1100 .floor => try sema.zirUnaryMath(block, inst, .floor, Value.floor), 1101 .ceil => try sema.zirUnaryMath(block, inst, .ceil, Value.ceil), 1102 .round => try sema.zirUnaryMath(block, inst, .round, Value.round), 1103 .trunc => try sema.zirUnaryMath(block, inst, .trunc_float, Value.trunc), 1104 1105 .error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent), 1106 .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon), 1107 .error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func), 1108 1109 .add => try sema.zirArithmetic(block, inst, .add, true), 1110 .addwrap => try sema.zirArithmetic(block, inst, .addwrap, true), 1111 .add_sat => try sema.zirArithmetic(block, inst, .add_sat, true), 1112 .add_unsafe=> try sema.zirArithmetic(block, inst, .add_unsafe, false), 1113 .mul => try sema.zirArithmetic(block, inst, .mul, true), 1114 .mulwrap => try sema.zirArithmetic(block, inst, .mulwrap, true), 1115 .mul_sat => try sema.zirArithmetic(block, inst, .mul_sat, true), 1116 .sub => try sema.zirArithmetic(block, inst, .sub, true), 1117 .subwrap => try sema.zirArithmetic(block, inst, .subwrap, true), 1118 .sub_sat => try sema.zirArithmetic(block, inst, .sub_sat, true), 1119 1120 .div => try sema.zirDiv(block, inst), 1121 .div_exact => try sema.zirDivExact(block, inst), 1122 .div_floor => try sema.zirDivFloor(block, inst), 1123 .div_trunc => try sema.zirDivTrunc(block, inst), 1124 1125 .mod_rem => try sema.zirModRem(block, inst), 1126 .mod => try sema.zirMod(block, inst), 1127 .rem => try sema.zirRem(block, inst), 1128 1129 .max => try sema.zirMinMax(block, inst, .max), 1130 .min => try sema.zirMinMax(block, inst, .min), 1131 1132 .shl => try sema.zirShl(block, inst, .shl), 1133 .shl_exact => try sema.zirShl(block, inst, .shl_exact), 1134 .shl_sat => try sema.zirShl(block, inst, .shl_sat), 1135 1136 .ret_ptr => try sema.zirRetPtr(block), 1137 .ret_type => try sema.addType(sema.fn_ret_ty), 1138 1139 // Instructions that we know to *always* be noreturn based solely on their tag. 1140 // These functions match the return type of analyzeBody so that we can 1141 // tail call them here. 1142 .compile_error => break sema.zirCompileError(block, inst), 1143 .ret_implicit => break sema.zirRetImplicit(block, inst), 1144 .ret_node => break sema.zirRetNode(block, inst), 1145 .ret_load => break sema.zirRetLoad(block, inst), 1146 .ret_err_value => break sema.zirRetErrValue(block, inst), 1147 .@"unreachable" => break sema.zirUnreachable(block, inst), 1148 .panic => break sema.zirPanic(block, inst), 1149 .trap => break sema.zirTrap(block, inst), 1150 // zig fmt: on 1151 1152 .extended => ext: { 1153 const extended = datas[inst].extended; 1154 break :ext switch (extended.opcode) { 1155 // zig fmt: off 1156 .variable => try sema.zirVarExtended( block, extended), 1157 .struct_decl => try sema.zirStructDecl( block, extended, inst), 1158 .enum_decl => try sema.zirEnumDecl( block, extended, inst), 1159 .union_decl => try sema.zirUnionDecl( block, extended, inst), 1160 .opaque_decl => try sema.zirOpaqueDecl( block, extended, inst), 1161 .this => try sema.zirThis( block, extended), 1162 .ret_addr => try sema.zirRetAddr( block, extended), 1163 .builtin_src => try sema.zirBuiltinSrc( block, extended), 1164 .error_return_trace => try sema.zirErrorReturnTrace( block), 1165 .frame => try sema.zirFrame( block, extended), 1166 .frame_address => try sema.zirFrameAddress( block, extended), 1167 .alloc => try sema.zirAllocExtended( block, extended), 1168 .builtin_extern => try sema.zirBuiltinExtern( block, extended), 1169 .@"asm" => try sema.zirAsm( block, extended, false), 1170 .asm_expr => try sema.zirAsm( block, extended, true), 1171 .typeof_peer => try sema.zirTypeofPeer( block, extended), 1172 .compile_log => try sema.zirCompileLog( extended), 1173 .min_multi => try sema.zirMinMaxMulti( block, extended, .min), 1174 .max_multi => try sema.zirMinMaxMulti( block, extended, .max), 1175 .add_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode), 1176 .sub_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode), 1177 .mul_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode), 1178 .shl_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode), 1179 .c_undef => try sema.zirCUndef( block, extended), 1180 .c_include => try sema.zirCInclude( block, extended), 1181 .c_define => try sema.zirCDefine( block, extended), 1182 .wasm_memory_size => try sema.zirWasmMemorySize( block, extended), 1183 .wasm_memory_grow => try sema.zirWasmMemoryGrow( block, extended), 1184 .prefetch => try sema.zirPrefetch( block, extended), 1185 .err_set_cast => try sema.zirErrSetCast( block, extended), 1186 .await_nosuspend => try sema.zirAwaitNosuspend( block, extended), 1187 .select => try sema.zirSelect( block, extended), 1188 .error_to_int => try sema.zirErrorToInt( block, extended), 1189 .int_to_error => try sema.zirIntToError( block, extended), 1190 .reify => try sema.zirReify( block, extended, inst), 1191 .builtin_async_call => try sema.zirBuiltinAsyncCall( block, extended), 1192 .cmpxchg => try sema.zirCmpxchg( block, extended), 1193 .addrspace_cast => try sema.zirAddrSpaceCast( block, extended), 1194 .c_va_arg => try sema.zirCVaArg( block, extended), 1195 .c_va_copy => try sema.zirCVaCopy( block, extended), 1196 .c_va_end => try sema.zirCVaEnd( block, extended), 1197 .c_va_start => try sema.zirCVaStart( block, extended), 1198 .const_cast, => try sema.zirConstCast( block, extended), 1199 .volatile_cast, => try sema.zirVolatileCast( block, extended), 1200 .work_item_id => try sema.zirWorkItem( block, extended, extended.opcode), 1201 .work_group_size => try sema.zirWorkItem( block, extended, extended.opcode), 1202 .work_group_id => try sema.zirWorkItem( block, extended, extended.opcode), 1203 .in_comptime => try sema.zirInComptime( block), 1204 // zig fmt: on 1205 1206 .fence => { 1207 try sema.zirFence(block, extended); 1208 i += 1; 1209 continue; 1210 }, 1211 .set_float_mode => { 1212 try sema.zirSetFloatMode(block, extended); 1213 i += 1; 1214 continue; 1215 }, 1216 .set_align_stack => { 1217 try sema.zirSetAlignStack(block, extended); 1218 i += 1; 1219 continue; 1220 }, 1221 .set_cold => { 1222 try sema.zirSetCold(block, extended); 1223 i += 1; 1224 continue; 1225 }, 1226 .breakpoint => { 1227 if (!block.is_comptime) { 1228 _ = try block.addNoOp(.breakpoint); 1229 } 1230 i += 1; 1231 continue; 1232 }, 1233 .errdefer_err_code => unreachable, // never appears in a body 1234 }; 1235 }, 1236 1237 // Instructions that we know can *never* be noreturn based solely on 1238 // their tag. We avoid needlessly checking if they are noreturn and 1239 // continue the loop. 1240 // We also know that they cannot be referenced later, so we avoid 1241 // putting them into the map. 1242 .dbg_stmt => { 1243 try sema.zirDbgStmt(block, inst); 1244 i += 1; 1245 continue; 1246 }, 1247 .dbg_var_ptr => { 1248 try sema.zirDbgVar(block, inst, .dbg_var_ptr); 1249 i += 1; 1250 continue; 1251 }, 1252 .dbg_var_val => { 1253 try sema.zirDbgVar(block, inst, .dbg_var_val); 1254 i += 1; 1255 continue; 1256 }, 1257 .dbg_block_begin => { 1258 dbg_block_begins += 1; 1259 try sema.zirDbgBlockBegin(block); 1260 i += 1; 1261 continue; 1262 }, 1263 .dbg_block_end => { 1264 dbg_block_begins -= 1; 1265 try sema.zirDbgBlockEnd(block); 1266 i += 1; 1267 continue; 1268 }, 1269 .ensure_err_union_payload_void => { 1270 try sema.zirEnsureErrUnionPayloadVoid(block, inst); 1271 i += 1; 1272 continue; 1273 }, 1274 .ensure_result_non_error => { 1275 try sema.zirEnsureResultNonError(block, inst); 1276 i += 1; 1277 continue; 1278 }, 1279 .ensure_result_used => { 1280 try sema.zirEnsureResultUsed(block, inst); 1281 i += 1; 1282 continue; 1283 }, 1284 .set_eval_branch_quota => { 1285 try sema.zirSetEvalBranchQuota(block, inst); 1286 i += 1; 1287 continue; 1288 }, 1289 .atomic_store => { 1290 try sema.zirAtomicStore(block, inst); 1291 i += 1; 1292 continue; 1293 }, 1294 .store => { 1295 try sema.zirStore(block, inst); 1296 i += 1; 1297 continue; 1298 }, 1299 .store_node => { 1300 try sema.zirStoreNode(block, inst); 1301 i += 1; 1302 continue; 1303 }, 1304 .store_to_block_ptr => { 1305 try sema.zirStoreToBlockPtr(block, inst); 1306 i += 1; 1307 continue; 1308 }, 1309 .store_to_inferred_ptr => { 1310 try sema.zirStoreToInferredPtr(block, inst); 1311 i += 1; 1312 continue; 1313 }, 1314 .resolve_inferred_alloc => { 1315 try sema.zirResolveInferredAlloc(block, inst); 1316 i += 1; 1317 continue; 1318 }, 1319 .validate_array_init_ty => { 1320 try sema.validateArrayInitTy(block, inst); 1321 i += 1; 1322 continue; 1323 }, 1324 .validate_struct_init_ty => { 1325 try sema.validateStructInitTy(block, inst); 1326 i += 1; 1327 continue; 1328 }, 1329 .validate_struct_init => { 1330 try sema.zirValidateStructInit(block, inst); 1331 i += 1; 1332 continue; 1333 }, 1334 .validate_array_init => { 1335 try sema.zirValidateArrayInit(block, inst); 1336 i += 1; 1337 continue; 1338 }, 1339 .validate_deref => { 1340 try sema.zirValidateDeref(block, inst); 1341 i += 1; 1342 continue; 1343 }, 1344 .@"export" => { 1345 try sema.zirExport(block, inst); 1346 i += 1; 1347 continue; 1348 }, 1349 .export_value => { 1350 try sema.zirExportValue(block, inst); 1351 i += 1; 1352 continue; 1353 }, 1354 .set_runtime_safety => { 1355 try sema.zirSetRuntimeSafety(block, inst); 1356 i += 1; 1357 continue; 1358 }, 1359 .param => { 1360 try sema.zirParam(block, inst, false); 1361 i += 1; 1362 continue; 1363 }, 1364 .param_comptime => { 1365 try sema.zirParam(block, inst, true); 1366 i += 1; 1367 continue; 1368 }, 1369 .param_anytype => { 1370 try sema.zirParamAnytype(block, inst, false); 1371 i += 1; 1372 continue; 1373 }, 1374 .param_anytype_comptime => { 1375 try sema.zirParamAnytype(block, inst, true); 1376 i += 1; 1377 continue; 1378 }, 1379 .closure_capture => { 1380 try sema.zirClosureCapture(block, inst); 1381 i += 1; 1382 continue; 1383 }, 1384 .memcpy => { 1385 try sema.zirMemcpy(block, inst); 1386 i += 1; 1387 continue; 1388 }, 1389 .memset => { 1390 try sema.zirMemset(block, inst); 1391 i += 1; 1392 continue; 1393 }, 1394 .check_comptime_control_flow => { 1395 if (!block.is_comptime) { 1396 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 1397 const src = inst_data.src(); 1398 const inline_block = Zir.refToIndex(inst_data.operand).?; 1399 1400 var check_block = block; 1401 const target_runtime_index = while (true) { 1402 if (check_block.inline_block == inline_block) { 1403 break check_block.runtime_index; 1404 } 1405 check_block = check_block.parent.?; 1406 }; 1407 1408 if (@enumToInt(target_runtime_index) < @enumToInt(block.runtime_index)) { 1409 const runtime_src = block.runtime_cond orelse block.runtime_loop.?; 1410 const msg = msg: { 1411 const msg = try sema.errMsg(block, src, "comptime control flow inside runtime block", .{}); 1412 errdefer msg.destroy(sema.gpa); 1413 1414 try sema.errNote(block, runtime_src, msg, "runtime control flow here", .{}); 1415 break :msg msg; 1416 }; 1417 return sema.failWithOwnedErrorMsg(msg); 1418 } 1419 } 1420 i += 1; 1421 continue; 1422 }, 1423 .save_err_ret_index => { 1424 try sema.zirSaveErrRetIndex(block, inst); 1425 i += 1; 1426 continue; 1427 }, 1428 .restore_err_ret_index => { 1429 try sema.zirRestoreErrRetIndex(block, inst); 1430 i += 1; 1431 continue; 1432 }, 1433 1434 // Special case instructions to handle comptime control flow. 1435 .@"break" => { 1436 if (block.is_comptime) { 1437 break inst; // same as break_inline 1438 } else { 1439 break sema.zirBreak(block, inst); 1440 } 1441 }, 1442 .break_inline => { 1443 if (block.is_comptime) { 1444 break inst; 1445 } else { 1446 sema.comptime_break_inst = inst; 1447 return error.ComptimeBreak; 1448 } 1449 }, 1450 .repeat => { 1451 if (block.is_comptime) { 1452 // Send comptime control flow back to the beginning of this block. 1453 const src = LazySrcLoc.nodeOffset(datas[inst].node); 1454 try sema.emitBackwardBranch(block, src); 1455 if (wip_captures.scope.captures.count() != orig_captures) { 1456 // We need to construct new capture scopes for the next loop iteration so it 1457 // can capture values without clobbering the earlier iteration's captures. 1458 // At first, we reused the parent capture scope as an optimization, but for 1459 // successive scopes we have to create new ones as children of the parent 1460 // scope. 1461 try wip_captures.reset(parent_capture_scope); 1462 block.wip_capture_scope = wip_captures.scope; 1463 orig_captures = 0; 1464 } 1465 i = 0; 1466 continue; 1467 } else { 1468 break always_noreturn; 1469 } 1470 }, 1471 .repeat_inline => { 1472 // Send comptime control flow back to the beginning of this block. 1473 const src = LazySrcLoc.nodeOffset(datas[inst].node); 1474 try sema.emitBackwardBranch(block, src); 1475 if (wip_captures.scope.captures.count() != orig_captures) { 1476 // We need to construct new capture scopes for the next loop iteration so it 1477 // can capture values without clobbering the earlier iteration's captures. 1478 // At first, we reused the parent capture scope as an optimization, but for 1479 // successive scopes we have to create new ones as children of the parent 1480 // scope. 1481 try wip_captures.reset(parent_capture_scope); 1482 block.wip_capture_scope = wip_captures.scope; 1483 orig_captures = 0; 1484 } 1485 i = 0; 1486 continue; 1487 }, 1488 .loop => blk: { 1489 if (!block.is_comptime) break :blk try sema.zirLoop(block, inst); 1490 // Same as `block_inline`. TODO https://github.com/ziglang/zig/issues/8220 1491 const inst_data = datas[inst].pl_node; 1492 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); 1493 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; 1494 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse 1495 break always_noreturn; 1496 if (inst == break_data.block_inst) { 1497 break :blk try sema.resolveInst(break_data.operand); 1498 } else { 1499 break break_data.inst; 1500 } 1501 }, 1502 .block, .block_comptime => blk: { 1503 if (!block.is_comptime) { 1504 break :blk try sema.zirBlock(block, inst, tags[inst] == .block_comptime); 1505 } 1506 // Same as `block_inline`. TODO https://github.com/ziglang/zig/issues/8220 1507 const inst_data = datas[inst].pl_node; 1508 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); 1509 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; 1510 // If this block contains a function prototype, we need to reset the 1511 // current list of parameters and restore it later. 1512 // Note: this probably needs to be resolved in a more general manner. 1513 const prev_params = block.params; 1514 block.params = .{}; 1515 defer { 1516 block.params.deinit(sema.gpa); 1517 block.params = prev_params; 1518 } 1519 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse 1520 break always_noreturn; 1521 if (inst == break_data.block_inst) { 1522 break :blk try sema.resolveInst(break_data.operand); 1523 } else { 1524 break break_data.inst; 1525 } 1526 }, 1527 .block_inline => blk: { 1528 // Directly analyze the block body without introducing a new block. 1529 // However, in the case of a corresponding break_inline which reaches 1530 // through a runtime conditional branch, we must retroactively emit 1531 // a block, so we remember the block index here just in case. 1532 const block_index = block.instructions.items.len; 1533 const inst_data = datas[inst].pl_node; 1534 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); 1535 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; 1536 const gpa = sema.gpa; 1537 1538 const opt_break_data = b: { 1539 // Create a temporary child block so that this inline block is properly 1540 // labeled for any .restore_err_ret_index instructions 1541 var child_block = block.makeSubBlock(); 1542 1543 // If this block contains a function prototype, we need to reset the 1544 // current list of parameters and restore it later. 1545 // Note: this probably needs to be resolved in a more general manner. 1546 child_block.inline_block = 1547 if (tags[inline_body[inline_body.len - 1]] == .repeat_inline) inline_body[0] else inst; 1548 1549 var label: Block.Label = .{ 1550 .zir_block = inst, 1551 .merges = undefined, 1552 }; 1553 child_block.label = &label; 1554 defer child_block.params.deinit(gpa); 1555 1556 // Write these instructions directly into the parent block 1557 child_block.instructions = block.instructions; 1558 defer block.instructions = child_block.instructions; 1559 1560 break :b try sema.analyzeBodyBreak(&child_block, inline_body); 1561 }; 1562 1563 // A runtime conditional branch that needs a post-hoc block to be 1564 // emitted communicates this by mapping the block index into the inst map. 1565 if (map.get(inst)) |new_block_ref| ph: { 1566 // Comptime control flow populates the map, so we don't actually know 1567 // if this is a post-hoc runtime block until we check the 1568 // post_hoc_block map. 1569 const new_block_inst = Air.refToIndex(new_block_ref) orelse break :ph; 1570 const labeled_block = sema.post_hoc_blocks.get(new_block_inst) orelse 1571 break :ph; 1572 1573 // In this case we need to move all the instructions starting at 1574 // block_index from the current block into this new one. 1575 1576 if (opt_break_data) |break_data| { 1577 // This is a comptime break which we now change to a runtime break 1578 // since it crosses a runtime branch. 1579 // It may pass through our currently being analyzed block_inline or it 1580 // may point directly to it. In the latter case, this modifies the 1581 // block that we are about to look up in the post_hoc_blocks map below. 1582 try sema.addRuntimeBreak(block, break_data); 1583 } else { 1584 // Here the comptime control flow ends with noreturn; however 1585 // we have runtime control flow continuing after this block. 1586 // This branch is therefore handled by the `i += 1; continue;` 1587 // logic below. 1588 } 1589 1590 try labeled_block.block.instructions.appendSlice(gpa, block.instructions.items[block_index..]); 1591 block.instructions.items.len = block_index; 1592 1593 const block_result = try sema.analyzeBlockBody(block, inst_data.src(), &labeled_block.block, &labeled_block.label.merges); 1594 { 1595 // Destroy the ad-hoc block entry so that it does not interfere with 1596 // the next iteration of comptime control flow, if any. 1597 labeled_block.destroy(gpa); 1598 assert(sema.post_hoc_blocks.remove(new_block_inst)); 1599 } 1600 map.putAssumeCapacity(inst, block_result); 1601 i += 1; 1602 continue; 1603 } 1604 1605 const break_data = opt_break_data orelse break always_noreturn; 1606 if (inst == break_data.block_inst) { 1607 break :blk try sema.resolveInst(break_data.operand); 1608 } else { 1609 break break_data.inst; 1610 } 1611 }, 1612 .condbr => blk: { 1613 if (!block.is_comptime) break sema.zirCondbr(block, inst); 1614 // Same as condbr_inline. TODO https://github.com/ziglang/zig/issues/8220 1615 const inst_data = datas[inst].pl_node; 1616 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; 1617 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); 1618 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len]; 1619 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; 1620 const cond = sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime-known") catch |err| { 1621 if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err); 1622 return err; 1623 }; 1624 const inline_body = if (cond.val.toBool()) then_body else else_body; 1625 1626 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src); 1627 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse 1628 break always_noreturn; 1629 if (inst == break_data.block_inst) { 1630 break :blk try sema.resolveInst(break_data.operand); 1631 } else { 1632 break break_data.inst; 1633 } 1634 }, 1635 .condbr_inline => blk: { 1636 const inst_data = datas[inst].pl_node; 1637 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; 1638 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); 1639 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len]; 1640 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; 1641 const cond = sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime-known") catch |err| { 1642 if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err); 1643 return err; 1644 }; 1645 const inline_body = if (cond.val.toBool()) then_body else else_body; 1646 1647 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src); 1648 const old_runtime_index = block.runtime_index; 1649 defer block.runtime_index = old_runtime_index; 1650 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse 1651 break always_noreturn; 1652 if (inst == break_data.block_inst) { 1653 break :blk try sema.resolveInst(break_data.operand); 1654 } else { 1655 break break_data.inst; 1656 } 1657 }, 1658 .@"try" => blk: { 1659 if (!block.is_comptime) break :blk try sema.zirTry(block, inst); 1660 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 1661 const src = inst_data.src(); 1662 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 1663 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index); 1664 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; 1665 const err_union = try sema.resolveInst(extra.data.operand); 1666 const err_union_ty = sema.typeOf(err_union); 1667 if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) { 1668 return sema.fail(block, operand_src, "expected error union type, found '{}'", .{ 1669 err_union_ty.fmt(mod), 1670 }); 1671 } 1672 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union); 1673 assert(is_non_err != .none); 1674 const is_non_err_val = sema.resolveConstValue(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known") catch |err| { 1675 if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err); 1676 return err; 1677 }; 1678 if (is_non_err_val.toBool()) { 1679 break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false); 1680 } 1681 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse 1682 break always_noreturn; 1683 if (inst == break_data.block_inst) { 1684 break :blk try sema.resolveInst(break_data.operand); 1685 } else { 1686 break break_data.inst; 1687 } 1688 }, 1689 .try_ptr => blk: { 1690 if (!block.is_comptime) break :blk try sema.zirTryPtr(block, inst); 1691 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 1692 const src = inst_data.src(); 1693 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 1694 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index); 1695 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; 1696 const operand = try sema.resolveInst(extra.data.operand); 1697 const err_union = try sema.analyzeLoad(block, src, operand, operand_src); 1698 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union); 1699 assert(is_non_err != .none); 1700 const is_non_err_val = sema.resolveConstValue(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known") catch |err| { 1701 if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err); 1702 return err; 1703 }; 1704 if (is_non_err_val.toBool()) { 1705 break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false); 1706 } 1707 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse 1708 break always_noreturn; 1709 if (inst == break_data.block_inst) { 1710 break :blk try sema.resolveInst(break_data.operand); 1711 } else { 1712 break break_data.inst; 1713 } 1714 }, 1715 .@"defer" => blk: { 1716 const inst_data = sema.code.instructions.items(.data)[inst].@"defer"; 1717 const defer_body = sema.code.extra[inst_data.index..][0..inst_data.len]; 1718 const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) { 1719 error.ComptimeBreak => sema.comptime_break_inst, 1720 else => |e| return e, 1721 }; 1722 if (break_inst != defer_body[defer_body.len - 1]) break always_noreturn; 1723 break :blk Air.Inst.Ref.void_value; 1724 }, 1725 .defer_err_code => blk: { 1726 const inst_data = sema.code.instructions.items(.data)[inst].defer_err_code; 1727 const extra = sema.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data; 1728 const defer_body = sema.code.extra[extra.index..][0..extra.len]; 1729 const err_code = try sema.resolveInst(inst_data.err_code); 1730 map.putAssumeCapacity(extra.remapped_err_code, err_code); 1731 const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) { 1732 error.ComptimeBreak => sema.comptime_break_inst, 1733 else => |e| return e, 1734 }; 1735 if (break_inst != defer_body[defer_body.len - 1]) break always_noreturn; 1736 break :blk Air.Inst.Ref.void_value; 1737 }, 1738 }; 1739 if (sema.isNoReturn(air_inst)) { 1740 // We're going to assume that the body itself is noreturn, so let's ensure that now 1741 assert(block.instructions.items.len > 0); 1742 assert(sema.isNoReturn(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1]))); 1743 break always_noreturn; 1744 } 1745 map.putAssumeCapacity(inst, air_inst); 1746 i += 1; 1747 }; 1748 1749 // balance out dbg_block_begins in case of early noreturn 1750 const noreturn_inst = block.instructions.popOrNull(); 1751 while (dbg_block_begins > 0) { 1752 dbg_block_begins -= 1; 1753 if (block.is_comptime or mod.comp.bin_file.options.strip) continue; 1754 1755 _ = try block.addInst(.{ 1756 .tag = .dbg_block_end, 1757 .data = undefined, 1758 }); 1759 } 1760 if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some); 1761 1762 if (!wip_captures.finalized) { 1763 // We've updated the capture scope due to a `repeat` instruction where 1764 // the body had a capture; finalize our child scope and reset 1765 try wip_captures.finalize(); 1766 block.wip_capture_scope = parent_capture_scope; 1767 } 1768 1769 return result; 1770 } 1771 1772 pub fn resolveInstAllowNone(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { 1773 if (zir_ref == .none) { 1774 return .none; 1775 } else { 1776 return resolveInst(sema, zir_ref); 1777 } 1778 } 1779 1780 pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { 1781 assert(zir_ref != .none); 1782 const i = @enumToInt(zir_ref); 1783 // First section of indexes correspond to a set number of constant values. 1784 // We intentionally map the same indexes to the same values between ZIR and AIR. 1785 if (i < InternPool.static_len) return @intToEnum(Air.Inst.Ref, i); 1786 // The last section of indexes refers to the map of ZIR => AIR. 1787 const inst = sema.inst_map.get(i - InternPool.static_len).?; 1788 if (inst == .generic_poison) return error.GenericPoison; 1789 return inst; 1790 } 1791 1792 fn resolveConstBool( 1793 sema: *Sema, 1794 block: *Block, 1795 src: LazySrcLoc, 1796 zir_ref: Zir.Inst.Ref, 1797 reason: []const u8, 1798 ) !bool { 1799 const air_inst = try sema.resolveInst(zir_ref); 1800 const wanted_type = Type.bool; 1801 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); 1802 const val = try sema.resolveConstValue(block, src, coerced_inst, reason); 1803 return val.toBool(); 1804 } 1805 1806 pub fn resolveConstString( 1807 sema: *Sema, 1808 block: *Block, 1809 src: LazySrcLoc, 1810 zir_ref: Zir.Inst.Ref, 1811 reason: []const u8, 1812 ) ![]u8 { 1813 const air_inst = try sema.resolveInst(zir_ref); 1814 const wanted_type = Type.slice_const_u8; 1815 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); 1816 const val = try sema.resolveConstValue(block, src, coerced_inst, reason); 1817 return val.toAllocatedBytes(wanted_type, sema.arena, sema.mod); 1818 } 1819 1820 pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type { 1821 const air_inst = try sema.resolveInst(zir_ref); 1822 assert(air_inst != .var_args_param_type); 1823 const ty = try sema.analyzeAsType(block, src, air_inst); 1824 if (ty.isGenericPoison()) return error.GenericPoison; 1825 return ty; 1826 } 1827 1828 fn analyzeAsType( 1829 sema: *Sema, 1830 block: *Block, 1831 src: LazySrcLoc, 1832 air_inst: Air.Inst.Ref, 1833 ) !Type { 1834 const wanted_type = Type.type; 1835 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); 1836 const val = try sema.resolveConstValue(block, src, coerced_inst, "types must be comptime-known"); 1837 return val.toType(); 1838 } 1839 1840 pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void { 1841 const mod = sema.mod; 1842 if (!mod.backendSupportsFeature(.error_return_trace)) return; 1843 1844 assert(!block.is_comptime); 1845 var err_trace_block = block.makeSubBlock(); 1846 defer err_trace_block.instructions.deinit(sema.gpa); 1847 1848 const src: LazySrcLoc = .unneeded; 1849 1850 // var addrs: [err_return_trace_addr_count]usize = undefined; 1851 const err_return_trace_addr_count = 32; 1852 const addr_arr_ty = try Type.array(sema.arena, err_return_trace_addr_count, null, Type.usize, mod); 1853 const addrs_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(addr_arr_ty)); 1854 1855 // var st: StackTrace = undefined; 1856 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); 1857 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); 1858 const st_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(stack_trace_ty)); 1859 1860 // st.instruction_addresses = &addrs; 1861 const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "instruction_addresses", src, true); 1862 try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store); 1863 1864 // st.index = 0; 1865 const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src, true); 1866 try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, .zero_usize, src, .store); 1867 1868 // @errorReturnTrace() = &st; 1869 _ = try err_trace_block.addUnOp(.set_err_return_trace, st_ptr); 1870 1871 try block.instructions.insertSlice(sema.gpa, last_arg_index, err_trace_block.instructions.items); 1872 } 1873 1874 /// May return Value Tags: `variable`, `undef`. 1875 /// See `resolveConstValue` for an alternative. 1876 /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. 1877 fn resolveValue( 1878 sema: *Sema, 1879 block: *Block, 1880 src: LazySrcLoc, 1881 air_ref: Air.Inst.Ref, 1882 reason: []const u8, 1883 ) CompileError!Value { 1884 if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| { 1885 if (val.isGenericPoison()) return error.GenericPoison; 1886 return val; 1887 } 1888 return sema.failWithNeededComptime(block, src, reason); 1889 } 1890 1891 /// Value Tag `variable` will cause a compile error. 1892 /// Value Tag `undef` may be returned. 1893 fn resolveConstMaybeUndefVal( 1894 sema: *Sema, 1895 block: *Block, 1896 src: LazySrcLoc, 1897 inst: Air.Inst.Ref, 1898 reason: []const u8, 1899 ) CompileError!Value { 1900 if (try sema.resolveMaybeUndefValAllowVariables(inst)) |val| { 1901 switch (val.toIntern()) { 1902 .generic_poison => return error.GenericPoison, 1903 else => switch (sema.mod.intern_pool.indexToKey(val.toIntern())) { 1904 .variable => return sema.failWithNeededComptime(block, src, reason), 1905 else => return val, 1906 }, 1907 } 1908 } 1909 return sema.failWithNeededComptime(block, src, reason); 1910 } 1911 1912 /// Will not return Value Tags: `variable`, `undef`. Instead they will emit compile errors. 1913 /// See `resolveValue` for an alternative. 1914 fn resolveConstValue( 1915 sema: *Sema, 1916 block: *Block, 1917 src: LazySrcLoc, 1918 air_ref: Air.Inst.Ref, 1919 reason: []const u8, 1920 ) CompileError!Value { 1921 if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| { 1922 switch (val.toIntern()) { 1923 .generic_poison => return error.GenericPoison, 1924 .undef => return sema.failWithUseOfUndef(block, src), 1925 else => switch (sema.mod.intern_pool.indexToKey(val.toIntern())) { 1926 .undef => return sema.failWithUseOfUndef(block, src), 1927 .variable => return sema.failWithNeededComptime(block, src, reason), 1928 else => return val, 1929 }, 1930 } 1931 } 1932 return sema.failWithNeededComptime(block, src, reason); 1933 } 1934 1935 /// Will not return Value Tags: `variable`, `undef`. Instead they will emit compile errors. 1936 /// Lazy values are recursively resolved. 1937 fn resolveConstLazyValue( 1938 sema: *Sema, 1939 block: *Block, 1940 src: LazySrcLoc, 1941 air_ref: Air.Inst.Ref, 1942 reason: []const u8, 1943 ) CompileError!Value { 1944 return sema.resolveLazyValue(try sema.resolveConstValue(block, src, air_ref, reason)); 1945 } 1946 1947 /// Value Tag `variable` causes this function to return `null`. 1948 /// Value Tag `undef` causes this function to return a compile error. 1949 fn resolveDefinedValue( 1950 sema: *Sema, 1951 block: *Block, 1952 src: LazySrcLoc, 1953 air_ref: Air.Inst.Ref, 1954 ) CompileError!?Value { 1955 const mod = sema.mod; 1956 if (try sema.resolveMaybeUndefVal(air_ref)) |val| { 1957 if (val.isUndef(mod)) { 1958 if (block.is_typeof) return null; 1959 return sema.failWithUseOfUndef(block, src); 1960 } 1961 return val; 1962 } 1963 return null; 1964 } 1965 1966 /// Value Tag `variable` causes this function to return `null`. 1967 /// Value Tag `undef` causes this function to return the Value. 1968 /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. 1969 fn resolveMaybeUndefVal( 1970 sema: *Sema, 1971 inst: Air.Inst.Ref, 1972 ) CompileError!?Value { 1973 const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null; 1974 switch (val.ip_index) { 1975 .generic_poison => return error.GenericPoison, 1976 .none => return val, 1977 else => switch (sema.mod.intern_pool.indexToKey(val.toIntern())) { 1978 .variable => return null, 1979 else => return val, 1980 }, 1981 } 1982 } 1983 1984 /// Value Tag `variable` causes this function to return `null`. 1985 /// Value Tag `undef` causes this function to return the Value. 1986 /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. 1987 /// Lazy values are recursively resolved. 1988 fn resolveMaybeUndefLazyVal( 1989 sema: *Sema, 1990 inst: Air.Inst.Ref, 1991 ) CompileError!?Value { 1992 return try sema.resolveLazyValue((try sema.resolveMaybeUndefVal(inst)) orelse return null); 1993 } 1994 1995 /// Value Tag `variable` results in `null`. 1996 /// Value Tag `undef` results in the Value. 1997 /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. 1998 /// Value Tag `decl_ref` and `decl_ref_mut` or any nested such value results in `null`. 1999 /// Lazy values are recursively resolved. 2000 fn resolveMaybeUndefValIntable( 2001 sema: *Sema, 2002 inst: Air.Inst.Ref, 2003 ) CompileError!?Value { 2004 const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null; 2005 var check = val; 2006 while (true) switch (check.ip_index) { 2007 .generic_poison => return error.GenericPoison, 2008 .none => break, 2009 else => switch (sema.mod.intern_pool.indexToKey(check.toIntern())) { 2010 .variable => return null, 2011 .ptr => |ptr| switch (ptr.addr) { 2012 .decl, .mut_decl, .comptime_field => return null, 2013 .int => break, 2014 .eu_payload, .opt_payload => |base| check = base.toValue(), 2015 .elem, .field => |base_index| check = base_index.base.toValue(), 2016 }, 2017 else => break, 2018 }, 2019 }; 2020 return try sema.resolveLazyValue(val); 2021 } 2022 2023 /// Returns all Value tags including `variable` and `undef`. 2024 fn resolveMaybeUndefValAllowVariables(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value { 2025 var make_runtime = false; 2026 if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(inst, &make_runtime)) |val| { 2027 if (make_runtime) return null; 2028 return val; 2029 } 2030 return null; 2031 } 2032 2033 /// Returns all Value tags including `variable`, `undef` and `runtime_value`. 2034 fn resolveMaybeUndefValAllowVariablesMaybeRuntime( 2035 sema: *Sema, 2036 inst: Air.Inst.Ref, 2037 make_runtime: *bool, 2038 ) CompileError!?Value { 2039 assert(inst != .none); 2040 // First section of indexes correspond to a set number of constant values. 2041 const int = @enumToInt(inst); 2042 if (int < InternPool.static_len) { 2043 return @intToEnum(InternPool.Index, int).toValue(); 2044 } 2045 2046 const i = int - InternPool.static_len; 2047 const air_tags = sema.air_instructions.items(.tag); 2048 if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| { 2049 if (air_tags[i] == .interned) { 2050 const interned = sema.air_instructions.items(.data)[i].interned; 2051 const val = interned.toValue(); 2052 if (val.getVariable(sema.mod) != null) return val; 2053 } 2054 return opv; 2055 } 2056 const air_datas = sema.air_instructions.items(.data); 2057 const val = switch (air_tags[i]) { 2058 .inferred_alloc => unreachable, 2059 .inferred_alloc_comptime => unreachable, 2060 .interned => air_datas[i].interned.toValue(), 2061 else => return null, 2062 }; 2063 if (val.isRuntimeValue(sema.mod)) make_runtime.* = true; 2064 if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true; 2065 return val; 2066 } 2067 2068 fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: []const u8) CompileError { 2069 const msg = msg: { 2070 const msg = try sema.errMsg(block, src, "unable to resolve comptime value", .{}); 2071 errdefer msg.destroy(sema.gpa); 2072 2073 try sema.errNote(block, src, msg, "{s}", .{reason}); 2074 break :msg msg; 2075 }; 2076 return sema.failWithOwnedErrorMsg(msg); 2077 } 2078 2079 fn failWithUseOfUndef(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError { 2080 return sema.fail(block, src, "use of undefined value here causes undefined behavior", .{}); 2081 } 2082 2083 fn failWithDivideByZero(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError { 2084 return sema.fail(block, src, "division by zero here causes undefined behavior", .{}); 2085 } 2086 2087 fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: Type, rhs_ty: Type) CompileError { 2088 return sema.fail(block, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{ 2089 lhs_ty.fmt(sema.mod), rhs_ty.fmt(sema.mod), 2090 }); 2091 } 2092 2093 fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, optional_ty: Type) CompileError { 2094 return sema.fail(block, src, "expected optional type, found '{}'", .{optional_ty.fmt(sema.mod)}); 2095 } 2096 2097 fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { 2098 const mod = sema.mod; 2099 const msg = msg: { 2100 const msg = try sema.errMsg(block, src, "type '{}' does not support array initialization syntax", .{ 2101 ty.fmt(mod), 2102 }); 2103 errdefer msg.destroy(sema.gpa); 2104 if (ty.isSlice(mod)) { 2105 try sema.errNote(block, src, msg, "inferred array length is specified with an underscore: '[_]{}'", .{ty.elemType2(mod).fmt(mod)}); 2106 } 2107 break :msg msg; 2108 }; 2109 return sema.failWithOwnedErrorMsg(msg); 2110 } 2111 2112 fn failWithStructInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { 2113 return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{ 2114 ty.fmt(sema.mod), 2115 }); 2116 } 2117 2118 fn failWithErrorSetCodeMissing( 2119 sema: *Sema, 2120 block: *Block, 2121 src: LazySrcLoc, 2122 dest_err_set_ty: Type, 2123 src_err_set_ty: Type, 2124 ) CompileError { 2125 return sema.fail(block, src, "expected type '{}', found type '{}'", .{ 2126 dest_err_set_ty.fmt(sema.mod), src_err_set_ty.fmt(sema.mod), 2127 }); 2128 } 2129 2130 fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: usize) CompileError { 2131 const mod = sema.mod; 2132 if (int_ty.zigTypeTag(mod) == .Vector) { 2133 const msg = msg: { 2134 const msg = try sema.errMsg(block, src, "overflow of vector type '{}' with value '{}'", .{ 2135 int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod), 2136 }); 2137 errdefer msg.destroy(sema.gpa); 2138 try sema.errNote(block, src, msg, "when computing vector element at index '{d}'", .{vector_index}); 2139 break :msg msg; 2140 }; 2141 return sema.failWithOwnedErrorMsg(msg); 2142 } 2143 return sema.fail(block, src, "overflow of integer type '{}' with value '{}'", .{ 2144 int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod), 2145 }); 2146 } 2147 2148 fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazySrcLoc, container_ty: Type, field_index: usize) CompileError { 2149 const mod = sema.mod; 2150 const msg = msg: { 2151 const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{}); 2152 errdefer msg.destroy(sema.gpa); 2153 2154 const struct_ty = mod.typeToStruct(container_ty) orelse break :msg msg; 2155 const default_value_src = mod.fieldSrcLoc(struct_ty.owner_decl, .{ 2156 .index = field_index, 2157 .range = .value, 2158 }); 2159 try mod.errNoteNonLazy(default_value_src, msg, "default value set here", .{}); 2160 break :msg msg; 2161 }; 2162 return sema.failWithOwnedErrorMsg(msg); 2163 } 2164 2165 fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError { 2166 const msg = msg: { 2167 const msg = try sema.errMsg(block, src, "async has not been implemented in the self-hosted compiler yet", .{}); 2168 errdefer msg.destroy(sema.gpa); 2169 break :msg msg; 2170 }; 2171 return sema.failWithOwnedErrorMsg(msg); 2172 } 2173 2174 fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, object_ty: Type, field_name: []const u8) CompileError { 2175 const mod = sema.mod; 2176 const inner_ty = if (object_ty.isSinglePointer(mod)) object_ty.childType(mod) else object_ty; 2177 2178 if (inner_ty.zigTypeTag(mod) == .Optional) opt: { 2179 const child_ty = inner_ty.optionalChild(mod); 2180 if (!typeSupportsFieldAccess(mod, child_ty, field_name)) break :opt; 2181 const msg = msg: { 2182 const msg = try sema.errMsg(block, src, "optional type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); 2183 errdefer msg.destroy(sema.gpa); 2184 try sema.errNote(block, src, msg, "consider using '.?', 'orelse', or 'if'", .{}); 2185 break :msg msg; 2186 }; 2187 return sema.failWithOwnedErrorMsg(msg); 2188 } else if (inner_ty.zigTypeTag(mod) == .ErrorUnion) err: { 2189 const child_ty = inner_ty.errorUnionPayload(mod); 2190 if (!typeSupportsFieldAccess(mod, child_ty, field_name)) break :err; 2191 const msg = msg: { 2192 const msg = try sema.errMsg(block, src, "error union type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); 2193 errdefer msg.destroy(sema.gpa); 2194 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); 2195 break :msg msg; 2196 }; 2197 return sema.failWithOwnedErrorMsg(msg); 2198 } 2199 return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); 2200 } 2201 2202 fn typeSupportsFieldAccess(mod: *const Module, ty: Type, field_name: []const u8) bool { 2203 switch (ty.zigTypeTag(mod)) { 2204 .Array => return mem.eql(u8, field_name, "len"), 2205 .Pointer => { 2206 const ptr_info = ty.ptrInfo(mod); 2207 if (ptr_info.size == .Slice) { 2208 return mem.eql(u8, field_name, "ptr") or mem.eql(u8, field_name, "len"); 2209 } else if (ptr_info.pointee_type.zigTypeTag(mod) == .Array) { 2210 return mem.eql(u8, field_name, "len"); 2211 } else return false; 2212 }, 2213 .Type, .Struct, .Union => return true, 2214 else => return false, 2215 } 2216 } 2217 2218 /// We don't return a pointer to the new error note because the pointer 2219 /// becomes invalid when you add another one. 2220 fn errNote( 2221 sema: *Sema, 2222 block: *Block, 2223 src: LazySrcLoc, 2224 parent: *Module.ErrorMsg, 2225 comptime format: []const u8, 2226 args: anytype, 2227 ) error{OutOfMemory}!void { 2228 const mod = sema.mod; 2229 const src_decl = mod.declPtr(block.src_decl); 2230 return mod.errNoteNonLazy(src.toSrcLoc(src_decl, mod), parent, format, args); 2231 } 2232 2233 fn addFieldErrNote( 2234 sema: *Sema, 2235 container_ty: Type, 2236 field_index: usize, 2237 parent: *Module.ErrorMsg, 2238 comptime format: []const u8, 2239 args: anytype, 2240 ) !void { 2241 @setCold(true); 2242 const mod = sema.mod; 2243 const decl_index = container_ty.getOwnerDecl(mod); 2244 const decl = mod.declPtr(decl_index); 2245 2246 const field_src = blk: { 2247 const tree = decl.getFileScope(mod).getTree(sema.gpa) catch |err| { 2248 log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); 2249 break :blk decl.srcLoc(mod); 2250 }; 2251 2252 const container_node = decl.relativeToNodeIndex(0); 2253 const node_tags = tree.nodes.items(.tag); 2254 var buf: [2]std.zig.Ast.Node.Index = undefined; 2255 const container_decl = tree.fullContainerDecl(&buf, container_node) orelse break :blk decl.srcLoc(mod); 2256 2257 var it_index: usize = 0; 2258 for (container_decl.ast.members) |member_node| { 2259 switch (node_tags[member_node]) { 2260 .container_field_init, 2261 .container_field_align, 2262 .container_field, 2263 => { 2264 if (it_index == field_index) { 2265 break :blk decl.nodeOffsetSrcLoc(decl.nodeIndexToRelative(member_node), mod); 2266 } 2267 it_index += 1; 2268 }, 2269 else => continue, 2270 } 2271 } 2272 unreachable; 2273 }; 2274 try mod.errNoteNonLazy(field_src, parent, format, args); 2275 } 2276 2277 fn errMsg( 2278 sema: *Sema, 2279 block: *Block, 2280 src: LazySrcLoc, 2281 comptime format: []const u8, 2282 args: anytype, 2283 ) error{OutOfMemory}!*Module.ErrorMsg { 2284 const mod = sema.mod; 2285 const src_decl = mod.declPtr(block.src_decl); 2286 return Module.ErrorMsg.create(sema.gpa, src.toSrcLoc(src_decl, mod), format, args); 2287 } 2288 2289 pub fn fail( 2290 sema: *Sema, 2291 block: *Block, 2292 src: LazySrcLoc, 2293 comptime format: []const u8, 2294 args: anytype, 2295 ) CompileError { 2296 const err_msg = try sema.errMsg(block, src, format, args); 2297 return sema.failWithOwnedErrorMsg(err_msg); 2298 } 2299 2300 fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { 2301 @setCold(true); 2302 const gpa = sema.gpa; 2303 2304 if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) { 2305 if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation; 2306 var wip_errors: std.zig.ErrorBundle.Wip = undefined; 2307 wip_errors.init(gpa) catch unreachable; 2308 Compilation.addModuleErrorMsg(&wip_errors, err_msg.*) catch unreachable; 2309 std.debug.print("compile error during Sema:\n", .{}); 2310 var error_bundle = wip_errors.toOwnedBundle("") catch unreachable; 2311 error_bundle.renderToStdErr(.{ .ttyconf = .no_color }); 2312 crash_report.compilerPanic("unexpected compile error occurred", null, null); 2313 } 2314 2315 const mod = sema.mod; 2316 ref: { 2317 errdefer err_msg.destroy(gpa); 2318 if (err_msg.src_loc.lazy == .unneeded) { 2319 return error.NeededSourceLocation; 2320 } 2321 try mod.failed_decls.ensureUnusedCapacity(gpa, 1); 2322 try mod.failed_files.ensureUnusedCapacity(gpa, 1); 2323 2324 const max_references = blk: { 2325 if (sema.mod.comp.reference_trace) |num| break :blk num; 2326 // Do not add multiple traces without explicit request. 2327 if (sema.mod.failed_decls.count() != 0) break :ref; 2328 break :blk default_reference_trace_len; 2329 }; 2330 2331 var referenced_by = if (sema.func) |some| some.owner_decl else sema.owner_decl_index; 2332 var reference_stack = std.ArrayList(Module.ErrorMsg.Trace).init(gpa); 2333 defer reference_stack.deinit(); 2334 2335 // Avoid infinite loops. 2336 var seen = std.AutoHashMap(Decl.Index, void).init(gpa); 2337 defer seen.deinit(); 2338 2339 var cur_reference_trace: u32 = 0; 2340 while (sema.mod.reference_table.get(referenced_by)) |ref| : (cur_reference_trace += 1) { 2341 const gop = try seen.getOrPut(ref.referencer); 2342 if (gop.found_existing) break; 2343 if (cur_reference_trace < max_references) { 2344 const decl = sema.mod.declPtr(ref.referencer); 2345 try reference_stack.append(.{ .decl = decl.name, .src_loc = ref.src.toSrcLoc(decl, mod) }); 2346 } 2347 referenced_by = ref.referencer; 2348 } 2349 if (sema.mod.comp.reference_trace == null and cur_reference_trace > 0) { 2350 try reference_stack.append(.{ 2351 .decl = null, 2352 .src_loc = undefined, 2353 .hidden = 0, 2354 }); 2355 } else if (cur_reference_trace > max_references) { 2356 try reference_stack.append(.{ 2357 .decl = undefined, 2358 .src_loc = undefined, 2359 .hidden = cur_reference_trace - max_references, 2360 }); 2361 } 2362 err_msg.reference_trace = try reference_stack.toOwnedSlice(); 2363 } 2364 if (sema.owner_func) |func| { 2365 func.state = .sema_failure; 2366 } else { 2367 sema.owner_decl.analysis = .sema_failure; 2368 sema.owner_decl.generation = mod.generation; 2369 } 2370 if (sema.func) |func| { 2371 func.state = .sema_failure; 2372 } 2373 const gop = mod.failed_decls.getOrPutAssumeCapacity(sema.owner_decl_index); 2374 if (gop.found_existing) { 2375 // If there are multiple errors for the same Decl, prefer the first one added. 2376 sema.err = null; 2377 err_msg.destroy(gpa); 2378 } else { 2379 sema.err = err_msg; 2380 gop.value_ptr.* = err_msg; 2381 } 2382 return error.AnalysisFail; 2383 } 2384 2385 const align_ty = Type.u29; 2386 2387 fn analyzeAsAlign( 2388 sema: *Sema, 2389 block: *Block, 2390 src: LazySrcLoc, 2391 air_ref: Air.Inst.Ref, 2392 ) !u32 { 2393 const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, "alignment must be comptime-known"); 2394 const alignment = @intCast(u32, alignment_big); // We coerce to u16 in the prev line. 2395 try sema.validateAlign(block, src, alignment); 2396 return alignment; 2397 } 2398 2399 fn validateAlign( 2400 sema: *Sema, 2401 block: *Block, 2402 src: LazySrcLoc, 2403 alignment: u32, 2404 ) !void { 2405 if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{}); 2406 if (!std.math.isPowerOfTwo(alignment)) { 2407 return sema.fail(block, src, "alignment value '{d}' is not a power of two", .{ 2408 alignment, 2409 }); 2410 } 2411 } 2412 2413 pub fn resolveAlign( 2414 sema: *Sema, 2415 block: *Block, 2416 src: LazySrcLoc, 2417 zir_ref: Zir.Inst.Ref, 2418 ) !u32 { 2419 const air_ref = try sema.resolveInst(zir_ref); 2420 return sema.analyzeAsAlign(block, src, air_ref); 2421 } 2422 2423 fn resolveInt( 2424 sema: *Sema, 2425 block: *Block, 2426 src: LazySrcLoc, 2427 zir_ref: Zir.Inst.Ref, 2428 dest_ty: Type, 2429 reason: []const u8, 2430 ) !u64 { 2431 const air_ref = try sema.resolveInst(zir_ref); 2432 return sema.analyzeAsInt(block, src, air_ref, dest_ty, reason); 2433 } 2434 2435 fn analyzeAsInt( 2436 sema: *Sema, 2437 block: *Block, 2438 src: LazySrcLoc, 2439 air_ref: Air.Inst.Ref, 2440 dest_ty: Type, 2441 reason: []const u8, 2442 ) !u64 { 2443 const mod = sema.mod; 2444 const coerced = try sema.coerce(block, dest_ty, air_ref, src); 2445 const val = try sema.resolveConstValue(block, src, coerced, reason); 2446 return (try val.getUnsignedIntAdvanced(mod, sema)).?; 2447 } 2448 2449 // Returns a compile error if the value has tag `variable`. See `resolveInstValue` for 2450 // a function that does not. 2451 pub fn resolveInstConst( 2452 sema: *Sema, 2453 block: *Block, 2454 src: LazySrcLoc, 2455 zir_ref: Zir.Inst.Ref, 2456 reason: []const u8, 2457 ) CompileError!TypedValue { 2458 const air_ref = try sema.resolveInst(zir_ref); 2459 const val = try sema.resolveConstValue(block, src, air_ref, reason); 2460 return TypedValue{ 2461 .ty = sema.typeOf(air_ref), 2462 .val = val, 2463 }; 2464 } 2465 2466 // Value Tag may be `undef` or `variable`. 2467 // See `resolveInstConst` for an alternative. 2468 pub fn resolveInstValue( 2469 sema: *Sema, 2470 block: *Block, 2471 src: LazySrcLoc, 2472 zir_ref: Zir.Inst.Ref, 2473 reason: []const u8, 2474 ) CompileError!TypedValue { 2475 const air_ref = try sema.resolveInst(zir_ref); 2476 const val = try sema.resolveValue(block, src, air_ref, reason); 2477 return TypedValue{ 2478 .ty = sema.typeOf(air_ref), 2479 .val = val, 2480 }; 2481 } 2482 2483 fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 2484 const tracy = trace(@src()); 2485 defer tracy.end(); 2486 2487 const mod = sema.mod; 2488 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 2489 const src = inst_data.src(); 2490 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 2491 const pointee_ty = try sema.resolveType(block, src, extra.lhs); 2492 const ptr = try sema.resolveInst(extra.rhs); 2493 const target = mod.getTarget(); 2494 const addr_space = target_util.defaultAddressSpace(target, .local); 2495 2496 if (Air.refToIndex(ptr)) |ptr_inst| { 2497 switch (sema.air_instructions.items(.tag)[ptr_inst]) { 2498 .inferred_alloc => { 2499 const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc; 2500 const ia2 = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?; 2501 // Add the stored instruction to the set we will use to resolve peer types 2502 // for the inferred allocation. 2503 // This instruction will not make it to codegen; it is only to participate 2504 // in the `stored_inst_list` of the `inferred_alloc`. 2505 var trash_block = block.makeSubBlock(); 2506 defer trash_block.instructions.deinit(sema.gpa); 2507 const operand = try trash_block.addBitCast(pointee_ty, .void_value); 2508 2509 const ptr_ty = try mod.ptrType(.{ 2510 .child = pointee_ty.toIntern(), 2511 .flags = .{ 2512 .alignment = ia1.alignment, 2513 .address_space = addr_space, 2514 }, 2515 }); 2516 const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr); 2517 2518 try ia2.prongs.append(sema.arena, .{ 2519 .stored_inst = operand, 2520 .placeholder = Air.refToIndex(bitcasted_ptr).?, 2521 }); 2522 2523 return bitcasted_ptr; 2524 }, 2525 .inferred_alloc_comptime => { 2526 const alignment = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime.alignment; 2527 // There will be only one coerce_result_ptr because we are running at comptime. 2528 // The alloc will turn into a Decl. 2529 var anon_decl = try block.startAnonDecl(); 2530 defer anon_decl.deinit(); 2531 const decl_index = try anon_decl.finish( 2532 pointee_ty, 2533 (try mod.intern(.{ .undef = pointee_ty.toIntern() })).toValue(), 2534 alignment.toByteUnits(0), 2535 ); 2536 sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime.decl_index = decl_index; 2537 if (alignment != .none) { 2538 try sema.resolveTypeLayout(pointee_ty); 2539 } 2540 const ptr_ty = try mod.ptrType(.{ 2541 .child = pointee_ty.toIntern(), 2542 .flags = .{ 2543 .alignment = alignment, 2544 .address_space = addr_space, 2545 }, 2546 }); 2547 try sema.maybeQueueFuncBodyAnalysis(decl_index); 2548 return sema.addConstant(ptr_ty, (try mod.intern(.{ .ptr = .{ 2549 .ty = ptr_ty.toIntern(), 2550 .addr = .{ .mut_decl = .{ 2551 .decl = decl_index, 2552 .runtime_index = block.runtime_index, 2553 } }, 2554 } })).toValue()); 2555 }, 2556 else => {}, 2557 } 2558 } 2559 2560 // Make a dummy store through the pointer to test the coercion. 2561 // We will then use the generated instructions to decide what 2562 // kind of transformations to make on the result pointer. 2563 var trash_block = block.makeSubBlock(); 2564 trash_block.is_comptime = false; 2565 defer trash_block.instructions.deinit(sema.gpa); 2566 2567 const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr)); 2568 const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value); 2569 return sema.coerceResultPtr(block, src, ptr, dummy_ptr, dummy_operand, &trash_block); 2570 } 2571 2572 fn coerceResultPtr( 2573 sema: *Sema, 2574 block: *Block, 2575 src: LazySrcLoc, 2576 ptr: Air.Inst.Ref, 2577 dummy_ptr: Air.Inst.Ref, 2578 dummy_operand: Air.Inst.Ref, 2579 trash_block: *Block, 2580 ) CompileError!Air.Inst.Ref { 2581 const mod = sema.mod; 2582 const target = sema.mod.getTarget(); 2583 const addr_space = target_util.defaultAddressSpace(target, .local); 2584 const pointee_ty = sema.typeOf(dummy_operand); 2585 const prev_trash_len = trash_block.instructions.items.len; 2586 2587 try sema.storePtr2(trash_block, src, dummy_ptr, src, dummy_operand, src, .bitcast); 2588 2589 { 2590 const air_tags = sema.air_instructions.items(.tag); 2591 2592 //std.debug.print("dummy storePtr instructions:\n", .{}); 2593 //for (trash_block.instructions.items) |item| { 2594 // std.debug.print(" {s}\n", .{@tagName(air_tags[item])}); 2595 //} 2596 2597 // The last one is always `store`. 2598 const trash_inst = trash_block.instructions.items[trash_block.instructions.items.len - 1]; 2599 if (air_tags[trash_inst] != .store and air_tags[trash_inst] != .store_safe) { 2600 // no store instruction is generated for zero sized types 2601 assert((try sema.typeHasOnePossibleValue(pointee_ty)) != null); 2602 } else { 2603 trash_block.instructions.items.len -= 1; 2604 assert(trash_inst == sema.air_instructions.len - 1); 2605 sema.air_instructions.len -= 1; 2606 } 2607 } 2608 2609 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 2610 .pointee_type = pointee_ty, 2611 .@"addrspace" = addr_space, 2612 }); 2613 2614 var new_ptr = ptr; 2615 2616 while (true) { 2617 const air_tags = sema.air_instructions.items(.tag); 2618 const air_datas = sema.air_instructions.items(.data); 2619 2620 if (trash_block.instructions.items.len == prev_trash_len) { 2621 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| { 2622 return sema.addConstant(ptr_ty, ptr_val); 2623 } 2624 if (pointee_ty.eql(Type.null, sema.mod)) { 2625 const opt_ty = sema.typeOf(new_ptr).childType(mod); 2626 const null_inst = try sema.addConstant(opt_ty, Value.null); 2627 _ = try block.addBinOp(.store, new_ptr, null_inst); 2628 return Air.Inst.Ref.void_value; 2629 } 2630 return sema.bitCast(block, ptr_ty, new_ptr, src, null); 2631 } 2632 2633 const trash_inst = trash_block.instructions.pop(); 2634 2635 switch (air_tags[trash_inst]) { 2636 // Array coerced to Vector where element size is not equal but coercible. 2637 .aggregate_init => { 2638 const ty_pl = air_datas[trash_inst].ty_pl; 2639 const ptr_operand_ty = try Type.ptr(sema.arena, sema.mod, .{ 2640 .pointee_type = try sema.analyzeAsType(block, src, ty_pl.ty), 2641 .@"addrspace" = addr_space, 2642 }); 2643 2644 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| { 2645 return sema.addConstant(ptr_operand_ty, ptr_val); 2646 } else { 2647 return sema.bitCast(block, ptr_operand_ty, new_ptr, src, null); 2648 } 2649 }, 2650 .bitcast => { 2651 const ty_op = air_datas[trash_inst].ty_op; 2652 const operand_ty = sema.typeOf(ty_op.operand); 2653 const ptr_operand_ty = try Type.ptr(sema.arena, sema.mod, .{ 2654 .pointee_type = operand_ty, 2655 .@"addrspace" = addr_space, 2656 }); 2657 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| { 2658 new_ptr = try sema.addConstant(ptr_operand_ty, try mod.getCoerced(ptr_val, ptr_operand_ty)); 2659 } else { 2660 new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src, null); 2661 } 2662 }, 2663 .wrap_optional => { 2664 new_ptr = try sema.analyzeOptionalPayloadPtr(block, src, new_ptr, false, true); 2665 }, 2666 .wrap_errunion_err => { 2667 return sema.fail(block, src, "TODO coerce_result_ptr wrap_errunion_err", .{}); 2668 }, 2669 .wrap_errunion_payload => { 2670 new_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, new_ptr, false, true); 2671 }, 2672 .array_to_slice => { 2673 return sema.fail(block, src, "TODO coerce_result_ptr array_to_slice", .{}); 2674 }, 2675 .get_union_tag => { 2676 return sema.fail(block, src, "TODO coerce_result_ptr get_union_tag", .{}); 2677 }, 2678 else => { 2679 if (std.debug.runtime_safety) { 2680 std.debug.panic("unexpected AIR tag for coerce_result_ptr: {}", .{ 2681 air_tags[trash_inst], 2682 }); 2683 } else { 2684 unreachable; 2685 } 2686 }, 2687 } 2688 } 2689 } 2690 2691 pub fn analyzeStructDecl( 2692 sema: *Sema, 2693 new_decl: *Decl, 2694 inst: Zir.Inst.Index, 2695 struct_index: Module.Struct.Index, 2696 ) SemaError!void { 2697 const mod = sema.mod; 2698 const struct_obj = mod.structPtr(struct_index); 2699 const extended = sema.code.instructions.items(.data)[inst].extended; 2700 assert(extended.opcode == .struct_decl); 2701 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); 2702 2703 struct_obj.known_non_opv = small.known_non_opv; 2704 if (small.known_comptime_only) { 2705 struct_obj.requires_comptime = .yes; 2706 } 2707 2708 var extra_index: usize = extended.operand; 2709 extra_index += @boolToInt(small.has_src_node); 2710 extra_index += @boolToInt(small.has_fields_len); 2711 const decls_len = if (small.has_decls_len) blk: { 2712 const decls_len = sema.code.extra[extra_index]; 2713 extra_index += 1; 2714 break :blk decls_len; 2715 } else 0; 2716 2717 if (small.has_backing_int) { 2718 const backing_int_body_len = sema.code.extra[extra_index]; 2719 extra_index += 1; // backing_int_body_len 2720 if (backing_int_body_len == 0) { 2721 extra_index += 1; // backing_int_ref 2722 } else { 2723 extra_index += backing_int_body_len; // backing_int_body_inst 2724 } 2725 } 2726 2727 _ = try mod.scanNamespace(struct_obj.namespace, extra_index, decls_len, new_decl); 2728 } 2729 2730 fn zirStructDecl( 2731 sema: *Sema, 2732 block: *Block, 2733 extended: Zir.Inst.Extended.InstData, 2734 inst: Zir.Inst.Index, 2735 ) CompileError!Air.Inst.Ref { 2736 const mod = sema.mod; 2737 const gpa = sema.gpa; 2738 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); 2739 const src: LazySrcLoc = if (small.has_src_node) blk: { 2740 const node_offset = @bitCast(i32, sema.code.extra[extended.operand]); 2741 break :blk LazySrcLoc.nodeOffset(node_offset); 2742 } else sema.src; 2743 2744 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 2745 errdefer new_decl_arena.deinit(); 2746 2747 // Because these three things each reference each other, `undefined` 2748 // placeholders are used before being set after the struct type gains an 2749 // InternPool index. 2750 2751 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 2752 .ty = Type.type, 2753 .val = undefined, 2754 }, small.name_strategy, "struct", inst); 2755 const new_decl = mod.declPtr(new_decl_index); 2756 new_decl.owns_tv = true; 2757 errdefer mod.abortAnonDecl(new_decl_index); 2758 2759 const new_namespace_index = try mod.createNamespace(.{ 2760 .parent = block.namespace.toOptional(), 2761 .ty = undefined, 2762 .file_scope = block.getFileScope(mod), 2763 }); 2764 const new_namespace = mod.namespacePtr(new_namespace_index); 2765 errdefer mod.destroyNamespace(new_namespace_index); 2766 2767 const struct_index = try mod.createStruct(.{ 2768 .owner_decl = new_decl_index, 2769 .fields = .{}, 2770 .zir_index = inst, 2771 .layout = small.layout, 2772 .status = .none, 2773 .known_non_opv = undefined, 2774 .is_tuple = small.is_tuple, 2775 .namespace = new_namespace_index, 2776 }); 2777 errdefer mod.destroyStruct(struct_index); 2778 2779 const struct_ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{ 2780 .index = struct_index.toOptional(), 2781 .namespace = new_namespace_index.toOptional(), 2782 } }); 2783 errdefer mod.intern_pool.remove(struct_ty); 2784 2785 new_decl.val = struct_ty.toValue(); 2786 new_namespace.ty = struct_ty.toType(); 2787 2788 try sema.analyzeStructDecl(new_decl, inst, struct_index); 2789 try new_decl.finalizeNewArena(&new_decl_arena); 2790 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); 2791 try mod.finalizeAnonDecl(new_decl_index); 2792 return decl_val; 2793 } 2794 2795 fn createAnonymousDeclTypeNamed( 2796 sema: *Sema, 2797 block: *Block, 2798 src: LazySrcLoc, 2799 typed_value: TypedValue, 2800 name_strategy: Zir.Inst.NameStrategy, 2801 anon_prefix: []const u8, 2802 inst: ?Zir.Inst.Index, 2803 ) !Decl.Index { 2804 const mod = sema.mod; 2805 const gpa = sema.gpa; 2806 const namespace = block.namespace; 2807 const src_scope = block.wip_capture_scope; 2808 const src_decl = mod.declPtr(block.src_decl); 2809 const src_node = src_decl.relativeToNodeIndex(src.node_offset.x); 2810 const new_decl_index = try mod.allocateNewDecl(namespace, src_node, src_scope); 2811 errdefer mod.destroyDecl(new_decl_index); 2812 2813 switch (name_strategy) { 2814 .anon => { 2815 // It would be neat to have "struct:line:column" but this name has 2816 // to survive incremental updates, where it may have been shifted down 2817 // or up to a different line, but unchanged, and thus not unnecessarily 2818 // semantically analyzed. 2819 // This name is also used as the key in the parent namespace so it cannot be 2820 // renamed. 2821 const name = try std.fmt.allocPrintZ(gpa, "{s}__{s}_{d}", .{ 2822 src_decl.name, anon_prefix, @enumToInt(new_decl_index), 2823 }); 2824 errdefer gpa.free(name); 2825 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); 2826 return new_decl_index; 2827 }, 2828 .parent => { 2829 const name = try gpa.dupeZ(u8, mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0)); 2830 errdefer gpa.free(name); 2831 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); 2832 return new_decl_index; 2833 }, 2834 .func => { 2835 const fn_info = sema.code.getFnInfo(sema.func.?.zir_body_inst); 2836 const zir_tags = sema.code.instructions.items(.tag); 2837 2838 var buf = std.ArrayList(u8).init(gpa); 2839 defer buf.deinit(); 2840 try buf.appendSlice(mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0)); 2841 try buf.appendSlice("("); 2842 2843 var arg_i: usize = 0; 2844 for (fn_info.param_body) |zir_inst| switch (zir_tags[zir_inst]) { 2845 .param, .param_comptime, .param_anytype, .param_anytype_comptime => { 2846 const arg = sema.inst_map.get(zir_inst).?; 2847 // If this is being called in a generic function then analyzeCall will 2848 // have already resolved the args and this will work. 2849 // If not then this is a struct type being returned from a non-generic 2850 // function and the name doesn't matter since it will later 2851 // result in a compile error. 2852 const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg, "") catch 2853 return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null); 2854 2855 if (arg_i != 0) try buf.appendSlice(","); 2856 try buf.writer().print("{}", .{arg_val.fmtValue(sema.typeOf(arg), sema.mod)}); 2857 2858 arg_i += 1; 2859 continue; 2860 }, 2861 else => continue, 2862 }; 2863 2864 try buf.appendSlice(")"); 2865 const name = try buf.toOwnedSliceSentinel(0); 2866 errdefer gpa.free(name); 2867 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); 2868 return new_decl_index; 2869 }, 2870 .dbg_var => { 2871 const ref = Zir.indexToRef(inst.?); 2872 const zir_tags = sema.code.instructions.items(.tag); 2873 const zir_data = sema.code.instructions.items(.data); 2874 var i = inst.?; 2875 while (i < zir_tags.len) : (i += 1) switch (zir_tags[i]) { 2876 .dbg_var_ptr, .dbg_var_val => { 2877 if (zir_data[i].str_op.operand != ref) continue; 2878 2879 const name = try std.fmt.allocPrintZ(gpa, "{s}.{s}", .{ 2880 src_decl.name, zir_data[i].str_op.getStr(sema.code), 2881 }); 2882 errdefer gpa.free(name); 2883 2884 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); 2885 return new_decl_index; 2886 }, 2887 else => {}, 2888 }; 2889 return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null); 2890 }, 2891 } 2892 } 2893 2894 fn zirEnumDecl( 2895 sema: *Sema, 2896 block: *Block, 2897 extended: Zir.Inst.Extended.InstData, 2898 inst: Zir.Inst.Index, 2899 ) CompileError!Air.Inst.Ref { 2900 const tracy = trace(@src()); 2901 defer tracy.end(); 2902 2903 const mod = sema.mod; 2904 const gpa = sema.gpa; 2905 const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small); 2906 var extra_index: usize = extended.operand; 2907 2908 const src: LazySrcLoc = if (small.has_src_node) blk: { 2909 const node_offset = @bitCast(i32, sema.code.extra[extra_index]); 2910 extra_index += 1; 2911 break :blk LazySrcLoc.nodeOffset(node_offset); 2912 } else sema.src; 2913 const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x }; 2914 2915 const tag_type_ref = if (small.has_tag_type) blk: { 2916 const tag_type_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 2917 extra_index += 1; 2918 break :blk tag_type_ref; 2919 } else .none; 2920 2921 const body_len = if (small.has_body_len) blk: { 2922 const body_len = sema.code.extra[extra_index]; 2923 extra_index += 1; 2924 break :blk body_len; 2925 } else 0; 2926 2927 const fields_len = if (small.has_fields_len) blk: { 2928 const fields_len = sema.code.extra[extra_index]; 2929 extra_index += 1; 2930 break :blk fields_len; 2931 } else 0; 2932 2933 const decls_len = if (small.has_decls_len) blk: { 2934 const decls_len = sema.code.extra[extra_index]; 2935 extra_index += 1; 2936 break :blk decls_len; 2937 } else 0; 2938 2939 // Because these three things each reference each other, `undefined` 2940 // placeholders are used before being set after the enum type gains an 2941 // InternPool index. 2942 2943 var done = false; 2944 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 2945 .ty = Type.type, 2946 .val = undefined, 2947 }, small.name_strategy, "enum", inst); 2948 const new_decl = mod.declPtr(new_decl_index); 2949 new_decl.owns_tv = true; 2950 errdefer if (!done) mod.abortAnonDecl(new_decl_index); 2951 2952 const new_namespace_index = try mod.createNamespace(.{ 2953 .parent = block.namespace.toOptional(), 2954 .ty = undefined, 2955 .file_scope = block.getFileScope(mod), 2956 }); 2957 const new_namespace = mod.namespacePtr(new_namespace_index); 2958 errdefer if (!done) mod.destroyNamespace(new_namespace_index); 2959 2960 extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl); 2961 2962 const body = sema.code.extra[extra_index..][0..body_len]; 2963 extra_index += body.len; 2964 2965 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; 2966 const body_end = extra_index; 2967 extra_index += bit_bags_count; 2968 2969 const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| { 2970 if (bag != 0) break true; 2971 } else false; 2972 2973 const incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{ 2974 .decl = new_decl_index, 2975 .namespace = new_namespace_index.toOptional(), 2976 .fields_len = fields_len, 2977 .has_values = any_values, 2978 .tag_mode = if (small.nonexhaustive) 2979 .nonexhaustive 2980 else if (tag_type_ref == .none) 2981 .auto 2982 else 2983 .explicit, 2984 }); 2985 errdefer if (!done) mod.intern_pool.remove(incomplete_enum.index); 2986 2987 new_decl.val = incomplete_enum.index.toValue(); 2988 new_namespace.ty = incomplete_enum.index.toType(); 2989 2990 const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index); 2991 try mod.finalizeAnonDecl(new_decl_index); 2992 done = true; 2993 2994 const int_tag_ty = ty: { 2995 // We create a block for the field type instructions because they 2996 // may need to reference Decls from inside the enum namespace. 2997 // Within the field type, default value, and alignment expressions, the "owner decl" 2998 // should be the enum itself. 2999 3000 const prev_owner_decl = sema.owner_decl; 3001 const prev_owner_decl_index = sema.owner_decl_index; 3002 sema.owner_decl = new_decl; 3003 sema.owner_decl_index = new_decl_index; 3004 defer { 3005 sema.owner_decl = prev_owner_decl; 3006 sema.owner_decl_index = prev_owner_decl_index; 3007 } 3008 3009 const prev_owner_func = sema.owner_func; 3010 const prev_owner_func_index = sema.owner_func_index; 3011 sema.owner_func = null; 3012 sema.owner_func_index = .none; 3013 defer sema.owner_func = prev_owner_func; 3014 defer sema.owner_func_index = prev_owner_func_index; 3015 3016 const prev_func = sema.func; 3017 const prev_func_index = sema.func_index; 3018 sema.func = null; 3019 sema.func_index = .none; 3020 defer sema.func = prev_func; 3021 defer sema.func_index = prev_func_index; 3022 3023 var wip_captures = try WipCaptureScope.init(gpa, new_decl.src_scope); 3024 defer wip_captures.deinit(); 3025 3026 var enum_block: Block = .{ 3027 .parent = null, 3028 .sema = sema, 3029 .src_decl = new_decl_index, 3030 .namespace = new_namespace_index, 3031 .wip_capture_scope = wip_captures.scope, 3032 .instructions = .{}, 3033 .inlining = null, 3034 .is_comptime = true, 3035 }; 3036 defer enum_block.instructions.deinit(sema.gpa); 3037 3038 if (body.len != 0) { 3039 try sema.analyzeBody(&enum_block, body); 3040 } 3041 3042 try wip_captures.finalize(); 3043 3044 if (tag_type_ref != .none) { 3045 const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref); 3046 if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) { 3047 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)}); 3048 } 3049 incomplete_enum.setTagType(&mod.intern_pool, ty.toIntern()); 3050 break :ty ty; 3051 } else if (fields_len == 0) { 3052 break :ty try mod.intType(.unsigned, 0); 3053 } else { 3054 const bits = std.math.log2_int_ceil(usize, fields_len); 3055 break :ty try mod.intType(.unsigned, bits); 3056 } 3057 }; 3058 3059 if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) { 3060 if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(mod)) { 3061 return sema.fail(block, src, "non-exhaustive enum specifies every value", .{}); 3062 } 3063 } 3064 3065 var bit_bag_index: usize = body_end; 3066 var cur_bit_bag: u32 = undefined; 3067 var field_i: u32 = 0; 3068 var last_tag_val: ?Value = null; 3069 while (field_i < fields_len) : (field_i += 1) { 3070 if (field_i % 32 == 0) { 3071 cur_bit_bag = sema.code.extra[bit_bag_index]; 3072 bit_bag_index += 1; 3073 } 3074 const has_tag_value = @truncate(u1, cur_bit_bag) != 0; 3075 cur_bit_bag >>= 1; 3076 3077 const field_name_zir = sema.code.nullTerminatedString(sema.code.extra[extra_index]); 3078 extra_index += 1; 3079 3080 // doc comment 3081 extra_index += 1; 3082 3083 const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir); 3084 if (try incomplete_enum.addFieldName(&mod.intern_pool, gpa, field_name)) |other_index| { 3085 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy; 3086 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy; 3087 const msg = msg: { 3088 const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name_zir}); 3089 errdefer msg.destroy(gpa); 3090 try sema.errNote(block, other_field_src, msg, "other field here", .{}); 3091 break :msg msg; 3092 }; 3093 return sema.failWithOwnedErrorMsg(msg); 3094 } 3095 3096 if (has_tag_value) { 3097 const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 3098 extra_index += 1; 3099 const tag_inst = try sema.resolveInst(tag_val_ref); 3100 const tag_val = sema.resolveConstValue(block, .unneeded, tag_inst, "") catch |err| switch (err) { 3101 error.NeededSourceLocation => { 3102 const value_src = mod.fieldSrcLoc(new_decl_index, .{ 3103 .index = field_i, 3104 .range = .value, 3105 }).lazy; 3106 _ = try sema.resolveConstValue(block, value_src, tag_inst, "enum tag value must be comptime-known"); 3107 unreachable; 3108 }, 3109 else => |e| return e, 3110 }; 3111 last_tag_val = tag_val; 3112 if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, tag_val.toIntern())) |other_index| { 3113 const value_src = mod.fieldSrcLoc(new_decl_index, .{ 3114 .index = field_i, 3115 .range = .value, 3116 }).lazy; 3117 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy; 3118 const msg = msg: { 3119 const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{tag_val.fmtValue(int_tag_ty, sema.mod)}); 3120 errdefer msg.destroy(gpa); 3121 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{}); 3122 break :msg msg; 3123 }; 3124 return sema.failWithOwnedErrorMsg(msg); 3125 } 3126 } else if (any_values) { 3127 const tag_val = if (last_tag_val) |val| 3128 try sema.intAdd(val, try mod.intValue(int_tag_ty, 1), int_tag_ty) 3129 else 3130 try mod.intValue(int_tag_ty, 0); 3131 last_tag_val = tag_val; 3132 if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, tag_val.toIntern())) |other_index| { 3133 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy; 3134 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy; 3135 const msg = msg: { 3136 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(int_tag_ty, sema.mod)}); 3137 errdefer msg.destroy(gpa); 3138 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{}); 3139 break :msg msg; 3140 }; 3141 return sema.failWithOwnedErrorMsg(msg); 3142 } 3143 } else { 3144 last_tag_val = try mod.intValue(int_tag_ty, field_i); 3145 } 3146 3147 if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) { 3148 const value_src = mod.fieldSrcLoc(new_decl_index, .{ 3149 .index = field_i, 3150 .range = if (has_tag_value) .value else .name, 3151 }).lazy; 3152 const msg = try sema.errMsg(block, value_src, "enumeration value '{}' too large for type '{}'", .{ 3153 last_tag_val.?.fmtValue(int_tag_ty, mod), int_tag_ty.fmt(mod), 3154 }); 3155 return sema.failWithOwnedErrorMsg(msg); 3156 } 3157 } 3158 return decl_val; 3159 } 3160 3161 fn zirUnionDecl( 3162 sema: *Sema, 3163 block: *Block, 3164 extended: Zir.Inst.Extended.InstData, 3165 inst: Zir.Inst.Index, 3166 ) CompileError!Air.Inst.Ref { 3167 const tracy = trace(@src()); 3168 defer tracy.end(); 3169 3170 const mod = sema.mod; 3171 const gpa = sema.gpa; 3172 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); 3173 var extra_index: usize = extended.operand; 3174 3175 const src: LazySrcLoc = if (small.has_src_node) blk: { 3176 const node_offset = @bitCast(i32, sema.code.extra[extra_index]); 3177 extra_index += 1; 3178 break :blk LazySrcLoc.nodeOffset(node_offset); 3179 } else sema.src; 3180 3181 extra_index += @boolToInt(small.has_tag_type); 3182 extra_index += @boolToInt(small.has_body_len); 3183 extra_index += @boolToInt(small.has_fields_len); 3184 3185 const decls_len = if (small.has_decls_len) blk: { 3186 const decls_len = sema.code.extra[extra_index]; 3187 extra_index += 1; 3188 break :blk decls_len; 3189 } else 0; 3190 3191 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 3192 errdefer new_decl_arena.deinit(); 3193 3194 // Because these three things each reference each other, `undefined` 3195 // placeholders are used before being set after the union type gains an 3196 // InternPool index. 3197 3198 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 3199 .ty = Type.type, 3200 .val = undefined, 3201 }, small.name_strategy, "union", inst); 3202 const new_decl = mod.declPtr(new_decl_index); 3203 new_decl.owns_tv = true; 3204 errdefer mod.abortAnonDecl(new_decl_index); 3205 3206 const new_namespace_index = try mod.createNamespace(.{ 3207 .parent = block.namespace.toOptional(), 3208 .ty = undefined, 3209 .file_scope = block.getFileScope(mod), 3210 }); 3211 const new_namespace = mod.namespacePtr(new_namespace_index); 3212 errdefer mod.destroyNamespace(new_namespace_index); 3213 3214 const union_index = try mod.createUnion(.{ 3215 .owner_decl = new_decl_index, 3216 .tag_ty = Type.null, 3217 .fields = .{}, 3218 .zir_index = inst, 3219 .layout = small.layout, 3220 .status = .none, 3221 .namespace = new_namespace_index, 3222 }); 3223 errdefer mod.destroyUnion(union_index); 3224 3225 const union_ty = try mod.intern_pool.get(gpa, .{ .union_type = .{ 3226 .index = union_index, 3227 .runtime_tag = if (small.has_tag_type or small.auto_enum_tag) 3228 .tagged 3229 else if (small.layout != .Auto) 3230 .none 3231 else switch (block.sema.mod.optimizeMode()) { 3232 .Debug, .ReleaseSafe => .safety, 3233 .ReleaseFast, .ReleaseSmall => .none, 3234 }, 3235 } }); 3236 errdefer mod.intern_pool.remove(union_ty); 3237 3238 new_decl.val = union_ty.toValue(); 3239 new_namespace.ty = union_ty.toType(); 3240 3241 _ = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl); 3242 3243 try new_decl.finalizeNewArena(&new_decl_arena); 3244 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); 3245 try mod.finalizeAnonDecl(new_decl_index); 3246 return decl_val; 3247 } 3248 3249 fn zirOpaqueDecl( 3250 sema: *Sema, 3251 block: *Block, 3252 extended: Zir.Inst.Extended.InstData, 3253 inst: Zir.Inst.Index, 3254 ) CompileError!Air.Inst.Ref { 3255 const tracy = trace(@src()); 3256 defer tracy.end(); 3257 3258 const mod = sema.mod; 3259 const gpa = sema.gpa; 3260 const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small); 3261 var extra_index: usize = extended.operand; 3262 3263 const src: LazySrcLoc = if (small.has_src_node) blk: { 3264 const node_offset = @bitCast(i32, sema.code.extra[extra_index]); 3265 extra_index += 1; 3266 break :blk LazySrcLoc.nodeOffset(node_offset); 3267 } else sema.src; 3268 3269 const decls_len = if (small.has_decls_len) blk: { 3270 const decls_len = sema.code.extra[extra_index]; 3271 extra_index += 1; 3272 break :blk decls_len; 3273 } else 0; 3274 3275 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 3276 errdefer new_decl_arena.deinit(); 3277 3278 // Because these three things each reference each other, `undefined` 3279 // placeholders are used in two places before being set after the opaque 3280 // type gains an InternPool index. 3281 3282 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 3283 .ty = Type.type, 3284 .val = undefined, 3285 }, small.name_strategy, "opaque", inst); 3286 const new_decl = mod.declPtr(new_decl_index); 3287 new_decl.owns_tv = true; 3288 errdefer mod.abortAnonDecl(new_decl_index); 3289 3290 const new_namespace_index = try mod.createNamespace(.{ 3291 .parent = block.namespace.toOptional(), 3292 .ty = undefined, 3293 .file_scope = block.getFileScope(mod), 3294 }); 3295 const new_namespace = mod.namespacePtr(new_namespace_index); 3296 errdefer mod.destroyNamespace(new_namespace_index); 3297 3298 const opaque_ty = try mod.intern(.{ .opaque_type = .{ 3299 .decl = new_decl_index, 3300 .namespace = new_namespace_index, 3301 } }); 3302 errdefer mod.intern_pool.remove(opaque_ty); 3303 3304 new_decl.val = opaque_ty.toValue(); 3305 new_namespace.ty = opaque_ty.toType(); 3306 3307 extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl); 3308 3309 try new_decl.finalizeNewArena(&new_decl_arena); 3310 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); 3311 try mod.finalizeAnonDecl(new_decl_index); 3312 return decl_val; 3313 } 3314 3315 fn zirErrorSetDecl( 3316 sema: *Sema, 3317 block: *Block, 3318 inst: Zir.Inst.Index, 3319 name_strategy: Zir.Inst.NameStrategy, 3320 ) CompileError!Air.Inst.Ref { 3321 const tracy = trace(@src()); 3322 defer tracy.end(); 3323 3324 const mod = sema.mod; 3325 const gpa = sema.gpa; 3326 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 3327 const src = inst_data.src(); 3328 const extra = sema.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index); 3329 3330 var names: Module.Fn.InferredErrorSet.NameMap = .{}; 3331 try names.ensureUnusedCapacity(sema.arena, extra.data.fields_len); 3332 3333 var extra_index = @intCast(u32, extra.end); 3334 const extra_index_end = extra_index + (extra.data.fields_len * 2); 3335 while (extra_index < extra_index_end) : (extra_index += 2) { // +2 to skip over doc_string 3336 const str_index = sema.code.extra[extra_index]; 3337 const name = sema.code.nullTerminatedString(str_index); 3338 const kv = try mod.getErrorValue(name); 3339 const name_ip = try mod.intern_pool.getOrPutString(gpa, kv.key); 3340 const result = names.getOrPutAssumeCapacity(name_ip); 3341 assert(!result.found_existing); // verified in AstGen 3342 } 3343 3344 const error_set_ty = try mod.errorSetFromUnsortedNames(names.keys()); 3345 3346 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 3347 .ty = Type.type, 3348 .val = error_set_ty.toValue(), 3349 }, name_strategy, "error", inst); 3350 const new_decl = mod.declPtr(new_decl_index); 3351 new_decl.owns_tv = true; 3352 errdefer mod.abortAnonDecl(new_decl_index); 3353 3354 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); 3355 try mod.finalizeAnonDecl(new_decl_index); 3356 return decl_val; 3357 } 3358 3359 fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { 3360 const tracy = trace(@src()); 3361 defer tracy.end(); 3362 3363 if (block.is_comptime or try sema.typeRequiresComptime(sema.fn_ret_ty)) { 3364 const fn_ret_ty = try sema.resolveTypeFields(sema.fn_ret_ty); 3365 return sema.analyzeComptimeAlloc(block, fn_ret_ty, 0); 3366 } 3367 3368 const target = sema.mod.getTarget(); 3369 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{ 3370 .pointee_type = sema.fn_ret_ty, 3371 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 3372 }); 3373 3374 if (block.inlining != null) { 3375 // We are inlining a function call; this should be emitted as an alloc, not a ret_ptr. 3376 // TODO when functions gain result location support, the inlining struct in 3377 // Block should contain the return pointer, and we would pass that through here. 3378 return block.addTy(.alloc, ptr_type); 3379 } 3380 3381 return block.addTy(.ret_ptr, ptr_type); 3382 } 3383 3384 fn zirRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3385 const tracy = trace(@src()); 3386 defer tracy.end(); 3387 3388 const inst_data = sema.code.instructions.items(.data)[inst].un_tok; 3389 const operand = try sema.resolveInst(inst_data.operand); 3390 return sema.analyzeRef(block, inst_data.src(), operand); 3391 } 3392 3393 fn zirEnsureResultUsed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 3394 const tracy = trace(@src()); 3395 defer tracy.end(); 3396 3397 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3398 const operand = try sema.resolveInst(inst_data.operand); 3399 const src = inst_data.src(); 3400 3401 return sema.ensureResultUsed(block, sema.typeOf(operand), src); 3402 } 3403 3404 fn ensureResultUsed( 3405 sema: *Sema, 3406 block: *Block, 3407 ty: Type, 3408 src: LazySrcLoc, 3409 ) CompileError!void { 3410 const mod = sema.mod; 3411 switch (ty.zigTypeTag(mod)) { 3412 .Void, .NoReturn => return, 3413 .ErrorSet, .ErrorUnion => { 3414 const msg = msg: { 3415 const msg = try sema.errMsg(block, src, "error is ignored", .{}); 3416 errdefer msg.destroy(sema.gpa); 3417 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); 3418 break :msg msg; 3419 }; 3420 return sema.failWithOwnedErrorMsg(msg); 3421 }, 3422 else => { 3423 const msg = msg: { 3424 const msg = try sema.errMsg(block, src, "value of type '{}' ignored", .{ty.fmt(sema.mod)}); 3425 errdefer msg.destroy(sema.gpa); 3426 try sema.errNote(block, src, msg, "all non-void values must be used", .{}); 3427 try sema.errNote(block, src, msg, "this error can be suppressed by assigning the value to '_'", .{}); 3428 break :msg msg; 3429 }; 3430 return sema.failWithOwnedErrorMsg(msg); 3431 }, 3432 } 3433 } 3434 3435 fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 3436 const tracy = trace(@src()); 3437 defer tracy.end(); 3438 3439 const mod = sema.mod; 3440 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3441 const operand = try sema.resolveInst(inst_data.operand); 3442 const src = inst_data.src(); 3443 const operand_ty = sema.typeOf(operand); 3444 switch (operand_ty.zigTypeTag(mod)) { 3445 .ErrorSet, .ErrorUnion => { 3446 const msg = msg: { 3447 const msg = try sema.errMsg(block, src, "error is discarded", .{}); 3448 errdefer msg.destroy(sema.gpa); 3449 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); 3450 break :msg msg; 3451 }; 3452 return sema.failWithOwnedErrorMsg(msg); 3453 }, 3454 else => return, 3455 } 3456 } 3457 3458 fn zirEnsureErrUnionPayloadVoid(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 3459 const tracy = trace(@src()); 3460 defer tracy.end(); 3461 3462 const mod = sema.mod; 3463 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3464 const src = inst_data.src(); 3465 const operand = try sema.resolveInst(inst_data.operand); 3466 const operand_ty = sema.typeOf(operand); 3467 const err_union_ty = if (operand_ty.zigTypeTag(mod) == .Pointer) 3468 operand_ty.childType(mod) 3469 else 3470 operand_ty; 3471 if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) return; 3472 const payload_ty = err_union_ty.errorUnionPayload(mod).zigTypeTag(mod); 3473 if (payload_ty != .Void and payload_ty != .NoReturn) { 3474 const msg = msg: { 3475 const msg = try sema.errMsg(block, src, "error union payload is ignored", .{}); 3476 errdefer msg.destroy(sema.gpa); 3477 try sema.errNote(block, src, msg, "payload value can be explicitly ignored with '|_|'", .{}); 3478 break :msg msg; 3479 }; 3480 return sema.failWithOwnedErrorMsg(msg); 3481 } 3482 } 3483 3484 fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3485 const tracy = trace(@src()); 3486 defer tracy.end(); 3487 3488 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3489 const src = inst_data.src(); 3490 const object = try sema.resolveInst(inst_data.operand); 3491 3492 return indexablePtrLen(sema, block, src, object); 3493 } 3494 3495 fn indexablePtrLen( 3496 sema: *Sema, 3497 block: *Block, 3498 src: LazySrcLoc, 3499 object: Air.Inst.Ref, 3500 ) CompileError!Air.Inst.Ref { 3501 const mod = sema.mod; 3502 const object_ty = sema.typeOf(object); 3503 const is_pointer_to = object_ty.isSinglePointer(mod); 3504 const indexable_ty = if (is_pointer_to) object_ty.childType(mod) else object_ty; 3505 try checkIndexable(sema, block, src, indexable_ty); 3506 return sema.fieldVal(block, src, object, "len", src); 3507 } 3508 3509 fn indexablePtrLenOrNone( 3510 sema: *Sema, 3511 block: *Block, 3512 src: LazySrcLoc, 3513 operand: Air.Inst.Ref, 3514 ) CompileError!Air.Inst.Ref { 3515 const mod = sema.mod; 3516 const operand_ty = sema.typeOf(operand); 3517 try checkMemOperand(sema, block, src, operand_ty); 3518 if (operand_ty.ptrSize(mod) == .Many) return .none; 3519 return sema.fieldVal(block, src, operand, "len", src); 3520 } 3521 3522 fn zirAllocExtended( 3523 sema: *Sema, 3524 block: *Block, 3525 extended: Zir.Inst.Extended.InstData, 3526 ) CompileError!Air.Inst.Ref { 3527 const gpa = sema.gpa; 3528 const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand); 3529 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = extra.data.src_node }; 3530 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = extra.data.src_node }; 3531 const small = @bitCast(Zir.Inst.AllocExtended.Small, extended.small); 3532 3533 var extra_index: usize = extra.end; 3534 3535 const var_ty: Type = if (small.has_type) blk: { 3536 const type_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 3537 extra_index += 1; 3538 break :blk try sema.resolveType(block, ty_src, type_ref); 3539 } else undefined; 3540 3541 const alignment: u32 = if (small.has_align) blk: { 3542 const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 3543 extra_index += 1; 3544 const alignment = try sema.resolveAlign(block, align_src, align_ref); 3545 break :blk alignment; 3546 } else 0; 3547 3548 if (block.is_comptime or small.is_comptime) { 3549 if (small.has_type) { 3550 return sema.analyzeComptimeAlloc(block, var_ty, alignment); 3551 } else { 3552 try sema.air_instructions.append(gpa, .{ 3553 .tag = .inferred_alloc_comptime, 3554 .data = .{ .inferred_alloc_comptime = .{ 3555 .decl_index = undefined, 3556 .alignment = InternPool.Alignment.fromByteUnits(alignment), 3557 .is_const = small.is_const, 3558 } }, 3559 }); 3560 return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); 3561 } 3562 } 3563 3564 if (small.has_type) { 3565 if (!small.is_const) { 3566 try sema.validateVarType(block, ty_src, var_ty, false); 3567 } 3568 const target = sema.mod.getTarget(); 3569 try sema.resolveTypeLayout(var_ty); 3570 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{ 3571 .pointee_type = var_ty, 3572 .@"align" = alignment, 3573 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 3574 }); 3575 return block.addTy(.alloc, ptr_type); 3576 } 3577 3578 const result_index = try block.addInstAsIndex(.{ 3579 .tag = .inferred_alloc, 3580 .data = .{ .inferred_alloc = .{ 3581 .alignment = InternPool.Alignment.fromByteUnits(alignment), 3582 .is_const = small.is_const, 3583 } }, 3584 }); 3585 try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{}); 3586 return Air.indexToRef(result_index); 3587 } 3588 3589 fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3590 const tracy = trace(@src()); 3591 defer tracy.end(); 3592 3593 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3594 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; 3595 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); 3596 return sema.analyzeComptimeAlloc(block, var_ty, 0); 3597 } 3598 3599 fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3600 const mod = sema.mod; 3601 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3602 const alloc = try sema.resolveInst(inst_data.operand); 3603 const alloc_ty = sema.typeOf(alloc); 3604 3605 var ptr_info = alloc_ty.ptrInfo(mod); 3606 const elem_ty = ptr_info.pointee_type; 3607 3608 // Detect if all stores to an `.alloc` were comptime-known. 3609 ct: { 3610 var search_index: usize = block.instructions.items.len; 3611 const air_tags = sema.air_instructions.items(.tag); 3612 const air_datas = sema.air_instructions.items(.data); 3613 3614 const store_inst = while (true) { 3615 if (search_index == 0) break :ct; 3616 search_index -= 1; 3617 3618 const candidate = block.instructions.items[search_index]; 3619 switch (air_tags[candidate]) { 3620 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue, 3621 .store, .store_safe => break candidate, 3622 else => break :ct, 3623 } 3624 }; 3625 3626 while (true) { 3627 if (search_index == 0) break :ct; 3628 search_index -= 1; 3629 3630 const candidate = block.instructions.items[search_index]; 3631 switch (air_tags[candidate]) { 3632 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue, 3633 .alloc => { 3634 if (Air.indexToRef(candidate) != alloc) break :ct; 3635 break; 3636 }, 3637 else => break :ct, 3638 } 3639 } 3640 3641 const store_op = air_datas[store_inst].bin_op; 3642 const store_val = (try sema.resolveMaybeUndefVal(store_op.rhs)) orelse break :ct; 3643 if (store_op.lhs != alloc) break :ct; 3644 3645 // Remove all the unnecessary runtime instructions. 3646 block.instructions.shrinkRetainingCapacity(search_index); 3647 3648 var anon_decl = try block.startAnonDecl(); 3649 defer anon_decl.deinit(); 3650 return sema.analyzeDeclRef(try anon_decl.finish( 3651 elem_ty, 3652 try store_val.copy(anon_decl.arena()), 3653 ptr_info.@"align", 3654 )); 3655 } 3656 3657 return sema.makePtrConst(block, alloc); 3658 } 3659 3660 fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Air.Inst.Ref { 3661 const mod = sema.mod; 3662 const alloc_ty = sema.typeOf(alloc); 3663 3664 var ptr_info = alloc_ty.ptrInfo(mod); 3665 ptr_info.mutable = false; 3666 const const_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); 3667 3668 // Detect if a comptime value simply needs to have its type changed. 3669 if (try sema.resolveMaybeUndefVal(alloc)) |val| { 3670 return sema.addConstant(const_ptr_ty, try mod.getCoerced(val, const_ptr_ty)); 3671 } 3672 3673 return block.addBitCast(const_ptr_ty, alloc); 3674 } 3675 3676 fn zirAllocInferredComptime( 3677 sema: *Sema, 3678 inst: Zir.Inst.Index, 3679 is_const: bool, 3680 ) CompileError!Air.Inst.Ref { 3681 const gpa = sema.gpa; 3682 const src_node = sema.code.instructions.items(.data)[inst].node; 3683 const src = LazySrcLoc.nodeOffset(src_node); 3684 sema.src = src; 3685 3686 try sema.air_instructions.append(gpa, .{ 3687 .tag = .inferred_alloc_comptime, 3688 .data = .{ .inferred_alloc_comptime = .{ 3689 .decl_index = undefined, 3690 .alignment = .none, 3691 .is_const = is_const, 3692 } }, 3693 }); 3694 return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); 3695 } 3696 3697 fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3698 const tracy = trace(@src()); 3699 defer tracy.end(); 3700 3701 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3702 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; 3703 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); 3704 if (block.is_comptime) { 3705 return sema.analyzeComptimeAlloc(block, var_ty, 0); 3706 } 3707 const target = sema.mod.getTarget(); 3708 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{ 3709 .pointee_type = var_ty, 3710 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 3711 }); 3712 try sema.queueFullTypeResolution(var_ty); 3713 return block.addTy(.alloc, ptr_type); 3714 } 3715 3716 fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3717 const tracy = trace(@src()); 3718 defer tracy.end(); 3719 3720 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3721 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; 3722 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); 3723 if (block.is_comptime) { 3724 return sema.analyzeComptimeAlloc(block, var_ty, 0); 3725 } 3726 try sema.validateVarType(block, ty_src, var_ty, false); 3727 const target = sema.mod.getTarget(); 3728 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{ 3729 .pointee_type = var_ty, 3730 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 3731 }); 3732 try sema.queueFullTypeResolution(var_ty); 3733 return block.addTy(.alloc, ptr_type); 3734 } 3735 3736 fn zirAllocInferred( 3737 sema: *Sema, 3738 block: *Block, 3739 inst: Zir.Inst.Index, 3740 is_const: bool, 3741 ) CompileError!Air.Inst.Ref { 3742 const tracy = trace(@src()); 3743 defer tracy.end(); 3744 3745 const gpa = sema.gpa; 3746 const src_node = sema.code.instructions.items(.data)[inst].node; 3747 const src = LazySrcLoc.nodeOffset(src_node); 3748 sema.src = src; 3749 3750 if (block.is_comptime) { 3751 try sema.air_instructions.append(gpa, .{ 3752 .tag = .inferred_alloc_comptime, 3753 .data = .{ .inferred_alloc_comptime = .{ 3754 .decl_index = undefined, 3755 .alignment = .none, 3756 .is_const = is_const, 3757 } }, 3758 }); 3759 return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); 3760 } 3761 3762 const result_index = try block.addInstAsIndex(.{ 3763 .tag = .inferred_alloc, 3764 .data = .{ .inferred_alloc = .{ 3765 .alignment = .none, 3766 .is_const = is_const, 3767 } }, 3768 }); 3769 try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{}); 3770 return Air.indexToRef(result_index); 3771 } 3772 3773 fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 3774 const tracy = trace(@src()); 3775 defer tracy.end(); 3776 3777 const mod = sema.mod; 3778 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3779 const src = inst_data.src(); 3780 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; 3781 const ptr = try sema.resolveInst(inst_data.operand); 3782 const ptr_inst = Air.refToIndex(ptr).?; 3783 const target = mod.getTarget(); 3784 3785 switch (sema.air_instructions.items(.tag)[ptr_inst]) { 3786 .inferred_alloc_comptime => { 3787 const iac = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime; 3788 const decl_index = iac.decl_index; 3789 try mod.declareDeclDependency(sema.owner_decl_index, decl_index); 3790 3791 const decl = mod.declPtr(decl_index); 3792 if (iac.is_const) try decl.intern(mod); 3793 const final_elem_ty = decl.ty; 3794 const final_ptr_ty = try mod.ptrType(.{ 3795 .child = final_elem_ty.toIntern(), 3796 .flags = .{ 3797 .is_const = false, 3798 .alignment = iac.alignment, 3799 .address_space = target_util.defaultAddressSpace(target, .local), 3800 }, 3801 }); 3802 3803 try sema.maybeQueueFuncBodyAnalysis(decl_index); 3804 // Change it to an interned. 3805 sema.air_instructions.set(ptr_inst, .{ 3806 .tag = .interned, 3807 .data = .{ .interned = try mod.intern(.{ .ptr = .{ 3808 .ty = final_ptr_ty.toIntern(), 3809 .addr = if (!iac.is_const) .{ .mut_decl = .{ 3810 .decl = decl_index, 3811 .runtime_index = block.runtime_index, 3812 } } else .{ .decl = decl_index }, 3813 } }) }, 3814 }); 3815 }, 3816 .inferred_alloc => { 3817 const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc; 3818 const ia2 = sema.unresolved_inferred_allocs.fetchRemove(ptr_inst).?.value; 3819 const peer_inst_list = ia2.prongs.items(.stored_inst); 3820 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none); 3821 3822 const final_ptr_ty = try mod.ptrType(.{ 3823 .child = final_elem_ty.toIntern(), 3824 .flags = .{ 3825 .alignment = ia1.alignment, 3826 .address_space = target_util.defaultAddressSpace(target, .local), 3827 }, 3828 }); 3829 3830 if (!ia1.is_const) { 3831 try sema.validateVarType(block, ty_src, final_elem_ty, false); 3832 } else ct: { 3833 // Detect if the value is comptime-known. In such case, the 3834 // last 3 AIR instructions of the block will look like this: 3835 // 3836 // %a = inferred_alloc 3837 // %b = bitcast(%a) 3838 // %c = store(%b, %d) 3839 // 3840 // If `%d` is comptime-known, then we want to store the value 3841 // inside an anonymous Decl and then erase these three AIR 3842 // instructions from the block, replacing the inst_map entry 3843 // corresponding to the ZIR alloc instruction with a constant 3844 // decl_ref pointing at our new Decl. 3845 // dbg_stmt instructions may be interspersed into this pattern 3846 // which must be ignored. 3847 if (block.instructions.items.len < 3) break :ct; 3848 var search_index: usize = block.instructions.items.len; 3849 const air_tags = sema.air_instructions.items(.tag); 3850 const air_datas = sema.air_instructions.items(.data); 3851 3852 const store_inst = while (true) { 3853 if (search_index == 0) break :ct; 3854 search_index -= 1; 3855 3856 const candidate = block.instructions.items[search_index]; 3857 switch (air_tags[candidate]) { 3858 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue, 3859 .store, .store_safe => break candidate, 3860 else => break :ct, 3861 } 3862 }; 3863 3864 const bitcast_inst = while (true) { 3865 if (search_index == 0) break :ct; 3866 search_index -= 1; 3867 3868 const candidate = block.instructions.items[search_index]; 3869 switch (air_tags[candidate]) { 3870 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue, 3871 .bitcast => break candidate, 3872 else => break :ct, 3873 } 3874 }; 3875 3876 while (true) { 3877 if (search_index == 0) break :ct; 3878 search_index -= 1; 3879 3880 const candidate = block.instructions.items[search_index]; 3881 if (candidate == ptr_inst) break; 3882 switch (air_tags[candidate]) { 3883 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue, 3884 else => break :ct, 3885 } 3886 } 3887 3888 const store_op = air_datas[store_inst].bin_op; 3889 const store_val = (try sema.resolveMaybeUndefVal(store_op.rhs)) orelse break :ct; 3890 if (store_op.lhs != Air.indexToRef(bitcast_inst)) break :ct; 3891 if (air_datas[bitcast_inst].ty_op.operand != ptr) break :ct; 3892 3893 const new_decl_index = d: { 3894 var anon_decl = try block.startAnonDecl(); 3895 defer anon_decl.deinit(); 3896 const new_decl_index = try anon_decl.finish( 3897 final_elem_ty, 3898 try store_val.copy(anon_decl.arena()), 3899 ia1.alignment.toByteUnits(0), 3900 ); 3901 break :d new_decl_index; 3902 }; 3903 try mod.declareDeclDependency(sema.owner_decl_index, new_decl_index); 3904 3905 // Even though we reuse the constant instruction, we still remove it from the 3906 // block so that codegen does not see it. 3907 block.instructions.shrinkRetainingCapacity(search_index); 3908 try sema.maybeQueueFuncBodyAnalysis(new_decl_index); 3909 sema.air_instructions.set(ptr_inst, .{ 3910 .tag = .interned, 3911 .data = .{ .interned = try mod.intern(.{ .ptr = .{ 3912 .ty = final_ptr_ty.toIntern(), 3913 .addr = .{ .decl = new_decl_index }, 3914 } }) }, 3915 }); 3916 3917 // Unless the block is comptime, `alloc_inferred` always produces 3918 // a runtime constant. The final inferred type needs to be 3919 // fully resolved so it can be lowered in codegen. 3920 try sema.resolveTypeFully(final_elem_ty); 3921 3922 return; 3923 } 3924 3925 try sema.queueFullTypeResolution(final_elem_ty); 3926 3927 // Change it to a normal alloc. 3928 sema.air_instructions.set(ptr_inst, .{ 3929 .tag = .alloc, 3930 .data = .{ .ty = final_ptr_ty }, 3931 }); 3932 3933 // Now we need to go back over all the coerce_result_ptr instructions, which 3934 // previously inserted a bitcast as a placeholder, and do the logic as if 3935 // the new result ptr type was available. 3936 const placeholders = ia2.prongs.items(.placeholder); 3937 const gpa = sema.gpa; 3938 3939 var trash_block = block.makeSubBlock(); 3940 trash_block.is_comptime = false; 3941 defer trash_block.instructions.deinit(gpa); 3942 3943 const mut_final_ptr_ty = try mod.ptrType(.{ 3944 .child = final_elem_ty.toIntern(), 3945 .flags = .{ 3946 .alignment = ia1.alignment, 3947 .address_space = target_util.defaultAddressSpace(target, .local), 3948 }, 3949 }); 3950 const dummy_ptr = try trash_block.addTy(.alloc, mut_final_ptr_ty); 3951 const empty_trash_count = trash_block.instructions.items.len; 3952 3953 for (peer_inst_list, placeholders) |peer_inst, placeholder_inst| { 3954 const sub_ptr_ty = sema.typeOf(Air.indexToRef(placeholder_inst)); 3955 3956 if (mut_final_ptr_ty.eql(sub_ptr_ty, mod)) { 3957 // New result location type is the same as the old one; nothing 3958 // to do here. 3959 continue; 3960 } 3961 3962 var replacement_block = block.makeSubBlock(); 3963 defer replacement_block.instructions.deinit(gpa); 3964 3965 const result = switch (sema.air_instructions.items(.tag)[placeholder_inst]) { 3966 .bitcast => result: { 3967 trash_block.instructions.shrinkRetainingCapacity(empty_trash_count); 3968 const sub_ptr = try sema.coerceResultPtr(&replacement_block, src, ptr, dummy_ptr, peer_inst, &trash_block); 3969 3970 assert(replacement_block.instructions.items.len > 0); 3971 break :result sub_ptr; 3972 }, 3973 .store, .store_safe => result: { 3974 const bin_op = sema.air_instructions.items(.data)[placeholder_inst].bin_op; 3975 try sema.storePtr2(&replacement_block, src, bin_op.lhs, src, bin_op.rhs, src, .bitcast); 3976 break :result .void_value; 3977 }, 3978 else => unreachable, 3979 }; 3980 3981 // If only one instruction is produced then we can replace the bitcast 3982 // placeholder instruction with this instruction; no need for an entire block. 3983 if (replacement_block.instructions.items.len == 1) { 3984 const only_inst = replacement_block.instructions.items[0]; 3985 sema.air_instructions.set(placeholder_inst, sema.air_instructions.get(only_inst)); 3986 continue; 3987 } 3988 3989 // Here we replace the placeholder bitcast instruction with a block 3990 // that does the coerce_result_ptr logic. 3991 _ = try replacement_block.addBr(placeholder_inst, result); 3992 const ty_inst = if (result == .void_value) 3993 .void_type 3994 else 3995 sema.air_instructions.items(.data)[placeholder_inst].ty_op.ty; 3996 try sema.air_extra.ensureUnusedCapacity( 3997 gpa, 3998 @typeInfo(Air.Block).Struct.fields.len + replacement_block.instructions.items.len, 3999 ); 4000 sema.air_instructions.set(placeholder_inst, .{ 4001 .tag = .block, 4002 .data = .{ .ty_pl = .{ 4003 .ty = ty_inst, 4004 .payload = sema.addExtraAssumeCapacity(Air.Block{ 4005 .body_len = @intCast(u32, replacement_block.instructions.items.len), 4006 }), 4007 } }, 4008 }); 4009 sema.air_extra.appendSliceAssumeCapacity(replacement_block.instructions.items); 4010 } 4011 }, 4012 else => unreachable, 4013 } 4014 } 4015 4016 fn zirArrayBasePtr( 4017 sema: *Sema, 4018 block: *Block, 4019 inst: Zir.Inst.Index, 4020 ) CompileError!Air.Inst.Ref { 4021 const mod = sema.mod; 4022 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 4023 const src = inst_data.src(); 4024 4025 const start_ptr = try sema.resolveInst(inst_data.operand); 4026 var base_ptr = start_ptr; 4027 while (true) switch (sema.typeOf(base_ptr).childType(mod).zigTypeTag(mod)) { 4028 .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), 4029 .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true), 4030 else => break, 4031 }; 4032 4033 const elem_ty = sema.typeOf(base_ptr).childType(mod); 4034 switch (elem_ty.zigTypeTag(mod)) { 4035 .Array, .Vector => return base_ptr, 4036 .Struct => if (elem_ty.isTuple(mod)) { 4037 // TODO validate element count 4038 return base_ptr; 4039 }, 4040 else => {}, 4041 } 4042 return sema.failWithArrayInitNotSupported(block, src, sema.typeOf(start_ptr).childType(mod)); 4043 } 4044 4045 fn zirFieldBasePtr( 4046 sema: *Sema, 4047 block: *Block, 4048 inst: Zir.Inst.Index, 4049 ) CompileError!Air.Inst.Ref { 4050 const mod = sema.mod; 4051 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 4052 const src = inst_data.src(); 4053 4054 const start_ptr = try sema.resolveInst(inst_data.operand); 4055 var base_ptr = start_ptr; 4056 while (true) switch (sema.typeOf(base_ptr).childType(mod).zigTypeTag(mod)) { 4057 .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), 4058 .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true), 4059 else => break, 4060 }; 4061 4062 const elem_ty = sema.typeOf(base_ptr).childType(mod); 4063 switch (elem_ty.zigTypeTag(mod)) { 4064 .Struct, .Union => return base_ptr, 4065 else => {}, 4066 } 4067 return sema.failWithStructInitNotSupported(block, src, sema.typeOf(start_ptr).childType(mod)); 4068 } 4069 4070 fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4071 const mod = sema.mod; 4072 const gpa = sema.gpa; 4073 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 4074 const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); 4075 const args = sema.code.refSlice(extra.end, extra.data.operands_len); 4076 const src = inst_data.src(); 4077 4078 var len: Air.Inst.Ref = .none; 4079 var len_val: ?Value = null; 4080 var len_idx: u32 = undefined; 4081 var any_runtime = false; 4082 4083 const runtime_arg_lens = try gpa.alloc(Air.Inst.Ref, args.len); 4084 defer gpa.free(runtime_arg_lens); 4085 4086 // First pass to look for comptime values. 4087 for (args, 0..) |zir_arg, i_usize| { 4088 const i = @intCast(u32, i_usize); 4089 runtime_arg_lens[i] = .none; 4090 if (zir_arg == .none) continue; 4091 const object = try sema.resolveInst(zir_arg); 4092 const object_ty = sema.typeOf(object); 4093 // Each arg could be an indexable, or a range, in which case the length 4094 // is passed directly as an integer. 4095 const is_int = switch (object_ty.zigTypeTag(mod)) { 4096 .Int, .ComptimeInt => true, 4097 else => false, 4098 }; 4099 const arg_src: LazySrcLoc = .{ .for_input = .{ 4100 .for_node_offset = inst_data.src_node, 4101 .input_index = i, 4102 } }; 4103 const arg_len_uncoerced = if (is_int) object else l: { 4104 if (!object_ty.isIndexable(mod)) { 4105 // Instead of using checkIndexable we customize this error. 4106 const msg = msg: { 4107 const msg = try sema.errMsg(block, arg_src, "type '{}' is not indexable and not a range", .{object_ty.fmt(sema.mod)}); 4108 errdefer msg.destroy(sema.gpa); 4109 try sema.errNote(block, arg_src, msg, "for loop operand must be a range, array, slice, tuple, or vector", .{}); 4110 break :msg msg; 4111 }; 4112 return sema.failWithOwnedErrorMsg(msg); 4113 } 4114 if (!object_ty.indexableHasLen(mod)) continue; 4115 4116 break :l try sema.fieldVal(block, arg_src, object, "len", arg_src); 4117 }; 4118 const arg_len = try sema.coerce(block, Type.usize, arg_len_uncoerced, arg_src); 4119 if (len == .none) { 4120 len = arg_len; 4121 len_idx = i; 4122 } 4123 if (try sema.resolveDefinedValue(block, src, arg_len)) |arg_val| { 4124 if (len_val) |v| { 4125 if (!(try sema.valuesEqual(arg_val, v, Type.usize))) { 4126 const msg = msg: { 4127 const msg = try sema.errMsg(block, src, "non-matching for loop lengths", .{}); 4128 errdefer msg.destroy(gpa); 4129 const a_src: LazySrcLoc = .{ .for_input = .{ 4130 .for_node_offset = inst_data.src_node, 4131 .input_index = len_idx, 4132 } }; 4133 try sema.errNote(block, a_src, msg, "length {} here", .{ 4134 v.fmtValue(Type.usize, sema.mod), 4135 }); 4136 try sema.errNote(block, arg_src, msg, "length {} here", .{ 4137 arg_val.fmtValue(Type.usize, sema.mod), 4138 }); 4139 break :msg msg; 4140 }; 4141 return sema.failWithOwnedErrorMsg(msg); 4142 } 4143 } else { 4144 len = arg_len; 4145 len_val = arg_val; 4146 len_idx = i; 4147 } 4148 continue; 4149 } 4150 runtime_arg_lens[i] = arg_len; 4151 any_runtime = true; 4152 } 4153 4154 if (len == .none) { 4155 const msg = msg: { 4156 const msg = try sema.errMsg(block, src, "unbounded for loop", .{}); 4157 errdefer msg.destroy(gpa); 4158 for (args, 0..) |zir_arg, i_usize| { 4159 const i = @intCast(u32, i_usize); 4160 if (zir_arg == .none) continue; 4161 const object = try sema.resolveInst(zir_arg); 4162 const object_ty = sema.typeOf(object); 4163 // Each arg could be an indexable, or a range, in which case the length 4164 // is passed directly as an integer. 4165 switch (object_ty.zigTypeTag(mod)) { 4166 .Int, .ComptimeInt => continue, 4167 else => {}, 4168 } 4169 const arg_src: LazySrcLoc = .{ .for_input = .{ 4170 .for_node_offset = inst_data.src_node, 4171 .input_index = i, 4172 } }; 4173 try sema.errNote(block, arg_src, msg, "type '{}' has no upper bound", .{ 4174 object_ty.fmt(sema.mod), 4175 }); 4176 } 4177 break :msg msg; 4178 }; 4179 return sema.failWithOwnedErrorMsg(msg); 4180 } 4181 4182 // Now for the runtime checks. 4183 if (any_runtime and block.wantSafety()) { 4184 for (runtime_arg_lens, 0..) |arg_len, i| { 4185 if (arg_len == .none) continue; 4186 if (i == len_idx) continue; 4187 const ok = try block.addBinOp(.cmp_eq, len, arg_len); 4188 try sema.addSafetyCheck(block, ok, .for_len_mismatch); 4189 } 4190 } 4191 4192 return len; 4193 } 4194 4195 fn validateArrayInitTy( 4196 sema: *Sema, 4197 block: *Block, 4198 inst: Zir.Inst.Index, 4199 ) CompileError!void { 4200 const mod = sema.mod; 4201 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 4202 const src = inst_data.src(); 4203 const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node }; 4204 const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data; 4205 const ty = try sema.resolveType(block, ty_src, extra.ty); 4206 4207 switch (ty.zigTypeTag(mod)) { 4208 .Array => { 4209 const array_len = ty.arrayLen(mod); 4210 if (extra.init_count != array_len) { 4211 return sema.fail(block, src, "expected {d} array elements; found {d}", .{ 4212 array_len, extra.init_count, 4213 }); 4214 } 4215 return; 4216 }, 4217 .Vector => { 4218 const array_len = ty.arrayLen(mod); 4219 if (extra.init_count != array_len) { 4220 return sema.fail(block, src, "expected {d} vector elements; found {d}", .{ 4221 array_len, extra.init_count, 4222 }); 4223 } 4224 return; 4225 }, 4226 .Struct => if (ty.isTuple(mod)) { 4227 _ = try sema.resolveTypeFields(ty); 4228 const array_len = ty.arrayLen(mod); 4229 if (extra.init_count > array_len) { 4230 return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{ 4231 array_len, extra.init_count, 4232 }); 4233 } 4234 return; 4235 }, 4236 else => {}, 4237 } 4238 return sema.failWithArrayInitNotSupported(block, ty_src, ty); 4239 } 4240 4241 fn validateStructInitTy( 4242 sema: *Sema, 4243 block: *Block, 4244 inst: Zir.Inst.Index, 4245 ) CompileError!void { 4246 const mod = sema.mod; 4247 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 4248 const src = inst_data.src(); 4249 const ty = try sema.resolveType(block, src, inst_data.operand); 4250 4251 switch (ty.zigTypeTag(mod)) { 4252 .Struct, .Union => return, 4253 else => {}, 4254 } 4255 return sema.failWithStructInitNotSupported(block, src, ty); 4256 } 4257 4258 fn zirValidateStructInit( 4259 sema: *Sema, 4260 block: *Block, 4261 inst: Zir.Inst.Index, 4262 ) CompileError!void { 4263 const tracy = trace(@src()); 4264 defer tracy.end(); 4265 4266 const mod = sema.mod; 4267 const validate_inst = sema.code.instructions.items(.data)[inst].pl_node; 4268 const init_src = validate_inst.src(); 4269 const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index); 4270 const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len]; 4271 const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; 4272 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; 4273 const object_ptr = try sema.resolveInst(field_ptr_extra.lhs); 4274 const agg_ty = sema.typeOf(object_ptr).childType(mod); 4275 switch (agg_ty.zigTypeTag(mod)) { 4276 .Struct => return sema.validateStructInit( 4277 block, 4278 agg_ty, 4279 init_src, 4280 instrs, 4281 ), 4282 .Union => return sema.validateUnionInit( 4283 block, 4284 agg_ty, 4285 init_src, 4286 instrs, 4287 object_ptr, 4288 ), 4289 else => unreachable, 4290 } 4291 } 4292 4293 fn validateUnionInit( 4294 sema: *Sema, 4295 block: *Block, 4296 union_ty: Type, 4297 init_src: LazySrcLoc, 4298 instrs: []const Zir.Inst.Index, 4299 union_ptr: Air.Inst.Ref, 4300 ) CompileError!void { 4301 const mod = sema.mod; 4302 4303 if (instrs.len != 1) { 4304 const msg = msg: { 4305 const msg = try sema.errMsg( 4306 block, 4307 init_src, 4308 "cannot initialize multiple union fields at once; unions can only have one active field", 4309 .{}, 4310 ); 4311 errdefer msg.destroy(sema.gpa); 4312 4313 for (instrs[1..]) |inst| { 4314 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 4315 const inst_src: LazySrcLoc = .{ .node_offset_initializer = inst_data.src_node }; 4316 try sema.errNote(block, inst_src, msg, "additional initializer here", .{}); 4317 } 4318 try sema.addDeclaredHereNote(msg, union_ty); 4319 break :msg msg; 4320 }; 4321 return sema.failWithOwnedErrorMsg(msg); 4322 } 4323 4324 if (block.is_comptime and 4325 (try sema.resolveDefinedValue(block, init_src, union_ptr)) != null) 4326 { 4327 // In this case, comptime machinery already did everything. No work to do here. 4328 return; 4329 } 4330 4331 const field_ptr = instrs[0]; 4332 const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; 4333 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node }; 4334 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; 4335 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); 4336 // Validate the field access but ignore the index since we want the tag enum field index. 4337 _ = try sema.unionFieldIndex(block, union_ty, field_name, field_src); 4338 const air_tags = sema.air_instructions.items(.tag); 4339 const air_datas = sema.air_instructions.items(.data); 4340 const field_ptr_air_ref = sema.inst_map.get(field_ptr).?; 4341 const field_ptr_air_inst = Air.refToIndex(field_ptr_air_ref).?; 4342 4343 // Our task here is to determine if the union is comptime-known. In such case, 4344 // we erase the runtime AIR instructions for initializing the union, and replace 4345 // the mapping with the comptime value. Either way, we will need to populate the tag. 4346 4347 // We expect to see something like this in the current block AIR: 4348 // %a = alloc(*const U) 4349 // %b = bitcast(*U, %a) 4350 // %c = field_ptr(..., %b) 4351 // %e!= store(%c!, %d!) 4352 // If %d is a comptime operand, the union is comptime. 4353 // If the union is comptime, we want `first_block_index` 4354 // to point at %c so that the bitcast becomes the last instruction in the block. 4355 // 4356 // In the case of a comptime-known pointer to a union, the 4357 // the field_ptr instruction is missing, so we have to pattern-match 4358 // based only on the store instructions. 4359 // `first_block_index` needs to point to the `field_ptr` if it exists; 4360 // the `store` otherwise. 4361 // 4362 // It's also possible for there to be no store instruction, in the case 4363 // of nested `coerce_result_ptr` instructions. If we see the `field_ptr` 4364 // but we have not found a `store`, treat as a runtime-known field. 4365 var first_block_index = block.instructions.items.len; 4366 var block_index = block.instructions.items.len - 1; 4367 var init_val: ?Value = null; 4368 var make_runtime = false; 4369 while (block_index > 0) : (block_index -= 1) { 4370 const store_inst = block.instructions.items[block_index]; 4371 if (store_inst == field_ptr_air_inst) break; 4372 switch (air_tags[store_inst]) { 4373 .store, .store_safe => {}, 4374 else => continue, 4375 } 4376 const bin_op = air_datas[store_inst].bin_op; 4377 var lhs = bin_op.lhs; 4378 if (Air.refToIndex(lhs)) |lhs_index| { 4379 if (air_tags[lhs_index] == .bitcast) { 4380 lhs = air_datas[lhs_index].ty_op.operand; 4381 block_index -= 1; 4382 } 4383 } 4384 if (lhs != field_ptr_air_ref) continue; 4385 while (block_index > 0) : (block_index -= 1) { 4386 const block_inst = block.instructions.items[block_index - 1]; 4387 if (air_tags[block_inst] != .dbg_stmt) break; 4388 } 4389 if (block_index > 0 and 4390 field_ptr_air_inst == block.instructions.items[block_index - 1]) 4391 { 4392 first_block_index = @min(first_block_index, block_index - 1); 4393 } else { 4394 first_block_index = @min(first_block_index, block_index); 4395 } 4396 init_val = try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime); 4397 break; 4398 } 4399 4400 const tag_ty = union_ty.unionTagTypeHypothetical(mod); 4401 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?); 4402 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); 4403 4404 if (init_val) |val| { 4405 // Our task is to delete all the `field_ptr` and `store` instructions, and insert 4406 // instead a single `store` to the result ptr with a comptime union value. 4407 block.instructions.shrinkRetainingCapacity(first_block_index); 4408 4409 var union_val = try mod.intern(.{ .un = .{ 4410 .ty = union_ty.toIntern(), 4411 .tag = tag_val.toIntern(), 4412 .val = val.toIntern(), 4413 } }); 4414 if (make_runtime) union_val = try mod.intern(.{ .runtime_value = .{ 4415 .ty = union_ty.toIntern(), 4416 .val = union_val, 4417 } }); 4418 const union_init = try sema.addConstant(union_ty, union_val.toValue()); 4419 try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store); 4420 return; 4421 } else if (try sema.typeRequiresComptime(union_ty)) { 4422 return sema.failWithNeededComptime(block, field_ptr_data.src(), "initializer of comptime only union must be comptime-known"); 4423 } 4424 4425 const new_tag = try sema.addConstant(tag_ty, tag_val); 4426 _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag); 4427 } 4428 4429 fn validateStructInit( 4430 sema: *Sema, 4431 block: *Block, 4432 struct_ty: Type, 4433 init_src: LazySrcLoc, 4434 instrs: []const Zir.Inst.Index, 4435 ) CompileError!void { 4436 const mod = sema.mod; 4437 const gpa = sema.gpa; 4438 4439 // Maps field index to field_ptr index of where it was already initialized. 4440 const found_fields = try gpa.alloc(Zir.Inst.Index, struct_ty.structFieldCount(mod)); 4441 defer gpa.free(found_fields); 4442 @memset(found_fields, 0); 4443 4444 var struct_ptr_zir_ref: Zir.Inst.Ref = undefined; 4445 4446 for (instrs) |field_ptr| { 4447 const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; 4448 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node }; 4449 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; 4450 struct_ptr_zir_ref = field_ptr_extra.lhs; 4451 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); 4452 const field_index = if (struct_ty.isTuple(mod)) 4453 try sema.tupleFieldIndex(block, struct_ty, field_name, field_src) 4454 else 4455 try sema.structFieldIndex(block, struct_ty, field_name, field_src); 4456 if (found_fields[field_index] != 0) { 4457 const other_field_ptr = found_fields[field_index]; 4458 const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node; 4459 const other_field_src: LazySrcLoc = .{ .node_offset_initializer = other_field_ptr_data.src_node }; 4460 const msg = msg: { 4461 const msg = try sema.errMsg(block, field_src, "duplicate field", .{}); 4462 errdefer msg.destroy(gpa); 4463 try sema.errNote(block, other_field_src, msg, "other field here", .{}); 4464 break :msg msg; 4465 }; 4466 return sema.failWithOwnedErrorMsg(msg); 4467 } 4468 found_fields[field_index] = field_ptr; 4469 } 4470 4471 var root_msg: ?*Module.ErrorMsg = null; 4472 errdefer if (root_msg) |msg| msg.destroy(sema.gpa); 4473 4474 const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref); 4475 if (block.is_comptime and 4476 (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null) 4477 { 4478 try sema.resolveStructLayout(struct_ty); 4479 // In this case the only thing we need to do is evaluate the implicit 4480 // store instructions for default field values, and report any missing fields. 4481 // Avoid the cost of the extra machinery for detecting a comptime struct init value. 4482 for (found_fields, 0..) |field_ptr, i| { 4483 if (field_ptr != 0) continue; 4484 4485 const default_val = struct_ty.structFieldDefaultValue(i, mod); 4486 if (default_val.toIntern() == .unreachable_value) { 4487 if (struct_ty.isTuple(mod)) { 4488 const template = "missing tuple field with index {d}"; 4489 if (root_msg) |msg| { 4490 try sema.errNote(block, init_src, msg, template, .{i}); 4491 } else { 4492 root_msg = try sema.errMsg(block, init_src, template, .{i}); 4493 } 4494 continue; 4495 } 4496 const field_name = struct_ty.structFieldName(i, mod); 4497 const template = "missing struct field: {s}"; 4498 const args = .{field_name}; 4499 if (root_msg) |msg| { 4500 try sema.errNote(block, init_src, msg, template, args); 4501 } else { 4502 root_msg = try sema.errMsg(block, init_src, template, args); 4503 } 4504 continue; 4505 } 4506 4507 const field_src = init_src; // TODO better source location 4508 const default_field_ptr = if (struct_ty.isTuple(mod)) 4509 try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true) 4510 else 4511 try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); 4512 const field_ty = sema.typeOf(default_field_ptr).childType(mod); 4513 const init = try sema.addConstant(field_ty, default_val); 4514 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); 4515 } 4516 4517 if (root_msg) |msg| { 4518 if (mod.typeToStruct(struct_ty)) |struct_obj| { 4519 const fqn = try struct_obj.getFullyQualifiedName(mod); 4520 defer gpa.free(fqn); 4521 try mod.errNoteNonLazy( 4522 struct_obj.srcLoc(mod), 4523 msg, 4524 "struct '{s}' declared here", 4525 .{fqn}, 4526 ); 4527 } 4528 root_msg = null; 4529 return sema.failWithOwnedErrorMsg(msg); 4530 } 4531 4532 return; 4533 } 4534 4535 var struct_is_comptime = true; 4536 var first_block_index = block.instructions.items.len; 4537 var make_runtime = false; 4538 4539 const require_comptime = try sema.typeRequiresComptime(struct_ty); 4540 const air_tags = sema.air_instructions.items(.tag); 4541 const air_datas = sema.air_instructions.items(.data); 4542 4543 // We collect the comptime field values in case the struct initialization 4544 // ends up being comptime-known. 4545 const field_values = try sema.arena.alloc(InternPool.Index, struct_ty.structFieldCount(mod)); 4546 4547 field: for (found_fields, 0..) |field_ptr, i| { 4548 if (field_ptr != 0) { 4549 // Determine whether the value stored to this pointer is comptime-known. 4550 const field_ty = struct_ty.structFieldType(i, mod); 4551 if (try sema.typeHasOnePossibleValue(field_ty)) |opv| { 4552 field_values[i] = opv.toIntern(); 4553 continue; 4554 } 4555 4556 const field_ptr_air_ref = sema.inst_map.get(field_ptr).?; 4557 const field_ptr_air_inst = Air.refToIndex(field_ptr_air_ref).?; 4558 4559 //std.debug.print("validateStructInit (field_ptr_air_inst=%{d}):\n", .{ 4560 // field_ptr_air_inst, 4561 //}); 4562 //for (block.instructions.items) |item| { 4563 // std.debug.print(" %{d} = {s}\n", .{item, @tagName(air_tags[item])}); 4564 //} 4565 4566 // We expect to see something like this in the current block AIR: 4567 // %a = field_ptr(...) 4568 // store(%a, %b) 4569 // With an optional bitcast between the store and the field_ptr. 4570 // If %b is a comptime operand, this field is comptime. 4571 // 4572 // However, in the case of a comptime-known pointer to a struct, the 4573 // the field_ptr instruction is missing, so we have to pattern-match 4574 // based only on the store instructions. 4575 // `first_block_index` needs to point to the `field_ptr` if it exists; 4576 // the `store` otherwise. 4577 // 4578 // It's also possible for there to be no store instruction, in the case 4579 // of nested `coerce_result_ptr` instructions. If we see the `field_ptr` 4580 // but we have not found a `store`, treat as a runtime-known field. 4581 4582 // Possible performance enhancement: save the `block_index` between iterations 4583 // of the for loop. 4584 var block_index = block.instructions.items.len - 1; 4585 while (block_index > 0) : (block_index -= 1) { 4586 const store_inst = block.instructions.items[block_index]; 4587 if (store_inst == field_ptr_air_inst) { 4588 struct_is_comptime = false; 4589 continue :field; 4590 } 4591 switch (air_tags[store_inst]) { 4592 .store, .store_safe => {}, 4593 else => continue, 4594 } 4595 const bin_op = air_datas[store_inst].bin_op; 4596 var lhs = bin_op.lhs; 4597 { 4598 const lhs_index = Air.refToIndex(lhs) orelse continue; 4599 if (air_tags[lhs_index] == .bitcast) { 4600 lhs = air_datas[lhs_index].ty_op.operand; 4601 block_index -= 1; 4602 } 4603 } 4604 if (lhs != field_ptr_air_ref) continue; 4605 while (block_index > 0) : (block_index -= 1) { 4606 const block_inst = block.instructions.items[block_index - 1]; 4607 if (air_tags[block_inst] != .dbg_stmt) break; 4608 } 4609 if (block_index > 0 and 4610 field_ptr_air_inst == block.instructions.items[block_index - 1]) 4611 { 4612 first_block_index = @min(first_block_index, block_index - 1); 4613 } else { 4614 first_block_index = @min(first_block_index, block_index); 4615 } 4616 if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| { 4617 field_values[i] = val.toIntern(); 4618 } else if (require_comptime) { 4619 const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; 4620 return sema.failWithNeededComptime(block, field_ptr_data.src(), "initializer of comptime only struct must be comptime-known"); 4621 } else { 4622 struct_is_comptime = false; 4623 } 4624 continue :field; 4625 } 4626 struct_is_comptime = false; 4627 continue :field; 4628 } 4629 4630 const default_val = struct_ty.structFieldDefaultValue(i, mod); 4631 if (default_val.toIntern() == .unreachable_value) { 4632 if (struct_ty.isTuple(mod)) { 4633 const template = "missing tuple field with index {d}"; 4634 if (root_msg) |msg| { 4635 try sema.errNote(block, init_src, msg, template, .{i}); 4636 } else { 4637 root_msg = try sema.errMsg(block, init_src, template, .{i}); 4638 } 4639 continue; 4640 } 4641 const field_name = struct_ty.structFieldName(i, mod); 4642 const template = "missing struct field: {s}"; 4643 const args = .{field_name}; 4644 if (root_msg) |msg| { 4645 try sema.errNote(block, init_src, msg, template, args); 4646 } else { 4647 root_msg = try sema.errMsg(block, init_src, template, args); 4648 } 4649 continue; 4650 } 4651 field_values[i] = default_val.toIntern(); 4652 } 4653 4654 if (root_msg) |msg| { 4655 if (mod.typeToStruct(struct_ty)) |struct_obj| { 4656 const fqn = try struct_obj.getFullyQualifiedName(sema.mod); 4657 defer gpa.free(fqn); 4658 try sema.mod.errNoteNonLazy( 4659 struct_obj.srcLoc(sema.mod), 4660 msg, 4661 "struct '{s}' declared here", 4662 .{fqn}, 4663 ); 4664 } 4665 root_msg = null; 4666 return sema.failWithOwnedErrorMsg(msg); 4667 } 4668 4669 if (struct_is_comptime) { 4670 // Our task is to delete all the `field_ptr` and `store` instructions, and insert 4671 // instead a single `store` to the struct_ptr with a comptime struct value. 4672 4673 block.instructions.shrinkRetainingCapacity(first_block_index); 4674 var struct_val = try mod.intern(.{ .aggregate = .{ 4675 .ty = struct_ty.toIntern(), 4676 .storage = .{ .elems = field_values }, 4677 } }); 4678 if (make_runtime) struct_val = try mod.intern(.{ .runtime_value = .{ 4679 .ty = struct_ty.toIntern(), 4680 .val = struct_val, 4681 } }); 4682 const struct_init = try sema.addConstant(struct_ty, struct_val.toValue()); 4683 try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store); 4684 return; 4685 } 4686 try sema.resolveStructLayout(struct_ty); 4687 4688 // Our task is to insert `store` instructions for all the default field values. 4689 for (found_fields, 0..) |field_ptr, i| { 4690 if (field_ptr != 0) continue; 4691 4692 const field_src = init_src; // TODO better source location 4693 const default_field_ptr = if (struct_ty.isTuple(mod)) 4694 try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true) 4695 else 4696 try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); 4697 const field_ty = sema.typeOf(default_field_ptr).childType(mod); 4698 const init = try sema.addConstant(field_ty, field_values[i].toValue()); 4699 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); 4700 } 4701 } 4702 4703 fn zirValidateArrayInit( 4704 sema: *Sema, 4705 block: *Block, 4706 inst: Zir.Inst.Index, 4707 ) CompileError!void { 4708 const mod = sema.mod; 4709 const validate_inst = sema.code.instructions.items(.data)[inst].pl_node; 4710 const init_src = validate_inst.src(); 4711 const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index); 4712 const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len]; 4713 const first_elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; 4714 const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data; 4715 const array_ptr = try sema.resolveInst(elem_ptr_extra.ptr); 4716 const array_ty = sema.typeOf(array_ptr).childType(mod); 4717 const array_len = array_ty.arrayLen(mod); 4718 4719 if (instrs.len != array_len) switch (array_ty.zigTypeTag(mod)) { 4720 .Struct => { 4721 var root_msg: ?*Module.ErrorMsg = null; 4722 errdefer if (root_msg) |msg| msg.destroy(sema.gpa); 4723 4724 var i = instrs.len; 4725 while (i < array_len) : (i += 1) { 4726 const default_val = array_ty.structFieldDefaultValue(i, mod); 4727 if (default_val.toIntern() == .unreachable_value) { 4728 const template = "missing tuple field with index {d}"; 4729 if (root_msg) |msg| { 4730 try sema.errNote(block, init_src, msg, template, .{i}); 4731 } else { 4732 root_msg = try sema.errMsg(block, init_src, template, .{i}); 4733 } 4734 } 4735 } 4736 4737 if (root_msg) |msg| { 4738 root_msg = null; 4739 return sema.failWithOwnedErrorMsg(msg); 4740 } 4741 }, 4742 .Array => { 4743 return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{ 4744 array_len, instrs.len, 4745 }); 4746 }, 4747 .Vector => { 4748 return sema.fail(block, init_src, "expected {d} vector elements; found {d}", .{ 4749 array_len, instrs.len, 4750 }); 4751 }, 4752 else => unreachable, 4753 }; 4754 4755 if (block.is_comptime and 4756 (try sema.resolveDefinedValue(block, init_src, array_ptr)) != null) 4757 { 4758 // In this case the comptime machinery will have evaluated the store instructions 4759 // at comptime so we have almost nothing to do here. However, in case of a 4760 // sentinel-terminated array, the sentinel will not have been populated by 4761 // any ZIR instructions at comptime; we need to do that here. 4762 if (array_ty.sentinel(mod)) |sentinel_val| { 4763 const array_len_ref = try sema.addIntUnsigned(Type.usize, array_len); 4764 const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true, true); 4765 const sentinel = try sema.addConstant(array_ty.childType(mod), sentinel_val); 4766 try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store); 4767 } 4768 return; 4769 } 4770 4771 // If the array has one possible value, the value is always comptime-known. 4772 if (try sema.typeHasOnePossibleValue(array_ty)) |array_opv| { 4773 const array_init = try sema.addConstant(array_ty, array_opv); 4774 try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store); 4775 return; 4776 } 4777 4778 var array_is_comptime = true; 4779 var first_block_index = block.instructions.items.len; 4780 var make_runtime = false; 4781 4782 // Collect the comptime element values in case the array literal ends up 4783 // being comptime-known. 4784 const element_vals = try sema.arena.alloc( 4785 InternPool.Index, 4786 try sema.usizeCast(block, init_src, array_len), 4787 ); 4788 const air_tags = sema.air_instructions.items(.tag); 4789 const air_datas = sema.air_instructions.items(.data); 4790 4791 outer: for (instrs, 0..) |elem_ptr, i| { 4792 // Determine whether the value stored to this pointer is comptime-known. 4793 4794 if (array_ty.isTuple(mod)) { 4795 if (try array_ty.structFieldValueComptime(mod, i)) |opv| { 4796 element_vals[i] = opv.toIntern(); 4797 continue; 4798 } 4799 } 4800 4801 const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?; 4802 const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?; 4803 4804 // We expect to see something like this in the current block AIR: 4805 // %a = elem_ptr(...) 4806 // store(%a, %b) 4807 // With an optional bitcast between the store and the elem_ptr. 4808 // If %b is a comptime operand, this element is comptime. 4809 // 4810 // However, in the case of a comptime-known pointer to an array, the 4811 // the elem_ptr instruction is missing, so we have to pattern-match 4812 // based only on the store instructions. 4813 // `first_block_index` needs to point to the `elem_ptr` if it exists; 4814 // the `store` otherwise. 4815 // 4816 // It's also possible for there to be no store instruction, in the case 4817 // of nested `coerce_result_ptr` instructions. If we see the `elem_ptr` 4818 // but we have not found a `store`, treat as a runtime-known element. 4819 // 4820 // This is nearly identical to similar logic in `validateStructInit`. 4821 4822 // Possible performance enhancement: save the `block_index` between iterations 4823 // of the for loop. 4824 var block_index = block.instructions.items.len - 1; 4825 while (block_index > 0) : (block_index -= 1) { 4826 const store_inst = block.instructions.items[block_index]; 4827 if (store_inst == elem_ptr_air_inst) { 4828 array_is_comptime = false; 4829 continue :outer; 4830 } 4831 switch (air_tags[store_inst]) { 4832 .store, .store_safe => {}, 4833 else => continue, 4834 } 4835 const bin_op = air_datas[store_inst].bin_op; 4836 var lhs = bin_op.lhs; 4837 { 4838 const lhs_index = Air.refToIndex(lhs) orelse continue; 4839 if (air_tags[lhs_index] == .bitcast) { 4840 lhs = air_datas[lhs_index].ty_op.operand; 4841 block_index -= 1; 4842 } 4843 } 4844 if (lhs != elem_ptr_air_ref) continue; 4845 while (block_index > 0) : (block_index -= 1) { 4846 const block_inst = block.instructions.items[block_index - 1]; 4847 if (air_tags[block_inst] != .dbg_stmt) break; 4848 } 4849 if (block_index > 0 and 4850 elem_ptr_air_inst == block.instructions.items[block_index - 1]) 4851 { 4852 first_block_index = @min(first_block_index, block_index - 1); 4853 } else { 4854 first_block_index = @min(first_block_index, block_index); 4855 } 4856 if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| { 4857 element_vals[i] = val.toIntern(); 4858 } else { 4859 array_is_comptime = false; 4860 } 4861 continue :outer; 4862 } 4863 array_is_comptime = false; 4864 continue :outer; 4865 } 4866 4867 if (array_is_comptime) { 4868 if (try sema.resolveDefinedValue(block, init_src, array_ptr)) |ptr_val| { 4869 switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) { 4870 .ptr => |ptr| switch (ptr.addr) { 4871 .comptime_field => return, // This store was validated by the individual elem ptrs. 4872 else => {}, 4873 }, 4874 else => {}, 4875 } 4876 } 4877 4878 // Our task is to delete all the `elem_ptr` and `store` instructions, and insert 4879 // instead a single `store` to the array_ptr with a comptime struct value. 4880 block.instructions.shrinkRetainingCapacity(first_block_index); 4881 4882 var array_val = try mod.intern(.{ .aggregate = .{ 4883 .ty = array_ty.toIntern(), 4884 .storage = .{ .elems = element_vals }, 4885 } }); 4886 if (make_runtime) array_val = try mod.intern(.{ .runtime_value = .{ 4887 .ty = array_ty.toIntern(), 4888 .val = array_val, 4889 } }); 4890 const array_init = try sema.addConstant(array_ty, array_val.toValue()); 4891 try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store); 4892 } 4893 } 4894 4895 fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 4896 const mod = sema.mod; 4897 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 4898 const src = inst_data.src(); 4899 const operand = try sema.resolveInst(inst_data.operand); 4900 const operand_ty = sema.typeOf(operand); 4901 4902 if (operand_ty.zigTypeTag(mod) != .Pointer) { 4903 return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(sema.mod)}); 4904 } else switch (operand_ty.ptrSize(mod)) { 4905 .One, .C => {}, 4906 .Many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(sema.mod)}), 4907 .Slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(sema.mod)}), 4908 } 4909 4910 if ((try sema.typeHasOnePossibleValue(operand_ty.childType(mod))) != null) { 4911 // No need to validate the actual pointer value, we don't need it! 4912 return; 4913 } 4914 4915 const elem_ty = operand_ty.elemType2(mod); 4916 if (try sema.resolveMaybeUndefVal(operand)) |val| { 4917 if (val.isUndef(mod)) { 4918 return sema.fail(block, src, "cannot dereference undefined value", .{}); 4919 } 4920 } else if (!(try sema.validateRunTimeType(elem_ty, false))) { 4921 const msg = msg: { 4922 const msg = try sema.errMsg( 4923 block, 4924 src, 4925 "values of type '{}' must be comptime-known, but operand value is runtime-known", 4926 .{elem_ty.fmt(sema.mod)}, 4927 ); 4928 errdefer msg.destroy(sema.gpa); 4929 4930 const src_decl = sema.mod.declPtr(block.src_decl); 4931 try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), elem_ty); 4932 break :msg msg; 4933 }; 4934 return sema.failWithOwnedErrorMsg(msg); 4935 } 4936 } 4937 4938 fn failWithBadMemberAccess( 4939 sema: *Sema, 4940 block: *Block, 4941 agg_ty: Type, 4942 field_src: LazySrcLoc, 4943 field_name: []const u8, 4944 ) CompileError { 4945 const mod = sema.mod; 4946 const kw_name = switch (agg_ty.zigTypeTag(mod)) { 4947 .Union => "union", 4948 .Struct => "struct", 4949 .Opaque => "opaque", 4950 .Enum => "enum", 4951 else => unreachable, 4952 }; 4953 if (agg_ty.getOwnerDeclOrNull(mod)) |some| if (sema.mod.declIsRoot(some)) { 4954 return sema.fail(block, field_src, "root struct of file '{}' has no member named '{s}'", .{ 4955 agg_ty.fmt(sema.mod), field_name, 4956 }); 4957 }; 4958 const msg = msg: { 4959 const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{s}'", .{ 4960 kw_name, agg_ty.fmt(sema.mod), field_name, 4961 }); 4962 errdefer msg.destroy(sema.gpa); 4963 try sema.addDeclaredHereNote(msg, agg_ty); 4964 break :msg msg; 4965 }; 4966 return sema.failWithOwnedErrorMsg(msg); 4967 } 4968 4969 fn failWithBadStructFieldAccess( 4970 sema: *Sema, 4971 block: *Block, 4972 struct_obj: *Module.Struct, 4973 field_src: LazySrcLoc, 4974 field_name: []const u8, 4975 ) CompileError { 4976 const gpa = sema.gpa; 4977 4978 const fqn = try struct_obj.getFullyQualifiedName(sema.mod); 4979 defer gpa.free(fqn); 4980 4981 const msg = msg: { 4982 const msg = try sema.errMsg( 4983 block, 4984 field_src, 4985 "no field named '{s}' in struct '{s}'", 4986 .{ field_name, fqn }, 4987 ); 4988 errdefer msg.destroy(gpa); 4989 try sema.mod.errNoteNonLazy(struct_obj.srcLoc(sema.mod), msg, "struct declared here", .{}); 4990 break :msg msg; 4991 }; 4992 return sema.failWithOwnedErrorMsg(msg); 4993 } 4994 4995 fn failWithBadUnionFieldAccess( 4996 sema: *Sema, 4997 block: *Block, 4998 union_obj: *Module.Union, 4999 field_src: LazySrcLoc, 5000 field_name: []const u8, 5001 ) CompileError { 5002 const gpa = sema.gpa; 5003 5004 const fqn = try union_obj.getFullyQualifiedName(sema.mod); 5005 defer gpa.free(fqn); 5006 5007 const msg = msg: { 5008 const msg = try sema.errMsg( 5009 block, 5010 field_src, 5011 "no field named '{s}' in union '{s}'", 5012 .{ field_name, fqn }, 5013 ); 5014 errdefer msg.destroy(gpa); 5015 try sema.mod.errNoteNonLazy(union_obj.srcLoc(sema.mod), msg, "union declared here", .{}); 5016 break :msg msg; 5017 }; 5018 return sema.failWithOwnedErrorMsg(msg); 5019 } 5020 5021 fn addDeclaredHereNote(sema: *Sema, parent: *Module.ErrorMsg, decl_ty: Type) !void { 5022 const mod = sema.mod; 5023 const src_loc = decl_ty.declSrcLocOrNull(mod) orelse return; 5024 const category = switch (decl_ty.zigTypeTag(mod)) { 5025 .Union => "union", 5026 .Struct => "struct", 5027 .Enum => "enum", 5028 .Opaque => "opaque", 5029 .ErrorSet => "error set", 5030 else => unreachable, 5031 }; 5032 try mod.errNoteNonLazy(src_loc, parent, "{s} declared here", .{category}); 5033 } 5034 5035 fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5036 const tracy = trace(@src()); 5037 defer tracy.end(); 5038 5039 const bin_inst = sema.code.instructions.items(.data)[inst].bin; 5040 const ptr = sema.inst_map.get(Zir.refToIndex(bin_inst.lhs).?) orelse { 5041 // This is an elided instruction, but AstGen was unable to omit it. 5042 return; 5043 }; 5044 const operand = try sema.resolveInst(bin_inst.rhs); 5045 const src: LazySrcLoc = sema.src; 5046 blk: { 5047 const ptr_inst = Air.refToIndex(ptr) orelse break :blk; 5048 switch (sema.air_instructions.items(.tag)[ptr_inst]) { 5049 .inferred_alloc_comptime => { 5050 const iac = &sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime; 5051 return sema.storeToInferredAllocComptime(block, src, operand, iac); 5052 }, 5053 .inferred_alloc => { 5054 const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?; 5055 return sema.storeToInferredAlloc(block, ptr, operand, ia); 5056 }, 5057 else => break :blk, 5058 } 5059 } 5060 5061 return sema.storePtr(block, src, ptr, operand); 5062 } 5063 5064 fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5065 const tracy = trace(@src()); 5066 defer tracy.end(); 5067 5068 const src: LazySrcLoc = sema.src; 5069 const bin_inst = sema.code.instructions.items(.data)[inst].bin; 5070 const ptr = try sema.resolveInst(bin_inst.lhs); 5071 const operand = try sema.resolveInst(bin_inst.rhs); 5072 const ptr_inst = Air.refToIndex(ptr).?; 5073 const air_datas = sema.air_instructions.items(.data); 5074 5075 switch (sema.air_instructions.items(.tag)[ptr_inst]) { 5076 .inferred_alloc_comptime => { 5077 const iac = &air_datas[ptr_inst].inferred_alloc_comptime; 5078 return sema.storeToInferredAllocComptime(block, src, operand, iac); 5079 }, 5080 .inferred_alloc => { 5081 const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?; 5082 return sema.storeToInferredAlloc(block, ptr, operand, ia); 5083 }, 5084 else => unreachable, 5085 } 5086 } 5087 5088 fn storeToInferredAlloc( 5089 sema: *Sema, 5090 block: *Block, 5091 ptr: Air.Inst.Ref, 5092 operand: Air.Inst.Ref, 5093 inferred_alloc: *InferredAlloc, 5094 ) CompileError!void { 5095 // Create a store instruction as a placeholder. This will be replaced by a 5096 // proper store sequence once we know the stored type. 5097 const dummy_store = try block.addBinOp(.store, ptr, operand); 5098 // Add the stored instruction to the set we will use to resolve peer types 5099 // for the inferred allocation. 5100 try inferred_alloc.prongs.append(sema.arena, .{ 5101 .stored_inst = operand, 5102 .placeholder = Air.refToIndex(dummy_store).?, 5103 }); 5104 } 5105 5106 fn storeToInferredAllocComptime( 5107 sema: *Sema, 5108 block: *Block, 5109 src: LazySrcLoc, 5110 operand: Air.Inst.Ref, 5111 iac: *Air.Inst.Data.InferredAllocComptime, 5112 ) CompileError!void { 5113 const operand_ty = sema.typeOf(operand); 5114 // There will be only one store_to_inferred_ptr because we are running at comptime. 5115 // The alloc will turn into a Decl. 5116 if (try sema.resolveMaybeUndefValAllowVariables(operand)) |operand_val| store: { 5117 if (operand_val.getVariable(sema.mod) != null) break :store; 5118 var anon_decl = try block.startAnonDecl(); 5119 defer anon_decl.deinit(); 5120 iac.decl_index = try anon_decl.finish( 5121 operand_ty, 5122 try operand_val.copy(anon_decl.arena()), 5123 iac.alignment.toByteUnits(0), 5124 ); 5125 return; 5126 } 5127 5128 return sema.failWithNeededComptime(block, src, "value being stored to a comptime variable must be comptime-known"); 5129 } 5130 5131 fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5132 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 5133 const src = inst_data.src(); 5134 const quota = @intCast(u32, try sema.resolveInt(block, src, inst_data.operand, Type.u32, "eval branch quota must be comptime-known")); 5135 sema.branch_quota = @max(sema.branch_quota, quota); 5136 } 5137 5138 fn zirStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5139 const tracy = trace(@src()); 5140 defer tracy.end(); 5141 5142 const bin_inst = sema.code.instructions.items(.data)[inst].bin; 5143 const ptr = try sema.resolveInst(bin_inst.lhs); 5144 const value = try sema.resolveInst(bin_inst.rhs); 5145 return sema.storePtr(block, sema.src, ptr, value); 5146 } 5147 5148 fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5149 const tracy = trace(@src()); 5150 defer tracy.end(); 5151 5152 const mod = sema.mod; 5153 const zir_tags = sema.code.instructions.items(.tag); 5154 const zir_datas = sema.code.instructions.items(.data); 5155 const inst_data = zir_datas[inst].pl_node; 5156 const src = inst_data.src(); 5157 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 5158 const ptr = try sema.resolveInst(extra.lhs); 5159 const operand = try sema.resolveInst(extra.rhs); 5160 5161 const is_ret = if (Zir.refToIndex(extra.lhs)) |ptr_index| 5162 zir_tags[ptr_index] == .ret_ptr 5163 else 5164 false; 5165 5166 // Check for the possibility of this pattern: 5167 // %a = ret_ptr 5168 // %b = store(%a, %c) 5169 // Where %c is an error union or error set. In such case we need to add 5170 // to the current function's inferred error set, if any. 5171 if (is_ret and (sema.typeOf(operand).zigTypeTag(mod) == .ErrorUnion or 5172 sema.typeOf(operand).zigTypeTag(mod) == .ErrorSet) and 5173 sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion) 5174 { 5175 try sema.addToInferredErrorSet(operand); 5176 } 5177 5178 const ptr_src: LazySrcLoc = .{ .node_offset_store_ptr = inst_data.src_node }; 5179 const operand_src: LazySrcLoc = .{ .node_offset_store_operand = inst_data.src_node }; 5180 const air_tag: Air.Inst.Tag = if (is_ret) 5181 .ret_ptr 5182 else if (block.wantSafety()) 5183 .store_safe 5184 else 5185 .store; 5186 return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag); 5187 } 5188 5189 fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5190 const tracy = trace(@src()); 5191 defer tracy.end(); 5192 5193 const bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code); 5194 return sema.addStrLit(block, bytes); 5195 } 5196 5197 fn addStrLit(sema: *Sema, block: *Block, bytes: []const u8) CompileError!Air.Inst.Ref { 5198 const mod = sema.mod; 5199 const gpa = sema.gpa; 5200 const ty = try mod.arrayType(.{ 5201 .len = bytes.len, 5202 .child = .u8_type, 5203 .sentinel = .zero_u8, 5204 }); 5205 const val = try mod.intern(.{ .aggregate = .{ 5206 .ty = ty.toIntern(), 5207 .storage = .{ .bytes = bytes }, 5208 } }); 5209 const gop = try mod.memoized_decls.getOrPut(gpa, val); 5210 if (!gop.found_existing) { 5211 const new_decl_index = try mod.createAnonymousDecl(block, .{ 5212 .ty = ty, 5213 .val = val.toValue(), 5214 }); 5215 gop.value_ptr.* = new_decl_index; 5216 try mod.finalizeAnonDecl(new_decl_index); 5217 } 5218 return sema.analyzeDeclRef(gop.value_ptr.*); 5219 } 5220 5221 fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5222 _ = block; 5223 const tracy = trace(@src()); 5224 defer tracy.end(); 5225 5226 const int = sema.code.instructions.items(.data)[inst].int; 5227 return sema.addIntUnsigned(Type.comptime_int, int); 5228 } 5229 5230 fn zirIntBig(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5231 _ = block; 5232 const tracy = trace(@src()); 5233 defer tracy.end(); 5234 5235 const mod = sema.mod; 5236 const int = sema.code.instructions.items(.data)[inst].str; 5237 const byte_count = int.len * @sizeOf(std.math.big.Limb); 5238 const limb_bytes = sema.code.string_bytes[int.start..][0..byte_count]; 5239 5240 // TODO: this allocation and copy is only needed because the limbs may be unaligned. 5241 // If ZIR is adjusted so that big int limbs are guaranteed to be aligned, these 5242 // two lines can be removed. 5243 const limbs = try sema.arena.alloc(std.math.big.Limb, int.len); 5244 @memcpy(mem.sliceAsBytes(limbs), limb_bytes); 5245 5246 return sema.addConstant( 5247 Type.comptime_int, 5248 try mod.intValue_big(Type.comptime_int, .{ 5249 .limbs = limbs, 5250 .positive = true, 5251 }), 5252 ); 5253 } 5254 5255 fn zirFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5256 _ = block; 5257 const number = sema.code.instructions.items(.data)[inst].float; 5258 return sema.addConstant( 5259 Type.comptime_float, 5260 try sema.mod.floatValue(Type.comptime_float, number), 5261 ); 5262 } 5263 5264 fn zirFloat128(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5265 _ = block; 5266 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 5267 const extra = sema.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data; 5268 const number = extra.get(); 5269 return sema.addConstant( 5270 Type.comptime_float, 5271 try sema.mod.floatValue(Type.comptime_float, number), 5272 ); 5273 } 5274 5275 fn zirCompileError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { 5276 const tracy = trace(@src()); 5277 defer tracy.end(); 5278 5279 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 5280 const src = inst_data.src(); 5281 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 5282 const msg = try sema.resolveConstString(block, operand_src, inst_data.operand, "compile error string must be comptime-known"); 5283 return sema.fail(block, src, "{s}", .{msg}); 5284 } 5285 5286 fn zirCompileLog( 5287 sema: *Sema, 5288 extended: Zir.Inst.Extended.InstData, 5289 ) CompileError!Air.Inst.Ref { 5290 var managed = sema.mod.compile_log_text.toManaged(sema.gpa); 5291 defer sema.mod.compile_log_text = managed.moveToUnmanaged(); 5292 const writer = managed.writer(); 5293 5294 const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand); 5295 const src_node = extra.data.src_node; 5296 const args = sema.code.refSlice(extra.end, extended.small); 5297 5298 for (args, 0..) |arg_ref, i| { 5299 if (i != 0) try writer.print(", ", .{}); 5300 5301 const arg = try sema.resolveInst(arg_ref); 5302 const arg_ty = sema.typeOf(arg); 5303 if (try sema.resolveMaybeUndefLazyVal(arg)) |val| { 5304 try writer.print("@as({}, {})", .{ 5305 arg_ty.fmt(sema.mod), val.fmtValue(arg_ty, sema.mod), 5306 }); 5307 } else { 5308 try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(sema.mod)}); 5309 } 5310 } 5311 try writer.print("\n", .{}); 5312 5313 const decl_index = if (sema.func) |some| some.owner_decl else sema.owner_decl_index; 5314 const gop = try sema.mod.compile_log_decls.getOrPut(sema.gpa, decl_index); 5315 if (!gop.found_existing) { 5316 gop.value_ptr.* = src_node; 5317 } 5318 return Air.Inst.Ref.void_value; 5319 } 5320 5321 fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { 5322 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 5323 const src = inst_data.src(); 5324 const msg_inst = try sema.resolveInst(inst_data.operand); 5325 5326 if (block.is_comptime) { 5327 return sema.fail(block, src, "encountered @panic at comptime", .{}); 5328 } 5329 try sema.panicWithMsg(block, msg_inst); 5330 return always_noreturn; 5331 } 5332 5333 fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { 5334 const src_node = sema.code.instructions.items(.data)[inst].node; 5335 const src = LazySrcLoc.nodeOffset(src_node); 5336 sema.src = src; 5337 _ = try block.addNoOp(.trap); 5338 return always_noreturn; 5339 } 5340 5341 fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5342 const tracy = trace(@src()); 5343 defer tracy.end(); 5344 5345 const mod = sema.mod; 5346 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 5347 const src = inst_data.src(); 5348 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); 5349 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 5350 const gpa = sema.gpa; 5351 5352 // AIR expects a block outside the loop block too. 5353 // Reserve space for a Loop instruction so that generated Break instructions can 5354 // point to it, even if it doesn't end up getting used because the code ends up being 5355 // comptime evaluated. 5356 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 5357 const loop_inst = block_inst + 1; 5358 try sema.air_instructions.ensureUnusedCapacity(gpa, 2); 5359 sema.air_instructions.appendAssumeCapacity(.{ 5360 .tag = .block, 5361 .data = undefined, 5362 }); 5363 sema.air_instructions.appendAssumeCapacity(.{ 5364 .tag = .loop, 5365 .data = .{ .ty_pl = .{ 5366 .ty = .noreturn_type, 5367 .payload = undefined, 5368 } }, 5369 }); 5370 var label: Block.Label = .{ 5371 .zir_block = inst, 5372 .merges = .{ 5373 .src_locs = .{}, 5374 .results = .{}, 5375 .br_list = .{}, 5376 .block_inst = block_inst, 5377 }, 5378 }; 5379 var child_block = parent_block.makeSubBlock(); 5380 child_block.label = &label; 5381 child_block.runtime_cond = null; 5382 child_block.runtime_loop = src; 5383 child_block.runtime_index.increment(); 5384 const merges = &child_block.label.?.merges; 5385 5386 defer child_block.instructions.deinit(gpa); 5387 defer merges.deinit(gpa); 5388 5389 var loop_block = child_block.makeSubBlock(); 5390 defer loop_block.instructions.deinit(gpa); 5391 5392 try sema.analyzeBody(&loop_block, body); 5393 5394 const loop_block_len = loop_block.instructions.items.len; 5395 if (loop_block_len > 0 and sema.typeOf(Air.indexToRef(loop_block.instructions.items[loop_block_len - 1])).isNoReturn(mod)) { 5396 // If the loop ended with a noreturn terminator, then there is no way for it to loop, 5397 // so we can just use the block instead. 5398 try child_block.instructions.appendSlice(gpa, loop_block.instructions.items); 5399 } else { 5400 try child_block.instructions.append(gpa, loop_inst); 5401 5402 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + loop_block_len); 5403 sema.air_instructions.items(.data)[loop_inst].ty_pl.payload = sema.addExtraAssumeCapacity( 5404 Air.Block{ .body_len = @intCast(u32, loop_block_len) }, 5405 ); 5406 sema.air_extra.appendSliceAssumeCapacity(loop_block.instructions.items); 5407 } 5408 return sema.analyzeBlockBody(parent_block, src, &child_block, merges); 5409 } 5410 5411 fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5412 const tracy = trace(@src()); 5413 defer tracy.end(); 5414 5415 const pl_node = sema.code.instructions.items(.data)[inst].pl_node; 5416 const src = pl_node.src(); 5417 const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index); 5418 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 5419 5420 // we check this here to avoid undefined symbols 5421 if (!@import("build_options").have_llvm) 5422 return sema.fail(parent_block, src, "cannot do C import on Zig compiler not built with LLVM-extension", .{}); 5423 5424 var c_import_buf = std.ArrayList(u8).init(sema.gpa); 5425 defer c_import_buf.deinit(); 5426 5427 var comptime_reason: Block.ComptimeReason = .{ .c_import = .{ 5428 .block = parent_block, 5429 .src = src, 5430 } }; 5431 var child_block: Block = .{ 5432 .parent = parent_block, 5433 .sema = sema, 5434 .src_decl = parent_block.src_decl, 5435 .namespace = parent_block.namespace, 5436 .wip_capture_scope = parent_block.wip_capture_scope, 5437 .instructions = .{}, 5438 .inlining = parent_block.inlining, 5439 .is_comptime = true, 5440 .comptime_reason = &comptime_reason, 5441 .c_import_buf = &c_import_buf, 5442 .runtime_cond = parent_block.runtime_cond, 5443 .runtime_loop = parent_block.runtime_loop, 5444 .runtime_index = parent_block.runtime_index, 5445 }; 5446 defer child_block.instructions.deinit(sema.gpa); 5447 5448 // Ignore the result, all the relevant operations have written to c_import_buf already. 5449 _ = try sema.analyzeBodyBreak(&child_block, body); 5450 5451 const mod = sema.mod; 5452 const c_import_res = mod.comp.cImport(c_import_buf.items) catch |err| 5453 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); 5454 5455 if (c_import_res.errors.len != 0) { 5456 const msg = msg: { 5457 defer @import("clang.zig").ErrorMsg.delete(c_import_res.errors.ptr, c_import_res.errors.len); 5458 5459 const msg = try sema.errMsg(&child_block, src, "C import failed", .{}); 5460 errdefer msg.destroy(sema.gpa); 5461 5462 if (!mod.comp.bin_file.options.link_libc) 5463 try sema.errNote(&child_block, src, msg, "libc headers not available; compilation does not link against libc", .{}); 5464 5465 const gop = try sema.mod.cimport_errors.getOrPut(sema.gpa, sema.owner_decl_index); 5466 if (!gop.found_existing) { 5467 var errs = try std.ArrayListUnmanaged(Module.CImportError).initCapacity(sema.gpa, c_import_res.errors.len); 5468 errdefer { 5469 for (errs.items) |err| err.deinit(sema.gpa); 5470 errs.deinit(sema.gpa); 5471 } 5472 5473 for (c_import_res.errors) |c_error| { 5474 const path = if (c_error.filename_ptr) |some| 5475 try sema.gpa.dupeZ(u8, some[0..c_error.filename_len]) 5476 else 5477 null; 5478 errdefer if (path) |some| sema.gpa.free(some); 5479 5480 const c_msg = try sema.gpa.dupeZ(u8, c_error.msg_ptr[0..c_error.msg_len]); 5481 errdefer sema.gpa.free(c_msg); 5482 5483 const line = line: { 5484 const source = c_error.source orelse break :line null; 5485 var start = c_error.offset; 5486 while (start > 0) : (start -= 1) { 5487 if (source[start - 1] == '\n') break; 5488 } 5489 var end = c_error.offset; 5490 while (true) : (end += 1) { 5491 if (source[end] == 0) break; 5492 if (source[end] == '\n') break; 5493 } 5494 break :line try sema.gpa.dupeZ(u8, source[start..end]); 5495 }; 5496 errdefer if (line) |some| sema.gpa.free(some); 5497 5498 errs.appendAssumeCapacity(.{ 5499 .path = path orelse null, 5500 .source_line = line orelse null, 5501 .line = c_error.line, 5502 .column = c_error.column, 5503 .offset = c_error.offset, 5504 .msg = c_msg, 5505 }); 5506 } 5507 gop.value_ptr.* = errs.items; 5508 } 5509 break :msg msg; 5510 }; 5511 return sema.failWithOwnedErrorMsg(msg); 5512 } 5513 const c_import_pkg = Package.create( 5514 sema.gpa, 5515 null, 5516 c_import_res.out_zig_path, 5517 ) catch |err| switch (err) { 5518 error.OutOfMemory => return error.OutOfMemory, 5519 else => unreachable, // we pass null for root_src_dir_path 5520 }; 5521 5522 const result = mod.importPkg(c_import_pkg) catch |err| 5523 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); 5524 5525 mod.astGenFile(result.file) catch |err| 5526 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); 5527 5528 try mod.semaFile(result.file); 5529 const file_root_decl_index = result.file.root_decl.unwrap().?; 5530 const file_root_decl = mod.declPtr(file_root_decl_index); 5531 try mod.declareDeclDependency(sema.owner_decl_index, file_root_decl_index); 5532 return sema.addConstant(file_root_decl.ty, file_root_decl.val); 5533 } 5534 5535 fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5536 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 5537 const src = inst_data.src(); 5538 return sema.failWithUseOfAsync(parent_block, src); 5539 } 5540 5541 fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index, force_comptime: bool) CompileError!Air.Inst.Ref { 5542 const tracy = trace(@src()); 5543 defer tracy.end(); 5544 5545 const pl_node = sema.code.instructions.items(.data)[inst].pl_node; 5546 const src = pl_node.src(); 5547 const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index); 5548 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 5549 const gpa = sema.gpa; 5550 5551 // Reserve space for a Block instruction so that generated Break instructions can 5552 // point to it, even if it doesn't end up getting used because the code ends up being 5553 // comptime evaluated or is an unlabeled block. 5554 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 5555 try sema.air_instructions.append(gpa, .{ 5556 .tag = .block, 5557 .data = undefined, 5558 }); 5559 5560 var label: Block.Label = .{ 5561 .zir_block = inst, 5562 .merges = .{ 5563 .src_locs = .{}, 5564 .results = .{}, 5565 .br_list = .{}, 5566 .block_inst = block_inst, 5567 }, 5568 }; 5569 5570 var child_block: Block = .{ 5571 .parent = parent_block, 5572 .sema = sema, 5573 .src_decl = parent_block.src_decl, 5574 .namespace = parent_block.namespace, 5575 .wip_capture_scope = parent_block.wip_capture_scope, 5576 .instructions = .{}, 5577 .label = &label, 5578 .inlining = parent_block.inlining, 5579 .is_comptime = parent_block.is_comptime or force_comptime, 5580 .comptime_reason = parent_block.comptime_reason, 5581 .is_typeof = parent_block.is_typeof, 5582 .want_safety = parent_block.want_safety, 5583 .float_mode = parent_block.float_mode, 5584 .c_import_buf = parent_block.c_import_buf, 5585 .runtime_cond = parent_block.runtime_cond, 5586 .runtime_loop = parent_block.runtime_loop, 5587 .runtime_index = parent_block.runtime_index, 5588 .error_return_trace_index = parent_block.error_return_trace_index, 5589 }; 5590 5591 defer child_block.instructions.deinit(gpa); 5592 defer label.merges.deinit(gpa); 5593 5594 return sema.resolveBlockBody(parent_block, src, &child_block, body, inst, &label.merges); 5595 } 5596 5597 fn resolveBlockBody( 5598 sema: *Sema, 5599 parent_block: *Block, 5600 src: LazySrcLoc, 5601 child_block: *Block, 5602 body: []const Zir.Inst.Index, 5603 /// This is the instruction that a break instruction within `body` can 5604 /// use to return from the body. 5605 body_inst: Zir.Inst.Index, 5606 merges: *Block.Merges, 5607 ) CompileError!Air.Inst.Ref { 5608 if (child_block.is_comptime) { 5609 return sema.resolveBody(child_block, body, body_inst); 5610 } else { 5611 if (sema.analyzeBodyInner(child_block, body)) |_| { 5612 return sema.analyzeBlockBody(parent_block, src, child_block, merges); 5613 } else |err| switch (err) { 5614 error.ComptimeBreak => { 5615 // Comptime control flow is happening, however child_block may still contain 5616 // runtime instructions which need to be copied to the parent block. 5617 try parent_block.instructions.appendSlice(sema.gpa, child_block.instructions.items); 5618 5619 const break_inst = sema.comptime_break_inst; 5620 const break_data = sema.code.instructions.items(.data)[break_inst].@"break"; 5621 const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data; 5622 if (extra.block_inst == body_inst) { 5623 return try sema.resolveInst(break_data.operand); 5624 } else { 5625 return error.ComptimeBreak; 5626 } 5627 }, 5628 else => |e| return e, 5629 } 5630 } 5631 } 5632 5633 fn analyzeBlockBody( 5634 sema: *Sema, 5635 parent_block: *Block, 5636 src: LazySrcLoc, 5637 child_block: *Block, 5638 merges: *Block.Merges, 5639 ) CompileError!Air.Inst.Ref { 5640 const tracy = trace(@src()); 5641 defer tracy.end(); 5642 5643 const gpa = sema.gpa; 5644 const mod = sema.mod; 5645 5646 // Blocks must terminate with noreturn instruction. 5647 assert(child_block.instructions.items.len != 0); 5648 assert(sema.typeOf(Air.indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1])).isNoReturn(mod)); 5649 5650 if (merges.results.items.len == 0) { 5651 // No need for a block instruction. We can put the new instructions 5652 // directly into the parent block. 5653 try parent_block.instructions.appendSlice(gpa, child_block.instructions.items); 5654 return Air.indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1]); 5655 } 5656 if (merges.results.items.len == 1) { 5657 const last_inst_index = child_block.instructions.items.len - 1; 5658 const last_inst = child_block.instructions.items[last_inst_index]; 5659 if (sema.getBreakBlock(last_inst)) |br_block| { 5660 if (br_block == merges.block_inst) { 5661 // No need for a block instruction. We can put the new instructions directly 5662 // into the parent block. Here we omit the break instruction. 5663 const without_break = child_block.instructions.items[0..last_inst_index]; 5664 try parent_block.instructions.appendSlice(gpa, without_break); 5665 return merges.results.items[0]; 5666 } 5667 } 5668 } 5669 // It is impossible to have the number of results be > 1 in a comptime scope. 5670 assert(!child_block.is_comptime); // Should already got a compile error in the condbr condition. 5671 5672 // Need to set the type and emit the Block instruction. This allows machine code generation 5673 // to emit a jump instruction to after the block when it encounters the break. 5674 try parent_block.instructions.append(gpa, merges.block_inst); 5675 const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .{ .override = merges.src_locs.items }); 5676 // TODO add note "missing else causes void value" 5677 5678 const type_src = src; // TODO: better source location 5679 const valid_rt = try sema.validateRunTimeType(resolved_ty, false); 5680 if (!valid_rt) { 5681 const msg = msg: { 5682 const msg = try sema.errMsg(child_block, type_src, "value with comptime-only type '{}' depends on runtime control flow", .{resolved_ty.fmt(mod)}); 5683 errdefer msg.destroy(sema.gpa); 5684 5685 const runtime_src = child_block.runtime_cond orelse child_block.runtime_loop.?; 5686 try sema.errNote(child_block, runtime_src, msg, "runtime control flow here", .{}); 5687 5688 const child_src_decl = mod.declPtr(child_block.src_decl); 5689 try sema.explainWhyTypeIsComptime(msg, type_src.toSrcLoc(child_src_decl, mod), resolved_ty); 5690 5691 break :msg msg; 5692 }; 5693 return sema.failWithOwnedErrorMsg(msg); 5694 } 5695 const ty_inst = try sema.addType(resolved_ty); 5696 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + 5697 child_block.instructions.items.len); 5698 sema.air_instructions.items(.data)[merges.block_inst] = .{ .ty_pl = .{ 5699 .ty = ty_inst, 5700 .payload = sema.addExtraAssumeCapacity(Air.Block{ 5701 .body_len = @intCast(u32, child_block.instructions.items.len), 5702 }), 5703 } }; 5704 sema.air_extra.appendSliceAssumeCapacity(child_block.instructions.items); 5705 // Now that the block has its type resolved, we need to go back into all the break 5706 // instructions, and insert type coercion on the operands. 5707 for (merges.br_list.items) |br| { 5708 const br_operand = sema.air_instructions.items(.data)[br].br.operand; 5709 const br_operand_src = src; 5710 const br_operand_ty = sema.typeOf(br_operand); 5711 if (br_operand_ty.eql(resolved_ty, mod)) { 5712 // No type coercion needed. 5713 continue; 5714 } 5715 var coerce_block = parent_block.makeSubBlock(); 5716 defer coerce_block.instructions.deinit(gpa); 5717 const coerced_operand = try sema.coerce(&coerce_block, resolved_ty, br_operand, br_operand_src); 5718 // If no instructions were produced, such as in the case of a coercion of a 5719 // constant value to a new type, we can simply point the br operand to it. 5720 if (coerce_block.instructions.items.len == 0) { 5721 sema.air_instructions.items(.data)[br].br.operand = coerced_operand; 5722 continue; 5723 } 5724 assert(coerce_block.instructions.items[coerce_block.instructions.items.len - 1] == 5725 Air.refToIndex(coerced_operand).?); 5726 5727 // Convert the br instruction to a block instruction that has the coercion 5728 // and then a new br inside that returns the coerced instruction. 5729 const sub_block_len = @intCast(u32, coerce_block.instructions.items.len + 1); 5730 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + 5731 sub_block_len); 5732 try sema.air_instructions.ensureUnusedCapacity(gpa, 1); 5733 const sub_br_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 5734 5735 sema.air_instructions.items(.tag)[br] = .block; 5736 sema.air_instructions.items(.data)[br] = .{ .ty_pl = .{ 5737 .ty = Air.Inst.Ref.noreturn_type, 5738 .payload = sema.addExtraAssumeCapacity(Air.Block{ 5739 .body_len = sub_block_len, 5740 }), 5741 } }; 5742 sema.air_extra.appendSliceAssumeCapacity(coerce_block.instructions.items); 5743 sema.air_extra.appendAssumeCapacity(sub_br_inst); 5744 5745 sema.air_instructions.appendAssumeCapacity(.{ 5746 .tag = .br, 5747 .data = .{ .br = .{ 5748 .block_inst = merges.block_inst, 5749 .operand = coerced_operand, 5750 } }, 5751 }); 5752 } 5753 return Air.indexToRef(merges.block_inst); 5754 } 5755 5756 fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5757 const tracy = trace(@src()); 5758 defer tracy.end(); 5759 5760 const mod = sema.mod; 5761 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 5762 const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data; 5763 const src = inst_data.src(); 5764 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 5765 const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 5766 const decl_name = sema.code.nullTerminatedString(extra.decl_name); 5767 const decl_index = if (extra.namespace != .none) index_blk: { 5768 const container_ty = try sema.resolveType(block, operand_src, extra.namespace); 5769 const container_namespace = container_ty.getNamespaceIndex(mod).unwrap().?; 5770 5771 const maybe_index = try sema.lookupInNamespace(block, operand_src, container_namespace, decl_name, false); 5772 break :index_blk maybe_index orelse 5773 return sema.failWithBadMemberAccess(block, container_ty, operand_src, decl_name); 5774 } else try sema.lookupIdentifier(block, operand_src, decl_name); 5775 const options = sema.resolveExportOptions(block, .unneeded, extra.options) catch |err| switch (err) { 5776 error.NeededSourceLocation => { 5777 _ = try sema.resolveExportOptions(block, options_src, extra.options); 5778 unreachable; 5779 }, 5780 else => |e| return e, 5781 }; 5782 { 5783 try mod.ensureDeclAnalyzed(decl_index); 5784 const exported_decl = mod.declPtr(decl_index); 5785 if (exported_decl.val.getFunction(mod)) |function| { 5786 return sema.analyzeExport(block, src, options, function.owner_decl); 5787 } 5788 } 5789 try sema.analyzeExport(block, src, options, decl_index); 5790 } 5791 5792 fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5793 const tracy = trace(@src()); 5794 defer tracy.end(); 5795 5796 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 5797 const extra = sema.code.extraData(Zir.Inst.ExportValue, inst_data.payload_index).data; 5798 const src = inst_data.src(); 5799 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 5800 const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 5801 const operand = try sema.resolveInstConst(block, operand_src, extra.operand, "export target must be comptime-known"); 5802 const options = sema.resolveExportOptions(block, .unneeded, extra.options) catch |err| switch (err) { 5803 error.NeededSourceLocation => { 5804 _ = try sema.resolveExportOptions(block, options_src, extra.options); 5805 unreachable; 5806 }, 5807 else => |e| return e, 5808 }; 5809 const decl_index = if (operand.val.getFunction(sema.mod)) |function| function.owner_decl else blk: { 5810 var anon_decl = try block.startAnonDecl(); 5811 defer anon_decl.deinit(); 5812 break :blk try anon_decl.finish( 5813 operand.ty, 5814 try operand.val.copy(anon_decl.arena()), 5815 0, 5816 ); 5817 }; 5818 try sema.analyzeExport(block, src, options, decl_index); 5819 } 5820 5821 pub fn analyzeExport( 5822 sema: *Sema, 5823 block: *Block, 5824 src: LazySrcLoc, 5825 borrowed_options: std.builtin.ExportOptions, 5826 exported_decl_index: Decl.Index, 5827 ) !void { 5828 const Export = Module.Export; 5829 const mod = sema.mod; 5830 5831 if (borrowed_options.linkage == .Internal) { 5832 return; 5833 } 5834 5835 try mod.ensureDeclAnalyzed(exported_decl_index); 5836 const exported_decl = mod.declPtr(exported_decl_index); 5837 5838 if (!try sema.validateExternType(exported_decl.ty, .other)) { 5839 const msg = msg: { 5840 const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(sema.mod)}); 5841 errdefer msg.destroy(sema.gpa); 5842 5843 const src_decl = sema.mod.declPtr(block.src_decl); 5844 try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), exported_decl.ty, .other); 5845 5846 try sema.addDeclaredHereNote(msg, exported_decl.ty); 5847 break :msg msg; 5848 }; 5849 return sema.failWithOwnedErrorMsg(msg); 5850 } 5851 5852 // TODO: some backends might support re-exporting extern decls 5853 if (exported_decl.isExtern(mod)) { 5854 return sema.fail(block, src, "export target cannot be extern", .{}); 5855 } 5856 5857 // This decl is alive no matter what, since it's being exported 5858 try mod.markDeclAlive(exported_decl); 5859 try sema.maybeQueueFuncBodyAnalysis(exported_decl_index); 5860 5861 const gpa = sema.gpa; 5862 5863 try mod.decl_exports.ensureUnusedCapacity(gpa, 1); 5864 try mod.export_owners.ensureUnusedCapacity(gpa, 1); 5865 5866 const new_export = try gpa.create(Export); 5867 errdefer gpa.destroy(new_export); 5868 5869 const symbol_name = try gpa.dupe(u8, borrowed_options.name); 5870 errdefer gpa.free(symbol_name); 5871 5872 const section: ?[]const u8 = if (borrowed_options.section) |s| try gpa.dupe(u8, s) else null; 5873 errdefer if (section) |s| gpa.free(s); 5874 5875 new_export.* = .{ 5876 .options = .{ 5877 .name = symbol_name, 5878 .linkage = borrowed_options.linkage, 5879 .section = section, 5880 .visibility = borrowed_options.visibility, 5881 }, 5882 .src = src, 5883 .owner_decl = sema.owner_decl_index, 5884 .src_decl = block.src_decl, 5885 .exported_decl = exported_decl_index, 5886 .status = .in_progress, 5887 }; 5888 5889 // Add to export_owners table. 5890 const eo_gop = mod.export_owners.getOrPutAssumeCapacity(sema.owner_decl_index); 5891 if (!eo_gop.found_existing) { 5892 eo_gop.value_ptr.* = .{}; 5893 } 5894 try eo_gop.value_ptr.append(gpa, new_export); 5895 errdefer _ = eo_gop.value_ptr.pop(); 5896 5897 // Add to exported_decl table. 5898 const de_gop = mod.decl_exports.getOrPutAssumeCapacity(exported_decl_index); 5899 if (!de_gop.found_existing) { 5900 de_gop.value_ptr.* = .{}; 5901 } 5902 try de_gop.value_ptr.append(gpa, new_export); 5903 errdefer _ = de_gop.value_ptr.pop(); 5904 } 5905 5906 fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { 5907 const mod = sema.mod; 5908 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 5909 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 5910 const src = LazySrcLoc.nodeOffset(extra.node); 5911 const alignment = try sema.resolveAlign(block, operand_src, extra.operand); 5912 if (alignment > 256) { 5913 return sema.fail(block, src, "attempt to @setAlignStack({d}); maximum is 256", .{ 5914 alignment, 5915 }); 5916 } 5917 const func_index = sema.func_index.unwrap() orelse 5918 return sema.fail(block, src, "@setAlignStack outside function body", .{}); 5919 const func = mod.funcPtr(func_index); 5920 5921 const fn_owner_decl = mod.declPtr(func.owner_decl); 5922 switch (fn_owner_decl.ty.fnCallingConvention(mod)) { 5923 .Naked => return sema.fail(block, src, "@setAlignStack in naked function", .{}), 5924 .Inline => return sema.fail(block, src, "@setAlignStack in inline function", .{}), 5925 else => if (block.inlining != null) { 5926 return sema.fail(block, src, "@setAlignStack in inline call", .{}); 5927 }, 5928 } 5929 5930 const gop = try mod.align_stack_fns.getOrPut(sema.gpa, func_index); 5931 if (gop.found_existing) { 5932 const msg = msg: { 5933 const msg = try sema.errMsg(block, src, "multiple @setAlignStack in the same function body", .{}); 5934 errdefer msg.destroy(sema.gpa); 5935 try sema.errNote(block, gop.value_ptr.src, msg, "other instance here", .{}); 5936 break :msg msg; 5937 }; 5938 return sema.failWithOwnedErrorMsg(msg); 5939 } 5940 gop.value_ptr.* = .{ .alignment = alignment, .src = src }; 5941 } 5942 5943 fn zirSetCold(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { 5944 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 5945 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 5946 const is_cold = try sema.resolveConstBool(block, operand_src, extra.operand, "operand to @setCold must be comptime-known"); 5947 const func = sema.func orelse return; // does nothing outside a function 5948 func.is_cold = is_cold; 5949 } 5950 5951 fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { 5952 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 5953 const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 5954 block.float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, "FloatMode", "operand to @setFloatMode must be comptime-known"); 5955 } 5956 5957 fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5958 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 5959 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 5960 block.want_safety = try sema.resolveConstBool(block, operand_src, inst_data.operand, "operand to @setRuntimeSafety must be comptime-known"); 5961 } 5962 5963 fn zirFence(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { 5964 if (block.is_comptime) return; 5965 5966 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 5967 const order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 5968 const order = try sema.resolveAtomicOrder(block, order_src, extra.operand, "atomic order of @fence must be comptime-known"); 5969 5970 if (@enumToInt(order) < @enumToInt(std.builtin.AtomicOrder.Acquire)) { 5971 return sema.fail(block, order_src, "atomic ordering must be Acquire or stricter", .{}); 5972 } 5973 5974 _ = try block.addInst(.{ 5975 .tag = .fence, 5976 .data = .{ .fence = order }, 5977 }); 5978 } 5979 5980 fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { 5981 const tracy = trace(@src()); 5982 defer tracy.end(); 5983 5984 const inst_data = sema.code.instructions.items(.data)[inst].@"break"; 5985 const extra = sema.code.extraData(Zir.Inst.Break, inst_data.payload_index).data; 5986 const operand = try sema.resolveInst(inst_data.operand); 5987 const zir_block = extra.block_inst; 5988 5989 var block = start_block; 5990 while (true) { 5991 if (block.label) |label| { 5992 if (label.zir_block == zir_block) { 5993 const br_ref = try start_block.addBr(label.merges.block_inst, operand); 5994 const src_loc = if (extra.operand_src_node != Zir.Inst.Break.no_src_node) 5995 LazySrcLoc.nodeOffset(extra.operand_src_node) 5996 else 5997 null; 5998 try label.merges.src_locs.append(sema.gpa, src_loc); 5999 try label.merges.results.append(sema.gpa, operand); 6000 try label.merges.br_list.append(sema.gpa, Air.refToIndex(br_ref).?); 6001 block.runtime_index.increment(); 6002 if (block.runtime_cond == null and block.runtime_loop == null) { 6003 block.runtime_cond = start_block.runtime_cond orelse start_block.runtime_loop; 6004 block.runtime_loop = start_block.runtime_loop; 6005 } 6006 return inst; 6007 } 6008 } 6009 block = block.parent.?; 6010 } 6011 } 6012 6013 fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 6014 // We do not set sema.src here because dbg_stmt instructions are only emitted for 6015 // ZIR code that possibly will need to generate runtime code. So error messages 6016 // and other source locations must not rely on sema.src being set from dbg_stmt 6017 // instructions. 6018 if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; 6019 6020 const inst_data = sema.code.instructions.items(.data)[inst].dbg_stmt; 6021 6022 if (block.instructions.items.len != 0) { 6023 const idx = block.instructions.items[block.instructions.items.len - 1]; 6024 if (sema.air_instructions.items(.tag)[idx] == .dbg_stmt) { 6025 // The previous dbg_stmt didn't correspond to any actual code, so replace it. 6026 sema.air_instructions.items(.data)[idx].dbg_stmt = .{ 6027 .line = inst_data.line, 6028 .column = inst_data.column, 6029 }; 6030 return; 6031 } 6032 } 6033 6034 _ = try block.addInst(.{ 6035 .tag = .dbg_stmt, 6036 .data = .{ .dbg_stmt = .{ 6037 .line = inst_data.line, 6038 .column = inst_data.column, 6039 } }, 6040 }); 6041 } 6042 6043 fn zirDbgBlockBegin(sema: *Sema, block: *Block) CompileError!void { 6044 if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; 6045 6046 _ = try block.addInst(.{ 6047 .tag = .dbg_block_begin, 6048 .data = undefined, 6049 }); 6050 } 6051 6052 fn zirDbgBlockEnd(sema: *Sema, block: *Block) CompileError!void { 6053 if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; 6054 6055 _ = try block.addInst(.{ 6056 .tag = .dbg_block_end, 6057 .data = undefined, 6058 }); 6059 } 6060 6061 fn zirDbgVar( 6062 sema: *Sema, 6063 block: *Block, 6064 inst: Zir.Inst.Index, 6065 air_tag: Air.Inst.Tag, 6066 ) CompileError!void { 6067 if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; 6068 6069 const str_op = sema.code.instructions.items(.data)[inst].str_op; 6070 const operand = try sema.resolveInst(str_op.operand); 6071 const name = str_op.getStr(sema.code); 6072 try sema.addDbgVar(block, operand, air_tag, name); 6073 } 6074 6075 fn addDbgVar( 6076 sema: *Sema, 6077 block: *Block, 6078 operand: Air.Inst.Ref, 6079 air_tag: Air.Inst.Tag, 6080 name: []const u8, 6081 ) CompileError!void { 6082 const mod = sema.mod; 6083 const operand_ty = sema.typeOf(operand); 6084 switch (air_tag) { 6085 .dbg_var_ptr => { 6086 if (!(try sema.typeHasRuntimeBits(operand_ty.childType(mod)))) return; 6087 }, 6088 .dbg_var_val => { 6089 if (!(try sema.typeHasRuntimeBits(operand_ty))) return; 6090 }, 6091 else => unreachable, 6092 } 6093 6094 try sema.queueFullTypeResolution(operand_ty); 6095 6096 // Add the name to the AIR. 6097 const name_extra_index = @intCast(u32, sema.air_extra.items.len); 6098 const elements_used = name.len / 4 + 1; 6099 try sema.air_extra.ensureUnusedCapacity(sema.gpa, elements_used); 6100 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); 6101 @memcpy(buffer[0..name.len], name); 6102 buffer[name.len] = 0; 6103 sema.air_extra.items.len += elements_used; 6104 6105 _ = try block.addInst(.{ 6106 .tag = air_tag, 6107 .data = .{ .pl_op = .{ 6108 .payload = name_extra_index, 6109 .operand = operand, 6110 } }, 6111 }); 6112 } 6113 6114 fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 6115 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 6116 const src = inst_data.src(); 6117 const decl_name = inst_data.get(sema.code); 6118 const decl_index = try sema.lookupIdentifier(block, src, decl_name); 6119 try sema.addReferencedBy(block, src, decl_index); 6120 return sema.analyzeDeclRef(decl_index); 6121 } 6122 6123 fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 6124 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 6125 const src = inst_data.src(); 6126 const decl_name = inst_data.get(sema.code); 6127 const decl = try sema.lookupIdentifier(block, src, decl_name); 6128 return sema.analyzeDeclVal(block, src, decl); 6129 } 6130 6131 fn lookupIdentifier(sema: *Sema, block: *Block, src: LazySrcLoc, name: []const u8) !Decl.Index { 6132 const mod = sema.mod; 6133 var namespace = block.namespace; 6134 while (true) { 6135 if (try sema.lookupInNamespace(block, src, namespace, name, false)) |decl_index| { 6136 return decl_index; 6137 } 6138 namespace = mod.namespacePtr(namespace).parent.unwrap() orelse break; 6139 } 6140 unreachable; // AstGen detects use of undeclared identifier errors. 6141 } 6142 6143 /// This looks up a member of a specific namespace. It is affected by `usingnamespace` but 6144 /// only for ones in the specified namespace. 6145 fn lookupInNamespace( 6146 sema: *Sema, 6147 block: *Block, 6148 src: LazySrcLoc, 6149 namespace_index: Namespace.Index, 6150 ident_name: []const u8, 6151 observe_usingnamespace: bool, 6152 ) CompileError!?Decl.Index { 6153 const mod = sema.mod; 6154 6155 const namespace = mod.namespacePtr(namespace_index); 6156 const namespace_decl_index = namespace.getDeclIndex(mod); 6157 const namespace_decl = sema.mod.declPtr(namespace_decl_index); 6158 if (namespace_decl.analysis == .file_failure) { 6159 try mod.declareDeclDependency(sema.owner_decl_index, namespace_decl_index); 6160 return error.AnalysisFail; 6161 } 6162 6163 if (observe_usingnamespace and namespace.usingnamespace_set.count() != 0) { 6164 const src_file = mod.namespacePtr(block.namespace).file_scope; 6165 6166 const gpa = sema.gpa; 6167 var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Namespace, bool) = .{}; 6168 defer checked_namespaces.deinit(gpa); 6169 6170 // Keep track of name conflicts for error notes. 6171 var candidates: std.ArrayListUnmanaged(Decl.Index) = .{}; 6172 defer candidates.deinit(gpa); 6173 6174 try checked_namespaces.put(gpa, namespace, namespace.file_scope == src_file); 6175 var check_i: usize = 0; 6176 6177 while (check_i < checked_namespaces.count()) : (check_i += 1) { 6178 const check_ns = checked_namespaces.keys()[check_i]; 6179 if (check_ns.decls.getKeyAdapted(ident_name, Module.DeclAdapter{ .mod = mod })) |decl_index| { 6180 // Skip decls which are not marked pub, which are in a different 6181 // file than the `a.b`/`@hasDecl` syntax. 6182 const decl = mod.declPtr(decl_index); 6183 if (decl.is_pub or (src_file == decl.getFileScope(mod) and checked_namespaces.values()[check_i])) { 6184 try candidates.append(gpa, decl_index); 6185 } 6186 } 6187 var it = check_ns.usingnamespace_set.iterator(); 6188 while (it.next()) |entry| { 6189 const sub_usingnamespace_decl_index = entry.key_ptr.*; 6190 // Skip the decl we're currently analysing. 6191 if (sub_usingnamespace_decl_index == sema.owner_decl_index) continue; 6192 const sub_usingnamespace_decl = mod.declPtr(sub_usingnamespace_decl_index); 6193 const sub_is_pub = entry.value_ptr.*; 6194 if (!sub_is_pub and src_file != sub_usingnamespace_decl.getFileScope(mod)) { 6195 // Skip usingnamespace decls which are not marked pub, which are in 6196 // a different file than the `a.b`/`@hasDecl` syntax. 6197 continue; 6198 } 6199 try sema.ensureDeclAnalyzed(sub_usingnamespace_decl_index); 6200 const ns_ty = sub_usingnamespace_decl.val.toType(); 6201 const sub_ns = ns_ty.getNamespace(mod).?; 6202 try checked_namespaces.put(gpa, sub_ns, src_file == sub_usingnamespace_decl.getFileScope(mod)); 6203 } 6204 } 6205 6206 { 6207 var i: usize = 0; 6208 while (i < candidates.items.len) { 6209 if (candidates.items[i] == sema.owner_decl_index) { 6210 _ = candidates.orderedRemove(i); 6211 } else { 6212 i += 1; 6213 } 6214 } 6215 } 6216 6217 switch (candidates.items.len) { 6218 0 => {}, 6219 1 => { 6220 const decl_index = candidates.items[0]; 6221 try mod.declareDeclDependency(sema.owner_decl_index, decl_index); 6222 return decl_index; 6223 }, 6224 else => { 6225 const msg = msg: { 6226 const msg = try sema.errMsg(block, src, "ambiguous reference", .{}); 6227 errdefer msg.destroy(gpa); 6228 for (candidates.items) |candidate_index| { 6229 const candidate = mod.declPtr(candidate_index); 6230 const src_loc = candidate.srcLoc(mod); 6231 try mod.errNoteNonLazy(src_loc, msg, "declared here", .{}); 6232 } 6233 break :msg msg; 6234 }; 6235 return sema.failWithOwnedErrorMsg(msg); 6236 }, 6237 } 6238 } else if (namespace.decls.getKeyAdapted(ident_name, Module.DeclAdapter{ .mod = mod })) |decl_index| { 6239 try mod.declareDeclDependency(sema.owner_decl_index, decl_index); 6240 return decl_index; 6241 } 6242 6243 log.debug("{*} ({s}) depends on non-existence of '{s}' in {*} ({s})", .{ 6244 sema.owner_decl, sema.owner_decl.name, ident_name, namespace_decl, namespace_decl.name, 6245 }); 6246 // TODO This dependency is too strong. Really, it should only be a dependency 6247 // on the non-existence of `ident_name` in the namespace. We can lessen the number of 6248 // outdated declarations by making this dependency more sophisticated. 6249 try mod.declareDeclDependency(sema.owner_decl_index, namespace_decl_index); 6250 return null; 6251 } 6252 6253 fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl { 6254 const mod = sema.mod; 6255 const func_val = (try sema.resolveMaybeUndefVal(func_inst)) orelse return null; 6256 if (func_val.isUndef(mod)) return null; 6257 const owner_decl_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) { 6258 .extern_func => |extern_func| extern_func.decl, 6259 .func => |func| mod.funcPtr(func.index).owner_decl, 6260 .ptr => |ptr| switch (ptr.addr) { 6261 .decl => |decl| mod.declPtr(decl).val.getFunction(mod).?.owner_decl, 6262 else => return null, 6263 }, 6264 else => return null, 6265 }; 6266 return mod.declPtr(owner_decl_index); 6267 } 6268 6269 pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref { 6270 const src = sema.src; 6271 6272 if (!sema.mod.backendSupportsFeature(.error_return_trace)) return .none; 6273 if (!sema.mod.comp.bin_file.options.error_return_tracing) return .none; 6274 6275 if (block.is_comptime) 6276 return .none; 6277 6278 const unresolved_stack_trace_ty = sema.getBuiltinType("StackTrace") catch |err| switch (err) { 6279 error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, 6280 else => |e| return e, 6281 }; 6282 const stack_trace_ty = sema.resolveTypeFields(unresolved_stack_trace_ty) catch |err| switch (err) { 6283 error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, 6284 else => |e| return e, 6285 }; 6286 const field_index = sema.structFieldIndex(block, stack_trace_ty, "index", src) catch |err| switch (err) { 6287 error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, 6288 else => |e| return e, 6289 }; 6290 6291 return try block.addInst(.{ 6292 .tag = .save_err_return_trace_index, 6293 .data = .{ .ty_pl = .{ 6294 .ty = try sema.addType(stack_trace_ty), 6295 .payload = @intCast(u32, field_index), 6296 } }, 6297 }); 6298 } 6299 6300 /// Add instructions to block to "pop" the error return trace. 6301 /// If `operand` is provided, only pops if operand is non-error. 6302 fn popErrorReturnTrace( 6303 sema: *Sema, 6304 block: *Block, 6305 src: LazySrcLoc, 6306 operand: Air.Inst.Ref, 6307 saved_error_trace_index: Air.Inst.Ref, 6308 ) CompileError!void { 6309 const mod = sema.mod; 6310 var is_non_error: ?bool = null; 6311 var is_non_error_inst: Air.Inst.Ref = undefined; 6312 if (operand != .none) { 6313 is_non_error_inst = try sema.analyzeIsNonErr(block, src, operand); 6314 if (try sema.resolveDefinedValue(block, src, is_non_error_inst)) |cond_val| 6315 is_non_error = cond_val.toBool(); 6316 } else is_non_error = true; // no operand means pop unconditionally 6317 6318 if (is_non_error == true) { 6319 // AstGen determined this result does not go to an error-handling expr (try/catch/return etc.), or 6320 // the result is comptime-known to be a non-error. Either way, pop unconditionally. 6321 6322 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); 6323 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); 6324 const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); 6325 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); 6326 const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, "index", src, stack_trace_ty, true); 6327 try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store); 6328 } else if (is_non_error == null) { 6329 // The result might be an error. If it is, we leave the error trace alone. If it isn't, we need 6330 // to pop any error trace that may have been propagated from our arguments. 6331 6332 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Block).Struct.fields.len); 6333 const cond_block_inst = try block.addInstAsIndex(.{ 6334 .tag = .block, 6335 .data = .{ 6336 .ty_pl = .{ 6337 .ty = Air.Inst.Ref.void_type, 6338 .payload = undefined, // updated below 6339 }, 6340 }, 6341 }); 6342 6343 var then_block = block.makeSubBlock(); 6344 defer then_block.instructions.deinit(sema.gpa); 6345 6346 // If non-error, then pop the error return trace by restoring the index. 6347 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); 6348 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); 6349 const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); 6350 const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty); 6351 const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, "index", src, stack_trace_ty, true); 6352 try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store); 6353 _ = try then_block.addBr(cond_block_inst, Air.Inst.Ref.void_value); 6354 6355 // Otherwise, do nothing 6356 var else_block = block.makeSubBlock(); 6357 defer else_block.instructions.deinit(sema.gpa); 6358 _ = try else_block.addBr(cond_block_inst, Air.Inst.Ref.void_value); 6359 6360 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.CondBr).Struct.fields.len + 6361 then_block.instructions.items.len + else_block.instructions.items.len + 6362 @typeInfo(Air.Block).Struct.fields.len + 1); // +1 for the sole .cond_br instruction in the .block 6363 6364 const cond_br_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 6365 try sema.air_instructions.append(sema.gpa, .{ .tag = .cond_br, .data = .{ .pl_op = .{ 6366 .operand = is_non_error_inst, 6367 .payload = sema.addExtraAssumeCapacity(Air.CondBr{ 6368 .then_body_len = @intCast(u32, then_block.instructions.items.len), 6369 .else_body_len = @intCast(u32, else_block.instructions.items.len), 6370 }), 6371 } } }); 6372 sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items); 6373 sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items); 6374 6375 sema.air_instructions.items(.data)[cond_block_inst].ty_pl.payload = sema.addExtraAssumeCapacity(Air.Block{ .body_len = 1 }); 6376 sema.air_extra.appendAssumeCapacity(cond_br_inst); 6377 } 6378 } 6379 6380 fn zirCall( 6381 sema: *Sema, 6382 block: *Block, 6383 inst: Zir.Inst.Index, 6384 comptime kind: enum { direct, field }, 6385 ) CompileError!Air.Inst.Ref { 6386 const tracy = trace(@src()); 6387 defer tracy.end(); 6388 6389 const mod = sema.mod; 6390 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 6391 const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node }; 6392 const call_src = inst_data.src(); 6393 const ExtraType = switch (kind) { 6394 .direct => Zir.Inst.Call, 6395 .field => Zir.Inst.FieldCall, 6396 }; 6397 const extra = sema.code.extraData(ExtraType, inst_data.payload_index); 6398 const args_len = extra.data.flags.args_len; 6399 6400 const modifier = @intToEnum(std.builtin.CallModifier, extra.data.flags.packed_modifier); 6401 const ensure_result_used = extra.data.flags.ensure_result_used; 6402 const pop_error_return_trace = extra.data.flags.pop_error_return_trace; 6403 6404 const callee: ResolvedFieldCallee = switch (kind) { 6405 .direct => .{ .direct = try sema.resolveInst(extra.data.callee) }, 6406 .field => blk: { 6407 const object_ptr = try sema.resolveInst(extra.data.obj_ptr); 6408 const field_name = sema.code.nullTerminatedString(extra.data.field_name_start); 6409 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; 6410 break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src); 6411 }, 6412 }; 6413 var resolved_args: []Air.Inst.Ref = undefined; 6414 var bound_arg_src: ?LazySrcLoc = null; 6415 var func: Air.Inst.Ref = undefined; 6416 var arg_index: u32 = 0; 6417 switch (callee) { 6418 .direct => |func_inst| { 6419 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len); 6420 func = func_inst; 6421 }, 6422 .method => |method| { 6423 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1); 6424 func = method.func_inst; 6425 resolved_args[0] = method.arg0_inst; 6426 arg_index += 1; 6427 bound_arg_src = callee_src; 6428 }, 6429 } 6430 6431 const callee_ty = sema.typeOf(func); 6432 const total_args = args_len + @boolToInt(bound_arg_src != null); 6433 const func_ty = try sema.checkCallArgumentCount(block, func, callee_src, callee_ty, total_args, bound_arg_src != null); 6434 6435 const args_body = sema.code.extra[extra.end..]; 6436 6437 var input_is_error = false; 6438 const block_index = @intCast(Air.Inst.Index, block.instructions.items.len); 6439 6440 const fn_params_len = mod.typeToFunc(func_ty).?.param_types.len; 6441 const parent_comptime = block.is_comptime; 6442 // `extra_index` and `arg_index` are separate since the bound function is passed as the first argument. 6443 var extra_index: usize = 0; 6444 var arg_start: u32 = args_len; 6445 while (extra_index < args_len) : ({ 6446 extra_index += 1; 6447 arg_index += 1; 6448 }) { 6449 const func_ty_info = mod.typeToFunc(func_ty).?; 6450 const arg_end = sema.code.extra[extra.end + extra_index]; 6451 defer arg_start = arg_end; 6452 6453 // Generate args to comptime params in comptime block. 6454 defer block.is_comptime = parent_comptime; 6455 if (arg_index < @min(fn_params_len, 32) and func_ty_info.paramIsComptime(@intCast(u5, arg_index))) { 6456 block.is_comptime = true; 6457 // TODO set comptime_reason 6458 } 6459 6460 sema.inst_map.putAssumeCapacity(inst, inst: { 6461 if (arg_index >= fn_params_len) 6462 break :inst Air.Inst.Ref.var_args_param_type; 6463 6464 if (func_ty_info.param_types[arg_index] == .generic_poison_type) 6465 break :inst Air.Inst.Ref.generic_poison_type; 6466 6467 break :inst try sema.addType(func_ty_info.param_types[arg_index].toType()); 6468 }); 6469 6470 const resolved = try sema.resolveBody(block, args_body[arg_start..arg_end], inst); 6471 const resolved_ty = sema.typeOf(resolved); 6472 if (resolved_ty.zigTypeTag(mod) == .NoReturn) { 6473 return resolved; 6474 } 6475 if (resolved_ty.isError(mod)) { 6476 input_is_error = true; 6477 } 6478 resolved_args[arg_index] = resolved; 6479 } 6480 if (sema.owner_func == null or !sema.owner_func.?.calls_or_awaits_errorable_fn) { 6481 input_is_error = false; // input was an error type, but no errorable fn's were actually called 6482 } 6483 6484 // AstGen ensures that a call instruction is always preceded by a dbg_stmt instruction. 6485 const call_dbg_node = inst - 1; 6486 6487 if (sema.mod.backendSupportsFeature(.error_return_trace) and sema.mod.comp.bin_file.options.error_return_tracing and 6488 !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace)) 6489 { 6490 const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: { 6491 break :b try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node); 6492 }; 6493 6494 const return_ty = sema.typeOf(call_inst); 6495 if (modifier != .always_tail and return_ty.isNoReturn(mod)) 6496 return call_inst; // call to "fn(...) noreturn", don't pop 6497 6498 // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only 6499 // need to clean-up our own trace if we were passed to a non-error-handling expression. 6500 if (input_is_error or (pop_error_return_trace and modifier != .always_tail and return_ty.isError(mod))) { 6501 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); 6502 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); 6503 const field_index = try sema.structFieldIndex(block, stack_trace_ty, "index", call_src); 6504 6505 // Insert a save instruction before the arg resolution + call instructions we just generated 6506 const save_inst = try block.insertInst(block_index, .{ 6507 .tag = .save_err_return_trace_index, 6508 .data = .{ .ty_pl = .{ 6509 .ty = try sema.addType(stack_trace_ty), 6510 .payload = @intCast(u32, field_index), 6511 } }, 6512 }); 6513 6514 // Pop the error return trace, testing the result for non-error if necessary 6515 const operand = if (pop_error_return_trace or modifier == .always_tail) .none else call_inst; 6516 try sema.popErrorReturnTrace(block, call_src, operand, save_inst); 6517 } 6518 6519 if (modifier == .always_tail) // Perform the call *after* the restore, so that a tail call is possible. 6520 return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node); 6521 6522 return call_inst; 6523 } else { 6524 return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node); 6525 } 6526 } 6527 6528 fn checkCallArgumentCount( 6529 sema: *Sema, 6530 block: *Block, 6531 func: Air.Inst.Ref, 6532 func_src: LazySrcLoc, 6533 callee_ty: Type, 6534 total_args: usize, 6535 member_fn: bool, 6536 ) !Type { 6537 const mod = sema.mod; 6538 const func_ty = func_ty: { 6539 switch (callee_ty.zigTypeTag(mod)) { 6540 .Fn => break :func_ty callee_ty, 6541 .Pointer => { 6542 const ptr_info = callee_ty.ptrInfo(mod); 6543 if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag(mod) == .Fn) { 6544 break :func_ty ptr_info.pointee_type; 6545 } 6546 }, 6547 .Optional => { 6548 const opt_child = callee_ty.optionalChild(mod); 6549 if (opt_child.zigTypeTag(mod) == .Fn or (opt_child.isSinglePointer(mod) and 6550 opt_child.childType(mod).zigTypeTag(mod) == .Fn)) 6551 { 6552 const msg = msg: { 6553 const msg = try sema.errMsg(block, func_src, "cannot call optional type '{}'", .{ 6554 callee_ty.fmt(sema.mod), 6555 }); 6556 errdefer msg.destroy(sema.gpa); 6557 try sema.errNote(block, func_src, msg, "consider using '.?', 'orelse' or 'if'", .{}); 6558 break :msg msg; 6559 }; 6560 return sema.failWithOwnedErrorMsg(msg); 6561 } 6562 }, 6563 else => {}, 6564 } 6565 return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)}); 6566 }; 6567 6568 const func_ty_info = mod.typeToFunc(func_ty).?; 6569 const fn_params_len = func_ty_info.param_types.len; 6570 const args_len = total_args - @boolToInt(member_fn); 6571 if (func_ty_info.is_var_args) { 6572 assert(func_ty_info.cc == .C); 6573 if (total_args >= fn_params_len) return func_ty; 6574 } else if (fn_params_len == total_args) { 6575 return func_ty; 6576 } 6577 6578 const maybe_decl = try sema.funcDeclSrc(func); 6579 const member_str = if (member_fn) "member function " else ""; 6580 const variadic_str = if (func_ty_info.is_var_args) "at least " else ""; 6581 const msg = msg: { 6582 const msg = try sema.errMsg( 6583 block, 6584 func_src, 6585 "{s}expected {s}{d} argument(s), found {d}", 6586 .{ 6587 member_str, 6588 variadic_str, 6589 fn_params_len - @boolToInt(member_fn), 6590 args_len, 6591 }, 6592 ); 6593 errdefer msg.destroy(sema.gpa); 6594 6595 if (maybe_decl) |fn_decl| try sema.mod.errNoteNonLazy(fn_decl.srcLoc(mod), msg, "function declared here", .{}); 6596 break :msg msg; 6597 }; 6598 return sema.failWithOwnedErrorMsg(msg); 6599 } 6600 6601 fn callBuiltin( 6602 sema: *Sema, 6603 block: *Block, 6604 builtin_fn: Air.Inst.Ref, 6605 modifier: std.builtin.CallModifier, 6606 args: []const Air.Inst.Ref, 6607 ) !void { 6608 const mod = sema.mod; 6609 const callee_ty = sema.typeOf(builtin_fn); 6610 const func_ty = func_ty: { 6611 switch (callee_ty.zigTypeTag(mod)) { 6612 .Fn => break :func_ty callee_ty, 6613 .Pointer => { 6614 const ptr_info = callee_ty.ptrInfo(mod); 6615 if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag(mod) == .Fn) { 6616 break :func_ty ptr_info.pointee_type; 6617 } 6618 }, 6619 else => {}, 6620 } 6621 std.debug.panic("type '{}' is not a function calling builtin fn", .{callee_ty.fmt(sema.mod)}); 6622 }; 6623 6624 const func_ty_info = mod.typeToFunc(func_ty).?; 6625 const fn_params_len = func_ty_info.param_types.len; 6626 if (args.len != fn_params_len or (func_ty_info.is_var_args and args.len < fn_params_len)) { 6627 std.debug.panic("parameter count mismatch calling builtin fn, expected {d}, found {d}", .{ fn_params_len, args.len }); 6628 } 6629 _ = try sema.analyzeCall(block, builtin_fn, func_ty, sema.src, sema.src, modifier, false, args, null, null); 6630 } 6631 6632 const GenericCallAdapter = struct { 6633 generic_fn: *Module.Fn, 6634 precomputed_hash: u64, 6635 func_ty_info: InternPool.Key.FuncType, 6636 args: []const Arg, 6637 module: *Module, 6638 6639 const Arg = struct { 6640 ty: Type, 6641 val: Value, 6642 is_anytype: bool, 6643 }; 6644 6645 pub fn eql(ctx: @This(), adapted_key: void, other_key: Module.Fn.Index) bool { 6646 _ = adapted_key; 6647 const other_func = ctx.module.funcPtr(other_key); 6648 6649 // Checking for equality may happen on an item that has been inserted 6650 // into the map but is not yet fully initialized. In such case, the 6651 // two initialized fields are `hash` and `generic_owner_decl`. 6652 if (ctx.generic_fn.owner_decl != other_func.generic_owner_decl.unwrap().?) return false; 6653 6654 const other_comptime_args = other_func.comptime_args.?; 6655 for (other_comptime_args[0..ctx.func_ty_info.param_types.len], 0..) |other_arg, i| { 6656 const this_arg = ctx.args[i]; 6657 const this_is_comptime = !this_arg.val.isGenericPoison(); 6658 const other_is_comptime = !other_arg.val.isGenericPoison(); 6659 const this_is_anytype = this_arg.is_anytype; 6660 const other_is_anytype = other_func.isAnytypeParam(ctx.module, @intCast(u32, i)); 6661 6662 if (other_is_anytype != this_is_anytype) return false; 6663 if (other_is_comptime != this_is_comptime) return false; 6664 6665 if (this_is_anytype) { 6666 // Both are anytype parameters. 6667 if (!this_arg.ty.eql(other_arg.ty, ctx.module)) { 6668 return false; 6669 } 6670 if (this_is_comptime) { 6671 // Both are comptime and anytype parameters with matching types. 6672 if (!this_arg.val.eql(other_arg.val, other_arg.ty, ctx.module)) { 6673 return false; 6674 } 6675 } 6676 } else if (this_is_comptime) { 6677 // Both are comptime parameters but not anytype parameters. 6678 // We assert no error is possible here because any lazy values must be resolved 6679 // before inserting into the generic function hash map. 6680 const is_eql = Value.eqlAdvanced( 6681 this_arg.val, 6682 this_arg.ty, 6683 other_arg.val, 6684 other_arg.ty, 6685 ctx.module, 6686 null, 6687 ) catch unreachable; 6688 if (!is_eql) { 6689 return false; 6690 } 6691 } 6692 } 6693 return true; 6694 } 6695 6696 /// The implementation of the hash is in semantic analysis of function calls, so 6697 /// that any errors when computing the hash can be properly reported. 6698 pub fn hash(ctx: @This(), adapted_key: void) u64 { 6699 _ = adapted_key; 6700 return ctx.precomputed_hash; 6701 } 6702 }; 6703 6704 fn analyzeCall( 6705 sema: *Sema, 6706 block: *Block, 6707 func: Air.Inst.Ref, 6708 func_ty: Type, 6709 func_src: LazySrcLoc, 6710 call_src: LazySrcLoc, 6711 modifier: std.builtin.CallModifier, 6712 ensure_result_used: bool, 6713 uncasted_args: []const Air.Inst.Ref, 6714 bound_arg_src: ?LazySrcLoc, 6715 call_dbg_node: ?Zir.Inst.Index, 6716 ) CompileError!Air.Inst.Ref { 6717 const mod = sema.mod; 6718 6719 const callee_ty = sema.typeOf(func); 6720 const func_ty_info = mod.typeToFunc(func_ty).?; 6721 const fn_params_len = func_ty_info.param_types.len; 6722 const cc = func_ty_info.cc; 6723 if (cc == .Naked) { 6724 const maybe_decl = try sema.funcDeclSrc(func); 6725 const msg = msg: { 6726 const msg = try sema.errMsg( 6727 block, 6728 func_src, 6729 "unable to call function with naked calling convention", 6730 .{}, 6731 ); 6732 errdefer msg.destroy(sema.gpa); 6733 6734 if (maybe_decl) |fn_decl| try mod.errNoteNonLazy(fn_decl.srcLoc(mod), msg, "function declared here", .{}); 6735 break :msg msg; 6736 }; 6737 return sema.failWithOwnedErrorMsg(msg); 6738 } 6739 6740 const call_tag: Air.Inst.Tag = switch (modifier) { 6741 .auto, 6742 .always_inline, 6743 .compile_time, 6744 .no_async, 6745 => Air.Inst.Tag.call, 6746 6747 .never_tail => Air.Inst.Tag.call_never_tail, 6748 .never_inline => Air.Inst.Tag.call_never_inline, 6749 .always_tail => Air.Inst.Tag.call_always_tail, 6750 6751 .async_kw => return sema.failWithUseOfAsync(block, call_src), 6752 }; 6753 6754 if (modifier == .never_inline and func_ty_info.cc == .Inline) { 6755 return sema.fail(block, call_src, "'never_inline' call of inline function", .{}); 6756 } 6757 if (modifier == .always_inline and func_ty_info.is_noinline) { 6758 return sema.fail(block, call_src, "'always_inline' call of noinline function", .{}); 6759 } 6760 6761 const gpa = sema.gpa; 6762 6763 var is_generic_call = func_ty_info.is_generic; 6764 var is_comptime_call = block.is_comptime or modifier == .compile_time; 6765 var comptime_reason_buf: Block.ComptimeReason = undefined; 6766 var comptime_reason: ?*const Block.ComptimeReason = null; 6767 if (!is_comptime_call) { 6768 if (sema.typeRequiresComptime(func_ty_info.return_type.toType())) |ct| { 6769 is_comptime_call = ct; 6770 if (ct) { 6771 // stage1 can't handle doing this directly 6772 comptime_reason_buf = .{ .comptime_ret_ty = .{ 6773 .block = block, 6774 .func = func, 6775 .func_src = func_src, 6776 .return_ty = func_ty_info.return_type.toType(), 6777 } }; 6778 comptime_reason = &comptime_reason_buf; 6779 } 6780 } else |err| switch (err) { 6781 error.GenericPoison => is_generic_call = true, 6782 else => |e| return e, 6783 } 6784 } 6785 var is_inline_call = is_comptime_call or modifier == .always_inline or 6786 func_ty_info.cc == .Inline; 6787 6788 if (!is_inline_call and is_generic_call) { 6789 if (sema.instantiateGenericCall( 6790 block, 6791 func, 6792 func_src, 6793 call_src, 6794 func_ty_info, 6795 ensure_result_used, 6796 uncasted_args, 6797 call_tag, 6798 bound_arg_src, 6799 call_dbg_node, 6800 )) |some| { 6801 return some; 6802 } else |err| switch (err) { 6803 error.GenericPoison => { 6804 is_inline_call = true; 6805 }, 6806 error.ComptimeReturn => { 6807 is_inline_call = true; 6808 is_comptime_call = true; 6809 // stage1 can't handle doing this directly 6810 comptime_reason_buf = .{ .comptime_ret_ty = .{ 6811 .block = block, 6812 .func = func, 6813 .func_src = func_src, 6814 .return_ty = func_ty_info.return_type.toType(), 6815 } }; 6816 comptime_reason = &comptime_reason_buf; 6817 }, 6818 else => |e| return e, 6819 } 6820 } 6821 6822 if (is_comptime_call and modifier == .never_inline) { 6823 return sema.fail(block, call_src, "unable to perform 'never_inline' call at compile-time", .{}); 6824 } 6825 6826 const result: Air.Inst.Ref = if (is_inline_call) res: { 6827 const func_val = sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime-known") catch |err| { 6828 if (err == error.AnalysisFail and comptime_reason != null) try comptime_reason.?.explain(sema, sema.err); 6829 return err; 6830 }; 6831 const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) { 6832 .extern_func => return sema.fail(block, call_src, "{s} call of extern function", .{ 6833 @as([]const u8, if (is_comptime_call) "comptime" else "inline"), 6834 }), 6835 .func => |function| function.index, 6836 .ptr => |ptr| switch (ptr.addr) { 6837 .decl => |decl| mod.declPtr(decl).val.getFunctionIndex(mod).unwrap().?, 6838 else => { 6839 assert(callee_ty.isPtrAtRuntime(mod)); 6840 return sema.fail(block, call_src, "{s} call of function pointer", .{ 6841 @as([]const u8, if (is_comptime_call) "comptime" else "inline"), 6842 }); 6843 }, 6844 }, 6845 else => unreachable, 6846 }; 6847 if (func_ty_info.is_var_args) { 6848 return sema.fail(block, call_src, "{s} call of variadic function", .{ 6849 @as([]const u8, if (is_comptime_call) "comptime" else "inline"), 6850 }); 6851 } 6852 6853 // Analyze the ZIR. The same ZIR gets analyzed into a runtime function 6854 // or an inlined call depending on what union tag the `label` field is 6855 // set to in the `Block`. 6856 // This block instruction will be used to capture the return value from the 6857 // inlined function. 6858 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 6859 try sema.air_instructions.append(gpa, .{ 6860 .tag = .block, 6861 .data = undefined, 6862 }); 6863 // This one is shared among sub-blocks within the same callee, but not 6864 // shared among the entire inline/comptime call stack. 6865 var inlining: Block.Inlining = .{ 6866 .func = null, 6867 .comptime_result = undefined, 6868 .merges = .{ 6869 .src_locs = .{}, 6870 .results = .{}, 6871 .br_list = .{}, 6872 .block_inst = block_inst, 6873 }, 6874 }; 6875 // In order to save a bit of stack space, directly modify Sema rather 6876 // than create a child one. 6877 const parent_zir = sema.code; 6878 const module_fn = mod.funcPtr(module_fn_index); 6879 const fn_owner_decl = mod.declPtr(module_fn.owner_decl); 6880 sema.code = fn_owner_decl.getFileScope(mod).zir; 6881 defer sema.code = parent_zir; 6882 6883 try mod.declareDeclDependencyType(sema.owner_decl_index, module_fn.owner_decl, .function_body); 6884 6885 const parent_inst_map = sema.inst_map; 6886 sema.inst_map = .{}; 6887 defer { 6888 sema.src = call_src; 6889 sema.inst_map.deinit(gpa); 6890 sema.inst_map = parent_inst_map; 6891 } 6892 6893 const parent_func = sema.func; 6894 const parent_func_index = sema.func_index; 6895 sema.func = module_fn; 6896 sema.func_index = module_fn_index.toOptional(); 6897 defer sema.func = parent_func; 6898 defer sema.func_index = parent_func_index; 6899 6900 const parent_err_ret_index = sema.error_return_trace_index_on_fn_entry; 6901 sema.error_return_trace_index_on_fn_entry = block.error_return_trace_index; 6902 defer sema.error_return_trace_index_on_fn_entry = parent_err_ret_index; 6903 6904 var wip_captures = try WipCaptureScope.init(gpa, fn_owner_decl.src_scope); 6905 defer wip_captures.deinit(); 6906 6907 var child_block: Block = .{ 6908 .parent = null, 6909 .sema = sema, 6910 .src_decl = module_fn.owner_decl, 6911 .namespace = fn_owner_decl.src_namespace, 6912 .wip_capture_scope = wip_captures.scope, 6913 .instructions = .{}, 6914 .label = null, 6915 .inlining = &inlining, 6916 .is_typeof = block.is_typeof, 6917 .is_comptime = is_comptime_call, 6918 .comptime_reason = comptime_reason, 6919 .error_return_trace_index = block.error_return_trace_index, 6920 }; 6921 6922 const merges = &child_block.inlining.?.merges; 6923 6924 defer child_block.instructions.deinit(gpa); 6925 defer merges.deinit(gpa); 6926 6927 try sema.emitBackwardBranch(block, call_src); 6928 6929 // Whether this call should be memoized, set to false if the call can mutate comptime state. 6930 var should_memoize = true; 6931 6932 // If it's a comptime function call, we need to memoize it as long as no external 6933 // comptime memory is mutated. 6934 const memoized_arg_values = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len); 6935 6936 var new_fn_info = mod.typeToFunc(fn_owner_decl.ty).?; 6937 new_fn_info.param_types = try sema.arena.alloc(InternPool.Index, new_fn_info.param_types.len); 6938 new_fn_info.comptime_bits = 0; 6939 6940 // This will have return instructions analyzed as break instructions to 6941 // the block_inst above. Here we are performing "comptime/inline semantic analysis" 6942 // for a function body, which means we must map the parameter ZIR instructions to 6943 // the AIR instructions of the callsite. The callee could be a generic function 6944 // which means its parameter type expressions must be resolved in order and used 6945 // to successively coerce the arguments. 6946 const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst); 6947 try sema.inst_map.ensureSpaceForInstructions(sema.gpa, fn_info.param_body); 6948 6949 var has_comptime_args = false; 6950 var arg_i: usize = 0; 6951 for (fn_info.param_body) |inst| { 6952 sema.analyzeInlineCallArg( 6953 block, 6954 &child_block, 6955 .unneeded, 6956 inst, 6957 &new_fn_info, 6958 &arg_i, 6959 uncasted_args, 6960 is_comptime_call, 6961 &should_memoize, 6962 memoized_arg_values, 6963 mod.typeToFunc(func_ty).?.param_types, 6964 func, 6965 &has_comptime_args, 6966 ) catch |err| switch (err) { 6967 error.NeededSourceLocation => { 6968 _ = sema.inst_map.remove(inst); 6969 const decl = sema.mod.declPtr(block.src_decl); 6970 try sema.analyzeInlineCallArg( 6971 block, 6972 &child_block, 6973 mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src), 6974 inst, 6975 &new_fn_info, 6976 &arg_i, 6977 uncasted_args, 6978 is_comptime_call, 6979 &should_memoize, 6980 memoized_arg_values, 6981 mod.typeToFunc(func_ty).?.param_types, 6982 func, 6983 &has_comptime_args, 6984 ); 6985 unreachable; 6986 }, 6987 else => |e| return e, 6988 }; 6989 } 6990 6991 if (!has_comptime_args and module_fn.state == .sema_failure) return error.AnalysisFail; 6992 6993 const recursive_msg = "inline call is recursive"; 6994 var head = if (!has_comptime_args) block else null; 6995 while (head) |some| { 6996 const parent_inlining = some.inlining orelse break; 6997 if (parent_inlining.func == module_fn) { 6998 return sema.fail(block, call_src, recursive_msg, .{}); 6999 } 7000 head = some.parent; 7001 } 7002 if (!has_comptime_args) inlining.func = module_fn; 7003 7004 // In case it is a generic function with an expression for the return type that depends 7005 // on parameters, we must now do the same for the return type as we just did with 7006 // each of the parameters, resolving the return type and providing it to the child 7007 // `Sema` so that it can be used for the `ret_ptr` instruction. 7008 const ret_ty_inst = if (fn_info.ret_ty_body.len != 0) 7009 try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst) 7010 else 7011 try sema.resolveInst(fn_info.ret_ty_ref); 7012 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; 7013 const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst); 7014 // Create a fresh inferred error set type for inline/comptime calls. 7015 const fn_ret_ty = blk: { 7016 if (module_fn.hasInferredErrorSet(mod)) { 7017 const ies_index = try mod.intern_pool.createInferredErrorSet(gpa, .{ 7018 .func = module_fn_index, 7019 }); 7020 const error_set_ty = try mod.intern(.{ .inferred_error_set_type = ies_index }); 7021 break :blk try mod.errorUnionType(error_set_ty.toType(), bare_return_type); 7022 } 7023 break :blk bare_return_type; 7024 }; 7025 new_fn_info.return_type = fn_ret_ty.toIntern(); 7026 const parent_fn_ret_ty = sema.fn_ret_ty; 7027 sema.fn_ret_ty = fn_ret_ty; 7028 defer sema.fn_ret_ty = parent_fn_ret_ty; 7029 7030 // This `res2` is here instead of directly breaking from `res` due to a stage1 7031 // bug generating invalid LLVM IR. 7032 const res2: Air.Inst.Ref = res2: { 7033 if (should_memoize and is_comptime_call) { 7034 if (mod.intern_pool.getIfExists(.{ .memoized_call = .{ 7035 .func = module_fn_index, 7036 .arg_values = memoized_arg_values, 7037 .result = .none, 7038 } })) |memoized_call_index| { 7039 const memoized_call = mod.intern_pool.indexToKey(memoized_call_index).memoized_call; 7040 break :res2 try sema.addConstant( 7041 mod.intern_pool.typeOf(memoized_call.result).toType(), 7042 memoized_call.result.toValue(), 7043 ); 7044 } 7045 } 7046 7047 const new_func_resolved_ty = try mod.funcType(new_fn_info); 7048 if (!is_comptime_call and !block.is_typeof) { 7049 try sema.emitDbgInline(block, parent_func_index.unwrap().?, module_fn_index, new_func_resolved_ty, .dbg_inline_begin); 7050 7051 const zir_tags = sema.code.instructions.items(.tag); 7052 for (fn_info.param_body) |param| switch (zir_tags[param]) { 7053 .param, .param_comptime => { 7054 const inst_data = sema.code.instructions.items(.data)[param].pl_tok; 7055 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index); 7056 const param_name = sema.code.nullTerminatedString(extra.data.name); 7057 const inst = sema.inst_map.get(param).?; 7058 7059 try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name); 7060 }, 7061 .param_anytype, .param_anytype_comptime => { 7062 const inst_data = sema.code.instructions.items(.data)[param].str_tok; 7063 const param_name = inst_data.get(sema.code); 7064 const inst = sema.inst_map.get(param).?; 7065 7066 try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name); 7067 }, 7068 else => continue, 7069 }; 7070 } 7071 7072 if (is_comptime_call and ensure_result_used) { 7073 try sema.ensureResultUsed(block, fn_ret_ty, call_src); 7074 } 7075 7076 const result = result: { 7077 sema.analyzeBody(&child_block, fn_info.body) catch |err| switch (err) { 7078 error.ComptimeReturn => break :result inlining.comptime_result, 7079 error.AnalysisFail => { 7080 const err_msg = sema.err orelse return err; 7081 if (mem.eql(u8, err_msg.msg, recursive_msg)) return err; 7082 try sema.errNote(block, call_src, err_msg, "called from here", .{}); 7083 err_msg.clearTrace(sema.gpa); 7084 return err; 7085 }, 7086 else => |e| return e, 7087 }; 7088 break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges); 7089 }; 7090 7091 if (!is_comptime_call and !block.is_typeof and sema.typeOf(result).zigTypeTag(mod) != .NoReturn) { 7092 try sema.emitDbgInline( 7093 block, 7094 module_fn_index, 7095 parent_func_index.unwrap().?, 7096 mod.declPtr(parent_func.?.owner_decl).ty, 7097 .dbg_inline_end, 7098 ); 7099 } 7100 7101 if (should_memoize and is_comptime_call) { 7102 const result_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, result, ""); 7103 7104 // TODO: check whether any external comptime memory was mutated by the 7105 // comptime function call. If so, then do not memoize the call here. 7106 _ = try mod.intern(.{ .memoized_call = .{ 7107 .func = module_fn_index, 7108 .arg_values = memoized_arg_values, 7109 .result = try result_val.intern(fn_ret_ty, mod), 7110 } }); 7111 } 7112 7113 break :res2 result; 7114 }; 7115 7116 try wip_captures.finalize(); 7117 7118 break :res res2; 7119 } else res: { 7120 assert(!func_ty_info.is_generic); 7121 7122 const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len); 7123 for (uncasted_args, 0..) |uncasted_arg, i| { 7124 if (i < fn_params_len) { 7125 const opts: CoerceOpts = .{ .param_src = .{ 7126 .func_inst = func, 7127 .param_i = @intCast(u32, i), 7128 } }; 7129 const param_ty = mod.typeToFunc(func_ty).?.param_types[i].toType(); 7130 args[i] = sema.analyzeCallArg( 7131 block, 7132 .unneeded, 7133 param_ty, 7134 uncasted_arg, 7135 opts, 7136 ) catch |err| switch (err) { 7137 error.NeededSourceLocation => { 7138 const decl = sema.mod.declPtr(block.src_decl); 7139 _ = try sema.analyzeCallArg( 7140 block, 7141 mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src), 7142 param_ty, 7143 uncasted_arg, 7144 opts, 7145 ); 7146 unreachable; 7147 }, 7148 else => |e| return e, 7149 }; 7150 } else { 7151 args[i] = sema.coerceVarArgParam(block, uncasted_arg, .unneeded) catch |err| switch (err) { 7152 error.NeededSourceLocation => { 7153 const decl = sema.mod.declPtr(block.src_decl); 7154 _ = try sema.coerceVarArgParam( 7155 block, 7156 uncasted_arg, 7157 mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src), 7158 ); 7159 unreachable; 7160 }, 7161 else => |e| return e, 7162 }; 7163 } 7164 } 7165 7166 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); 7167 7168 try sema.queueFullTypeResolution(func_ty_info.return_type.toType()); 7169 if (sema.owner_func != null and func_ty_info.return_type.toType().isError(mod)) { 7170 sema.owner_func.?.calls_or_awaits_errorable_fn = true; 7171 } 7172 7173 if (try sema.resolveMaybeUndefVal(func)) |func_val| { 7174 if (mod.intern_pool.indexToFunc(func_val.toIntern()).unwrap()) |func_index| { 7175 try sema.mod.ensureFuncBodyAnalysisQueued(func_index); 7176 } 7177 } 7178 7179 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len + 7180 args.len); 7181 const func_inst = try block.addInst(.{ 7182 .tag = call_tag, 7183 .data = .{ .pl_op = .{ 7184 .operand = func, 7185 .payload = sema.addExtraAssumeCapacity(Air.Call{ 7186 .args_len = @intCast(u32, args.len), 7187 }), 7188 } }, 7189 }); 7190 sema.appendRefsAssumeCapacity(args); 7191 7192 if (call_tag == .call_always_tail) { 7193 if (ensure_result_used) { 7194 try sema.ensureResultUsed(block, sema.typeOf(func_inst), call_src); 7195 } 7196 return sema.handleTailCall(block, call_src, func_ty, func_inst); 7197 } else if (block.wantSafety() and func_ty_info.return_type == .noreturn_type) { 7198 // Function pointers and extern functions aren't guaranteed to 7199 // actually be noreturn so we add a safety check for them. 7200 check: { 7201 const func_val = (try sema.resolveMaybeUndefVal(func)) orelse break :check; 7202 switch (mod.intern_pool.indexToKey(func_val.toIntern())) { 7203 .func, .extern_func, .ptr => { 7204 _ = try block.addNoOp(.unreach); 7205 return Air.Inst.Ref.unreachable_value; 7206 }, 7207 else => break :check, 7208 } 7209 } 7210 7211 try sema.safetyPanic(block, .noreturn_returned); 7212 return Air.Inst.Ref.unreachable_value; 7213 } else if (func_ty_info.return_type == .noreturn_type) { 7214 _ = try block.addNoOp(.unreach); 7215 return Air.Inst.Ref.unreachable_value; 7216 } 7217 break :res func_inst; 7218 }; 7219 7220 if (ensure_result_used) { 7221 try sema.ensureResultUsed(block, sema.typeOf(result), call_src); 7222 } 7223 return result; 7224 } 7225 7226 fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref { 7227 const target = sema.mod.getTarget(); 7228 const backend = sema.mod.comp.getZigBackend(); 7229 if (!target_util.supportsTailCall(target, backend)) { 7230 return sema.fail(block, call_src, "unable to perform tail call: compiler backend '{s}' does not support tail calls on target architecture '{s}' with the selected CPU feature flags", .{ 7231 @tagName(backend), @tagName(target.cpu.arch), 7232 }); 7233 } 7234 const func_decl = sema.mod.declPtr(sema.owner_func.?.owner_decl); 7235 if (!func_ty.eql(func_decl.ty, sema.mod)) { 7236 return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{ 7237 func_ty.fmt(sema.mod), func_decl.ty.fmt(sema.mod), 7238 }); 7239 } 7240 _ = try block.addUnOp(.ret, result); 7241 return Air.Inst.Ref.unreachable_value; 7242 } 7243 7244 fn analyzeInlineCallArg( 7245 sema: *Sema, 7246 arg_block: *Block, 7247 param_block: *Block, 7248 arg_src: LazySrcLoc, 7249 inst: Zir.Inst.Index, 7250 new_fn_info: *InternPool.Key.FuncType, 7251 arg_i: *usize, 7252 uncasted_args: []const Air.Inst.Ref, 7253 is_comptime_call: bool, 7254 should_memoize: *bool, 7255 memoized_arg_values: []InternPool.Index, 7256 raw_param_types: []const InternPool.Index, 7257 func_inst: Air.Inst.Ref, 7258 has_comptime_args: *bool, 7259 ) !void { 7260 const mod = sema.mod; 7261 const zir_tags = sema.code.instructions.items(.tag); 7262 switch (zir_tags[inst]) { 7263 .param_comptime, .param_anytype_comptime => has_comptime_args.* = true, 7264 else => {}, 7265 } 7266 switch (zir_tags[inst]) { 7267 .param, .param_comptime => { 7268 // Evaluate the parameter type expression now that previous ones have 7269 // been mapped, and coerce the corresponding argument to it. 7270 const pl_tok = sema.code.instructions.items(.data)[inst].pl_tok; 7271 const param_src = pl_tok.src(); 7272 const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index); 7273 const param_body = sema.code.extra[extra.end..][0..extra.data.body_len]; 7274 const param_ty = param_ty: { 7275 const raw_param_ty = raw_param_types[arg_i.*]; 7276 if (raw_param_ty != .generic_poison_type) break :param_ty raw_param_ty; 7277 const param_ty_inst = try sema.resolveBody(param_block, param_body, inst); 7278 const param_ty = try sema.analyzeAsType(param_block, param_src, param_ty_inst); 7279 break :param_ty param_ty.toIntern(); 7280 }; 7281 new_fn_info.param_types[arg_i.*] = param_ty; 7282 const uncasted_arg = uncasted_args[arg_i.*]; 7283 if (try sema.typeRequiresComptime(param_ty.toType())) { 7284 _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime-only type must be comptime-known") catch |err| { 7285 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); 7286 return err; 7287 }; 7288 } else if (!is_comptime_call and zir_tags[inst] == .param_comptime) { 7289 _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime"); 7290 } 7291 const casted_arg = sema.coerceExtra(arg_block, param_ty.toType(), uncasted_arg, arg_src, .{ .param_src = .{ 7292 .func_inst = func_inst, 7293 .param_i = @intCast(u32, arg_i.*), 7294 } }) catch |err| switch (err) { 7295 error.NotCoercible => unreachable, 7296 else => |e| return e, 7297 }; 7298 7299 if (is_comptime_call) { 7300 sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg); 7301 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime-known") catch |err| { 7302 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); 7303 return err; 7304 }; 7305 switch (arg_val.toIntern()) { 7306 .generic_poison, .generic_poison_type => { 7307 // This function is currently evaluated as part of an as-of-yet unresolvable 7308 // parameter or return type. 7309 return error.GenericPoison; 7310 }, 7311 else => {}, 7312 } 7313 // Needed so that lazy values do not trigger 7314 // assertion due to type not being resolved 7315 // when the hash function is called. 7316 const resolved_arg_val = try sema.resolveLazyValue(arg_val); 7317 should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod); 7318 memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(param_ty.toType(), mod); 7319 } else { 7320 sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg); 7321 } 7322 7323 if (try sema.resolveMaybeUndefVal(casted_arg)) |_| { 7324 has_comptime_args.* = true; 7325 } 7326 7327 arg_i.* += 1; 7328 }, 7329 .param_anytype, .param_anytype_comptime => { 7330 // No coercion needed. 7331 const uncasted_arg = uncasted_args[arg_i.*]; 7332 new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg).toIntern(); 7333 7334 if (is_comptime_call) { 7335 sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); 7336 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime-known") catch |err| { 7337 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); 7338 return err; 7339 }; 7340 switch (arg_val.toIntern()) { 7341 .generic_poison, .generic_poison_type => { 7342 // This function is currently evaluated as part of an as-of-yet unresolvable 7343 // parameter or return type. 7344 return error.GenericPoison; 7345 }, 7346 else => {}, 7347 } 7348 // Needed so that lazy values do not trigger 7349 // assertion due to type not being resolved 7350 // when the hash function is called. 7351 const resolved_arg_val = try sema.resolveLazyValue(arg_val); 7352 should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod); 7353 memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(sema.typeOf(uncasted_arg), mod); 7354 } else { 7355 if (zir_tags[inst] == .param_anytype_comptime) { 7356 _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime"); 7357 } 7358 sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); 7359 } 7360 7361 if (try sema.resolveMaybeUndefVal(uncasted_arg)) |_| { 7362 has_comptime_args.* = true; 7363 } 7364 7365 arg_i.* += 1; 7366 }, 7367 else => {}, 7368 } 7369 } 7370 7371 fn analyzeCallArg( 7372 sema: *Sema, 7373 block: *Block, 7374 arg_src: LazySrcLoc, 7375 param_ty: Type, 7376 uncasted_arg: Air.Inst.Ref, 7377 opts: CoerceOpts, 7378 ) !Air.Inst.Ref { 7379 try sema.resolveTypeFully(param_ty); 7380 return sema.coerceExtra(block, param_ty, uncasted_arg, arg_src, opts) catch |err| switch (err) { 7381 error.NotCoercible => unreachable, 7382 else => |e| return e, 7383 }; 7384 } 7385 7386 fn analyzeGenericCallArg( 7387 sema: *Sema, 7388 block: *Block, 7389 arg_src: LazySrcLoc, 7390 uncasted_arg: Air.Inst.Ref, 7391 comptime_arg: TypedValue, 7392 runtime_args: []Air.Inst.Ref, 7393 new_fn_info: InternPool.Key.FuncType, 7394 runtime_i: *u32, 7395 ) !void { 7396 const mod = sema.mod; 7397 const is_runtime = comptime_arg.val.isGenericPoison() and 7398 comptime_arg.ty.hasRuntimeBits(mod) and 7399 !(try sema.typeRequiresComptime(comptime_arg.ty)); 7400 if (is_runtime) { 7401 const param_ty = new_fn_info.param_types[runtime_i.*].toType(); 7402 const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src); 7403 try sema.queueFullTypeResolution(param_ty); 7404 runtime_args[runtime_i.*] = casted_arg; 7405 runtime_i.* += 1; 7406 } else if (try sema.typeHasOnePossibleValue(comptime_arg.ty)) |_| { 7407 _ = try sema.coerce(block, comptime_arg.ty, uncasted_arg, arg_src); 7408 } 7409 } 7410 7411 fn analyzeGenericCallArgVal(sema: *Sema, block: *Block, arg_src: LazySrcLoc, uncasted_arg: Air.Inst.Ref) !Value { 7412 return sema.resolveLazyValue(try sema.resolveValue(block, arg_src, uncasted_arg, "parameter is comptime")); 7413 } 7414 7415 fn instantiateGenericCall( 7416 sema: *Sema, 7417 block: *Block, 7418 func: Air.Inst.Ref, 7419 func_src: LazySrcLoc, 7420 call_src: LazySrcLoc, 7421 func_ty_info: InternPool.Key.FuncType, 7422 ensure_result_used: bool, 7423 uncasted_args: []const Air.Inst.Ref, 7424 call_tag: Air.Inst.Tag, 7425 bound_arg_src: ?LazySrcLoc, 7426 call_dbg_node: ?Zir.Inst.Index, 7427 ) CompileError!Air.Inst.Ref { 7428 const mod = sema.mod; 7429 const gpa = sema.gpa; 7430 7431 const func_val = try sema.resolveConstValue(block, func_src, func, "generic function being called must be comptime-known"); 7432 const module_fn = mod.funcPtr(switch (mod.intern_pool.indexToKey(func_val.toIntern())) { 7433 .func => |function| function.index, 7434 .ptr => |ptr| mod.declPtr(ptr.addr.decl).val.getFunctionIndex(mod).unwrap().?, 7435 else => unreachable, 7436 }); 7437 // Check the Module's generic function map with an adapted context, so that we 7438 // can match against `uncasted_args` rather than doing the work below to create a 7439 // generic Scope only to junk it if it matches an existing instantiation. 7440 const fn_owner_decl = mod.declPtr(module_fn.owner_decl); 7441 const namespace_index = fn_owner_decl.src_namespace; 7442 const namespace = mod.namespacePtr(namespace_index); 7443 const fn_zir = namespace.file_scope.zir; 7444 const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); 7445 const zir_tags = fn_zir.instructions.items(.tag); 7446 7447 // This hash must match `Module.MonomorphedFuncsContext.hash`. 7448 // For parameters explicitly marked comptime and simple parameter type expressions, 7449 // we know whether a parameter is elided from a monomorphed function, and can 7450 // use it in the hash here. However, for parameter type expressions that are not 7451 // explicitly marked comptime and rely on previous parameter comptime values, we 7452 // don't find out until after generating a monomorphed function whether the parameter 7453 // type ended up being a "must-be-comptime-known" type. 7454 var hasher = std.hash.Wyhash.init(0); 7455 std.hash.autoHash(&hasher, module_fn.owner_decl); 7456 7457 const generic_args = try sema.arena.alloc(GenericCallAdapter.Arg, func_ty_info.param_types.len); 7458 { 7459 var i: usize = 0; 7460 for (fn_info.param_body) |inst| { 7461 var is_comptime = false; 7462 var is_anytype = false; 7463 switch (zir_tags[inst]) { 7464 .param => { 7465 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, i)); 7466 }, 7467 .param_comptime => { 7468 is_comptime = true; 7469 }, 7470 .param_anytype => { 7471 is_anytype = true; 7472 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, i)); 7473 }, 7474 .param_anytype_comptime => { 7475 is_anytype = true; 7476 is_comptime = true; 7477 }, 7478 else => continue, 7479 } 7480 7481 const arg_ty = sema.typeOf(uncasted_args[i]); 7482 if (is_comptime or is_anytype) { 7483 // Tuple default values are a part of the type and need to be 7484 // resolved to hash the type. 7485 try sema.resolveTupleLazyValues(block, call_src, arg_ty); 7486 } 7487 7488 if (is_comptime) { 7489 const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[i]) catch |err| switch (err) { 7490 error.NeededSourceLocation => { 7491 const decl = sema.mod.declPtr(block.src_decl); 7492 const arg_src = mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src); 7493 _ = try sema.analyzeGenericCallArgVal(block, arg_src, uncasted_args[i]); 7494 unreachable; 7495 }, 7496 else => |e| return e, 7497 }; 7498 arg_val.hashUncoerced(arg_ty, &hasher, mod); 7499 if (is_anytype) { 7500 std.hash.autoHash(&hasher, arg_ty.toIntern()); 7501 generic_args[i] = .{ 7502 .ty = arg_ty, 7503 .val = arg_val, 7504 .is_anytype = true, 7505 }; 7506 } else { 7507 generic_args[i] = .{ 7508 .ty = arg_ty, 7509 .val = arg_val, 7510 .is_anytype = false, 7511 }; 7512 } 7513 } else if (is_anytype) { 7514 std.hash.autoHash(&hasher, arg_ty.toIntern()); 7515 generic_args[i] = .{ 7516 .ty = arg_ty, 7517 .val = Value.generic_poison, 7518 .is_anytype = true, 7519 }; 7520 } else { 7521 generic_args[i] = .{ 7522 .ty = arg_ty, 7523 .val = Value.generic_poison, 7524 .is_anytype = false, 7525 }; 7526 } 7527 7528 i += 1; 7529 } 7530 } 7531 7532 const precomputed_hash = hasher.final(); 7533 7534 const adapter: GenericCallAdapter = .{ 7535 .generic_fn = module_fn, 7536 .precomputed_hash = precomputed_hash, 7537 .func_ty_info = func_ty_info, 7538 .args = generic_args, 7539 .module = mod, 7540 }; 7541 const gop = try mod.monomorphed_funcs.getOrPutContextAdapted(gpa, {}, adapter, .{ .mod = mod }); 7542 const callee_index = if (!gop.found_existing) callee: { 7543 const new_module_func_index = try mod.createFunc(undefined); 7544 const new_module_func = mod.funcPtr(new_module_func_index); 7545 7546 // This ensures that we can operate on the hash map before the Module.Fn 7547 // struct is fully initialized. 7548 new_module_func.hash = precomputed_hash; 7549 new_module_func.generic_owner_decl = module_fn.owner_decl.toOptional(); 7550 new_module_func.comptime_args = null; 7551 gop.key_ptr.* = new_module_func_index; 7552 7553 try namespace.anon_decls.ensureUnusedCapacity(gpa, 1); 7554 7555 // Create a Decl for the new function. 7556 const src_decl_index = namespace.getDeclIndex(mod); 7557 const src_decl = mod.declPtr(src_decl_index); 7558 const new_decl_index = try mod.allocateNewDecl(namespace_index, fn_owner_decl.src_node, src_decl.src_scope); 7559 const new_decl = mod.declPtr(new_decl_index); 7560 // TODO better names for generic function instantiations 7561 const decl_name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{ 7562 fn_owner_decl.name, @enumToInt(new_decl_index), 7563 }); 7564 new_decl.name = decl_name; 7565 new_decl.src_line = fn_owner_decl.src_line; 7566 new_decl.is_pub = fn_owner_decl.is_pub; 7567 new_decl.is_exported = fn_owner_decl.is_exported; 7568 new_decl.has_align = fn_owner_decl.has_align; 7569 new_decl.has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace; 7570 new_decl.@"linksection" = fn_owner_decl.@"linksection"; 7571 new_decl.@"addrspace" = fn_owner_decl.@"addrspace"; 7572 new_decl.zir_decl_index = fn_owner_decl.zir_decl_index; 7573 new_decl.alive = true; // This Decl is called at runtime. 7574 new_decl.analysis = .in_progress; 7575 new_decl.generation = mod.generation; 7576 7577 namespace.anon_decls.putAssumeCapacityNoClobber(new_decl_index, {}); 7578 7579 // The generic function Decl is guaranteed to be the first dependency 7580 // of each of its instantiations. 7581 assert(new_decl.dependencies.keys().len == 0); 7582 try mod.declareDeclDependencyType(new_decl_index, module_fn.owner_decl, .function_body); 7583 7584 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); 7585 const new_decl_arena_allocator = new_decl_arena.allocator(); 7586 7587 const new_func = sema.resolveGenericInstantiationType( 7588 block, 7589 new_decl_arena_allocator, 7590 fn_zir, 7591 new_decl, 7592 new_decl_index, 7593 uncasted_args, 7594 module_fn, 7595 new_module_func_index, 7596 namespace_index, 7597 func_ty_info, 7598 call_src, 7599 bound_arg_src, 7600 ) catch |err| switch (err) { 7601 error.GenericPoison, error.ComptimeReturn => { 7602 new_decl_arena.deinit(); 7603 // Resolving the new function type below will possibly declare more decl dependencies 7604 // and so we remove them all here in case of error. 7605 for (new_decl.dependencies.keys()) |dep_index| { 7606 const dep = mod.declPtr(dep_index); 7607 dep.removeDependant(new_decl_index); 7608 } 7609 assert(namespace.anon_decls.orderedRemove(new_decl_index)); 7610 mod.destroyDecl(new_decl_index); 7611 assert(mod.monomorphed_funcs.removeContext(new_module_func_index, .{ .mod = mod })); 7612 mod.destroyFunc(new_module_func_index); 7613 return err; 7614 }, 7615 else => { 7616 assert(mod.monomorphed_funcs.removeContext(new_module_func_index, .{ .mod = mod })); 7617 { 7618 errdefer new_decl_arena.deinit(); 7619 try new_decl.finalizeNewArena(&new_decl_arena); 7620 } 7621 // TODO look up the compile error that happened here and attach a note to it 7622 // pointing here, at the generic instantiation callsite. 7623 if (sema.owner_func) |owner_func| { 7624 owner_func.state = .dependency_failure; 7625 } else { 7626 sema.owner_decl.analysis = .dependency_failure; 7627 } 7628 return err; 7629 }, 7630 }; 7631 errdefer new_decl_arena.deinit(); 7632 7633 try new_decl.finalizeNewArena(&new_decl_arena); 7634 break :callee new_func; 7635 } else gop.key_ptr.*; 7636 const callee = mod.funcPtr(callee_index); 7637 7638 callee.branch_quota = @max(callee.branch_quota, sema.branch_quota); 7639 7640 const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl); 7641 7642 // Make a runtime call to the new function, making sure to omit the comptime args. 7643 const comptime_args = callee.comptime_args.?; 7644 const func_ty = mod.declPtr(callee.owner_decl).ty; 7645 const new_fn_info = mod.typeToFunc(func_ty).?; 7646 const runtime_args_len = @intCast(u32, new_fn_info.param_types.len); 7647 const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len); 7648 { 7649 var runtime_i: u32 = 0; 7650 var total_i: u32 = 0; 7651 for (fn_info.param_body) |inst| { 7652 switch (zir_tags[inst]) { 7653 .param_comptime, .param_anytype_comptime, .param, .param_anytype => {}, 7654 else => continue, 7655 } 7656 sema.analyzeGenericCallArg( 7657 block, 7658 .unneeded, 7659 uncasted_args[total_i], 7660 comptime_args[total_i], 7661 runtime_args, 7662 new_fn_info, 7663 &runtime_i, 7664 ) catch |err| switch (err) { 7665 error.NeededSourceLocation => { 7666 const decl = sema.mod.declPtr(block.src_decl); 7667 _ = try sema.analyzeGenericCallArg( 7668 block, 7669 mod.argSrc(call_src.node_offset.x, decl, total_i, bound_arg_src), 7670 uncasted_args[total_i], 7671 comptime_args[total_i], 7672 runtime_args, 7673 new_fn_info, 7674 &runtime_i, 7675 ); 7676 unreachable; 7677 }, 7678 else => |e| return e, 7679 }; 7680 total_i += 1; 7681 } 7682 7683 try sema.queueFullTypeResolution(new_fn_info.return_type.toType()); 7684 } 7685 7686 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); 7687 7688 if (sema.owner_func != null and new_fn_info.return_type.toType().isError(mod)) { 7689 sema.owner_func.?.calls_or_awaits_errorable_fn = true; 7690 } 7691 7692 try sema.mod.ensureFuncBodyAnalysisQueued(callee_index); 7693 7694 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + 7695 runtime_args_len); 7696 const result = try block.addInst(.{ 7697 .tag = call_tag, 7698 .data = .{ .pl_op = .{ 7699 .operand = callee_inst, 7700 .payload = sema.addExtraAssumeCapacity(Air.Call{ 7701 .args_len = runtime_args_len, 7702 }), 7703 } }, 7704 }); 7705 sema.appendRefsAssumeCapacity(runtime_args); 7706 7707 if (ensure_result_used) { 7708 try sema.ensureResultUsed(block, sema.typeOf(result), call_src); 7709 } 7710 if (call_tag == .call_always_tail) { 7711 return sema.handleTailCall(block, call_src, func_ty, result); 7712 } 7713 if (new_fn_info.return_type == .noreturn_type) { 7714 _ = try block.addNoOp(.unreach); 7715 return Air.Inst.Ref.unreachable_value; 7716 } 7717 return result; 7718 } 7719 7720 fn resolveGenericInstantiationType( 7721 sema: *Sema, 7722 block: *Block, 7723 new_decl_arena_allocator: Allocator, 7724 fn_zir: Zir, 7725 new_decl: *Decl, 7726 new_decl_index: Decl.Index, 7727 uncasted_args: []const Air.Inst.Ref, 7728 module_fn: *Module.Fn, 7729 new_module_func: Module.Fn.Index, 7730 namespace: Namespace.Index, 7731 func_ty_info: InternPool.Key.FuncType, 7732 call_src: LazySrcLoc, 7733 bound_arg_src: ?LazySrcLoc, 7734 ) !Module.Fn.Index { 7735 const mod = sema.mod; 7736 const gpa = sema.gpa; 7737 7738 const zir_tags = fn_zir.instructions.items(.tag); 7739 const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); 7740 7741 // Re-run the block that creates the function, with the comptime parameters 7742 // pre-populated inside `inst_map`. This causes `param_comptime` and 7743 // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a 7744 // new, monomorphized function, with the comptime parameters elided. 7745 var child_sema: Sema = .{ 7746 .mod = mod, 7747 .gpa = gpa, 7748 .arena = sema.arena, 7749 .perm_arena = new_decl_arena_allocator, 7750 .code = fn_zir, 7751 .owner_decl = new_decl, 7752 .owner_decl_index = new_decl_index, 7753 .func = null, 7754 .func_index = .none, 7755 .fn_ret_ty = Type.void, 7756 .owner_func = null, 7757 .owner_func_index = .none, 7758 .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len), 7759 .comptime_args_fn_inst = module_fn.zir_body_inst, 7760 .preallocated_new_func = new_module_func.toOptional(), 7761 .is_generic_instantiation = true, 7762 .branch_quota = sema.branch_quota, 7763 .branch_count = sema.branch_count, 7764 }; 7765 defer child_sema.deinit(); 7766 7767 var wip_captures = try WipCaptureScope.init(gpa, new_decl.src_scope); 7768 defer wip_captures.deinit(); 7769 7770 var child_block: Block = .{ 7771 .parent = null, 7772 .sema = &child_sema, 7773 .src_decl = new_decl_index, 7774 .namespace = namespace, 7775 .wip_capture_scope = wip_captures.scope, 7776 .instructions = .{}, 7777 .inlining = null, 7778 .is_comptime = true, 7779 }; 7780 defer { 7781 child_block.instructions.deinit(gpa); 7782 child_block.params.deinit(gpa); 7783 } 7784 7785 try child_sema.inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body); 7786 7787 var arg_i: usize = 0; 7788 for (fn_info.param_body) |inst| { 7789 var is_comptime = false; 7790 var is_anytype = false; 7791 switch (zir_tags[inst]) { 7792 .param => { 7793 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i)); 7794 }, 7795 .param_comptime => { 7796 is_comptime = true; 7797 }, 7798 .param_anytype => { 7799 is_anytype = true; 7800 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i)); 7801 }, 7802 .param_anytype_comptime => { 7803 is_anytype = true; 7804 is_comptime = true; 7805 }, 7806 else => continue, 7807 } 7808 const arg = uncasted_args[arg_i]; 7809 if (is_comptime) { 7810 const arg_val = (try sema.resolveMaybeUndefVal(arg)).?; 7811 const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val); 7812 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); 7813 } else if (is_anytype) { 7814 const arg_ty = sema.typeOf(arg); 7815 if (try sema.typeRequiresComptime(arg_ty)) { 7816 const arg_val = sema.resolveConstValue(block, .unneeded, arg, "") catch |err| switch (err) { 7817 error.NeededSourceLocation => { 7818 const decl = sema.mod.declPtr(block.src_decl); 7819 const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src); 7820 _ = try sema.resolveConstValue(block, arg_src, arg, "argument to parameter with comptime-only type must be comptime-known"); 7821 unreachable; 7822 }, 7823 else => |e| return e, 7824 }; 7825 const child_arg = try child_sema.addConstant(arg_ty, arg_val); 7826 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); 7827 } else { 7828 // We insert into the map an instruction which is runtime-known 7829 // but has the type of the argument. 7830 const child_arg = try child_block.addInst(.{ 7831 .tag = .arg, 7832 .data = .{ .arg = .{ 7833 .ty = try child_sema.addType(arg_ty), 7834 .src_index = @intCast(u32, arg_i), 7835 } }, 7836 }); 7837 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); 7838 } 7839 } 7840 arg_i += 1; 7841 } 7842 7843 // Save the error trace as our first action in the function. 7844 // If this is unnecessary after all, Liveness will clean it up for us. 7845 const error_return_trace_index = try sema.analyzeSaveErrRetIndex(&child_block); 7846 child_sema.error_return_trace_index_on_fn_entry = error_return_trace_index; 7847 child_block.error_return_trace_index = error_return_trace_index; 7848 7849 const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst); 7850 const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst, undefined) catch unreachable; 7851 const new_func = new_func_val.getFunctionIndex(mod).unwrap().?; 7852 assert(new_func == new_module_func); 7853 7854 arg_i = 0; 7855 for (fn_info.param_body) |inst| { 7856 var is_comptime = false; 7857 switch (zir_tags[inst]) { 7858 .param => { 7859 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i)); 7860 }, 7861 .param_comptime => { 7862 is_comptime = true; 7863 }, 7864 .param_anytype => { 7865 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i)); 7866 }, 7867 .param_anytype_comptime => { 7868 is_comptime = true; 7869 }, 7870 else => continue, 7871 } 7872 7873 // We populate the Type here regardless because it is needed by 7874 // `GenericCallAdapter.eql` as well as function body analysis. 7875 // Whether it is anytype is communicated by `isAnytypeParam`. 7876 const arg = child_sema.inst_map.get(inst).?; 7877 const arg_ty = child_sema.typeOf(arg); 7878 7879 if (try sema.typeRequiresComptime(arg_ty)) { 7880 is_comptime = true; 7881 } 7882 7883 if (is_comptime) { 7884 const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(arg) catch unreachable).?; 7885 child_sema.comptime_args[arg_i] = .{ 7886 .ty = arg_ty, 7887 .val = (try arg_val.intern(arg_ty, mod)).toValue(), 7888 }; 7889 } else { 7890 child_sema.comptime_args[arg_i] = .{ 7891 .ty = arg_ty, 7892 .val = Value.generic_poison, 7893 }; 7894 } 7895 7896 arg_i += 1; 7897 } 7898 7899 try wip_captures.finalize(); 7900 7901 // Populate the Decl ty/val with the function and its type. 7902 new_decl.ty = child_sema.typeOf(new_func_inst); 7903 // If the call evaluated to a return type that requires comptime, never mind 7904 // our generic instantiation. Instead we need to perform a comptime call. 7905 const new_fn_info = mod.typeToFunc(new_decl.ty).?; 7906 if (try sema.typeRequiresComptime(new_fn_info.return_type.toType())) { 7907 return error.ComptimeReturn; 7908 } 7909 // Similarly, if the call evaluated to a generic type we need to instead 7910 // call it inline. 7911 if (new_fn_info.is_generic or new_fn_info.cc == .Inline) { 7912 return error.GenericPoison; 7913 } 7914 7915 new_decl.val = (try mod.intern(.{ .func = .{ 7916 .ty = new_decl.ty.toIntern(), 7917 .index = new_func, 7918 } })).toValue(); 7919 new_decl.@"align" = 0; 7920 new_decl.has_tv = true; 7921 new_decl.owns_tv = true; 7922 new_decl.analysis = .complete; 7923 7924 log.debug("generic function '{s}' instantiated with type {}", .{ 7925 new_decl.name, new_decl.ty.fmtDebug(), 7926 }); 7927 7928 // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field 7929 // will be populated, ensuring it will have `analyzeBody` called with the ZIR 7930 // parameters mapped appropriately. 7931 try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func }); 7932 return new_func; 7933 } 7934 7935 fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { 7936 const mod = sema.mod; 7937 const tuple = switch (mod.intern_pool.indexToKey(ty.toIntern())) { 7938 .anon_struct_type => |tuple| tuple, 7939 else => return, 7940 }; 7941 for (tuple.types, tuple.values) |field_ty, field_val| { 7942 try sema.resolveTupleLazyValues(block, src, field_ty.toType()); 7943 if (field_val == .none) continue; 7944 // TODO: mutate in intern pool 7945 _ = try sema.resolveLazyValue(field_val.toValue()); 7946 } 7947 } 7948 7949 fn emitDbgInline( 7950 sema: *Sema, 7951 block: *Block, 7952 old_func: Module.Fn.Index, 7953 new_func: Module.Fn.Index, 7954 new_func_ty: Type, 7955 tag: Air.Inst.Tag, 7956 ) CompileError!void { 7957 const mod = sema.mod; 7958 if (mod.comp.bin_file.options.strip) return; 7959 7960 // Recursive inline call; no dbg_inline needed. 7961 if (old_func == new_func) return; 7962 7963 _ = try block.addInst(.{ 7964 .tag = tag, 7965 .data = .{ .ty_fn = .{ 7966 .ty = try sema.addType(new_func_ty), 7967 .func = new_func, 7968 } }, 7969 }); 7970 } 7971 7972 fn zirIntType(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7973 const mod = sema.mod; 7974 const int_type = sema.code.instructions.items(.data)[inst].int_type; 7975 const ty = try mod.intType(int_type.signedness, int_type.bit_count); 7976 return sema.addType(ty); 7977 } 7978 7979 fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7980 const tracy = trace(@src()); 7981 defer tracy.end(); 7982 7983 const mod = sema.mod; 7984 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 7985 const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; 7986 const child_type = try sema.resolveType(block, operand_src, inst_data.operand); 7987 if (child_type.zigTypeTag(mod) == .Opaque) { 7988 return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(sema.mod)}); 7989 } else if (child_type.zigTypeTag(mod) == .Null) { 7990 return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(sema.mod)}); 7991 } 7992 const opt_type = try Type.optional(sema.arena, child_type, mod); 7993 7994 return sema.addType(opt_type); 7995 } 7996 7997 fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7998 const mod = sema.mod; 7999 const bin = sema.code.instructions.items(.data)[inst].bin; 8000 const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs); 8001 assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction 8002 if (indexable_ty.zigTypeTag(mod) == .Struct) { 8003 const elem_type = indexable_ty.structFieldType(@enumToInt(bin.rhs), mod); 8004 return sema.addType(elem_type); 8005 } else { 8006 const elem_type = indexable_ty.elemType2(mod); 8007 return sema.addType(elem_type); 8008 } 8009 } 8010 8011 fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8012 const mod = sema.mod; 8013 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8014 const elem_type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 8015 const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 8016 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 8017 const len = @intCast(u32, try sema.resolveInt(block, len_src, extra.lhs, Type.u32, "vector length must be comptime-known")); 8018 const elem_type = try sema.resolveType(block, elem_type_src, extra.rhs); 8019 try sema.checkVectorElemType(block, elem_type_src, elem_type); 8020 const vector_type = try mod.vectorType(.{ 8021 .len = len, 8022 .child = elem_type.toIntern(), 8023 }); 8024 return sema.addType(vector_type); 8025 } 8026 8027 fn zirArrayType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8028 const tracy = trace(@src()); 8029 defer tracy.end(); 8030 8031 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8032 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 8033 const len_src: LazySrcLoc = .{ .node_offset_array_type_len = inst_data.src_node }; 8034 const elem_src: LazySrcLoc = .{ .node_offset_array_type_elem = inst_data.src_node }; 8035 const len = try sema.resolveInt(block, len_src, extra.lhs, Type.usize, "array length must be comptime-known"); 8036 const elem_type = try sema.resolveType(block, elem_src, extra.rhs); 8037 try sema.validateArrayElemType(block, elem_type, elem_src); 8038 const array_ty = try Type.array(sema.arena, len, null, elem_type, sema.mod); 8039 8040 return sema.addType(array_ty); 8041 } 8042 8043 fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8044 const tracy = trace(@src()); 8045 defer tracy.end(); 8046 8047 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8048 const extra = sema.code.extraData(Zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data; 8049 const len_src: LazySrcLoc = .{ .node_offset_array_type_len = inst_data.src_node }; 8050 const sentinel_src: LazySrcLoc = .{ .node_offset_array_type_sentinel = inst_data.src_node }; 8051 const elem_src: LazySrcLoc = .{ .node_offset_array_type_elem = inst_data.src_node }; 8052 const len = try sema.resolveInt(block, len_src, extra.len, Type.usize, "array length must be comptime-known"); 8053 const elem_type = try sema.resolveType(block, elem_src, extra.elem_type); 8054 try sema.validateArrayElemType(block, elem_type, elem_src); 8055 const uncasted_sentinel = try sema.resolveInst(extra.sentinel); 8056 const sentinel = try sema.coerce(block, elem_type, uncasted_sentinel, sentinel_src); 8057 const sentinel_val = try sema.resolveConstValue(block, sentinel_src, sentinel, "array sentinel value must be comptime-known"); 8058 const array_ty = try Type.array(sema.arena, len, sentinel_val, elem_type, sema.mod); 8059 8060 return sema.addType(array_ty); 8061 } 8062 8063 fn validateArrayElemType(sema: *Sema, block: *Block, elem_type: Type, elem_src: LazySrcLoc) !void { 8064 const mod = sema.mod; 8065 if (elem_type.zigTypeTag(mod) == .Opaque) { 8066 return sema.fail(block, elem_src, "array of opaque type '{}' not allowed", .{elem_type.fmt(sema.mod)}); 8067 } else if (elem_type.zigTypeTag(mod) == .NoReturn) { 8068 return sema.fail(block, elem_src, "array of 'noreturn' not allowed", .{}); 8069 } 8070 } 8071 8072 fn zirAnyframeType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8073 const tracy = trace(@src()); 8074 defer tracy.end(); 8075 8076 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 8077 if (true) { 8078 return sema.failWithUseOfAsync(block, inst_data.src()); 8079 } 8080 const mod = sema.mod; 8081 const operand_src: LazySrcLoc = .{ .node_offset_anyframe_type = inst_data.src_node }; 8082 const return_type = try sema.resolveType(block, operand_src, inst_data.operand); 8083 const anyframe_type = try mod.anyframeType(return_type); 8084 8085 return sema.addType(anyframe_type); 8086 } 8087 8088 fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8089 const tracy = trace(@src()); 8090 defer tracy.end(); 8091 8092 const mod = sema.mod; 8093 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8094 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 8095 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 8096 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 8097 const error_set = try sema.resolveType(block, lhs_src, extra.lhs); 8098 const payload = try sema.resolveType(block, rhs_src, extra.rhs); 8099 8100 if (error_set.zigTypeTag(mod) != .ErrorSet) { 8101 return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{ 8102 error_set.fmt(sema.mod), 8103 }); 8104 } 8105 try sema.validateErrorUnionPayloadType(block, payload, rhs_src); 8106 const err_union_ty = try mod.errorUnionType(error_set, payload); 8107 return sema.addType(err_union_ty); 8108 } 8109 8110 fn validateErrorUnionPayloadType(sema: *Sema, block: *Block, payload_ty: Type, payload_src: LazySrcLoc) !void { 8111 const mod = sema.mod; 8112 if (payload_ty.zigTypeTag(mod) == .Opaque) { 8113 return sema.fail(block, payload_src, "error union with payload of opaque type '{}' not allowed", .{ 8114 payload_ty.fmt(sema.mod), 8115 }); 8116 } else if (payload_ty.zigTypeTag(mod) == .ErrorSet) { 8117 return sema.fail(block, payload_src, "error union with payload of error set type '{}' not allowed", .{ 8118 payload_ty.fmt(sema.mod), 8119 }); 8120 } 8121 } 8122 8123 fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8124 _ = block; 8125 const mod = sema.mod; 8126 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 8127 const name = inst_data.get(sema.code); 8128 // Create an error set type with only this error value, and return the value. 8129 const kv = try sema.mod.getErrorValue(name); 8130 const error_set_type = try mod.singleErrorSetType(kv.key); 8131 return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ 8132 .ty = error_set_type.toIntern(), 8133 .name = try mod.intern_pool.getOrPutString(sema.gpa, kv.key), 8134 } })).toValue()); 8135 } 8136 8137 fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 8138 const tracy = trace(@src()); 8139 defer tracy.end(); 8140 8141 const mod = sema.mod; 8142 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 8143 const src = LazySrcLoc.nodeOffset(extra.node); 8144 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 8145 const uncasted_operand = try sema.resolveInst(extra.operand); 8146 const operand = try sema.coerce(block, Type.anyerror, uncasted_operand, operand_src); 8147 8148 if (try sema.resolveMaybeUndefVal(operand)) |val| { 8149 if (val.isUndef(mod)) { 8150 return sema.addConstUndef(Type.err_int); 8151 } 8152 const err_name = mod.intern_pool.indexToKey(val.toIntern()).err.name; 8153 return sema.addConstant(Type.err_int, try mod.intValue( 8154 Type.err_int, 8155 (try mod.getErrorValue(mod.intern_pool.stringToSlice(err_name))).value, 8156 )); 8157 } 8158 8159 const op_ty = sema.typeOf(uncasted_operand); 8160 try sema.resolveInferredErrorSetTy(block, src, op_ty); 8161 if (!op_ty.isAnyError(mod)) { 8162 const names = op_ty.errorSetNames(mod); 8163 switch (names.len) { 8164 0 => return sema.addConstant(Type.err_int, try mod.intValue(Type.err_int, 0)), 8165 1 => { 8166 const name = mod.intern_pool.stringToSlice(names[0]); 8167 return sema.addIntUnsigned(Type.err_int, mod.global_error_set.get(name).?); 8168 }, 8169 else => {}, 8170 } 8171 } 8172 8173 try sema.requireRuntimeBlock(block, src, operand_src); 8174 return block.addBitCast(Type.err_int, operand); 8175 } 8176 8177 fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 8178 const tracy = trace(@src()); 8179 defer tracy.end(); 8180 8181 const mod = sema.mod; 8182 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 8183 const src = LazySrcLoc.nodeOffset(extra.node); 8184 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 8185 const uncasted_operand = try sema.resolveInst(extra.operand); 8186 const operand = try sema.coerce(block, Type.err_int, uncasted_operand, operand_src); 8187 8188 if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| { 8189 const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(mod)); 8190 if (int > sema.mod.global_error_set.count() or int == 0) 8191 return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int}); 8192 return sema.addConstant(Type.anyerror, (try mod.intern(.{ .err = .{ 8193 .ty = .anyerror_type, 8194 .name = mod.intern_pool.getString(sema.mod.error_name_list.items[int]).unwrap().?, 8195 } })).toValue()); 8196 } 8197 try sema.requireRuntimeBlock(block, src, operand_src); 8198 if (block.wantSafety()) { 8199 const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand); 8200 const zero_val = try sema.addConstant(Type.err_int, try mod.intValue(Type.err_int, 0)); 8201 const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val); 8202 const ok = try block.addBinOp(.bit_and, is_lt_len, is_non_zero); 8203 try sema.addSafetyCheck(block, ok, .invalid_error_code); 8204 } 8205 return block.addInst(.{ 8206 .tag = .bitcast, 8207 .data = .{ .ty_op = .{ 8208 .ty = Air.Inst.Ref.anyerror_type, 8209 .operand = operand, 8210 } }, 8211 }); 8212 } 8213 8214 fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8215 const tracy = trace(@src()); 8216 defer tracy.end(); 8217 8218 const mod = sema.mod; 8219 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8220 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 8221 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 8222 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 8223 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 8224 const lhs = try sema.resolveInst(extra.lhs); 8225 const rhs = try sema.resolveInst(extra.rhs); 8226 if (sema.typeOf(lhs).zigTypeTag(mod) == .Bool and sema.typeOf(rhs).zigTypeTag(mod) == .Bool) { 8227 const msg = msg: { 8228 const msg = try sema.errMsg(block, lhs_src, "expected error set type, found 'bool'", .{}); 8229 errdefer msg.destroy(sema.gpa); 8230 try sema.errNote(block, src, msg, "'||' merges error sets; 'or' performs boolean OR", .{}); 8231 break :msg msg; 8232 }; 8233 return sema.failWithOwnedErrorMsg(msg); 8234 } 8235 const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs); 8236 const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs); 8237 if (lhs_ty.zigTypeTag(mod) != .ErrorSet) 8238 return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{lhs_ty.fmt(sema.mod)}); 8239 if (rhs_ty.zigTypeTag(mod) != .ErrorSet) 8240 return sema.fail(block, rhs_src, "expected error set type, found '{}'", .{rhs_ty.fmt(sema.mod)}); 8241 8242 // Anything merged with anyerror is anyerror. 8243 if (lhs_ty.toIntern() == .anyerror_type or rhs_ty.toIntern() == .anyerror_type) { 8244 return Air.Inst.Ref.anyerror_type; 8245 } 8246 8247 if (mod.typeToInferredErrorSetIndex(lhs_ty).unwrap()) |ies_index| { 8248 try sema.resolveInferredErrorSet(block, src, ies_index); 8249 // isAnyError might have changed from a false negative to a true positive after resolution. 8250 if (lhs_ty.isAnyError(mod)) { 8251 return Air.Inst.Ref.anyerror_type; 8252 } 8253 } 8254 if (mod.typeToInferredErrorSetIndex(rhs_ty).unwrap()) |ies_index| { 8255 try sema.resolveInferredErrorSet(block, src, ies_index); 8256 // isAnyError might have changed from a false negative to a true positive after resolution. 8257 if (rhs_ty.isAnyError(mod)) { 8258 return Air.Inst.Ref.anyerror_type; 8259 } 8260 } 8261 8262 const err_set_ty = try sema.errorSetMerge(lhs_ty, rhs_ty); 8263 return sema.addType(err_set_ty); 8264 } 8265 8266 fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8267 _ = block; 8268 const tracy = trace(@src()); 8269 defer tracy.end(); 8270 8271 const mod = sema.mod; 8272 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 8273 const name = inst_data.get(sema.code); 8274 return sema.addConstant(.{ .ip_index = .enum_literal_type }, (try mod.intern(.{ 8275 .enum_literal = try mod.intern_pool.getOrPutString(sema.gpa, name), 8276 })).toValue()); 8277 } 8278 8279 fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8280 const mod = sema.mod; 8281 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 8282 const src = inst_data.src(); 8283 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 8284 const operand = try sema.resolveInst(inst_data.operand); 8285 const operand_ty = sema.typeOf(operand); 8286 8287 const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(mod)) { 8288 .Enum => operand, 8289 .Union => blk: { 8290 const union_ty = try sema.resolveTypeFields(operand_ty); 8291 const tag_ty = union_ty.unionTagType(mod) orelse { 8292 return sema.fail( 8293 block, 8294 operand_src, 8295 "untagged union '{}' cannot be converted to integer", 8296 .{src}, 8297 ); 8298 }; 8299 break :blk try sema.unionToTag(block, tag_ty, operand, operand_src); 8300 }, 8301 else => { 8302 return sema.fail(block, operand_src, "expected enum or tagged union, found '{}'", .{ 8303 operand_ty.fmt(sema.mod), 8304 }); 8305 }, 8306 }; 8307 const enum_tag_ty = sema.typeOf(enum_tag); 8308 8309 const int_tag_ty = enum_tag_ty.intTagType(mod); 8310 8311 if (try sema.typeHasOnePossibleValue(enum_tag_ty)) |opv| { 8312 return sema.addConstant(int_tag_ty, try mod.getCoerced(opv, int_tag_ty)); 8313 } 8314 8315 if (try sema.resolveMaybeUndefVal(enum_tag)) |enum_tag_val| { 8316 const val = try enum_tag_val.enumToInt(enum_tag_ty, mod); 8317 return sema.addConstant(int_tag_ty, try val.copy(sema.arena)); 8318 } 8319 8320 try sema.requireRuntimeBlock(block, src, operand_src); 8321 return block.addBitCast(int_tag_ty, enum_tag); 8322 } 8323 8324 fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8325 const mod = sema.mod; 8326 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8327 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 8328 const src = inst_data.src(); 8329 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 8330 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 8331 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); 8332 const operand = try sema.resolveInst(extra.rhs); 8333 8334 if (dest_ty.zigTypeTag(mod) != .Enum) { 8335 return sema.fail(block, dest_ty_src, "expected enum, found '{}'", .{dest_ty.fmt(sema.mod)}); 8336 } 8337 _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand)); 8338 8339 if (try sema.resolveMaybeUndefVal(operand)) |int_val| { 8340 if (dest_ty.isNonexhaustiveEnum(mod)) { 8341 const int_tag_ty = dest_ty.intTagType(mod); 8342 if (try sema.intFitsInType(int_val, int_tag_ty, null)) { 8343 return sema.addConstant(dest_ty, try mod.getCoerced(int_val, dest_ty)); 8344 } 8345 const msg = msg: { 8346 const msg = try sema.errMsg( 8347 block, 8348 src, 8349 "int value '{}' out of range of non-exhaustive enum '{}'", 8350 .{ int_val.fmtValue(sema.typeOf(operand), sema.mod), dest_ty.fmt(sema.mod) }, 8351 ); 8352 errdefer msg.destroy(sema.gpa); 8353 try sema.addDeclaredHereNote(msg, dest_ty); 8354 break :msg msg; 8355 }; 8356 return sema.failWithOwnedErrorMsg(msg); 8357 } 8358 if (int_val.isUndef(mod)) { 8359 return sema.failWithUseOfUndef(block, operand_src); 8360 } 8361 if (!(try sema.enumHasInt(dest_ty, int_val))) { 8362 const msg = msg: { 8363 const msg = try sema.errMsg( 8364 block, 8365 src, 8366 "enum '{}' has no tag with value '{}'", 8367 .{ dest_ty.fmt(sema.mod), int_val.fmtValue(sema.typeOf(operand), sema.mod) }, 8368 ); 8369 errdefer msg.destroy(sema.gpa); 8370 try sema.addDeclaredHereNote(msg, dest_ty); 8371 break :msg msg; 8372 }; 8373 return sema.failWithOwnedErrorMsg(msg); 8374 } 8375 return sema.addConstant(dest_ty, try mod.getCoerced(int_val, dest_ty)); 8376 } 8377 8378 if (try sema.typeHasOnePossibleValue(dest_ty)) |opv| { 8379 const result = try sema.addConstant(dest_ty, opv); 8380 // The operand is runtime-known but the result is comptime-known. In 8381 // this case we still need a safety check. 8382 // TODO add a safety check here. we can't use is_named_enum_value - 8383 // it needs to convert the enum back to int and make sure it equals the operand int. 8384 return result; 8385 } 8386 8387 try sema.requireRuntimeBlock(block, src, operand_src); 8388 const result = try block.addTyOp(.intcast, dest_ty, operand); 8389 if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum(mod) and 8390 sema.mod.backendSupportsFeature(.is_named_enum_value)) 8391 { 8392 const ok = try block.addUnOp(.is_named_enum_value, result); 8393 try sema.addSafetyCheck(block, ok, .invalid_enum_value); 8394 } 8395 return result; 8396 } 8397 8398 /// Pointer in, pointer out. 8399 fn zirOptionalPayloadPtr( 8400 sema: *Sema, 8401 block: *Block, 8402 inst: Zir.Inst.Index, 8403 safety_check: bool, 8404 ) CompileError!Air.Inst.Ref { 8405 const tracy = trace(@src()); 8406 defer tracy.end(); 8407 8408 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 8409 const optional_ptr = try sema.resolveInst(inst_data.operand); 8410 const src = inst_data.src(); 8411 8412 return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false); 8413 } 8414 8415 fn analyzeOptionalPayloadPtr( 8416 sema: *Sema, 8417 block: *Block, 8418 src: LazySrcLoc, 8419 optional_ptr: Air.Inst.Ref, 8420 safety_check: bool, 8421 initializing: bool, 8422 ) CompileError!Air.Inst.Ref { 8423 const mod = sema.mod; 8424 const optional_ptr_ty = sema.typeOf(optional_ptr); 8425 assert(optional_ptr_ty.zigTypeTag(mod) == .Pointer); 8426 8427 const opt_type = optional_ptr_ty.childType(mod); 8428 if (opt_type.zigTypeTag(mod) != .Optional) { 8429 return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(sema.mod)}); 8430 } 8431 8432 const child_type = opt_type.optionalChild(mod); 8433 const child_pointer = try Type.ptr(sema.arena, sema.mod, .{ 8434 .pointee_type = child_type, 8435 .mutable = !optional_ptr_ty.isConstPtr(mod), 8436 .@"addrspace" = optional_ptr_ty.ptrAddressSpace(mod), 8437 }); 8438 8439 if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| { 8440 if (initializing) { 8441 if (!ptr_val.isComptimeMutablePtr(mod)) { 8442 // If the pointer resulting from this function was stored at comptime, 8443 // the optional non-null bit would be set that way. But in this case, 8444 // we need to emit a runtime instruction to do it. 8445 _ = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr); 8446 } 8447 return sema.addConstant(child_pointer, (try mod.intern(.{ .ptr = .{ 8448 .ty = child_pointer.toIntern(), 8449 .addr = .{ .opt_payload = ptr_val.toIntern() }, 8450 } })).toValue()); 8451 } 8452 if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| { 8453 if (val.isNull(mod)) { 8454 return sema.fail(block, src, "unable to unwrap null", .{}); 8455 } 8456 // The same Value represents the pointer to the optional and the payload. 8457 return sema.addConstant(child_pointer, (try mod.intern(.{ .ptr = .{ 8458 .ty = child_pointer.toIntern(), 8459 .addr = .{ .opt_payload = ptr_val.toIntern() }, 8460 } })).toValue()); 8461 } 8462 } 8463 8464 try sema.requireRuntimeBlock(block, src, null); 8465 if (safety_check and block.wantSafety()) { 8466 const is_non_null = try block.addUnOp(.is_non_null_ptr, optional_ptr); 8467 try sema.addSafetyCheck(block, is_non_null, .unwrap_null); 8468 } 8469 const air_tag: Air.Inst.Tag = if (initializing) 8470 .optional_payload_ptr_set 8471 else 8472 .optional_payload_ptr; 8473 return block.addTyOp(air_tag, child_pointer, optional_ptr); 8474 } 8475 8476 /// Value in, value out. 8477 fn zirOptionalPayload( 8478 sema: *Sema, 8479 block: *Block, 8480 inst: Zir.Inst.Index, 8481 safety_check: bool, 8482 ) CompileError!Air.Inst.Ref { 8483 const tracy = trace(@src()); 8484 defer tracy.end(); 8485 8486 const mod = sema.mod; 8487 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 8488 const src = inst_data.src(); 8489 const operand = try sema.resolveInst(inst_data.operand); 8490 const operand_ty = sema.typeOf(operand); 8491 const result_ty = switch (operand_ty.zigTypeTag(mod)) { 8492 .Optional => operand_ty.optionalChild(mod), 8493 .Pointer => t: { 8494 if (operand_ty.ptrSize(mod) != .C) { 8495 return sema.failWithExpectedOptionalType(block, src, operand_ty); 8496 } 8497 // TODO https://github.com/ziglang/zig/issues/6597 8498 if (true) break :t operand_ty; 8499 const ptr_info = operand_ty.ptrInfo(mod); 8500 break :t try Type.ptr(sema.arena, sema.mod, .{ 8501 .pointee_type = ptr_info.pointee_type, 8502 .@"align" = ptr_info.@"align", 8503 .@"addrspace" = ptr_info.@"addrspace", 8504 .mutable = ptr_info.mutable, 8505 .@"allowzero" = ptr_info.@"allowzero", 8506 .@"volatile" = ptr_info.@"volatile", 8507 .size = .One, 8508 }); 8509 }, 8510 else => return sema.failWithExpectedOptionalType(block, src, operand_ty), 8511 }; 8512 8513 if (try sema.resolveDefinedValue(block, src, operand)) |val| { 8514 return if (val.optionalValue(mod)) |payload| 8515 sema.addConstant(result_ty, payload) 8516 else 8517 sema.fail(block, src, "unable to unwrap null", .{}); 8518 } 8519 8520 try sema.requireRuntimeBlock(block, src, null); 8521 if (safety_check and block.wantSafety()) { 8522 const is_non_null = try block.addUnOp(.is_non_null, operand); 8523 try sema.addSafetyCheck(block, is_non_null, .unwrap_null); 8524 } 8525 return block.addTyOp(.optional_payload, result_ty, operand); 8526 } 8527 8528 /// Value in, value out 8529 fn zirErrUnionPayload( 8530 sema: *Sema, 8531 block: *Block, 8532 inst: Zir.Inst.Index, 8533 ) CompileError!Air.Inst.Ref { 8534 const tracy = trace(@src()); 8535 defer tracy.end(); 8536 8537 const mod = sema.mod; 8538 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 8539 const src = inst_data.src(); 8540 const operand = try sema.resolveInst(inst_data.operand); 8541 const operand_src = src; 8542 const err_union_ty = sema.typeOf(operand); 8543 if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) { 8544 return sema.fail(block, operand_src, "expected error union type, found '{}'", .{ 8545 err_union_ty.fmt(sema.mod), 8546 }); 8547 } 8548 return sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false); 8549 } 8550 8551 fn analyzeErrUnionPayload( 8552 sema: *Sema, 8553 block: *Block, 8554 src: LazySrcLoc, 8555 err_union_ty: Type, 8556 operand: Air.Inst.Ref, 8557 operand_src: LazySrcLoc, 8558 safety_check: bool, 8559 ) CompileError!Air.Inst.Ref { 8560 const mod = sema.mod; 8561 const payload_ty = err_union_ty.errorUnionPayload(mod); 8562 if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { 8563 if (val.getError(mod)) |name| { 8564 return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); 8565 } 8566 return sema.addConstant( 8567 payload_ty, 8568 mod.intern_pool.indexToKey(val.toIntern()).error_union.val.payload.toValue(), 8569 ); 8570 } 8571 8572 try sema.requireRuntimeBlock(block, src, null); 8573 8574 // If the error set has no fields then no safety check is needed. 8575 if (safety_check and block.wantSafety() and 8576 !err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) 8577 { 8578 try sema.panicUnwrapError(block, operand, .unwrap_errunion_err, .is_non_err); 8579 } 8580 8581 return block.addTyOp(.unwrap_errunion_payload, payload_ty, operand); 8582 } 8583 8584 /// Pointer in, pointer out. 8585 fn zirErrUnionPayloadPtr( 8586 sema: *Sema, 8587 block: *Block, 8588 inst: Zir.Inst.Index, 8589 ) CompileError!Air.Inst.Ref { 8590 const tracy = trace(@src()); 8591 defer tracy.end(); 8592 8593 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 8594 const operand = try sema.resolveInst(inst_data.operand); 8595 const src = inst_data.src(); 8596 8597 return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false); 8598 } 8599 8600 fn analyzeErrUnionPayloadPtr( 8601 sema: *Sema, 8602 block: *Block, 8603 src: LazySrcLoc, 8604 operand: Air.Inst.Ref, 8605 safety_check: bool, 8606 initializing: bool, 8607 ) CompileError!Air.Inst.Ref { 8608 const mod = sema.mod; 8609 const operand_ty = sema.typeOf(operand); 8610 assert(operand_ty.zigTypeTag(mod) == .Pointer); 8611 8612 if (operand_ty.childType(mod).zigTypeTag(mod) != .ErrorUnion) { 8613 return sema.fail(block, src, "expected error union type, found '{}'", .{ 8614 operand_ty.childType(mod).fmt(sema.mod), 8615 }); 8616 } 8617 8618 const err_union_ty = operand_ty.childType(mod); 8619 const payload_ty = err_union_ty.errorUnionPayload(mod); 8620 const operand_pointer_ty = try Type.ptr(sema.arena, sema.mod, .{ 8621 .pointee_type = payload_ty, 8622 .mutable = !operand_ty.isConstPtr(mod), 8623 .@"addrspace" = operand_ty.ptrAddressSpace(mod), 8624 }); 8625 8626 if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| { 8627 if (initializing) { 8628 if (!ptr_val.isComptimeMutablePtr(mod)) { 8629 // If the pointer resulting from this function was stored at comptime, 8630 // the error union error code would be set that way. But in this case, 8631 // we need to emit a runtime instruction to do it. 8632 try sema.requireRuntimeBlock(block, src, null); 8633 _ = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand); 8634 } 8635 return sema.addConstant(operand_pointer_ty, (try mod.intern(.{ .ptr = .{ 8636 .ty = operand_pointer_ty.toIntern(), 8637 .addr = .{ .eu_payload = ptr_val.toIntern() }, 8638 } })).toValue()); 8639 } 8640 if (try sema.pointerDeref(block, src, ptr_val, operand_ty)) |val| { 8641 if (val.getError(mod)) |name| { 8642 return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); 8643 } 8644 return sema.addConstant(operand_pointer_ty, (try mod.intern(.{ .ptr = .{ 8645 .ty = operand_pointer_ty.toIntern(), 8646 .addr = .{ .eu_payload = ptr_val.toIntern() }, 8647 } })).toValue()); 8648 } 8649 } 8650 8651 try sema.requireRuntimeBlock(block, src, null); 8652 8653 // If the error set has no fields then no safety check is needed. 8654 if (safety_check and block.wantSafety() and 8655 !err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) 8656 { 8657 try sema.panicUnwrapError(block, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr); 8658 } 8659 8660 const air_tag: Air.Inst.Tag = if (initializing) 8661 .errunion_payload_ptr_set 8662 else 8663 .unwrap_errunion_payload_ptr; 8664 return block.addTyOp(air_tag, operand_pointer_ty, operand); 8665 } 8666 8667 /// Value in, value out 8668 fn zirErrUnionCode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8669 const tracy = trace(@src()); 8670 defer tracy.end(); 8671 8672 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 8673 const src = inst_data.src(); 8674 const operand = try sema.resolveInst(inst_data.operand); 8675 return sema.analyzeErrUnionCode(block, src, operand); 8676 } 8677 8678 fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref) CompileError!Air.Inst.Ref { 8679 const mod = sema.mod; 8680 const operand_ty = sema.typeOf(operand); 8681 if (operand_ty.zigTypeTag(mod) != .ErrorUnion) { 8682 return sema.fail(block, src, "expected error union type, found '{}'", .{ 8683 operand_ty.fmt(sema.mod), 8684 }); 8685 } 8686 8687 const result_ty = operand_ty.errorUnionSet(mod); 8688 8689 if (try sema.resolveDefinedValue(block, src, operand)) |val| { 8690 return sema.addConstant(result_ty, (try mod.intern(.{ .err = .{ 8691 .ty = result_ty.toIntern(), 8692 .name = mod.intern_pool.indexToKey(val.toIntern()).error_union.val.err_name, 8693 } })).toValue()); 8694 } 8695 8696 try sema.requireRuntimeBlock(block, src, null); 8697 return block.addTyOp(.unwrap_errunion_err, result_ty, operand); 8698 } 8699 8700 /// Pointer in, value out 8701 fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8702 const tracy = trace(@src()); 8703 defer tracy.end(); 8704 8705 const mod = sema.mod; 8706 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 8707 const src = inst_data.src(); 8708 const operand = try sema.resolveInst(inst_data.operand); 8709 const operand_ty = sema.typeOf(operand); 8710 assert(operand_ty.zigTypeTag(mod) == .Pointer); 8711 8712 if (operand_ty.childType(mod).zigTypeTag(mod) != .ErrorUnion) { 8713 return sema.fail(block, src, "expected error union type, found '{}'", .{ 8714 operand_ty.childType(mod).fmt(sema.mod), 8715 }); 8716 } 8717 8718 const result_ty = operand_ty.childType(mod).errorUnionSet(mod); 8719 8720 if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| { 8721 if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| { 8722 assert(val.getError(mod) != null); 8723 return sema.addConstant(result_ty, val); 8724 } 8725 } 8726 8727 try sema.requireRuntimeBlock(block, src, null); 8728 return block.addTyOp(.unwrap_errunion_err_ptr, result_ty, operand); 8729 } 8730 8731 fn zirFunc( 8732 sema: *Sema, 8733 block: *Block, 8734 inst: Zir.Inst.Index, 8735 inferred_error_set: bool, 8736 ) CompileError!Air.Inst.Ref { 8737 const tracy = trace(@src()); 8738 defer tracy.end(); 8739 8740 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8741 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index); 8742 const target = sema.mod.getTarget(); 8743 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = inst_data.src_node }; 8744 8745 var extra_index = extra.end; 8746 8747 const ret_ty: Type = switch (extra.data.ret_body_len) { 8748 0 => Type.void, 8749 1 => blk: { 8750 const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 8751 extra_index += 1; 8752 if (sema.resolveType(block, ret_ty_src, ret_ty_ref)) |ret_ty| { 8753 break :blk ret_ty; 8754 } else |err| switch (err) { 8755 error.GenericPoison => { 8756 break :blk Type.generic_poison; 8757 }, 8758 else => |e| return e, 8759 } 8760 }, 8761 else => blk: { 8762 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len]; 8763 extra_index += ret_ty_body.len; 8764 8765 const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type, "return type must be comptime-known"); 8766 break :blk ret_ty_val.toType(); 8767 }, 8768 }; 8769 8770 var src_locs: Zir.Inst.Func.SrcLocs = undefined; 8771 const has_body = extra.data.body_len != 0; 8772 if (has_body) { 8773 extra_index += extra.data.body_len; 8774 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; 8775 } 8776 8777 // If this instruction has a body it means it's the type of the `owner_decl` 8778 // otherwise it's a function type without a `callconv` attribute and should 8779 // never be `.C`. 8780 // NOTE: revisit when doing #1717 8781 const cc: std.builtin.CallingConvention = if (sema.owner_decl.is_exported and has_body) 8782 .C 8783 else 8784 .Unspecified; 8785 8786 return sema.funcCommon( 8787 block, 8788 inst_data.src_node, 8789 inst, 8790 0, 8791 target_util.defaultAddressSpace(target, .function), 8792 FuncLinkSection.default, 8793 cc, 8794 ret_ty, 8795 false, 8796 inferred_error_set, 8797 false, 8798 has_body, 8799 src_locs, 8800 null, 8801 0, 8802 false, 8803 ); 8804 } 8805 8806 fn resolveGenericBody( 8807 sema: *Sema, 8808 block: *Block, 8809 src: LazySrcLoc, 8810 body: []const Zir.Inst.Index, 8811 func_inst: Zir.Inst.Index, 8812 dest_ty: Type, 8813 reason: []const u8, 8814 ) !Value { 8815 assert(body.len != 0); 8816 8817 const err = err: { 8818 // Make sure any nested param instructions don't clobber our work. 8819 const prev_params = block.params; 8820 block.params = .{}; 8821 defer { 8822 block.params.deinit(sema.gpa); 8823 block.params = prev_params; 8824 } 8825 8826 const uncasted = sema.resolveBody(block, body, func_inst) catch |err| break :err err; 8827 const result = sema.coerce(block, dest_ty, uncasted, src) catch |err| break :err err; 8828 const val = sema.resolveConstValue(block, src, result, reason) catch |err| break :err err; 8829 return val; 8830 }; 8831 switch (err) { 8832 error.GenericPoison => { 8833 if (dest_ty.toIntern() == .type_type) { 8834 return Value.generic_poison_type; 8835 } else { 8836 return Value.generic_poison; 8837 } 8838 }, 8839 else => |e| return e, 8840 } 8841 } 8842 8843 /// Given a library name, examines if the library name should end up in 8844 /// `link.File.Options.system_libs` table (for example, libc is always 8845 /// specified via dedicated flag `link.File.Options.link_libc` instead), 8846 /// and puts it there if it doesn't exist. 8847 /// It also dupes the library name which can then be saved as part of the 8848 /// respective `Decl` (either `ExternFn` or `Var`). 8849 /// The liveness of the duped library name is tied to liveness of `Module`. 8850 /// To deallocate, call `deinit` on the respective `Decl` (`ExternFn` or `Var`). 8851 fn handleExternLibName( 8852 sema: *Sema, 8853 block: *Block, 8854 src_loc: LazySrcLoc, 8855 lib_name: []const u8, 8856 ) CompileError![:0]u8 { 8857 blk: { 8858 const mod = sema.mod; 8859 const comp = mod.comp; 8860 const target = mod.getTarget(); 8861 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name}); 8862 if (target_util.is_libc_lib_name(target, lib_name)) { 8863 if (!comp.bin_file.options.link_libc and !comp.bin_file.options.parent_compilation_link_libc) { 8864 return sema.fail( 8865 block, 8866 src_loc, 8867 "dependency on libc must be explicitly specified in the build command", 8868 .{}, 8869 ); 8870 } 8871 comp.bin_file.options.link_libc = true; 8872 break :blk; 8873 } 8874 if (target_util.is_libcpp_lib_name(target, lib_name)) { 8875 if (!comp.bin_file.options.link_libcpp) { 8876 return sema.fail( 8877 block, 8878 src_loc, 8879 "dependency on libc++ must be explicitly specified in the build command", 8880 .{}, 8881 ); 8882 } 8883 comp.bin_file.options.link_libcpp = true; 8884 break :blk; 8885 } 8886 if (mem.eql(u8, lib_name, "unwind")) { 8887 comp.bin_file.options.link_libunwind = true; 8888 break :blk; 8889 } 8890 if (!target.isWasm() and !comp.bin_file.options.pic) { 8891 return sema.fail( 8892 block, 8893 src_loc, 8894 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by '-l{s}' or '-fPIC'.", 8895 .{ lib_name, lib_name }, 8896 ); 8897 } 8898 comp.addLinkLib(lib_name) catch |err| { 8899 return sema.fail(block, src_loc, "unable to add link lib '{s}': {s}", .{ 8900 lib_name, @errorName(err), 8901 }); 8902 }; 8903 } 8904 return sema.gpa.dupeZ(u8, lib_name); 8905 } 8906 8907 const FuncLinkSection = union(enum) { 8908 generic, 8909 default, 8910 explicit: []const u8, 8911 }; 8912 8913 fn funcCommon( 8914 sema: *Sema, 8915 block: *Block, 8916 src_node_offset: i32, 8917 func_inst: Zir.Inst.Index, 8918 /// null means generic poison 8919 alignment: ?u32, 8920 /// null means generic poison 8921 address_space: ?std.builtin.AddressSpace, 8922 /// outer null means generic poison; inner null means default link section 8923 section: FuncLinkSection, 8924 /// null means generic poison 8925 cc: ?std.builtin.CallingConvention, 8926 /// this might be Type.generic_poison 8927 bare_return_type: Type, 8928 var_args: bool, 8929 inferred_error_set: bool, 8930 is_extern: bool, 8931 has_body: bool, 8932 src_locs: Zir.Inst.Func.SrcLocs, 8933 opt_lib_name: ?[]const u8, 8934 noalias_bits: u32, 8935 is_noinline: bool, 8936 ) CompileError!Air.Inst.Ref { 8937 const mod = sema.mod; 8938 const gpa = sema.gpa; 8939 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset }; 8940 const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset }; 8941 const func_src = LazySrcLoc.nodeOffset(src_node_offset); 8942 8943 var is_generic = bare_return_type.isGenericPoison() or 8944 alignment == null or 8945 address_space == null or 8946 section == .generic or 8947 cc == null; 8948 8949 if (var_args) { 8950 if (is_generic) { 8951 return sema.fail(block, func_src, "generic function cannot be variadic", .{}); 8952 } 8953 if (cc.? != .C) { 8954 return sema.fail(block, cc_src, "variadic function must have 'C' calling convention", .{}); 8955 } 8956 } 8957 8958 var destroy_fn_on_error = false; 8959 const new_func_index = new_func: { 8960 if (!has_body) break :new_func undefined; 8961 if (sema.comptime_args_fn_inst == func_inst) { 8962 const new_func_index = sema.preallocated_new_func.unwrap().?; 8963 sema.preallocated_new_func = .none; // take ownership 8964 break :new_func new_func_index; 8965 } 8966 destroy_fn_on_error = true; 8967 var new_func: Module.Fn = undefined; 8968 // Set this here so that the inferred return type can be printed correctly if it appears in an error. 8969 new_func.owner_decl = sema.owner_decl_index; 8970 const new_func_index = try mod.createFunc(new_func); 8971 break :new_func new_func_index; 8972 }; 8973 errdefer if (destroy_fn_on_error) mod.destroyFunc(new_func_index); 8974 8975 const target = sema.mod.getTarget(); 8976 const fn_ty: Type = fn_ty: { 8977 // In the case of generic calling convention, or generic alignment, we use 8978 // default values which are only meaningful for the generic function, *not* 8979 // the instantiation, which can depend on comptime parameters. 8980 // Related proposal: https://github.com/ziglang/zig/issues/11834 8981 const cc_resolved = cc orelse .Unspecified; 8982 const param_types = try sema.arena.alloc(InternPool.Index, block.params.items.len); 8983 var comptime_bits: u32 = 0; 8984 for (param_types, block.params.items, 0..) |*dest_param_ty, param, i| { 8985 const is_noalias = blk: { 8986 const index = std.math.cast(u5, i) orelse break :blk false; 8987 break :blk @truncate(u1, noalias_bits >> index) != 0; 8988 }; 8989 dest_param_ty.* = param.ty.toIntern(); 8990 sema.analyzeParameter( 8991 block, 8992 .unneeded, 8993 param, 8994 &comptime_bits, 8995 i, 8996 &is_generic, 8997 cc_resolved, 8998 has_body, 8999 is_noalias, 9000 ) catch |err| switch (err) { 9001 error.NeededSourceLocation => { 9002 const decl = sema.mod.declPtr(block.src_decl); 9003 try sema.analyzeParameter( 9004 block, 9005 Module.paramSrc(src_node_offset, mod, decl, i), 9006 param, 9007 &comptime_bits, 9008 i, 9009 &is_generic, 9010 cc_resolved, 9011 has_body, 9012 is_noalias, 9013 ); 9014 unreachable; 9015 }, 9016 else => |e| return e, 9017 }; 9018 } 9019 9020 var ret_ty_requires_comptime = false; 9021 const ret_poison = if (sema.typeRequiresComptime(bare_return_type)) |ret_comptime| rp: { 9022 ret_ty_requires_comptime = ret_comptime; 9023 break :rp bare_return_type.isGenericPoison(); 9024 } else |err| switch (err) { 9025 error.GenericPoison => rp: { 9026 is_generic = true; 9027 break :rp true; 9028 }, 9029 else => |e| return e, 9030 }; 9031 9032 const return_type: Type = if (!inferred_error_set or ret_poison) 9033 bare_return_type 9034 else blk: { 9035 try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src); 9036 const ies_index = try mod.intern_pool.createInferredErrorSet(gpa, .{ 9037 .func = new_func_index, 9038 }); 9039 const error_set_ty = try mod.intern(.{ .inferred_error_set_type = ies_index }); 9040 break :blk try mod.errorUnionType(error_set_ty.toType(), bare_return_type); 9041 }; 9042 9043 if (!return_type.isValidReturnType(mod)) { 9044 const opaque_str = if (return_type.zigTypeTag(mod) == .Opaque) "opaque " else ""; 9045 const msg = msg: { 9046 const msg = try sema.errMsg(block, ret_ty_src, "{s}return type '{}' not allowed", .{ 9047 opaque_str, return_type.fmt(sema.mod), 9048 }); 9049 errdefer msg.destroy(gpa); 9050 9051 try sema.addDeclaredHereNote(msg, return_type); 9052 break :msg msg; 9053 }; 9054 return sema.failWithOwnedErrorMsg(msg); 9055 } 9056 if (!ret_poison and !target_util.fnCallConvAllowsZigTypes(target, cc_resolved) and 9057 !try sema.validateExternType(return_type, .ret_ty)) 9058 { 9059 const msg = msg: { 9060 const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{ 9061 return_type.fmt(sema.mod), @tagName(cc_resolved), 9062 }); 9063 errdefer msg.destroy(gpa); 9064 9065 const src_decl = sema.mod.declPtr(block.src_decl); 9066 try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl, mod), return_type, .ret_ty); 9067 9068 try sema.addDeclaredHereNote(msg, return_type); 9069 break :msg msg; 9070 }; 9071 return sema.failWithOwnedErrorMsg(msg); 9072 } 9073 9074 // If the return type is comptime-only but not dependent on parameters then all parameter types also need to be comptime 9075 if (!sema.is_generic_instantiation and has_body and ret_ty_requires_comptime) comptime_check: { 9076 for (block.params.items) |param| { 9077 if (!param.is_comptime) break; 9078 } else break :comptime_check; 9079 9080 const msg = try sema.errMsg( 9081 block, 9082 ret_ty_src, 9083 "function with comptime-only return type '{}' requires all parameters to be comptime", 9084 .{return_type.fmt(sema.mod)}, 9085 ); 9086 try sema.explainWhyTypeIsComptime(msg, ret_ty_src.toSrcLoc(sema.owner_decl, mod), return_type); 9087 9088 const tags = sema.code.instructions.items(.tag); 9089 const data = sema.code.instructions.items(.data); 9090 const param_body = sema.code.getParamBody(func_inst); 9091 for (block.params.items, 0..) |param, i| { 9092 if (!param.is_comptime) { 9093 const param_index = param_body[i]; 9094 const param_src = switch (tags[param_index]) { 9095 .param => data[param_index].pl_tok.src(), 9096 .param_anytype => data[param_index].str_tok.src(), 9097 else => unreachable, 9098 }; 9099 if (param.name.len != 0) { 9100 try sema.errNote(block, param_src, msg, "param '{s}' is required to be comptime", .{param.name}); 9101 } else { 9102 try sema.errNote(block, param_src, msg, "param is required to be comptime", .{}); 9103 } 9104 } 9105 } 9106 return sema.failWithOwnedErrorMsg(msg); 9107 } 9108 9109 const arch = sema.mod.getTarget().cpu.arch; 9110 if (switch (cc_resolved) { 9111 .Unspecified, .C, .Naked, .Async, .Inline => null, 9112 .Interrupt => switch (arch) { 9113 .x86, .x86_64, .avr, .msp430 => null, 9114 else => @as([]const u8, "x86, x86_64, AVR, and MSP430"), 9115 }, 9116 .Signal => switch (arch) { 9117 .avr => null, 9118 else => @as([]const u8, "AVR"), 9119 }, 9120 .Stdcall, .Fastcall, .Thiscall => switch (arch) { 9121 .x86 => null, 9122 else => @as([]const u8, "x86"), 9123 }, 9124 .Vectorcall => switch (arch) { 9125 .x86, .aarch64, .aarch64_be, .aarch64_32 => null, 9126 else => @as([]const u8, "x86 and AArch64"), 9127 }, 9128 .APCS, .AAPCS, .AAPCSVFP => switch (arch) { 9129 .arm, .armeb, .aarch64, .aarch64_be, .aarch64_32, .thumb, .thumbeb => null, 9130 else => @as([]const u8, "ARM"), 9131 }, 9132 .SysV, .Win64 => switch (arch) { 9133 .x86_64 => null, 9134 else => @as([]const u8, "x86_64"), 9135 }, 9136 .Kernel => switch (arch) { 9137 .nvptx, .nvptx64, .amdgcn, .spirv32, .spirv64 => null, 9138 else => @as([]const u8, "nvptx, amdgcn and SPIR-V"), 9139 }, 9140 }) |allowed_platform| { 9141 return sema.fail(block, cc_src, "callconv '{s}' is only available on {s}, not {s}", .{ 9142 @tagName(cc_resolved), 9143 allowed_platform, 9144 @tagName(arch), 9145 }); 9146 } 9147 9148 if (cc_resolved == .Inline and is_noinline) { 9149 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{}); 9150 } 9151 if (is_generic and sema.no_partial_func_ty) return error.GenericPoison; 9152 is_generic = is_generic or comptime_bits != 0 or ret_ty_requires_comptime; 9153 9154 if (!is_generic and sema.wantErrorReturnTracing(return_type)) { 9155 // Make sure that StackTrace's fields are resolved so that the backend can 9156 // lower this fn type. 9157 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); 9158 _ = try sema.resolveTypeFields(unresolved_stack_trace_ty); 9159 } 9160 9161 break :fn_ty try mod.funcType(.{ 9162 .param_types = param_types, 9163 .noalias_bits = noalias_bits, 9164 .comptime_bits = comptime_bits, 9165 .return_type = return_type.toIntern(), 9166 .cc = cc_resolved, 9167 .cc_is_generic = cc == null, 9168 .alignment = if (alignment) |a| InternPool.Alignment.fromByteUnits(a) else .none, 9169 .align_is_generic = alignment == null, 9170 .section_is_generic = section == .generic, 9171 .addrspace_is_generic = address_space == null, 9172 .is_var_args = var_args, 9173 .is_generic = is_generic, 9174 .is_noinline = is_noinline, 9175 }); 9176 }; 9177 9178 sema.owner_decl.@"linksection" = switch (section) { 9179 .generic => undefined, 9180 .default => null, 9181 .explicit => |section_name| try sema.perm_arena.dupeZ(u8, section_name), 9182 }; 9183 sema.owner_decl.@"align" = alignment orelse 0; 9184 sema.owner_decl.@"addrspace" = address_space orelse .generic; 9185 9186 if (is_extern) { 9187 return sema.addConstant(fn_ty, (try mod.intern(.{ .extern_func = .{ 9188 .ty = fn_ty.toIntern(), 9189 .decl = sema.owner_decl_index, 9190 .lib_name = if (opt_lib_name) |lib_name| (try mod.intern_pool.getOrPutString( 9191 gpa, 9192 try sema.handleExternLibName(block, .{ 9193 .node_offset_lib_name = src_node_offset, 9194 }, lib_name), 9195 )).toOptional() else .none, 9196 } })).toValue()); 9197 } 9198 9199 if (!has_body) { 9200 return sema.addType(fn_ty); 9201 } 9202 9203 const is_inline = fn_ty.fnCallingConvention(mod) == .Inline; 9204 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .none; 9205 9206 const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == func_inst) blk: { 9207 break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr; 9208 } else null; 9209 9210 const new_func = mod.funcPtr(new_func_index); 9211 const hash = new_func.hash; 9212 const generic_owner_decl = if (comptime_args == null) .none else new_func.generic_owner_decl; 9213 new_func.* = .{ 9214 .state = anal_state, 9215 .zir_body_inst = func_inst, 9216 .owner_decl = sema.owner_decl_index, 9217 .generic_owner_decl = generic_owner_decl, 9218 .comptime_args = comptime_args, 9219 .hash = hash, 9220 .lbrace_line = src_locs.lbrace_line, 9221 .rbrace_line = src_locs.rbrace_line, 9222 .lbrace_column = @truncate(u16, src_locs.columns), 9223 .rbrace_column = @truncate(u16, src_locs.columns >> 16), 9224 .branch_quota = default_branch_quota, 9225 .is_noinline = is_noinline, 9226 }; 9227 return sema.addConstant(fn_ty, (try mod.intern(.{ .func = .{ 9228 .ty = fn_ty.toIntern(), 9229 .index = new_func_index, 9230 } })).toValue()); 9231 } 9232 9233 fn analyzeParameter( 9234 sema: *Sema, 9235 block: *Block, 9236 param_src: LazySrcLoc, 9237 param: Block.Param, 9238 comptime_bits: *u32, 9239 i: usize, 9240 is_generic: *bool, 9241 cc: std.builtin.CallingConvention, 9242 has_body: bool, 9243 is_noalias: bool, 9244 ) !void { 9245 const mod = sema.mod; 9246 const requires_comptime = try sema.typeRequiresComptime(param.ty); 9247 if (param.is_comptime or requires_comptime) { 9248 comptime_bits.* |= @as(u32, 1) << @intCast(u5, i); // TODO: handle cast error 9249 } 9250 const this_generic = param.ty.isGenericPoison(); 9251 is_generic.* = is_generic.* or this_generic; 9252 const target = mod.getTarget(); 9253 if (param.is_comptime and !target_util.fnCallConvAllowsZigTypes(target, cc)) { 9254 return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); 9255 } 9256 if (this_generic and !sema.no_partial_func_ty and !target_util.fnCallConvAllowsZigTypes(target, cc)) { 9257 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); 9258 } 9259 if (!param.ty.isValidParamType(mod)) { 9260 const opaque_str = if (param.ty.zigTypeTag(mod) == .Opaque) "opaque " else ""; 9261 const msg = msg: { 9262 const msg = try sema.errMsg(block, param_src, "parameter of {s}type '{}' not allowed", .{ 9263 opaque_str, param.ty.fmt(mod), 9264 }); 9265 errdefer msg.destroy(sema.gpa); 9266 9267 try sema.addDeclaredHereNote(msg, param.ty); 9268 break :msg msg; 9269 }; 9270 return sema.failWithOwnedErrorMsg(msg); 9271 } 9272 if (!this_generic and !target_util.fnCallConvAllowsZigTypes(target, cc) and !try sema.validateExternType(param.ty, .param_ty)) { 9273 const msg = msg: { 9274 const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{ 9275 param.ty.fmt(mod), @tagName(cc), 9276 }); 9277 errdefer msg.destroy(sema.gpa); 9278 9279 const src_decl = mod.declPtr(block.src_decl); 9280 try sema.explainWhyTypeIsNotExtern(msg, param_src.toSrcLoc(src_decl, mod), param.ty, .param_ty); 9281 9282 try sema.addDeclaredHereNote(msg, param.ty); 9283 break :msg msg; 9284 }; 9285 return sema.failWithOwnedErrorMsg(msg); 9286 } 9287 if (!sema.is_generic_instantiation and requires_comptime and !param.is_comptime and has_body) { 9288 const msg = msg: { 9289 const msg = try sema.errMsg(block, param_src, "parameter of type '{}' must be declared comptime", .{ 9290 param.ty.fmt(mod), 9291 }); 9292 errdefer msg.destroy(sema.gpa); 9293 9294 const src_decl = mod.declPtr(block.src_decl); 9295 try sema.explainWhyTypeIsComptime(msg, param_src.toSrcLoc(src_decl, mod), param.ty); 9296 9297 try sema.addDeclaredHereNote(msg, param.ty); 9298 break :msg msg; 9299 }; 9300 return sema.failWithOwnedErrorMsg(msg); 9301 } 9302 if (!sema.is_generic_instantiation and !this_generic and is_noalias and 9303 !(param.ty.zigTypeTag(mod) == .Pointer or param.ty.isPtrLikeOptional(mod))) 9304 { 9305 return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{}); 9306 } 9307 } 9308 9309 fn zirParam( 9310 sema: *Sema, 9311 block: *Block, 9312 inst: Zir.Inst.Index, 9313 comptime_syntax: bool, 9314 ) CompileError!void { 9315 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok; 9316 const src = inst_data.src(); 9317 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index); 9318 const param_name = sema.code.nullTerminatedString(extra.data.name); 9319 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 9320 9321 // We could be in a generic function instantiation, or we could be evaluating a generic 9322 // function without any comptime args provided. 9323 const param_ty = param_ty: { 9324 const err = err: { 9325 // Make sure any nested param instructions don't clobber our work. 9326 const prev_params = block.params; 9327 const prev_preallocated_new_func = sema.preallocated_new_func; 9328 const prev_no_partial_func_type = sema.no_partial_func_ty; 9329 block.params = .{}; 9330 sema.preallocated_new_func = .none; 9331 sema.no_partial_func_ty = true; 9332 defer { 9333 block.params.deinit(sema.gpa); 9334 block.params = prev_params; 9335 sema.preallocated_new_func = prev_preallocated_new_func; 9336 sema.no_partial_func_ty = prev_no_partial_func_type; 9337 } 9338 9339 if (sema.resolveBody(block, body, inst)) |param_ty_inst| { 9340 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| { 9341 break :param_ty param_ty; 9342 } else |err| break :err err; 9343 } else |err| break :err err; 9344 }; 9345 switch (err) { 9346 error.GenericPoison => { 9347 if (sema.inst_map.get(inst)) |_| { 9348 // A generic function is about to evaluate to another generic function. 9349 // Return an error instead. 9350 return error.GenericPoison; 9351 } 9352 // The type is not available until the generic instantiation. 9353 // We result the param instruction with a poison value and 9354 // insert an anytype parameter. 9355 try block.params.append(sema.gpa, .{ 9356 .ty = Type.generic_poison, 9357 .is_comptime = comptime_syntax, 9358 .name = param_name, 9359 }); 9360 sema.inst_map.putAssumeCapacityNoClobber(inst, .generic_poison); 9361 return; 9362 }, 9363 else => |e| return e, 9364 } 9365 }; 9366 const is_comptime = sema.typeRequiresComptime(param_ty) catch |err| switch (err) { 9367 error.GenericPoison => { 9368 if (sema.inst_map.get(inst)) |_| { 9369 // A generic function is about to evaluate to another generic function. 9370 // Return an error instead. 9371 return error.GenericPoison; 9372 } 9373 // The type is not available until the generic instantiation. 9374 // We result the param instruction with a poison value and 9375 // insert an anytype parameter. 9376 try block.params.append(sema.gpa, .{ 9377 .ty = Type.generic_poison, 9378 .is_comptime = comptime_syntax, 9379 .name = param_name, 9380 }); 9381 sema.inst_map.putAssumeCapacityNoClobber(inst, .generic_poison); 9382 return; 9383 }, 9384 else => |e| return e, 9385 } or comptime_syntax; 9386 if (sema.inst_map.get(inst)) |arg| { 9387 if (is_comptime and sema.preallocated_new_func != .none) { 9388 // We have a comptime value for this parameter so it should be elided from the 9389 // function type of the function instruction in this block. 9390 const coerced_arg = sema.coerce(block, param_ty, arg, .unneeded) catch |err| switch (err) { 9391 error.NeededSourceLocation => { 9392 // We are instantiating a generic function and a comptime arg 9393 // cannot be coerced to the param type, but since we don't 9394 // have the callee source location return `GenericPoison` 9395 // so that the instantiation is failed and the coercion 9396 // is handled by comptime call logic instead. 9397 assert(sema.is_generic_instantiation); 9398 return error.GenericPoison; 9399 }, 9400 else => return err, 9401 }; 9402 sema.inst_map.putAssumeCapacity(inst, coerced_arg); 9403 return; 9404 } 9405 // Even though a comptime argument is provided, the generic function wants to treat 9406 // this as a runtime parameter. 9407 assert(sema.inst_map.remove(inst)); 9408 } 9409 9410 if (sema.preallocated_new_func != .none) { 9411 if (try sema.typeHasOnePossibleValue(param_ty)) |opv| { 9412 // In this case we are instantiating a generic function call with a non-comptime 9413 // non-anytype parameter that ended up being a one-possible-type. 9414 // We don't want the parameter to be part of the instantiated function type. 9415 const result = try sema.addConstant(param_ty, opv); 9416 sema.inst_map.putAssumeCapacity(inst, result); 9417 return; 9418 } 9419 } 9420 9421 try block.params.append(sema.gpa, .{ 9422 .ty = param_ty, 9423 .is_comptime = comptime_syntax, 9424 .name = param_name, 9425 }); 9426 9427 if (is_comptime) { 9428 // If this is a comptime parameter we can add a constant generic_poison 9429 // since this is also a generic parameter. 9430 const result = try sema.addConstant(Type.generic_poison, Value.generic_poison); 9431 sema.inst_map.putAssumeCapacityNoClobber(inst, result); 9432 } else { 9433 // Otherwise we need a dummy runtime instruction. 9434 const result_index = @intCast(Air.Inst.Index, sema.air_instructions.len); 9435 try sema.air_instructions.append(sema.gpa, .{ 9436 .tag = .alloc, 9437 .data = .{ .ty = param_ty }, 9438 }); 9439 const result = Air.indexToRef(result_index); 9440 sema.inst_map.putAssumeCapacityNoClobber(inst, result); 9441 } 9442 } 9443 9444 fn zirParamAnytype( 9445 sema: *Sema, 9446 block: *Block, 9447 inst: Zir.Inst.Index, 9448 comptime_syntax: bool, 9449 ) CompileError!void { 9450 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 9451 const param_name = inst_data.get(sema.code); 9452 9453 if (sema.inst_map.get(inst)) |air_ref| { 9454 const param_ty = sema.typeOf(air_ref); 9455 if (comptime_syntax or try sema.typeRequiresComptime(param_ty)) { 9456 // We have a comptime value for this parameter so it should be elided from the 9457 // function type of the function instruction in this block. 9458 return; 9459 } 9460 if (null != try sema.typeHasOnePossibleValue(param_ty)) { 9461 return; 9462 } 9463 // The map is already populated but we do need to add a runtime parameter. 9464 try block.params.append(sema.gpa, .{ 9465 .ty = param_ty, 9466 .is_comptime = false, 9467 .name = param_name, 9468 }); 9469 return; 9470 } 9471 9472 // We are evaluating a generic function without any comptime args provided. 9473 9474 try block.params.append(sema.gpa, .{ 9475 .ty = Type.generic_poison, 9476 .is_comptime = comptime_syntax, 9477 .name = param_name, 9478 }); 9479 sema.inst_map.putAssumeCapacity(inst, .generic_poison); 9480 } 9481 9482 fn zirAs(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 9483 const tracy = trace(@src()); 9484 defer tracy.end(); 9485 9486 const bin_inst = sema.code.instructions.items(.data)[inst].bin; 9487 return sema.analyzeAs(block, sema.src, bin_inst.lhs, bin_inst.rhs, false); 9488 } 9489 9490 fn zirAsNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 9491 const tracy = trace(@src()); 9492 defer tracy.end(); 9493 9494 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 9495 const src = inst_data.src(); 9496 const extra = sema.code.extraData(Zir.Inst.As, inst_data.payload_index).data; 9497 sema.src = src; 9498 return sema.analyzeAs(block, src, extra.dest_type, extra.operand, false); 9499 } 9500 9501 fn zirAsShiftOperand(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 9502 const tracy = trace(@src()); 9503 defer tracy.end(); 9504 9505 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 9506 const src = inst_data.src(); 9507 const extra = sema.code.extraData(Zir.Inst.As, inst_data.payload_index).data; 9508 return sema.analyzeAs(block, src, extra.dest_type, extra.operand, true); 9509 } 9510 9511 fn analyzeAs( 9512 sema: *Sema, 9513 block: *Block, 9514 src: LazySrcLoc, 9515 zir_dest_type: Zir.Inst.Ref, 9516 zir_operand: Zir.Inst.Ref, 9517 no_cast_to_comptime_int: bool, 9518 ) CompileError!Air.Inst.Ref { 9519 const mod = sema.mod; 9520 const operand = try sema.resolveInst(zir_operand); 9521 if (zir_dest_type == .var_args_param_type) return operand; 9522 const dest_ty = sema.resolveType(block, src, zir_dest_type) catch |err| switch (err) { 9523 error.GenericPoison => return operand, 9524 else => |e| return e, 9525 }; 9526 if (dest_ty.zigTypeTag(mod) == .NoReturn) { 9527 return sema.fail(block, src, "cannot cast to noreturn", .{}); 9528 } 9529 const is_ret = if (Zir.refToIndex(zir_dest_type)) |ptr_index| 9530 sema.code.instructions.items(.tag)[ptr_index] == .ret_type 9531 else 9532 false; 9533 return sema.coerceExtra(block, dest_ty, operand, src, .{ .is_ret = is_ret, .no_cast_to_comptime_int = no_cast_to_comptime_int }) catch |err| switch (err) { 9534 error.NotCoercible => unreachable, 9535 else => |e| return e, 9536 }; 9537 } 9538 9539 fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 9540 const tracy = trace(@src()); 9541 defer tracy.end(); 9542 9543 const mod = sema.mod; 9544 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 9545 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 9546 const ptr = try sema.resolveInst(inst_data.operand); 9547 const ptr_ty = sema.typeOf(ptr); 9548 if (!ptr_ty.isPtrAtRuntime(mod)) { 9549 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}); 9550 } 9551 if (try sema.resolveMaybeUndefValIntable(ptr)) |ptr_val| { 9552 return sema.addConstant( 9553 Type.usize, 9554 try mod.intValue(Type.usize, (try ptr_val.getUnsignedIntAdvanced(mod, sema)).?), 9555 ); 9556 } 9557 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); 9558 return block.addUnOp(.ptrtoint, ptr); 9559 } 9560 9561 fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 9562 const tracy = trace(@src()); 9563 defer tracy.end(); 9564 9565 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 9566 const src = inst_data.src(); 9567 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; 9568 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; 9569 const field_name = sema.code.nullTerminatedString(extra.field_name_start); 9570 const object = try sema.resolveInst(extra.lhs); 9571 return sema.fieldVal(block, src, object, field_name, field_name_src); 9572 } 9573 9574 fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: bool) CompileError!Air.Inst.Ref { 9575 const tracy = trace(@src()); 9576 defer tracy.end(); 9577 9578 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 9579 const src = inst_data.src(); 9580 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; 9581 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; 9582 const field_name = sema.code.nullTerminatedString(extra.field_name_start); 9583 const object_ptr = try sema.resolveInst(extra.lhs); 9584 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing); 9585 } 9586 9587 fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 9588 const tracy = trace(@src()); 9589 defer tracy.end(); 9590 9591 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 9592 const src = inst_data.src(); 9593 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 9594 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; 9595 const object = try sema.resolveInst(extra.lhs); 9596 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime-known"); 9597 return sema.fieldVal(block, src, object, field_name, field_name_src); 9598 } 9599 9600 fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 9601 const tracy = trace(@src()); 9602 defer tracy.end(); 9603 9604 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 9605 const src = inst_data.src(); 9606 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 9607 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; 9608 const object_ptr = try sema.resolveInst(extra.lhs); 9609 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime-known"); 9610 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false); 9611 } 9612 9613 fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 9614 const tracy = trace(@src()); 9615 defer tracy.end(); 9616 9617 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 9618 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 9619 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 9620 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 9621 9622 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); 9623 const operand = try sema.resolveInst(extra.rhs); 9624 9625 return sema.intCast(block, inst_data.src(), dest_ty, dest_ty_src, operand, operand_src, true); 9626 } 9627 9628 fn intCast( 9629 sema: *Sema, 9630 block: *Block, 9631 src: LazySrcLoc, 9632 dest_ty: Type, 9633 dest_ty_src: LazySrcLoc, 9634 operand: Air.Inst.Ref, 9635 operand_src: LazySrcLoc, 9636 runtime_safety: bool, 9637 ) CompileError!Air.Inst.Ref { 9638 const mod = sema.mod; 9639 const operand_ty = sema.typeOf(operand); 9640 const dest_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, dest_ty, dest_ty_src); 9641 const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); 9642 9643 if (try sema.isComptimeKnown(operand)) { 9644 return sema.coerce(block, dest_ty, operand, operand_src); 9645 } else if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeInt) { 9646 return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{}); 9647 } 9648 9649 try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, dest_ty_src, operand_src); 9650 const is_vector = dest_ty.zigTypeTag(mod) == .Vector; 9651 9652 if ((try sema.typeHasOnePossibleValue(dest_ty))) |opv| { 9653 // requirement: intCast(u0, input) iff input == 0 9654 if (runtime_safety and block.wantSafety()) { 9655 try sema.requireRuntimeBlock(block, src, operand_src); 9656 const wanted_info = dest_scalar_ty.intInfo(mod); 9657 const wanted_bits = wanted_info.bits; 9658 9659 if (wanted_bits == 0) { 9660 const ok = if (is_vector) ok: { 9661 const zeros = try sema.splat(operand_ty, try mod.intValue(operand_scalar_ty, 0)); 9662 const zero_inst = try sema.addConstant(operand_ty, zeros); 9663 const is_in_range = try block.addCmpVector(operand, zero_inst, .eq); 9664 const all_in_range = try block.addInst(.{ 9665 .tag = .reduce, 9666 .data = .{ .reduce = .{ .operand = is_in_range, .operation = .And } }, 9667 }); 9668 break :ok all_in_range; 9669 } else ok: { 9670 const zero_inst = try sema.addConstant(operand_ty, try mod.intValue(operand_ty, 0)); 9671 const is_in_range = try block.addBinOp(.cmp_lte, operand, zero_inst); 9672 break :ok is_in_range; 9673 }; 9674 try sema.addSafetyCheck(block, ok, .cast_truncated_data); 9675 } 9676 } 9677 9678 return sema.addConstant(dest_ty, opv); 9679 } 9680 9681 try sema.requireRuntimeBlock(block, src, operand_src); 9682 if (runtime_safety and block.wantSafety()) { 9683 const actual_info = operand_scalar_ty.intInfo(mod); 9684 const wanted_info = dest_scalar_ty.intInfo(mod); 9685 const actual_bits = actual_info.bits; 9686 const wanted_bits = wanted_info.bits; 9687 const actual_value_bits = actual_bits - @boolToInt(actual_info.signedness == .signed); 9688 const wanted_value_bits = wanted_bits - @boolToInt(wanted_info.signedness == .signed); 9689 9690 // range shrinkage 9691 // requirement: int value fits into target type 9692 if (wanted_value_bits < actual_value_bits) { 9693 const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod, operand_scalar_ty); 9694 const dest_max_val = try sema.splat(operand_ty, dest_max_val_scalar); 9695 const dest_max = try sema.addConstant(operand_ty, dest_max_val); 9696 const diff = try block.addBinOp(.subwrap, dest_max, operand); 9697 9698 if (actual_info.signedness == .signed) { 9699 // Reinterpret the sign-bit as part of the value. This will make 9700 // negative differences (`operand` > `dest_max`) appear too big. 9701 const unsigned_operand_ty = try mod.intType(.unsigned, actual_bits); 9702 const diff_unsigned = try block.addBitCast(unsigned_operand_ty, diff); 9703 9704 // If the destination type is signed, then we need to double its 9705 // range to account for negative values. 9706 const dest_range_val = if (wanted_info.signedness == .signed) range_val: { 9707 const one = try mod.intValue(unsigned_operand_ty, 1); 9708 const range_minus_one = try dest_max_val.shl(one, unsigned_operand_ty, sema.arena, mod); 9709 break :range_val try sema.intAdd(range_minus_one, one, unsigned_operand_ty); 9710 } else try mod.getCoerced(dest_max_val, unsigned_operand_ty); 9711 const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val); 9712 9713 const ok = if (is_vector) ok: { 9714 const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte); 9715 const all_in_range = try block.addInst(.{ 9716 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, 9717 .data = .{ .reduce = .{ 9718 .operand = is_in_range, 9719 .operation = .And, 9720 } }, 9721 }); 9722 break :ok all_in_range; 9723 } else ok: { 9724 const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range); 9725 break :ok is_in_range; 9726 }; 9727 // TODO negative_to_unsigned? 9728 try sema.addSafetyCheck(block, ok, .cast_truncated_data); 9729 } else { 9730 const ok = if (is_vector) ok: { 9731 const is_in_range = try block.addCmpVector(diff, dest_max, .lte); 9732 const all_in_range = try block.addInst(.{ 9733 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, 9734 .data = .{ .reduce = .{ 9735 .operand = is_in_range, 9736 .operation = .And, 9737 } }, 9738 }); 9739 break :ok all_in_range; 9740 } else ok: { 9741 const is_in_range = try block.addBinOp(.cmp_lte, diff, dest_max); 9742 break :ok is_in_range; 9743 }; 9744 try sema.addSafetyCheck(block, ok, .cast_truncated_data); 9745 } 9746 } else if (actual_info.signedness == .signed and wanted_info.signedness == .unsigned) { 9747 // no shrinkage, yes sign loss 9748 // requirement: signed to unsigned >= 0 9749 const ok = if (is_vector) ok: { 9750 const scalar_zero = try mod.intValue(operand_scalar_ty, 0); 9751 const zero_val = try sema.splat(operand_ty, scalar_zero); 9752 const zero_inst = try sema.addConstant(operand_ty, zero_val); 9753 const is_in_range = try block.addCmpVector(operand, zero_inst, .gte); 9754 const all_in_range = try block.addInst(.{ 9755 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, 9756 .data = .{ .reduce = .{ 9757 .operand = is_in_range, 9758 .operation = .And, 9759 } }, 9760 }); 9761 break :ok all_in_range; 9762 } else ok: { 9763 const zero_inst = try sema.addConstant(operand_ty, try mod.intValue(operand_ty, 0)); 9764 const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst); 9765 break :ok is_in_range; 9766 }; 9767 try sema.addSafetyCheck(block, ok, .negative_to_unsigned); 9768 } 9769 } 9770 return block.addTyOp(.intcast, dest_ty, operand); 9771 } 9772 9773 fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 9774 const tracy = trace(@src()); 9775 defer tracy.end(); 9776 9777 const mod = sema.mod; 9778 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 9779 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 9780 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 9781 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 9782 9783 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); 9784 const operand = try sema.resolveInst(extra.rhs); 9785 const operand_ty = sema.typeOf(operand); 9786 switch (dest_ty.zigTypeTag(mod)) { 9787 .AnyFrame, 9788 .ComptimeFloat, 9789 .ComptimeInt, 9790 .EnumLiteral, 9791 .ErrorSet, 9792 .ErrorUnion, 9793 .Fn, 9794 .Frame, 9795 .NoReturn, 9796 .Null, 9797 .Opaque, 9798 .Optional, 9799 .Type, 9800 .Undefined, 9801 .Void, 9802 => return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)}), 9803 9804 .Enum => { 9805 const msg = msg: { 9806 const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)}); 9807 errdefer msg.destroy(sema.gpa); 9808 switch (operand_ty.zigTypeTag(mod)) { 9809 .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToEnum to cast from '{}'", .{operand_ty.fmt(sema.mod)}), 9810 else => {}, 9811 } 9812 9813 break :msg msg; 9814 }; 9815 return sema.failWithOwnedErrorMsg(msg); 9816 }, 9817 9818 .Pointer => { 9819 const msg = msg: { 9820 const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)}); 9821 errdefer msg.destroy(sema.gpa); 9822 switch (operand_ty.zigTypeTag(mod)) { 9823 .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToPtr to cast from '{}'", .{operand_ty.fmt(sema.mod)}), 9824 .Pointer => try sema.errNote(block, dest_ty_src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(sema.mod)}), 9825 else => {}, 9826 } 9827 9828 break :msg msg; 9829 }; 9830 return sema.failWithOwnedErrorMsg(msg); 9831 }, 9832 .Struct, .Union => if (dest_ty.containerLayout(mod) == .Auto) { 9833 const container = switch (dest_ty.zigTypeTag(mod)) { 9834 .Struct => "struct", 9835 .Union => "union", 9836 else => unreachable, 9837 }; 9838 return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'; {s} does not have a guaranteed in-memory layout", .{ 9839 dest_ty.fmt(sema.mod), container, 9840 }); 9841 }, 9842 9843 .Array, 9844 .Bool, 9845 .Float, 9846 .Int, 9847 .Vector, 9848 => {}, 9849 } 9850 switch (operand_ty.zigTypeTag(mod)) { 9851 .AnyFrame, 9852 .ComptimeFloat, 9853 .ComptimeInt, 9854 .EnumLiteral, 9855 .ErrorSet, 9856 .ErrorUnion, 9857 .Fn, 9858 .Frame, 9859 .NoReturn, 9860 .Null, 9861 .Opaque, 9862 .Optional, 9863 .Type, 9864 .Undefined, 9865 .Void, 9866 => return sema.fail(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)}), 9867 9868 .Enum => { 9869 const msg = msg: { 9870 const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)}); 9871 errdefer msg.destroy(sema.gpa); 9872 switch (dest_ty.zigTypeTag(mod)) { 9873 .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @enumToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}), 9874 else => {}, 9875 } 9876 9877 break :msg msg; 9878 }; 9879 return sema.failWithOwnedErrorMsg(msg); 9880 }, 9881 .Pointer => { 9882 const msg = msg: { 9883 const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)}); 9884 errdefer msg.destroy(sema.gpa); 9885 switch (dest_ty.zigTypeTag(mod)) { 9886 .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @ptrToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}), 9887 .Pointer => try sema.errNote(block, operand_src, msg, "use @ptrCast to cast to '{}'", .{dest_ty.fmt(sema.mod)}), 9888 else => {}, 9889 } 9890 9891 break :msg msg; 9892 }; 9893 return sema.failWithOwnedErrorMsg(msg); 9894 }, 9895 .Struct, .Union => if (operand_ty.containerLayout(mod) == .Auto) { 9896 const container = switch (operand_ty.zigTypeTag(mod)) { 9897 .Struct => "struct", 9898 .Union => "union", 9899 else => unreachable, 9900 }; 9901 return sema.fail(block, operand_src, "cannot @bitCast from '{}'; {s} does not have a guaranteed in-memory layout", .{ 9902 operand_ty.fmt(sema.mod), container, 9903 }); 9904 }, 9905 9906 .Array, 9907 .Bool, 9908 .Float, 9909 .Int, 9910 .Vector, 9911 => {}, 9912 } 9913 return sema.bitCast(block, dest_ty, operand, inst_data.src(), operand_src); 9914 } 9915 9916 fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 9917 const tracy = trace(@src()); 9918 defer tracy.end(); 9919 9920 const mod = sema.mod; 9921 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 9922 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 9923 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 9924 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 9925 9926 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); 9927 const operand = try sema.resolveInst(extra.rhs); 9928 9929 const target = sema.mod.getTarget(); 9930 const dest_is_comptime_float = switch (dest_ty.zigTypeTag(mod)) { 9931 .ComptimeFloat => true, 9932 .Float => false, 9933 else => return sema.fail( 9934 block, 9935 dest_ty_src, 9936 "expected float type, found '{}'", 9937 .{dest_ty.fmt(sema.mod)}, 9938 ), 9939 }; 9940 9941 const operand_ty = sema.typeOf(operand); 9942 switch (operand_ty.zigTypeTag(mod)) { 9943 .ComptimeFloat, .Float, .ComptimeInt => {}, 9944 else => return sema.fail( 9945 block, 9946 operand_src, 9947 "expected float type, found '{}'", 9948 .{operand_ty.fmt(sema.mod)}, 9949 ), 9950 } 9951 9952 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { 9953 return sema.addConstant(dest_ty, try operand_val.floatCast(dest_ty, mod)); 9954 } 9955 if (dest_is_comptime_float) { 9956 return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_float'", .{}); 9957 } 9958 const src_bits = operand_ty.floatBits(target); 9959 const dst_bits = dest_ty.floatBits(target); 9960 if (dst_bits >= src_bits) { 9961 return sema.coerce(block, dest_ty, operand, operand_src); 9962 } 9963 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); 9964 return block.addTyOp(.fptrunc, dest_ty, operand); 9965 } 9966 9967 fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 9968 const tracy = trace(@src()); 9969 defer tracy.end(); 9970 9971 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 9972 const src = inst_data.src(); 9973 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 9974 const array = try sema.resolveInst(extra.lhs); 9975 const elem_index = try sema.resolveInst(extra.rhs); 9976 return sema.elemVal(block, src, array, elem_index, src, false); 9977 } 9978 9979 fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 9980 const tracy = trace(@src()); 9981 defer tracy.end(); 9982 9983 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 9984 const src = inst_data.src(); 9985 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node }; 9986 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 9987 const array = try sema.resolveInst(extra.lhs); 9988 const elem_index = try sema.resolveInst(extra.rhs); 9989 return sema.elemVal(block, src, array, elem_index, elem_index_src, true); 9990 } 9991 9992 fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 9993 const tracy = trace(@src()); 9994 defer tracy.end(); 9995 9996 const mod = sema.mod; 9997 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 9998 const src = inst_data.src(); 9999 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 10000 const array_ptr = try sema.resolveInst(extra.lhs); 10001 const elem_index = try sema.resolveInst(extra.rhs); 10002 const indexable_ty = sema.typeOf(array_ptr); 10003 if (indexable_ty.zigTypeTag(mod) != .Pointer) { 10004 const capture_src: LazySrcLoc = .{ .for_capture_from_input = inst_data.src_node }; 10005 const msg = msg: { 10006 const msg = try sema.errMsg(block, capture_src, "pointer capture of non pointer type '{}'", .{ 10007 indexable_ty.fmt(sema.mod), 10008 }); 10009 errdefer msg.destroy(sema.gpa); 10010 if (indexable_ty.zigTypeTag(mod) == .Array) { 10011 try sema.errNote(block, src, msg, "consider using '&' here", .{}); 10012 } 10013 break :msg msg; 10014 }; 10015 return sema.failWithOwnedErrorMsg(msg); 10016 } 10017 return sema.elemPtrOneLayerOnly(block, src, array_ptr, elem_index, src, false, false); 10018 } 10019 10020 fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 10021 const tracy = trace(@src()); 10022 defer tracy.end(); 10023 10024 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 10025 const src = inst_data.src(); 10026 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node }; 10027 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 10028 const array_ptr = try sema.resolveInst(extra.lhs); 10029 const elem_index = try sema.resolveInst(extra.rhs); 10030 return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false, true); 10031 } 10032 10033 fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 10034 const tracy = trace(@src()); 10035 defer tracy.end(); 10036 10037 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 10038 const src = inst_data.src(); 10039 const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data; 10040 const array_ptr = try sema.resolveInst(extra.ptr); 10041 const elem_index = try sema.addIntUnsigned(Type.usize, extra.index); 10042 return sema.elemPtr(block, src, array_ptr, elem_index, src, true, true); 10043 } 10044 10045 fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 10046 const tracy = trace(@src()); 10047 defer tracy.end(); 10048 10049 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 10050 const src = inst_data.src(); 10051 const extra = sema.code.extraData(Zir.Inst.SliceStart, inst_data.payload_index).data; 10052 const array_ptr = try sema.resolveInst(extra.lhs); 10053 const start = try sema.resolveInst(extra.start); 10054 const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node }; 10055 const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; 10056 const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; 10057 10058 return sema.analyzeSlice(block, src, array_ptr, start, .none, .none, .unneeded, ptr_src, start_src, end_src, false); 10059 } 10060 10061 fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 10062 const tracy = trace(@src()); 10063 defer tracy.end(); 10064 10065 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 10066 const src = inst_data.src(); 10067 const extra = sema.code.extraData(Zir.Inst.SliceEnd, inst_data.payload_index).data; 10068 const array_ptr = try sema.resolveInst(extra.lhs); 10069 const start = try sema.resolveInst(extra.start); 10070 const end = try sema.resolveInst(extra.end); 10071 const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node }; 10072 const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; 10073 const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; 10074 10075 return sema.analyzeSlice(block, src, array_ptr, start, end, .none, .unneeded, ptr_src, start_src, end_src, false); 10076 } 10077 10078 fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 10079 const tracy = trace(@src()); 10080 defer tracy.end(); 10081 10082 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 10083 const src = inst_data.src(); 10084 const sentinel_src: LazySrcLoc = .{ .node_offset_slice_sentinel = inst_data.src_node }; 10085 const extra = sema.code.extraData(Zir.Inst.SliceSentinel, inst_data.payload_index).data; 10086 const array_ptr = try sema.resolveInst(extra.lhs); 10087 const start = try sema.resolveInst(extra.start); 10088 const end = try sema.resolveInst(extra.end); 10089 const sentinel = try sema.resolveInst(extra.sentinel); 10090 const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node }; 10091 const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; 10092 const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; 10093 10094 return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src, ptr_src, start_src, end_src, false); 10095 } 10096 10097 fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 10098 const tracy = trace(@src()); 10099 defer tracy.end(); 10100 10101 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 10102 const src = inst_data.src(); 10103 const extra = sema.code.extraData(Zir.Inst.SliceLength, inst_data.payload_index).data; 10104 const array_ptr = try sema.resolveInst(extra.lhs); 10105 const start = try sema.resolveInst(extra.start); 10106 const len = try sema.resolveInst(extra.len); 10107 const sentinel = if (extra.sentinel == .none) .none else try sema.resolveInst(extra.sentinel); 10108 const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node }; 10109 const start_src: LazySrcLoc = .{ .node_offset_slice_start = extra.start_src_node_offset }; 10110 const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; 10111 const sentinel_src: LazySrcLoc = if (sentinel == .none) 10112 .unneeded 10113 else 10114 .{ .node_offset_slice_sentinel = inst_data.src_node }; 10115 10116 return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true); 10117 } 10118 10119 fn zirSwitchCapture( 10120 sema: *Sema, 10121 block: *Block, 10122 inst: Zir.Inst.Index, 10123 is_multi: bool, 10124 is_ref: bool, 10125 ) CompileError!Air.Inst.Ref { 10126 const tracy = trace(@src()); 10127 defer tracy.end(); 10128 10129 const mod = sema.mod; 10130 const gpa = sema.gpa; 10131 const zir_datas = sema.code.instructions.items(.data); 10132 const capture_info = zir_datas[inst].switch_capture; 10133 const switch_info = zir_datas[capture_info.switch_inst].pl_node; 10134 const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index); 10135 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_info.src_node }; 10136 const cond_inst = Zir.refToIndex(switch_extra.data.operand).?; 10137 const cond_info = zir_datas[cond_inst].un_node; 10138 const cond_tag = sema.code.instructions.items(.tag)[cond_inst]; 10139 const operand_is_ref = cond_tag == .switch_cond_ref; 10140 const operand_ptr = try sema.resolveInst(cond_info.operand); 10141 const operand_ptr_ty = sema.typeOf(operand_ptr); 10142 const operand_ty = if (operand_is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty; 10143 10144 if (block.inline_case_capture != .none) { 10145 const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable; 10146 const resolved_item_val = try sema.resolveLazyValue(item_val); 10147 if (operand_ty.zigTypeTag(mod) == .Union) { 10148 const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(resolved_item_val, sema.mod).?); 10149 const union_obj = mod.typeToUnion(operand_ty).?; 10150 const field_ty = union_obj.fields.values()[field_index].ty; 10151 if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| { 10152 if (is_ref) { 10153 const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{ 10154 .pointee_type = field_ty, 10155 .mutable = operand_ptr_ty.ptrIsMutable(mod), 10156 .@"volatile" = operand_ptr_ty.isVolatilePtr(mod), 10157 .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod), 10158 }); 10159 return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ 10160 .ty = ptr_field_ty.toIntern(), 10161 .addr = .{ .field = .{ 10162 .base = union_val.toIntern(), 10163 .index = field_index, 10164 } }, 10165 } })).toValue()); 10166 } 10167 return sema.addConstant( 10168 field_ty, 10169 mod.intern_pool.indexToKey(union_val.toIntern()).un.val.toValue(), 10170 ); 10171 } 10172 if (is_ref) { 10173 const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{ 10174 .pointee_type = field_ty, 10175 .mutable = operand_ptr_ty.ptrIsMutable(mod), 10176 .@"volatile" = operand_ptr_ty.isVolatilePtr(mod), 10177 .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod), 10178 }); 10179 return block.addStructFieldPtr(operand_ptr, field_index, ptr_field_ty); 10180 } else { 10181 return block.addStructFieldVal(operand_ptr, field_index, field_ty); 10182 } 10183 } else if (is_ref) { 10184 return sema.addConstantMaybeRef(block, operand_ty, resolved_item_val, true); 10185 } else { 10186 return block.inline_case_capture; 10187 } 10188 } 10189 10190 const operand = if (operand_is_ref) 10191 try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src) 10192 else 10193 operand_ptr; 10194 10195 if (capture_info.prong_index == std.math.maxInt(@TypeOf(capture_info.prong_index))) { 10196 // It is the else/`_` prong. 10197 if (is_ref) { 10198 return operand_ptr; 10199 } 10200 10201 switch (operand_ty.zigTypeTag(mod)) { 10202 .ErrorSet => if (block.switch_else_err_ty) |some| { 10203 return sema.bitCast(block, some, operand, operand_src, null); 10204 } else { 10205 try block.addUnreachable(false); 10206 return Air.Inst.Ref.unreachable_value; 10207 }, 10208 else => return operand, 10209 } 10210 } 10211 10212 const items = if (is_multi) 10213 switch_extra.data.getMultiProng(sema.code, switch_extra.end, capture_info.prong_index).items 10214 else 10215 &[_]Zir.Inst.Ref{ 10216 switch_extra.data.getScalarProng(sema.code, switch_extra.end, capture_info.prong_index).item, 10217 }; 10218 10219 switch (operand_ty.zigTypeTag(mod)) { 10220 .Union => { 10221 const union_obj = mod.typeToUnion(operand_ty).?; 10222 const first_item = try sema.resolveInst(items[0]); 10223 // Previous switch validation ensured this will succeed 10224 const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, "") catch unreachable; 10225 10226 const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, sema.mod).?); 10227 const first_field = union_obj.fields.values()[first_field_index]; 10228 10229 for (items[1..], 0..) |item, i| { 10230 const item_ref = try sema.resolveInst(item); 10231 // Previous switch validation ensured this will succeed 10232 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable; 10233 10234 const field_index = operand_ty.unionTagFieldIndex(item_val, sema.mod).?; 10235 const field = union_obj.fields.values()[field_index]; 10236 if (!field.ty.eql(first_field.ty, sema.mod)) { 10237 const msg = msg: { 10238 const raw_capture_src = Module.SwitchProngSrc{ .multi_capture = capture_info.prong_index }; 10239 const capture_src = raw_capture_src.resolve(mod, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first); 10240 10241 const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{}); 10242 errdefer msg.destroy(gpa); 10243 10244 const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 0 } }; 10245 const first_item_src = raw_first_item_src.resolve(mod, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first); 10246 const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 1 + @intCast(u32, i) } }; 10247 const item_src = raw_item_src.resolve(mod, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first); 10248 try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(sema.mod)}); 10249 try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(sema.mod)}); 10250 break :msg msg; 10251 }; 10252 return sema.failWithOwnedErrorMsg(msg); 10253 } 10254 } 10255 10256 if (is_ref) { 10257 const field_ty_ptr = try Type.ptr(sema.arena, sema.mod, .{ 10258 .pointee_type = first_field.ty, 10259 .@"addrspace" = .generic, 10260 .mutable = operand_ptr_ty.ptrIsMutable(mod), 10261 }); 10262 10263 if (try sema.resolveDefinedValue(block, operand_src, operand_ptr)) |op_ptr_val| { 10264 return sema.addConstant(field_ty_ptr, (try mod.intern(.{ .ptr = .{ 10265 .ty = field_ty_ptr.toIntern(), 10266 .addr = .{ .field = .{ 10267 .base = op_ptr_val.toIntern(), 10268 .index = first_field_index, 10269 } }, 10270 } })).toValue()); 10271 } 10272 try sema.requireRuntimeBlock(block, operand_src, null); 10273 return block.addStructFieldPtr(operand_ptr, first_field_index, field_ty_ptr); 10274 } 10275 10276 if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| { 10277 return sema.addConstant( 10278 first_field.ty, 10279 mod.intern_pool.indexToKey(operand_val.toIntern()).un.val.toValue(), 10280 ); 10281 } 10282 try sema.requireRuntimeBlock(block, operand_src, null); 10283 return block.addStructFieldVal(operand, first_field_index, first_field.ty); 10284 }, 10285 .ErrorSet => { 10286 if (is_multi) { 10287 var names: Module.Fn.InferredErrorSet.NameMap = .{}; 10288 try names.ensureUnusedCapacity(sema.arena, items.len); 10289 for (items) |item| { 10290 const item_ref = try sema.resolveInst(item); 10291 // Previous switch validation ensured this will succeed 10292 const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable; 10293 const name_ip = try mod.intern_pool.getOrPutString(gpa, item_val.getError(mod).?); 10294 names.putAssumeCapacityNoClobber(name_ip, {}); 10295 } 10296 const else_error_ty = try mod.errorSetFromUnsortedNames(names.keys()); 10297 10298 return sema.bitCast(block, else_error_ty, operand, operand_src, null); 10299 } else { 10300 const item_ref = try sema.resolveInst(items[0]); 10301 // Previous switch validation ensured this will succeed 10302 const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable; 10303 10304 const item_ty = try mod.singleErrorSetType(item_val.getError(mod).?); 10305 return sema.bitCast(block, item_ty, operand, operand_src, null); 10306 } 10307 }, 10308 else => { 10309 // In this case the capture value is just the passed-through value of the 10310 // switch condition. 10311 if (is_ref) { 10312 return operand_ptr; 10313 } else { 10314 return operand; 10315 } 10316 }, 10317 } 10318 } 10319 10320 fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 10321 const mod = sema.mod; 10322 const zir_datas = sema.code.instructions.items(.data); 10323 const inst_data = zir_datas[inst].un_tok; 10324 const src = inst_data.src(); 10325 10326 const switch_tag = sema.code.instructions.items(.tag)[Zir.refToIndex(inst_data.operand).?]; 10327 const is_ref = switch_tag == .switch_cond_ref; 10328 const cond_data = zir_datas[Zir.refToIndex(inst_data.operand).?].un_node; 10329 const operand_ptr = try sema.resolveInst(cond_data.operand); 10330 const operand_ptr_ty = sema.typeOf(operand_ptr); 10331 const operand_ty = if (is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty; 10332 10333 if (operand_ty.zigTypeTag(mod) != .Union) { 10334 const msg = msg: { 10335 const msg = try sema.errMsg(block, src, "cannot capture tag of non-union type '{}'", .{ 10336 operand_ty.fmt(sema.mod), 10337 }); 10338 errdefer msg.destroy(sema.gpa); 10339 try sema.addDeclaredHereNote(msg, operand_ty); 10340 break :msg msg; 10341 }; 10342 return sema.failWithOwnedErrorMsg(msg); 10343 } 10344 10345 return block.inline_case_capture; 10346 } 10347 10348 fn zirSwitchCond( 10349 sema: *Sema, 10350 block: *Block, 10351 inst: Zir.Inst.Index, 10352 is_ref: bool, 10353 ) CompileError!Air.Inst.Ref { 10354 const mod = sema.mod; 10355 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 10356 const src = inst_data.src(); 10357 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node }; 10358 const operand_ptr = try sema.resolveInst(inst_data.operand); 10359 const operand = if (is_ref) 10360 try sema.analyzeLoad(block, src, operand_ptr, operand_src) 10361 else 10362 operand_ptr; 10363 const operand_ty = sema.typeOf(operand); 10364 10365 switch (operand_ty.zigTypeTag(mod)) { 10366 .Type, 10367 .Void, 10368 .Bool, 10369 .Int, 10370 .Float, 10371 .ComptimeFloat, 10372 .ComptimeInt, 10373 .EnumLiteral, 10374 .Pointer, 10375 .Fn, 10376 .ErrorSet, 10377 .Enum, 10378 => { 10379 if (operand_ty.isSlice(mod)) { 10380 return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)}); 10381 } 10382 if ((try sema.typeHasOnePossibleValue(operand_ty))) |opv| { 10383 return sema.addConstant(operand_ty, opv); 10384 } 10385 return operand; 10386 }, 10387 10388 .Union => { 10389 const union_ty = try sema.resolveTypeFields(operand_ty); 10390 const enum_ty = union_ty.unionTagType(mod) orelse { 10391 const msg = msg: { 10392 const msg = try sema.errMsg(block, src, "switch on union with no attached enum", .{}); 10393 errdefer msg.destroy(sema.gpa); 10394 if (union_ty.declSrcLocOrNull(sema.mod)) |union_src| { 10395 try sema.mod.errNoteNonLazy(union_src, msg, "consider 'union(enum)' here", .{}); 10396 } 10397 break :msg msg; 10398 }; 10399 return sema.failWithOwnedErrorMsg(msg); 10400 }; 10401 return sema.unionToTag(block, enum_ty, operand, src); 10402 }, 10403 10404 .ErrorUnion, 10405 .NoReturn, 10406 .Array, 10407 .Struct, 10408 .Undefined, 10409 .Null, 10410 .Optional, 10411 .Opaque, 10412 .Vector, 10413 .Frame, 10414 .AnyFrame, 10415 => return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)}), 10416 } 10417 } 10418 10419 const SwitchErrorSet = std.StringHashMap(Module.SwitchProngSrc); 10420 10421 fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 10422 const tracy = trace(@src()); 10423 defer tracy.end(); 10424 10425 const mod = sema.mod; 10426 const gpa = sema.gpa; 10427 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 10428 const src = inst_data.src(); 10429 const src_node_offset = inst_data.src_node; 10430 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset }; 10431 const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset }; 10432 const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); 10433 10434 const operand = try sema.resolveInst(extra.data.operand); 10435 // AstGen guarantees that the instruction immediately following 10436 // switch_cond(_ref) is a dbg_stmt 10437 const cond_dbg_node_index = Zir.refToIndex(extra.data.operand).? + 1; 10438 10439 var header_extra_index: usize = extra.end; 10440 10441 const scalar_cases_len = extra.data.bits.scalar_cases_len; 10442 const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: { 10443 const multi_cases_len = sema.code.extra[header_extra_index]; 10444 header_extra_index += 1; 10445 break :blk multi_cases_len; 10446 } else 0; 10447 10448 const special_prong = extra.data.bits.specialProng(); 10449 const special: struct { body: []const Zir.Inst.Index, end: usize, is_inline: bool } = switch (special_prong) { 10450 .none => .{ .body = &.{}, .end = header_extra_index, .is_inline = false }, 10451 .under, .@"else" => blk: { 10452 const body_len = @truncate(u31, sema.code.extra[header_extra_index]); 10453 const extra_body_start = header_extra_index + 1; 10454 break :blk .{ 10455 .body = sema.code.extra[extra_body_start..][0..body_len], 10456 .end = extra_body_start + body_len, 10457 .is_inline = sema.code.extra[header_extra_index] >> 31 != 0, 10458 }; 10459 }, 10460 }; 10461 10462 const maybe_union_ty = blk: { 10463 const zir_tags = sema.code.instructions.items(.tag); 10464 const zir_data = sema.code.instructions.items(.data); 10465 const cond_index = Zir.refToIndex(extra.data.operand).?; 10466 const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable; 10467 const target_ty = sema.typeOf(raw_operand); 10468 break :blk if (zir_tags[cond_index] == .switch_cond_ref) target_ty.childType(mod) else target_ty; 10469 }; 10470 const union_originally = maybe_union_ty.zigTypeTag(mod) == .Union; 10471 10472 // Duplicate checking variables later also used for `inline else`. 10473 var seen_enum_fields: []?Module.SwitchProngSrc = &.{}; 10474 var seen_errors = SwitchErrorSet.init(gpa); 10475 var range_set = RangeSet.init(gpa, mod); 10476 var true_count: u8 = 0; 10477 var false_count: u8 = 0; 10478 10479 defer { 10480 range_set.deinit(); 10481 gpa.free(seen_enum_fields); 10482 seen_errors.deinit(); 10483 } 10484 10485 var empty_enum = false; 10486 10487 const operand_ty = sema.typeOf(operand); 10488 const err_set = operand_ty.zigTypeTag(mod) == .ErrorSet; 10489 10490 var else_error_ty: ?Type = null; 10491 10492 // Validate usage of '_' prongs. 10493 if (special_prong == .under and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally)) { 10494 const msg = msg: { 10495 const msg = try sema.errMsg( 10496 block, 10497 src, 10498 "'_' prong only allowed when switching on non-exhaustive enums", 10499 .{}, 10500 ); 10501 errdefer msg.destroy(gpa); 10502 try sema.errNote( 10503 block, 10504 special_prong_src, 10505 msg, 10506 "'_' prong here", 10507 .{}, 10508 ); 10509 break :msg msg; 10510 }; 10511 return sema.failWithOwnedErrorMsg(msg); 10512 } 10513 10514 // Validate for duplicate items, missing else prong, and invalid range. 10515 switch (operand_ty.zigTypeTag(mod)) { 10516 .Union => unreachable, // handled in zirSwitchCond 10517 .Enum => { 10518 seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount(mod)); 10519 empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(mod); 10520 @memset(seen_enum_fields, null); 10521 // `range_set` is used for non-exhaustive enum values that do not correspond to any tags. 10522 10523 var extra_index: usize = special.end; 10524 { 10525 var scalar_i: u32 = 0; 10526 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 10527 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 10528 extra_index += 1; 10529 const body_len = @truncate(u31, sema.code.extra[extra_index]); 10530 extra_index += 1; 10531 extra_index += body_len; 10532 10533 try sema.validateSwitchItemEnum( 10534 block, 10535 seen_enum_fields, 10536 &range_set, 10537 item_ref, 10538 src_node_offset, 10539 .{ .scalar = scalar_i }, 10540 ); 10541 } 10542 } 10543 { 10544 var multi_i: u32 = 0; 10545 while (multi_i < multi_cases_len) : (multi_i += 1) { 10546 const items_len = sema.code.extra[extra_index]; 10547 extra_index += 1; 10548 const ranges_len = sema.code.extra[extra_index]; 10549 extra_index += 1; 10550 const body_len = @truncate(u31, sema.code.extra[extra_index]); 10551 extra_index += 1; 10552 const items = sema.code.refSlice(extra_index, items_len); 10553 extra_index += items_len + body_len; 10554 10555 for (items, 0..) |item_ref, item_i| { 10556 try sema.validateSwitchItemEnum( 10557 block, 10558 seen_enum_fields, 10559 &range_set, 10560 item_ref, 10561 src_node_offset, 10562 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, 10563 ); 10564 } 10565 10566 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); 10567 } 10568 } 10569 const all_tags_handled = for (seen_enum_fields) |seen_src| { 10570 if (seen_src == null) break false; 10571 } else true; 10572 10573 if (special_prong == .@"else") { 10574 if (all_tags_handled and !operand_ty.isNonexhaustiveEnum(mod)) return sema.fail( 10575 block, 10576 special_prong_src, 10577 "unreachable else prong; all cases already handled", 10578 .{}, 10579 ); 10580 } else if (!all_tags_handled) { 10581 const msg = msg: { 10582 const msg = try sema.errMsg( 10583 block, 10584 src, 10585 "switch must handle all possibilities", 10586 .{}, 10587 ); 10588 errdefer msg.destroy(sema.gpa); 10589 for (seen_enum_fields, 0..) |seen_src, i| { 10590 if (seen_src != null) continue; 10591 10592 const field_name = operand_ty.enumFieldName(i, mod); 10593 try sema.addFieldErrNote( 10594 operand_ty, 10595 i, 10596 msg, 10597 "unhandled enumeration value: '{s}'", 10598 .{field_name}, 10599 ); 10600 } 10601 try mod.errNoteNonLazy( 10602 operand_ty.declSrcLoc(mod), 10603 msg, 10604 "enum '{}' declared here", 10605 .{operand_ty.fmt(mod)}, 10606 ); 10607 break :msg msg; 10608 }; 10609 return sema.failWithOwnedErrorMsg(msg); 10610 } else if (special_prong == .none and operand_ty.isNonexhaustiveEnum(mod) and !union_originally) { 10611 return sema.fail( 10612 block, 10613 src, 10614 "switch on non-exhaustive enum must include 'else' or '_' prong", 10615 .{}, 10616 ); 10617 } 10618 }, 10619 .ErrorSet => { 10620 var extra_index: usize = special.end; 10621 { 10622 var scalar_i: u32 = 0; 10623 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 10624 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 10625 extra_index += 1; 10626 const body_len = @truncate(u31, sema.code.extra[extra_index]); 10627 extra_index += 1; 10628 extra_index += body_len; 10629 10630 try sema.validateSwitchItemError( 10631 block, 10632 &seen_errors, 10633 item_ref, 10634 src_node_offset, 10635 .{ .scalar = scalar_i }, 10636 ); 10637 } 10638 } 10639 { 10640 var multi_i: u32 = 0; 10641 while (multi_i < multi_cases_len) : (multi_i += 1) { 10642 const items_len = sema.code.extra[extra_index]; 10643 extra_index += 1; 10644 const ranges_len = sema.code.extra[extra_index]; 10645 extra_index += 1; 10646 const body_len = @truncate(u31, sema.code.extra[extra_index]); 10647 extra_index += 1; 10648 const items = sema.code.refSlice(extra_index, items_len); 10649 extra_index += items_len + body_len; 10650 10651 for (items, 0..) |item_ref, item_i| { 10652 try sema.validateSwitchItemError( 10653 block, 10654 &seen_errors, 10655 item_ref, 10656 src_node_offset, 10657 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, 10658 ); 10659 } 10660 10661 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); 10662 } 10663 } 10664 10665 try sema.resolveInferredErrorSetTy(block, src, operand_ty); 10666 10667 if (operand_ty.isAnyError(mod)) { 10668 if (special_prong != .@"else") { 10669 return sema.fail( 10670 block, 10671 src, 10672 "else prong required when switching on type 'anyerror'", 10673 .{}, 10674 ); 10675 } 10676 else_error_ty = Type.anyerror; 10677 } else else_validation: { 10678 var maybe_msg: ?*Module.ErrorMsg = null; 10679 errdefer if (maybe_msg) |msg| msg.destroy(sema.gpa); 10680 10681 for (operand_ty.errorSetNames(mod)) |error_name_ip| { 10682 const error_name = mod.intern_pool.stringToSlice(error_name_ip); 10683 if (!seen_errors.contains(error_name) and special_prong != .@"else") { 10684 const msg = maybe_msg orelse blk: { 10685 maybe_msg = try sema.errMsg( 10686 block, 10687 src, 10688 "switch must handle all possibilities", 10689 .{}, 10690 ); 10691 break :blk maybe_msg.?; 10692 }; 10693 10694 try sema.errNote( 10695 block, 10696 src, 10697 msg, 10698 "unhandled error value: 'error.{s}'", 10699 .{error_name}, 10700 ); 10701 } 10702 } 10703 10704 if (maybe_msg) |msg| { 10705 maybe_msg = null; 10706 try sema.addDeclaredHereNote(msg, operand_ty); 10707 return sema.failWithOwnedErrorMsg(msg); 10708 } 10709 10710 if (special_prong == .@"else" and seen_errors.count() == operand_ty.errorSetNames(mod).len) { 10711 // In order to enable common patterns for generic code allow simple else bodies 10712 // else => unreachable, 10713 // else => return, 10714 // else => |e| return e, 10715 // even if all the possible errors were already handled. 10716 const tags = sema.code.instructions.items(.tag); 10717 for (special.body) |else_inst| switch (tags[else_inst]) { 10718 .dbg_block_begin, 10719 .dbg_block_end, 10720 .dbg_stmt, 10721 .dbg_var_val, 10722 .switch_capture, 10723 .ret_type, 10724 .as_node, 10725 .ret_node, 10726 .@"unreachable", 10727 .@"defer", 10728 .defer_err_code, 10729 .err_union_code, 10730 .ret_err_value_code, 10731 .restore_err_ret_index, 10732 .is_non_err, 10733 .ret_is_non_err, 10734 .condbr, 10735 => {}, 10736 else => break, 10737 } else break :else_validation; 10738 10739 return sema.fail( 10740 block, 10741 special_prong_src, 10742 "unreachable else prong; all cases already handled", 10743 .{}, 10744 ); 10745 } 10746 10747 const error_names = operand_ty.errorSetNames(mod); 10748 var names: Module.Fn.InferredErrorSet.NameMap = .{}; 10749 try names.ensureUnusedCapacity(sema.arena, error_names.len); 10750 for (error_names) |error_name_ip| { 10751 const error_name = mod.intern_pool.stringToSlice(error_name_ip); 10752 if (seen_errors.contains(error_name)) continue; 10753 10754 names.putAssumeCapacityNoClobber(error_name_ip, {}); 10755 } 10756 // No need to keep the hash map metadata correct; here we 10757 // extract the (sorted) keys only. 10758 else_error_ty = try mod.errorSetFromUnsortedNames(names.keys()); 10759 } 10760 }, 10761 .Int, .ComptimeInt => { 10762 var extra_index: usize = special.end; 10763 { 10764 var scalar_i: u32 = 0; 10765 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 10766 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 10767 extra_index += 1; 10768 const body_len = @truncate(u31, sema.code.extra[extra_index]); 10769 extra_index += 1; 10770 extra_index += body_len; 10771 10772 try sema.validateSwitchItem( 10773 block, 10774 &range_set, 10775 item_ref, 10776 src_node_offset, 10777 .{ .scalar = scalar_i }, 10778 ); 10779 } 10780 } 10781 { 10782 var multi_i: u32 = 0; 10783 while (multi_i < multi_cases_len) : (multi_i += 1) { 10784 const items_len = sema.code.extra[extra_index]; 10785 extra_index += 1; 10786 const ranges_len = sema.code.extra[extra_index]; 10787 extra_index += 1; 10788 const body_len = @truncate(u31, sema.code.extra[extra_index]); 10789 extra_index += 1; 10790 const items = sema.code.refSlice(extra_index, items_len); 10791 extra_index += items_len; 10792 10793 for (items, 0..) |item_ref, item_i| { 10794 try sema.validateSwitchItem( 10795 block, 10796 &range_set, 10797 item_ref, 10798 src_node_offset, 10799 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, 10800 ); 10801 } 10802 10803 var range_i: u32 = 0; 10804 while (range_i < ranges_len) : (range_i += 1) { 10805 const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 10806 extra_index += 1; 10807 const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 10808 extra_index += 1; 10809 10810 try sema.validateSwitchRange( 10811 block, 10812 &range_set, 10813 item_first, 10814 item_last, 10815 src_node_offset, 10816 .{ .range = .{ .prong = multi_i, .item = range_i } }, 10817 ); 10818 } 10819 10820 extra_index += body_len; 10821 } 10822 } 10823 10824 check_range: { 10825 if (operand_ty.zigTypeTag(mod) == .Int) { 10826 const min_int = try operand_ty.minInt(mod, operand_ty); 10827 const max_int = try operand_ty.maxInt(mod, operand_ty); 10828 if (try range_set.spans(min_int.toIntern(), max_int.toIntern())) { 10829 if (special_prong == .@"else") { 10830 return sema.fail( 10831 block, 10832 special_prong_src, 10833 "unreachable else prong; all cases already handled", 10834 .{}, 10835 ); 10836 } 10837 break :check_range; 10838 } 10839 } 10840 if (special_prong != .@"else") { 10841 return sema.fail( 10842 block, 10843 src, 10844 "switch must handle all possibilities", 10845 .{}, 10846 ); 10847 } 10848 } 10849 }, 10850 .Bool => { 10851 var extra_index: usize = special.end; 10852 { 10853 var scalar_i: u32 = 0; 10854 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 10855 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 10856 extra_index += 1; 10857 const body_len = @truncate(u31, sema.code.extra[extra_index]); 10858 extra_index += 1; 10859 extra_index += body_len; 10860 10861 try sema.validateSwitchItemBool( 10862 block, 10863 &true_count, 10864 &false_count, 10865 item_ref, 10866 src_node_offset, 10867 .{ .scalar = scalar_i }, 10868 ); 10869 } 10870 } 10871 { 10872 var multi_i: u32 = 0; 10873 while (multi_i < multi_cases_len) : (multi_i += 1) { 10874 const items_len = sema.code.extra[extra_index]; 10875 extra_index += 1; 10876 const ranges_len = sema.code.extra[extra_index]; 10877 extra_index += 1; 10878 const body_len = @truncate(u31, sema.code.extra[extra_index]); 10879 extra_index += 1; 10880 const items = sema.code.refSlice(extra_index, items_len); 10881 extra_index += items_len + body_len; 10882 10883 for (items, 0..) |item_ref, item_i| { 10884 try sema.validateSwitchItemBool( 10885 block, 10886 &true_count, 10887 &false_count, 10888 item_ref, 10889 src_node_offset, 10890 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, 10891 ); 10892 } 10893 10894 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); 10895 } 10896 } 10897 switch (special_prong) { 10898 .@"else" => { 10899 if (true_count + false_count == 2) { 10900 return sema.fail( 10901 block, 10902 special_prong_src, 10903 "unreachable else prong; all cases already handled", 10904 .{}, 10905 ); 10906 } 10907 }, 10908 .under, .none => { 10909 if (true_count + false_count < 2) { 10910 return sema.fail( 10911 block, 10912 src, 10913 "switch must handle all possibilities", 10914 .{}, 10915 ); 10916 } 10917 }, 10918 } 10919 }, 10920 .EnumLiteral, .Void, .Fn, .Pointer, .Type => { 10921 if (special_prong != .@"else") { 10922 return sema.fail( 10923 block, 10924 src, 10925 "else prong required when switching on type '{}'", 10926 .{operand_ty.fmt(mod)}, 10927 ); 10928 } 10929 10930 var seen_values = ValueSrcMap{}; 10931 defer seen_values.deinit(gpa); 10932 10933 var extra_index: usize = special.end; 10934 { 10935 var scalar_i: u32 = 0; 10936 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 10937 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 10938 extra_index += 1; 10939 const body_len = @truncate(u31, sema.code.extra[extra_index]); 10940 extra_index += 1; 10941 extra_index += body_len; 10942 10943 try sema.validateSwitchItemSparse( 10944 block, 10945 &seen_values, 10946 item_ref, 10947 src_node_offset, 10948 .{ .scalar = scalar_i }, 10949 ); 10950 } 10951 } 10952 { 10953 var multi_i: u32 = 0; 10954 while (multi_i < multi_cases_len) : (multi_i += 1) { 10955 const items_len = sema.code.extra[extra_index]; 10956 extra_index += 1; 10957 const ranges_len = sema.code.extra[extra_index]; 10958 extra_index += 1; 10959 const body_len = @truncate(u31, sema.code.extra[extra_index]); 10960 extra_index += 1; 10961 const items = sema.code.refSlice(extra_index, items_len); 10962 extra_index += items_len + body_len; 10963 10964 for (items, 0..) |item_ref, item_i| { 10965 try sema.validateSwitchItemSparse( 10966 block, 10967 &seen_values, 10968 item_ref, 10969 src_node_offset, 10970 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, 10971 ); 10972 } 10973 10974 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); 10975 } 10976 } 10977 }, 10978 10979 .ErrorUnion, 10980 .NoReturn, 10981 .Array, 10982 .Struct, 10983 .Undefined, 10984 .Null, 10985 .Optional, 10986 .Opaque, 10987 .Vector, 10988 .Frame, 10989 .AnyFrame, 10990 .ComptimeFloat, 10991 .Float, 10992 => return sema.fail(block, operand_src, "invalid switch operand type '{}'", .{ 10993 operand_ty.fmt(mod), 10994 }), 10995 } 10996 10997 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 10998 try sema.air_instructions.append(gpa, .{ 10999 .tag = .block, 11000 .data = undefined, 11001 }); 11002 var label: Block.Label = .{ 11003 .zir_block = inst, 11004 .merges = .{ 11005 .src_locs = .{}, 11006 .results = .{}, 11007 .br_list = .{}, 11008 .block_inst = block_inst, 11009 }, 11010 }; 11011 11012 var child_block: Block = .{ 11013 .parent = block, 11014 .sema = sema, 11015 .src_decl = block.src_decl, 11016 .namespace = block.namespace, 11017 .wip_capture_scope = block.wip_capture_scope, 11018 .instructions = .{}, 11019 .label = &label, 11020 .inlining = block.inlining, 11021 .is_comptime = block.is_comptime, 11022 .comptime_reason = block.comptime_reason, 11023 .is_typeof = block.is_typeof, 11024 .switch_else_err_ty = else_error_ty, 11025 .c_import_buf = block.c_import_buf, 11026 .runtime_cond = block.runtime_cond, 11027 .runtime_loop = block.runtime_loop, 11028 .runtime_index = block.runtime_index, 11029 .error_return_trace_index = block.error_return_trace_index, 11030 }; 11031 const merges = &child_block.label.?.merges; 11032 defer child_block.instructions.deinit(gpa); 11033 defer merges.deinit(gpa); 11034 11035 if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| { 11036 const resolved_operand_val = try sema.resolveLazyValue(operand_val); 11037 var extra_index: usize = special.end; 11038 { 11039 var scalar_i: usize = 0; 11040 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 11041 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 11042 extra_index += 1; 11043 const body_len = @truncate(u31, sema.code.extra[extra_index]); 11044 const is_inline = sema.code.extra[extra_index] >> 31 != 0; 11045 extra_index += 1; 11046 const body = sema.code.extra[extra_index..][0..body_len]; 11047 extra_index += body_len; 11048 11049 const item = try sema.resolveInst(item_ref); 11050 // Validation above ensured these will succeed. 11051 const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable; 11052 if (resolved_operand_val.eql(item_val, operand_ty, mod)) { 11053 if (is_inline) child_block.inline_case_capture = operand; 11054 11055 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); 11056 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); 11057 } 11058 } 11059 } 11060 { 11061 var multi_i: usize = 0; 11062 while (multi_i < multi_cases_len) : (multi_i += 1) { 11063 const items_len = sema.code.extra[extra_index]; 11064 extra_index += 1; 11065 const ranges_len = sema.code.extra[extra_index]; 11066 extra_index += 1; 11067 const body_len = @truncate(u31, sema.code.extra[extra_index]); 11068 const is_inline = sema.code.extra[extra_index] >> 31 != 0; 11069 extra_index += 1; 11070 const items = sema.code.refSlice(extra_index, items_len); 11071 extra_index += items_len; 11072 const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..body_len]; 11073 11074 for (items) |item_ref| { 11075 const item = try sema.resolveInst(item_ref); 11076 // Validation above ensured these will succeed. 11077 const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable; 11078 if (resolved_operand_val.eql(item_val, operand_ty, mod)) { 11079 if (is_inline) child_block.inline_case_capture = operand; 11080 11081 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); 11082 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); 11083 } 11084 } 11085 11086 var range_i: usize = 0; 11087 while (range_i < ranges_len) : (range_i += 1) { 11088 const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 11089 extra_index += 1; 11090 const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 11091 extra_index += 1; 11092 11093 // Validation above ensured these will succeed. 11094 const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, "") catch unreachable; 11095 const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, "") catch unreachable; 11096 if ((try sema.compareAll(resolved_operand_val, .gte, first_tv.val, operand_ty)) and 11097 (try sema.compareAll(resolved_operand_val, .lte, last_tv.val, operand_ty))) 11098 { 11099 if (is_inline) child_block.inline_case_capture = operand; 11100 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); 11101 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); 11102 } 11103 } 11104 11105 extra_index += body_len; 11106 } 11107 } 11108 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand); 11109 if (special.is_inline) child_block.inline_case_capture = operand; 11110 if (empty_enum) { 11111 return Air.Inst.Ref.void_value; 11112 } 11113 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges); 11114 } 11115 11116 if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) { 11117 if (empty_enum) { 11118 return Air.Inst.Ref.void_value; 11119 } 11120 if (special_prong == .none) { 11121 return sema.fail(block, src, "switch must handle all possibilities", .{}); 11122 } 11123 if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) { 11124 return Air.Inst.Ref.unreachable_value; 11125 } 11126 if (mod.backendSupportsFeature(.is_named_enum_value) and block.wantSafety() and operand_ty.zigTypeTag(mod) == .Enum and 11127 (!operand_ty.isNonexhaustiveEnum(mod) or union_originally)) 11128 { 11129 try sema.zirDbgStmt(block, cond_dbg_node_index); 11130 const ok = try block.addUnOp(.is_named_enum_value, operand); 11131 try sema.addSafetyCheck(block, ok, .corrupt_switch); 11132 } 11133 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges); 11134 } 11135 11136 if (child_block.is_comptime) { 11137 _ = sema.resolveConstValue(&child_block, operand_src, operand, "condition in comptime switch must be comptime-known") catch |err| { 11138 if (err == error.AnalysisFail and child_block.comptime_reason != null) try child_block.comptime_reason.?.explain(sema, sema.err); 11139 return err; 11140 }; 11141 unreachable; 11142 } 11143 11144 const estimated_cases_extra = (scalar_cases_len + multi_cases_len) * 11145 @typeInfo(Air.SwitchBr.Case).Struct.fields.len + 2; 11146 var cases_extra = try std.ArrayListUnmanaged(u32).initCapacity(gpa, estimated_cases_extra); 11147 defer cases_extra.deinit(gpa); 11148 11149 var case_block = child_block.makeSubBlock(); 11150 case_block.runtime_loop = null; 11151 case_block.runtime_cond = operand_src; 11152 case_block.runtime_index.increment(); 11153 defer case_block.instructions.deinit(gpa); 11154 11155 var extra_index: usize = special.end; 11156 11157 var scalar_i: usize = 0; 11158 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 11159 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 11160 extra_index += 1; 11161 const body_len = @truncate(u31, sema.code.extra[extra_index]); 11162 const is_inline = sema.code.extra[extra_index] >> 31 != 0; 11163 extra_index += 1; 11164 const body = sema.code.extra[extra_index..][0..body_len]; 11165 extra_index += body_len; 11166 11167 var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope); 11168 defer wip_captures.deinit(); 11169 11170 case_block.instructions.shrinkRetainingCapacity(0); 11171 case_block.wip_capture_scope = wip_captures.scope; 11172 case_block.inline_case_capture = .none; 11173 11174 const item = try sema.resolveInst(item_ref); 11175 if (is_inline) case_block.inline_case_capture = item; 11176 // `item` is already guaranteed to be constant known. 11177 11178 const analyze_body = if (union_originally) blk: { 11179 const item_val = sema.resolveConstLazyValue(block, .unneeded, item, "") catch unreachable; 11180 const field_ty = maybe_union_ty.unionFieldType(item_val, mod); 11181 break :blk field_ty.zigTypeTag(mod) != .NoReturn; 11182 } else true; 11183 11184 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { 11185 // nothing to do here 11186 } else if (analyze_body) { 11187 try sema.analyzeBodyRuntimeBreak(&case_block, body); 11188 } else { 11189 _ = try case_block.addNoOp(.unreach); 11190 } 11191 11192 try wip_captures.finalize(); 11193 11194 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); 11195 cases_extra.appendAssumeCapacity(1); // items_len 11196 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); 11197 cases_extra.appendAssumeCapacity(@enumToInt(item)); 11198 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); 11199 } 11200 11201 var is_first = true; 11202 var prev_cond_br: Air.Inst.Index = undefined; 11203 var first_else_body: []const Air.Inst.Index = &.{}; 11204 defer gpa.free(first_else_body); 11205 var prev_then_body: []const Air.Inst.Index = &.{}; 11206 defer gpa.free(prev_then_body); 11207 11208 var cases_len = scalar_cases_len; 11209 var multi_i: u32 = 0; 11210 while (multi_i < multi_cases_len) : (multi_i += 1) { 11211 const items_len = sema.code.extra[extra_index]; 11212 extra_index += 1; 11213 const ranges_len = sema.code.extra[extra_index]; 11214 extra_index += 1; 11215 const body_len = @truncate(u31, sema.code.extra[extra_index]); 11216 const is_inline = sema.code.extra[extra_index] >> 31 != 0; 11217 extra_index += 1; 11218 const items = sema.code.refSlice(extra_index, items_len); 11219 extra_index += items_len; 11220 11221 case_block.instructions.shrinkRetainingCapacity(0); 11222 case_block.wip_capture_scope = child_block.wip_capture_scope; 11223 case_block.inline_case_capture = .none; 11224 11225 // Generate all possible cases as scalar prongs. 11226 if (is_inline) { 11227 const body_start = extra_index + 2 * ranges_len; 11228 const body = sema.code.extra[body_start..][0..body_len]; 11229 var emit_bb = false; 11230 11231 var range_i: u32 = 0; 11232 while (range_i < ranges_len) : (range_i += 1) { 11233 const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 11234 extra_index += 1; 11235 const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 11236 extra_index += 1; 11237 11238 const item_first_ref = try sema.resolveInst(first_ref); 11239 var item = sema.resolveConstValue(block, .unneeded, item_first_ref, undefined) catch unreachable; 11240 const item_last_ref = try sema.resolveInst(last_ref); 11241 const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable; 11242 11243 while (item.compareScalar(.lte, item_last, operand_ty, mod)) : ({ 11244 // Previous validation has resolved any possible lazy values. 11245 item = try sema.intAddScalar(item, try mod.intValue(operand_ty, 1), operand_ty); 11246 }) { 11247 cases_len += 1; 11248 11249 const item_ref = try sema.addConstant(operand_ty, item); 11250 case_block.inline_case_capture = item_ref; 11251 11252 case_block.instructions.shrinkRetainingCapacity(0); 11253 case_block.wip_capture_scope = child_block.wip_capture_scope; 11254 11255 if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) { 11256 error.NeededSourceLocation => { 11257 const case_src = Module.SwitchProngSrc{ .range = .{ .prong = multi_i, .item = range_i } }; 11258 const decl = mod.declPtr(case_block.src_decl); 11259 try sema.emitBackwardBranch(block, case_src.resolve(mod, decl, src_node_offset, .none)); 11260 unreachable; 11261 }, 11262 else => return err, 11263 }; 11264 emit_bb = true; 11265 11266 try sema.analyzeBodyRuntimeBreak(&case_block, body); 11267 11268 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); 11269 cases_extra.appendAssumeCapacity(1); // items_len 11270 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); 11271 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); 11272 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); 11273 } 11274 } 11275 11276 for (items, 0..) |item_ref, item_i| { 11277 cases_len += 1; 11278 11279 const item = try sema.resolveInst(item_ref); 11280 case_block.inline_case_capture = item; 11281 11282 case_block.instructions.shrinkRetainingCapacity(0); 11283 case_block.wip_capture_scope = child_block.wip_capture_scope; 11284 11285 const analyze_body = if (union_originally) blk: { 11286 const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable; 11287 const field_ty = maybe_union_ty.unionFieldType(item_val, mod); 11288 break :blk field_ty.zigTypeTag(mod) != .NoReturn; 11289 } else true; 11290 11291 if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) { 11292 error.NeededSourceLocation => { 11293 const case_src = Module.SwitchProngSrc{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }; 11294 const decl = mod.declPtr(case_block.src_decl); 11295 try sema.emitBackwardBranch(block, case_src.resolve(mod, decl, src_node_offset, .none)); 11296 unreachable; 11297 }, 11298 else => return err, 11299 }; 11300 emit_bb = true; 11301 11302 if (analyze_body) { 11303 try sema.analyzeBodyRuntimeBreak(&case_block, body); 11304 } else { 11305 _ = try case_block.addNoOp(.unreach); 11306 } 11307 11308 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); 11309 cases_extra.appendAssumeCapacity(1); // items_len 11310 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); 11311 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); 11312 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); 11313 } 11314 11315 extra_index += body_len; 11316 continue; 11317 } 11318 11319 var any_ok: Air.Inst.Ref = .none; 11320 11321 // If there are any ranges, we have to put all the items into the 11322 // else prong. Otherwise, we can take advantage of multiple items 11323 // mapping to the same body. 11324 if (ranges_len == 0) { 11325 cases_len += 1; 11326 11327 const analyze_body = if (union_originally) 11328 for (items) |item_ref| { 11329 const item = try sema.resolveInst(item_ref); 11330 const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable; 11331 const field_ty = maybe_union_ty.unionFieldType(item_val, mod); 11332 if (field_ty.zigTypeTag(mod) != .NoReturn) break true; 11333 } else false 11334 else 11335 true; 11336 11337 const body = sema.code.extra[extra_index..][0..body_len]; 11338 extra_index += body_len; 11339 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { 11340 // nothing to do here 11341 } else if (analyze_body) { 11342 try sema.analyzeBodyRuntimeBreak(&case_block, body); 11343 } else { 11344 _ = try case_block.addNoOp(.unreach); 11345 } 11346 11347 try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len + 11348 case_block.instructions.items.len); 11349 11350 cases_extra.appendAssumeCapacity(@intCast(u32, items.len)); 11351 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); 11352 11353 for (items) |item_ref| { 11354 const item = try sema.resolveInst(item_ref); 11355 cases_extra.appendAssumeCapacity(@enumToInt(item)); 11356 } 11357 11358 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); 11359 } else { 11360 for (items) |item_ref| { 11361 const item = try sema.resolveInst(item_ref); 11362 const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item); 11363 if (any_ok != .none) { 11364 any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok); 11365 } else { 11366 any_ok = cmp_ok; 11367 } 11368 } 11369 11370 var range_i: usize = 0; 11371 while (range_i < ranges_len) : (range_i += 1) { 11372 const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 11373 extra_index += 1; 11374 const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 11375 extra_index += 1; 11376 11377 const item_first = try sema.resolveInst(first_ref); 11378 const item_last = try sema.resolveInst(last_ref); 11379 11380 // operand >= first and operand <= last 11381 const range_first_ok = try case_block.addBinOp( 11382 if (case_block.float_mode == .Optimized) .cmp_gte_optimized else .cmp_gte, 11383 operand, 11384 item_first, 11385 ); 11386 const range_last_ok = try case_block.addBinOp( 11387 if (case_block.float_mode == .Optimized) .cmp_lte_optimized else .cmp_lte, 11388 operand, 11389 item_last, 11390 ); 11391 const range_ok = try case_block.addBinOp( 11392 .bool_and, 11393 range_first_ok, 11394 range_last_ok, 11395 ); 11396 if (any_ok != .none) { 11397 any_ok = try case_block.addBinOp(.bool_or, any_ok, range_ok); 11398 } else { 11399 any_ok = range_ok; 11400 } 11401 } 11402 11403 const new_cond_br = try case_block.addInstAsIndex(.{ .tag = .cond_br, .data = .{ 11404 .pl_op = .{ 11405 .operand = any_ok, 11406 .payload = undefined, 11407 }, 11408 } }); 11409 var cond_body = try case_block.instructions.toOwnedSlice(gpa); 11410 defer gpa.free(cond_body); 11411 11412 var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope); 11413 defer wip_captures.deinit(); 11414 11415 case_block.instructions.shrinkRetainingCapacity(0); 11416 case_block.wip_capture_scope = wip_captures.scope; 11417 11418 const body = sema.code.extra[extra_index..][0..body_len]; 11419 extra_index += body_len; 11420 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { 11421 // nothing to do here 11422 } else { 11423 try sema.analyzeBodyRuntimeBreak(&case_block, body); 11424 } 11425 11426 try wip_captures.finalize(); 11427 11428 if (is_first) { 11429 is_first = false; 11430 first_else_body = cond_body; 11431 cond_body = &.{}; 11432 } else { 11433 try sema.air_extra.ensureUnusedCapacity( 11434 gpa, 11435 @typeInfo(Air.CondBr).Struct.fields.len + prev_then_body.len + cond_body.len, 11436 ); 11437 11438 sema.air_instructions.items(.data)[prev_cond_br].pl_op.payload = 11439 sema.addExtraAssumeCapacity(Air.CondBr{ 11440 .then_body_len = @intCast(u32, prev_then_body.len), 11441 .else_body_len = @intCast(u32, cond_body.len), 11442 }); 11443 sema.air_extra.appendSliceAssumeCapacity(prev_then_body); 11444 sema.air_extra.appendSliceAssumeCapacity(cond_body); 11445 } 11446 gpa.free(prev_then_body); 11447 prev_then_body = try case_block.instructions.toOwnedSlice(gpa); 11448 prev_cond_br = new_cond_br; 11449 } 11450 } 11451 11452 var final_else_body: []const Air.Inst.Index = &.{}; 11453 if (special.body.len != 0 or !is_first or case_block.wantSafety()) { 11454 var emit_bb = false; 11455 if (special.is_inline) switch (operand_ty.zigTypeTag(mod)) { 11456 .Enum => { 11457 if (operand_ty.isNonexhaustiveEnum(mod) and !union_originally) { 11458 return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ 11459 operand_ty.fmt(mod), 11460 }); 11461 } 11462 for (seen_enum_fields, 0..) |f, i| { 11463 if (f != null) continue; 11464 cases_len += 1; 11465 11466 const item_val = try mod.enumValueFieldIndex(operand_ty, @intCast(u32, i)); 11467 const item_ref = try sema.addConstant(operand_ty, item_val); 11468 case_block.inline_case_capture = item_ref; 11469 11470 case_block.instructions.shrinkRetainingCapacity(0); 11471 case_block.wip_capture_scope = child_block.wip_capture_scope; 11472 11473 const analyze_body = if (union_originally) blk: { 11474 const field_ty = maybe_union_ty.unionFieldType(item_val, mod); 11475 break :blk field_ty.zigTypeTag(mod) != .NoReturn; 11476 } else true; 11477 11478 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); 11479 emit_bb = true; 11480 11481 if (analyze_body) { 11482 try sema.analyzeBodyRuntimeBreak(&case_block, special.body); 11483 } else { 11484 _ = try case_block.addNoOp(.unreach); 11485 } 11486 11487 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); 11488 cases_extra.appendAssumeCapacity(1); // items_len 11489 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); 11490 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); 11491 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); 11492 } 11493 }, 11494 .ErrorSet => { 11495 if (operand_ty.isAnyError(mod)) { 11496 return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ 11497 operand_ty.fmt(mod), 11498 }); 11499 } 11500 for (operand_ty.errorSetNames(mod)) |error_name_ip| { 11501 const error_name = mod.intern_pool.stringToSlice(error_name_ip); 11502 if (seen_errors.contains(error_name)) continue; 11503 cases_len += 1; 11504 11505 const item_val = try mod.intern(.{ .err = .{ 11506 .ty = operand_ty.toIntern(), 11507 .name = error_name_ip, 11508 } }); 11509 const item_ref = try sema.addConstant(operand_ty, item_val.toValue()); 11510 case_block.inline_case_capture = item_ref; 11511 11512 case_block.instructions.shrinkRetainingCapacity(0); 11513 case_block.wip_capture_scope = child_block.wip_capture_scope; 11514 11515 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); 11516 emit_bb = true; 11517 11518 try sema.analyzeBodyRuntimeBreak(&case_block, special.body); 11519 11520 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); 11521 cases_extra.appendAssumeCapacity(1); // items_len 11522 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); 11523 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); 11524 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); 11525 } 11526 }, 11527 .Int => { 11528 var it = try RangeSetUnhandledIterator.init(sema, operand_ty, range_set); 11529 while (try it.next()) |cur| { 11530 cases_len += 1; 11531 11532 const item_ref = try sema.addConstant(operand_ty, cur.toValue()); 11533 case_block.inline_case_capture = item_ref; 11534 11535 case_block.instructions.shrinkRetainingCapacity(0); 11536 case_block.wip_capture_scope = child_block.wip_capture_scope; 11537 11538 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); 11539 emit_bb = true; 11540 11541 try sema.analyzeBodyRuntimeBreak(&case_block, special.body); 11542 11543 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); 11544 cases_extra.appendAssumeCapacity(1); // items_len 11545 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); 11546 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); 11547 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); 11548 } 11549 }, 11550 .Bool => { 11551 if (true_count == 0) { 11552 cases_len += 1; 11553 case_block.inline_case_capture = Air.Inst.Ref.bool_true; 11554 11555 case_block.instructions.shrinkRetainingCapacity(0); 11556 case_block.wip_capture_scope = child_block.wip_capture_scope; 11557 11558 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); 11559 emit_bb = true; 11560 11561 try sema.analyzeBodyRuntimeBreak(&case_block, special.body); 11562 11563 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); 11564 cases_extra.appendAssumeCapacity(1); // items_len 11565 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); 11566 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); 11567 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); 11568 } 11569 if (false_count == 0) { 11570 cases_len += 1; 11571 case_block.inline_case_capture = Air.Inst.Ref.bool_false; 11572 11573 case_block.instructions.shrinkRetainingCapacity(0); 11574 case_block.wip_capture_scope = child_block.wip_capture_scope; 11575 11576 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); 11577 emit_bb = true; 11578 11579 try sema.analyzeBodyRuntimeBreak(&case_block, special.body); 11580 11581 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); 11582 cases_extra.appendAssumeCapacity(1); // items_len 11583 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); 11584 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); 11585 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); 11586 } 11587 }, 11588 else => return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ 11589 operand_ty.fmt(mod), 11590 }), 11591 }; 11592 11593 var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope); 11594 defer wip_captures.deinit(); 11595 11596 case_block.instructions.shrinkRetainingCapacity(0); 11597 case_block.wip_capture_scope = wip_captures.scope; 11598 case_block.inline_case_capture = .none; 11599 11600 if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and 11601 operand_ty.zigTypeTag(mod) == .Enum and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally)) 11602 { 11603 try sema.zirDbgStmt(&case_block, cond_dbg_node_index); 11604 const ok = try case_block.addUnOp(.is_named_enum_value, operand); 11605 try sema.addSafetyCheck(&case_block, ok, .corrupt_switch); 11606 } 11607 11608 const analyze_body = if (union_originally and !special.is_inline) 11609 for (seen_enum_fields, 0..) |seen_field, index| { 11610 if (seen_field != null) continue; 11611 const union_obj = mod.typeToUnion(maybe_union_ty).?; 11612 const field_ty = union_obj.fields.values()[index].ty; 11613 if (field_ty.zigTypeTag(mod) != .NoReturn) break true; 11614 } else false 11615 else 11616 true; 11617 if (special.body.len != 0 and err_set and 11618 try sema.maybeErrorUnwrap(&case_block, special.body, operand)) 11619 { 11620 // nothing to do here 11621 } else if (special.body.len != 0 and analyze_body and !special.is_inline) { 11622 try sema.analyzeBodyRuntimeBreak(&case_block, special.body); 11623 } else { 11624 // We still need a terminator in this block, but we have proven 11625 // that it is unreachable. 11626 if (case_block.wantSafety()) { 11627 try sema.zirDbgStmt(&case_block, cond_dbg_node_index); 11628 try sema.safetyPanic(&case_block, .corrupt_switch); 11629 } else { 11630 _ = try case_block.addNoOp(.unreach); 11631 } 11632 } 11633 11634 try wip_captures.finalize(); 11635 11636 if (is_first) { 11637 final_else_body = case_block.instructions.items; 11638 } else { 11639 try sema.air_extra.ensureUnusedCapacity(gpa, prev_then_body.len + 11640 @typeInfo(Air.CondBr).Struct.fields.len + case_block.instructions.items.len); 11641 11642 sema.air_instructions.items(.data)[prev_cond_br].pl_op.payload = 11643 sema.addExtraAssumeCapacity(Air.CondBr{ 11644 .then_body_len = @intCast(u32, prev_then_body.len), 11645 .else_body_len = @intCast(u32, case_block.instructions.items.len), 11646 }); 11647 sema.air_extra.appendSliceAssumeCapacity(prev_then_body); 11648 sema.air_extra.appendSliceAssumeCapacity(case_block.instructions.items); 11649 final_else_body = first_else_body; 11650 } 11651 } 11652 11653 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr).Struct.fields.len + 11654 cases_extra.items.len + final_else_body.len); 11655 11656 _ = try child_block.addInst(.{ .tag = .switch_br, .data = .{ .pl_op = .{ 11657 .operand = operand, 11658 .payload = sema.addExtraAssumeCapacity(Air.SwitchBr{ 11659 .cases_len = @intCast(u32, cases_len), 11660 .else_body_len = @intCast(u32, final_else_body.len), 11661 }), 11662 } } }); 11663 sema.air_extra.appendSliceAssumeCapacity(cases_extra.items); 11664 sema.air_extra.appendSliceAssumeCapacity(final_else_body); 11665 11666 return sema.analyzeBlockBody(block, src, &child_block, merges); 11667 } 11668 11669 const RangeSetUnhandledIterator = struct { 11670 mod: *Module, 11671 cur: ?InternPool.Index, 11672 max: InternPool.Index, 11673 range_i: usize, 11674 ranges: []const RangeSet.Range, 11675 limbs: []math.big.Limb, 11676 11677 const preallocated_limbs = math.big.int.calcTwosCompLimbCount(128); 11678 11679 fn init(sema: *Sema, ty: Type, range_set: RangeSet) !RangeSetUnhandledIterator { 11680 const mod = sema.mod; 11681 const int_type = mod.intern_pool.indexToKey(ty.toIntern()).int_type; 11682 const needed_limbs = math.big.int.calcTwosCompLimbCount(int_type.bits); 11683 return .{ 11684 .mod = mod, 11685 .cur = (try ty.minInt(mod, ty)).toIntern(), 11686 .max = (try ty.maxInt(mod, ty)).toIntern(), 11687 .range_i = 0, 11688 .ranges = range_set.ranges.items, 11689 .limbs = if (needed_limbs > preallocated_limbs) 11690 try sema.arena.alloc(math.big.Limb, needed_limbs) 11691 else 11692 &.{}, 11693 }; 11694 } 11695 11696 fn addOne(it: *const RangeSetUnhandledIterator, val: InternPool.Index) !?InternPool.Index { 11697 if (val == it.max) return null; 11698 const int = it.mod.intern_pool.indexToKey(val).int; 11699 11700 switch (int.storage) { 11701 inline .u64, .i64 => |val_int| { 11702 const next_int = @addWithOverflow(val_int, 1); 11703 if (next_int[1] == 0) 11704 return (try it.mod.intValue(int.ty.toType(), next_int[0])).toIntern(); 11705 }, 11706 .big_int => {}, 11707 .lazy_align, .lazy_size => unreachable, 11708 } 11709 11710 var val_space: InternPool.Key.Int.Storage.BigIntSpace = undefined; 11711 const val_bigint = int.storage.toBigInt(&val_space); 11712 11713 var result_limbs: [preallocated_limbs]math.big.Limb = undefined; 11714 var result_bigint = math.big.int.Mutable.init( 11715 if (it.limbs.len > 0) it.limbs else &result_limbs, 11716 0, 11717 ); 11718 11719 result_bigint.addScalar(val_bigint, 1); 11720 return (try it.mod.intValue_big(int.ty.toType(), result_bigint.toConst())).toIntern(); 11721 } 11722 11723 fn next(it: *RangeSetUnhandledIterator) !?InternPool.Index { 11724 var cur = it.cur orelse return null; 11725 while (it.range_i < it.ranges.len and cur == it.ranges[it.range_i].first) { 11726 defer it.range_i += 1; 11727 cur = (try it.addOne(it.ranges[it.range_i].last)) orelse { 11728 it.cur = null; 11729 return null; 11730 }; 11731 } 11732 it.cur = try it.addOne(cur); 11733 return cur; 11734 } 11735 }; 11736 11737 fn resolveSwitchItemVal( 11738 sema: *Sema, 11739 block: *Block, 11740 item_ref: Zir.Inst.Ref, 11741 switch_node_offset: i32, 11742 switch_prong_src: Module.SwitchProngSrc, 11743 range_expand: Module.SwitchProngSrc.RangeExpand, 11744 ) CompileError!InternPool.Index { 11745 const mod = sema.mod; 11746 const item = try sema.resolveInst(item_ref); 11747 // Constructing a LazySrcLoc is costly because we only have the switch AST node. 11748 // Only if we know for sure we need to report a compile error do we resolve the 11749 // full source locations. 11750 if (sema.resolveConstLazyValue(block, .unneeded, item, "")) |val| { 11751 return val.toIntern(); 11752 } else |err| switch (err) { 11753 error.NeededSourceLocation => { 11754 const src = switch_prong_src.resolve(mod, sema.mod.declPtr(block.src_decl), switch_node_offset, range_expand); 11755 _ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known"); 11756 unreachable; 11757 }, 11758 else => |e| return e, 11759 } 11760 } 11761 11762 fn validateSwitchRange( 11763 sema: *Sema, 11764 block: *Block, 11765 range_set: *RangeSet, 11766 first_ref: Zir.Inst.Ref, 11767 last_ref: Zir.Inst.Ref, 11768 src_node_offset: i32, 11769 switch_prong_src: Module.SwitchProngSrc, 11770 ) CompileError!void { 11771 const mod = sema.mod; 11772 const first = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first); 11773 const last = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last); 11774 if (first.toValue().compareScalar(.gt, last.toValue(), mod.intern_pool.typeOf(first).toType(), mod)) { 11775 const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), src_node_offset, .first); 11776 return sema.fail(block, src, "range start value is greater than the end value", .{}); 11777 } 11778 const maybe_prev_src = try range_set.add(first, last, switch_prong_src); 11779 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); 11780 } 11781 11782 fn validateSwitchItem( 11783 sema: *Sema, 11784 block: *Block, 11785 range_set: *RangeSet, 11786 item_ref: Zir.Inst.Ref, 11787 src_node_offset: i32, 11788 switch_prong_src: Module.SwitchProngSrc, 11789 ) CompileError!void { 11790 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); 11791 const maybe_prev_src = try range_set.add(item, item, switch_prong_src); 11792 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); 11793 } 11794 11795 fn validateSwitchItemEnum( 11796 sema: *Sema, 11797 block: *Block, 11798 seen_fields: []?Module.SwitchProngSrc, 11799 range_set: *RangeSet, 11800 item_ref: Zir.Inst.Ref, 11801 src_node_offset: i32, 11802 switch_prong_src: Module.SwitchProngSrc, 11803 ) CompileError!void { 11804 const ip = &sema.mod.intern_pool; 11805 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); 11806 const int = ip.indexToKey(item).enum_tag.int; 11807 const field_index = ip.indexToKey(ip.typeOf(item)).enum_type.tagValueIndex(ip, int) orelse { 11808 const maybe_prev_src = try range_set.add(int, int, switch_prong_src); 11809 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); 11810 }; 11811 const maybe_prev_src = seen_fields[field_index]; 11812 seen_fields[field_index] = switch_prong_src; 11813 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); 11814 } 11815 11816 fn validateSwitchItemError( 11817 sema: *Sema, 11818 block: *Block, 11819 seen_errors: *SwitchErrorSet, 11820 item_ref: Zir.Inst.Ref, 11821 src_node_offset: i32, 11822 switch_prong_src: Module.SwitchProngSrc, 11823 ) CompileError!void { 11824 const ip = &sema.mod.intern_pool; 11825 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); 11826 // TODO: Do i need to typecheck here? 11827 const error_name = ip.stringToSlice(ip.indexToKey(item).err.name); 11828 const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev| 11829 prev.value 11830 else 11831 null; 11832 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); 11833 } 11834 11835 fn validateSwitchDupe( 11836 sema: *Sema, 11837 block: *Block, 11838 maybe_prev_src: ?Module.SwitchProngSrc, 11839 switch_prong_src: Module.SwitchProngSrc, 11840 src_node_offset: i32, 11841 ) CompileError!void { 11842 const prev_prong_src = maybe_prev_src orelse return; 11843 const mod = sema.mod; 11844 const block_src_decl = sema.mod.declPtr(block.src_decl); 11845 const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none); 11846 const prev_src = prev_prong_src.resolve(mod, block_src_decl, src_node_offset, .none); 11847 const msg = msg: { 11848 const msg = try sema.errMsg( 11849 block, 11850 src, 11851 "duplicate switch value", 11852 .{}, 11853 ); 11854 errdefer msg.destroy(sema.gpa); 11855 try sema.errNote( 11856 block, 11857 prev_src, 11858 msg, 11859 "previous value here", 11860 .{}, 11861 ); 11862 break :msg msg; 11863 }; 11864 return sema.failWithOwnedErrorMsg(msg); 11865 } 11866 11867 fn validateSwitchItemBool( 11868 sema: *Sema, 11869 block: *Block, 11870 true_count: *u8, 11871 false_count: *u8, 11872 item_ref: Zir.Inst.Ref, 11873 src_node_offset: i32, 11874 switch_prong_src: Module.SwitchProngSrc, 11875 ) CompileError!void { 11876 const mod = sema.mod; 11877 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); 11878 if (item.toValue().toBool()) { 11879 true_count.* += 1; 11880 } else { 11881 false_count.* += 1; 11882 } 11883 if (true_count.* + false_count.* > 2) { 11884 const block_src_decl = sema.mod.declPtr(block.src_decl); 11885 const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none); 11886 return sema.fail(block, src, "duplicate switch value", .{}); 11887 } 11888 } 11889 11890 const ValueSrcMap = std.AutoHashMapUnmanaged(InternPool.Index, Module.SwitchProngSrc); 11891 11892 fn validateSwitchItemSparse( 11893 sema: *Sema, 11894 block: *Block, 11895 seen_values: *ValueSrcMap, 11896 item_ref: Zir.Inst.Ref, 11897 src_node_offset: i32, 11898 switch_prong_src: Module.SwitchProngSrc, 11899 ) CompileError!void { 11900 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); 11901 const kv = (try seen_values.fetchPut(sema.gpa, item, switch_prong_src)) orelse return; 11902 return sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset); 11903 } 11904 11905 fn validateSwitchNoRange( 11906 sema: *Sema, 11907 block: *Block, 11908 ranges_len: u32, 11909 operand_ty: Type, 11910 src_node_offset: i32, 11911 ) CompileError!void { 11912 if (ranges_len == 0) 11913 return; 11914 11915 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset }; 11916 const range_src: LazySrcLoc = .{ .node_offset_switch_range = src_node_offset }; 11917 11918 const msg = msg: { 11919 const msg = try sema.errMsg( 11920 block, 11921 operand_src, 11922 "ranges not allowed when switching on type '{}'", 11923 .{operand_ty.fmt(sema.mod)}, 11924 ); 11925 errdefer msg.destroy(sema.gpa); 11926 try sema.errNote( 11927 block, 11928 range_src, 11929 msg, 11930 "range here", 11931 .{}, 11932 ); 11933 break :msg msg; 11934 }; 11935 return sema.failWithOwnedErrorMsg(msg); 11936 } 11937 11938 fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !bool { 11939 const mod = sema.mod; 11940 if (!mod.backendSupportsFeature(.panic_unwrap_error)) return false; 11941 11942 const tags = sema.code.instructions.items(.tag); 11943 for (body) |inst| { 11944 switch (tags[inst]) { 11945 .save_err_ret_index, 11946 .dbg_block_begin, 11947 .dbg_block_end, 11948 .dbg_stmt, 11949 .@"unreachable", 11950 .str, 11951 .as_node, 11952 .panic, 11953 .field_val, 11954 => {}, 11955 else => return false, 11956 } 11957 } 11958 11959 for (body) |inst| { 11960 const air_inst = switch (tags[inst]) { 11961 .dbg_block_begin, 11962 .dbg_block_end, 11963 => continue, 11964 .dbg_stmt => { 11965 try sema.zirDbgStmt(block, inst); 11966 continue; 11967 }, 11968 .save_err_ret_index => { 11969 try sema.zirSaveErrRetIndex(block, inst); 11970 continue; 11971 }, 11972 .str => try sema.zirStr(block, inst), 11973 .as_node => try sema.zirAsNode(block, inst), 11974 .field_val => try sema.zirFieldVal(block, inst), 11975 .@"unreachable" => { 11976 if (!mod.comp.formatted_panics) { 11977 try sema.safetyPanic(block, .unwrap_error); 11978 return true; 11979 } 11980 11981 const panic_fn = try sema.getBuiltin("panicUnwrapError"); 11982 const err_return_trace = try sema.getErrorReturnTrace(block); 11983 const args: [2]Air.Inst.Ref = .{ err_return_trace, operand }; 11984 try sema.callBuiltin(block, panic_fn, .auto, &args); 11985 return true; 11986 }, 11987 .panic => { 11988 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 11989 const msg_inst = try sema.resolveInst(inst_data.operand); 11990 11991 const panic_fn = try sema.getBuiltin("panic"); 11992 const err_return_trace = try sema.getErrorReturnTrace(block); 11993 const args: [3]Air.Inst.Ref = .{ msg_inst, err_return_trace, .null_value }; 11994 try sema.callBuiltin(block, panic_fn, .auto, &args); 11995 return true; 11996 }, 11997 else => unreachable, 11998 }; 11999 if (sema.typeOf(air_inst).isNoReturn(mod)) 12000 return true; 12001 sema.inst_map.putAssumeCapacity(inst, air_inst); 12002 } 12003 unreachable; 12004 } 12005 12006 fn maybeErrorUnwrapCondbr(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, cond: Zir.Inst.Ref, cond_src: LazySrcLoc) !void { 12007 const mod = sema.mod; 12008 const index = Zir.refToIndex(cond) orelse return; 12009 if (sema.code.instructions.items(.tag)[index] != .is_non_err) return; 12010 12011 const err_inst_data = sema.code.instructions.items(.data)[index].un_node; 12012 const err_operand = try sema.resolveInst(err_inst_data.operand); 12013 const operand_ty = sema.typeOf(err_operand); 12014 if (operand_ty.zigTypeTag(mod) == .ErrorSet) { 12015 try sema.maybeErrorUnwrapComptime(block, body, err_operand); 12016 return; 12017 } 12018 if (try sema.resolveDefinedValue(block, cond_src, err_operand)) |val| { 12019 if (!operand_ty.isError(mod)) return; 12020 if (val.getError(mod) == null) return; 12021 try sema.maybeErrorUnwrapComptime(block, body, err_operand); 12022 } 12023 } 12024 12025 fn maybeErrorUnwrapComptime(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !void { 12026 const tags = sema.code.instructions.items(.tag); 12027 const inst = for (body) |inst| { 12028 switch (tags[inst]) { 12029 .dbg_block_begin, 12030 .dbg_block_end, 12031 .dbg_stmt, 12032 .save_err_ret_index, 12033 => {}, 12034 .@"unreachable" => break inst, 12035 else => return, 12036 } 12037 } else return; 12038 const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable"; 12039 const src = inst_data.src(); 12040 12041 if (try sema.resolveDefinedValue(block, src, operand)) |val| { 12042 if (val.getError(sema.mod)) |name| { 12043 return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); 12044 } 12045 } 12046 } 12047 12048 fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 12049 const mod = sema.mod; 12050 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 12051 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 12052 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 12053 const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 12054 const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs); 12055 const field_name = try sema.resolveConstString(block, name_src, extra.rhs, "field name must be comptime-known"); 12056 const ty = try sema.resolveTypeFields(unresolved_ty); 12057 const ip = &mod.intern_pool; 12058 12059 const has_field = hf: { 12060 switch (ip.indexToKey(ty.toIntern())) { 12061 .ptr_type => |ptr_type| switch (ptr_type.flags.size) { 12062 .Slice => { 12063 if (mem.eql(u8, field_name, "ptr")) break :hf true; 12064 if (mem.eql(u8, field_name, "len")) break :hf true; 12065 break :hf false; 12066 }, 12067 else => {}, 12068 }, 12069 .anon_struct_type => |anon_struct| { 12070 if (anon_struct.names.len != 0) { 12071 // If the string is not interned, then the field certainly is not present. 12072 const name_interned = ip.getString(field_name).unwrap() orelse break :hf false; 12073 break :hf mem.indexOfScalar(InternPool.NullTerminatedString, anon_struct.names, name_interned) != null; 12074 } else { 12075 const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch break :hf false; 12076 break :hf field_index < ty.structFieldCount(mod); 12077 } 12078 }, 12079 .struct_type => |struct_type| { 12080 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :hf false; 12081 assert(struct_obj.haveFieldTypes()); 12082 break :hf struct_obj.fields.contains(field_name); 12083 }, 12084 .union_type => |union_type| { 12085 const union_obj = mod.unionPtr(union_type.index); 12086 assert(union_obj.haveFieldTypes()); 12087 break :hf union_obj.fields.contains(field_name); 12088 }, 12089 .enum_type => |enum_type| { 12090 // If the string is not interned, then the field certainly is not present. 12091 const name_interned = ip.getString(field_name).unwrap() orelse break :hf false; 12092 break :hf enum_type.nameIndex(ip, name_interned) != null; 12093 }, 12094 .array_type => break :hf mem.eql(u8, field_name, "len"), 12095 else => {}, 12096 } 12097 return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{ 12098 ty.fmt(sema.mod), 12099 }); 12100 }; 12101 if (has_field) { 12102 return Air.Inst.Ref.bool_true; 12103 } else { 12104 return Air.Inst.Ref.bool_false; 12105 } 12106 } 12107 12108 fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 12109 const mod = sema.mod; 12110 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 12111 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 12112 const src = inst_data.src(); 12113 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 12114 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 12115 const container_type = try sema.resolveType(block, lhs_src, extra.lhs); 12116 const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "decl name must be comptime-known"); 12117 12118 try sema.checkNamespaceType(block, lhs_src, container_type); 12119 12120 const namespace = container_type.getNamespaceIndex(mod).unwrap() orelse 12121 return Air.Inst.Ref.bool_false; 12122 if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| { 12123 const decl = mod.declPtr(decl_index); 12124 if (decl.is_pub or decl.getFileScope(mod) == block.getFileScope(mod)) { 12125 return Air.Inst.Ref.bool_true; 12126 } 12127 } 12128 return Air.Inst.Ref.bool_false; 12129 } 12130 12131 fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 12132 const tracy = trace(@src()); 12133 defer tracy.end(); 12134 12135 const mod = sema.mod; 12136 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 12137 const operand_src = inst_data.src(); 12138 const operand = inst_data.get(sema.code); 12139 12140 const result = mod.importFile(block.getFileScope(mod), operand) catch |err| switch (err) { 12141 error.ImportOutsidePkgPath => { 12142 return sema.fail(block, operand_src, "import of file outside package path: '{s}'", .{operand}); 12143 }, 12144 error.PackageNotFound => { 12145 const name = try block.getFileScope(mod).pkg.getName(sema.gpa, mod.*); 12146 defer sema.gpa.free(name); 12147 return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, name }); 12148 }, 12149 else => { 12150 // TODO: these errors are file system errors; make sure an update() will 12151 // retry this and not cache the file system error, which may be transient. 12152 return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) }); 12153 }, 12154 }; 12155 try mod.semaFile(result.file); 12156 const file_root_decl_index = result.file.root_decl.unwrap().?; 12157 const file_root_decl = mod.declPtr(file_root_decl_index); 12158 try mod.declareDeclDependency(sema.owner_decl_index, file_root_decl_index); 12159 return sema.addConstant(file_root_decl.ty, file_root_decl.val); 12160 } 12161 12162 fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 12163 const tracy = trace(@src()); 12164 defer tracy.end(); 12165 12166 const mod = sema.mod; 12167 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 12168 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 12169 const name = try sema.resolveConstString(block, operand_src, inst_data.operand, "file path name must be comptime-known"); 12170 12171 const embed_file = mod.embedFile(block.getFileScope(mod), name) catch |err| switch (err) { 12172 error.ImportOutsidePkgPath => { 12173 return sema.fail(block, operand_src, "embed of file outside package path: '{s}'", .{name}); 12174 }, 12175 else => { 12176 // TODO: these errors are file system errors; make sure an update() will 12177 // retry this and not cache the file system error, which may be transient. 12178 return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ name, @errorName(err) }); 12179 }, 12180 }; 12181 12182 var anon_decl = try block.startAnonDecl(); 12183 defer anon_decl.deinit(); 12184 12185 // TODO instead of using `.bytes`, create a new value tag for pointing at 12186 // a `*Module.EmbedFile`. The purpose of this would be: 12187 // - If only the length is read and the bytes are not inspected by comptime code, 12188 // there can be an optimization where the codegen backend does a copy_file_range 12189 // into the final binary, and never loads the data into memory. 12190 // - When a Decl is destroyed, it can free the `*Module.EmbedFile`. 12191 const ty = try mod.arrayType(.{ 12192 .len = embed_file.bytes.len, 12193 .child = .u8_type, 12194 .sentinel = .zero_u8, 12195 }); 12196 embed_file.owner_decl = try anon_decl.finish( 12197 ty, 12198 (try mod.intern(.{ .aggregate = .{ 12199 .ty = ty.toIntern(), 12200 .storage = .{ .bytes = embed_file.bytes }, 12201 } })).toValue(), 12202 0, // default alignment 12203 ); 12204 12205 return sema.analyzeDeclRef(embed_file.owner_decl); 12206 } 12207 12208 fn zirRetErrValueCode(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 12209 const mod = sema.mod; 12210 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 12211 const err_name = inst_data.get(sema.code); 12212 12213 // Return the error code from the function. 12214 const kv = try mod.getErrorValue(err_name); 12215 const error_set_type = try mod.singleErrorSetType(kv.key); 12216 return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ 12217 .ty = error_set_type.toIntern(), 12218 .name = mod.intern_pool.getString(kv.key).unwrap().?, 12219 } })).toValue()); 12220 } 12221 12222 fn zirShl( 12223 sema: *Sema, 12224 block: *Block, 12225 inst: Zir.Inst.Index, 12226 air_tag: Air.Inst.Tag, 12227 ) CompileError!Air.Inst.Ref { 12228 const tracy = trace(@src()); 12229 defer tracy.end(); 12230 12231 const mod = sema.mod; 12232 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 12233 const src = inst_data.src(); 12234 sema.src = src; 12235 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 12236 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 12237 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 12238 const lhs = try sema.resolveInst(extra.lhs); 12239 const rhs = try sema.resolveInst(extra.rhs); 12240 const lhs_ty = sema.typeOf(lhs); 12241 const rhs_ty = sema.typeOf(rhs); 12242 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 12243 12244 const scalar_ty = lhs_ty.scalarType(mod); 12245 const scalar_rhs_ty = rhs_ty.scalarType(mod); 12246 12247 // TODO coerce rhs if air_tag is not shl_sat 12248 const rhs_is_comptime_int = try sema.checkIntType(block, rhs_src, scalar_rhs_ty); 12249 12250 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(lhs); 12251 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(rhs); 12252 12253 if (maybe_rhs_val) |rhs_val| { 12254 if (rhs_val.isUndef(mod)) { 12255 return sema.addConstUndef(sema.typeOf(lhs)); 12256 } 12257 // If rhs is 0, return lhs without doing any calculations. 12258 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 12259 return lhs; 12260 } 12261 if (scalar_ty.zigTypeTag(mod) != .ComptimeInt and air_tag != .shl_sat) { 12262 const bit_value = try mod.intValue(Type.comptime_int, scalar_ty.intInfo(mod).bits); 12263 if (rhs_ty.zigTypeTag(mod) == .Vector) { 12264 var i: usize = 0; 12265 while (i < rhs_ty.vectorLen(mod)) : (i += 1) { 12266 const rhs_elem = try rhs_val.elemValue(sema.mod, i); 12267 if (rhs_elem.compareHetero(.gte, bit_value, mod)) { 12268 return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ 12269 rhs_elem.fmtValue(scalar_ty, sema.mod), 12270 i, 12271 scalar_ty.fmt(sema.mod), 12272 }); 12273 } 12274 } 12275 } else if (rhs_val.compareHetero(.gte, bit_value, mod)) { 12276 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ 12277 rhs_val.fmtValue(scalar_ty, sema.mod), 12278 scalar_ty.fmt(sema.mod), 12279 }); 12280 } 12281 } 12282 if (rhs_ty.zigTypeTag(mod) == .Vector) { 12283 var i: usize = 0; 12284 while (i < rhs_ty.vectorLen(mod)) : (i += 1) { 12285 const rhs_elem = try rhs_val.elemValue(sema.mod, i); 12286 if (rhs_elem.compareHetero(.lt, try mod.intValue(scalar_rhs_ty, 0), mod)) { 12287 return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{ 12288 rhs_elem.fmtValue(scalar_ty, sema.mod), 12289 i, 12290 }); 12291 } 12292 } 12293 } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) { 12294 return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{ 12295 rhs_val.fmtValue(scalar_ty, sema.mod), 12296 }); 12297 } 12298 } 12299 12300 const runtime_src = if (maybe_lhs_val) |lhs_val| rs: { 12301 if (lhs_val.isUndef(mod)) return sema.addConstUndef(lhs_ty); 12302 const rhs_val = maybe_rhs_val orelse { 12303 if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) { 12304 return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be comptime-known", .{}); 12305 } 12306 break :rs rhs_src; 12307 }; 12308 12309 const val = switch (air_tag) { 12310 .shl_exact => val: { 12311 const shifted = try lhs_val.shlWithOverflow(rhs_val, lhs_ty, sema.arena, sema.mod); 12312 if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) { 12313 break :val shifted.wrapped_result; 12314 } 12315 if (shifted.overflow_bit.compareAllWithZero(.eq, sema.mod)) { 12316 break :val shifted.wrapped_result; 12317 } 12318 return sema.fail(block, src, "operation caused overflow", .{}); 12319 }, 12320 12321 .shl_sat => if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) 12322 try lhs_val.shl(rhs_val, lhs_ty, sema.arena, sema.mod) 12323 else 12324 try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, sema.mod), 12325 12326 .shl => if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) 12327 try lhs_val.shl(rhs_val, lhs_ty, sema.arena, sema.mod) 12328 else 12329 try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, sema.mod), 12330 12331 else => unreachable, 12332 }; 12333 12334 return sema.addConstant(lhs_ty, val); 12335 } else lhs_src; 12336 12337 const new_rhs = if (air_tag == .shl_sat) rhs: { 12338 // Limit the RHS type for saturating shl to be an integer as small as the LHS. 12339 if (rhs_is_comptime_int or 12340 scalar_rhs_ty.intInfo(mod).bits > scalar_ty.intInfo(mod).bits) 12341 { 12342 const max_int = try sema.addConstant( 12343 lhs_ty, 12344 try lhs_ty.maxInt(mod, lhs_ty), 12345 ); 12346 const rhs_limited = try sema.analyzeMinMax(block, rhs_src, .min, &.{ rhs, max_int }, &.{ rhs_src, rhs_src }); 12347 break :rhs try sema.intCast(block, src, lhs_ty, rhs_src, rhs_limited, rhs_src, false); 12348 } else { 12349 break :rhs rhs; 12350 } 12351 } else rhs; 12352 12353 try sema.requireRuntimeBlock(block, src, runtime_src); 12354 if (block.wantSafety()) { 12355 const bit_count = scalar_ty.intInfo(mod).bits; 12356 if (!std.math.isPowerOfTwo(bit_count)) { 12357 const bit_count_val = try mod.intValue(scalar_rhs_ty, bit_count); 12358 const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: { 12359 const bit_count_inst = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, bit_count_val)); 12360 const lt = try block.addCmpVector(rhs, bit_count_inst, .lt); 12361 break :ok try block.addInst(.{ 12362 .tag = .reduce, 12363 .data = .{ .reduce = .{ 12364 .operand = lt, 12365 .operation = .And, 12366 } }, 12367 }); 12368 } else ok: { 12369 const bit_count_inst = try sema.addConstant(rhs_ty, bit_count_val); 12370 break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst); 12371 }; 12372 try sema.addSafetyCheck(block, ok, .shift_rhs_too_big); 12373 } 12374 12375 if (air_tag == .shl_exact) { 12376 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty); 12377 const op_ov = try block.addInst(.{ 12378 .tag = .shl_with_overflow, 12379 .data = .{ .ty_pl = .{ 12380 .ty = try sema.addType(op_ov_tuple_ty), 12381 .payload = try sema.addExtra(Air.Bin{ 12382 .lhs = lhs, 12383 .rhs = rhs, 12384 }), 12385 } }, 12386 }); 12387 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); 12388 const any_ov_bit = if (lhs_ty.zigTypeTag(mod) == .Vector) 12389 try block.addInst(.{ 12390 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, 12391 .data = .{ .reduce = .{ 12392 .operand = ov_bit, 12393 .operation = .Or, 12394 } }, 12395 }) 12396 else 12397 ov_bit; 12398 const zero_ov = try sema.addConstant(Type.u1, try mod.intValue(Type.u1, 0)); 12399 const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); 12400 12401 try sema.addSafetyCheck(block, no_ov, .shl_overflow); 12402 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); 12403 } 12404 } 12405 return block.addBinOp(air_tag, lhs, new_rhs); 12406 } 12407 12408 fn zirShr( 12409 sema: *Sema, 12410 block: *Block, 12411 inst: Zir.Inst.Index, 12412 air_tag: Air.Inst.Tag, 12413 ) CompileError!Air.Inst.Ref { 12414 const tracy = trace(@src()); 12415 defer tracy.end(); 12416 12417 const mod = sema.mod; 12418 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 12419 const src = inst_data.src(); 12420 sema.src = src; 12421 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 12422 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 12423 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 12424 const lhs = try sema.resolveInst(extra.lhs); 12425 const rhs = try sema.resolveInst(extra.rhs); 12426 const lhs_ty = sema.typeOf(lhs); 12427 const rhs_ty = sema.typeOf(rhs); 12428 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 12429 const scalar_ty = lhs_ty.scalarType(mod); 12430 12431 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(lhs); 12432 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(rhs); 12433 12434 const runtime_src = if (maybe_rhs_val) |rhs_val| rs: { 12435 if (rhs_val.isUndef(mod)) { 12436 return sema.addConstUndef(lhs_ty); 12437 } 12438 // If rhs is 0, return lhs without doing any calculations. 12439 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 12440 return lhs; 12441 } 12442 if (scalar_ty.zigTypeTag(mod) != .ComptimeInt) { 12443 const bit_value = try mod.intValue(Type.comptime_int, scalar_ty.intInfo(mod).bits); 12444 if (rhs_ty.zigTypeTag(mod) == .Vector) { 12445 var i: usize = 0; 12446 while (i < rhs_ty.vectorLen(mod)) : (i += 1) { 12447 const rhs_elem = try rhs_val.elemValue(sema.mod, i); 12448 if (rhs_elem.compareHetero(.gte, bit_value, mod)) { 12449 return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ 12450 rhs_elem.fmtValue(scalar_ty, sema.mod), 12451 i, 12452 scalar_ty.fmt(sema.mod), 12453 }); 12454 } 12455 } 12456 } else if (rhs_val.compareHetero(.gte, bit_value, mod)) { 12457 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ 12458 rhs_val.fmtValue(scalar_ty, sema.mod), 12459 scalar_ty.fmt(sema.mod), 12460 }); 12461 } 12462 } 12463 if (rhs_ty.zigTypeTag(mod) == .Vector) { 12464 var i: usize = 0; 12465 while (i < rhs_ty.vectorLen(mod)) : (i += 1) { 12466 const rhs_elem = try rhs_val.elemValue(sema.mod, i); 12467 if (rhs_elem.compareHetero(.lt, try mod.intValue(rhs_ty.childType(mod), 0), mod)) { 12468 return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{ 12469 rhs_elem.fmtValue(scalar_ty, sema.mod), 12470 i, 12471 }); 12472 } 12473 } 12474 } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) { 12475 return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{ 12476 rhs_val.fmtValue(scalar_ty, sema.mod), 12477 }); 12478 } 12479 if (maybe_lhs_val) |lhs_val| { 12480 if (lhs_val.isUndef(mod)) { 12481 return sema.addConstUndef(lhs_ty); 12482 } 12483 if (air_tag == .shr_exact) { 12484 // Detect if any ones would be shifted out. 12485 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, sema.mod); 12486 if (!(try truncated.compareAllWithZeroAdvanced(.eq, sema))) { 12487 return sema.fail(block, src, "exact shift shifted out 1 bits", .{}); 12488 } 12489 } 12490 const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, sema.mod); 12491 return sema.addConstant(lhs_ty, val); 12492 } else { 12493 break :rs lhs_src; 12494 } 12495 } else rhs_src; 12496 12497 if (maybe_rhs_val == null and scalar_ty.zigTypeTag(mod) == .ComptimeInt) { 12498 return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be comptime-known", .{}); 12499 } 12500 12501 try sema.requireRuntimeBlock(block, src, runtime_src); 12502 const result = try block.addBinOp(air_tag, lhs, rhs); 12503 if (block.wantSafety()) { 12504 const bit_count = scalar_ty.intInfo(mod).bits; 12505 if (!std.math.isPowerOfTwo(bit_count)) { 12506 const bit_count_val = try mod.intValue(rhs_ty.scalarType(mod), bit_count); 12507 12508 const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: { 12509 const bit_count_inst = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, bit_count_val)); 12510 const lt = try block.addCmpVector(rhs, bit_count_inst, .lt); 12511 break :ok try block.addInst(.{ 12512 .tag = .reduce, 12513 .data = .{ .reduce = .{ 12514 .operand = lt, 12515 .operation = .And, 12516 } }, 12517 }); 12518 } else ok: { 12519 const bit_count_inst = try sema.addConstant(rhs_ty, bit_count_val); 12520 break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst); 12521 }; 12522 try sema.addSafetyCheck(block, ok, .shift_rhs_too_big); 12523 } 12524 12525 if (air_tag == .shr_exact) { 12526 const back = try block.addBinOp(.shl, result, rhs); 12527 12528 const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: { 12529 const eql = try block.addCmpVector(lhs, back, .eq); 12530 break :ok try block.addInst(.{ 12531 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, 12532 .data = .{ .reduce = .{ 12533 .operand = eql, 12534 .operation = .And, 12535 } }, 12536 }); 12537 } else try block.addBinOp(.cmp_eq, lhs, back); 12538 try sema.addSafetyCheck(block, ok, .shr_overflow); 12539 } 12540 } 12541 return result; 12542 } 12543 12544 fn zirBitwise( 12545 sema: *Sema, 12546 block: *Block, 12547 inst: Zir.Inst.Index, 12548 air_tag: Air.Inst.Tag, 12549 ) CompileError!Air.Inst.Ref { 12550 const tracy = trace(@src()); 12551 defer tracy.end(); 12552 12553 const mod = sema.mod; 12554 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 12555 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 12556 sema.src = src; 12557 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 12558 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 12559 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 12560 const lhs = try sema.resolveInst(extra.lhs); 12561 const rhs = try sema.resolveInst(extra.rhs); 12562 const lhs_ty = sema.typeOf(lhs); 12563 const rhs_ty = sema.typeOf(rhs); 12564 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 12565 12566 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 12567 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } }); 12568 const scalar_type = resolved_type.scalarType(mod); 12569 const scalar_tag = scalar_type.zigTypeTag(mod); 12570 12571 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 12572 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 12573 12574 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 12575 12576 if (!is_int) { 12577 return sema.fail(block, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag(mod)), @tagName(rhs_ty.zigTypeTag(mod)) }); 12578 } 12579 12580 const runtime_src = runtime: { 12581 // TODO: ask the linker what kind of relocations are available, and 12582 // in some cases emit a Value that means "this decl's address AND'd with this operand". 12583 if (try sema.resolveMaybeUndefValIntable(casted_lhs)) |lhs_val| { 12584 if (try sema.resolveMaybeUndefValIntable(casted_rhs)) |rhs_val| { 12585 const result_val = switch (air_tag) { 12586 .bit_and => try lhs_val.bitwiseAnd(rhs_val, resolved_type, sema.arena, sema.mod), 12587 .bit_or => try lhs_val.bitwiseOr(rhs_val, resolved_type, sema.arena, sema.mod), 12588 .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena, sema.mod), 12589 else => unreachable, 12590 }; 12591 return sema.addConstant(resolved_type, result_val); 12592 } else { 12593 break :runtime rhs_src; 12594 } 12595 } else { 12596 break :runtime lhs_src; 12597 } 12598 }; 12599 12600 try sema.requireRuntimeBlock(block, src, runtime_src); 12601 return block.addBinOp(air_tag, casted_lhs, casted_rhs); 12602 } 12603 12604 fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 12605 const tracy = trace(@src()); 12606 defer tracy.end(); 12607 12608 const mod = sema.mod; 12609 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 12610 const src = inst_data.src(); 12611 const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; 12612 12613 const operand = try sema.resolveInst(inst_data.operand); 12614 const operand_type = sema.typeOf(operand); 12615 const scalar_type = operand_type.scalarType(mod); 12616 12617 if (scalar_type.zigTypeTag(mod) != .Int) { 12618 return sema.fail(block, src, "unable to perform binary not operation on type '{}'", .{ 12619 operand_type.fmt(sema.mod), 12620 }); 12621 } 12622 12623 if (try sema.resolveMaybeUndefVal(operand)) |val| { 12624 if (val.isUndef(mod)) { 12625 return sema.addConstUndef(operand_type); 12626 } else if (operand_type.zigTypeTag(mod) == .Vector) { 12627 const vec_len = try sema.usizeCast(block, operand_src, operand_type.vectorLen(mod)); 12628 const elems = try sema.arena.alloc(InternPool.Index, vec_len); 12629 for (elems, 0..) |*elem, i| { 12630 const elem_val = try val.elemValue(sema.mod, i); 12631 elem.* = try (try elem_val.bitwiseNot(scalar_type, sema.arena, sema.mod)).intern(scalar_type, mod); 12632 } 12633 return sema.addConstant(operand_type, (try mod.intern(.{ .aggregate = .{ 12634 .ty = operand_type.toIntern(), 12635 .storage = .{ .elems = elems }, 12636 } })).toValue()); 12637 } else { 12638 const result_val = try val.bitwiseNot(operand_type, sema.arena, sema.mod); 12639 return sema.addConstant(operand_type, result_val); 12640 } 12641 } 12642 12643 try sema.requireRuntimeBlock(block, src, null); 12644 return block.addTyOp(.not, operand_type, operand); 12645 } 12646 12647 fn analyzeTupleCat( 12648 sema: *Sema, 12649 block: *Block, 12650 src_node: i32, 12651 lhs: Air.Inst.Ref, 12652 rhs: Air.Inst.Ref, 12653 ) CompileError!Air.Inst.Ref { 12654 const mod = sema.mod; 12655 const lhs_ty = sema.typeOf(lhs); 12656 const rhs_ty = sema.typeOf(rhs); 12657 const src = LazySrcLoc.nodeOffset(src_node); 12658 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node }; 12659 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; 12660 12661 const lhs_len = lhs_ty.structFieldCount(mod); 12662 const rhs_len = rhs_ty.structFieldCount(mod); 12663 const dest_fields = lhs_len + rhs_len; 12664 12665 if (dest_fields == 0) { 12666 return sema.addConstant(Type.empty_struct_literal, Value.empty_struct); 12667 } 12668 if (lhs_len == 0) { 12669 return rhs; 12670 } 12671 if (rhs_len == 0) { 12672 return lhs; 12673 } 12674 const final_len = try sema.usizeCast(block, rhs_src, dest_fields); 12675 12676 const types = try sema.arena.alloc(InternPool.Index, final_len); 12677 const values = try sema.arena.alloc(InternPool.Index, final_len); 12678 12679 const opt_runtime_src = rs: { 12680 var runtime_src: ?LazySrcLoc = null; 12681 var i: u32 = 0; 12682 while (i < lhs_len) : (i += 1) { 12683 types[i] = lhs_ty.structFieldType(i, mod).toIntern(); 12684 const default_val = lhs_ty.structFieldDefaultValue(i, mod); 12685 values[i] = default_val.toIntern(); 12686 const operand_src = lhs_src; // TODO better source location 12687 if (default_val.toIntern() == .unreachable_value) { 12688 runtime_src = operand_src; 12689 values[i] = .none; 12690 } 12691 } 12692 i = 0; 12693 while (i < rhs_len) : (i += 1) { 12694 types[i + lhs_len] = rhs_ty.structFieldType(i, mod).toIntern(); 12695 const default_val = rhs_ty.structFieldDefaultValue(i, mod); 12696 values[i + lhs_len] = default_val.toIntern(); 12697 const operand_src = rhs_src; // TODO better source location 12698 if (default_val.toIntern() == .unreachable_value) { 12699 runtime_src = operand_src; 12700 values[i + lhs_len] = .none; 12701 } 12702 } 12703 break :rs runtime_src; 12704 }; 12705 12706 const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ 12707 .types = types, 12708 .values = values, 12709 .names = &.{}, 12710 } }); 12711 12712 const runtime_src = opt_runtime_src orelse { 12713 const tuple_val = try mod.intern(.{ .aggregate = .{ 12714 .ty = tuple_ty, 12715 .storage = .{ .elems = values }, 12716 } }); 12717 return sema.addConstant(tuple_ty.toType(), tuple_val.toValue()); 12718 }; 12719 12720 try sema.requireRuntimeBlock(block, src, runtime_src); 12721 12722 const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len); 12723 var i: u32 = 0; 12724 while (i < lhs_len) : (i += 1) { 12725 const operand_src = lhs_src; // TODO better source location 12726 element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, lhs, i, lhs_ty); 12727 } 12728 i = 0; 12729 while (i < rhs_len) : (i += 1) { 12730 const operand_src = rhs_src; // TODO better source location 12731 element_refs[i + lhs_len] = 12732 try sema.tupleFieldValByIndex(block, operand_src, rhs, i, rhs_ty); 12733 } 12734 12735 return block.addAggregateInit(tuple_ty.toType(), element_refs); 12736 } 12737 12738 fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 12739 const tracy = trace(@src()); 12740 defer tracy.end(); 12741 12742 const mod = sema.mod; 12743 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 12744 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 12745 const lhs = try sema.resolveInst(extra.lhs); 12746 const rhs = try sema.resolveInst(extra.rhs); 12747 const lhs_ty = sema.typeOf(lhs); 12748 const rhs_ty = sema.typeOf(rhs); 12749 const src = inst_data.src(); 12750 12751 const lhs_is_tuple = lhs_ty.isTuple(mod); 12752 const rhs_is_tuple = rhs_ty.isTuple(mod); 12753 if (lhs_is_tuple and rhs_is_tuple) { 12754 return sema.analyzeTupleCat(block, inst_data.src_node, lhs, rhs); 12755 } 12756 12757 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 12758 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 12759 12760 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, rhs_ty) orelse lhs_info: { 12761 if (lhs_is_tuple) break :lhs_info @as(Type.ArrayInfo, undefined); 12762 return sema.fail(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(mod)}); 12763 }; 12764 const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs, lhs_ty) orelse { 12765 assert(!rhs_is_tuple); 12766 return sema.fail(block, rhs_src, "expected indexable; found '{}'", .{rhs_ty.fmt(mod)}); 12767 }; 12768 12769 const resolved_elem_ty = t: { 12770 var trash_block = block.makeSubBlock(); 12771 trash_block.is_comptime = false; 12772 defer trash_block.instructions.deinit(sema.gpa); 12773 12774 const instructions = [_]Air.Inst.Ref{ 12775 try trash_block.addBitCast(lhs_info.elem_type, .void_value), 12776 try trash_block.addBitCast(rhs_info.elem_type, .void_value), 12777 }; 12778 break :t try sema.resolvePeerTypes(block, src, &instructions, .{ 12779 .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, 12780 }); 12781 }; 12782 12783 // When there is a sentinel mismatch, no sentinel on the result. 12784 // Otherwise, use the sentinel value provided by either operand, 12785 // coercing it to the peer-resolved element type. 12786 const res_sent_val: ?Value = s: { 12787 if (lhs_info.sentinel) |lhs_sent_val| { 12788 const lhs_sent = try sema.addConstant(lhs_info.elem_type, lhs_sent_val); 12789 if (rhs_info.sentinel) |rhs_sent_val| { 12790 const rhs_sent = try sema.addConstant(rhs_info.elem_type, rhs_sent_val); 12791 const lhs_sent_casted = try sema.coerce(block, resolved_elem_ty, lhs_sent, lhs_src); 12792 const rhs_sent_casted = try sema.coerce(block, resolved_elem_ty, rhs_sent, rhs_src); 12793 const lhs_sent_casted_val = try sema.resolveConstValue(block, lhs_src, lhs_sent_casted, "array sentinel value must be comptime-known"); 12794 const rhs_sent_casted_val = try sema.resolveConstValue(block, rhs_src, rhs_sent_casted, "array sentinel value must be comptime-known"); 12795 if (try sema.valuesEqual(lhs_sent_casted_val, rhs_sent_casted_val, resolved_elem_ty)) { 12796 break :s lhs_sent_casted_val; 12797 } else { 12798 break :s null; 12799 } 12800 } else { 12801 const lhs_sent_casted = try sema.coerce(block, resolved_elem_ty, lhs_sent, lhs_src); 12802 const lhs_sent_casted_val = try sema.resolveConstValue(block, lhs_src, lhs_sent_casted, "array sentinel value must be comptime-known"); 12803 break :s lhs_sent_casted_val; 12804 } 12805 } else { 12806 if (rhs_info.sentinel) |rhs_sent_val| { 12807 const rhs_sent = try sema.addConstant(rhs_info.elem_type, rhs_sent_val); 12808 const rhs_sent_casted = try sema.coerce(block, resolved_elem_ty, rhs_sent, rhs_src); 12809 const rhs_sent_casted_val = try sema.resolveConstValue(block, rhs_src, rhs_sent_casted, "array sentinel value must be comptime-known"); 12810 break :s rhs_sent_casted_val; 12811 } else { 12812 break :s null; 12813 } 12814 } 12815 }; 12816 12817 const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len); 12818 const rhs_len = try sema.usizeCast(block, lhs_src, rhs_info.len); 12819 const result_len = std.math.add(usize, lhs_len, rhs_len) catch |err| switch (err) { 12820 error.Overflow => return sema.fail( 12821 block, 12822 src, 12823 "concatenating arrays of length {d} and {d} produces an array too large for this compiler implementation to handle", 12824 .{ lhs_len, rhs_len }, 12825 ), 12826 }; 12827 12828 const result_ty = try Type.array(sema.arena, result_len, res_sent_val, resolved_elem_ty, mod); 12829 const ptr_addrspace = p: { 12830 if (lhs_ty.zigTypeTag(mod) == .Pointer) break :p lhs_ty.ptrAddressSpace(mod); 12831 if (rhs_ty.zigTypeTag(mod) == .Pointer) break :p rhs_ty.ptrAddressSpace(mod); 12832 break :p null; 12833 }; 12834 12835 const runtime_src = if (switch (lhs_ty.zigTypeTag(mod)) { 12836 .Array, .Struct => try sema.resolveMaybeUndefVal(lhs), 12837 .Pointer => try sema.resolveDefinedValue(block, lhs_src, lhs), 12838 else => unreachable, 12839 }) |lhs_val| rs: { 12840 if (switch (rhs_ty.zigTypeTag(mod)) { 12841 .Array, .Struct => try sema.resolveMaybeUndefVal(rhs), 12842 .Pointer => try sema.resolveDefinedValue(block, rhs_src, rhs), 12843 else => unreachable, 12844 }) |rhs_val| { 12845 const lhs_sub_val = if (lhs_ty.isSinglePointer(mod)) 12846 (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? 12847 else 12848 lhs_val; 12849 12850 const rhs_sub_val = if (rhs_ty.isSinglePointer(mod)) 12851 (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? 12852 else 12853 rhs_val; 12854 12855 const element_vals = try sema.arena.alloc(InternPool.Index, result_len); 12856 var elem_i: usize = 0; 12857 while (elem_i < lhs_len) : (elem_i += 1) { 12858 const lhs_elem_i = elem_i; 12859 const elem_ty = if (lhs_is_tuple) lhs_ty.structFieldType(lhs_elem_i, mod) else lhs_info.elem_type; 12860 const elem_default_val = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i, mod) else Value.@"unreachable"; 12861 const elem_val = if (elem_default_val.toIntern() == .unreachable_value) try lhs_sub_val.elemValue(mod, lhs_elem_i) else elem_default_val; 12862 const elem_val_inst = try sema.addConstant(elem_ty, elem_val); 12863 const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded); 12864 const coerced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, ""); 12865 element_vals[elem_i] = try coerced_elem_val.intern(resolved_elem_ty, mod); 12866 } 12867 while (elem_i < result_len) : (elem_i += 1) { 12868 const rhs_elem_i = elem_i - lhs_len; 12869 const elem_ty = if (rhs_is_tuple) rhs_ty.structFieldType(rhs_elem_i, mod) else rhs_info.elem_type; 12870 const elem_default_val = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i, mod) else Value.@"unreachable"; 12871 const elem_val = if (elem_default_val.toIntern() == .unreachable_value) try rhs_sub_val.elemValue(mod, rhs_elem_i) else elem_default_val; 12872 const elem_val_inst = try sema.addConstant(elem_ty, elem_val); 12873 const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded); 12874 const coerced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, ""); 12875 element_vals[elem_i] = try coerced_elem_val.intern(resolved_elem_ty, mod); 12876 } 12877 return sema.addConstantMaybeRef(block, result_ty, (try mod.intern(.{ .aggregate = .{ 12878 .ty = result_ty.toIntern(), 12879 .storage = .{ .elems = element_vals }, 12880 } })).toValue(), ptr_addrspace != null); 12881 } else break :rs rhs_src; 12882 } else lhs_src; 12883 12884 try sema.requireRuntimeBlock(block, src, runtime_src); 12885 12886 if (ptr_addrspace) |ptr_as| { 12887 const alloc_ty = try Type.ptr(sema.arena, mod, .{ 12888 .pointee_type = result_ty, 12889 .@"addrspace" = ptr_as, 12890 }); 12891 const alloc = try block.addTy(.alloc, alloc_ty); 12892 const elem_ptr_ty = try Type.ptr(sema.arena, mod, .{ 12893 .pointee_type = resolved_elem_ty, 12894 .@"addrspace" = ptr_as, 12895 }); 12896 12897 var elem_i: usize = 0; 12898 while (elem_i < lhs_len) : (elem_i += 1) { 12899 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i); 12900 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); 12901 const init = try sema.elemVal(block, lhs_src, lhs, elem_index, src, true); 12902 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); 12903 } 12904 while (elem_i < result_len) : (elem_i += 1) { 12905 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i); 12906 const rhs_index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len); 12907 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); 12908 const init = try sema.elemVal(block, rhs_src, rhs, rhs_index, src, true); 12909 try sema.storePtr2(block, src, elem_ptr, src, init, rhs_src, .store); 12910 } 12911 if (res_sent_val) |sent_val| { 12912 const elem_index = try sema.addIntUnsigned(Type.usize, result_len); 12913 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); 12914 const init = try sema.addConstant(lhs_info.elem_type, try mod.getCoerced(sent_val, lhs_info.elem_type)); 12915 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); 12916 } 12917 12918 return alloc; 12919 } 12920 12921 const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len); 12922 { 12923 var elem_i: usize = 0; 12924 while (elem_i < lhs_len) : (elem_i += 1) { 12925 const index = try sema.addIntUnsigned(Type.usize, elem_i); 12926 const init = try sema.elemVal(block, lhs_src, lhs, index, src, true); 12927 element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, lhs_src); 12928 } 12929 while (elem_i < result_len) : (elem_i += 1) { 12930 const index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len); 12931 const init = try sema.elemVal(block, rhs_src, rhs, index, src, true); 12932 element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, rhs_src); 12933 } 12934 } 12935 12936 return block.addAggregateInit(result_ty, element_refs); 12937 } 12938 12939 fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref, peer_ty: Type) !?Type.ArrayInfo { 12940 const mod = sema.mod; 12941 const operand_ty = sema.typeOf(operand); 12942 switch (operand_ty.zigTypeTag(mod)) { 12943 .Array => return operand_ty.arrayInfo(mod), 12944 .Pointer => { 12945 const ptr_info = operand_ty.ptrInfo(mod); 12946 switch (ptr_info.size) { 12947 // TODO: in the Many case here this should only work if the type 12948 // has a sentinel, and this code should compute the length based 12949 // on the sentinel value. 12950 .Slice, .Many => { 12951 const val = try sema.resolveConstValue(block, src, operand, "slice value being concatenated must be comptime-known"); 12952 return Type.ArrayInfo{ 12953 .elem_type = ptr_info.pointee_type, 12954 .sentinel = ptr_info.sentinel, 12955 .len = val.sliceLen(sema.mod), 12956 }; 12957 }, 12958 .One => { 12959 if (ptr_info.pointee_type.zigTypeTag(mod) == .Array) { 12960 return ptr_info.pointee_type.arrayInfo(mod); 12961 } 12962 }, 12963 .C => {}, 12964 } 12965 }, 12966 .Struct => { 12967 if (operand_ty.isTuple(mod) and peer_ty.isIndexable(mod)) { 12968 assert(!peer_ty.isTuple(mod)); 12969 return .{ 12970 .elem_type = peer_ty.elemType2(mod), 12971 .sentinel = null, 12972 .len = operand_ty.arrayLen(mod), 12973 }; 12974 } 12975 }, 12976 else => {}, 12977 } 12978 return null; 12979 } 12980 12981 fn analyzeTupleMul( 12982 sema: *Sema, 12983 block: *Block, 12984 src_node: i32, 12985 operand: Air.Inst.Ref, 12986 factor: usize, 12987 ) CompileError!Air.Inst.Ref { 12988 const mod = sema.mod; 12989 const operand_ty = sema.typeOf(operand); 12990 const src = LazySrcLoc.nodeOffset(src_node); 12991 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node }; 12992 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; 12993 12994 const tuple_len = operand_ty.structFieldCount(mod); 12995 const final_len = std.math.mul(usize, tuple_len, factor) catch 12996 return sema.fail(block, rhs_src, "operation results in overflow", .{}); 12997 12998 if (final_len == 0) { 12999 return sema.addConstant(Type.empty_struct_literal, Value.empty_struct); 13000 } 13001 const types = try sema.arena.alloc(InternPool.Index, final_len); 13002 const values = try sema.arena.alloc(InternPool.Index, final_len); 13003 13004 const opt_runtime_src = rs: { 13005 var runtime_src: ?LazySrcLoc = null; 13006 for (0..tuple_len) |i| { 13007 types[i] = operand_ty.structFieldType(i, mod).toIntern(); 13008 values[i] = operand_ty.structFieldDefaultValue(i, mod).toIntern(); 13009 const operand_src = lhs_src; // TODO better source location 13010 if (values[i] == .unreachable_value) { 13011 runtime_src = operand_src; 13012 values[i] = .none; // TODO don't treat unreachable_value as special 13013 } 13014 } 13015 for (0..factor) |i| { 13016 mem.copyForwards(InternPool.Index, types[tuple_len * i ..], types[0..tuple_len]); 13017 mem.copyForwards(InternPool.Index, values[tuple_len * i ..], values[0..tuple_len]); 13018 } 13019 break :rs runtime_src; 13020 }; 13021 13022 const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ 13023 .types = types, 13024 .values = values, 13025 .names = &.{}, 13026 } }); 13027 13028 const runtime_src = opt_runtime_src orelse { 13029 const tuple_val = try mod.intern(.{ .aggregate = .{ 13030 .ty = tuple_ty, 13031 .storage = .{ .elems = values }, 13032 } }); 13033 return sema.addConstant(tuple_ty.toType(), tuple_val.toValue()); 13034 }; 13035 13036 try sema.requireRuntimeBlock(block, src, runtime_src); 13037 13038 const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len); 13039 var i: u32 = 0; 13040 while (i < tuple_len) : (i += 1) { 13041 const operand_src = lhs_src; // TODO better source location 13042 element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, operand, @intCast(u32, i), operand_ty); 13043 } 13044 i = 1; 13045 while (i < factor) : (i += 1) { 13046 @memcpy(element_refs[tuple_len * i ..][0..tuple_len], element_refs[0..tuple_len]); 13047 } 13048 13049 return block.addAggregateInit(tuple_ty.toType(), element_refs); 13050 } 13051 13052 fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 13053 const tracy = trace(@src()); 13054 defer tracy.end(); 13055 13056 const mod = sema.mod; 13057 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 13058 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 13059 const lhs = try sema.resolveInst(extra.lhs); 13060 const lhs_ty = sema.typeOf(lhs); 13061 const src: LazySrcLoc = inst_data.src(); 13062 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 13063 const operator_src: LazySrcLoc = .{ .node_offset_main_token = inst_data.src_node }; 13064 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 13065 13066 if (lhs_ty.isTuple(mod)) { 13067 // In `**` rhs must be comptime-known, but lhs can be runtime-known 13068 const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, "array multiplication factor must be comptime-known"); 13069 const factor_casted = try sema.usizeCast(block, rhs_src, factor); 13070 return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor_casted); 13071 } 13072 13073 // Analyze the lhs first, to catch the case that someone tried to do exponentiation 13074 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, lhs_ty) orelse { 13075 const msg = msg: { 13076 const msg = try sema.errMsg(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(mod)}); 13077 errdefer msg.destroy(sema.gpa); 13078 switch (lhs_ty.zigTypeTag(mod)) { 13079 .Int, .Float, .ComptimeFloat, .ComptimeInt, .Vector => { 13080 try sema.errNote(block, operator_src, msg, "this operator multiplies arrays; use std.math.pow for exponentiation", .{}); 13081 }, 13082 else => {}, 13083 } 13084 break :msg msg; 13085 }; 13086 return sema.failWithOwnedErrorMsg(msg); 13087 }; 13088 13089 // In `**` rhs must be comptime-known, but lhs can be runtime-known 13090 const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, "array multiplication factor must be comptime-known"); 13091 13092 const result_len_u64 = std.math.mul(u64, lhs_info.len, factor) catch 13093 return sema.fail(block, rhs_src, "operation results in overflow", .{}); 13094 const result_len = try sema.usizeCast(block, src, result_len_u64); 13095 13096 const result_ty = try Type.array(sema.arena, result_len, lhs_info.sentinel, lhs_info.elem_type, mod); 13097 13098 const ptr_addrspace = if (lhs_ty.zigTypeTag(mod) == .Pointer) lhs_ty.ptrAddressSpace(mod) else null; 13099 const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len); 13100 13101 if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| { 13102 const lhs_sub_val = if (lhs_ty.isSinglePointer(mod)) 13103 (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? 13104 else 13105 lhs_val; 13106 13107 const val = v: { 13108 // Optimization for the common pattern of a single element repeated N times, such 13109 // as zero-filling a byte array. 13110 if (lhs_len == 1 and lhs_info.sentinel == null) { 13111 const elem_val = try lhs_sub_val.elemValue(mod, 0); 13112 break :v try mod.intern(.{ .aggregate = .{ 13113 .ty = result_ty.toIntern(), 13114 .storage = .{ .repeated_elem = elem_val.toIntern() }, 13115 } }); 13116 } 13117 13118 const element_vals = try sema.arena.alloc(InternPool.Index, result_len); 13119 var elem_i: usize = 0; 13120 while (elem_i < result_len) { 13121 var lhs_i: usize = 0; 13122 while (lhs_i < lhs_len) : (lhs_i += 1) { 13123 const elem_val = try lhs_sub_val.elemValue(mod, lhs_i); 13124 element_vals[elem_i] = elem_val.toIntern(); 13125 elem_i += 1; 13126 } 13127 } 13128 break :v try mod.intern(.{ .aggregate = .{ 13129 .ty = result_ty.toIntern(), 13130 .storage = .{ .elems = element_vals }, 13131 } }); 13132 }; 13133 return sema.addConstantMaybeRef(block, result_ty, val.toValue(), ptr_addrspace != null); 13134 } 13135 13136 try sema.requireRuntimeBlock(block, src, lhs_src); 13137 13138 if (ptr_addrspace) |ptr_as| { 13139 const alloc_ty = try Type.ptr(sema.arena, mod, .{ 13140 .pointee_type = result_ty, 13141 .@"addrspace" = ptr_as, 13142 }); 13143 const alloc = try block.addTy(.alloc, alloc_ty); 13144 const elem_ptr_ty = try Type.ptr(sema.arena, mod, .{ 13145 .pointee_type = lhs_info.elem_type, 13146 .@"addrspace" = ptr_as, 13147 }); 13148 13149 var elem_i: usize = 0; 13150 while (elem_i < result_len) { 13151 var lhs_i: usize = 0; 13152 while (lhs_i < lhs_len) : (lhs_i += 1) { 13153 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i); 13154 elem_i += 1; 13155 const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i); 13156 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); 13157 const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src, true); 13158 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); 13159 } 13160 } 13161 if (lhs_info.sentinel) |sent_val| { 13162 const elem_index = try sema.addIntUnsigned(Type.usize, result_len); 13163 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); 13164 const init = try sema.addConstant(lhs_info.elem_type, sent_val); 13165 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); 13166 } 13167 13168 return alloc; 13169 } 13170 13171 const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len); 13172 var elem_i: usize = 0; 13173 while (elem_i < result_len) { 13174 var lhs_i: usize = 0; 13175 while (lhs_i < lhs_len) : (lhs_i += 1) { 13176 const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i); 13177 const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src, true); 13178 element_refs[elem_i] = init; 13179 elem_i += 1; 13180 } 13181 } 13182 13183 return block.addAggregateInit(result_ty, element_refs); 13184 } 13185 13186 fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 13187 const mod = sema.mod; 13188 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 13189 const src = inst_data.src(); 13190 const lhs_src = src; 13191 const rhs_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; 13192 13193 const rhs = try sema.resolveInst(inst_data.operand); 13194 const rhs_ty = sema.typeOf(rhs); 13195 const rhs_scalar_ty = rhs_ty.scalarType(mod); 13196 13197 if (rhs_scalar_ty.isUnsignedInt(mod) or switch (rhs_scalar_ty.zigTypeTag(mod)) { 13198 .Int, .ComptimeInt, .Float, .ComptimeFloat => false, 13199 else => true, 13200 }) { 13201 return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)}); 13202 } 13203 13204 if (rhs_scalar_ty.isAnyFloat()) { 13205 // We handle float negation here to ensure negative zero is represented in the bits. 13206 if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { 13207 if (rhs_val.isUndef(mod)) return sema.addConstUndef(rhs_ty); 13208 return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, sema.mod)); 13209 } 13210 try sema.requireRuntimeBlock(block, src, null); 13211 return block.addUnOp(if (block.float_mode == .Optimized) .neg_optimized else .neg, rhs); 13212 } 13213 13214 const lhs = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, try mod.intValue(rhs_scalar_ty, 0))); 13215 return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src, true); 13216 } 13217 13218 fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 13219 const mod = sema.mod; 13220 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 13221 const src = inst_data.src(); 13222 const lhs_src = src; 13223 const rhs_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; 13224 13225 const rhs = try sema.resolveInst(inst_data.operand); 13226 const rhs_ty = sema.typeOf(rhs); 13227 const rhs_scalar_ty = rhs_ty.scalarType(mod); 13228 13229 switch (rhs_scalar_ty.zigTypeTag(mod)) { 13230 .Int, .ComptimeInt, .Float, .ComptimeFloat => {}, 13231 else => return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)}), 13232 } 13233 13234 const lhs = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, try mod.intValue(rhs_scalar_ty, 0))); 13235 return sema.analyzeArithmetic(block, .subwrap, lhs, rhs, src, lhs_src, rhs_src, true); 13236 } 13237 13238 fn zirArithmetic( 13239 sema: *Sema, 13240 block: *Block, 13241 inst: Zir.Inst.Index, 13242 zir_tag: Zir.Inst.Tag, 13243 safety: bool, 13244 ) CompileError!Air.Inst.Ref { 13245 const tracy = trace(@src()); 13246 defer tracy.end(); 13247 13248 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 13249 sema.src = .{ .node_offset_bin_op = inst_data.src_node }; 13250 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 13251 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 13252 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 13253 const lhs = try sema.resolveInst(extra.lhs); 13254 const rhs = try sema.resolveInst(extra.rhs); 13255 13256 return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src, safety); 13257 } 13258 13259 fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 13260 const mod = sema.mod; 13261 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 13262 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 13263 sema.src = src; 13264 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 13265 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 13266 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 13267 const lhs = try sema.resolveInst(extra.lhs); 13268 const rhs = try sema.resolveInst(extra.rhs); 13269 const lhs_ty = sema.typeOf(lhs); 13270 const rhs_ty = sema.typeOf(rhs); 13271 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); 13272 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); 13273 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 13274 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); 13275 13276 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 13277 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 13278 .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, 13279 }); 13280 13281 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 13282 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 13283 13284 const lhs_scalar_ty = lhs_ty.scalarType(mod); 13285 const rhs_scalar_ty = rhs_ty.scalarType(mod); 13286 const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); 13287 13288 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 13289 13290 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div); 13291 13292 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); 13293 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); 13294 13295 if ((lhs_ty.zigTypeTag(mod) == .ComptimeFloat and rhs_ty.zigTypeTag(mod) == .ComptimeInt) or 13296 (lhs_ty.zigTypeTag(mod) == .ComptimeInt and rhs_ty.zigTypeTag(mod) == .ComptimeFloat)) 13297 { 13298 // If it makes a difference whether we coerce to ints or floats before doing the division, error. 13299 // If lhs % rhs is 0, it doesn't matter. 13300 const lhs_val = maybe_lhs_val orelse unreachable; 13301 const rhs_val = maybe_rhs_val orelse unreachable; 13302 const rem = lhs_val.floatRem(rhs_val, resolved_type, sema.arena, mod) catch unreachable; 13303 if (!rem.compareAllWithZero(.eq, mod)) { 13304 return sema.fail( 13305 block, 13306 src, 13307 "ambiguous coercion of division operands '{}' and '{}'; non-zero remainder '{}'", 13308 .{ lhs_ty.fmt(mod), rhs_ty.fmt(mod), rem.fmtValue(resolved_type, mod) }, 13309 ); 13310 } 13311 } 13312 13313 // TODO: emit compile error when .div is used on integers and there would be an 13314 // ambiguous result between div_floor and div_trunc. 13315 13316 // For integers: 13317 // If the lhs is zero, then zero is returned regardless of rhs. 13318 // If the rhs is zero, compile error for division by zero. 13319 // If the rhs is undefined, compile error because there is a possible 13320 // value (zero) for which the division would be illegal behavior. 13321 // If the lhs is undefined: 13322 // * if lhs type is signed: 13323 // * if rhs is comptime-known and not -1, result is undefined 13324 // * if rhs is -1 or runtime-known, compile error because there is a 13325 // possible value (-min_int / -1) for which division would be 13326 // illegal behavior. 13327 // * if lhs type is unsigned, undef is returned regardless of rhs. 13328 // 13329 // For floats: 13330 // If the rhs is zero: 13331 // * comptime_float: compile error for division by zero. 13332 // * other float type: 13333 // * if the lhs is zero: QNaN 13334 // * otherwise: +Inf or -Inf depending on lhs sign 13335 // If the rhs is undefined: 13336 // * comptime_float: compile error because there is a possible 13337 // value (zero) for which the division would be illegal behavior. 13338 // * other float type: result is undefined 13339 // If the lhs is undefined, result is undefined. 13340 switch (scalar_tag) { 13341 .Int, .ComptimeInt, .ComptimeFloat => { 13342 if (maybe_lhs_val) |lhs_val| { 13343 if (!lhs_val.isUndef(mod)) { 13344 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 13345 const scalar_zero = switch (scalar_tag) { 13346 .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), 13347 .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), 13348 else => unreachable, 13349 }; 13350 const zero_val = try sema.splat(resolved_type, scalar_zero); 13351 return sema.addConstant(resolved_type, zero_val); 13352 } 13353 } 13354 } 13355 if (maybe_rhs_val) |rhs_val| { 13356 if (rhs_val.isUndef(mod)) { 13357 return sema.failWithUseOfUndef(block, rhs_src); 13358 } 13359 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { 13360 return sema.failWithDivideByZero(block, rhs_src); 13361 } 13362 // TODO: if the RHS is one, return the LHS directly 13363 } 13364 }, 13365 else => {}, 13366 } 13367 13368 const runtime_src = rs: { 13369 if (maybe_lhs_val) |lhs_val| { 13370 if (lhs_val.isUndef(mod)) { 13371 if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) { 13372 if (maybe_rhs_val) |rhs_val| { 13373 if (try sema.compareAll(rhs_val, .neq, try mod.intValue(resolved_type, -1), resolved_type)) { 13374 return sema.addConstUndef(resolved_type); 13375 } 13376 } 13377 return sema.failWithUseOfUndef(block, rhs_src); 13378 } 13379 return sema.addConstUndef(resolved_type); 13380 } 13381 13382 if (maybe_rhs_val) |rhs_val| { 13383 if (is_int) { 13384 const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, mod); 13385 var vector_index: usize = undefined; 13386 if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) { 13387 return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index); 13388 } 13389 return sema.addConstant(resolved_type, res); 13390 } else { 13391 return sema.addConstant( 13392 resolved_type, 13393 try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, mod), 13394 ); 13395 } 13396 } else { 13397 break :rs rhs_src; 13398 } 13399 } else { 13400 break :rs lhs_src; 13401 } 13402 }; 13403 13404 try sema.requireRuntimeBlock(block, src, runtime_src); 13405 13406 if (block.wantSafety()) { 13407 try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int); 13408 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); 13409 } 13410 13411 const air_tag = if (is_int) blk: { 13412 if (lhs_ty.isSignedInt(mod) or rhs_ty.isSignedInt(mod)) { 13413 return sema.fail( 13414 block, 13415 src, 13416 "division with '{}' and '{}': signed integers must use @divTrunc, @divFloor, or @divExact", 13417 .{ lhs_ty.fmt(mod), rhs_ty.fmt(mod) }, 13418 ); 13419 } 13420 break :blk Air.Inst.Tag.div_trunc; 13421 } else switch (block.float_mode) { 13422 .Optimized => Air.Inst.Tag.div_float_optimized, 13423 .Strict => Air.Inst.Tag.div_float, 13424 }; 13425 return block.addBinOp(air_tag, casted_lhs, casted_rhs); 13426 } 13427 13428 fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 13429 const mod = sema.mod; 13430 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 13431 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 13432 sema.src = src; 13433 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 13434 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 13435 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 13436 const lhs = try sema.resolveInst(extra.lhs); 13437 const rhs = try sema.resolveInst(extra.rhs); 13438 const lhs_ty = sema.typeOf(lhs); 13439 const rhs_ty = sema.typeOf(rhs); 13440 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); 13441 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); 13442 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 13443 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); 13444 13445 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 13446 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 13447 .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, 13448 }); 13449 13450 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 13451 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 13452 13453 const lhs_scalar_ty = lhs_ty.scalarType(mod); 13454 const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); 13455 13456 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 13457 13458 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_exact); 13459 13460 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); 13461 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); 13462 13463 const runtime_src = rs: { 13464 // For integers: 13465 // If the lhs is zero, then zero is returned regardless of rhs. 13466 // If the rhs is zero, compile error for division by zero. 13467 // If the rhs is undefined, compile error because there is a possible 13468 // value (zero) for which the division would be illegal behavior. 13469 // If the lhs is undefined, compile error because there is a possible 13470 // value for which the division would result in a remainder. 13471 // TODO: emit runtime safety for if there is a remainder 13472 // TODO: emit runtime safety for division by zero 13473 // 13474 // For floats: 13475 // If the rhs is zero, compile error for division by zero. 13476 // If the rhs is undefined, compile error because there is a possible 13477 // value (zero) for which the division would be illegal behavior. 13478 // If the lhs is undefined, compile error because there is a possible 13479 // value for which the division would result in a remainder. 13480 if (maybe_lhs_val) |lhs_val| { 13481 if (lhs_val.isUndef(mod)) { 13482 return sema.failWithUseOfUndef(block, rhs_src); 13483 } else { 13484 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 13485 const scalar_zero = switch (scalar_tag) { 13486 .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), 13487 .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), 13488 else => unreachable, 13489 }; 13490 const zero_val = try sema.splat(resolved_type, scalar_zero); 13491 return sema.addConstant(resolved_type, zero_val); 13492 } 13493 } 13494 } 13495 if (maybe_rhs_val) |rhs_val| { 13496 if (rhs_val.isUndef(mod)) { 13497 return sema.failWithUseOfUndef(block, rhs_src); 13498 } 13499 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { 13500 return sema.failWithDivideByZero(block, rhs_src); 13501 } 13502 // TODO: if the RHS is one, return the LHS directly 13503 } 13504 if (maybe_lhs_val) |lhs_val| { 13505 if (maybe_rhs_val) |rhs_val| { 13506 if (is_int) { 13507 const modulus_val = try lhs_val.intMod(rhs_val, resolved_type, sema.arena, mod); 13508 if (!(modulus_val.compareAllWithZero(.eq, mod))) { 13509 return sema.fail(block, src, "exact division produced remainder", .{}); 13510 } 13511 const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, mod); 13512 var vector_index: usize = undefined; 13513 if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) { 13514 return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index); 13515 } 13516 return sema.addConstant(resolved_type, res); 13517 } else { 13518 const modulus_val = try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, mod); 13519 if (!(modulus_val.compareAllWithZero(.eq, mod))) { 13520 return sema.fail(block, src, "exact division produced remainder", .{}); 13521 } 13522 return sema.addConstant( 13523 resolved_type, 13524 try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, mod), 13525 ); 13526 } 13527 } else break :rs rhs_src; 13528 } else break :rs lhs_src; 13529 }; 13530 13531 try sema.requireRuntimeBlock(block, src, runtime_src); 13532 13533 // Depending on whether safety is enabled, we will have a slightly different strategy 13534 // here. The `div_exact` AIR instruction causes undefined behavior if a remainder 13535 // is produced, so in the safety check case, it cannot be used. Instead we do a 13536 // div_trunc and check for remainder. 13537 13538 if (block.wantSafety()) { 13539 try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int); 13540 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); 13541 13542 const result = try block.addBinOp(.div_trunc, casted_lhs, casted_rhs); 13543 const ok = if (!is_int) ok: { 13544 const floored = try block.addUnOp(.floor, result); 13545 13546 if (resolved_type.zigTypeTag(mod) == .Vector) { 13547 const eql = try block.addCmpVector(result, floored, .eq); 13548 break :ok try block.addInst(.{ 13549 .tag = switch (block.float_mode) { 13550 .Strict => .reduce, 13551 .Optimized => .reduce_optimized, 13552 }, 13553 .data = .{ .reduce = .{ 13554 .operand = eql, 13555 .operation = .And, 13556 } }, 13557 }); 13558 } else { 13559 const is_in_range = try block.addBinOp(switch (block.float_mode) { 13560 .Strict => .cmp_eq, 13561 .Optimized => .cmp_eq_optimized, 13562 }, result, floored); 13563 break :ok is_in_range; 13564 } 13565 } else ok: { 13566 const remainder = try block.addBinOp(.rem, casted_lhs, casted_rhs); 13567 13568 const scalar_zero = switch (scalar_tag) { 13569 .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), 13570 .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), 13571 else => unreachable, 13572 }; 13573 if (resolved_type.zigTypeTag(mod) == .Vector) { 13574 const zero_val = try sema.splat(resolved_type, scalar_zero); 13575 const zero = try sema.addConstant(resolved_type, zero_val); 13576 const eql = try block.addCmpVector(remainder, zero, .eq); 13577 break :ok try block.addInst(.{ 13578 .tag = .reduce, 13579 .data = .{ .reduce = .{ 13580 .operand = eql, 13581 .operation = .And, 13582 } }, 13583 }); 13584 } else { 13585 const zero = try sema.addConstant(resolved_type, scalar_zero); 13586 const is_in_range = try block.addBinOp(.cmp_eq, remainder, zero); 13587 break :ok is_in_range; 13588 } 13589 }; 13590 try sema.addSafetyCheck(block, ok, .exact_division_remainder); 13591 return result; 13592 } 13593 13594 return block.addBinOp(airTag(block, is_int, .div_exact, .div_exact_optimized), casted_lhs, casted_rhs); 13595 } 13596 13597 fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 13598 const mod = sema.mod; 13599 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 13600 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 13601 sema.src = src; 13602 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 13603 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 13604 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 13605 const lhs = try sema.resolveInst(extra.lhs); 13606 const rhs = try sema.resolveInst(extra.rhs); 13607 const lhs_ty = sema.typeOf(lhs); 13608 const rhs_ty = sema.typeOf(rhs); 13609 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); 13610 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); 13611 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 13612 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); 13613 13614 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 13615 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 13616 .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, 13617 }); 13618 13619 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 13620 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 13621 13622 const lhs_scalar_ty = lhs_ty.scalarType(mod); 13623 const rhs_scalar_ty = rhs_ty.scalarType(mod); 13624 const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); 13625 13626 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 13627 13628 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_floor); 13629 13630 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); 13631 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); 13632 13633 const runtime_src = rs: { 13634 // For integers: 13635 // If the lhs is zero, then zero is returned regardless of rhs. 13636 // If the rhs is zero, compile error for division by zero. 13637 // If the rhs is undefined, compile error because there is a possible 13638 // value (zero) for which the division would be illegal behavior. 13639 // If the lhs is undefined: 13640 // * if lhs type is signed: 13641 // * if rhs is comptime-known and not -1, result is undefined 13642 // * if rhs is -1 or runtime-known, compile error because there is a 13643 // possible value (-min_int / -1) for which division would be 13644 // illegal behavior. 13645 // * if lhs type is unsigned, undef is returned regardless of rhs. 13646 // TODO: emit runtime safety for division by zero 13647 // 13648 // For floats: 13649 // If the rhs is zero, compile error for division by zero. 13650 // If the rhs is undefined, compile error because there is a possible 13651 // value (zero) for which the division would be illegal behavior. 13652 // If the lhs is undefined, result is undefined. 13653 if (maybe_lhs_val) |lhs_val| { 13654 if (!lhs_val.isUndef(mod)) { 13655 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 13656 const scalar_zero = switch (scalar_tag) { 13657 .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), 13658 .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), 13659 else => unreachable, 13660 }; 13661 const zero_val = try sema.splat(resolved_type, scalar_zero); 13662 return sema.addConstant(resolved_type, zero_val); 13663 } 13664 } 13665 } 13666 if (maybe_rhs_val) |rhs_val| { 13667 if (rhs_val.isUndef(mod)) { 13668 return sema.failWithUseOfUndef(block, rhs_src); 13669 } 13670 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { 13671 return sema.failWithDivideByZero(block, rhs_src); 13672 } 13673 // TODO: if the RHS is one, return the LHS directly 13674 } 13675 if (maybe_lhs_val) |lhs_val| { 13676 if (lhs_val.isUndef(mod)) { 13677 if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) { 13678 if (maybe_rhs_val) |rhs_val| { 13679 if (try sema.compareAll(rhs_val, .neq, try mod.intValue(resolved_type, -1), resolved_type)) { 13680 return sema.addConstUndef(resolved_type); 13681 } 13682 } 13683 return sema.failWithUseOfUndef(block, rhs_src); 13684 } 13685 return sema.addConstUndef(resolved_type); 13686 } 13687 13688 if (maybe_rhs_val) |rhs_val| { 13689 if (is_int) { 13690 return sema.addConstant( 13691 resolved_type, 13692 try lhs_val.intDivFloor(rhs_val, resolved_type, sema.arena, mod), 13693 ); 13694 } else { 13695 return sema.addConstant( 13696 resolved_type, 13697 try lhs_val.floatDivFloor(rhs_val, resolved_type, sema.arena, mod), 13698 ); 13699 } 13700 } else break :rs rhs_src; 13701 } else break :rs lhs_src; 13702 }; 13703 13704 try sema.requireRuntimeBlock(block, src, runtime_src); 13705 13706 if (block.wantSafety()) { 13707 try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int); 13708 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); 13709 } 13710 13711 return block.addBinOp(airTag(block, is_int, .div_floor, .div_floor_optimized), casted_lhs, casted_rhs); 13712 } 13713 13714 fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 13715 const mod = sema.mod; 13716 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 13717 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 13718 sema.src = src; 13719 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 13720 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 13721 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 13722 const lhs = try sema.resolveInst(extra.lhs); 13723 const rhs = try sema.resolveInst(extra.rhs); 13724 const lhs_ty = sema.typeOf(lhs); 13725 const rhs_ty = sema.typeOf(rhs); 13726 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); 13727 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); 13728 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 13729 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); 13730 13731 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 13732 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 13733 .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, 13734 }); 13735 13736 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 13737 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 13738 13739 const lhs_scalar_ty = lhs_ty.scalarType(mod); 13740 const rhs_scalar_ty = rhs_ty.scalarType(mod); 13741 const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); 13742 13743 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 13744 13745 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_trunc); 13746 13747 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); 13748 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); 13749 13750 const runtime_src = rs: { 13751 // For integers: 13752 // If the lhs is zero, then zero is returned regardless of rhs. 13753 // If the rhs is zero, compile error for division by zero. 13754 // If the rhs is undefined, compile error because there is a possible 13755 // value (zero) for which the division would be illegal behavior. 13756 // If the lhs is undefined: 13757 // * if lhs type is signed: 13758 // * if rhs is comptime-known and not -1, result is undefined 13759 // * if rhs is -1 or runtime-known, compile error because there is a 13760 // possible value (-min_int / -1) for which division would be 13761 // illegal behavior. 13762 // * if lhs type is unsigned, undef is returned regardless of rhs. 13763 // TODO: emit runtime safety for division by zero 13764 // 13765 // For floats: 13766 // If the rhs is zero, compile error for division by zero. 13767 // If the rhs is undefined, compile error because there is a possible 13768 // value (zero) for which the division would be illegal behavior. 13769 // If the lhs is undefined, result is undefined. 13770 if (maybe_lhs_val) |lhs_val| { 13771 if (!lhs_val.isUndef(mod)) { 13772 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 13773 const scalar_zero = switch (scalar_tag) { 13774 .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), 13775 .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), 13776 else => unreachable, 13777 }; 13778 const zero_val = try sema.splat(resolved_type, scalar_zero); 13779 return sema.addConstant(resolved_type, zero_val); 13780 } 13781 } 13782 } 13783 if (maybe_rhs_val) |rhs_val| { 13784 if (rhs_val.isUndef(mod)) { 13785 return sema.failWithUseOfUndef(block, rhs_src); 13786 } 13787 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { 13788 return sema.failWithDivideByZero(block, rhs_src); 13789 } 13790 } 13791 if (maybe_lhs_val) |lhs_val| { 13792 if (lhs_val.isUndef(mod)) { 13793 if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) { 13794 if (maybe_rhs_val) |rhs_val| { 13795 if (try sema.compareAll(rhs_val, .neq, try mod.intValue(resolved_type, -1), resolved_type)) { 13796 return sema.addConstUndef(resolved_type); 13797 } 13798 } 13799 return sema.failWithUseOfUndef(block, rhs_src); 13800 } 13801 return sema.addConstUndef(resolved_type); 13802 } 13803 13804 if (maybe_rhs_val) |rhs_val| { 13805 if (is_int) { 13806 const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, mod); 13807 var vector_index: usize = undefined; 13808 if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) { 13809 return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index); 13810 } 13811 return sema.addConstant(resolved_type, res); 13812 } else { 13813 return sema.addConstant( 13814 resolved_type, 13815 try lhs_val.floatDivTrunc(rhs_val, resolved_type, sema.arena, mod), 13816 ); 13817 } 13818 } else break :rs rhs_src; 13819 } else break :rs lhs_src; 13820 }; 13821 13822 try sema.requireRuntimeBlock(block, src, runtime_src); 13823 13824 if (block.wantSafety()) { 13825 try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int); 13826 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); 13827 } 13828 13829 return block.addBinOp(airTag(block, is_int, .div_trunc, .div_trunc_optimized), casted_lhs, casted_rhs); 13830 } 13831 13832 fn addDivIntOverflowSafety( 13833 sema: *Sema, 13834 block: *Block, 13835 resolved_type: Type, 13836 lhs_scalar_ty: Type, 13837 maybe_lhs_val: ?Value, 13838 maybe_rhs_val: ?Value, 13839 casted_lhs: Air.Inst.Ref, 13840 casted_rhs: Air.Inst.Ref, 13841 is_int: bool, 13842 ) CompileError!void { 13843 const mod = sema.mod; 13844 if (!is_int) return; 13845 13846 // If the LHS is unsigned, it cannot cause overflow. 13847 if (!lhs_scalar_ty.isSignedInt(mod)) return; 13848 13849 // If the LHS is widened to a larger integer type, no overflow is possible. 13850 if (lhs_scalar_ty.intInfo(mod).bits < resolved_type.intInfo(mod).bits) { 13851 return; 13852 } 13853 13854 const min_int = try resolved_type.minInt(mod, resolved_type); 13855 const neg_one_scalar = try mod.intValue(lhs_scalar_ty, -1); 13856 const neg_one = try sema.splat(resolved_type, neg_one_scalar); 13857 13858 // If the LHS is comptime-known to be not equal to the min int, 13859 // no overflow is possible. 13860 if (maybe_lhs_val) |lhs_val| { 13861 if (try lhs_val.compareAll(.neq, min_int, resolved_type, mod)) return; 13862 } 13863 13864 // If the RHS is comptime-known to not be equal to -1, no overflow is possible. 13865 if (maybe_rhs_val) |rhs_val| { 13866 if (try rhs_val.compareAll(.neq, neg_one, resolved_type, mod)) return; 13867 } 13868 13869 var ok: Air.Inst.Ref = .none; 13870 if (resolved_type.zigTypeTag(mod) == .Vector) { 13871 if (maybe_lhs_val == null) { 13872 const min_int_ref = try sema.addConstant(resolved_type, min_int); 13873 ok = try block.addCmpVector(casted_lhs, min_int_ref, .neq); 13874 } 13875 if (maybe_rhs_val == null) { 13876 const neg_one_ref = try sema.addConstant(resolved_type, neg_one); 13877 const rhs_ok = try block.addCmpVector(casted_rhs, neg_one_ref, .neq); 13878 if (ok == .none) { 13879 ok = rhs_ok; 13880 } else { 13881 ok = try block.addBinOp(.bool_or, ok, rhs_ok); 13882 } 13883 } 13884 assert(ok != .none); 13885 ok = try block.addInst(.{ 13886 .tag = .reduce, 13887 .data = .{ .reduce = .{ 13888 .operand = ok, 13889 .operation = .And, 13890 } }, 13891 }); 13892 } else { 13893 if (maybe_lhs_val == null) { 13894 const min_int_ref = try sema.addConstant(resolved_type, min_int); 13895 ok = try block.addBinOp(.cmp_neq, casted_lhs, min_int_ref); 13896 } 13897 if (maybe_rhs_val == null) { 13898 const neg_one_ref = try sema.addConstant(resolved_type, neg_one); 13899 const rhs_ok = try block.addBinOp(.cmp_neq, casted_rhs, neg_one_ref); 13900 if (ok == .none) { 13901 ok = rhs_ok; 13902 } else { 13903 ok = try block.addBinOp(.bool_or, ok, rhs_ok); 13904 } 13905 } 13906 assert(ok != .none); 13907 } 13908 try sema.addSafetyCheck(block, ok, .integer_overflow); 13909 } 13910 13911 fn addDivByZeroSafety( 13912 sema: *Sema, 13913 block: *Block, 13914 resolved_type: Type, 13915 maybe_rhs_val: ?Value, 13916 casted_rhs: Air.Inst.Ref, 13917 is_int: bool, 13918 ) CompileError!void { 13919 // Strict IEEE floats have well-defined division by zero. 13920 if (!is_int and block.float_mode == .Strict) return; 13921 13922 // If rhs was comptime-known to be zero a compile error would have been 13923 // emitted above. 13924 if (maybe_rhs_val != null) return; 13925 13926 const mod = sema.mod; 13927 const scalar_zero = if (is_int) 13928 try mod.intValue(resolved_type.scalarType(mod), 0) 13929 else 13930 try mod.floatValue(resolved_type.scalarType(mod), 0.0); 13931 const ok = if (resolved_type.zigTypeTag(mod) == .Vector) ok: { 13932 const zero_val = try sema.splat(resolved_type, scalar_zero); 13933 const zero = try sema.addConstant(resolved_type, zero_val); 13934 const ok = try block.addCmpVector(casted_rhs, zero, .neq); 13935 break :ok try block.addInst(.{ 13936 .tag = if (is_int) .reduce else .reduce_optimized, 13937 .data = .{ .reduce = .{ 13938 .operand = ok, 13939 .operation = .And, 13940 } }, 13941 }); 13942 } else ok: { 13943 const zero = try sema.addConstant(resolved_type, scalar_zero); 13944 break :ok try block.addBinOp(if (is_int) .cmp_neq else .cmp_neq_optimized, casted_rhs, zero); 13945 }; 13946 try sema.addSafetyCheck(block, ok, .divide_by_zero); 13947 } 13948 13949 fn airTag(block: *Block, is_int: bool, normal: Air.Inst.Tag, optimized: Air.Inst.Tag) Air.Inst.Tag { 13950 if (is_int) return normal; 13951 return switch (block.float_mode) { 13952 .Strict => normal, 13953 .Optimized => optimized, 13954 }; 13955 } 13956 13957 fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 13958 const mod = sema.mod; 13959 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 13960 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 13961 sema.src = src; 13962 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 13963 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 13964 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 13965 const lhs = try sema.resolveInst(extra.lhs); 13966 const rhs = try sema.resolveInst(extra.rhs); 13967 const lhs_ty = sema.typeOf(lhs); 13968 const rhs_ty = sema.typeOf(rhs); 13969 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); 13970 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); 13971 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 13972 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); 13973 13974 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 13975 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 13976 .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, 13977 }); 13978 13979 const is_vector = resolved_type.zigTypeTag(mod) == .Vector; 13980 13981 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 13982 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 13983 13984 const lhs_scalar_ty = lhs_ty.scalarType(mod); 13985 const rhs_scalar_ty = rhs_ty.scalarType(mod); 13986 const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); 13987 13988 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 13989 13990 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod_rem); 13991 13992 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); 13993 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); 13994 13995 const runtime_src = rs: { 13996 // For integers: 13997 // Either operand being undef is a compile error because there exists 13998 // a possible value (TODO what is it?) that would invoke illegal behavior. 13999 // TODO: can lhs undef be handled better? 14000 // 14001 // For floats: 14002 // If the rhs is zero, compile error for division by zero. 14003 // If the rhs is undefined, compile error because there is a possible 14004 // value (zero) for which the division would be illegal behavior. 14005 // If the lhs is undefined, result is undefined. 14006 // 14007 // For either one: if the result would be different between @mod and @rem, 14008 // then emit a compile error saying you have to pick one. 14009 if (is_int) { 14010 if (maybe_lhs_val) |lhs_val| { 14011 if (lhs_val.isUndef(mod)) { 14012 return sema.failWithUseOfUndef(block, lhs_src); 14013 } 14014 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 14015 const scalar_zero = switch (scalar_tag) { 14016 .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), 14017 .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), 14018 else => unreachable, 14019 }; 14020 const zero_val = if (is_vector) (try mod.intern(.{ .aggregate = .{ 14021 .ty = resolved_type.toIntern(), 14022 .storage = .{ .repeated_elem = scalar_zero.toIntern() }, 14023 } })).toValue() else scalar_zero; 14024 return sema.addConstant(resolved_type, zero_val); 14025 } 14026 } else if (lhs_scalar_ty.isSignedInt(mod)) { 14027 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); 14028 } 14029 if (maybe_rhs_val) |rhs_val| { 14030 if (rhs_val.isUndef(mod)) { 14031 return sema.failWithUseOfUndef(block, rhs_src); 14032 } 14033 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { 14034 return sema.failWithDivideByZero(block, rhs_src); 14035 } 14036 if (!(try rhs_val.compareAllWithZeroAdvanced(.gte, sema))) { 14037 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); 14038 } 14039 if (maybe_lhs_val) |lhs_val| { 14040 const rem_result = try sema.intRem(resolved_type, lhs_val, rhs_val); 14041 // If this answer could possibly be different by doing `intMod`, 14042 // we must emit a compile error. Otherwise, it's OK. 14043 if (!(try lhs_val.compareAllWithZeroAdvanced(.gte, sema)) and 14044 !(try rem_result.compareAllWithZeroAdvanced(.eq, sema))) 14045 { 14046 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); 14047 } 14048 return sema.addConstant(resolved_type, rem_result); 14049 } 14050 break :rs lhs_src; 14051 } else if (rhs_scalar_ty.isSignedInt(mod)) { 14052 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); 14053 } else { 14054 break :rs rhs_src; 14055 } 14056 } 14057 // float operands 14058 if (maybe_rhs_val) |rhs_val| { 14059 if (rhs_val.isUndef(mod)) { 14060 return sema.failWithUseOfUndef(block, rhs_src); 14061 } 14062 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { 14063 return sema.failWithDivideByZero(block, rhs_src); 14064 } 14065 if (!(try rhs_val.compareAllWithZeroAdvanced(.gte, sema))) { 14066 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); 14067 } 14068 if (maybe_lhs_val) |lhs_val| { 14069 if (lhs_val.isUndef(mod) or !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema))) { 14070 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); 14071 } 14072 return sema.addConstant( 14073 resolved_type, 14074 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, mod), 14075 ); 14076 } else { 14077 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); 14078 } 14079 } else { 14080 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); 14081 } 14082 }; 14083 14084 try sema.requireRuntimeBlock(block, src, runtime_src); 14085 14086 if (block.wantSafety()) { 14087 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); 14088 } 14089 14090 const air_tag = airTag(block, is_int, .rem, .rem_optimized); 14091 return block.addBinOp(air_tag, casted_lhs, casted_rhs); 14092 } 14093 14094 fn intRem( 14095 sema: *Sema, 14096 ty: Type, 14097 lhs: Value, 14098 rhs: Value, 14099 ) CompileError!Value { 14100 const mod = sema.mod; 14101 if (ty.zigTypeTag(mod) == .Vector) { 14102 const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod)); 14103 const scalar_ty = ty.scalarType(mod); 14104 for (result_data, 0..) |*scalar, i| { 14105 const lhs_elem = try lhs.elemValue(sema.mod, i); 14106 const rhs_elem = try rhs.elemValue(sema.mod, i); 14107 scalar.* = try (try sema.intRemScalar(lhs_elem, rhs_elem, scalar_ty)).intern(scalar_ty, mod); 14108 } 14109 return (try mod.intern(.{ .aggregate = .{ 14110 .ty = ty.toIntern(), 14111 .storage = .{ .elems = result_data }, 14112 } })).toValue(); 14113 } 14114 return sema.intRemScalar(lhs, rhs, ty); 14115 } 14116 14117 fn intRemScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) CompileError!Value { 14118 const mod = sema.mod; 14119 // TODO is this a performance issue? maybe we should try the operation without 14120 // resorting to BigInt first. 14121 var lhs_space: Value.BigIntSpace = undefined; 14122 var rhs_space: Value.BigIntSpace = undefined; 14123 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); 14124 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); 14125 const limbs_q = try sema.arena.alloc( 14126 math.big.Limb, 14127 lhs_bigint.limbs.len, 14128 ); 14129 const limbs_r = try sema.arena.alloc( 14130 math.big.Limb, 14131 // TODO: consider reworking Sema to re-use Values rather than 14132 // always producing new Value objects. 14133 rhs_bigint.limbs.len, 14134 ); 14135 const limbs_buffer = try sema.arena.alloc( 14136 math.big.Limb, 14137 math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len), 14138 ); 14139 var result_q = math.big.int.Mutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; 14140 var result_r = math.big.int.Mutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; 14141 result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer); 14142 return mod.intValue_big(scalar_ty, result_r.toConst()); 14143 } 14144 14145 fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 14146 const mod = sema.mod; 14147 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 14148 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 14149 sema.src = src; 14150 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 14151 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 14152 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 14153 const lhs = try sema.resolveInst(extra.lhs); 14154 const rhs = try sema.resolveInst(extra.rhs); 14155 const lhs_ty = sema.typeOf(lhs); 14156 const rhs_ty = sema.typeOf(rhs); 14157 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); 14158 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); 14159 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 14160 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); 14161 14162 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 14163 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 14164 .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, 14165 }); 14166 14167 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 14168 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 14169 14170 const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); 14171 14172 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 14173 14174 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod); 14175 14176 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); 14177 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); 14178 14179 const runtime_src = rs: { 14180 // For integers: 14181 // Either operand being undef is a compile error because there exists 14182 // a possible value (TODO what is it?) that would invoke illegal behavior. 14183 // TODO: can lhs zero be handled better? 14184 // TODO: can lhs undef be handled better? 14185 // 14186 // For floats: 14187 // If the rhs is zero, compile error for division by zero. 14188 // If the rhs is undefined, compile error because there is a possible 14189 // value (zero) for which the division would be illegal behavior. 14190 // If the lhs is undefined, result is undefined. 14191 if (is_int) { 14192 if (maybe_lhs_val) |lhs_val| { 14193 if (lhs_val.isUndef(mod)) { 14194 return sema.failWithUseOfUndef(block, lhs_src); 14195 } 14196 } 14197 if (maybe_rhs_val) |rhs_val| { 14198 if (rhs_val.isUndef(mod)) { 14199 return sema.failWithUseOfUndef(block, rhs_src); 14200 } 14201 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { 14202 return sema.failWithDivideByZero(block, rhs_src); 14203 } 14204 if (maybe_lhs_val) |lhs_val| { 14205 return sema.addConstant( 14206 resolved_type, 14207 try lhs_val.intMod(rhs_val, resolved_type, sema.arena, mod), 14208 ); 14209 } 14210 break :rs lhs_src; 14211 } else { 14212 break :rs rhs_src; 14213 } 14214 } 14215 // float operands 14216 if (maybe_rhs_val) |rhs_val| { 14217 if (rhs_val.isUndef(mod)) { 14218 return sema.failWithUseOfUndef(block, rhs_src); 14219 } 14220 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { 14221 return sema.failWithDivideByZero(block, rhs_src); 14222 } 14223 } 14224 if (maybe_lhs_val) |lhs_val| { 14225 if (lhs_val.isUndef(mod)) { 14226 return sema.addConstUndef(resolved_type); 14227 } 14228 if (maybe_rhs_val) |rhs_val| { 14229 return sema.addConstant( 14230 resolved_type, 14231 try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, mod), 14232 ); 14233 } else break :rs rhs_src; 14234 } else break :rs lhs_src; 14235 }; 14236 14237 try sema.requireRuntimeBlock(block, src, runtime_src); 14238 14239 if (block.wantSafety()) { 14240 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); 14241 } 14242 14243 const air_tag = airTag(block, is_int, .mod, .mod_optimized); 14244 return block.addBinOp(air_tag, casted_lhs, casted_rhs); 14245 } 14246 14247 fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 14248 const mod = sema.mod; 14249 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 14250 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 14251 sema.src = src; 14252 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 14253 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 14254 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 14255 const lhs = try sema.resolveInst(extra.lhs); 14256 const rhs = try sema.resolveInst(extra.rhs); 14257 const lhs_ty = sema.typeOf(lhs); 14258 const rhs_ty = sema.typeOf(rhs); 14259 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); 14260 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); 14261 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 14262 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); 14263 14264 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 14265 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 14266 .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, 14267 }); 14268 14269 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 14270 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 14271 14272 const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); 14273 14274 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 14275 14276 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .rem); 14277 14278 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); 14279 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); 14280 14281 const runtime_src = rs: { 14282 // For integers: 14283 // Either operand being undef is a compile error because there exists 14284 // a possible value (TODO what is it?) that would invoke illegal behavior. 14285 // TODO: can lhs zero be handled better? 14286 // TODO: can lhs undef be handled better? 14287 // 14288 // For floats: 14289 // If the rhs is zero, compile error for division by zero. 14290 // If the rhs is undefined, compile error because there is a possible 14291 // value (zero) for which the division would be illegal behavior. 14292 // If the lhs is undefined, result is undefined. 14293 if (is_int) { 14294 if (maybe_lhs_val) |lhs_val| { 14295 if (lhs_val.isUndef(mod)) { 14296 return sema.failWithUseOfUndef(block, lhs_src); 14297 } 14298 } 14299 if (maybe_rhs_val) |rhs_val| { 14300 if (rhs_val.isUndef(mod)) { 14301 return sema.failWithUseOfUndef(block, rhs_src); 14302 } 14303 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { 14304 return sema.failWithDivideByZero(block, rhs_src); 14305 } 14306 if (maybe_lhs_val) |lhs_val| { 14307 return sema.addConstant( 14308 resolved_type, 14309 try sema.intRem(resolved_type, lhs_val, rhs_val), 14310 ); 14311 } 14312 break :rs lhs_src; 14313 } else { 14314 break :rs rhs_src; 14315 } 14316 } 14317 // float operands 14318 if (maybe_rhs_val) |rhs_val| { 14319 if (rhs_val.isUndef(mod)) { 14320 return sema.failWithUseOfUndef(block, rhs_src); 14321 } 14322 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { 14323 return sema.failWithDivideByZero(block, rhs_src); 14324 } 14325 } 14326 if (maybe_lhs_val) |lhs_val| { 14327 if (lhs_val.isUndef(mod)) { 14328 return sema.addConstUndef(resolved_type); 14329 } 14330 if (maybe_rhs_val) |rhs_val| { 14331 return sema.addConstant( 14332 resolved_type, 14333 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, mod), 14334 ); 14335 } else break :rs rhs_src; 14336 } else break :rs lhs_src; 14337 }; 14338 14339 try sema.requireRuntimeBlock(block, src, runtime_src); 14340 14341 if (block.wantSafety()) { 14342 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); 14343 } 14344 14345 const air_tag = airTag(block, is_int, .rem, .rem_optimized); 14346 return block.addBinOp(air_tag, casted_lhs, casted_rhs); 14347 } 14348 14349 fn zirOverflowArithmetic( 14350 sema: *Sema, 14351 block: *Block, 14352 extended: Zir.Inst.Extended.InstData, 14353 zir_tag: Zir.Inst.Extended, 14354 ) CompileError!Air.Inst.Ref { 14355 const tracy = trace(@src()); 14356 defer tracy.end(); 14357 14358 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; 14359 const src = LazySrcLoc.nodeOffset(extra.node); 14360 14361 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 14362 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 14363 14364 const uncasted_lhs = try sema.resolveInst(extra.lhs); 14365 const uncasted_rhs = try sema.resolveInst(extra.rhs); 14366 14367 const lhs_ty = sema.typeOf(uncasted_lhs); 14368 const rhs_ty = sema.typeOf(uncasted_rhs); 14369 const mod = sema.mod; 14370 14371 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 14372 14373 const instructions = &[_]Air.Inst.Ref{ uncasted_lhs, uncasted_rhs }; 14374 const dest_ty = if (zir_tag == .shl_with_overflow) 14375 lhs_ty 14376 else 14377 try sema.resolvePeerTypes(block, src, instructions, .{ 14378 .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, 14379 }); 14380 14381 const rhs_dest_ty = if (zir_tag == .shl_with_overflow) 14382 try sema.log2IntType(block, lhs_ty, src) 14383 else 14384 dest_ty; 14385 14386 const lhs = try sema.coerce(block, dest_ty, uncasted_lhs, lhs_src); 14387 const rhs = try sema.coerce(block, rhs_dest_ty, uncasted_rhs, rhs_src); 14388 14389 if (dest_ty.scalarType(mod).zigTypeTag(mod) != .Int) { 14390 return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(mod)}); 14391 } 14392 14393 const maybe_lhs_val = try sema.resolveMaybeUndefVal(lhs); 14394 const maybe_rhs_val = try sema.resolveMaybeUndefVal(rhs); 14395 14396 const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty); 14397 const overflow_ty = mod.intern_pool.indexToKey(tuple_ty.toIntern()).anon_struct_type.types[1].toType(); 14398 14399 var result: struct { 14400 inst: Air.Inst.Ref = .none, 14401 wrapped: Value = Value.@"unreachable", 14402 overflow_bit: Value, 14403 } = result: { 14404 const zero_bit = try mod.intValue(Type.u1, 0); 14405 switch (zir_tag) { 14406 .add_with_overflow => { 14407 // If either of the arguments is zero, `false` is returned and the other is stored 14408 // to the result, even if it is undefined.. 14409 // Otherwise, if either of the argument is undefined, undefined is returned. 14410 if (maybe_lhs_val) |lhs_val| { 14411 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { 14412 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs }; 14413 } 14414 } 14415 if (maybe_rhs_val) |rhs_val| { 14416 if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { 14417 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; 14418 } 14419 } 14420 if (maybe_lhs_val) |lhs_val| { 14421 if (maybe_rhs_val) |rhs_val| { 14422 if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) { 14423 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; 14424 } 14425 14426 const result = try sema.intAddWithOverflow(lhs_val, rhs_val, dest_ty); 14427 break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result }; 14428 } 14429 } 14430 }, 14431 .sub_with_overflow => { 14432 // If the rhs is zero, then the result is lhs and no overflow occured. 14433 // Otherwise, if either result is undefined, both results are undefined. 14434 if (maybe_rhs_val) |rhs_val| { 14435 if (rhs_val.isUndef(mod)) { 14436 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; 14437 } else if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 14438 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; 14439 } else if (maybe_lhs_val) |lhs_val| { 14440 if (lhs_val.isUndef(mod)) { 14441 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; 14442 } 14443 14444 const result = try sema.intSubWithOverflow(lhs_val, rhs_val, dest_ty); 14445 break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result }; 14446 } 14447 } 14448 }, 14449 .mul_with_overflow => { 14450 // If either of the arguments is zero, the result is zero and no overflow occured. 14451 // If either of the arguments is one, the result is the other and no overflow occured. 14452 // Otherwise, if either of the arguments is undefined, both results are undefined. 14453 const scalar_one = try mod.intValue(dest_ty.scalarType(mod), 1); 14454 if (maybe_lhs_val) |lhs_val| { 14455 if (!lhs_val.isUndef(mod)) { 14456 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 14457 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; 14458 } else if (try sema.compareAll(lhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) { 14459 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs }; 14460 } 14461 } 14462 } 14463 14464 if (maybe_rhs_val) |rhs_val| { 14465 if (!rhs_val.isUndef(mod)) { 14466 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 14467 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs }; 14468 } else if (try sema.compareAll(rhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) { 14469 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; 14470 } 14471 } 14472 } 14473 14474 if (maybe_lhs_val) |lhs_val| { 14475 if (maybe_rhs_val) |rhs_val| { 14476 if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) { 14477 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; 14478 } 14479 14480 const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, mod); 14481 break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result }; 14482 } 14483 } 14484 }, 14485 .shl_with_overflow => { 14486 // If lhs is zero, the result is zero and no overflow occurred. 14487 // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred. 14488 // Oterhwise if either of the arguments is undefined, both results are undefined. 14489 if (maybe_lhs_val) |lhs_val| { 14490 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { 14491 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; 14492 } 14493 } 14494 if (maybe_rhs_val) |rhs_val| { 14495 if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { 14496 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; 14497 } 14498 } 14499 if (maybe_lhs_val) |lhs_val| { 14500 if (maybe_rhs_val) |rhs_val| { 14501 if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) { 14502 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; 14503 } 14504 14505 const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, sema.mod); 14506 break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result }; 14507 } 14508 } 14509 }, 14510 else => unreachable, 14511 } 14512 14513 const air_tag: Air.Inst.Tag = switch (zir_tag) { 14514 .add_with_overflow => .add_with_overflow, 14515 .mul_with_overflow => .mul_with_overflow, 14516 .sub_with_overflow => .sub_with_overflow, 14517 .shl_with_overflow => .shl_with_overflow, 14518 else => unreachable, 14519 }; 14520 14521 const runtime_src = if (maybe_lhs_val == null) lhs_src else rhs_src; 14522 try sema.requireRuntimeBlock(block, src, runtime_src); 14523 14524 return block.addInst(.{ 14525 .tag = air_tag, 14526 .data = .{ .ty_pl = .{ 14527 .ty = try block.sema.addType(tuple_ty), 14528 .payload = try block.sema.addExtra(Air.Bin{ 14529 .lhs = lhs, 14530 .rhs = rhs, 14531 }), 14532 } }, 14533 }); 14534 }; 14535 14536 if (result.inst != .none) { 14537 if (try sema.resolveMaybeUndefVal(result.inst)) |some| { 14538 result.wrapped = some; 14539 result.inst = .none; 14540 } 14541 } 14542 14543 if (result.inst == .none) { 14544 return sema.addConstant(tuple_ty, (try mod.intern(.{ .aggregate = .{ 14545 .ty = tuple_ty.toIntern(), 14546 .storage = .{ .elems = &.{ 14547 result.wrapped.toIntern(), 14548 result.overflow_bit.toIntern(), 14549 } }, 14550 } })).toValue()); 14551 } 14552 14553 const element_refs = try sema.arena.alloc(Air.Inst.Ref, 2); 14554 element_refs[0] = result.inst; 14555 element_refs[1] = try sema.addConstant(tuple_ty.structFieldType(1, mod), result.overflow_bit); 14556 return block.addAggregateInit(tuple_ty, element_refs); 14557 } 14558 14559 fn splat(sema: *Sema, ty: Type, val: Value) !Value { 14560 const mod = sema.mod; 14561 if (ty.zigTypeTag(mod) != .Vector) return val; 14562 const repeated = try mod.intern(.{ .aggregate = .{ 14563 .ty = ty.toIntern(), 14564 .storage = .{ .repeated_elem = val.toIntern() }, 14565 } }); 14566 return repeated.toValue(); 14567 } 14568 14569 fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type { 14570 const mod = sema.mod; 14571 const ov_ty = if (ty.zigTypeTag(mod) == .Vector) try mod.vectorType(.{ 14572 .len = ty.vectorLen(mod), 14573 .child = .u1_type, 14574 }) else Type.u1; 14575 14576 const types = [2]InternPool.Index{ ty.toIntern(), ov_ty.toIntern() }; 14577 const values = [2]InternPool.Index{ .none, .none }; 14578 const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ 14579 .types = &types, 14580 .values = &values, 14581 .names = &.{}, 14582 } }); 14583 return tuple_ty.toType(); 14584 } 14585 14586 fn analyzeArithmetic( 14587 sema: *Sema, 14588 block: *Block, 14589 /// TODO performance investigation: make this comptime? 14590 zir_tag: Zir.Inst.Tag, 14591 lhs: Air.Inst.Ref, 14592 rhs: Air.Inst.Ref, 14593 src: LazySrcLoc, 14594 lhs_src: LazySrcLoc, 14595 rhs_src: LazySrcLoc, 14596 want_safety: bool, 14597 ) CompileError!Air.Inst.Ref { 14598 const mod = sema.mod; 14599 const lhs_ty = sema.typeOf(lhs); 14600 const rhs_ty = sema.typeOf(rhs); 14601 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); 14602 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); 14603 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 14604 14605 if (lhs_zig_ty_tag == .Pointer) switch (lhs_ty.ptrSize(mod)) { 14606 .One, .Slice => {}, 14607 .Many, .C => { 14608 const air_tag: Air.Inst.Tag = switch (zir_tag) { 14609 .add => .ptr_add, 14610 .sub => .ptr_sub, 14611 else => return sema.fail(block, src, "invalid pointer arithmetic operator", .{}), 14612 }; 14613 return sema.analyzePtrArithmetic(block, src, lhs, rhs, air_tag, lhs_src, rhs_src); 14614 }, 14615 }; 14616 14617 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 14618 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 14619 .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, 14620 }); 14621 14622 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 14623 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 14624 14625 const scalar_type = resolved_type.scalarType(mod); 14626 const scalar_tag = scalar_type.zigTypeTag(mod); 14627 14628 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 14629 14630 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, zir_tag); 14631 14632 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); 14633 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); 14634 const rs: struct { src: LazySrcLoc, air_tag: Air.Inst.Tag } = rs: { 14635 switch (zir_tag) { 14636 .add, .add_unsafe => { 14637 // For integers:intAddSat 14638 // If either of the operands are zero, then the other operand is 14639 // returned, even if it is undefined. 14640 // If either of the operands are undefined, it's a compile error 14641 // because there is a possible value for which the addition would 14642 // overflow (max_int), causing illegal behavior. 14643 // For floats: either operand being undef makes the result undef. 14644 if (maybe_lhs_val) |lhs_val| { 14645 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { 14646 return casted_rhs; 14647 } 14648 } 14649 if (maybe_rhs_val) |rhs_val| { 14650 if (rhs_val.isUndef(mod)) { 14651 if (is_int) { 14652 return sema.failWithUseOfUndef(block, rhs_src); 14653 } else { 14654 return sema.addConstUndef(resolved_type); 14655 } 14656 } 14657 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 14658 return casted_lhs; 14659 } 14660 } 14661 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .add_optimized else .add; 14662 if (maybe_lhs_val) |lhs_val| { 14663 if (lhs_val.isUndef(mod)) { 14664 if (is_int) { 14665 return sema.failWithUseOfUndef(block, lhs_src); 14666 } else { 14667 return sema.addConstUndef(resolved_type); 14668 } 14669 } 14670 if (maybe_rhs_val) |rhs_val| { 14671 if (is_int) { 14672 const sum = try sema.intAdd(lhs_val, rhs_val, resolved_type); 14673 var vector_index: usize = undefined; 14674 if (!(try sema.intFitsInType(sum, resolved_type, &vector_index))) { 14675 return sema.failWithIntegerOverflow(block, src, resolved_type, sum, vector_index); 14676 } 14677 return sema.addConstant(resolved_type, sum); 14678 } else { 14679 return sema.addConstant( 14680 resolved_type, 14681 try Value.floatAdd(lhs_val, rhs_val, resolved_type, sema.arena, mod), 14682 ); 14683 } 14684 } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; 14685 } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; 14686 }, 14687 .addwrap => { 14688 // Integers only; floats are checked above. 14689 // If either of the operands are zero, the other operand is returned. 14690 // If either of the operands are undefined, the result is undefined. 14691 if (maybe_lhs_val) |lhs_val| { 14692 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { 14693 return casted_rhs; 14694 } 14695 } 14696 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .addwrap_optimized else .addwrap; 14697 if (maybe_rhs_val) |rhs_val| { 14698 if (rhs_val.isUndef(mod)) { 14699 return sema.addConstUndef(resolved_type); 14700 } 14701 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 14702 return casted_lhs; 14703 } 14704 if (maybe_lhs_val) |lhs_val| { 14705 return sema.addConstant( 14706 resolved_type, 14707 try sema.numberAddWrapScalar(lhs_val, rhs_val, resolved_type), 14708 ); 14709 } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; 14710 } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; 14711 }, 14712 .add_sat => { 14713 // Integers only; floats are checked above. 14714 // If either of the operands are zero, then the other operand is returned. 14715 // If either of the operands are undefined, the result is undefined. 14716 if (maybe_lhs_val) |lhs_val| { 14717 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { 14718 return casted_rhs; 14719 } 14720 } 14721 if (maybe_rhs_val) |rhs_val| { 14722 if (rhs_val.isUndef(mod)) { 14723 return sema.addConstUndef(resolved_type); 14724 } 14725 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 14726 return casted_lhs; 14727 } 14728 if (maybe_lhs_val) |lhs_val| { 14729 const val = if (scalar_tag == .ComptimeInt) 14730 try sema.intAdd(lhs_val, rhs_val, resolved_type) 14731 else 14732 try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, mod); 14733 14734 return sema.addConstant(resolved_type, val); 14735 } else break :rs .{ .src = lhs_src, .air_tag = .add_sat }; 14736 } else break :rs .{ .src = rhs_src, .air_tag = .add_sat }; 14737 }, 14738 .sub => { 14739 // For integers: 14740 // If the rhs is zero, then the other operand is 14741 // returned, even if it is undefined. 14742 // If either of the operands are undefined, it's a compile error 14743 // because there is a possible value for which the subtraction would 14744 // overflow, causing illegal behavior. 14745 // For floats: either operand being undef makes the result undef. 14746 if (maybe_rhs_val) |rhs_val| { 14747 if (rhs_val.isUndef(mod)) { 14748 if (is_int) { 14749 return sema.failWithUseOfUndef(block, rhs_src); 14750 } else { 14751 return sema.addConstUndef(resolved_type); 14752 } 14753 } 14754 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 14755 return casted_lhs; 14756 } 14757 } 14758 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .sub_optimized else .sub; 14759 if (maybe_lhs_val) |lhs_val| { 14760 if (lhs_val.isUndef(mod)) { 14761 if (is_int) { 14762 return sema.failWithUseOfUndef(block, lhs_src); 14763 } else { 14764 return sema.addConstUndef(resolved_type); 14765 } 14766 } 14767 if (maybe_rhs_val) |rhs_val| { 14768 if (is_int) { 14769 const diff = try sema.intSub(lhs_val, rhs_val, resolved_type); 14770 var vector_index: usize = undefined; 14771 if (!(try sema.intFitsInType(diff, resolved_type, &vector_index))) { 14772 return sema.failWithIntegerOverflow(block, src, resolved_type, diff, vector_index); 14773 } 14774 return sema.addConstant(resolved_type, diff); 14775 } else { 14776 return sema.addConstant( 14777 resolved_type, 14778 try Value.floatSub(lhs_val, rhs_val, resolved_type, sema.arena, mod), 14779 ); 14780 } 14781 } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; 14782 } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; 14783 }, 14784 .subwrap => { 14785 // Integers only; floats are checked above. 14786 // If the RHS is zero, then the other operand is returned, even if it is undefined. 14787 // If either of the operands are undefined, the result is undefined. 14788 if (maybe_rhs_val) |rhs_val| { 14789 if (rhs_val.isUndef(mod)) { 14790 return sema.addConstUndef(resolved_type); 14791 } 14792 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 14793 return casted_lhs; 14794 } 14795 } 14796 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .subwrap_optimized else .subwrap; 14797 if (maybe_lhs_val) |lhs_val| { 14798 if (lhs_val.isUndef(mod)) { 14799 return sema.addConstUndef(resolved_type); 14800 } 14801 if (maybe_rhs_val) |rhs_val| { 14802 return sema.addConstant( 14803 resolved_type, 14804 try sema.numberSubWrapScalar(lhs_val, rhs_val, resolved_type), 14805 ); 14806 } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; 14807 } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; 14808 }, 14809 .sub_sat => { 14810 // Integers only; floats are checked above. 14811 // If the RHS is zero, result is LHS. 14812 // If either of the operands are undefined, result is undefined. 14813 if (maybe_rhs_val) |rhs_val| { 14814 if (rhs_val.isUndef(mod)) { 14815 return sema.addConstUndef(resolved_type); 14816 } 14817 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 14818 return casted_lhs; 14819 } 14820 } 14821 if (maybe_lhs_val) |lhs_val| { 14822 if (lhs_val.isUndef(mod)) { 14823 return sema.addConstUndef(resolved_type); 14824 } 14825 if (maybe_rhs_val) |rhs_val| { 14826 const val = if (scalar_tag == .ComptimeInt) 14827 try sema.intSub(lhs_val, rhs_val, resolved_type) 14828 else 14829 try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, mod); 14830 14831 return sema.addConstant(resolved_type, val); 14832 } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat }; 14833 } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat }; 14834 }, 14835 .mul => { 14836 // For integers: 14837 // If either of the operands are zero, the result is zero. 14838 // If either of the operands are one, the result is the other 14839 // operand, even if it is undefined. 14840 // If either of the operands are undefined, it's a compile error 14841 // because there is a possible value for which the addition would 14842 // overflow (max_int), causing illegal behavior. 14843 // For floats: either operand being undef makes the result undef. 14844 // If either of the operands are inf, and the other operand is zero, 14845 // the result is nan. 14846 // If either of the operands are nan, the result is nan. 14847 const scalar_zero = switch (scalar_tag) { 14848 .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 0.0), 14849 .ComptimeInt, .Int => try mod.intValue(scalar_type, 0), 14850 else => unreachable, 14851 }; 14852 const scalar_one = switch (scalar_tag) { 14853 .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 1.0), 14854 .ComptimeInt, .Int => try mod.intValue(scalar_type, 1), 14855 else => unreachable, 14856 }; 14857 if (maybe_lhs_val) |lhs_val| { 14858 if (!lhs_val.isUndef(mod)) { 14859 if (lhs_val.isNan(mod)) { 14860 return sema.addConstant(resolved_type, lhs_val); 14861 } 14862 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) lz: { 14863 if (maybe_rhs_val) |rhs_val| { 14864 if (rhs_val.isNan(mod)) { 14865 return sema.addConstant(resolved_type, rhs_val); 14866 } 14867 if (rhs_val.isInf(mod)) { 14868 return sema.addConstant( 14869 resolved_type, 14870 try mod.floatValue(resolved_type, std.math.nan_f128), 14871 ); 14872 } 14873 } else if (resolved_type.isAnyFloat()) { 14874 break :lz; 14875 } 14876 const zero_val = try sema.splat(resolved_type, scalar_zero); 14877 return sema.addConstant(resolved_type, zero_val); 14878 } 14879 if (try sema.compareAll(lhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) { 14880 return casted_rhs; 14881 } 14882 } 14883 } 14884 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mul_optimized else .mul; 14885 if (maybe_rhs_val) |rhs_val| { 14886 if (rhs_val.isUndef(mod)) { 14887 if (is_int) { 14888 return sema.failWithUseOfUndef(block, rhs_src); 14889 } else { 14890 return sema.addConstUndef(resolved_type); 14891 } 14892 } 14893 if (rhs_val.isNan(mod)) { 14894 return sema.addConstant(resolved_type, rhs_val); 14895 } 14896 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) rz: { 14897 if (maybe_lhs_val) |lhs_val| { 14898 if (lhs_val.isInf(mod)) { 14899 return sema.addConstant( 14900 resolved_type, 14901 try mod.floatValue(resolved_type, std.math.nan_f128), 14902 ); 14903 } 14904 } else if (resolved_type.isAnyFloat()) { 14905 break :rz; 14906 } 14907 const zero_val = try sema.splat(resolved_type, scalar_zero); 14908 return sema.addConstant(resolved_type, zero_val); 14909 } 14910 if (try sema.compareAll(rhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) { 14911 return casted_lhs; 14912 } 14913 if (maybe_lhs_val) |lhs_val| { 14914 if (lhs_val.isUndef(mod)) { 14915 if (is_int) { 14916 return sema.failWithUseOfUndef(block, lhs_src); 14917 } else { 14918 return sema.addConstUndef(resolved_type); 14919 } 14920 } 14921 if (is_int) { 14922 const product = try lhs_val.intMul(rhs_val, resolved_type, sema.arena, sema.mod); 14923 var vector_index: usize = undefined; 14924 if (!(try sema.intFitsInType(product, resolved_type, &vector_index))) { 14925 return sema.failWithIntegerOverflow(block, src, resolved_type, product, vector_index); 14926 } 14927 return sema.addConstant(resolved_type, product); 14928 } else { 14929 return sema.addConstant( 14930 resolved_type, 14931 try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, sema.mod), 14932 ); 14933 } 14934 } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; 14935 } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; 14936 }, 14937 .mulwrap => { 14938 // Integers only; floats are handled above. 14939 // If either of the operands are zero, result is zero. 14940 // If either of the operands are one, result is the other operand. 14941 // If either of the operands are undefined, result is undefined. 14942 const scalar_zero = switch (scalar_tag) { 14943 .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 0.0), 14944 .ComptimeInt, .Int => try mod.intValue(scalar_type, 0), 14945 else => unreachable, 14946 }; 14947 const scalar_one = switch (scalar_tag) { 14948 .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 1.0), 14949 .ComptimeInt, .Int => try mod.intValue(scalar_type, 1), 14950 else => unreachable, 14951 }; 14952 if (maybe_lhs_val) |lhs_val| { 14953 if (!lhs_val.isUndef(mod)) { 14954 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 14955 const zero_val = try sema.splat(resolved_type, scalar_zero); 14956 return sema.addConstant(resolved_type, zero_val); 14957 } 14958 if (try sema.compareAll(lhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) { 14959 return casted_rhs; 14960 } 14961 } 14962 } 14963 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mulwrap_optimized else .mulwrap; 14964 if (maybe_rhs_val) |rhs_val| { 14965 if (rhs_val.isUndef(mod)) { 14966 return sema.addConstUndef(resolved_type); 14967 } 14968 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 14969 const zero_val = try sema.splat(resolved_type, scalar_zero); 14970 return sema.addConstant(resolved_type, zero_val); 14971 } 14972 if (try sema.compareAll(rhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) { 14973 return casted_lhs; 14974 } 14975 if (maybe_lhs_val) |lhs_val| { 14976 if (lhs_val.isUndef(mod)) { 14977 return sema.addConstUndef(resolved_type); 14978 } 14979 return sema.addConstant( 14980 resolved_type, 14981 try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, sema.mod), 14982 ); 14983 } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; 14984 } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; 14985 }, 14986 .mul_sat => { 14987 // Integers only; floats are checked above. 14988 // If either of the operands are zero, result is zero. 14989 // If either of the operands are one, result is the other operand. 14990 // If either of the operands are undefined, result is undefined. 14991 const scalar_zero = switch (scalar_tag) { 14992 .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 0.0), 14993 .ComptimeInt, .Int => try mod.intValue(scalar_type, 0), 14994 else => unreachable, 14995 }; 14996 const scalar_one = switch (scalar_tag) { 14997 .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 1.0), 14998 .ComptimeInt, .Int => try mod.intValue(scalar_type, 1), 14999 else => unreachable, 15000 }; 15001 if (maybe_lhs_val) |lhs_val| { 15002 if (!lhs_val.isUndef(mod)) { 15003 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 15004 const zero_val = try sema.splat(resolved_type, scalar_zero); 15005 return sema.addConstant(resolved_type, zero_val); 15006 } 15007 if (try sema.compareAll(lhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) { 15008 return casted_rhs; 15009 } 15010 } 15011 } 15012 if (maybe_rhs_val) |rhs_val| { 15013 if (rhs_val.isUndef(mod)) { 15014 return sema.addConstUndef(resolved_type); 15015 } 15016 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { 15017 const zero_val = try sema.splat(resolved_type, scalar_zero); 15018 return sema.addConstant(resolved_type, zero_val); 15019 } 15020 if (try sema.compareAll(rhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) { 15021 return casted_lhs; 15022 } 15023 if (maybe_lhs_val) |lhs_val| { 15024 if (lhs_val.isUndef(mod)) { 15025 return sema.addConstUndef(resolved_type); 15026 } 15027 15028 const val = if (scalar_tag == .ComptimeInt) 15029 try lhs_val.intMul(rhs_val, resolved_type, sema.arena, sema.mod) 15030 else 15031 try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, sema.mod); 15032 15033 return sema.addConstant(resolved_type, val); 15034 } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat }; 15035 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat }; 15036 }, 15037 else => unreachable, 15038 } 15039 }; 15040 15041 try sema.requireRuntimeBlock(block, src, rs.src); 15042 if (block.wantSafety() and want_safety) { 15043 if (scalar_tag == .Int) { 15044 const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) { 15045 .add => .add_with_overflow, 15046 .sub => .sub_with_overflow, 15047 .mul => .mul_with_overflow, 15048 else => null, 15049 }; 15050 if (maybe_op_ov) |op_ov_tag| { 15051 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(resolved_type); 15052 const op_ov = try block.addInst(.{ 15053 .tag = op_ov_tag, 15054 .data = .{ .ty_pl = .{ 15055 .ty = try sema.addType(op_ov_tuple_ty), 15056 .payload = try sema.addExtra(Air.Bin{ 15057 .lhs = casted_lhs, 15058 .rhs = casted_rhs, 15059 }), 15060 } }, 15061 }); 15062 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); 15063 const any_ov_bit = if (resolved_type.zigTypeTag(mod) == .Vector) 15064 try block.addInst(.{ 15065 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, 15066 .data = .{ .reduce = .{ 15067 .operand = ov_bit, 15068 .operation = .Or, 15069 } }, 15070 }) 15071 else 15072 ov_bit; 15073 const zero_ov = try sema.addConstant(Type.u1, try mod.intValue(Type.u1, 0)); 15074 const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); 15075 15076 try sema.addSafetyCheck(block, no_ov, .integer_overflow); 15077 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); 15078 } 15079 } 15080 } 15081 return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs); 15082 } 15083 15084 fn analyzePtrArithmetic( 15085 sema: *Sema, 15086 block: *Block, 15087 op_src: LazySrcLoc, 15088 ptr: Air.Inst.Ref, 15089 uncasted_offset: Air.Inst.Ref, 15090 air_tag: Air.Inst.Tag, 15091 ptr_src: LazySrcLoc, 15092 offset_src: LazySrcLoc, 15093 ) CompileError!Air.Inst.Ref { 15094 // TODO if the operand is comptime-known to be negative, or is a negative int, 15095 // coerce to isize instead of usize. 15096 const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src); 15097 const mod = sema.mod; 15098 const opt_ptr_val = try sema.resolveMaybeUndefVal(ptr); 15099 const opt_off_val = try sema.resolveDefinedValue(block, offset_src, offset); 15100 const ptr_ty = sema.typeOf(ptr); 15101 const ptr_info = ptr_ty.ptrInfo(mod); 15102 assert(ptr_info.size == .Many or ptr_info.size == .C); 15103 15104 const new_ptr_ty = t: { 15105 // Calculate the new pointer alignment. 15106 // This code is duplicated in `elemPtrType`. 15107 if (ptr_info.@"align" == 0) { 15108 // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness. 15109 break :t ptr_ty; 15110 } 15111 // If the addend is not a comptime-known value we can still count on 15112 // it being a multiple of the type size. 15113 const elem_size = ptr_info.pointee_type.abiSize(mod); 15114 const addend = if (opt_off_val) |off_val| a: { 15115 const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(mod)); 15116 break :a elem_size * off_int; 15117 } else elem_size; 15118 15119 // The resulting pointer is aligned to the lcd between the offset (an 15120 // arbitrary number) and the alignment factor (always a power of two, 15121 // non zero). 15122 const new_align = @as(u32, 1) << @intCast(u5, @ctz(addend | ptr_info.@"align")); 15123 15124 break :t try Type.ptr(sema.arena, sema.mod, .{ 15125 .pointee_type = ptr_info.pointee_type, 15126 .sentinel = ptr_info.sentinel, 15127 .@"align" = new_align, 15128 .@"addrspace" = ptr_info.@"addrspace", 15129 .mutable = ptr_info.mutable, 15130 .@"allowzero" = ptr_info.@"allowzero", 15131 .@"volatile" = ptr_info.@"volatile", 15132 .size = ptr_info.size, 15133 }); 15134 }; 15135 15136 const runtime_src = rs: { 15137 if (opt_ptr_val) |ptr_val| { 15138 if (opt_off_val) |offset_val| { 15139 if (ptr_val.isUndef(mod)) return sema.addConstUndef(new_ptr_ty); 15140 15141 const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(mod)); 15142 if (offset_int == 0) return ptr; 15143 if (try ptr_val.getUnsignedIntAdvanced(mod, sema)) |addr| { 15144 const elem_size = ptr_info.pointee_type.abiSize(mod); 15145 const new_addr = switch (air_tag) { 15146 .ptr_add => addr + elem_size * offset_int, 15147 .ptr_sub => addr - elem_size * offset_int, 15148 else => unreachable, 15149 }; 15150 const new_ptr_val = try mod.ptrIntValue(new_ptr_ty, new_addr); 15151 return sema.addConstant(new_ptr_ty, new_ptr_val); 15152 } 15153 if (air_tag == .ptr_sub) { 15154 return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{}); 15155 } 15156 const new_ptr_val = try ptr_val.elemPtr(new_ptr_ty, offset_int, sema.mod); 15157 return sema.addConstant(new_ptr_ty, new_ptr_val); 15158 } else break :rs offset_src; 15159 } else break :rs ptr_src; 15160 }; 15161 15162 try sema.requireRuntimeBlock(block, op_src, runtime_src); 15163 return block.addInst(.{ 15164 .tag = air_tag, 15165 .data = .{ .ty_pl = .{ 15166 .ty = try sema.addType(new_ptr_ty), 15167 .payload = try sema.addExtra(Air.Bin{ 15168 .lhs = ptr, 15169 .rhs = offset, 15170 }), 15171 } }, 15172 }); 15173 } 15174 15175 fn zirLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 15176 const tracy = trace(@src()); 15177 defer tracy.end(); 15178 15179 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15180 const src = inst_data.src(); 15181 const ptr_src = src; // TODO better source location 15182 const ptr = try sema.resolveInst(inst_data.operand); 15183 return sema.analyzeLoad(block, src, ptr, ptr_src); 15184 } 15185 15186 fn zirAsm( 15187 sema: *Sema, 15188 block: *Block, 15189 extended: Zir.Inst.Extended.InstData, 15190 tmpl_is_expr: bool, 15191 ) CompileError!Air.Inst.Ref { 15192 const tracy = trace(@src()); 15193 defer tracy.end(); 15194 15195 const extra = sema.code.extraData(Zir.Inst.Asm, extended.operand); 15196 const src = LazySrcLoc.nodeOffset(extra.data.src_node); 15197 const ret_ty_src: LazySrcLoc = .{ .node_offset_asm_ret_ty = extra.data.src_node }; 15198 const outputs_len = @truncate(u5, extended.small); 15199 const inputs_len = @truncate(u5, extended.small >> 5); 15200 const clobbers_len = @truncate(u5, extended.small >> 10); 15201 const is_volatile = @truncate(u1, extended.small >> 15) != 0; 15202 const is_global_assembly = sema.func_index == .none; 15203 15204 const asm_source: []const u8 = if (tmpl_is_expr) blk: { 15205 const tmpl = @intToEnum(Zir.Inst.Ref, extra.data.asm_source); 15206 const s: []const u8 = try sema.resolveConstString(block, src, tmpl, "assembly code must be comptime-known"); 15207 break :blk s; 15208 } else sema.code.nullTerminatedString(extra.data.asm_source); 15209 15210 if (is_global_assembly) { 15211 if (outputs_len != 0) { 15212 return sema.fail(block, src, "module-level assembly does not support outputs", .{}); 15213 } 15214 if (inputs_len != 0) { 15215 return sema.fail(block, src, "module-level assembly does not support inputs", .{}); 15216 } 15217 if (clobbers_len != 0) { 15218 return sema.fail(block, src, "module-level assembly does not support clobbers", .{}); 15219 } 15220 if (is_volatile) { 15221 return sema.fail(block, src, "volatile keyword is redundant on module-level assembly", .{}); 15222 } 15223 try sema.mod.addGlobalAssembly(sema.owner_decl_index, asm_source); 15224 return Air.Inst.Ref.void_value; 15225 } 15226 15227 if (block.is_comptime) { 15228 try sema.requireRuntimeBlock(block, src, null); 15229 } 15230 15231 var extra_i = extra.end; 15232 var output_type_bits = extra.data.output_type_bits; 15233 var needed_capacity: usize = @typeInfo(Air.Asm).Struct.fields.len + outputs_len + inputs_len; 15234 15235 const ConstraintName = struct { c: []const u8, n: []const u8 }; 15236 const out_args = try sema.arena.alloc(Air.Inst.Ref, outputs_len); 15237 const outputs = try sema.arena.alloc(ConstraintName, outputs_len); 15238 var expr_ty = Air.Inst.Ref.void_type; 15239 15240 for (out_args, 0..) |*arg, out_i| { 15241 const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i); 15242 extra_i = output.end; 15243 15244 const is_type = @truncate(u1, output_type_bits) != 0; 15245 output_type_bits >>= 1; 15246 15247 if (is_type) { 15248 // Indicate the output is the asm instruction return value. 15249 arg.* = .none; 15250 const out_ty = try sema.resolveType(block, ret_ty_src, output.data.operand); 15251 try sema.queueFullTypeResolution(out_ty); 15252 expr_ty = try sema.addType(out_ty); 15253 } else { 15254 arg.* = try sema.resolveInst(output.data.operand); 15255 } 15256 15257 const constraint = sema.code.nullTerminatedString(output.data.constraint); 15258 const name = sema.code.nullTerminatedString(output.data.name); 15259 needed_capacity += (constraint.len + name.len + (2 + 3)) / 4; 15260 15261 outputs[out_i] = .{ .c = constraint, .n = name }; 15262 } 15263 15264 const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len); 15265 const inputs = try sema.arena.alloc(ConstraintName, inputs_len); 15266 const mod = sema.mod; 15267 15268 for (args, 0..) |*arg, arg_i| { 15269 const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i); 15270 extra_i = input.end; 15271 15272 const uncasted_arg = try sema.resolveInst(input.data.operand); 15273 const uncasted_arg_ty = sema.typeOf(uncasted_arg); 15274 switch (uncasted_arg_ty.zigTypeTag(mod)) { 15275 .ComptimeInt => arg.* = try sema.coerce(block, Type.usize, uncasted_arg, src), 15276 .ComptimeFloat => arg.* = try sema.coerce(block, Type.f64, uncasted_arg, src), 15277 else => { 15278 arg.* = uncasted_arg; 15279 try sema.queueFullTypeResolution(uncasted_arg_ty); 15280 }, 15281 } 15282 15283 const constraint = sema.code.nullTerminatedString(input.data.constraint); 15284 const name = sema.code.nullTerminatedString(input.data.name); 15285 needed_capacity += (constraint.len + name.len + (2 + 3)) / 4; 15286 inputs[arg_i] = .{ .c = constraint, .n = name }; 15287 } 15288 15289 const clobbers = try sema.arena.alloc([]const u8, clobbers_len); 15290 for (clobbers) |*name| { 15291 name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]); 15292 extra_i += 1; 15293 15294 needed_capacity += name.*.len / 4 + 1; 15295 } 15296 15297 needed_capacity += (asm_source.len + 3) / 4; 15298 15299 const gpa = sema.gpa; 15300 try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity); 15301 const asm_air = try block.addInst(.{ 15302 .tag = .assembly, 15303 .data = .{ .ty_pl = .{ 15304 .ty = expr_ty, 15305 .payload = sema.addExtraAssumeCapacity(Air.Asm{ 15306 .source_len = @intCast(u32, asm_source.len), 15307 .outputs_len = outputs_len, 15308 .inputs_len = @intCast(u32, args.len), 15309 .flags = (@as(u32, @boolToInt(is_volatile)) << 31) | @intCast(u32, clobbers.len), 15310 }), 15311 } }, 15312 }); 15313 sema.appendRefsAssumeCapacity(out_args); 15314 sema.appendRefsAssumeCapacity(args); 15315 for (outputs) |o| { 15316 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); 15317 @memcpy(buffer[0..o.c.len], o.c); 15318 buffer[o.c.len] = 0; 15319 @memcpy(buffer[o.c.len + 1 ..][0..o.n.len], o.n); 15320 buffer[o.c.len + 1 + o.n.len] = 0; 15321 sema.air_extra.items.len += (o.c.len + o.n.len + (2 + 3)) / 4; 15322 } 15323 for (inputs) |input| { 15324 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); 15325 @memcpy(buffer[0..input.c.len], input.c); 15326 buffer[input.c.len] = 0; 15327 @memcpy(buffer[input.c.len + 1 ..][0..input.n.len], input.n); 15328 buffer[input.c.len + 1 + input.n.len] = 0; 15329 sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4; 15330 } 15331 for (clobbers) |clobber| { 15332 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); 15333 @memcpy(buffer[0..clobber.len], clobber); 15334 buffer[clobber.len] = 0; 15335 sema.air_extra.items.len += clobber.len / 4 + 1; 15336 } 15337 { 15338 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); 15339 @memcpy(buffer[0..asm_source.len], asm_source); 15340 sema.air_extra.items.len += (asm_source.len + 3) / 4; 15341 } 15342 return asm_air; 15343 } 15344 15345 /// Only called for equality operators. See also `zirCmp`. 15346 fn zirCmpEq( 15347 sema: *Sema, 15348 block: *Block, 15349 inst: Zir.Inst.Index, 15350 op: std.math.CompareOperator, 15351 air_tag: Air.Inst.Tag, 15352 ) CompileError!Air.Inst.Ref { 15353 const tracy = trace(@src()); 15354 defer tracy.end(); 15355 15356 const mod = sema.mod; 15357 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 15358 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 15359 const src: LazySrcLoc = inst_data.src(); 15360 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 15361 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 15362 const lhs = try sema.resolveInst(extra.lhs); 15363 const rhs = try sema.resolveInst(extra.rhs); 15364 15365 const lhs_ty = sema.typeOf(lhs); 15366 const rhs_ty = sema.typeOf(rhs); 15367 const lhs_ty_tag = lhs_ty.zigTypeTag(mod); 15368 const rhs_ty_tag = rhs_ty.zigTypeTag(mod); 15369 if (lhs_ty_tag == .Null and rhs_ty_tag == .Null) { 15370 // null == null, null != null 15371 if (op == .eq) { 15372 return Air.Inst.Ref.bool_true; 15373 } else { 15374 return Air.Inst.Ref.bool_false; 15375 } 15376 } 15377 15378 // comparing null with optionals 15379 if (lhs_ty_tag == .Null and (rhs_ty_tag == .Optional or rhs_ty.isCPtr(mod))) { 15380 return sema.analyzeIsNull(block, src, rhs, op == .neq); 15381 } 15382 if (rhs_ty_tag == .Null and (lhs_ty_tag == .Optional or lhs_ty.isCPtr(mod))) { 15383 return sema.analyzeIsNull(block, src, lhs, op == .neq); 15384 } 15385 15386 if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) { 15387 const non_null_type = if (lhs_ty_tag == .Null) rhs_ty else lhs_ty; 15388 return sema.fail(block, src, "comparison of '{}' with null", .{non_null_type.fmt(sema.mod)}); 15389 } 15390 15391 if (lhs_ty_tag == .Union and (rhs_ty_tag == .EnumLiteral or rhs_ty_tag == .Enum)) { 15392 return sema.analyzeCmpUnionTag(block, src, lhs, lhs_src, rhs, rhs_src, op); 15393 } 15394 if (rhs_ty_tag == .Union and (lhs_ty_tag == .EnumLiteral or lhs_ty_tag == .Enum)) { 15395 return sema.analyzeCmpUnionTag(block, src, rhs, rhs_src, lhs, lhs_src, op); 15396 } 15397 15398 if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) { 15399 const runtime_src: LazySrcLoc = src: { 15400 if (try sema.resolveMaybeUndefVal(lhs)) |lval| { 15401 if (try sema.resolveMaybeUndefVal(rhs)) |rval| { 15402 if (lval.isUndef(mod) or rval.isUndef(mod)) { 15403 return sema.addConstUndef(Type.bool); 15404 } 15405 const lkey = mod.intern_pool.indexToKey(lval.toIntern()); 15406 const rkey = mod.intern_pool.indexToKey(rval.toIntern()); 15407 if ((lkey.err.name == rkey.err.name) == (op == .eq)) { 15408 return Air.Inst.Ref.bool_true; 15409 } else { 15410 return Air.Inst.Ref.bool_false; 15411 } 15412 } else { 15413 break :src rhs_src; 15414 } 15415 } else { 15416 break :src lhs_src; 15417 } 15418 }; 15419 try sema.requireRuntimeBlock(block, src, runtime_src); 15420 return block.addBinOp(air_tag, lhs, rhs); 15421 } 15422 if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) { 15423 const lhs_as_type = try sema.analyzeAsType(block, lhs_src, lhs); 15424 const rhs_as_type = try sema.analyzeAsType(block, rhs_src, rhs); 15425 if (lhs_as_type.eql(rhs_as_type, sema.mod) == (op == .eq)) { 15426 return Air.Inst.Ref.bool_true; 15427 } else { 15428 return Air.Inst.Ref.bool_false; 15429 } 15430 } 15431 return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, true); 15432 } 15433 15434 fn analyzeCmpUnionTag( 15435 sema: *Sema, 15436 block: *Block, 15437 src: LazySrcLoc, 15438 un: Air.Inst.Ref, 15439 un_src: LazySrcLoc, 15440 tag: Air.Inst.Ref, 15441 tag_src: LazySrcLoc, 15442 op: std.math.CompareOperator, 15443 ) CompileError!Air.Inst.Ref { 15444 const mod = sema.mod; 15445 const union_ty = try sema.resolveTypeFields(sema.typeOf(un)); 15446 const union_tag_ty = union_ty.unionTagType(mod) orelse { 15447 const msg = msg: { 15448 const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{}); 15449 errdefer msg.destroy(sema.gpa); 15450 try sema.mod.errNoteNonLazy(union_ty.declSrcLoc(sema.mod), msg, "union '{}' is not a tagged union", .{union_ty.fmt(sema.mod)}); 15451 break :msg msg; 15452 }; 15453 return sema.failWithOwnedErrorMsg(msg); 15454 }; 15455 // Coerce both the union and the tag to the union's tag type, and then execute the 15456 // enum comparison codepath. 15457 const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src); 15458 const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src); 15459 15460 if (try sema.resolveMaybeUndefVal(coerced_tag)) |enum_val| { 15461 if (enum_val.isUndef(mod)) return sema.addConstUndef(Type.bool); 15462 const field_ty = union_ty.unionFieldType(enum_val, sema.mod); 15463 if (field_ty.zigTypeTag(mod) == .NoReturn) { 15464 return Air.Inst.Ref.bool_false; 15465 } 15466 } 15467 15468 return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src); 15469 } 15470 15471 /// Only called for non-equality operators. See also `zirCmpEq`. 15472 fn zirCmp( 15473 sema: *Sema, 15474 block: *Block, 15475 inst: Zir.Inst.Index, 15476 op: std.math.CompareOperator, 15477 ) CompileError!Air.Inst.Ref { 15478 const tracy = trace(@src()); 15479 defer tracy.end(); 15480 15481 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 15482 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 15483 const src: LazySrcLoc = inst_data.src(); 15484 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 15485 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 15486 const lhs = try sema.resolveInst(extra.lhs); 15487 const rhs = try sema.resolveInst(extra.rhs); 15488 return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, false); 15489 } 15490 15491 fn analyzeCmp( 15492 sema: *Sema, 15493 block: *Block, 15494 src: LazySrcLoc, 15495 lhs: Air.Inst.Ref, 15496 rhs: Air.Inst.Ref, 15497 op: std.math.CompareOperator, 15498 lhs_src: LazySrcLoc, 15499 rhs_src: LazySrcLoc, 15500 is_equality_cmp: bool, 15501 ) CompileError!Air.Inst.Ref { 15502 const mod = sema.mod; 15503 const lhs_ty = sema.typeOf(lhs); 15504 const rhs_ty = sema.typeOf(rhs); 15505 if (lhs_ty.zigTypeTag(mod) != .Optional and rhs_ty.zigTypeTag(mod) != .Optional) { 15506 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 15507 } 15508 15509 if (lhs_ty.zigTypeTag(mod) == .Vector and rhs_ty.zigTypeTag(mod) == .Vector) { 15510 return sema.cmpVector(block, src, lhs, rhs, op, lhs_src, rhs_src); 15511 } 15512 if (lhs_ty.isNumeric(mod) and rhs_ty.isNumeric(mod)) { 15513 // This operation allows any combination of integer and float types, regardless of the 15514 // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for 15515 // numeric types. 15516 return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src); 15517 } 15518 if (is_equality_cmp and lhs_ty.zigTypeTag(mod) == .ErrorUnion and rhs_ty.zigTypeTag(mod) == .ErrorSet) { 15519 const casted_lhs = try sema.analyzeErrUnionCode(block, lhs_src, lhs); 15520 return sema.cmpSelf(block, src, casted_lhs, rhs, op, lhs_src, rhs_src); 15521 } 15522 if (is_equality_cmp and lhs_ty.zigTypeTag(mod) == .ErrorSet and rhs_ty.zigTypeTag(mod) == .ErrorUnion) { 15523 const casted_rhs = try sema.analyzeErrUnionCode(block, rhs_src, rhs); 15524 return sema.cmpSelf(block, src, lhs, casted_rhs, op, lhs_src, rhs_src); 15525 } 15526 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 15527 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } }); 15528 if (!resolved_type.isSelfComparable(mod, is_equality_cmp)) { 15529 return sema.fail(block, src, "operator {s} not allowed for type '{}'", .{ 15530 compareOperatorName(op), resolved_type.fmt(sema.mod), 15531 }); 15532 } 15533 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 15534 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 15535 return sema.cmpSelf(block, src, casted_lhs, casted_rhs, op, lhs_src, rhs_src); 15536 } 15537 15538 fn compareOperatorName(comp: std.math.CompareOperator) []const u8 { 15539 return switch (comp) { 15540 .lt => "<", 15541 .lte => "<=", 15542 .eq => "==", 15543 .gte => ">=", 15544 .gt => ">", 15545 .neq => "!=", 15546 }; 15547 } 15548 15549 fn cmpSelf( 15550 sema: *Sema, 15551 block: *Block, 15552 src: LazySrcLoc, 15553 casted_lhs: Air.Inst.Ref, 15554 casted_rhs: Air.Inst.Ref, 15555 op: std.math.CompareOperator, 15556 lhs_src: LazySrcLoc, 15557 rhs_src: LazySrcLoc, 15558 ) CompileError!Air.Inst.Ref { 15559 const mod = sema.mod; 15560 const resolved_type = sema.typeOf(casted_lhs); 15561 const runtime_src: LazySrcLoc = src: { 15562 if (try sema.resolveMaybeUndefVal(casted_lhs)) |lhs_val| { 15563 if (lhs_val.isUndef(mod)) return sema.addConstUndef(Type.bool); 15564 if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| { 15565 if (rhs_val.isUndef(mod)) return sema.addConstUndef(Type.bool); 15566 15567 if (resolved_type.zigTypeTag(mod) == .Vector) { 15568 const result_ty = try mod.vectorType(.{ 15569 .len = resolved_type.vectorLen(mod), 15570 .child = .bool_type, 15571 }); 15572 const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_type); 15573 return sema.addConstant(result_ty, cmp_val); 15574 } 15575 15576 if (try sema.compareAll(lhs_val, op, rhs_val, resolved_type)) { 15577 return Air.Inst.Ref.bool_true; 15578 } else { 15579 return Air.Inst.Ref.bool_false; 15580 } 15581 } else { 15582 if (resolved_type.zigTypeTag(mod) == .Bool) { 15583 // We can lower bool eq/neq more efficiently. 15584 return sema.runtimeBoolCmp(block, src, op, casted_rhs, lhs_val.toBool(), rhs_src); 15585 } 15586 break :src rhs_src; 15587 } 15588 } else { 15589 // For bools, we still check the other operand, because we can lower 15590 // bool eq/neq more efficiently. 15591 if (resolved_type.zigTypeTag(mod) == .Bool) { 15592 if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| { 15593 if (rhs_val.isUndef(mod)) return sema.addConstUndef(Type.bool); 15594 return sema.runtimeBoolCmp(block, src, op, casted_lhs, rhs_val.toBool(), lhs_src); 15595 } 15596 } 15597 break :src lhs_src; 15598 } 15599 }; 15600 try sema.requireRuntimeBlock(block, src, runtime_src); 15601 if (resolved_type.zigTypeTag(mod) == .Vector) { 15602 return block.addCmpVector(casted_lhs, casted_rhs, op); 15603 } 15604 const tag = Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized); 15605 return block.addBinOp(tag, casted_lhs, casted_rhs); 15606 } 15607 15608 /// cmp_eq (x, false) => not(x) 15609 /// cmp_eq (x, true ) => x 15610 /// cmp_neq(x, false) => x 15611 /// cmp_neq(x, true ) => not(x) 15612 fn runtimeBoolCmp( 15613 sema: *Sema, 15614 block: *Block, 15615 src: LazySrcLoc, 15616 op: std.math.CompareOperator, 15617 lhs: Air.Inst.Ref, 15618 rhs: bool, 15619 runtime_src: LazySrcLoc, 15620 ) CompileError!Air.Inst.Ref { 15621 if ((op == .neq) == rhs) { 15622 try sema.requireRuntimeBlock(block, src, runtime_src); 15623 return block.addTyOp(.not, Type.bool, lhs); 15624 } else { 15625 return lhs; 15626 } 15627 } 15628 15629 fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 15630 const mod = sema.mod; 15631 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15632 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 15633 const ty = try sema.resolveType(block, operand_src, inst_data.operand); 15634 switch (ty.zigTypeTag(mod)) { 15635 .Fn, 15636 .NoReturn, 15637 .Undefined, 15638 .Null, 15639 .Opaque, 15640 => return sema.fail(block, operand_src, "no size available for type '{}'", .{ty.fmt(sema.mod)}), 15641 15642 .Type, 15643 .EnumLiteral, 15644 .ComptimeFloat, 15645 .ComptimeInt, 15646 .Void, 15647 => return sema.addIntUnsigned(Type.comptime_int, 0), 15648 15649 .Bool, 15650 .Int, 15651 .Float, 15652 .Pointer, 15653 .Array, 15654 .Struct, 15655 .Optional, 15656 .ErrorUnion, 15657 .ErrorSet, 15658 .Enum, 15659 .Union, 15660 .Vector, 15661 .Frame, 15662 .AnyFrame, 15663 => {}, 15664 } 15665 const val = try ty.lazyAbiSize(mod); 15666 if (val.isLazySize(mod)) { 15667 try sema.queueFullTypeResolution(ty); 15668 } 15669 return sema.addConstant(Type.comptime_int, val); 15670 } 15671 15672 fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 15673 const mod = sema.mod; 15674 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15675 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 15676 const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand); 15677 switch (operand_ty.zigTypeTag(mod)) { 15678 .Fn, 15679 .NoReturn, 15680 .Undefined, 15681 .Null, 15682 .Opaque, 15683 => return sema.fail(block, operand_src, "no size available for type '{}'", .{operand_ty.fmt(sema.mod)}), 15684 15685 .Type, 15686 .EnumLiteral, 15687 .ComptimeFloat, 15688 .ComptimeInt, 15689 .Void, 15690 => return sema.addIntUnsigned(Type.comptime_int, 0), 15691 15692 .Bool, 15693 .Int, 15694 .Float, 15695 .Pointer, 15696 .Array, 15697 .Struct, 15698 .Optional, 15699 .ErrorUnion, 15700 .ErrorSet, 15701 .Enum, 15702 .Union, 15703 .Vector, 15704 .Frame, 15705 .AnyFrame, 15706 => {}, 15707 } 15708 const bit_size = try operand_ty.bitSizeAdvanced(mod, sema); 15709 return sema.addIntUnsigned(Type.comptime_int, bit_size); 15710 } 15711 15712 fn zirThis( 15713 sema: *Sema, 15714 block: *Block, 15715 extended: Zir.Inst.Extended.InstData, 15716 ) CompileError!Air.Inst.Ref { 15717 const mod = sema.mod; 15718 const this_decl_index = mod.namespaceDeclIndex(block.namespace); 15719 const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand)); 15720 return sema.analyzeDeclVal(block, src, this_decl_index); 15721 } 15722 15723 fn zirClosureCapture( 15724 sema: *Sema, 15725 block: *Block, 15726 inst: Zir.Inst.Index, 15727 ) CompileError!void { 15728 // TODO: Compile error when closed over values are modified 15729 const inst_data = sema.code.instructions.items(.data)[inst].un_tok; 15730 // Closures are not necessarily constant values. For example, the 15731 // code might do something like this: 15732 // fn foo(x: anytype) void { const S = struct {field: @TypeOf(x)}; } 15733 // ...in which case the closure_capture instruction has access to a runtime 15734 // value only. In such case we preserve the type and use a dummy runtime value. 15735 const operand = try sema.resolveInst(inst_data.operand); 15736 const ty = sema.typeOf(operand); 15737 const capture: CaptureScope.Capture = blk: { 15738 if (try sema.resolveMaybeUndefValAllowVariables(operand)) |val| { 15739 const ip_index = try val.intern(ty, sema.mod); 15740 break :blk .{ .comptime_val = ip_index }; 15741 } 15742 break :blk .{ .runtime_val = ty.toIntern() }; 15743 }; 15744 try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, capture); 15745 } 15746 15747 fn zirClosureGet( 15748 sema: *Sema, 15749 block: *Block, 15750 inst: Zir.Inst.Index, 15751 ) CompileError!Air.Inst.Ref { 15752 const mod = sema.mod; 15753 // TODO CLOSURE: Test this with inline functions 15754 const inst_data = sema.code.instructions.items(.data)[inst].inst_node; 15755 var scope: *CaptureScope = mod.declPtr(block.src_decl).src_scope.?; 15756 // Note: The target closure must be in this scope list. 15757 // If it's not here, the zir is invalid, or the list is broken. 15758 const capture = while (true) { 15759 // Note: We don't need to add a dependency here, because 15760 // decls always depend on their lexical parents. 15761 15762 // Fail this decl if a scope it depended on failed. 15763 if (scope.failed()) { 15764 if (sema.owner_func) |owner_func| { 15765 owner_func.state = .dependency_failure; 15766 } else { 15767 sema.owner_decl.analysis = .dependency_failure; 15768 } 15769 return error.AnalysisFail; 15770 } 15771 if (scope.captures.get(inst_data.inst)) |capture| { 15772 break capture; 15773 } 15774 scope = scope.parent.?; 15775 }; 15776 15777 if (capture == .runtime_val and !block.is_typeof and sema.func_index == .none) { 15778 const msg = msg: { 15779 const name = name: { 15780 const file = sema.owner_decl.getFileScope(mod); 15781 const tree = file.getTree(sema.gpa) catch |err| { 15782 // In this case we emit a warning + a less precise source location. 15783 log.warn("unable to load {s}: {s}", .{ 15784 file.sub_file_path, @errorName(err), 15785 }); 15786 break :name null; 15787 }; 15788 const node = sema.owner_decl.relativeToNodeIndex(inst_data.src_node); 15789 const token = tree.nodes.items(.main_token)[node]; 15790 break :name tree.tokenSlice(token); 15791 }; 15792 15793 const msg = if (name) |some| 15794 try sema.errMsg(block, inst_data.src(), "'{s}' not accessible outside function scope", .{some}) 15795 else 15796 try sema.errMsg(block, inst_data.src(), "variable not accessible outside function scope", .{}); 15797 errdefer msg.destroy(sema.gpa); 15798 15799 // TODO add "declared here" note 15800 break :msg msg; 15801 }; 15802 return sema.failWithOwnedErrorMsg(msg); 15803 } 15804 15805 if (capture == .runtime_val and !block.is_typeof and !block.is_comptime and sema.func_index != .none) { 15806 const msg = msg: { 15807 const name = name: { 15808 const file = sema.owner_decl.getFileScope(mod); 15809 const tree = file.getTree(sema.gpa) catch |err| { 15810 // In this case we emit a warning + a less precise source location. 15811 log.warn("unable to load {s}: {s}", .{ 15812 file.sub_file_path, @errorName(err), 15813 }); 15814 break :name null; 15815 }; 15816 const node = sema.owner_decl.relativeToNodeIndex(inst_data.src_node); 15817 const token = tree.nodes.items(.main_token)[node]; 15818 break :name tree.tokenSlice(token); 15819 }; 15820 15821 const msg = if (name) |some| 15822 try sema.errMsg(block, inst_data.src(), "'{s}' not accessible from inner function", .{some}) 15823 else 15824 try sema.errMsg(block, inst_data.src(), "variable not accessible from inner function", .{}); 15825 errdefer msg.destroy(sema.gpa); 15826 15827 try sema.errNote(block, LazySrcLoc.nodeOffset(0), msg, "crossed function definition here", .{}); 15828 15829 // TODO add "declared here" note 15830 break :msg msg; 15831 }; 15832 return sema.failWithOwnedErrorMsg(msg); 15833 } 15834 15835 switch (capture) { 15836 .runtime_val => |ty_ip_index| { 15837 assert(block.is_typeof); 15838 // We need a dummy runtime instruction with the correct type. 15839 return block.addTy(.alloc, ty_ip_index.toType()); 15840 }, 15841 .comptime_val => |val_ip_index| { 15842 const ty = mod.intern_pool.typeOf(val_ip_index).toType(); 15843 return sema.addConstant(ty, val_ip_index.toValue()); 15844 }, 15845 } 15846 } 15847 15848 fn zirRetAddr( 15849 sema: *Sema, 15850 block: *Block, 15851 extended: Zir.Inst.Extended.InstData, 15852 ) CompileError!Air.Inst.Ref { 15853 _ = extended; 15854 if (block.is_comptime) { 15855 // TODO: we could give a meaningful lazy value here. #14938 15856 return sema.addIntUnsigned(Type.usize, 0); 15857 } else { 15858 return block.addNoOp(.ret_addr); 15859 } 15860 } 15861 15862 fn zirFrameAddress( 15863 sema: *Sema, 15864 block: *Block, 15865 extended: Zir.Inst.Extended.InstData, 15866 ) CompileError!Air.Inst.Ref { 15867 const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand)); 15868 try sema.requireRuntimeBlock(block, src, null); 15869 return try block.addNoOp(.frame_addr); 15870 } 15871 15872 fn zirBuiltinSrc( 15873 sema: *Sema, 15874 block: *Block, 15875 extended: Zir.Inst.Extended.InstData, 15876 ) CompileError!Air.Inst.Ref { 15877 const tracy = trace(@src()); 15878 defer tracy.end(); 15879 15880 const mod = sema.mod; 15881 const extra = sema.code.extraData(Zir.Inst.Src, extended.operand).data; 15882 const src = LazySrcLoc.nodeOffset(extra.node); 15883 const func = sema.func orelse return sema.fail(block, src, "@src outside function", .{}); 15884 const fn_owner_decl = mod.declPtr(func.owner_decl); 15885 15886 const func_name_val = blk: { 15887 var anon_decl = try block.startAnonDecl(); 15888 defer anon_decl.deinit(); 15889 const name = mem.span(fn_owner_decl.name); 15890 const new_decl_ty = try mod.arrayType(.{ 15891 .len = name.len, 15892 .child = .u8_type, 15893 .sentinel = .zero_u8, 15894 }); 15895 const new_decl = try anon_decl.finish( 15896 new_decl_ty, 15897 (try mod.intern(.{ .aggregate = .{ 15898 .ty = new_decl_ty.toIntern(), 15899 .storage = .{ .bytes = name }, 15900 } })).toValue(), 15901 0, // default alignment 15902 ); 15903 break :blk try mod.intern(.{ .ptr = .{ 15904 .ty = .slice_const_u8_sentinel_0_type, 15905 .addr = .{ .decl = new_decl }, 15906 .len = (try mod.intValue(Type.usize, name.len)).toIntern(), 15907 } }); 15908 }; 15909 15910 const file_name_val = blk: { 15911 var anon_decl = try block.startAnonDecl(); 15912 defer anon_decl.deinit(); 15913 // The compiler must not call realpath anywhere. 15914 const name = try fn_owner_decl.getFileScope(mod).fullPathZ(anon_decl.arena()); 15915 const new_decl_ty = try mod.arrayType(.{ 15916 .len = name.len, 15917 .child = .u8_type, 15918 .sentinel = .zero_u8, 15919 }); 15920 const new_decl = try anon_decl.finish( 15921 new_decl_ty, 15922 (try mod.intern(.{ .aggregate = .{ 15923 .ty = new_decl_ty.toIntern(), 15924 .storage = .{ .bytes = name }, 15925 } })).toValue(), 15926 0, // default alignment 15927 ); 15928 break :blk try mod.intern(.{ .ptr = .{ 15929 .ty = .slice_const_u8_sentinel_0_type, 15930 .addr = .{ .decl = new_decl }, 15931 .len = (try mod.intValue(Type.usize, name.len)).toIntern(), 15932 } }); 15933 }; 15934 15935 const src_loc_ty = try sema.getBuiltinType("SourceLocation"); 15936 const fields = .{ 15937 // file: [:0]const u8, 15938 file_name_val, 15939 // fn_name: [:0]const u8, 15940 func_name_val, 15941 // line: u32, 15942 try mod.intern(.{ .runtime_value = .{ 15943 .ty = .u32_type, 15944 .val = (try mod.intValue(Type.u32, extra.line + 1)).toIntern(), 15945 } }), 15946 // column: u32, 15947 (try mod.intValue(Type.u32, extra.column + 1)).toIntern(), 15948 }; 15949 return sema.addConstant(src_loc_ty, (try mod.intern(.{ .aggregate = .{ 15950 .ty = src_loc_ty.toIntern(), 15951 .storage = .{ .elems = &fields }, 15952 } })).toValue()); 15953 } 15954 15955 fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 15956 const mod = sema.mod; 15957 const gpa = sema.gpa; 15958 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15959 const src = inst_data.src(); 15960 const ty = try sema.resolveType(block, src, inst_data.operand); 15961 const type_info_ty = try sema.getBuiltinType("Type"); 15962 const type_info_tag_ty = type_info_ty.unionTagType(mod).?; 15963 15964 switch (ty.zigTypeTag(mod)) { 15965 .Type, 15966 .Void, 15967 .Bool, 15968 .NoReturn, 15969 .ComptimeFloat, 15970 .ComptimeInt, 15971 .Undefined, 15972 .Null, 15973 .EnumLiteral, 15974 => |type_info_tag| return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ 15975 .ty = type_info_ty.toIntern(), 15976 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(type_info_tag))).toIntern(), 15977 .val = .void_value, 15978 } })).toValue()), 15979 .Fn => { 15980 // TODO: look into memoizing this result. 15981 var params_anon_decl = try block.startAnonDecl(); 15982 defer params_anon_decl.deinit(); 15983 15984 const fn_info_decl_index = (try sema.namespaceLookup( 15985 block, 15986 src, 15987 type_info_ty.getNamespaceIndex(mod).unwrap().?, 15988 "Fn", 15989 )).?; 15990 try mod.declareDeclDependency(sema.owner_decl_index, fn_info_decl_index); 15991 try sema.ensureDeclAnalyzed(fn_info_decl_index); 15992 const fn_info_decl = mod.declPtr(fn_info_decl_index); 15993 const fn_info_ty = fn_info_decl.val.toType(); 15994 15995 const param_info_decl_index = (try sema.namespaceLookup( 15996 block, 15997 src, 15998 fn_info_ty.getNamespaceIndex(mod).unwrap().?, 15999 "Param", 16000 )).?; 16001 try mod.declareDeclDependency(sema.owner_decl_index, param_info_decl_index); 16002 try sema.ensureDeclAnalyzed(param_info_decl_index); 16003 const param_info_decl = mod.declPtr(param_info_decl_index); 16004 const param_info_ty = param_info_decl.val.toType(); 16005 16006 const param_vals = try sema.arena.alloc(InternPool.Index, mod.typeToFunc(ty).?.param_types.len); 16007 for (param_vals, 0..) |*param_val, i| { 16008 const info = mod.typeToFunc(ty).?; 16009 const param_ty = info.param_types[i]; 16010 const is_generic = param_ty == .generic_poison_type; 16011 const param_ty_val = try mod.intern_pool.get(gpa, .{ .opt = .{ 16012 .ty = try mod.intern_pool.get(gpa, .{ .opt_type = .type_type }), 16013 .val = if (is_generic) .none else param_ty, 16014 } }); 16015 16016 const is_noalias = blk: { 16017 const index = std.math.cast(u5, i) orelse break :blk false; 16018 break :blk @truncate(u1, info.noalias_bits >> index) != 0; 16019 }; 16020 16021 const param_fields = .{ 16022 // is_generic: bool, 16023 Value.makeBool(is_generic).toIntern(), 16024 // is_noalias: bool, 16025 Value.makeBool(is_noalias).toIntern(), 16026 // type: ?type, 16027 param_ty_val, 16028 }; 16029 param_val.* = try mod.intern(.{ .aggregate = .{ 16030 .ty = param_info_ty.toIntern(), 16031 .storage = .{ .elems = ¶m_fields }, 16032 } }); 16033 } 16034 16035 const args_val = v: { 16036 const new_decl_ty = try mod.arrayType(.{ 16037 .len = param_vals.len, 16038 .child = param_info_ty.toIntern(), 16039 }); 16040 const new_decl = try params_anon_decl.finish( 16041 new_decl_ty, 16042 (try mod.intern(.{ .aggregate = .{ 16043 .ty = new_decl_ty.toIntern(), 16044 .storage = .{ .elems = param_vals }, 16045 } })).toValue(), 16046 0, // default alignment 16047 ); 16048 break :v try mod.intern(.{ .ptr = .{ 16049 .ty = (try mod.ptrType(.{ 16050 .child = param_info_ty.toIntern(), 16051 .flags = .{ 16052 .size = .Slice, 16053 .is_const = true, 16054 }, 16055 })).toIntern(), 16056 .addr = .{ .decl = new_decl }, 16057 .len = (try mod.intValue(Type.usize, param_vals.len)).toIntern(), 16058 } }); 16059 }; 16060 16061 const info = mod.typeToFunc(ty).?; 16062 const ret_ty_opt = try mod.intern(.{ .opt = .{ 16063 .ty = try mod.intern_pool.get(gpa, .{ .opt_type = .type_type }), 16064 .val = if (info.return_type == .generic_poison_type) .none else info.return_type, 16065 } }); 16066 16067 const callconv_ty = try sema.getBuiltinType("CallingConvention"); 16068 16069 const field_values = .{ 16070 // calling_convention: CallingConvention, 16071 (try mod.enumValueFieldIndex(callconv_ty, @enumToInt(info.cc))).toIntern(), 16072 // alignment: comptime_int, 16073 (try mod.intValue(Type.comptime_int, ty.abiAlignment(mod))).toIntern(), 16074 // is_generic: bool, 16075 Value.makeBool(info.is_generic).toIntern(), 16076 // is_var_args: bool, 16077 Value.makeBool(info.is_var_args).toIntern(), 16078 // return_type: ?type, 16079 ret_ty_opt, 16080 // args: []const Fn.Param, 16081 args_val, 16082 }; 16083 return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ 16084 .ty = type_info_ty.toIntern(), 16085 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Fn))).toIntern(), 16086 .val = try mod.intern(.{ .aggregate = .{ 16087 .ty = fn_info_ty.toIntern(), 16088 .storage = .{ .elems = &field_values }, 16089 } }), 16090 } })).toValue()); 16091 }, 16092 .Int => { 16093 const int_info_decl_index = (try sema.namespaceLookup( 16094 block, 16095 src, 16096 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16097 "Int", 16098 )).?; 16099 try mod.declareDeclDependency(sema.owner_decl_index, int_info_decl_index); 16100 try sema.ensureDeclAnalyzed(int_info_decl_index); 16101 const int_info_decl = mod.declPtr(int_info_decl_index); 16102 const int_info_ty = int_info_decl.val.toType(); 16103 16104 const signedness_ty = try sema.getBuiltinType("Signedness"); 16105 const info = ty.intInfo(mod); 16106 const field_values = .{ 16107 // signedness: Signedness, 16108 try (try mod.enumValueFieldIndex(signedness_ty, @enumToInt(info.signedness))).intern(signedness_ty, mod), 16109 // bits: u16, 16110 (try mod.intValue(Type.u16, info.bits)).toIntern(), 16111 }; 16112 return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ 16113 .ty = type_info_ty.toIntern(), 16114 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Int))).toIntern(), 16115 .val = try mod.intern(.{ .aggregate = .{ 16116 .ty = int_info_ty.toIntern(), 16117 .storage = .{ .elems = &field_values }, 16118 } }), 16119 } })).toValue()); 16120 }, 16121 .Float => { 16122 const float_info_decl_index = (try sema.namespaceLookup( 16123 block, 16124 src, 16125 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16126 "Float", 16127 )).?; 16128 try mod.declareDeclDependency(sema.owner_decl_index, float_info_decl_index); 16129 try sema.ensureDeclAnalyzed(float_info_decl_index); 16130 const float_info_decl = mod.declPtr(float_info_decl_index); 16131 const float_info_ty = float_info_decl.val.toType(); 16132 16133 const field_vals = .{ 16134 // bits: u16, 16135 (try mod.intValue(Type.u16, ty.bitSize(mod))).toIntern(), 16136 }; 16137 return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ 16138 .ty = type_info_ty.toIntern(), 16139 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Float))).toIntern(), 16140 .val = try mod.intern(.{ .aggregate = .{ 16141 .ty = float_info_ty.toIntern(), 16142 .storage = .{ .elems = &field_vals }, 16143 } }), 16144 } })).toValue()); 16145 }, 16146 .Pointer => { 16147 const info = ty.ptrInfo(mod); 16148 const alignment = if (info.@"align" != 0) 16149 try mod.intValue(Type.comptime_int, info.@"align") 16150 else 16151 try info.pointee_type.lazyAbiAlignment(mod); 16152 16153 const addrspace_ty = try sema.getBuiltinType("AddressSpace"); 16154 const pointer_ty = t: { 16155 const decl_index = (try sema.namespaceLookup( 16156 block, 16157 src, 16158 (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?, 16159 "Pointer", 16160 )).?; 16161 try mod.declareDeclDependency(sema.owner_decl_index, decl_index); 16162 try sema.ensureDeclAnalyzed(decl_index); 16163 const decl = mod.declPtr(decl_index); 16164 break :t decl.val.toType(); 16165 }; 16166 const ptr_size_ty = t: { 16167 const decl_index = (try sema.namespaceLookup( 16168 block, 16169 src, 16170 pointer_ty.getNamespaceIndex(mod).unwrap().?, 16171 "Size", 16172 )).?; 16173 try mod.declareDeclDependency(sema.owner_decl_index, decl_index); 16174 try sema.ensureDeclAnalyzed(decl_index); 16175 const decl = mod.declPtr(decl_index); 16176 break :t decl.val.toType(); 16177 }; 16178 16179 const field_values = .{ 16180 // size: Size, 16181 try (try mod.enumValueFieldIndex(ptr_size_ty, @enumToInt(info.size))).intern(ptr_size_ty, mod), 16182 // is_const: bool, 16183 Value.makeBool(!info.mutable).toIntern(), 16184 // is_volatile: bool, 16185 Value.makeBool(info.@"volatile").toIntern(), 16186 // alignment: comptime_int, 16187 alignment.toIntern(), 16188 // address_space: AddressSpace 16189 try (try mod.enumValueFieldIndex(addrspace_ty, @enumToInt(info.@"addrspace"))).intern(addrspace_ty, mod), 16190 // child: type, 16191 info.pointee_type.toIntern(), 16192 // is_allowzero: bool, 16193 Value.makeBool(info.@"allowzero").toIntern(), 16194 // sentinel: ?*const anyopaque, 16195 (try sema.optRefValue(block, info.pointee_type, info.sentinel)).toIntern(), 16196 }; 16197 return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ 16198 .ty = type_info_ty.toIntern(), 16199 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Pointer))).toIntern(), 16200 .val = try mod.intern(.{ .aggregate = .{ 16201 .ty = pointer_ty.toIntern(), 16202 .storage = .{ .elems = &field_values }, 16203 } }), 16204 } })).toValue()); 16205 }, 16206 .Array => { 16207 const array_field_ty = t: { 16208 const array_field_ty_decl_index = (try sema.namespaceLookup( 16209 block, 16210 src, 16211 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16212 "Array", 16213 )).?; 16214 try mod.declareDeclDependency(sema.owner_decl_index, array_field_ty_decl_index); 16215 try sema.ensureDeclAnalyzed(array_field_ty_decl_index); 16216 const array_field_ty_decl = mod.declPtr(array_field_ty_decl_index); 16217 break :t array_field_ty_decl.val.toType(); 16218 }; 16219 16220 const info = ty.arrayInfo(mod); 16221 const field_values = .{ 16222 // len: comptime_int, 16223 (try mod.intValue(Type.comptime_int, info.len)).toIntern(), 16224 // child: type, 16225 info.elem_type.toIntern(), 16226 // sentinel: ?*const anyopaque, 16227 (try sema.optRefValue(block, info.elem_type, info.sentinel)).toIntern(), 16228 }; 16229 return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ 16230 .ty = type_info_ty.toIntern(), 16231 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Array))).toIntern(), 16232 .val = try mod.intern(.{ .aggregate = .{ 16233 .ty = array_field_ty.toIntern(), 16234 .storage = .{ .elems = &field_values }, 16235 } }), 16236 } })).toValue()); 16237 }, 16238 .Vector => { 16239 const vector_field_ty = t: { 16240 const vector_field_ty_decl_index = (try sema.namespaceLookup( 16241 block, 16242 src, 16243 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16244 "Vector", 16245 )).?; 16246 try mod.declareDeclDependency(sema.owner_decl_index, vector_field_ty_decl_index); 16247 try sema.ensureDeclAnalyzed(vector_field_ty_decl_index); 16248 const vector_field_ty_decl = mod.declPtr(vector_field_ty_decl_index); 16249 break :t vector_field_ty_decl.val.toType(); 16250 }; 16251 16252 const info = ty.arrayInfo(mod); 16253 const field_values = .{ 16254 // len: comptime_int, 16255 (try mod.intValue(Type.comptime_int, info.len)).toIntern(), 16256 // child: type, 16257 info.elem_type.toIntern(), 16258 }; 16259 return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ 16260 .ty = type_info_ty.toIntern(), 16261 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Vector))).toIntern(), 16262 .val = try mod.intern(.{ .aggregate = .{ 16263 .ty = vector_field_ty.toIntern(), 16264 .storage = .{ .elems = &field_values }, 16265 } }), 16266 } })).toValue()); 16267 }, 16268 .Optional => { 16269 const optional_field_ty = t: { 16270 const optional_field_ty_decl_index = (try sema.namespaceLookup( 16271 block, 16272 src, 16273 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16274 "Optional", 16275 )).?; 16276 try mod.declareDeclDependency(sema.owner_decl_index, optional_field_ty_decl_index); 16277 try sema.ensureDeclAnalyzed(optional_field_ty_decl_index); 16278 const optional_field_ty_decl = mod.declPtr(optional_field_ty_decl_index); 16279 break :t optional_field_ty_decl.val.toType(); 16280 }; 16281 16282 const field_values = .{ 16283 // child: type, 16284 ty.optionalChild(mod).toIntern(), 16285 }; 16286 return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ 16287 .ty = type_info_ty.toIntern(), 16288 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Optional))).toIntern(), 16289 .val = try mod.intern(.{ .aggregate = .{ 16290 .ty = optional_field_ty.toIntern(), 16291 .storage = .{ .elems = &field_values }, 16292 } }), 16293 } })).toValue()); 16294 }, 16295 .ErrorSet => { 16296 var fields_anon_decl = try block.startAnonDecl(); 16297 defer fields_anon_decl.deinit(); 16298 16299 // Get the Error type 16300 const error_field_ty = t: { 16301 const set_field_ty_decl_index = (try sema.namespaceLookup( 16302 block, 16303 src, 16304 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16305 "Error", 16306 )).?; 16307 try mod.declareDeclDependency(sema.owner_decl_index, set_field_ty_decl_index); 16308 try sema.ensureDeclAnalyzed(set_field_ty_decl_index); 16309 const set_field_ty_decl = mod.declPtr(set_field_ty_decl_index); 16310 break :t set_field_ty_decl.val.toType(); 16311 }; 16312 16313 try sema.queueFullTypeResolution(error_field_ty); 16314 16315 // If the error set is inferred it must be resolved at this point 16316 try sema.resolveInferredErrorSetTy(block, src, ty); 16317 16318 // Build our list of Error values 16319 // Optional value is only null if anyerror 16320 // Value can be zero-length slice otherwise 16321 const error_field_vals = if (ty.isAnyError(mod)) null else blk: { 16322 const names = ty.errorSetNames(mod); 16323 const vals = try sema.arena.alloc(InternPool.Index, names.len); 16324 for (vals, names) |*field_val, name_ip| { 16325 const name = mod.intern_pool.stringToSlice(name_ip); 16326 const name_val = v: { 16327 var anon_decl = try block.startAnonDecl(); 16328 defer anon_decl.deinit(); 16329 const new_decl_ty = try mod.arrayType(.{ 16330 .len = name.len, 16331 .child = .u8_type, 16332 }); 16333 const new_decl = try anon_decl.finish( 16334 new_decl_ty, 16335 (try mod.intern(.{ .aggregate = .{ 16336 .ty = new_decl_ty.toIntern(), 16337 .storage = .{ .bytes = name }, 16338 } })).toValue(), 16339 0, // default alignment 16340 ); 16341 break :v try mod.intern(.{ .ptr = .{ 16342 .ty = .slice_const_u8_type, 16343 .addr = .{ .decl = new_decl }, 16344 .len = (try mod.intValue(Type.usize, name.len)).toIntern(), 16345 } }); 16346 }; 16347 16348 const error_field_fields = .{ 16349 // name: []const u8, 16350 name_val, 16351 }; 16352 field_val.* = try mod.intern(.{ .aggregate = .{ 16353 .ty = error_field_ty.toIntern(), 16354 .storage = .{ .elems = &error_field_fields }, 16355 } }); 16356 } 16357 16358 break :blk vals; 16359 }; 16360 16361 // Build our ?[]const Error value 16362 const slice_errors_ty = try mod.ptrType(.{ 16363 .child = error_field_ty.toIntern(), 16364 .flags = .{ 16365 .size = .Slice, 16366 .is_const = true, 16367 }, 16368 }); 16369 const opt_slice_errors_ty = try mod.optionalType(slice_errors_ty.toIntern()); 16370 const errors_payload_val: InternPool.Index = if (error_field_vals) |vals| v: { 16371 const array_errors_ty = try mod.arrayType(.{ 16372 .len = vals.len, 16373 .child = error_field_ty.toIntern(), 16374 .sentinel = .none, 16375 }); 16376 const new_decl = try fields_anon_decl.finish( 16377 array_errors_ty, 16378 (try mod.intern(.{ .aggregate = .{ 16379 .ty = array_errors_ty.toIntern(), 16380 .storage = .{ .elems = vals }, 16381 } })).toValue(), 16382 0, // default alignment 16383 ); 16384 break :v try mod.intern(.{ .ptr = .{ 16385 .ty = slice_errors_ty.toIntern(), 16386 .addr = .{ .decl = new_decl }, 16387 .len = (try mod.intValue(Type.usize, vals.len)).toIntern(), 16388 } }); 16389 } else .none; 16390 const errors_val = try mod.intern(.{ .opt = .{ 16391 .ty = opt_slice_errors_ty.toIntern(), 16392 .val = errors_payload_val, 16393 } }); 16394 16395 // Construct Type{ .ErrorSet = errors_val } 16396 return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ 16397 .ty = type_info_ty.toIntern(), 16398 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ErrorSet))).toIntern(), 16399 .val = errors_val, 16400 } })).toValue()); 16401 }, 16402 .ErrorUnion => { 16403 const error_union_field_ty = t: { 16404 const error_union_field_ty_decl_index = (try sema.namespaceLookup( 16405 block, 16406 src, 16407 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16408 "ErrorUnion", 16409 )).?; 16410 try mod.declareDeclDependency(sema.owner_decl_index, error_union_field_ty_decl_index); 16411 try sema.ensureDeclAnalyzed(error_union_field_ty_decl_index); 16412 const error_union_field_ty_decl = mod.declPtr(error_union_field_ty_decl_index); 16413 break :t error_union_field_ty_decl.val.toType(); 16414 }; 16415 16416 const field_values = .{ 16417 // error_set: type, 16418 ty.errorUnionSet(mod).toIntern(), 16419 // payload: type, 16420 ty.errorUnionPayload(mod).toIntern(), 16421 }; 16422 return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ 16423 .ty = type_info_ty.toIntern(), 16424 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ErrorUnion))).toIntern(), 16425 .val = try mod.intern(.{ .aggregate = .{ 16426 .ty = error_union_field_ty.toIntern(), 16427 .storage = .{ .elems = &field_values }, 16428 } }), 16429 } })).toValue()); 16430 }, 16431 .Enum => { 16432 // TODO: look into memoizing this result. 16433 const enum_type = mod.intern_pool.indexToKey(ty.toIntern()).enum_type; 16434 16435 const is_exhaustive = Value.makeBool(enum_type.tag_mode != .nonexhaustive); 16436 16437 var fields_anon_decl = try block.startAnonDecl(); 16438 defer fields_anon_decl.deinit(); 16439 16440 const enum_field_ty = t: { 16441 const enum_field_ty_decl_index = (try sema.namespaceLookup( 16442 block, 16443 src, 16444 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16445 "EnumField", 16446 )).?; 16447 try mod.declareDeclDependency(sema.owner_decl_index, enum_field_ty_decl_index); 16448 try sema.ensureDeclAnalyzed(enum_field_ty_decl_index); 16449 const enum_field_ty_decl = mod.declPtr(enum_field_ty_decl_index); 16450 break :t enum_field_ty_decl.val.toType(); 16451 }; 16452 16453 const enum_field_vals = try sema.arena.alloc(InternPool.Index, enum_type.names.len); 16454 for (enum_field_vals, 0..) |*field_val, i| { 16455 const name_ip = mod.intern_pool.indexToKey(ty.toIntern()).enum_type.names[i]; 16456 const name = mod.intern_pool.stringToSlice(name_ip); 16457 const name_val = v: { 16458 var anon_decl = try block.startAnonDecl(); 16459 defer anon_decl.deinit(); 16460 const new_decl_ty = try mod.arrayType(.{ 16461 .len = name.len, 16462 .child = .u8_type, 16463 }); 16464 const new_decl = try anon_decl.finish( 16465 new_decl_ty, 16466 (try mod.intern(.{ .aggregate = .{ 16467 .ty = new_decl_ty.toIntern(), 16468 .storage = .{ .bytes = name }, 16469 } })).toValue(), 16470 0, // default alignment 16471 ); 16472 break :v try mod.intern(.{ .ptr = .{ 16473 .ty = .slice_const_u8_type, 16474 .addr = .{ .decl = new_decl }, 16475 .len = (try mod.intValue(Type.usize, name.len)).toIntern(), 16476 } }); 16477 }; 16478 16479 const enum_field_fields = .{ 16480 // name: []const u8, 16481 name_val, 16482 // value: comptime_int, 16483 (try mod.intValue(Type.comptime_int, i)).toIntern(), 16484 }; 16485 field_val.* = try mod.intern(.{ .aggregate = .{ 16486 .ty = enum_field_ty.toIntern(), 16487 .storage = .{ .elems = &enum_field_fields }, 16488 } }); 16489 } 16490 16491 const fields_val = v: { 16492 const fields_array_ty = try mod.arrayType(.{ 16493 .len = enum_field_vals.len, 16494 .child = enum_field_ty.toIntern(), 16495 .sentinel = .none, 16496 }); 16497 const new_decl = try fields_anon_decl.finish( 16498 fields_array_ty, 16499 (try mod.intern(.{ .aggregate = .{ 16500 .ty = fields_array_ty.toIntern(), 16501 .storage = .{ .elems = enum_field_vals }, 16502 } })).toValue(), 16503 0, // default alignment 16504 ); 16505 break :v try mod.intern(.{ .ptr = .{ 16506 .ty = (try mod.ptrType(.{ 16507 .child = enum_field_ty.toIntern(), 16508 .flags = .{ 16509 .size = .Slice, 16510 .is_const = true, 16511 }, 16512 })).toIntern(), 16513 .addr = .{ .decl = new_decl }, 16514 .len = (try mod.intValue(Type.usize, enum_field_vals.len)).toIntern(), 16515 } }); 16516 }; 16517 16518 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, enum_type.namespace); 16519 16520 const type_enum_ty = t: { 16521 const type_enum_ty_decl_index = (try sema.namespaceLookup( 16522 block, 16523 src, 16524 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16525 "Enum", 16526 )).?; 16527 try mod.declareDeclDependency(sema.owner_decl_index, type_enum_ty_decl_index); 16528 try sema.ensureDeclAnalyzed(type_enum_ty_decl_index); 16529 const type_enum_ty_decl = mod.declPtr(type_enum_ty_decl_index); 16530 break :t type_enum_ty_decl.val.toType(); 16531 }; 16532 16533 const field_values = .{ 16534 // tag_type: type, 16535 enum_type.tag_ty, 16536 // fields: []const EnumField, 16537 fields_val, 16538 // decls: []const Declaration, 16539 decls_val, 16540 // is_exhaustive: bool, 16541 is_exhaustive.toIntern(), 16542 }; 16543 return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ 16544 .ty = type_info_ty.toIntern(), 16545 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Enum))).toIntern(), 16546 .val = try mod.intern(.{ .aggregate = .{ 16547 .ty = type_enum_ty.toIntern(), 16548 .storage = .{ .elems = &field_values }, 16549 } }), 16550 } })).toValue()); 16551 }, 16552 .Union => { 16553 // TODO: look into memoizing this result. 16554 16555 var fields_anon_decl = try block.startAnonDecl(); 16556 defer fields_anon_decl.deinit(); 16557 16558 const type_union_ty = t: { 16559 const type_union_ty_decl_index = (try sema.namespaceLookup( 16560 block, 16561 src, 16562 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16563 "Union", 16564 )).?; 16565 try mod.declareDeclDependency(sema.owner_decl_index, type_union_ty_decl_index); 16566 try sema.ensureDeclAnalyzed(type_union_ty_decl_index); 16567 const type_union_ty_decl = mod.declPtr(type_union_ty_decl_index); 16568 break :t type_union_ty_decl.val.toType(); 16569 }; 16570 16571 const union_field_ty = t: { 16572 const union_field_ty_decl_index = (try sema.namespaceLookup( 16573 block, 16574 src, 16575 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16576 "UnionField", 16577 )).?; 16578 try mod.declareDeclDependency(sema.owner_decl_index, union_field_ty_decl_index); 16579 try sema.ensureDeclAnalyzed(union_field_ty_decl_index); 16580 const union_field_ty_decl = mod.declPtr(union_field_ty_decl_index); 16581 break :t union_field_ty_decl.val.toType(); 16582 }; 16583 16584 const union_ty = try sema.resolveTypeFields(ty); 16585 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout 16586 const layout = union_ty.containerLayout(mod); 16587 16588 const union_fields = union_ty.unionFields(mod); 16589 const union_field_vals = try gpa.alloc(InternPool.Index, union_fields.count()); 16590 defer gpa.free(union_field_vals); 16591 16592 for (union_field_vals, 0..) |*field_val, i| { 16593 const field = union_fields.values()[i]; 16594 const name = union_fields.keys()[i]; 16595 const name_val = v: { 16596 var anon_decl = try block.startAnonDecl(); 16597 defer anon_decl.deinit(); 16598 const new_decl_ty = try mod.arrayType(.{ 16599 .len = name.len, 16600 .child = .u8_type, 16601 }); 16602 const new_decl = try anon_decl.finish( 16603 new_decl_ty, 16604 (try mod.intern(.{ .aggregate = .{ 16605 .ty = new_decl_ty.toIntern(), 16606 .storage = .{ .bytes = name }, 16607 } })).toValue(), 16608 0, // default alignment 16609 ); 16610 break :v try mod.intern(.{ .ptr = .{ 16611 .ty = .slice_const_u8_type, 16612 .addr = .{ .decl = new_decl }, 16613 .len = (try mod.intValue(Type.usize, name.len)).toIntern(), 16614 } }); 16615 }; 16616 16617 const alignment = switch (layout) { 16618 .Auto, .Extern => try sema.unionFieldAlignment(field), 16619 .Packed => 0, 16620 }; 16621 16622 const union_field_fields = .{ 16623 // name: []const u8, 16624 name_val, 16625 // type: type, 16626 field.ty.toIntern(), 16627 // alignment: comptime_int, 16628 (try mod.intValue(Type.comptime_int, alignment)).toIntern(), 16629 }; 16630 field_val.* = try mod.intern(.{ .aggregate = .{ 16631 .ty = union_field_ty.toIntern(), 16632 .storage = .{ .elems = &union_field_fields }, 16633 } }); 16634 } 16635 16636 const fields_val = v: { 16637 const array_fields_ty = try mod.arrayType(.{ 16638 .len = union_field_vals.len, 16639 .child = union_field_ty.toIntern(), 16640 .sentinel = .none, 16641 }); 16642 const new_decl = try fields_anon_decl.finish( 16643 array_fields_ty, 16644 (try mod.intern(.{ .aggregate = .{ 16645 .ty = array_fields_ty.toIntern(), 16646 .storage = .{ .elems = union_field_vals }, 16647 } })).toValue(), 16648 0, // default alignment 16649 ); 16650 break :v try mod.intern(.{ .ptr = .{ 16651 .ty = (try mod.ptrType(.{ 16652 .child = union_field_ty.toIntern(), 16653 .flags = .{ 16654 .size = .Slice, 16655 .is_const = true, 16656 }, 16657 })).toIntern(), 16658 .addr = .{ .decl = new_decl }, 16659 .len = (try mod.intValue(Type.usize, union_field_vals.len)).toIntern(), 16660 } }); 16661 }; 16662 16663 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespaceIndex(mod)); 16664 16665 const enum_tag_ty_val = try mod.intern(.{ .opt = .{ 16666 .ty = (try mod.optionalType(.type_type)).toIntern(), 16667 .val = if (union_ty.unionTagType(mod)) |tag_ty| tag_ty.toIntern() else .none, 16668 } }); 16669 16670 const container_layout_ty = t: { 16671 const decl_index = (try sema.namespaceLookup( 16672 block, 16673 src, 16674 (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?, 16675 "ContainerLayout", 16676 )).?; 16677 try mod.declareDeclDependency(sema.owner_decl_index, decl_index); 16678 try sema.ensureDeclAnalyzed(decl_index); 16679 const decl = mod.declPtr(decl_index); 16680 break :t decl.val.toType(); 16681 }; 16682 16683 const field_values = .{ 16684 // layout: ContainerLayout, 16685 (try mod.enumValueFieldIndex(container_layout_ty, @enumToInt(layout))).toIntern(), 16686 16687 // tag_type: ?type, 16688 enum_tag_ty_val, 16689 // fields: []const UnionField, 16690 fields_val, 16691 // decls: []const Declaration, 16692 decls_val, 16693 }; 16694 return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ 16695 .ty = type_info_ty.toIntern(), 16696 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Union))).toIntern(), 16697 .val = try mod.intern(.{ .aggregate = .{ 16698 .ty = type_union_ty.toIntern(), 16699 .storage = .{ .elems = &field_values }, 16700 } }), 16701 } })).toValue()); 16702 }, 16703 .Struct => { 16704 // TODO: look into memoizing this result. 16705 16706 var fields_anon_decl = try block.startAnonDecl(); 16707 defer fields_anon_decl.deinit(); 16708 16709 const type_struct_ty = t: { 16710 const type_struct_ty_decl_index = (try sema.namespaceLookup( 16711 block, 16712 src, 16713 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16714 "Struct", 16715 )).?; 16716 try mod.declareDeclDependency(sema.owner_decl_index, type_struct_ty_decl_index); 16717 try sema.ensureDeclAnalyzed(type_struct_ty_decl_index); 16718 const type_struct_ty_decl = mod.declPtr(type_struct_ty_decl_index); 16719 break :t type_struct_ty_decl.val.toType(); 16720 }; 16721 16722 const struct_field_ty = t: { 16723 const struct_field_ty_decl_index = (try sema.namespaceLookup( 16724 block, 16725 src, 16726 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16727 "StructField", 16728 )).?; 16729 try mod.declareDeclDependency(sema.owner_decl_index, struct_field_ty_decl_index); 16730 try sema.ensureDeclAnalyzed(struct_field_ty_decl_index); 16731 const struct_field_ty_decl = mod.declPtr(struct_field_ty_decl_index); 16732 break :t struct_field_ty_decl.val.toType(); 16733 }; 16734 16735 const struct_ty = try sema.resolveTypeFields(ty); 16736 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout 16737 const layout = struct_ty.containerLayout(mod); 16738 16739 var struct_field_vals: []InternPool.Index = &.{}; 16740 defer gpa.free(struct_field_vals); 16741 fv: { 16742 const struct_type = switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { 16743 .anon_struct_type => |tuple| { 16744 struct_field_vals = try gpa.alloc(InternPool.Index, tuple.types.len); 16745 for (struct_field_vals, 0..) |*struct_field_val, i| { 16746 const anon_struct_type = mod.intern_pool.indexToKey(struct_ty.toIntern()).anon_struct_type; 16747 const field_ty = anon_struct_type.types[i]; 16748 const field_val = anon_struct_type.values[i]; 16749 const name_val = v: { 16750 var anon_decl = try block.startAnonDecl(); 16751 defer anon_decl.deinit(); 16752 const bytes = if (tuple.names.len != 0) 16753 // https://github.com/ziglang/zig/issues/15709 16754 @as([]const u8, mod.intern_pool.stringToSlice(tuple.names[i])) 16755 else 16756 try std.fmt.allocPrint(sema.arena, "{d}", .{i}); 16757 const new_decl_ty = try mod.arrayType(.{ 16758 .len = bytes.len, 16759 .child = .u8_type, 16760 }); 16761 const new_decl = try anon_decl.finish( 16762 new_decl_ty, 16763 (try mod.intern(.{ .aggregate = .{ 16764 .ty = new_decl_ty.toIntern(), 16765 .storage = .{ .bytes = bytes }, 16766 } })).toValue(), 16767 0, // default alignment 16768 ); 16769 break :v try mod.intern(.{ .ptr = .{ 16770 .ty = .slice_const_u8_type, 16771 .addr = .{ .decl = new_decl }, 16772 .len = (try mod.intValue(Type.usize, bytes.len)).toIntern(), 16773 } }); 16774 }; 16775 16776 const is_comptime = field_val != .none; 16777 const opt_default_val = if (is_comptime) field_val.toValue() else null; 16778 const default_val_ptr = try sema.optRefValue(block, field_ty.toType(), opt_default_val); 16779 const struct_field_fields = .{ 16780 // name: []const u8, 16781 name_val, 16782 // type: type, 16783 field_ty, 16784 // default_value: ?*const anyopaque, 16785 default_val_ptr.toIntern(), 16786 // is_comptime: bool, 16787 Value.makeBool(is_comptime).toIntern(), 16788 // alignment: comptime_int, 16789 (try mod.intValue(Type.comptime_int, field_ty.toType().abiAlignment(mod))).toIntern(), 16790 }; 16791 struct_field_val.* = try mod.intern(.{ .aggregate = .{ 16792 .ty = struct_field_ty.toIntern(), 16793 .storage = .{ .elems = &struct_field_fields }, 16794 } }); 16795 } 16796 break :fv; 16797 }, 16798 .struct_type => |s| s, 16799 else => unreachable, 16800 }; 16801 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :fv; 16802 struct_field_vals = try gpa.alloc(InternPool.Index, struct_obj.fields.count()); 16803 16804 for ( 16805 struct_field_vals, 16806 struct_obj.fields.keys(), 16807 struct_obj.fields.values(), 16808 ) |*field_val, name, field| { 16809 const name_val = v: { 16810 var anon_decl = try block.startAnonDecl(); 16811 defer anon_decl.deinit(); 16812 const new_decl_ty = try mod.arrayType(.{ 16813 .len = name.len, 16814 .child = .u8_type, 16815 }); 16816 const new_decl = try anon_decl.finish( 16817 new_decl_ty, 16818 (try mod.intern(.{ .aggregate = .{ 16819 .ty = new_decl_ty.toIntern(), 16820 .storage = .{ .bytes = name }, 16821 } })).toValue(), 16822 0, // default alignment 16823 ); 16824 break :v try mod.intern(.{ .ptr = .{ 16825 .ty = .slice_const_u8_type, 16826 .addr = .{ .decl = new_decl }, 16827 .len = (try mod.intValue(Type.usize, name.len)).toIntern(), 16828 } }); 16829 }; 16830 16831 const opt_default_val = if (field.default_val.toIntern() == .unreachable_value) 16832 null 16833 else 16834 field.default_val; 16835 const default_val_ptr = try sema.optRefValue(block, field.ty, opt_default_val); 16836 const alignment = field.alignment(mod, layout); 16837 16838 const struct_field_fields = .{ 16839 // name: []const u8, 16840 name_val, 16841 // type: type, 16842 field.ty.toIntern(), 16843 // default_value: ?*const anyopaque, 16844 default_val_ptr.toIntern(), 16845 // is_comptime: bool, 16846 Value.makeBool(field.is_comptime).toIntern(), 16847 // alignment: comptime_int, 16848 (try mod.intValue(Type.comptime_int, alignment)).toIntern(), 16849 }; 16850 field_val.* = try mod.intern(.{ .aggregate = .{ 16851 .ty = struct_field_ty.toIntern(), 16852 .storage = .{ .elems = &struct_field_fields }, 16853 } }); 16854 } 16855 } 16856 16857 const fields_val = v: { 16858 const array_fields_ty = try mod.arrayType(.{ 16859 .len = struct_field_vals.len, 16860 .child = struct_field_ty.toIntern(), 16861 .sentinel = .none, 16862 }); 16863 const new_decl = try fields_anon_decl.finish( 16864 array_fields_ty, 16865 (try mod.intern(.{ .aggregate = .{ 16866 .ty = array_fields_ty.toIntern(), 16867 .storage = .{ .elems = struct_field_vals }, 16868 } })).toValue(), 16869 0, // default alignment 16870 ); 16871 break :v try mod.intern(.{ .ptr = .{ 16872 .ty = (try mod.ptrType(.{ 16873 .child = struct_field_ty.toIntern(), 16874 .flags = .{ 16875 .size = .Slice, 16876 .is_const = true, 16877 }, 16878 })).toIntern(), 16879 .addr = .{ .decl = new_decl }, 16880 .len = (try mod.intValue(Type.usize, struct_field_vals.len)).toIntern(), 16881 } }); 16882 }; 16883 16884 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespaceIndex(mod)); 16885 16886 const backing_integer_val = try mod.intern(.{ .opt = .{ 16887 .ty = (try mod.optionalType(.type_type)).toIntern(), 16888 .val = if (layout == .Packed) val: { 16889 const struct_obj = mod.typeToStruct(struct_ty).?; 16890 assert(struct_obj.haveLayout()); 16891 assert(struct_obj.backing_int_ty.isInt(mod)); 16892 break :val struct_obj.backing_int_ty.toIntern(); 16893 } else .none, 16894 } }); 16895 16896 const container_layout_ty = t: { 16897 const decl_index = (try sema.namespaceLookup( 16898 block, 16899 src, 16900 (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?, 16901 "ContainerLayout", 16902 )).?; 16903 try mod.declareDeclDependency(sema.owner_decl_index, decl_index); 16904 try sema.ensureDeclAnalyzed(decl_index); 16905 const decl = mod.declPtr(decl_index); 16906 break :t decl.val.toType(); 16907 }; 16908 16909 const field_values = [_]InternPool.Index{ 16910 // layout: ContainerLayout, 16911 (try mod.enumValueFieldIndex(container_layout_ty, @enumToInt(layout))).toIntern(), 16912 // backing_integer: ?type, 16913 backing_integer_val, 16914 // fields: []const StructField, 16915 fields_val, 16916 // decls: []const Declaration, 16917 decls_val, 16918 // is_tuple: bool, 16919 Value.makeBool(struct_ty.isTuple(mod)).toIntern(), 16920 }; 16921 return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ 16922 .ty = type_info_ty.toIntern(), 16923 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Struct))).toIntern(), 16924 .val = try mod.intern(.{ .aggregate = .{ 16925 .ty = type_struct_ty.toIntern(), 16926 .storage = .{ .elems = &field_values }, 16927 } }), 16928 } })).toValue()); 16929 }, 16930 .Opaque => { 16931 // TODO: look into memoizing this result. 16932 16933 const type_opaque_ty = t: { 16934 const type_opaque_ty_decl_index = (try sema.namespaceLookup( 16935 block, 16936 src, 16937 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16938 "Opaque", 16939 )).?; 16940 try mod.declareDeclDependency(sema.owner_decl_index, type_opaque_ty_decl_index); 16941 try sema.ensureDeclAnalyzed(type_opaque_ty_decl_index); 16942 const type_opaque_ty_decl = mod.declPtr(type_opaque_ty_decl_index); 16943 break :t type_opaque_ty_decl.val.toType(); 16944 }; 16945 16946 const opaque_ty = try sema.resolveTypeFields(ty); 16947 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespaceIndex(mod)); 16948 16949 const field_values = .{ 16950 // decls: []const Declaration, 16951 decls_val, 16952 }; 16953 return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ 16954 .ty = type_info_ty.toIntern(), 16955 .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Opaque))).toIntern(), 16956 .val = try mod.intern(.{ .aggregate = .{ 16957 .ty = type_opaque_ty.toIntern(), 16958 .storage = .{ .elems = &field_values }, 16959 } }), 16960 } })).toValue()); 16961 }, 16962 .Frame => return sema.failWithUseOfAsync(block, src), 16963 .AnyFrame => return sema.failWithUseOfAsync(block, src), 16964 } 16965 } 16966 16967 fn typeInfoDecls( 16968 sema: *Sema, 16969 block: *Block, 16970 src: LazySrcLoc, 16971 type_info_ty: Type, 16972 opt_namespace: Module.Namespace.OptionalIndex, 16973 ) CompileError!InternPool.Index { 16974 const mod = sema.mod; 16975 var decls_anon_decl = try block.startAnonDecl(); 16976 defer decls_anon_decl.deinit(); 16977 16978 const declaration_ty = t: { 16979 const declaration_ty_decl_index = (try sema.namespaceLookup( 16980 block, 16981 src, 16982 type_info_ty.getNamespaceIndex(mod).unwrap().?, 16983 "Declaration", 16984 )).?; 16985 try mod.declareDeclDependency(sema.owner_decl_index, declaration_ty_decl_index); 16986 try sema.ensureDeclAnalyzed(declaration_ty_decl_index); 16987 const declaration_ty_decl = mod.declPtr(declaration_ty_decl_index); 16988 break :t declaration_ty_decl.val.toType(); 16989 }; 16990 try sema.queueFullTypeResolution(declaration_ty); 16991 16992 var decl_vals = std.ArrayList(InternPool.Index).init(sema.gpa); 16993 defer decl_vals.deinit(); 16994 16995 var seen_namespaces = std.AutoHashMap(*Namespace, void).init(sema.gpa); 16996 defer seen_namespaces.deinit(); 16997 16998 if (opt_namespace.unwrap()) |namespace_index| { 16999 const namespace = mod.namespacePtr(namespace_index); 17000 try sema.typeInfoNamespaceDecls(block, namespace, declaration_ty, &decl_vals, &seen_namespaces); 17001 } 17002 17003 const array_decl_ty = try mod.arrayType(.{ 17004 .len = decl_vals.items.len, 17005 .child = declaration_ty.toIntern(), 17006 .sentinel = .none, 17007 }); 17008 const new_decl = try decls_anon_decl.finish( 17009 array_decl_ty, 17010 (try mod.intern(.{ .aggregate = .{ 17011 .ty = array_decl_ty.toIntern(), 17012 .storage = .{ .elems = decl_vals.items }, 17013 } })).toValue(), 17014 0, // default alignment 17015 ); 17016 return try mod.intern(.{ .ptr = .{ 17017 .ty = (try mod.ptrType(.{ 17018 .child = declaration_ty.toIntern(), 17019 .flags = .{ 17020 .size = .Slice, 17021 .is_const = true, 17022 }, 17023 })).toIntern(), 17024 .addr = .{ .decl = new_decl }, 17025 .len = (try mod.intValue(Type.usize, decl_vals.items.len)).toIntern(), 17026 } }); 17027 } 17028 17029 fn typeInfoNamespaceDecls( 17030 sema: *Sema, 17031 block: *Block, 17032 namespace: *Namespace, 17033 declaration_ty: Type, 17034 decl_vals: *std.ArrayList(InternPool.Index), 17035 seen_namespaces: *std.AutoHashMap(*Namespace, void), 17036 ) !void { 17037 const mod = sema.mod; 17038 const gop = try seen_namespaces.getOrPut(namespace); 17039 if (gop.found_existing) return; 17040 const decls = namespace.decls.keys(); 17041 for (decls) |decl_index| { 17042 const decl = mod.declPtr(decl_index); 17043 if (decl.kind == .@"usingnamespace") { 17044 if (decl.analysis == .in_progress) continue; 17045 try mod.ensureDeclAnalyzed(decl_index); 17046 const new_ns = decl.val.toType().getNamespace(mod).?; 17047 try sema.typeInfoNamespaceDecls(block, new_ns, declaration_ty, decl_vals, seen_namespaces); 17048 continue; 17049 } 17050 if (decl.kind != .named) continue; 17051 const name_val = v: { 17052 var anon_decl = try block.startAnonDecl(); 17053 defer anon_decl.deinit(); 17054 const name = mem.span(decl.name); 17055 const new_decl_ty = try mod.arrayType(.{ 17056 .len = name.len, 17057 .child = .u8_type, 17058 }); 17059 const new_decl = try anon_decl.finish( 17060 new_decl_ty, 17061 (try mod.intern(.{ .aggregate = .{ 17062 .ty = new_decl_ty.toIntern(), 17063 .storage = .{ .bytes = name }, 17064 } })).toValue(), 17065 0, // default alignment 17066 ); 17067 break :v try mod.intern(.{ .ptr = .{ 17068 .ty = .slice_const_u8_type, 17069 .addr = .{ .decl = new_decl }, 17070 .len = (try mod.intValue(Type.usize, name.len)).toIntern(), 17071 } }); 17072 }; 17073 17074 const fields = .{ 17075 //name: []const u8, 17076 name_val, 17077 //is_pub: bool, 17078 Value.makeBool(decl.is_pub).toIntern(), 17079 }; 17080 try decl_vals.append(try mod.intern(.{ .aggregate = .{ 17081 .ty = declaration_ty.toIntern(), 17082 .storage = .{ .elems = &fields }, 17083 } })); 17084 } 17085 } 17086 17087 fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17088 _ = block; 17089 const zir_datas = sema.code.instructions.items(.data); 17090 const inst_data = zir_datas[inst].un_node; 17091 const operand = try sema.resolveInst(inst_data.operand); 17092 const operand_ty = sema.typeOf(operand); 17093 return sema.addType(operand_ty); 17094 } 17095 17096 fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17097 const pl_node = sema.code.instructions.items(.data)[inst].pl_node; 17098 const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index); 17099 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 17100 17101 var child_block: Block = .{ 17102 .parent = block, 17103 .sema = sema, 17104 .src_decl = block.src_decl, 17105 .namespace = block.namespace, 17106 .wip_capture_scope = block.wip_capture_scope, 17107 .instructions = .{}, 17108 .inlining = block.inlining, 17109 .is_comptime = false, 17110 .is_typeof = true, 17111 .want_safety = false, 17112 .error_return_trace_index = block.error_return_trace_index, 17113 }; 17114 defer child_block.instructions.deinit(sema.gpa); 17115 17116 const operand = try sema.resolveBody(&child_block, body, inst); 17117 const operand_ty = sema.typeOf(operand); 17118 if (operand_ty.isGenericPoison()) return error.GenericPoison; 17119 return sema.addType(operand_ty); 17120 } 17121 17122 fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17123 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 17124 const src = inst_data.src(); 17125 const operand = try sema.resolveInst(inst_data.operand); 17126 const operand_ty = sema.typeOf(operand); 17127 const res_ty = try sema.log2IntType(block, operand_ty, src); 17128 return sema.addType(res_ty); 17129 } 17130 17131 fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) CompileError!Type { 17132 const mod = sema.mod; 17133 switch (operand.zigTypeTag(mod)) { 17134 .ComptimeInt => return Type.comptime_int, 17135 .Int => { 17136 const bits = operand.bitSize(mod); 17137 const count = if (bits == 0) 17138 0 17139 else blk: { 17140 var count: u16 = 0; 17141 var s = bits - 1; 17142 while (s != 0) : (s >>= 1) { 17143 count += 1; 17144 } 17145 break :blk count; 17146 }; 17147 return mod.intType(.unsigned, count); 17148 }, 17149 .Vector => { 17150 const elem_ty = operand.elemType2(mod); 17151 const log2_elem_ty = try sema.log2IntType(block, elem_ty, src); 17152 return mod.vectorType(.{ 17153 .len = operand.vectorLen(mod), 17154 .child = log2_elem_ty.toIntern(), 17155 }); 17156 }, 17157 else => {}, 17158 } 17159 return sema.fail( 17160 block, 17161 src, 17162 "bit shifting operation expected integer type, found '{}'", 17163 .{operand.fmt(sema.mod)}, 17164 ); 17165 } 17166 17167 fn zirTypeofPeer( 17168 sema: *Sema, 17169 block: *Block, 17170 extended: Zir.Inst.Extended.InstData, 17171 ) CompileError!Air.Inst.Ref { 17172 const tracy = trace(@src()); 17173 defer tracy.end(); 17174 17175 const extra = sema.code.extraData(Zir.Inst.TypeOfPeer, extended.operand); 17176 const src = LazySrcLoc.nodeOffset(extra.data.src_node); 17177 const body = sema.code.extra[extra.data.body_index..][0..extra.data.body_len]; 17178 17179 var child_block: Block = .{ 17180 .parent = block, 17181 .sema = sema, 17182 .src_decl = block.src_decl, 17183 .namespace = block.namespace, 17184 .wip_capture_scope = block.wip_capture_scope, 17185 .instructions = .{}, 17186 .inlining = block.inlining, 17187 .is_comptime = false, 17188 .is_typeof = true, 17189 .runtime_cond = block.runtime_cond, 17190 .runtime_loop = block.runtime_loop, 17191 .runtime_index = block.runtime_index, 17192 }; 17193 defer child_block.instructions.deinit(sema.gpa); 17194 // Ignore the result, we only care about the instructions in `args`. 17195 _ = try sema.analyzeBodyBreak(&child_block, body); 17196 17197 const args = sema.code.refSlice(extra.end, extended.small); 17198 17199 const inst_list = try sema.gpa.alloc(Air.Inst.Ref, args.len); 17200 defer sema.gpa.free(inst_list); 17201 17202 for (args, 0..) |arg_ref, i| { 17203 inst_list[i] = try sema.resolveInst(arg_ref); 17204 } 17205 17206 const result_type = try sema.resolvePeerTypes(block, src, inst_list, .{ .typeof_builtin_call_node_offset = extra.data.src_node }); 17207 return sema.addType(result_type); 17208 } 17209 17210 fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17211 const tracy = trace(@src()); 17212 defer tracy.end(); 17213 17214 const mod = sema.mod; 17215 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 17216 const src = inst_data.src(); 17217 const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; 17218 const uncasted_operand = try sema.resolveInst(inst_data.operand); 17219 17220 const operand = try sema.coerce(block, Type.bool, uncasted_operand, operand_src); 17221 if (try sema.resolveMaybeUndefVal(operand)) |val| { 17222 return if (val.isUndef(mod)) 17223 sema.addConstUndef(Type.bool) 17224 else if (val.toBool()) 17225 Air.Inst.Ref.bool_false 17226 else 17227 Air.Inst.Ref.bool_true; 17228 } 17229 try sema.requireRuntimeBlock(block, src, null); 17230 return block.addTyOp(.not, Type.bool, operand); 17231 } 17232 17233 fn zirBoolBr( 17234 sema: *Sema, 17235 parent_block: *Block, 17236 inst: Zir.Inst.Index, 17237 is_bool_or: bool, 17238 ) CompileError!Air.Inst.Ref { 17239 const tracy = trace(@src()); 17240 defer tracy.end(); 17241 17242 const mod = sema.mod; 17243 const datas = sema.code.instructions.items(.data); 17244 const inst_data = datas[inst].bool_br; 17245 const lhs = try sema.resolveInst(inst_data.lhs); 17246 const lhs_src = sema.src; 17247 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); 17248 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 17249 const gpa = sema.gpa; 17250 17251 if (try sema.resolveDefinedValue(parent_block, lhs_src, lhs)) |lhs_val| { 17252 if (is_bool_or and lhs_val.toBool()) { 17253 return Air.Inst.Ref.bool_true; 17254 } else if (!is_bool_or and !lhs_val.toBool()) { 17255 return Air.Inst.Ref.bool_false; 17256 } 17257 // comptime-known left-hand side. No need for a block here; the result 17258 // is simply the rhs expression. Here we rely on there only being 1 17259 // break instruction (`break_inline`). 17260 return sema.resolveBody(parent_block, body, inst); 17261 } 17262 17263 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 17264 try sema.air_instructions.append(gpa, .{ 17265 .tag = .block, 17266 .data = .{ .ty_pl = .{ 17267 .ty = .bool_type, 17268 .payload = undefined, 17269 } }, 17270 }); 17271 17272 var child_block = parent_block.makeSubBlock(); 17273 child_block.runtime_loop = null; 17274 child_block.runtime_cond = lhs_src; 17275 child_block.runtime_index.increment(); 17276 defer child_block.instructions.deinit(gpa); 17277 17278 var then_block = child_block.makeSubBlock(); 17279 defer then_block.instructions.deinit(gpa); 17280 17281 var else_block = child_block.makeSubBlock(); 17282 defer else_block.instructions.deinit(gpa); 17283 17284 const lhs_block = if (is_bool_or) &then_block else &else_block; 17285 const rhs_block = if (is_bool_or) &else_block else &then_block; 17286 17287 const lhs_result: Air.Inst.Ref = if (is_bool_or) .bool_true else .bool_false; 17288 _ = try lhs_block.addBr(block_inst, lhs_result); 17289 17290 const rhs_result = try sema.resolveBody(rhs_block, body, inst); 17291 if (!sema.typeOf(rhs_result).isNoReturn(mod)) { 17292 _ = try rhs_block.addBr(block_inst, rhs_result); 17293 } 17294 17295 const result = sema.finishCondBr(parent_block, &child_block, &then_block, &else_block, lhs, block_inst); 17296 if (!sema.typeOf(rhs_result).isNoReturn(mod)) { 17297 if (try sema.resolveDefinedValue(rhs_block, sema.src, rhs_result)) |rhs_val| { 17298 if (is_bool_or and rhs_val.toBool()) { 17299 return Air.Inst.Ref.bool_true; 17300 } else if (!is_bool_or and !rhs_val.toBool()) { 17301 return Air.Inst.Ref.bool_false; 17302 } 17303 } 17304 } 17305 17306 return result; 17307 } 17308 17309 fn finishCondBr( 17310 sema: *Sema, 17311 parent_block: *Block, 17312 child_block: *Block, 17313 then_block: *Block, 17314 else_block: *Block, 17315 cond: Air.Inst.Ref, 17316 block_inst: Air.Inst.Index, 17317 ) !Air.Inst.Ref { 17318 const gpa = sema.gpa; 17319 17320 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + 17321 then_block.instructions.items.len + else_block.instructions.items.len + 17322 @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1); 17323 17324 const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{ 17325 .then_body_len = @intCast(u32, then_block.instructions.items.len), 17326 .else_body_len = @intCast(u32, else_block.instructions.items.len), 17327 }); 17328 sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items); 17329 sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items); 17330 17331 _ = try child_block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{ 17332 .operand = cond, 17333 .payload = cond_br_payload, 17334 } } }); 17335 17336 sema.air_instructions.items(.data)[block_inst].ty_pl.payload = sema.addExtraAssumeCapacity( 17337 Air.Block{ .body_len = @intCast(u32, child_block.instructions.items.len) }, 17338 ); 17339 sema.air_extra.appendSliceAssumeCapacity(child_block.instructions.items); 17340 17341 try parent_block.instructions.append(gpa, block_inst); 17342 return Air.indexToRef(block_inst); 17343 } 17344 17345 fn checkNullableType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { 17346 const mod = sema.mod; 17347 switch (ty.zigTypeTag(mod)) { 17348 .Optional, .Null, .Undefined => return, 17349 .Pointer => if (ty.isPtrLikeOptional(mod)) return, 17350 else => {}, 17351 } 17352 return sema.failWithExpectedOptionalType(block, src, ty); 17353 } 17354 17355 fn zirIsNonNull( 17356 sema: *Sema, 17357 block: *Block, 17358 inst: Zir.Inst.Index, 17359 ) CompileError!Air.Inst.Ref { 17360 const tracy = trace(@src()); 17361 defer tracy.end(); 17362 17363 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 17364 const src = inst_data.src(); 17365 const operand = try sema.resolveInst(inst_data.operand); 17366 try sema.checkNullableType(block, src, sema.typeOf(operand)); 17367 return sema.analyzeIsNull(block, src, operand, true); 17368 } 17369 17370 fn zirIsNonNullPtr( 17371 sema: *Sema, 17372 block: *Block, 17373 inst: Zir.Inst.Index, 17374 ) CompileError!Air.Inst.Ref { 17375 const tracy = trace(@src()); 17376 defer tracy.end(); 17377 17378 const mod = sema.mod; 17379 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 17380 const src = inst_data.src(); 17381 const ptr = try sema.resolveInst(inst_data.operand); 17382 try sema.checkNullableType(block, src, sema.typeOf(ptr).elemType2(mod)); 17383 if ((try sema.resolveMaybeUndefVal(ptr)) == null) { 17384 return block.addUnOp(.is_non_null_ptr, ptr); 17385 } 17386 const loaded = try sema.analyzeLoad(block, src, ptr, src); 17387 return sema.analyzeIsNull(block, src, loaded, true); 17388 } 17389 17390 fn checkErrorType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { 17391 const mod = sema.mod; 17392 switch (ty.zigTypeTag(mod)) { 17393 .ErrorSet, .ErrorUnion, .Undefined => return, 17394 else => return sema.fail(block, src, "expected error union type, found '{}'", .{ 17395 ty.fmt(sema.mod), 17396 }), 17397 } 17398 } 17399 17400 fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17401 const tracy = trace(@src()); 17402 defer tracy.end(); 17403 17404 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 17405 const src = inst_data.src(); 17406 const operand = try sema.resolveInst(inst_data.operand); 17407 try sema.checkErrorType(block, src, sema.typeOf(operand)); 17408 return sema.analyzeIsNonErr(block, src, operand); 17409 } 17410 17411 fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17412 const tracy = trace(@src()); 17413 defer tracy.end(); 17414 17415 const mod = sema.mod; 17416 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 17417 const src = inst_data.src(); 17418 const ptr = try sema.resolveInst(inst_data.operand); 17419 try sema.checkErrorType(block, src, sema.typeOf(ptr).elemType2(mod)); 17420 const loaded = try sema.analyzeLoad(block, src, ptr, src); 17421 return sema.analyzeIsNonErr(block, src, loaded); 17422 } 17423 17424 fn zirRetIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17425 const tracy = trace(@src()); 17426 defer tracy.end(); 17427 17428 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 17429 const src = inst_data.src(); 17430 const operand = try sema.resolveInst(inst_data.operand); 17431 return sema.analyzeIsNonErr(block, src, operand); 17432 } 17433 17434 fn zirCondbr( 17435 sema: *Sema, 17436 parent_block: *Block, 17437 inst: Zir.Inst.Index, 17438 ) CompileError!Zir.Inst.Index { 17439 const tracy = trace(@src()); 17440 defer tracy.end(); 17441 17442 const mod = sema.mod; 17443 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 17444 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; 17445 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); 17446 17447 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len]; 17448 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; 17449 17450 const uncasted_cond = try sema.resolveInst(extra.data.condition); 17451 const cond = try sema.coerce(parent_block, Type.bool, uncasted_cond, cond_src); 17452 17453 if (try sema.resolveDefinedValue(parent_block, cond_src, cond)) |cond_val| { 17454 const body = if (cond_val.toBool()) then_body else else_body; 17455 17456 try sema.maybeErrorUnwrapCondbr(parent_block, body, extra.data.condition, cond_src); 17457 // We use `analyzeBodyInner` since we want to propagate any possible 17458 // `error.ComptimeBreak` to the caller. 17459 return sema.analyzeBodyInner(parent_block, body); 17460 } 17461 17462 const gpa = sema.gpa; 17463 17464 // We'll re-use the sub block to save on memory bandwidth, and yank out the 17465 // instructions array in between using it for the then block and else block. 17466 var sub_block = parent_block.makeSubBlock(); 17467 sub_block.runtime_loop = null; 17468 sub_block.runtime_cond = cond_src; 17469 sub_block.runtime_index.increment(); 17470 defer sub_block.instructions.deinit(gpa); 17471 17472 try sema.analyzeBodyRuntimeBreak(&sub_block, then_body); 17473 const true_instructions = try sub_block.instructions.toOwnedSlice(gpa); 17474 defer gpa.free(true_instructions); 17475 17476 const err_cond = blk: { 17477 const index = Zir.refToIndex(extra.data.condition) orelse break :blk null; 17478 if (sema.code.instructions.items(.tag)[index] != .is_non_err) break :blk null; 17479 17480 const err_inst_data = sema.code.instructions.items(.data)[index].un_node; 17481 const err_operand = try sema.resolveInst(err_inst_data.operand); 17482 const operand_ty = sema.typeOf(err_operand); 17483 assert(operand_ty.zigTypeTag(mod) == .ErrorUnion); 17484 const result_ty = operand_ty.errorUnionSet(mod); 17485 break :blk try sub_block.addTyOp(.unwrap_errunion_err, result_ty, err_operand); 17486 }; 17487 17488 if (err_cond != null and try sema.maybeErrorUnwrap(&sub_block, else_body, err_cond.?)) { 17489 // nothing to do 17490 } else { 17491 try sema.analyzeBodyRuntimeBreak(&sub_block, else_body); 17492 } 17493 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + 17494 true_instructions.len + sub_block.instructions.items.len); 17495 _ = try parent_block.addInst(.{ 17496 .tag = .cond_br, 17497 .data = .{ .pl_op = .{ 17498 .operand = cond, 17499 .payload = sema.addExtraAssumeCapacity(Air.CondBr{ 17500 .then_body_len = @intCast(u32, true_instructions.len), 17501 .else_body_len = @intCast(u32, sub_block.instructions.items.len), 17502 }), 17503 } }, 17504 }); 17505 sema.air_extra.appendSliceAssumeCapacity(true_instructions); 17506 sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items); 17507 return always_noreturn; 17508 } 17509 17510 fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17511 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 17512 const src = inst_data.src(); 17513 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 17514 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index); 17515 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 17516 const err_union = try sema.resolveInst(extra.data.operand); 17517 const err_union_ty = sema.typeOf(err_union); 17518 const mod = sema.mod; 17519 if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) { 17520 return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{ 17521 err_union_ty.fmt(sema.mod), 17522 }); 17523 } 17524 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union); 17525 if (is_non_err != .none) { 17526 const is_non_err_val = (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)).?; 17527 if (is_non_err_val.toBool()) { 17528 return sema.analyzeErrUnionPayload(parent_block, src, err_union_ty, err_union, operand_src, false); 17529 } 17530 // We can analyze the body directly in the parent block because we know there are 17531 // no breaks from the body possible, and that the body is noreturn. 17532 return sema.resolveBody(parent_block, body, inst); 17533 } 17534 17535 var sub_block = parent_block.makeSubBlock(); 17536 defer sub_block.instructions.deinit(sema.gpa); 17537 17538 // This body is guaranteed to end with noreturn and has no breaks. 17539 _ = try sema.analyzeBodyInner(&sub_block, body); 17540 17541 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Try).Struct.fields.len + 17542 sub_block.instructions.items.len); 17543 const try_inst = try parent_block.addInst(.{ 17544 .tag = .@"try", 17545 .data = .{ .pl_op = .{ 17546 .operand = err_union, 17547 .payload = sema.addExtraAssumeCapacity(Air.Try{ 17548 .body_len = @intCast(u32, sub_block.instructions.items.len), 17549 }), 17550 } }, 17551 }); 17552 sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items); 17553 return try_inst; 17554 } 17555 17556 fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17557 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 17558 const src = inst_data.src(); 17559 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 17560 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index); 17561 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 17562 const operand = try sema.resolveInst(extra.data.operand); 17563 const err_union = try sema.analyzeLoad(parent_block, src, operand, operand_src); 17564 const err_union_ty = sema.typeOf(err_union); 17565 const mod = sema.mod; 17566 if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) { 17567 return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{ 17568 err_union_ty.fmt(sema.mod), 17569 }); 17570 } 17571 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union); 17572 if (is_non_err != .none) { 17573 const is_non_err_val = (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)).?; 17574 if (is_non_err_val.toBool()) { 17575 return sema.analyzeErrUnionPayloadPtr(parent_block, src, operand, false, false); 17576 } 17577 // We can analyze the body directly in the parent block because we know there are 17578 // no breaks from the body possible, and that the body is noreturn. 17579 return sema.resolveBody(parent_block, body, inst); 17580 } 17581 17582 var sub_block = parent_block.makeSubBlock(); 17583 defer sub_block.instructions.deinit(sema.gpa); 17584 17585 // This body is guaranteed to end with noreturn and has no breaks. 17586 _ = try sema.analyzeBodyInner(&sub_block, body); 17587 17588 const operand_ty = sema.typeOf(operand); 17589 const ptr_info = operand_ty.ptrInfo(mod); 17590 const res_ty = try Type.ptr(sema.arena, sema.mod, .{ 17591 .pointee_type = err_union_ty.errorUnionPayload(mod), 17592 .@"addrspace" = ptr_info.@"addrspace", 17593 .mutable = ptr_info.mutable, 17594 .@"allowzero" = ptr_info.@"allowzero", 17595 .@"volatile" = ptr_info.@"volatile", 17596 }); 17597 const res_ty_ref = try sema.addType(res_ty); 17598 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.TryPtr).Struct.fields.len + 17599 sub_block.instructions.items.len); 17600 const try_inst = try parent_block.addInst(.{ 17601 .tag = .try_ptr, 17602 .data = .{ .ty_pl = .{ 17603 .ty = res_ty_ref, 17604 .payload = sema.addExtraAssumeCapacity(Air.TryPtr{ 17605 .ptr = operand, 17606 .body_len = @intCast(u32, sub_block.instructions.items.len), 17607 }), 17608 } }, 17609 }); 17610 sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items); 17611 return try_inst; 17612 } 17613 17614 // A `break` statement is inside a runtime condition, but trying to 17615 // break from an inline loop. In such case we must convert it to 17616 // a runtime break. 17617 fn addRuntimeBreak(sema: *Sema, child_block: *Block, break_data: BreakData) !void { 17618 const gop = sema.inst_map.getOrPutAssumeCapacity(break_data.block_inst); 17619 const labeled_block = if (!gop.found_existing) blk: { 17620 try sema.post_hoc_blocks.ensureUnusedCapacity(sema.gpa, 1); 17621 17622 const new_block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 17623 gop.value_ptr.* = Air.indexToRef(new_block_inst); 17624 try sema.air_instructions.append(sema.gpa, .{ 17625 .tag = .block, 17626 .data = undefined, 17627 }); 17628 const labeled_block = try sema.gpa.create(LabeledBlock); 17629 labeled_block.* = .{ 17630 .label = .{ 17631 .zir_block = break_data.block_inst, 17632 .merges = .{ 17633 .src_locs = .{}, 17634 .results = .{}, 17635 .br_list = .{}, 17636 .block_inst = new_block_inst, 17637 }, 17638 }, 17639 .block = .{ 17640 .parent = child_block, 17641 .sema = sema, 17642 .src_decl = child_block.src_decl, 17643 .namespace = child_block.namespace, 17644 .wip_capture_scope = child_block.wip_capture_scope, 17645 .instructions = .{}, 17646 .label = &labeled_block.label, 17647 .inlining = child_block.inlining, 17648 .is_comptime = child_block.is_comptime, 17649 }, 17650 }; 17651 sema.post_hoc_blocks.putAssumeCapacityNoClobber(new_block_inst, labeled_block); 17652 break :blk labeled_block; 17653 } else blk: { 17654 const new_block_inst = Air.refToIndex(gop.value_ptr.*).?; 17655 const labeled_block = sema.post_hoc_blocks.get(new_block_inst).?; 17656 break :blk labeled_block; 17657 }; 17658 17659 const operand = try sema.resolveInst(break_data.operand); 17660 const br_ref = try child_block.addBr(labeled_block.label.merges.block_inst, operand); 17661 try labeled_block.label.merges.results.append(sema.gpa, operand); 17662 try labeled_block.label.merges.br_list.append(sema.gpa, Air.refToIndex(br_ref).?); 17663 labeled_block.block.runtime_index.increment(); 17664 if (labeled_block.block.runtime_cond == null and labeled_block.block.runtime_loop == null) { 17665 labeled_block.block.runtime_cond = child_block.runtime_cond orelse child_block.runtime_loop; 17666 labeled_block.block.runtime_loop = child_block.runtime_loop; 17667 } 17668 } 17669 17670 fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { 17671 const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable"; 17672 const src = inst_data.src(); 17673 17674 if (block.is_comptime) { 17675 return sema.fail(block, src, "reached unreachable code", .{}); 17676 } 17677 // TODO Add compile error for @optimizeFor occurring too late in a scope. 17678 try block.addUnreachable(true); 17679 return always_noreturn; 17680 } 17681 17682 fn zirRetErrValue( 17683 sema: *Sema, 17684 block: *Block, 17685 inst: Zir.Inst.Index, 17686 ) CompileError!Zir.Inst.Index { 17687 const mod = sema.mod; 17688 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 17689 const err_name = inst_data.get(sema.code); 17690 const src = inst_data.src(); 17691 17692 // Return the error code from the function. 17693 const kv = try mod.getErrorValue(err_name); 17694 const error_set_type = try mod.singleErrorSetType(err_name); 17695 const result_inst = try sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ 17696 .ty = error_set_type.toIntern(), 17697 .name = try mod.intern_pool.getOrPutString(sema.gpa, kv.key), 17698 } })).toValue()); 17699 return sema.analyzeRet(block, result_inst, src); 17700 } 17701 17702 fn zirRetImplicit( 17703 sema: *Sema, 17704 block: *Block, 17705 inst: Zir.Inst.Index, 17706 ) CompileError!Zir.Inst.Index { 17707 const tracy = trace(@src()); 17708 defer tracy.end(); 17709 17710 const mod = sema.mod; 17711 const inst_data = sema.code.instructions.items(.data)[inst].un_tok; 17712 const operand = try sema.resolveInst(inst_data.operand); 17713 17714 const r_brace_src = inst_data.src(); 17715 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; 17716 const base_tag = sema.fn_ret_ty.baseZigTypeTag(mod); 17717 if (base_tag == .NoReturn) { 17718 const msg = msg: { 17719 const msg = try sema.errMsg(block, ret_ty_src, "function declared '{}' implicitly returns", .{ 17720 sema.fn_ret_ty.fmt(mod), 17721 }); 17722 errdefer msg.destroy(sema.gpa); 17723 try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{}); 17724 break :msg msg; 17725 }; 17726 return sema.failWithOwnedErrorMsg(msg); 17727 } else if (base_tag != .Void) { 17728 const msg = msg: { 17729 const msg = try sema.errMsg(block, ret_ty_src, "function with non-void return type '{}' implicitly returns", .{ 17730 sema.fn_ret_ty.fmt(mod), 17731 }); 17732 errdefer msg.destroy(sema.gpa); 17733 try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{}); 17734 break :msg msg; 17735 }; 17736 return sema.failWithOwnedErrorMsg(msg); 17737 } 17738 17739 return sema.analyzeRet(block, operand, .unneeded); 17740 } 17741 17742 fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { 17743 const tracy = trace(@src()); 17744 defer tracy.end(); 17745 17746 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 17747 const operand = try sema.resolveInst(inst_data.operand); 17748 const src = inst_data.src(); 17749 17750 return sema.analyzeRet(block, operand, src); 17751 } 17752 17753 fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { 17754 const tracy = trace(@src()); 17755 defer tracy.end(); 17756 17757 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 17758 const src = inst_data.src(); 17759 const ret_ptr = try sema.resolveInst(inst_data.operand); 17760 17761 if (block.is_comptime or block.inlining != null) { 17762 const operand = try sema.analyzeLoad(block, src, ret_ptr, src); 17763 return sema.analyzeRet(block, operand, src); 17764 } 17765 17766 if (sema.wantErrorReturnTracing(sema.fn_ret_ty)) { 17767 const is_non_err = try sema.analyzePtrIsNonErr(block, src, ret_ptr); 17768 return sema.retWithErrTracing(block, is_non_err, .ret_load, ret_ptr); 17769 } 17770 17771 _ = try block.addUnOp(.ret_load, ret_ptr); 17772 return always_noreturn; 17773 } 17774 17775 fn retWithErrTracing( 17776 sema: *Sema, 17777 block: *Block, 17778 is_non_err: Air.Inst.Ref, 17779 ret_tag: Air.Inst.Tag, 17780 operand: Air.Inst.Ref, 17781 ) CompileError!Zir.Inst.Index { 17782 const mod = sema.mod; 17783 const need_check = switch (is_non_err) { 17784 .bool_true => { 17785 _ = try block.addUnOp(ret_tag, operand); 17786 return always_noreturn; 17787 }, 17788 .bool_false => false, 17789 else => true, 17790 }; 17791 const gpa = sema.gpa; 17792 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); 17793 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); 17794 const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); 17795 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); 17796 const return_err_fn = try sema.getBuiltin("returnError"); 17797 const args: [1]Air.Inst.Ref = .{err_return_trace}; 17798 17799 if (!need_check) { 17800 try sema.callBuiltin(block, return_err_fn, .never_inline, &args); 17801 _ = try block.addUnOp(ret_tag, operand); 17802 return always_noreturn; 17803 } 17804 17805 var then_block = block.makeSubBlock(); 17806 defer then_block.instructions.deinit(gpa); 17807 _ = try then_block.addUnOp(ret_tag, operand); 17808 17809 var else_block = block.makeSubBlock(); 17810 defer else_block.instructions.deinit(gpa); 17811 try sema.callBuiltin(&else_block, return_err_fn, .never_inline, &args); 17812 _ = try else_block.addUnOp(ret_tag, operand); 17813 17814 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + 17815 then_block.instructions.items.len + else_block.instructions.items.len + 17816 @typeInfo(Air.Block).Struct.fields.len + 1); 17817 17818 const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{ 17819 .then_body_len = @intCast(u32, then_block.instructions.items.len), 17820 .else_body_len = @intCast(u32, else_block.instructions.items.len), 17821 }); 17822 sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items); 17823 sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items); 17824 17825 _ = try block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{ 17826 .operand = is_non_err, 17827 .payload = cond_br_payload, 17828 } } }); 17829 17830 return always_noreturn; 17831 } 17832 17833 fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool { 17834 const mod = sema.mod; 17835 if (!mod.backendSupportsFeature(.error_return_trace)) return false; 17836 17837 return fn_ret_ty.isError(mod) and 17838 mod.comp.bin_file.options.error_return_tracing; 17839 } 17840 17841 fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 17842 const mod = sema.mod; 17843 const inst_data = sema.code.instructions.items(.data)[inst].save_err_ret_index; 17844 17845 if (!mod.backendSupportsFeature(.error_return_trace)) return; 17846 if (!mod.comp.bin_file.options.error_return_tracing) return; 17847 17848 // This is only relevant at runtime. 17849 if (block.is_comptime or block.is_typeof) return; 17850 17851 const save_index = inst_data.operand == .none or b: { 17852 const operand = try sema.resolveInst(inst_data.operand); 17853 const operand_ty = sema.typeOf(operand); 17854 break :b operand_ty.isError(mod); 17855 }; 17856 17857 if (save_index) 17858 block.error_return_trace_index = try sema.analyzeSaveErrRetIndex(block); 17859 } 17860 17861 fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError!void { 17862 const inst_data = sema.code.instructions.items(.data)[inst].restore_err_ret_index; 17863 const src = sema.src; // TODO 17864 17865 // This is only relevant at runtime. 17866 if (start_block.is_comptime or start_block.is_typeof) return; 17867 17868 if (!sema.mod.backendSupportsFeature(.error_return_trace)) return; 17869 if (!sema.owner_func.?.calls_or_awaits_errorable_fn) return; 17870 if (!sema.mod.comp.bin_file.options.error_return_tracing) return; 17871 17872 const tracy = trace(@src()); 17873 defer tracy.end(); 17874 17875 const saved_index = if (Zir.refToIndexAllowNone(inst_data.block)) |zir_block| b: { 17876 var block = start_block; 17877 while (true) { 17878 if (block.label) |label| { 17879 if (label.zir_block == zir_block) { 17880 const target_trace_index = if (block.parent) |parent_block| tgt: { 17881 break :tgt parent_block.error_return_trace_index; 17882 } else sema.error_return_trace_index_on_fn_entry; 17883 17884 if (start_block.error_return_trace_index != target_trace_index) 17885 break :b target_trace_index; 17886 17887 return; // No need to restore 17888 } 17889 } 17890 block = block.parent.?; 17891 } 17892 } else b: { 17893 if (start_block.error_return_trace_index != sema.error_return_trace_index_on_fn_entry) 17894 break :b sema.error_return_trace_index_on_fn_entry; 17895 17896 return; // No need to restore 17897 }; 17898 17899 assert(saved_index != .none); // The .error_return_trace_index field was dropped somewhere 17900 17901 const operand = try sema.resolveInstAllowNone(inst_data.operand); 17902 return sema.popErrorReturnTrace(start_block, src, operand, saved_index); 17903 } 17904 17905 fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void { 17906 const mod = sema.mod; 17907 const gpa = sema.gpa; 17908 const ip = &mod.intern_pool; 17909 assert(sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion); 17910 17911 if (mod.typeToInferredErrorSet(sema.fn_ret_ty.errorUnionSet(mod))) |ies| { 17912 const op_ty = sema.typeOf(uncasted_operand); 17913 switch (op_ty.zigTypeTag(mod)) { 17914 .ErrorSet => try ies.addErrorSet(op_ty, ip, gpa), 17915 .ErrorUnion => try ies.addErrorSet(op_ty.errorUnionSet(mod), ip, gpa), 17916 else => {}, 17917 } 17918 } 17919 } 17920 17921 fn analyzeRet( 17922 sema: *Sema, 17923 block: *Block, 17924 uncasted_operand: Air.Inst.Ref, 17925 src: LazySrcLoc, 17926 ) CompileError!Zir.Inst.Index { 17927 // Special case for returning an error to an inferred error set; we need to 17928 // add the error tag to the inferred error set of the in-scope function, so 17929 // that the coercion below works correctly. 17930 const mod = sema.mod; 17931 if (sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion) { 17932 try sema.addToInferredErrorSet(uncasted_operand); 17933 } 17934 const operand = sema.coerceExtra(block, sema.fn_ret_ty, uncasted_operand, src, .{ .is_ret = true }) catch |err| switch (err) { 17935 error.NotCoercible => unreachable, 17936 else => |e| return e, 17937 }; 17938 17939 if (block.inlining) |inlining| { 17940 if (block.is_comptime) { 17941 _ = try sema.resolveConstMaybeUndefVal(block, src, operand, "value being returned at comptime must be comptime-known"); 17942 inlining.comptime_result = operand; 17943 return error.ComptimeReturn; 17944 } 17945 // We are inlining a function call; rewrite the `ret` as a `break`. 17946 try inlining.merges.results.append(sema.gpa, operand); 17947 _ = try block.addBr(inlining.merges.block_inst, operand); 17948 return always_noreturn; 17949 } else if (block.is_comptime) { 17950 return sema.fail(block, src, "function called at runtime cannot return value at comptime", .{}); 17951 } 17952 17953 try sema.resolveTypeLayout(sema.fn_ret_ty); 17954 17955 if (sema.wantErrorReturnTracing(sema.fn_ret_ty)) { 17956 // Avoid adding a frame to the error return trace in case the value is comptime-known 17957 // to be not an error. 17958 const is_non_err = try sema.analyzeIsNonErr(block, src, operand); 17959 return sema.retWithErrTracing(block, is_non_err, .ret, operand); 17960 } 17961 17962 _ = try block.addUnOp(.ret, operand); 17963 17964 return always_noreturn; 17965 } 17966 17967 fn floatOpAllowed(tag: Zir.Inst.Tag) bool { 17968 // extend this swich as additional operators are implemented 17969 return switch (tag) { 17970 .add, .sub, .mul, .div, .div_exact, .div_trunc, .div_floor, .mod, .rem, .mod_rem => true, 17971 else => false, 17972 }; 17973 } 17974 17975 fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17976 const tracy = trace(@src()); 17977 defer tracy.end(); 17978 17979 const mod = sema.mod; 17980 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type; 17981 const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index); 17982 const elem_ty_src: LazySrcLoc = .{ .node_offset_ptr_elem = extra.data.src_node }; 17983 const sentinel_src: LazySrcLoc = .{ .node_offset_ptr_sentinel = extra.data.src_node }; 17984 const align_src: LazySrcLoc = .{ .node_offset_ptr_align = extra.data.src_node }; 17985 const addrspace_src: LazySrcLoc = .{ .node_offset_ptr_addrspace = extra.data.src_node }; 17986 const bitoffset_src: LazySrcLoc = .{ .node_offset_ptr_bitoffset = extra.data.src_node }; 17987 const hostsize_src: LazySrcLoc = .{ .node_offset_ptr_hostsize = extra.data.src_node }; 17988 17989 const elem_ty = blk: { 17990 const air_inst = try sema.resolveInst(extra.data.elem_type); 17991 const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| { 17992 if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer(mod)) { 17993 try sema.errNote(block, elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{}); 17994 } 17995 return err; 17996 }; 17997 if (ty.isGenericPoison()) return error.GenericPoison; 17998 break :blk ty; 17999 }; 18000 18001 if (elem_ty.zigTypeTag(mod) == .NoReturn) 18002 return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{}); 18003 18004 const target = sema.mod.getTarget(); 18005 18006 var extra_i = extra.end; 18007 18008 const sentinel = if (inst_data.flags.has_sentinel) blk: { 18009 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); 18010 extra_i += 1; 18011 const coerced = try sema.coerce(block, elem_ty, try sema.resolveInst(ref), sentinel_src); 18012 const val = try sema.resolveConstValue(block, sentinel_src, coerced, "pointer sentinel value must be comptime-known"); 18013 break :blk val.toIntern(); 18014 } else .none; 18015 18016 const abi_align: InternPool.Alignment = if (inst_data.flags.has_align) blk: { 18017 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); 18018 extra_i += 1; 18019 const coerced = try sema.coerce(block, Type.u32, try sema.resolveInst(ref), align_src); 18020 const val = try sema.resolveConstValue(block, align_src, coerced, "pointer alignment must be comptime-known"); 18021 // Check if this happens to be the lazy alignment of our element type, in 18022 // which case we can make this 0 without resolving it. 18023 switch (mod.intern_pool.indexToKey(val.toIntern())) { 18024 .int => |int| switch (int.storage) { 18025 .lazy_align => |lazy_ty| if (lazy_ty == elem_ty.toIntern()) break :blk .none, 18026 else => {}, 18027 }, 18028 else => {}, 18029 } 18030 const abi_align = @intCast(u32, (try val.getUnsignedIntAdvanced(mod, sema)).?); 18031 try sema.validateAlign(block, align_src, abi_align); 18032 break :blk InternPool.Alignment.fromByteUnits(abi_align); 18033 } else .none; 18034 18035 const address_space: std.builtin.AddressSpace = if (inst_data.flags.has_addrspace) blk: { 18036 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); 18037 extra_i += 1; 18038 break :blk try sema.analyzeAddressSpace(block, addrspace_src, ref, .pointer); 18039 } else if (elem_ty.zigTypeTag(mod) == .Fn and target.cpu.arch == .avr) .flash else .generic; 18040 18041 const bit_offset = if (inst_data.flags.has_bit_range) blk: { 18042 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); 18043 extra_i += 1; 18044 const bit_offset = try sema.resolveInt(block, bitoffset_src, ref, Type.u16, "pointer bit-offset must be comptime-known"); 18045 break :blk @intCast(u16, bit_offset); 18046 } else 0; 18047 18048 const host_size: u16 = if (inst_data.flags.has_bit_range) blk: { 18049 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); 18050 extra_i += 1; 18051 const host_size = try sema.resolveInt(block, hostsize_src, ref, Type.u16, "pointer host size must be comptime-known"); 18052 break :blk @intCast(u16, host_size); 18053 } else 0; 18054 18055 if (host_size != 0 and bit_offset >= host_size * 8) { 18056 return sema.fail(block, bitoffset_src, "bit offset starts after end of host integer", .{}); 18057 } 18058 18059 if (elem_ty.zigTypeTag(mod) == .Fn) { 18060 if (inst_data.size != .One) { 18061 return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{}); 18062 } 18063 const fn_align = mod.typeToFunc(elem_ty).?.alignment; 18064 if (inst_data.flags.has_align and abi_align != .none and fn_align != .none and 18065 abi_align != fn_align) 18066 { 18067 return sema.fail(block, align_src, "function pointer alignment disagrees with function alignment", .{}); 18068 } 18069 } else if (inst_data.size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) { 18070 return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{}); 18071 } else if (inst_data.size == .C) { 18072 if (!try sema.validateExternType(elem_ty, .other)) { 18073 const msg = msg: { 18074 const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); 18075 errdefer msg.destroy(sema.gpa); 18076 18077 const src_decl = sema.mod.declPtr(block.src_decl); 18078 try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src.toSrcLoc(src_decl, mod), elem_ty, .other); 18079 18080 try sema.addDeclaredHereNote(msg, elem_ty); 18081 break :msg msg; 18082 }; 18083 return sema.failWithOwnedErrorMsg(msg); 18084 } 18085 if (elem_ty.zigTypeTag(mod) == .Opaque) { 18086 return sema.fail(block, elem_ty_src, "C pointers cannot point to opaque types", .{}); 18087 } 18088 } 18089 18090 const ty = try mod.ptrType(.{ 18091 .child = elem_ty.toIntern(), 18092 .sentinel = sentinel, 18093 .flags = .{ 18094 .alignment = abi_align, 18095 .address_space = address_space, 18096 .is_const = !inst_data.flags.is_mutable, 18097 .is_allowzero = inst_data.flags.is_allowzero, 18098 .is_volatile = inst_data.flags.is_volatile, 18099 .size = inst_data.size, 18100 }, 18101 .packed_offset = .{ 18102 .bit_offset = bit_offset, 18103 .host_size = host_size, 18104 }, 18105 }); 18106 return sema.addType(ty); 18107 } 18108 18109 fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 18110 const tracy = trace(@src()); 18111 defer tracy.end(); 18112 18113 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 18114 const src = inst_data.src(); 18115 const obj_ty = try sema.resolveType(block, src, inst_data.operand); 18116 const mod = sema.mod; 18117 18118 switch (obj_ty.zigTypeTag(mod)) { 18119 .Struct => return sema.structInitEmpty(block, obj_ty, src, src), 18120 .Array, .Vector => return sema.arrayInitEmpty(block, src, obj_ty), 18121 .Void => return sema.addConstant(obj_ty, Value.void), 18122 .Union => return sema.fail(block, src, "union initializer must initialize one field", .{}), 18123 else => return sema.failWithArrayInitNotSupported(block, src, obj_ty), 18124 } 18125 } 18126 18127 fn structInitEmpty( 18128 sema: *Sema, 18129 block: *Block, 18130 obj_ty: Type, 18131 dest_src: LazySrcLoc, 18132 init_src: LazySrcLoc, 18133 ) CompileError!Air.Inst.Ref { 18134 const mod = sema.mod; 18135 const gpa = sema.gpa; 18136 // This logic must be synchronized with that in `zirStructInit`. 18137 const struct_ty = try sema.resolveTypeFields(obj_ty); 18138 18139 // The init values to use for the struct instance. 18140 const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount(mod)); 18141 defer gpa.free(field_inits); 18142 @memset(field_inits, .none); 18143 18144 return sema.finishStructInit(block, init_src, dest_src, field_inits, struct_ty, false); 18145 } 18146 18147 fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) CompileError!Air.Inst.Ref { 18148 const mod = sema.mod; 18149 const arr_len = obj_ty.arrayLen(mod); 18150 if (arr_len != 0) { 18151 if (obj_ty.zigTypeTag(mod) == .Array) { 18152 return sema.fail(block, src, "expected {d} array elements; found 0", .{arr_len}); 18153 } else { 18154 return sema.fail(block, src, "expected {d} vector elements; found 0", .{arr_len}); 18155 } 18156 } 18157 return sema.addConstant(obj_ty, (try mod.intern(.{ .aggregate = .{ 18158 .ty = obj_ty.toIntern(), 18159 .storage = .{ .elems = &.{} }, 18160 } })).toValue()); 18161 } 18162 18163 fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 18164 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 18165 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 18166 const field_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 18167 const init_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 18168 const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data; 18169 const union_ty = try sema.resolveType(block, ty_src, extra.union_type); 18170 const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "name of field being initialized must be comptime-known"); 18171 const init = try sema.resolveInst(extra.init); 18172 return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src); 18173 } 18174 18175 fn unionInit( 18176 sema: *Sema, 18177 block: *Block, 18178 uncasted_init: Air.Inst.Ref, 18179 init_src: LazySrcLoc, 18180 union_ty: Type, 18181 union_ty_src: LazySrcLoc, 18182 field_name: []const u8, 18183 field_src: LazySrcLoc, 18184 ) CompileError!Air.Inst.Ref { 18185 const mod = sema.mod; 18186 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src); 18187 const field = union_ty.unionFields(mod).values()[field_index]; 18188 const init = try sema.coerce(block, field.ty, uncasted_init, init_src); 18189 18190 if (try sema.resolveMaybeUndefVal(init)) |init_val| { 18191 const tag_ty = union_ty.unionTagTypeHypothetical(mod); 18192 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?); 18193 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); 18194 return sema.addConstant(union_ty, (try mod.intern(.{ .un = .{ 18195 .ty = union_ty.toIntern(), 18196 .tag = try tag_val.intern(tag_ty, mod), 18197 .val = try init_val.intern(field.ty, mod), 18198 } })).toValue()); 18199 } 18200 18201 try sema.requireRuntimeBlock(block, init_src, null); 18202 _ = union_ty_src; 18203 try sema.queueFullTypeResolution(union_ty); 18204 return block.addUnionInit(union_ty, field_index, init); 18205 } 18206 18207 fn zirStructInit( 18208 sema: *Sema, 18209 block: *Block, 18210 inst: Zir.Inst.Index, 18211 is_ref: bool, 18212 ) CompileError!Air.Inst.Ref { 18213 const gpa = sema.gpa; 18214 const zir_datas = sema.code.instructions.items(.data); 18215 const inst_data = zir_datas[inst].pl_node; 18216 const extra = sema.code.extraData(Zir.Inst.StructInit, inst_data.payload_index); 18217 const src = inst_data.src(); 18218 18219 const mod = sema.mod; 18220 const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data; 18221 const first_field_type_data = zir_datas[first_item.field_type].pl_node; 18222 const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data; 18223 const resolved_ty = try sema.resolveType(block, src, first_field_type_extra.container_type); 18224 try sema.resolveTypeLayout(resolved_ty); 18225 18226 if (resolved_ty.zigTypeTag(mod) == .Struct) { 18227 // This logic must be synchronized with that in `zirStructInitEmpty`. 18228 18229 // Maps field index to field_type index of where it was already initialized. 18230 // For making sure all fields are accounted for and no fields are duplicated. 18231 const found_fields = try gpa.alloc(Zir.Inst.Index, resolved_ty.structFieldCount(mod)); 18232 defer gpa.free(found_fields); 18233 18234 // The init values to use for the struct instance. 18235 const field_inits = try gpa.alloc(Air.Inst.Ref, resolved_ty.structFieldCount(mod)); 18236 defer gpa.free(field_inits); 18237 @memset(field_inits, .none); 18238 18239 var field_i: u32 = 0; 18240 var extra_index = extra.end; 18241 18242 const is_packed = resolved_ty.containerLayout(mod) == .Packed; 18243 while (field_i < extra.data.fields_len) : (field_i += 1) { 18244 const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index); 18245 extra_index = item.end; 18246 18247 const field_type_data = zir_datas[item.data.field_type].pl_node; 18248 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node }; 18249 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; 18250 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); 18251 const field_index = if (resolved_ty.isTuple(mod)) 18252 try sema.tupleFieldIndex(block, resolved_ty, field_name, field_src) 18253 else 18254 try sema.structFieldIndex(block, resolved_ty, field_name, field_src); 18255 if (field_inits[field_index] != .none) { 18256 const other_field_type = found_fields[field_index]; 18257 const other_field_type_data = zir_datas[other_field_type].pl_node; 18258 const other_field_src: LazySrcLoc = .{ .node_offset_initializer = other_field_type_data.src_node }; 18259 const msg = msg: { 18260 const msg = try sema.errMsg(block, field_src, "duplicate field", .{}); 18261 errdefer msg.destroy(gpa); 18262 try sema.errNote(block, other_field_src, msg, "other field here", .{}); 18263 break :msg msg; 18264 }; 18265 return sema.failWithOwnedErrorMsg(msg); 18266 } 18267 found_fields[field_index] = item.data.field_type; 18268 field_inits[field_index] = try sema.resolveInst(item.data.init); 18269 if (!is_packed) if (try resolved_ty.structFieldValueComptime(mod, field_index)) |default_value| { 18270 const init_val = (try sema.resolveMaybeUndefVal(field_inits[field_index])) orelse { 18271 return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known"); 18272 }; 18273 18274 if (!init_val.eql(default_value, resolved_ty.structFieldType(field_index, mod), sema.mod)) { 18275 return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index); 18276 } 18277 }; 18278 } 18279 18280 return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref); 18281 } else if (resolved_ty.zigTypeTag(mod) == .Union) { 18282 if (extra.data.fields_len != 1) { 18283 return sema.fail(block, src, "union initialization expects exactly one field", .{}); 18284 } 18285 18286 const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end); 18287 18288 const field_type_data = zir_datas[item.data.field_type].pl_node; 18289 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node }; 18290 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; 18291 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); 18292 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src); 18293 const tag_ty = resolved_ty.unionTagTypeHypothetical(mod); 18294 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?); 18295 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); 18296 18297 const init_inst = try sema.resolveInst(item.data.init); 18298 if (try sema.resolveMaybeUndefVal(init_inst)) |val| { 18299 const field = resolved_ty.unionFields(mod).values()[field_index]; 18300 return sema.addConstantMaybeRef(block, resolved_ty, (try mod.intern(.{ .un = .{ 18301 .ty = resolved_ty.toIntern(), 18302 .tag = try tag_val.intern(tag_ty, mod), 18303 .val = try val.intern(field.ty, mod), 18304 } })).toValue(), is_ref); 18305 } 18306 18307 if (is_ref) { 18308 const target = sema.mod.getTarget(); 18309 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ 18310 .pointee_type = resolved_ty, 18311 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 18312 }); 18313 const alloc = try block.addTy(.alloc, alloc_ty); 18314 const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true); 18315 try sema.storePtr(block, src, field_ptr, init_inst); 18316 const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(mod), tag_val); 18317 _ = try block.addBinOp(.set_union_tag, alloc, new_tag); 18318 return sema.makePtrConst(block, alloc); 18319 } 18320 18321 try sema.requireRuntimeBlock(block, src, null); 18322 try sema.queueFullTypeResolution(resolved_ty); 18323 return block.addUnionInit(resolved_ty, field_index, init_inst); 18324 } else if (resolved_ty.isAnonStruct(mod)) { 18325 return sema.fail(block, src, "TODO anon struct init validation", .{}); 18326 } 18327 unreachable; 18328 } 18329 18330 fn finishStructInit( 18331 sema: *Sema, 18332 block: *Block, 18333 init_src: LazySrcLoc, 18334 dest_src: LazySrcLoc, 18335 field_inits: []Air.Inst.Ref, 18336 struct_ty: Type, 18337 is_ref: bool, 18338 ) CompileError!Air.Inst.Ref { 18339 const mod = sema.mod; 18340 const gpa = sema.gpa; 18341 18342 var root_msg: ?*Module.ErrorMsg = null; 18343 errdefer if (root_msg) |msg| msg.destroy(sema.gpa); 18344 18345 switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { 18346 .anon_struct_type => |anon_struct| { 18347 for (anon_struct.types, anon_struct.values, 0..) |field_ty, default_val, i| { 18348 if (field_inits[i] != .none) continue; 18349 18350 if (default_val == .none) { 18351 if (anon_struct.names.len == 0) { 18352 const template = "missing tuple field with index {d}"; 18353 if (root_msg) |msg| { 18354 try sema.errNote(block, init_src, msg, template, .{i}); 18355 } else { 18356 root_msg = try sema.errMsg(block, init_src, template, .{i}); 18357 } 18358 } else { 18359 const field_name = mod.intern_pool.stringToSlice(anon_struct.names[i]); 18360 const template = "missing struct field: {s}"; 18361 const args = .{field_name}; 18362 if (root_msg) |msg| { 18363 try sema.errNote(block, init_src, msg, template, args); 18364 } else { 18365 root_msg = try sema.errMsg(block, init_src, template, args); 18366 } 18367 } 18368 } else { 18369 field_inits[i] = try sema.addConstant(field_ty.toType(), default_val.toValue()); 18370 } 18371 } 18372 }, 18373 .struct_type => |struct_type| { 18374 const struct_obj = mod.structPtrUnwrap(struct_type.index).?; 18375 for (struct_obj.fields.values(), 0..) |field, i| { 18376 if (field_inits[i] != .none) continue; 18377 18378 if (field.default_val.toIntern() == .unreachable_value) { 18379 const field_name = struct_obj.fields.keys()[i]; 18380 const template = "missing struct field: {s}"; 18381 const args = .{field_name}; 18382 if (root_msg) |msg| { 18383 try sema.errNote(block, init_src, msg, template, args); 18384 } else { 18385 root_msg = try sema.errMsg(block, init_src, template, args); 18386 } 18387 } else { 18388 field_inits[i] = try sema.addConstant(field.ty, field.default_val); 18389 } 18390 } 18391 }, 18392 else => unreachable, 18393 } 18394 18395 if (root_msg) |msg| { 18396 if (mod.typeToStruct(struct_ty)) |struct_obj| { 18397 const fqn = try struct_obj.getFullyQualifiedName(sema.mod); 18398 defer gpa.free(fqn); 18399 try sema.mod.errNoteNonLazy( 18400 struct_obj.srcLoc(sema.mod), 18401 msg, 18402 "struct '{s}' declared here", 18403 .{fqn}, 18404 ); 18405 } 18406 root_msg = null; 18407 return sema.failWithOwnedErrorMsg(msg); 18408 } 18409 18410 // Find which field forces the expression to be runtime, if any. 18411 const opt_runtime_index = for (field_inits, 0..) |field_init, i| { 18412 if (!(try sema.isComptimeKnown(field_init))) { 18413 break i; 18414 } 18415 } else null; 18416 18417 const runtime_index = opt_runtime_index orelse { 18418 const elems = try sema.arena.alloc(InternPool.Index, field_inits.len); 18419 for (elems, field_inits, 0..) |*elem, field_init, field_i| { 18420 elem.* = try (sema.resolveMaybeUndefVal(field_init) catch unreachable).? 18421 .intern(struct_ty.structFieldType(field_i, mod), mod); 18422 } 18423 const struct_val = try mod.intern(.{ .aggregate = .{ 18424 .ty = struct_ty.toIntern(), 18425 .storage = .{ .elems = elems }, 18426 } }); 18427 return sema.addConstantMaybeRef(block, struct_ty, struct_val.toValue(), is_ref); 18428 }; 18429 18430 if (is_ref) { 18431 try sema.resolveStructLayout(struct_ty); 18432 const target = sema.mod.getTarget(); 18433 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ 18434 .pointee_type = struct_ty, 18435 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 18436 }); 18437 const alloc = try block.addTy(.alloc, alloc_ty); 18438 for (field_inits, 0..) |field_init, i_usize| { 18439 const i = @intCast(u32, i_usize); 18440 const field_src = dest_src; 18441 const field_ptr = try sema.structFieldPtrByIndex(block, dest_src, alloc, i, field_src, struct_ty, true); 18442 try sema.storePtr(block, dest_src, field_ptr, field_init); 18443 } 18444 18445 return sema.makePtrConst(block, alloc); 18446 } 18447 18448 sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { 18449 error.NeededSourceLocation => { 18450 const decl = mod.declPtr(block.src_decl); 18451 const field_src = mod.initSrc(dest_src.node_offset.x, decl, runtime_index); 18452 try sema.requireRuntimeBlock(block, dest_src, field_src); 18453 unreachable; 18454 }, 18455 else => |e| return e, 18456 }; 18457 try sema.queueFullTypeResolution(struct_ty); 18458 return block.addAggregateInit(struct_ty, field_inits); 18459 } 18460 18461 fn zirStructInitAnon( 18462 sema: *Sema, 18463 block: *Block, 18464 inst: Zir.Inst.Index, 18465 is_ref: bool, 18466 ) CompileError!Air.Inst.Ref { 18467 const mod = sema.mod; 18468 const gpa = sema.gpa; 18469 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 18470 const src = inst_data.src(); 18471 const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index); 18472 const types = try sema.arena.alloc(InternPool.Index, extra.data.fields_len); 18473 const values = try sema.arena.alloc(InternPool.Index, types.len); 18474 var fields = std.AutoArrayHashMap(InternPool.NullTerminatedString, u32).init(sema.arena); 18475 try fields.ensureUnusedCapacity(types.len); 18476 18477 // Find which field forces the expression to be runtime, if any. 18478 const opt_runtime_index = rs: { 18479 var runtime_index: ?usize = null; 18480 var extra_index = extra.end; 18481 for (types, 0..) |*field_ty, i_usize| { 18482 const i = @intCast(u32, i_usize); 18483 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); 18484 extra_index = item.end; 18485 18486 const name = sema.code.nullTerminatedString(item.data.field_name); 18487 const name_ip = try mod.intern_pool.getOrPutString(gpa, name); 18488 const gop = fields.getOrPutAssumeCapacity(name_ip); 18489 if (gop.found_existing) { 18490 const msg = msg: { 18491 const decl = sema.mod.declPtr(block.src_decl); 18492 const field_src = mod.initSrc(src.node_offset.x, decl, i); 18493 const msg = try sema.errMsg(block, field_src, "duplicate field", .{}); 18494 errdefer msg.destroy(gpa); 18495 18496 const prev_source = mod.initSrc(src.node_offset.x, decl, gop.value_ptr.*); 18497 try sema.errNote(block, prev_source, msg, "other field here", .{}); 18498 break :msg msg; 18499 }; 18500 return sema.failWithOwnedErrorMsg(msg); 18501 } 18502 gop.value_ptr.* = i; 18503 18504 const init = try sema.resolveInst(item.data.init); 18505 field_ty.* = sema.typeOf(init).toIntern(); 18506 if (field_ty.toType().zigTypeTag(mod) == .Opaque) { 18507 const msg = msg: { 18508 const decl = sema.mod.declPtr(block.src_decl); 18509 const field_src = mod.initSrc(src.node_offset.x, decl, i); 18510 const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); 18511 errdefer msg.destroy(sema.gpa); 18512 18513 try sema.addDeclaredHereNote(msg, field_ty.toType()); 18514 break :msg msg; 18515 }; 18516 return sema.failWithOwnedErrorMsg(msg); 18517 } 18518 if (try sema.resolveMaybeUndefVal(init)) |init_val| { 18519 values[i] = try init_val.intern(field_ty.toType(), mod); 18520 } else { 18521 values[i] = .none; 18522 runtime_index = i; 18523 } 18524 } 18525 break :rs runtime_index; 18526 }; 18527 18528 const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ 18529 .names = fields.keys(), 18530 .types = types, 18531 .values = values, 18532 } }); 18533 18534 const runtime_index = opt_runtime_index orelse { 18535 const tuple_val = try mod.intern(.{ .aggregate = .{ 18536 .ty = tuple_ty, 18537 .storage = .{ .elems = values }, 18538 } }); 18539 return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref); 18540 }; 18541 18542 sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { 18543 error.NeededSourceLocation => { 18544 const decl = sema.mod.declPtr(block.src_decl); 18545 const field_src = mod.initSrc(src.node_offset.x, decl, runtime_index); 18546 try sema.requireRuntimeBlock(block, src, field_src); 18547 unreachable; 18548 }, 18549 else => |e| return e, 18550 }; 18551 18552 if (is_ref) { 18553 const target = sema.mod.getTarget(); 18554 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ 18555 .pointee_type = tuple_ty.toType(), 18556 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 18557 }); 18558 const alloc = try block.addTy(.alloc, alloc_ty); 18559 var extra_index = extra.end; 18560 for (types, 0..) |field_ty, i_usize| { 18561 const i = @intCast(u32, i_usize); 18562 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); 18563 extra_index = item.end; 18564 18565 const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 18566 .mutable = true, 18567 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 18568 .pointee_type = field_ty.toType(), 18569 }); 18570 if (values[i] == .none) { 18571 const init = try sema.resolveInst(item.data.init); 18572 const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); 18573 _ = try block.addBinOp(.store, field_ptr, init); 18574 } 18575 } 18576 18577 return sema.makePtrConst(block, alloc); 18578 } 18579 18580 const element_refs = try sema.arena.alloc(Air.Inst.Ref, types.len); 18581 var extra_index = extra.end; 18582 for (types, 0..) |_, i| { 18583 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); 18584 extra_index = item.end; 18585 element_refs[i] = try sema.resolveInst(item.data.init); 18586 } 18587 18588 return block.addAggregateInit(tuple_ty.toType(), element_refs); 18589 } 18590 18591 fn zirArrayInit( 18592 sema: *Sema, 18593 block: *Block, 18594 inst: Zir.Inst.Index, 18595 is_ref: bool, 18596 ) CompileError!Air.Inst.Ref { 18597 const mod = sema.mod; 18598 const gpa = sema.gpa; 18599 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 18600 const src = inst_data.src(); 18601 18602 const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); 18603 const args = sema.code.refSlice(extra.end, extra.data.operands_len); 18604 assert(args.len >= 2); // array_ty + at least one element 18605 18606 const array_ty = try sema.resolveType(block, src, args[0]); 18607 const sentinel_val = array_ty.sentinel(mod); 18608 18609 const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @boolToInt(sentinel_val != null)); 18610 defer gpa.free(resolved_args); 18611 for (args[1..], 0..) |arg, i| { 18612 const resolved_arg = try sema.resolveInst(arg); 18613 const elem_ty = if (array_ty.zigTypeTag(mod) == .Struct) 18614 array_ty.structFieldType(i, mod) 18615 else 18616 array_ty.elemType2(mod); 18617 resolved_args[i] = sema.coerce(block, elem_ty, resolved_arg, .unneeded) catch |err| switch (err) { 18618 error.NeededSourceLocation => { 18619 const decl = sema.mod.declPtr(block.src_decl); 18620 const elem_src = mod.initSrc(src.node_offset.x, decl, i); 18621 _ = try sema.coerce(block, elem_ty, resolved_arg, elem_src); 18622 unreachable; 18623 }, 18624 else => return err, 18625 }; 18626 } 18627 18628 if (sentinel_val) |some| { 18629 resolved_args[resolved_args.len - 1] = try sema.addConstant(array_ty.elemType2(mod), some); 18630 } 18631 18632 const opt_runtime_index: ?u32 = for (resolved_args, 0..) |arg, i| { 18633 const comptime_known = try sema.isComptimeKnown(arg); 18634 if (!comptime_known) break @intCast(u32, i); 18635 } else null; 18636 18637 const runtime_index = opt_runtime_index orelse { 18638 const elem_vals = try sema.arena.alloc(InternPool.Index, resolved_args.len); 18639 for (elem_vals, resolved_args, 0..) |*val, arg, i| { 18640 const elem_ty = if (array_ty.zigTypeTag(mod) == .Struct) 18641 array_ty.structFieldType(i, mod) 18642 else 18643 array_ty.elemType2(mod); 18644 // We checked that all args are comptime above. 18645 val.* = try ((sema.resolveMaybeUndefVal(arg) catch unreachable).?).intern(elem_ty, mod); 18646 } 18647 return sema.addConstantMaybeRef(block, array_ty, (try mod.intern(.{ .aggregate = .{ 18648 .ty = array_ty.toIntern(), 18649 .storage = .{ .elems = elem_vals }, 18650 } })).toValue(), is_ref); 18651 }; 18652 18653 sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { 18654 error.NeededSourceLocation => { 18655 const decl = sema.mod.declPtr(block.src_decl); 18656 const elem_src = mod.initSrc(src.node_offset.x, decl, runtime_index); 18657 try sema.requireRuntimeBlock(block, src, elem_src); 18658 unreachable; 18659 }, 18660 else => return err, 18661 }; 18662 try sema.queueFullTypeResolution(array_ty); 18663 18664 if (is_ref) { 18665 const target = sema.mod.getTarget(); 18666 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ 18667 .pointee_type = array_ty, 18668 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 18669 }); 18670 const alloc = try block.addTy(.alloc, alloc_ty); 18671 18672 if (array_ty.isTuple(mod)) { 18673 for (resolved_args, 0..) |arg, i| { 18674 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 18675 .mutable = true, 18676 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 18677 .pointee_type = array_ty.structFieldType(i, mod), 18678 }); 18679 const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty); 18680 18681 const index = try sema.addIntUnsigned(Type.usize, i); 18682 const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref); 18683 _ = try block.addBinOp(.store, elem_ptr, arg); 18684 } 18685 return sema.makePtrConst(block, alloc); 18686 } 18687 18688 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 18689 .mutable = true, 18690 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 18691 .pointee_type = array_ty.elemType2(mod), 18692 }); 18693 const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty); 18694 18695 for (resolved_args, 0..) |arg, i| { 18696 const index = try sema.addIntUnsigned(Type.usize, i); 18697 const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref); 18698 _ = try block.addBinOp(.store, elem_ptr, arg); 18699 } 18700 return sema.makePtrConst(block, alloc); 18701 } 18702 18703 return block.addAggregateInit(array_ty, resolved_args); 18704 } 18705 18706 fn zirArrayInitAnon( 18707 sema: *Sema, 18708 block: *Block, 18709 inst: Zir.Inst.Index, 18710 is_ref: bool, 18711 ) CompileError!Air.Inst.Ref { 18712 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 18713 const src = inst_data.src(); 18714 const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); 18715 const operands = sema.code.refSlice(extra.end, extra.data.operands_len); 18716 const mod = sema.mod; 18717 18718 const types = try sema.arena.alloc(InternPool.Index, operands.len); 18719 const values = try sema.arena.alloc(InternPool.Index, operands.len); 18720 18721 const opt_runtime_src = rs: { 18722 var runtime_src: ?LazySrcLoc = null; 18723 for (operands, 0..) |operand, i| { 18724 const operand_src = src; // TODO better source location 18725 const elem = try sema.resolveInst(operand); 18726 types[i] = sema.typeOf(elem).toIntern(); 18727 if (types[i].toType().zigTypeTag(mod) == .Opaque) { 18728 const msg = msg: { 18729 const msg = try sema.errMsg(block, operand_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); 18730 errdefer msg.destroy(sema.gpa); 18731 18732 try sema.addDeclaredHereNote(msg, types[i].toType()); 18733 break :msg msg; 18734 }; 18735 return sema.failWithOwnedErrorMsg(msg); 18736 } 18737 if (try sema.resolveMaybeUndefVal(elem)) |val| { 18738 values[i] = val.toIntern(); 18739 } else { 18740 values[i] = .none; 18741 runtime_src = operand_src; 18742 } 18743 } 18744 break :rs runtime_src; 18745 }; 18746 18747 const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ 18748 .types = types, 18749 .values = values, 18750 .names = &.{}, 18751 } }); 18752 18753 const runtime_src = opt_runtime_src orelse { 18754 const tuple_val = try mod.intern(.{ .aggregate = .{ 18755 .ty = tuple_ty, 18756 .storage = .{ .elems = values }, 18757 } }); 18758 return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref); 18759 }; 18760 18761 try sema.requireRuntimeBlock(block, src, runtime_src); 18762 18763 if (is_ref) { 18764 const target = sema.mod.getTarget(); 18765 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ 18766 .pointee_type = tuple_ty.toType(), 18767 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 18768 }); 18769 const alloc = try block.addTy(.alloc, alloc_ty); 18770 for (operands, 0..) |operand, i_usize| { 18771 const i = @intCast(u32, i_usize); 18772 const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 18773 .mutable = true, 18774 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 18775 .pointee_type = types[i].toType(), 18776 }); 18777 if (values[i] == .none) { 18778 const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); 18779 _ = try block.addBinOp(.store, field_ptr, try sema.resolveInst(operand)); 18780 } 18781 } 18782 18783 return sema.makePtrConst(block, alloc); 18784 } 18785 18786 const element_refs = try sema.arena.alloc(Air.Inst.Ref, operands.len); 18787 for (operands, 0..) |operand, i| { 18788 element_refs[i] = try sema.resolveInst(operand); 18789 } 18790 18791 return block.addAggregateInit(tuple_ty.toType(), element_refs); 18792 } 18793 18794 fn addConstantMaybeRef( 18795 sema: *Sema, 18796 block: *Block, 18797 ty: Type, 18798 val: Value, 18799 is_ref: bool, 18800 ) !Air.Inst.Ref { 18801 if (!is_ref) return sema.addConstant(ty, val); 18802 18803 var anon_decl = try block.startAnonDecl(); 18804 defer anon_decl.deinit(); 18805 const decl = try anon_decl.finish( 18806 ty, 18807 try val.copy(anon_decl.arena()), 18808 0, // default alignment 18809 ); 18810 return sema.analyzeDeclRef(decl); 18811 } 18812 18813 fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 18814 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 18815 const extra = sema.code.extraData(Zir.Inst.FieldTypeRef, inst_data.payload_index).data; 18816 const ty_src = inst_data.src(); 18817 const field_src = inst_data.src(); 18818 const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type); 18819 const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "field name must be comptime-known"); 18820 return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src); 18821 } 18822 18823 fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 18824 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 18825 const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data; 18826 const ty_src = inst_data.src(); 18827 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; 18828 const aggregate_ty = sema.resolveType(block, ty_src, extra.container_type) catch |err| switch (err) { 18829 // Since this is a ZIR instruction that returns a type, encountering 18830 // generic poison should not result in a failed compilation, but the 18831 // generic poison type. This prevents unnecessary failures when 18832 // constructing types at compile-time. 18833 error.GenericPoison => return Air.Inst.Ref.generic_poison_type, 18834 else => |e| return e, 18835 }; 18836 const field_name = sema.code.nullTerminatedString(extra.name_start); 18837 return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src); 18838 } 18839 18840 fn fieldType( 18841 sema: *Sema, 18842 block: *Block, 18843 aggregate_ty: Type, 18844 field_name: []const u8, 18845 field_src: LazySrcLoc, 18846 ty_src: LazySrcLoc, 18847 ) CompileError!Air.Inst.Ref { 18848 const mod = sema.mod; 18849 var cur_ty = aggregate_ty; 18850 while (true) { 18851 const resolved_ty = try sema.resolveTypeFields(cur_ty); 18852 cur_ty = resolved_ty; 18853 switch (cur_ty.zigTypeTag(mod)) { 18854 .Struct => switch (mod.intern_pool.indexToKey(cur_ty.toIntern())) { 18855 .anon_struct_type => |anon_struct| { 18856 const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src); 18857 return sema.addType(anon_struct.types[field_index].toType()); 18858 }, 18859 .struct_type => |struct_type| { 18860 const struct_obj = mod.structPtrUnwrap(struct_type.index).?; 18861 const field = struct_obj.fields.get(field_name) orelse 18862 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); 18863 return sema.addType(field.ty); 18864 }, 18865 else => unreachable, 18866 }, 18867 .Union => { 18868 const union_obj = mod.typeToUnion(cur_ty).?; 18869 const field = union_obj.fields.get(field_name) orelse 18870 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); 18871 return sema.addType(field.ty); 18872 }, 18873 .Optional => { 18874 // Struct/array init through optional requires the child type to not be a pointer. 18875 // If the child of .optional is a pointer it'll error on the next loop. 18876 cur_ty = mod.intern_pool.indexToKey(cur_ty.toIntern()).opt_type.toType(); 18877 continue; 18878 }, 18879 .ErrorUnion => { 18880 cur_ty = cur_ty.errorUnionPayload(mod); 18881 continue; 18882 }, 18883 else => {}, 18884 } 18885 return sema.fail(block, ty_src, "expected struct or union; found '{}'", .{ 18886 resolved_ty.fmt(sema.mod), 18887 }); 18888 } 18889 } 18890 18891 fn zirErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { 18892 return sema.getErrorReturnTrace(block); 18893 } 18894 18895 fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { 18896 const mod = sema.mod; 18897 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); 18898 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); 18899 const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); 18900 const opt_ptr_stack_trace_ty = try Type.optional(sema.arena, ptr_stack_trace_ty, mod); 18901 18902 if (sema.owner_func != null and 18903 sema.owner_func.?.calls_or_awaits_errorable_fn and 18904 mod.comp.bin_file.options.error_return_tracing and 18905 mod.backendSupportsFeature(.error_return_trace)) 18906 { 18907 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); 18908 } 18909 return sema.addConstant(opt_ptr_stack_trace_ty, (try mod.intern(.{ .opt = .{ 18910 .ty = opt_ptr_stack_trace_ty.toIntern(), 18911 .val = .none, 18912 } })).toValue()); 18913 } 18914 18915 fn zirFrame( 18916 sema: *Sema, 18917 block: *Block, 18918 extended: Zir.Inst.Extended.InstData, 18919 ) CompileError!Air.Inst.Ref { 18920 const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand)); 18921 return sema.failWithUseOfAsync(block, src); 18922 } 18923 18924 fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 18925 const mod = sema.mod; 18926 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 18927 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 18928 const ty = try sema.resolveType(block, operand_src, inst_data.operand); 18929 if (ty.isNoReturn(mod)) { 18930 return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.mod)}); 18931 } 18932 const val = try ty.lazyAbiAlignment(mod); 18933 if (val.isLazyAlign(mod)) { 18934 try sema.queueFullTypeResolution(ty); 18935 } 18936 return sema.addConstant(Type.comptime_int, val); 18937 } 18938 18939 fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 18940 const mod = sema.mod; 18941 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 18942 const operand = try sema.resolveInst(inst_data.operand); 18943 if (try sema.resolveMaybeUndefVal(operand)) |val| { 18944 if (val.isUndef(mod)) return sema.addConstUndef(Type.u1); 18945 if (val.toBool()) return sema.addConstant(Type.u1, try mod.intValue(Type.u1, 1)); 18946 return sema.addConstant(Type.u1, try mod.intValue(Type.u1, 0)); 18947 } 18948 return block.addUnOp(.bool_to_int, operand); 18949 } 18950 18951 fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 18952 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 18953 const operand = try sema.resolveInst(inst_data.operand); 18954 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 18955 18956 if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { 18957 const err_name = sema.mod.intern_pool.indexToKey(val.toIntern()).err.name; 18958 const bytes = sema.mod.intern_pool.stringToSlice(err_name); 18959 return sema.addStrLit(block, bytes); 18960 } 18961 18962 // Similar to zirTagName, we have special AIR instruction for the error name in case an optimimzation pass 18963 // might be able to resolve the result at compile time. 18964 return block.addUnOp(.error_name, operand); 18965 } 18966 18967 fn zirUnaryMath( 18968 sema: *Sema, 18969 block: *Block, 18970 inst: Zir.Inst.Index, 18971 air_tag: Air.Inst.Tag, 18972 comptime eval: fn (Value, Type, Allocator, *Module) Allocator.Error!Value, 18973 ) CompileError!Air.Inst.Ref { 18974 const tracy = trace(@src()); 18975 defer tracy.end(); 18976 18977 const mod = sema.mod; 18978 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 18979 const operand = try sema.resolveInst(inst_data.operand); 18980 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 18981 const operand_ty = sema.typeOf(operand); 18982 18983 switch (operand_ty.zigTypeTag(mod)) { 18984 .ComptimeFloat, .Float => {}, 18985 .Vector => { 18986 const scalar_ty = operand_ty.scalarType(mod); 18987 switch (scalar_ty.zigTypeTag(mod)) { 18988 .ComptimeFloat, .Float => {}, 18989 else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{scalar_ty.fmt(sema.mod)}), 18990 } 18991 }, 18992 else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{operand_ty.fmt(sema.mod)}), 18993 } 18994 18995 switch (operand_ty.zigTypeTag(mod)) { 18996 .Vector => { 18997 const scalar_ty = operand_ty.scalarType(mod); 18998 const vec_len = operand_ty.vectorLen(mod); 18999 const result_ty = try mod.vectorType(.{ 19000 .len = vec_len, 19001 .child = scalar_ty.toIntern(), 19002 }); 19003 if (try sema.resolveMaybeUndefVal(operand)) |val| { 19004 if (val.isUndef(mod)) 19005 return sema.addConstUndef(result_ty); 19006 19007 const elems = try sema.arena.alloc(InternPool.Index, vec_len); 19008 for (elems, 0..) |*elem, i| { 19009 const elem_val = try val.elemValue(sema.mod, i); 19010 elem.* = try (try eval(elem_val, scalar_ty, sema.arena, sema.mod)).intern(scalar_ty, mod); 19011 } 19012 return sema.addConstant(result_ty, (try mod.intern(.{ .aggregate = .{ 19013 .ty = result_ty.toIntern(), 19014 .storage = .{ .elems = elems }, 19015 } })).toValue()); 19016 } 19017 19018 try sema.requireRuntimeBlock(block, operand_src, null); 19019 return block.addUnOp(air_tag, operand); 19020 }, 19021 .ComptimeFloat, .Float => { 19022 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { 19023 if (operand_val.isUndef(mod)) 19024 return sema.addConstUndef(operand_ty); 19025 const result_val = try eval(operand_val, operand_ty, sema.arena, sema.mod); 19026 return sema.addConstant(operand_ty, result_val); 19027 } 19028 19029 try sema.requireRuntimeBlock(block, operand_src, null); 19030 return block.addUnOp(air_tag, operand); 19031 }, 19032 else => unreachable, 19033 } 19034 } 19035 19036 fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 19037 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 19038 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 19039 const src = inst_data.src(); 19040 const operand = try sema.resolveInst(inst_data.operand); 19041 const operand_ty = sema.typeOf(operand); 19042 const mod = sema.mod; 19043 19044 try sema.resolveTypeLayout(operand_ty); 19045 const enum_ty = switch (operand_ty.zigTypeTag(mod)) { 19046 .EnumLiteral => { 19047 const val = try sema.resolveConstValue(block, .unneeded, operand, ""); 19048 const tag_name = mod.intern_pool.indexToKey(val.toIntern()).enum_literal; 19049 const bytes = mod.intern_pool.stringToSlice(tag_name); 19050 return sema.addStrLit(block, bytes); 19051 }, 19052 .Enum => operand_ty, 19053 .Union => operand_ty.unionTagType(mod) orelse { 19054 const msg = msg: { 19055 const msg = try sema.errMsg(block, src, "union '{}' is untagged", .{ 19056 operand_ty.fmt(sema.mod), 19057 }); 19058 errdefer msg.destroy(sema.gpa); 19059 try sema.addDeclaredHereNote(msg, operand_ty); 19060 break :msg msg; 19061 }; 19062 return sema.failWithOwnedErrorMsg(msg); 19063 }, 19064 else => return sema.fail(block, operand_src, "expected enum or union; found '{}'", .{ 19065 operand_ty.fmt(mod), 19066 }), 19067 }; 19068 if (enum_ty.enumFieldCount(mod) == 0) { 19069 // TODO I don't think this is the correct way to handle this but 19070 // it prevents a crash. 19071 return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{}'", .{ 19072 enum_ty.fmt(mod), 19073 }); 19074 } 19075 const enum_decl_index = enum_ty.getOwnerDecl(mod); 19076 const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src); 19077 if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| { 19078 const field_index = enum_ty.enumTagFieldIndex(val, mod) orelse { 19079 const enum_decl = mod.declPtr(enum_decl_index); 19080 const msg = msg: { 19081 const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{s}'", .{ 19082 val.fmtValue(enum_ty, sema.mod), enum_decl.name, 19083 }); 19084 errdefer msg.destroy(sema.gpa); 19085 try mod.errNoteNonLazy(enum_decl.srcLoc(mod), msg, "declared here", .{}); 19086 break :msg msg; 19087 }; 19088 return sema.failWithOwnedErrorMsg(msg); 19089 }; 19090 const field_name = enum_ty.enumFieldName(field_index, mod); 19091 return sema.addStrLit(block, field_name); 19092 } 19093 try sema.requireRuntimeBlock(block, src, operand_src); 19094 if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) { 19095 const ok = try block.addUnOp(.is_named_enum_value, casted_operand); 19096 try sema.addSafetyCheck(block, ok, .invalid_enum_value); 19097 } 19098 // In case the value is runtime-known, we have an AIR instruction for this instead 19099 // of trying to lower it in Sema because an optimization pass may result in the operand 19100 // being comptime-known, which would let us elide the `tag_name` AIR instruction. 19101 return block.addUnOp(.tag_name, casted_operand); 19102 } 19103 19104 fn zirReify( 19105 sema: *Sema, 19106 block: *Block, 19107 extended: Zir.Inst.Extended.InstData, 19108 inst: Zir.Inst.Index, 19109 ) CompileError!Air.Inst.Ref { 19110 const mod = sema.mod; 19111 const gpa = sema.gpa; 19112 const name_strategy = @intToEnum(Zir.Inst.NameStrategy, extended.small); 19113 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 19114 const src = LazySrcLoc.nodeOffset(extra.node); 19115 const type_info_ty = try sema.getBuiltinType("Type"); 19116 const uncasted_operand = try sema.resolveInst(extra.operand); 19117 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 19118 const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src); 19119 const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime-known"); 19120 const union_val = mod.intern_pool.indexToKey(val.toIntern()).un; 19121 const target = mod.getTarget(); 19122 if (try union_val.val.toValue().anyUndef(mod)) return sema.failWithUseOfUndef(block, src); 19123 const tag_index = type_info_ty.unionTagFieldIndex(union_val.tag.toValue(), mod).?; 19124 const ip = &mod.intern_pool; 19125 switch (@intToEnum(std.builtin.TypeId, tag_index)) { 19126 .Type => return Air.Inst.Ref.type_type, 19127 .Void => return Air.Inst.Ref.void_type, 19128 .Bool => return Air.Inst.Ref.bool_type, 19129 .NoReturn => return Air.Inst.Ref.noreturn_type, 19130 .ComptimeFloat => return Air.Inst.Ref.comptime_float_type, 19131 .ComptimeInt => return Air.Inst.Ref.comptime_int_type, 19132 .Undefined => return Air.Inst.Ref.undefined_type, 19133 .Null => return Air.Inst.Ref.null_type, 19134 .AnyFrame => return sema.failWithUseOfAsync(block, src), 19135 .EnumLiteral => return Air.Inst.Ref.enum_literal_type, 19136 .Int => { 19137 const fields = ip.typeOf(union_val.val).toType().structFields(mod); 19138 const signedness_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("signedness").?); 19139 const bits_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("bits").?); 19140 19141 const signedness = mod.toEnum(std.builtin.Signedness, signedness_val); 19142 const bits = @intCast(u16, bits_val.toUnsignedInt(mod)); 19143 const ty = try mod.intType(signedness, bits); 19144 return sema.addType(ty); 19145 }, 19146 .Vector => { 19147 const fields = ip.typeOf(union_val.val).toType().structFields(mod); 19148 const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("len").?); 19149 const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("child").?); 19150 19151 const len = @intCast(u32, len_val.toUnsignedInt(mod)); 19152 const child_ty = child_val.toType(); 19153 19154 try sema.checkVectorElemType(block, src, child_ty); 19155 19156 const ty = try mod.vectorType(.{ 19157 .len = len, 19158 .child = child_ty.toIntern(), 19159 }); 19160 return sema.addType(ty); 19161 }, 19162 .Float => { 19163 const fields = ip.typeOf(union_val.val).toType().structFields(mod); 19164 const bits_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("bits").?); 19165 19166 const bits = @intCast(u16, bits_val.toUnsignedInt(mod)); 19167 const ty = switch (bits) { 19168 16 => Type.f16, 19169 32 => Type.f32, 19170 64 => Type.f64, 19171 80 => Type.f80, 19172 128 => Type.f128, 19173 else => return sema.fail(block, src, "{}-bit float unsupported", .{bits}), 19174 }; 19175 return sema.addType(ty); 19176 }, 19177 .Pointer => { 19178 const fields = ip.typeOf(union_val.val).toType().structFields(mod); 19179 const size_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("size").?); 19180 const is_const_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_const").?); 19181 const is_volatile_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_volatile").?); 19182 const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("alignment").?); 19183 const address_space_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("address_space").?); 19184 const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("child").?); 19185 const is_allowzero_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_allowzero").?); 19186 const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("sentinel").?); 19187 19188 if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { 19189 return sema.fail(block, src, "alignment must fit in 'u32'", .{}); 19190 } 19191 19192 const abi_align = InternPool.Alignment.fromByteUnits( 19193 (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?, 19194 ); 19195 19196 const unresolved_elem_ty = child_val.toType(); 19197 const elem_ty = if (abi_align == .none) 19198 unresolved_elem_ty 19199 else t: { 19200 const elem_ty = try sema.resolveTypeFields(unresolved_elem_ty); 19201 try sema.resolveTypeLayout(elem_ty); 19202 break :t elem_ty; 19203 }; 19204 19205 const ptr_size = mod.toEnum(std.builtin.Type.Pointer.Size, size_val); 19206 19207 const actual_sentinel: InternPool.Index = s: { 19208 if (!sentinel_val.isNull(mod)) { 19209 if (ptr_size == .One or ptr_size == .C) { 19210 return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{}); 19211 } 19212 const sentinel_ptr_val = sentinel_val.optionalValue(mod).?; 19213 const ptr_ty = try Type.ptr(sema.arena, mod, .{ 19214 .@"addrspace" = .generic, 19215 .pointee_type = elem_ty, 19216 }); 19217 const sent_val = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?; 19218 break :s sent_val.toIntern(); 19219 } 19220 break :s .none; 19221 }; 19222 19223 if (elem_ty.zigTypeTag(mod) == .NoReturn) { 19224 return sema.fail(block, src, "pointer to noreturn not allowed", .{}); 19225 } else if (elem_ty.zigTypeTag(mod) == .Fn) { 19226 if (ptr_size != .One) { 19227 return sema.fail(block, src, "function pointers must be single pointers", .{}); 19228 } 19229 const fn_align = mod.typeToFunc(elem_ty).?.alignment; 19230 if (abi_align != .none and fn_align != .none and 19231 abi_align != fn_align) 19232 { 19233 return sema.fail(block, src, "function pointer alignment disagrees with function alignment", .{}); 19234 } 19235 } else if (ptr_size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) { 19236 return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); 19237 } else if (ptr_size == .C) { 19238 if (!try sema.validateExternType(elem_ty, .other)) { 19239 const msg = msg: { 19240 const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(mod)}); 19241 errdefer msg.destroy(gpa); 19242 19243 const src_decl = mod.declPtr(block.src_decl); 19244 try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), elem_ty, .other); 19245 19246 try sema.addDeclaredHereNote(msg, elem_ty); 19247 break :msg msg; 19248 }; 19249 return sema.failWithOwnedErrorMsg(msg); 19250 } 19251 if (elem_ty.zigTypeTag(mod) == .Opaque) { 19252 return sema.fail(block, src, "C pointers cannot point to opaque types", .{}); 19253 } 19254 } 19255 19256 const ty = try mod.ptrType(.{ 19257 .child = elem_ty.toIntern(), 19258 .sentinel = actual_sentinel, 19259 .flags = .{ 19260 .size = ptr_size, 19261 .is_const = is_const_val.toBool(), 19262 .is_volatile = is_volatile_val.toBool(), 19263 .alignment = abi_align, 19264 .address_space = mod.toEnum(std.builtin.AddressSpace, address_space_val), 19265 .is_allowzero = is_allowzero_val.toBool(), 19266 }, 19267 }); 19268 return sema.addType(ty); 19269 }, 19270 .Array => { 19271 const fields = ip.typeOf(union_val.val).toType().structFields(mod); 19272 const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("len").?); 19273 const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("child").?); 19274 const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("sentinel").?); 19275 19276 const len = len_val.toUnsignedInt(mod); 19277 const child_ty = child_val.toType(); 19278 const sentinel = if (sentinel_val.optionalValue(mod)) |p| blk: { 19279 const ptr_ty = try Type.ptr(sema.arena, mod, .{ 19280 .@"addrspace" = .generic, 19281 .pointee_type = child_ty, 19282 }); 19283 break :blk (try sema.pointerDeref(block, src, p, ptr_ty)).?; 19284 } else null; 19285 19286 const ty = try Type.array(sema.arena, len, sentinel, child_ty, mod); 19287 return sema.addType(ty); 19288 }, 19289 .Optional => { 19290 const fields = ip.typeOf(union_val.val).toType().structFields(mod); 19291 const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("child").?); 19292 19293 const child_ty = child_val.toType(); 19294 19295 const ty = try Type.optional(sema.arena, child_ty, mod); 19296 return sema.addType(ty); 19297 }, 19298 .ErrorUnion => { 19299 const fields = ip.typeOf(union_val.val).toType().structFields(mod); 19300 const error_set_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("error_set").?); 19301 const payload_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("payload").?); 19302 19303 const error_set_ty = error_set_val.toType(); 19304 const payload_ty = payload_val.toType(); 19305 19306 if (error_set_ty.zigTypeTag(mod) != .ErrorSet) { 19307 return sema.fail(block, src, "Type.ErrorUnion.error_set must be an error set type", .{}); 19308 } 19309 19310 const ty = try mod.errorUnionType(error_set_ty, payload_ty); 19311 return sema.addType(ty); 19312 }, 19313 .ErrorSet => { 19314 const payload_val = union_val.val.toValue().optionalValue(mod) orelse 19315 return sema.addType(Type.anyerror); 19316 19317 const len = try sema.usizeCast(block, src, payload_val.sliceLen(mod)); 19318 var names: Module.Fn.InferredErrorSet.NameMap = .{}; 19319 try names.ensureUnusedCapacity(sema.arena, len); 19320 for (0..len) |i| { 19321 const elem_val = try payload_val.elemValue(mod, i); 19322 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); 19323 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?); 19324 19325 const name_str = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); 19326 const kv = try mod.getErrorValue(name_str); 19327 const name_ip = try mod.intern_pool.getOrPutString(gpa, kv.key); 19328 const gop = names.getOrPutAssumeCapacity(name_ip); 19329 if (gop.found_existing) { 19330 return sema.fail(block, src, "duplicate error '{s}'", .{name_str}); 19331 } 19332 } 19333 19334 const ty = try mod.errorSetFromUnsortedNames(names.keys()); 19335 return sema.addType(ty); 19336 }, 19337 .Struct => { 19338 const fields = ip.typeOf(union_val.val).toType().structFields(mod); 19339 const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("layout").?); 19340 const backing_integer_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("backing_integer").?); 19341 const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("fields").?); 19342 const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("decls").?); 19343 const is_tuple_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_tuple").?); 19344 19345 const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); 19346 19347 // Decls 19348 if (decls_val.sliceLen(mod) > 0) { 19349 return sema.fail(block, src, "reified structs must have no decls", .{}); 19350 } 19351 19352 if (layout != .Packed and !backing_integer_val.isNull(mod)) { 19353 return sema.fail(block, src, "non-packed struct does not support backing integer type", .{}); 19354 } 19355 19356 return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool()); 19357 }, 19358 .Enum => { 19359 const fields = ip.typeOf(union_val.val).toType().structFields(mod); 19360 const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("tag_type").?); 19361 const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("fields").?); 19362 const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("decls").?); 19363 const is_exhaustive_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_exhaustive").?); 19364 19365 // Decls 19366 if (decls_val.sliceLen(mod) > 0) { 19367 return sema.fail(block, src, "reified enums must have no decls", .{}); 19368 } 19369 19370 const int_tag_ty = tag_type_val.toType(); 19371 if (int_tag_ty.zigTypeTag(mod) != .Int) { 19372 return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{}); 19373 } 19374 19375 // Because these things each reference each other, `undefined` 19376 // placeholders are used before being set after the enum type gains 19377 // an InternPool index. 19378 19379 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 19380 .ty = Type.type, 19381 .val = undefined, 19382 }, name_strategy, "enum", inst); 19383 const new_decl = mod.declPtr(new_decl_index); 19384 new_decl.owns_tv = true; 19385 errdefer mod.abortAnonDecl(new_decl_index); 19386 19387 // Define our empty enum decl 19388 const fields_len = @intCast(u32, try sema.usizeCast(block, src, fields_val.sliceLen(mod))); 19389 const incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{ 19390 .decl = new_decl_index, 19391 .namespace = .none, 19392 .fields_len = fields_len, 19393 .has_values = true, 19394 .tag_mode = if (!is_exhaustive_val.toBool()) 19395 .nonexhaustive 19396 else 19397 .explicit, 19398 .tag_ty = int_tag_ty.toIntern(), 19399 }); 19400 errdefer mod.intern_pool.remove(incomplete_enum.index); 19401 19402 new_decl.val = incomplete_enum.index.toValue(); 19403 19404 for (0..fields_len) |field_i| { 19405 const elem_val = try fields_val.elemValue(mod, field_i); 19406 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); 19407 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?); 19408 const value_val = try elem_val.fieldValue(mod, elem_fields.getIndex("value").?); 19409 19410 const field_name = try name_val.toAllocatedBytes( 19411 Type.slice_const_u8, 19412 sema.arena, 19413 mod, 19414 ); 19415 const field_name_ip = try mod.intern_pool.getOrPutString(gpa, field_name); 19416 19417 if (!try sema.intFitsInType(value_val, int_tag_ty, null)) { 19418 // TODO: better source location 19419 return sema.fail(block, src, "field '{s}' with enumeration value '{}' is too large for backing int type '{}'", .{ 19420 field_name, 19421 value_val.fmtValue(Type.comptime_int, mod), 19422 int_tag_ty.fmt(mod), 19423 }); 19424 } 19425 19426 if (try incomplete_enum.addFieldName(&mod.intern_pool, gpa, field_name_ip)) |other_index| { 19427 const msg = msg: { 19428 const msg = try sema.errMsg(block, src, "duplicate enum field '{s}'", .{field_name}); 19429 errdefer msg.destroy(gpa); 19430 _ = other_index; // TODO: this note is incorrect 19431 try sema.errNote(block, src, msg, "other field here", .{}); 19432 break :msg msg; 19433 }; 19434 return sema.failWithOwnedErrorMsg(msg); 19435 } 19436 19437 if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, (try mod.getCoerced(value_val, int_tag_ty)).toIntern())) |other| { 19438 const msg = msg: { 19439 const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)}); 19440 errdefer msg.destroy(gpa); 19441 _ = other; // TODO: this note is incorrect 19442 try sema.errNote(block, src, msg, "other enum tag value here", .{}); 19443 break :msg msg; 19444 }; 19445 return sema.failWithOwnedErrorMsg(msg); 19446 } 19447 } 19448 19449 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); 19450 try mod.finalizeAnonDecl(new_decl_index); 19451 return decl_val; 19452 }, 19453 .Opaque => { 19454 const fields = ip.typeOf(union_val.val).toType().structFields(mod); 19455 const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("decls").?); 19456 19457 // Decls 19458 if (decls_val.sliceLen(mod) > 0) { 19459 return sema.fail(block, src, "reified opaque must have no decls", .{}); 19460 } 19461 19462 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 19463 errdefer new_decl_arena.deinit(); 19464 19465 // Because these three things each reference each other, 19466 // `undefined` placeholders are used in two places before being set 19467 // after the opaque type gains an InternPool index. 19468 19469 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 19470 .ty = Type.type, 19471 .val = undefined, 19472 }, name_strategy, "opaque", inst); 19473 const new_decl = mod.declPtr(new_decl_index); 19474 new_decl.owns_tv = true; 19475 errdefer mod.abortAnonDecl(new_decl_index); 19476 19477 const new_namespace_index = try mod.createNamespace(.{ 19478 .parent = block.namespace.toOptional(), 19479 .ty = undefined, 19480 .file_scope = block.getFileScope(mod), 19481 }); 19482 const new_namespace = mod.namespacePtr(new_namespace_index); 19483 errdefer mod.destroyNamespace(new_namespace_index); 19484 19485 const opaque_ty = try mod.intern(.{ .opaque_type = .{ 19486 .decl = new_decl_index, 19487 .namespace = new_namespace_index, 19488 } }); 19489 errdefer mod.intern_pool.remove(opaque_ty); 19490 19491 new_decl.val = opaque_ty.toValue(); 19492 new_namespace.ty = opaque_ty.toType(); 19493 19494 try new_decl.finalizeNewArena(&new_decl_arena); 19495 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); 19496 try mod.finalizeAnonDecl(new_decl_index); 19497 return decl_val; 19498 }, 19499 .Union => { 19500 const fields = ip.typeOf(union_val.val).toType().structFields(mod); 19501 const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("layout").?); 19502 const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("tag_type").?); 19503 const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("fields").?); 19504 const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("decls").?); 19505 19506 // Decls 19507 if (decls_val.sliceLen(mod) > 0) { 19508 return sema.fail(block, src, "reified unions must have no decls", .{}); 19509 } 19510 const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); 19511 19512 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 19513 errdefer new_decl_arena.deinit(); 19514 const new_decl_arena_allocator = new_decl_arena.allocator(); 19515 19516 // Because these three things each reference each other, `undefined` 19517 // placeholders are used before being set after the union type gains an 19518 // InternPool index. 19519 19520 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 19521 .ty = Type.type, 19522 .val = undefined, 19523 }, name_strategy, "union", inst); 19524 const new_decl = mod.declPtr(new_decl_index); 19525 new_decl.owns_tv = true; 19526 errdefer mod.abortAnonDecl(new_decl_index); 19527 19528 const new_namespace_index = try mod.createNamespace(.{ 19529 .parent = block.namespace.toOptional(), 19530 .ty = undefined, 19531 .file_scope = block.getFileScope(mod), 19532 }); 19533 const new_namespace = mod.namespacePtr(new_namespace_index); 19534 errdefer mod.destroyNamespace(new_namespace_index); 19535 19536 const union_index = try mod.createUnion(.{ 19537 .owner_decl = new_decl_index, 19538 .tag_ty = Type.null, 19539 .fields = .{}, 19540 .zir_index = inst, 19541 .layout = layout, 19542 .status = .have_field_types, 19543 .namespace = new_namespace_index, 19544 }); 19545 const union_obj = mod.unionPtr(union_index); 19546 errdefer mod.destroyUnion(union_index); 19547 19548 const union_ty = try mod.intern_pool.get(gpa, .{ .union_type = .{ 19549 .index = union_index, 19550 .runtime_tag = if (!tag_type_val.isNull(mod)) 19551 .tagged 19552 else if (layout != .Auto) 19553 .none 19554 else switch (mod.optimizeMode()) { 19555 .Debug, .ReleaseSafe => .safety, 19556 .ReleaseFast, .ReleaseSmall => .none, 19557 }, 19558 } }); 19559 errdefer mod.intern_pool.remove(union_ty); 19560 19561 new_decl.val = union_ty.toValue(); 19562 new_namespace.ty = union_ty.toType(); 19563 19564 // Tag type 19565 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); 19566 var explicit_tags_seen: []bool = &.{}; 19567 var explicit_enum_info: ?InternPool.Key.EnumType = null; 19568 var enum_field_names: []InternPool.NullTerminatedString = &.{}; 19569 if (tag_type_val.optionalValue(mod)) |payload_val| { 19570 union_obj.tag_ty = payload_val.toType(); 19571 19572 const enum_type = switch (mod.intern_pool.indexToKey(union_obj.tag_ty.toIntern())) { 19573 .enum_type => |x| x, 19574 else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}), 19575 }; 19576 19577 explicit_enum_info = enum_type; 19578 explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len); 19579 @memset(explicit_tags_seen, false); 19580 } else { 19581 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len); 19582 } 19583 19584 // Fields 19585 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); 19586 19587 for (0..fields_len) |i| { 19588 const elem_val = try fields_val.elemValue(mod, i); 19589 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); 19590 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?); 19591 const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex("type").?); 19592 const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex("alignment").?); 19593 19594 const field_name = try name_val.toAllocatedBytes( 19595 Type.slice_const_u8, 19596 new_decl_arena_allocator, 19597 mod, 19598 ); 19599 19600 const field_name_ip = try mod.intern_pool.getOrPutString(gpa, field_name); 19601 19602 if (enum_field_names.len != 0) { 19603 enum_field_names[i] = field_name_ip; 19604 } 19605 19606 if (explicit_enum_info) |tag_info| { 19607 const enum_index = tag_info.nameIndex(&mod.intern_pool, field_name_ip) orelse { 19608 const msg = msg: { 19609 const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(mod) }); 19610 errdefer msg.destroy(gpa); 19611 try sema.addDeclaredHereNote(msg, union_obj.tag_ty); 19612 break :msg msg; 19613 }; 19614 return sema.failWithOwnedErrorMsg(msg); 19615 }; 19616 // No check for duplicate because the check already happened in order 19617 // to create the enum type in the first place. 19618 assert(!explicit_tags_seen[enum_index]); 19619 explicit_tags_seen[enum_index] = true; 19620 } 19621 19622 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); 19623 if (gop.found_existing) { 19624 // TODO: better source location 19625 return sema.fail(block, src, "duplicate union field {s}", .{field_name}); 19626 } 19627 19628 const field_ty = type_val.toType(); 19629 gop.value_ptr.* = .{ 19630 .ty = field_ty, 19631 .abi_align = @intCast(u32, (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?), 19632 }; 19633 19634 if (field_ty.zigTypeTag(mod) == .Opaque) { 19635 const msg = msg: { 19636 const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{}); 19637 errdefer msg.destroy(gpa); 19638 19639 try sema.addDeclaredHereNote(msg, field_ty); 19640 break :msg msg; 19641 }; 19642 return sema.failWithOwnedErrorMsg(msg); 19643 } 19644 if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) { 19645 const msg = msg: { 19646 const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)}); 19647 errdefer msg.destroy(gpa); 19648 19649 const src_decl = mod.declPtr(block.src_decl); 19650 try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .union_field); 19651 19652 try sema.addDeclaredHereNote(msg, field_ty); 19653 break :msg msg; 19654 }; 19655 return sema.failWithOwnedErrorMsg(msg); 19656 } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) { 19657 const msg = msg: { 19658 const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)}); 19659 errdefer msg.destroy(gpa); 19660 19661 const src_decl = mod.declPtr(block.src_decl); 19662 try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty); 19663 19664 try sema.addDeclaredHereNote(msg, field_ty); 19665 break :msg msg; 19666 }; 19667 return sema.failWithOwnedErrorMsg(msg); 19668 } 19669 } 19670 19671 if (explicit_enum_info) |tag_info| { 19672 if (tag_info.names.len > fields_len) { 19673 const msg = msg: { 19674 const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{}); 19675 errdefer msg.destroy(gpa); 19676 19677 const enum_ty = union_obj.tag_ty; 19678 for (tag_info.names, 0..) |field_name, field_index| { 19679 if (explicit_tags_seen[field_index]) continue; 19680 try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{ 19681 mod.intern_pool.stringToSlice(field_name), 19682 }); 19683 } 19684 try sema.addDeclaredHereNote(msg, union_obj.tag_ty); 19685 break :msg msg; 19686 }; 19687 return sema.failWithOwnedErrorMsg(msg); 19688 } 19689 } else { 19690 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, enum_field_names, null); 19691 } 19692 19693 try new_decl.finalizeNewArena(&new_decl_arena); 19694 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); 19695 try mod.finalizeAnonDecl(new_decl_index); 19696 return decl_val; 19697 }, 19698 .Fn => { 19699 const fields = ip.typeOf(union_val.val).toType().structFields(mod); 19700 const calling_convention_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("calling_convention").?); 19701 const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("alignment").?); 19702 const is_generic_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_generic").?); 19703 const is_var_args_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_var_args").?); 19704 const return_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("return_type").?); 19705 const params_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("params").?); 19706 19707 const is_generic = is_generic_val.toBool(); 19708 if (is_generic) { 19709 return sema.fail(block, src, "Type.Fn.is_generic must be false for @Type", .{}); 19710 } 19711 19712 const is_var_args = is_var_args_val.toBool(); 19713 const cc = mod.toEnum(std.builtin.CallingConvention, calling_convention_val); 19714 if (is_var_args and cc != .C) { 19715 return sema.fail(block, src, "varargs functions must have C calling convention", .{}); 19716 } 19717 19718 const alignment = alignment: { 19719 if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { 19720 return sema.fail(block, src, "alignment must fit in 'u32'", .{}); 19721 } 19722 const alignment = @intCast(u29, alignment_val.toUnsignedInt(mod)); 19723 if (alignment == target_util.defaultFunctionAlignment(target)) { 19724 break :alignment .none; 19725 } else { 19726 break :alignment InternPool.Alignment.fromByteUnits(alignment); 19727 } 19728 }; 19729 const return_type = return_type_val.optionalValue(mod) orelse 19730 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); 19731 19732 const args_len = try sema.usizeCast(block, src, params_val.sliceLen(mod)); 19733 const param_types = try sema.arena.alloc(InternPool.Index, args_len); 19734 19735 var noalias_bits: u32 = 0; 19736 for (param_types, 0..) |*param_type, i| { 19737 const elem_val = try params_val.elemValue(mod, i); 19738 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); 19739 const param_is_generic_val = try elem_val.fieldValue(mod, elem_fields.getIndex("is_generic").?); 19740 const param_is_noalias_val = try elem_val.fieldValue(mod, elem_fields.getIndex("is_noalias").?); 19741 const opt_param_type_val = try elem_val.fieldValue(mod, elem_fields.getIndex("type").?); 19742 19743 if (param_is_generic_val.toBool()) { 19744 return sema.fail(block, src, "Type.Fn.Param.is_generic must be false for @Type", .{}); 19745 } 19746 19747 const param_type_val = opt_param_type_val.optionalValue(mod) orelse 19748 return sema.fail(block, src, "Type.Fn.Param.arg_type must be non-null for @Type", .{}); 19749 param_type.* = param_type_val.toIntern(); 19750 19751 if (param_is_noalias_val.toBool()) { 19752 if (!param_type.toType().isPtrAtRuntime(mod)) { 19753 return sema.fail(block, src, "non-pointer parameter declared noalias", .{}); 19754 } 19755 noalias_bits |= @as(u32, 1) << (std.math.cast(u5, i) orelse 19756 return sema.fail(block, src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{})); 19757 } 19758 } 19759 19760 const ty = try mod.funcType(.{ 19761 .param_types = param_types, 19762 .comptime_bits = 0, 19763 .noalias_bits = noalias_bits, 19764 .return_type = return_type.toIntern(), 19765 .alignment = alignment, 19766 .cc = cc, 19767 .is_var_args = is_var_args, 19768 .is_generic = false, 19769 .is_noinline = false, 19770 .align_is_generic = false, 19771 .cc_is_generic = false, 19772 .section_is_generic = false, 19773 .addrspace_is_generic = false, 19774 }); 19775 return sema.addType(ty); 19776 }, 19777 .Frame => return sema.failWithUseOfAsync(block, src), 19778 } 19779 } 19780 19781 fn reifyStruct( 19782 sema: *Sema, 19783 block: *Block, 19784 inst: Zir.Inst.Index, 19785 src: LazySrcLoc, 19786 layout: std.builtin.Type.ContainerLayout, 19787 backing_int_val: Value, 19788 fields_val: Value, 19789 name_strategy: Zir.Inst.NameStrategy, 19790 is_tuple: bool, 19791 ) CompileError!Air.Inst.Ref { 19792 const mod = sema.mod; 19793 const gpa = sema.gpa; 19794 19795 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 19796 errdefer new_decl_arena.deinit(); 19797 const new_decl_arena_allocator = new_decl_arena.allocator(); 19798 19799 // Because these three things each reference each other, `undefined` 19800 // placeholders are used before being set after the struct type gains an 19801 // InternPool index. 19802 19803 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 19804 .ty = Type.type, 19805 .val = undefined, 19806 }, name_strategy, "struct", inst); 19807 const new_decl = mod.declPtr(new_decl_index); 19808 new_decl.owns_tv = true; 19809 errdefer mod.abortAnonDecl(new_decl_index); 19810 19811 const new_namespace_index = try mod.createNamespace(.{ 19812 .parent = block.namespace.toOptional(), 19813 .ty = undefined, 19814 .file_scope = block.getFileScope(mod), 19815 }); 19816 const new_namespace = mod.namespacePtr(new_namespace_index); 19817 errdefer mod.destroyNamespace(new_namespace_index); 19818 19819 const struct_index = try mod.createStruct(.{ 19820 .owner_decl = new_decl_index, 19821 .fields = .{}, 19822 .zir_index = inst, 19823 .layout = layout, 19824 .status = .have_field_types, 19825 .known_non_opv = false, 19826 .is_tuple = is_tuple, 19827 .namespace = new_namespace_index, 19828 }); 19829 const struct_obj = mod.structPtr(struct_index); 19830 errdefer mod.destroyStruct(struct_index); 19831 19832 const struct_ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{ 19833 .index = struct_index.toOptional(), 19834 .namespace = new_namespace_index.toOptional(), 19835 } }); 19836 errdefer mod.intern_pool.remove(struct_ty); 19837 19838 new_decl.val = struct_ty.toValue(); 19839 new_namespace.ty = struct_ty.toType(); 19840 19841 // Fields 19842 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); 19843 try struct_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); 19844 var i: usize = 0; 19845 while (i < fields_len) : (i += 1) { 19846 const elem_val = try fields_val.elemValue(mod, i); 19847 const elem_fields = mod.intern_pool.typeOf(elem_val.toIntern()).toType().structFields(mod); 19848 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?); 19849 const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex("type").?); 19850 const default_value_val = try elem_val.fieldValue(mod, elem_fields.getIndex("default_value").?); 19851 const is_comptime_val = try elem_val.fieldValue(mod, elem_fields.getIndex("is_comptime").?); 19852 const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex("alignment").?); 19853 19854 if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { 19855 return sema.fail(block, src, "alignment must fit in 'u32'", .{}); 19856 } 19857 const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?); 19858 19859 if (layout == .Packed) { 19860 if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{}); 19861 if (is_comptime_val.toBool()) return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{}); 19862 } 19863 if (layout == .Extern and is_comptime_val.toBool()) { 19864 return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{}); 19865 } 19866 19867 const field_name = try name_val.toAllocatedBytes( 19868 Type.slice_const_u8, 19869 new_decl_arena_allocator, 19870 mod, 19871 ); 19872 19873 if (is_tuple) { 19874 const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch { 19875 return sema.fail( 19876 block, 19877 src, 19878 "tuple cannot have non-numeric field '{s}'", 19879 .{field_name}, 19880 ); 19881 }; 19882 19883 if (field_index >= fields_len) { 19884 return sema.fail( 19885 block, 19886 src, 19887 "tuple field {} exceeds tuple field count", 19888 .{field_index}, 19889 ); 19890 } 19891 } 19892 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); 19893 if (gop.found_existing) { 19894 // TODO: better source location 19895 return sema.fail(block, src, "duplicate struct field {s}", .{field_name}); 19896 } 19897 19898 const field_ty = type_val.toType(); 19899 const default_val = if (default_value_val.optionalValue(mod)) |opt_val| 19900 try sema.pointerDeref(block, src, opt_val, try mod.singleConstPtrType(field_ty)) orelse 19901 return sema.failWithNeededComptime(block, src, "struct field default value must be comptime-known") 19902 else 19903 Value.@"unreachable"; 19904 if (is_comptime_val.toBool() and default_val.toIntern() == .unreachable_value) { 19905 return sema.fail(block, src, "comptime field without default initialization value", .{}); 19906 } 19907 19908 gop.value_ptr.* = .{ 19909 .ty = field_ty, 19910 .abi_align = abi_align, 19911 .default_val = default_val, 19912 .is_comptime = is_comptime_val.toBool(), 19913 .offset = undefined, 19914 }; 19915 19916 if (field_ty.zigTypeTag(mod) == .Opaque) { 19917 const msg = msg: { 19918 const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); 19919 errdefer msg.destroy(gpa); 19920 19921 try sema.addDeclaredHereNote(msg, field_ty); 19922 break :msg msg; 19923 }; 19924 return sema.failWithOwnedErrorMsg(msg); 19925 } 19926 if (field_ty.zigTypeTag(mod) == .NoReturn) { 19927 const msg = msg: { 19928 const msg = try sema.errMsg(block, src, "struct fields cannot be 'noreturn'", .{}); 19929 errdefer msg.destroy(gpa); 19930 19931 try sema.addDeclaredHereNote(msg, field_ty); 19932 break :msg msg; 19933 }; 19934 return sema.failWithOwnedErrorMsg(msg); 19935 } 19936 if (struct_obj.layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) { 19937 const msg = msg: { 19938 const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); 19939 errdefer msg.destroy(gpa); 19940 19941 const src_decl = sema.mod.declPtr(block.src_decl); 19942 try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .struct_field); 19943 19944 try sema.addDeclaredHereNote(msg, field_ty); 19945 break :msg msg; 19946 }; 19947 return sema.failWithOwnedErrorMsg(msg); 19948 } else if (struct_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) { 19949 const msg = msg: { 19950 const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); 19951 errdefer msg.destroy(gpa); 19952 19953 const src_decl = sema.mod.declPtr(block.src_decl); 19954 try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty); 19955 19956 try sema.addDeclaredHereNote(msg, field_ty); 19957 break :msg msg; 19958 }; 19959 return sema.failWithOwnedErrorMsg(msg); 19960 } 19961 } 19962 19963 if (layout == .Packed) { 19964 struct_obj.status = .layout_wip; 19965 19966 for (struct_obj.fields.values(), 0..) |field, index| { 19967 sema.resolveTypeLayout(field.ty) catch |err| switch (err) { 19968 error.AnalysisFail => { 19969 const msg = sema.err orelse return err; 19970 try sema.addFieldErrNote(struct_ty.toType(), index, msg, "while checking this field", .{}); 19971 return err; 19972 }, 19973 else => return err, 19974 }; 19975 } 19976 19977 var fields_bit_sum: u64 = 0; 19978 for (struct_obj.fields.values()) |field| { 19979 fields_bit_sum += field.ty.bitSize(mod); 19980 } 19981 19982 if (backing_int_val.optionalValue(mod)) |payload| { 19983 const backing_int_ty = payload.toType(); 19984 try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum); 19985 struct_obj.backing_int_ty = backing_int_ty; 19986 } else { 19987 struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(u16, fields_bit_sum)); 19988 } 19989 19990 struct_obj.status = .have_layout; 19991 } 19992 19993 try new_decl.finalizeNewArena(&new_decl_arena); 19994 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); 19995 try mod.finalizeAnonDecl(new_decl_index); 19996 return decl_val; 19997 } 19998 19999 fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 20000 const mod = sema.mod; 20001 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; 20002 const src = LazySrcLoc.nodeOffset(extra.node); 20003 const addrspace_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 20004 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 20005 20006 const dest_addrspace = try sema.analyzeAddressSpace(block, addrspace_src, extra.lhs, .pointer); 20007 const ptr = try sema.resolveInst(extra.rhs); 20008 const ptr_ty = sema.typeOf(ptr); 20009 20010 try sema.checkPtrOperand(block, ptr_src, ptr_ty); 20011 20012 var ptr_info = ptr_ty.ptrInfo(mod); 20013 const src_addrspace = ptr_info.@"addrspace"; 20014 if (!target_util.addrSpaceCastIsValid(sema.mod.getTarget(), src_addrspace, dest_addrspace)) { 20015 const msg = msg: { 20016 const msg = try sema.errMsg(block, src, "invalid address space cast", .{}); 20017 errdefer msg.destroy(sema.gpa); 20018 try sema.errNote(block, src, msg, "address space '{s}' is not compatible with address space '{s}'", .{ @tagName(src_addrspace), @tagName(dest_addrspace) }); 20019 break :msg msg; 20020 }; 20021 return sema.failWithOwnedErrorMsg(msg); 20022 } 20023 20024 ptr_info.@"addrspace" = dest_addrspace; 20025 const dest_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); 20026 const dest_ty = if (ptr_ty.zigTypeTag(mod) == .Optional) 20027 try Type.optional(sema.arena, dest_ptr_ty, mod) 20028 else 20029 dest_ptr_ty; 20030 20031 try sema.requireRuntimeBlock(block, src, ptr_src); 20032 // TODO: Address space cast safety? 20033 20034 return block.addInst(.{ 20035 .tag = .addrspace_cast, 20036 .data = .{ .ty_op = .{ 20037 .ty = try sema.addType(dest_ty), 20038 .operand = ptr, 20039 } }, 20040 }); 20041 } 20042 20043 fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref { 20044 const va_list_ty = try sema.getBuiltinType("VaList"); 20045 const va_list_ptr = try Type.ptr(sema.arena, sema.mod, .{ 20046 .pointee_type = va_list_ty, 20047 .mutable = true, 20048 .@"addrspace" = .generic, 20049 }); 20050 20051 const inst = try sema.resolveInst(zir_ref); 20052 return sema.coerce(block, va_list_ptr, inst, src); 20053 } 20054 20055 fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 20056 const mod = sema.mod; 20057 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; 20058 const src = LazySrcLoc.nodeOffset(extra.node); 20059 const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 20060 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 20061 20062 const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.lhs); 20063 const arg_ty = try sema.resolveType(block, ty_src, extra.rhs); 20064 20065 if (!try sema.validateExternType(arg_ty, .param_ty)) { 20066 const msg = msg: { 20067 const msg = try sema.errMsg(block, ty_src, "cannot get '{}' from variadic argument", .{arg_ty.fmt(sema.mod)}); 20068 errdefer msg.destroy(sema.gpa); 20069 20070 const src_decl = sema.mod.declPtr(block.src_decl); 20071 try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl, mod), arg_ty, .param_ty); 20072 20073 try sema.addDeclaredHereNote(msg, arg_ty); 20074 break :msg msg; 20075 }; 20076 return sema.failWithOwnedErrorMsg(msg); 20077 } 20078 20079 try sema.requireRuntimeBlock(block, src, null); 20080 return block.addTyOp(.c_va_arg, arg_ty, va_list_ref); 20081 } 20082 20083 fn zirCVaCopy(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 20084 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 20085 const src = LazySrcLoc.nodeOffset(extra.node); 20086 const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 20087 20088 const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand); 20089 const va_list_ty = try sema.getBuiltinType("VaList"); 20090 20091 try sema.requireRuntimeBlock(block, src, null); 20092 return block.addTyOp(.c_va_copy, va_list_ty, va_list_ref); 20093 } 20094 20095 fn zirCVaEnd(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 20096 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 20097 const src = LazySrcLoc.nodeOffset(extra.node); 20098 const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 20099 20100 const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand); 20101 20102 try sema.requireRuntimeBlock(block, src, null); 20103 return block.addUnOp(.c_va_end, va_list_ref); 20104 } 20105 20106 fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 20107 const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand)); 20108 20109 const va_list_ty = try sema.getBuiltinType("VaList"); 20110 try sema.requireRuntimeBlock(block, src, null); 20111 return block.addInst(.{ 20112 .tag = .c_va_start, 20113 .data = .{ .ty = va_list_ty }, 20114 }); 20115 } 20116 20117 fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20118 const mod = sema.mod; 20119 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 20120 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 20121 const ty = try sema.resolveType(block, ty_src, inst_data.operand); 20122 20123 var anon_decl = try block.startAnonDecl(); 20124 defer anon_decl.deinit(); 20125 20126 const bytes = try ty.nameAllocArena(anon_decl.arena(), mod); 20127 20128 const decl_ty = try mod.arrayType(.{ 20129 .len = bytes.len, 20130 .child = .u8_type, 20131 .sentinel = .zero_u8, 20132 }); 20133 const new_decl = try anon_decl.finish( 20134 decl_ty, 20135 (try mod.intern(.{ .aggregate = .{ 20136 .ty = decl_ty.toIntern(), 20137 .storage = .{ .bytes = bytes }, 20138 } })).toValue(), 20139 0, // default alignment 20140 ); 20141 20142 return sema.analyzeDeclRef(new_decl); 20143 } 20144 20145 fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20146 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 20147 const src = inst_data.src(); 20148 return sema.failWithUseOfAsync(block, src); 20149 } 20150 20151 fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20152 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 20153 const src = inst_data.src(); 20154 return sema.failWithUseOfAsync(block, src); 20155 } 20156 20157 fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20158 const mod = sema.mod; 20159 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 20160 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 20161 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 20162 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 20163 const dest_ty = try sema.resolveType(block, ty_src, extra.lhs); 20164 const operand = try sema.resolveInst(extra.rhs); 20165 const operand_ty = sema.typeOf(operand); 20166 20167 _ = try sema.checkIntType(block, ty_src, dest_ty); 20168 try sema.checkFloatType(block, operand_src, operand_ty); 20169 20170 if (try sema.resolveMaybeUndefVal(operand)) |val| { 20171 const result_val = try sema.floatToInt(block, operand_src, val, operand_ty, dest_ty); 20172 return sema.addConstant(dest_ty, result_val); 20173 } else if (dest_ty.zigTypeTag(mod) == .ComptimeInt) { 20174 return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_int' must be comptime-known"); 20175 } 20176 20177 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); 20178 if (dest_ty.intInfo(mod).bits == 0) { 20179 if (block.wantSafety()) { 20180 const ok = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, try sema.addConstant(operand_ty, try mod.intValue(operand_ty, 0))); 20181 try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds); 20182 } 20183 return sema.addConstant(dest_ty, try mod.intValue(dest_ty, 0)); 20184 } 20185 const result = try block.addTyOp(if (block.float_mode == .Optimized) .float_to_int_optimized else .float_to_int, dest_ty, operand); 20186 if (block.wantSafety()) { 20187 const back = try block.addTyOp(.int_to_float, operand_ty, result); 20188 const diff = try block.addBinOp(.sub, operand, back); 20189 const ok_pos = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_lt_optimized else .cmp_lt, diff, try sema.addConstant(operand_ty, try mod.floatValue(operand_ty, 1.0))); 20190 const ok_neg = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_gt_optimized else .cmp_gt, diff, try sema.addConstant(operand_ty, try mod.floatValue(operand_ty, -1.0))); 20191 const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg); 20192 try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds); 20193 } 20194 return result; 20195 } 20196 20197 fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20198 const mod = sema.mod; 20199 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 20200 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 20201 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 20202 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 20203 const dest_ty = try sema.resolveType(block, ty_src, extra.lhs); 20204 const operand = try sema.resolveInst(extra.rhs); 20205 const operand_ty = sema.typeOf(operand); 20206 20207 try sema.checkFloatType(block, ty_src, dest_ty); 20208 _ = try sema.checkIntType(block, operand_src, operand_ty); 20209 20210 if (try sema.resolveMaybeUndefVal(operand)) |val| { 20211 const result_val = try val.intToFloatAdvanced(sema.arena, operand_ty, dest_ty, sema.mod, sema); 20212 return sema.addConstant(dest_ty, result_val); 20213 } else if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) { 20214 return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_float' must be comptime-known"); 20215 } 20216 20217 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); 20218 return block.addTyOp(.int_to_float, dest_ty, operand); 20219 } 20220 20221 fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20222 const mod = sema.mod; 20223 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 20224 const src = inst_data.src(); 20225 20226 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 20227 20228 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 20229 const operand_res = try sema.resolveInst(extra.rhs); 20230 const operand_coerced = try sema.coerce(block, Type.usize, operand_res, operand_src); 20231 20232 const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 20233 const ptr_ty = try sema.resolveType(block, src, extra.lhs); 20234 try sema.checkPtrType(block, type_src, ptr_ty); 20235 const elem_ty = ptr_ty.elemType2(mod); 20236 const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema); 20237 20238 if (ptr_ty.isSlice(mod)) { 20239 const msg = msg: { 20240 const msg = try sema.errMsg(block, type_src, "integer cannot be converted to slice type '{}'", .{ptr_ty.fmt(sema.mod)}); 20241 errdefer msg.destroy(sema.gpa); 20242 try sema.errNote(block, type_src, msg, "slice length cannot be inferred from address", .{}); 20243 break :msg msg; 20244 }; 20245 return sema.failWithOwnedErrorMsg(msg); 20246 } 20247 20248 if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| { 20249 const addr = val.toUnsignedInt(mod); 20250 if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0) 20251 return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)}); 20252 if (addr != 0 and ptr_align != 0 and addr % ptr_align != 0) 20253 return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)}); 20254 20255 return sema.addConstant(ptr_ty, try mod.ptrIntValue(ptr_ty, addr)); 20256 } 20257 20258 try sema.requireRuntimeBlock(block, src, operand_src); 20259 if (block.wantSafety() and (try sema.typeHasRuntimeBits(elem_ty) or elem_ty.zigTypeTag(mod) == .Fn)) { 20260 if (!ptr_ty.isAllowzeroPtr(mod)) { 20261 const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize); 20262 try sema.addSafetyCheck(block, is_non_zero, .cast_to_null); 20263 } 20264 20265 if (ptr_align > 1) { 20266 const align_minus_1 = try sema.addConstant( 20267 Type.usize, 20268 try mod.intValue(Type.usize, ptr_align - 1), 20269 ); 20270 const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1); 20271 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); 20272 try sema.addSafetyCheck(block, is_aligned, .incorrect_alignment); 20273 } 20274 } 20275 return block.addBitCast(ptr_ty, operand_coerced); 20276 } 20277 20278 fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 20279 const mod = sema.mod; 20280 const ip = &mod.intern_pool; 20281 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; 20282 const src = LazySrcLoc.nodeOffset(extra.node); 20283 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 20284 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 20285 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); 20286 const operand = try sema.resolveInst(extra.rhs); 20287 const operand_ty = sema.typeOf(operand); 20288 try sema.checkErrorSetType(block, dest_ty_src, dest_ty); 20289 try sema.checkErrorSetType(block, operand_src, operand_ty); 20290 20291 // operand must be defined since it can be an invalid error value 20292 const maybe_operand_val = try sema.resolveDefinedValue(block, operand_src, operand); 20293 20294 if (disjoint: { 20295 // Try avoiding resolving inferred error sets if we can 20296 if (!dest_ty.isAnyError(mod) and dest_ty.errorSetNames(mod).len == 0) break :disjoint true; 20297 if (!operand_ty.isAnyError(mod) and operand_ty.errorSetNames(mod).len == 0) break :disjoint true; 20298 if (dest_ty.isAnyError(mod)) break :disjoint false; 20299 if (operand_ty.isAnyError(mod)) break :disjoint false; 20300 for (dest_ty.errorSetNames(mod)) |dest_err_name| { 20301 if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name)) 20302 break :disjoint false; 20303 } 20304 20305 if (!ip.isInferredErrorSetType(dest_ty.toIntern()) and 20306 !ip.isInferredErrorSetType(operand_ty.toIntern())) 20307 { 20308 break :disjoint true; 20309 } 20310 20311 try sema.resolveInferredErrorSetTy(block, dest_ty_src, dest_ty); 20312 try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty); 20313 for (dest_ty.errorSetNames(mod)) |dest_err_name| { 20314 if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name)) 20315 break :disjoint false; 20316 } 20317 20318 break :disjoint true; 20319 }) { 20320 const msg = msg: { 20321 const msg = try sema.errMsg( 20322 block, 20323 src, 20324 "error sets '{}' and '{}' have no common errors", 20325 .{ operand_ty.fmt(sema.mod), dest_ty.fmt(sema.mod) }, 20326 ); 20327 errdefer msg.destroy(sema.gpa); 20328 try sema.addDeclaredHereNote(msg, operand_ty); 20329 try sema.addDeclaredHereNote(msg, dest_ty); 20330 break :msg msg; 20331 }; 20332 return sema.failWithOwnedErrorMsg(msg); 20333 } 20334 20335 if (maybe_operand_val) |val| { 20336 if (!dest_ty.isAnyError(mod)) { 20337 const error_name = mod.intern_pool.stringToSlice(mod.intern_pool.indexToKey(val.toIntern()).err.name); 20338 if (!dest_ty.errorSetHasField(error_name, mod)) { 20339 const msg = msg: { 20340 const msg = try sema.errMsg( 20341 block, 20342 src, 20343 "'error.{s}' not a member of error set '{}'", 20344 .{ error_name, dest_ty.fmt(sema.mod) }, 20345 ); 20346 errdefer msg.destroy(sema.gpa); 20347 try sema.addDeclaredHereNote(msg, dest_ty); 20348 break :msg msg; 20349 }; 20350 return sema.failWithOwnedErrorMsg(msg); 20351 } 20352 } 20353 20354 return sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty)); 20355 } 20356 20357 try sema.requireRuntimeBlock(block, src, operand_src); 20358 if (block.wantSafety() and !dest_ty.isAnyError(mod) and sema.mod.backendSupportsFeature(.error_set_has_value)) { 20359 const err_int_inst = try block.addBitCast(Type.err_int, operand); 20360 const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst); 20361 try sema.addSafetyCheck(block, ok, .invalid_error_code); 20362 } 20363 return block.addBitCast(dest_ty, operand); 20364 } 20365 20366 fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20367 const mod = sema.mod; 20368 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 20369 const src = inst_data.src(); 20370 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 20371 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 20372 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 20373 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); 20374 const operand = try sema.resolveInst(extra.rhs); 20375 const operand_ty = sema.typeOf(operand); 20376 20377 try sema.checkPtrType(block, dest_ty_src, dest_ty); 20378 try sema.checkPtrOperand(block, operand_src, operand_ty); 20379 20380 const operand_info = operand_ty.ptrInfo(mod); 20381 const dest_info = dest_ty.ptrInfo(mod); 20382 if (!operand_info.mutable and dest_info.mutable) { 20383 const msg = msg: { 20384 const msg = try sema.errMsg(block, src, "cast discards const qualifier", .{}); 20385 errdefer msg.destroy(sema.gpa); 20386 20387 try sema.errNote(block, src, msg, "consider using '@constCast'", .{}); 20388 break :msg msg; 20389 }; 20390 return sema.failWithOwnedErrorMsg(msg); 20391 } 20392 if (operand_info.@"volatile" and !dest_info.@"volatile") { 20393 const msg = msg: { 20394 const msg = try sema.errMsg(block, src, "cast discards volatile qualifier", .{}); 20395 errdefer msg.destroy(sema.gpa); 20396 20397 try sema.errNote(block, src, msg, "consider using '@volatileCast'", .{}); 20398 break :msg msg; 20399 }; 20400 return sema.failWithOwnedErrorMsg(msg); 20401 } 20402 if (operand_info.@"addrspace" != dest_info.@"addrspace") { 20403 const msg = msg: { 20404 const msg = try sema.errMsg(block, src, "cast changes pointer address space", .{}); 20405 errdefer msg.destroy(sema.gpa); 20406 20407 try sema.errNote(block, src, msg, "consider using '@addrSpaceCast'", .{}); 20408 break :msg msg; 20409 }; 20410 return sema.failWithOwnedErrorMsg(msg); 20411 } 20412 20413 const dest_is_slice = dest_ty.isSlice(mod); 20414 const operand_is_slice = operand_ty.isSlice(mod); 20415 if (dest_is_slice and !operand_is_slice) { 20416 return sema.fail(block, dest_ty_src, "illegal pointer cast to slice", .{}); 20417 } 20418 const ptr = if (operand_is_slice and !dest_is_slice) 20419 try sema.analyzeSlicePtr(block, operand_src, operand, operand_ty) 20420 else 20421 operand; 20422 20423 const dest_elem_ty = dest_ty.elemType2(mod); 20424 try sema.resolveTypeLayout(dest_elem_ty); 20425 const dest_align = dest_ty.ptrAlignment(mod); 20426 20427 const operand_elem_ty = operand_ty.elemType2(mod); 20428 try sema.resolveTypeLayout(operand_elem_ty); 20429 const operand_align = operand_ty.ptrAlignment(mod); 20430 20431 // If the destination is less aligned than the source, preserve the source alignment 20432 const aligned_dest_ty = if (operand_align <= dest_align) dest_ty else blk: { 20433 // Unwrap the pointer (or pointer-like optional) type, set alignment, and re-wrap into result 20434 if (dest_ty.zigTypeTag(mod) == .Optional) { 20435 var dest_ptr_info = dest_ty.optionalChild(mod).ptrInfo(mod); 20436 dest_ptr_info.@"align" = operand_align; 20437 break :blk try Type.optional(sema.arena, try Type.ptr(sema.arena, mod, dest_ptr_info), mod); 20438 } else { 20439 var dest_ptr_info = dest_ty.ptrInfo(mod); 20440 dest_ptr_info.@"align" = operand_align; 20441 break :blk try Type.ptr(sema.arena, mod, dest_ptr_info); 20442 } 20443 }; 20444 20445 if (dest_is_slice) { 20446 const operand_elem_size = operand_elem_ty.abiSize(mod); 20447 const dest_elem_size = dest_elem_ty.abiSize(mod); 20448 if (operand_elem_size != dest_elem_size) { 20449 return sema.fail(block, dest_ty_src, "TODO: implement @ptrCast between slices changing the length", .{}); 20450 } 20451 } 20452 20453 if (dest_align > operand_align) { 20454 const msg = msg: { 20455 const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{}); 20456 errdefer msg.destroy(sema.gpa); 20457 20458 try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{ 20459 operand_ty.fmt(mod), operand_align, 20460 }); 20461 try sema.errNote(block, dest_ty_src, msg, "'{}' has alignment '{d}'", .{ 20462 dest_ty.fmt(mod), dest_align, 20463 }); 20464 20465 try sema.errNote(block, src, msg, "consider using '@alignCast'", .{}); 20466 break :msg msg; 20467 }; 20468 return sema.failWithOwnedErrorMsg(msg); 20469 } 20470 20471 if (try sema.resolveMaybeUndefVal(ptr)) |operand_val| { 20472 if (!dest_ty.ptrAllowsZero(mod) and operand_val.isUndef(mod)) { 20473 return sema.failWithUseOfUndef(block, operand_src); 20474 } 20475 if (!dest_ty.ptrAllowsZero(mod) and operand_val.isNull(mod)) { 20476 return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)}); 20477 } 20478 return sema.addConstant(aligned_dest_ty, try mod.getCoerced(operand_val, aligned_dest_ty)); 20479 } 20480 20481 try sema.requireRuntimeBlock(block, src, null); 20482 if (block.wantSafety() and operand_ty.ptrAllowsZero(mod) and !dest_ty.ptrAllowsZero(mod) and 20483 (try sema.typeHasRuntimeBits(dest_ty.elemType2(mod)) or dest_ty.elemType2(mod).zigTypeTag(mod) == .Fn)) 20484 { 20485 const ptr_int = try block.addUnOp(.ptrtoint, ptr); 20486 const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize); 20487 const ok = if (operand_is_slice) ok: { 20488 const len = try sema.analyzeSliceLen(block, operand_src, operand); 20489 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); 20490 break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero); 20491 } else is_non_zero; 20492 try sema.addSafetyCheck(block, ok, .cast_to_null); 20493 } 20494 20495 return block.addBitCast(aligned_dest_ty, ptr); 20496 } 20497 20498 fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 20499 const mod = sema.mod; 20500 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 20501 const src = LazySrcLoc.nodeOffset(extra.node); 20502 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 20503 const operand = try sema.resolveInst(extra.operand); 20504 const operand_ty = sema.typeOf(operand); 20505 try sema.checkPtrOperand(block, operand_src, operand_ty); 20506 20507 var ptr_info = operand_ty.ptrInfo(mod); 20508 ptr_info.mutable = true; 20509 const dest_ty = try Type.ptr(sema.arena, mod, ptr_info); 20510 20511 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { 20512 return sema.addConstant(dest_ty, try mod.getCoerced(operand_val, dest_ty)); 20513 } 20514 20515 try sema.requireRuntimeBlock(block, src, null); 20516 return block.addBitCast(dest_ty, operand); 20517 } 20518 20519 fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 20520 const mod = sema.mod; 20521 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 20522 const src = LazySrcLoc.nodeOffset(extra.node); 20523 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 20524 const operand = try sema.resolveInst(extra.operand); 20525 const operand_ty = sema.typeOf(operand); 20526 try sema.checkPtrOperand(block, operand_src, operand_ty); 20527 20528 var ptr_info = operand_ty.ptrInfo(mod); 20529 ptr_info.@"volatile" = false; 20530 const dest_ty = try Type.ptr(sema.arena, mod, ptr_info); 20531 20532 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { 20533 return sema.addConstant(dest_ty, operand_val); 20534 } 20535 20536 try sema.requireRuntimeBlock(block, src, null); 20537 return block.addBitCast(dest_ty, operand); 20538 } 20539 20540 fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20541 const mod = sema.mod; 20542 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 20543 const src = inst_data.src(); 20544 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 20545 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 20546 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 20547 const dest_scalar_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); 20548 const operand = try sema.resolveInst(extra.rhs); 20549 const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_scalar_ty); 20550 const operand_ty = sema.typeOf(operand); 20551 const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); 20552 const is_vector = operand_ty.zigTypeTag(mod) == .Vector; 20553 const dest_ty = if (is_vector) 20554 try mod.vectorType(.{ 20555 .len = operand_ty.vectorLen(mod), 20556 .child = dest_scalar_ty.toIntern(), 20557 }) 20558 else 20559 dest_scalar_ty; 20560 20561 if (dest_is_comptime_int) { 20562 return sema.coerce(block, dest_ty, operand, operand_src); 20563 } 20564 20565 const dest_info = dest_scalar_ty.intInfo(mod); 20566 20567 if (try sema.typeHasOnePossibleValue(dest_ty)) |val| { 20568 return sema.addConstant(dest_ty, val); 20569 } 20570 20571 if (operand_scalar_ty.zigTypeTag(mod) != .ComptimeInt) { 20572 const operand_info = operand_ty.intInfo(mod); 20573 if (try sema.typeHasOnePossibleValue(operand_ty)) |val| { 20574 return sema.addConstant(operand_ty, val); 20575 } 20576 20577 if (operand_info.signedness != dest_info.signedness) { 20578 return sema.fail(block, operand_src, "expected {s} integer type, found '{}'", .{ 20579 @tagName(dest_info.signedness), operand_ty.fmt(mod), 20580 }); 20581 } 20582 if (operand_info.bits < dest_info.bits) { 20583 const msg = msg: { 20584 const msg = try sema.errMsg( 20585 block, 20586 src, 20587 "destination type '{}' has more bits than source type '{}'", 20588 .{ dest_ty.fmt(mod), operand_ty.fmt(mod) }, 20589 ); 20590 errdefer msg.destroy(sema.gpa); 20591 try sema.errNote(block, dest_ty_src, msg, "destination type has {d} bits", .{ 20592 dest_info.bits, 20593 }); 20594 try sema.errNote(block, operand_src, msg, "operand type has {d} bits", .{ 20595 operand_info.bits, 20596 }); 20597 break :msg msg; 20598 }; 20599 return sema.failWithOwnedErrorMsg(msg); 20600 } 20601 } 20602 20603 if (try sema.resolveMaybeUndefValIntable(operand)) |val| { 20604 if (val.isUndef(mod)) return sema.addConstUndef(dest_ty); 20605 if (!is_vector) { 20606 return sema.addConstant(dest_ty, try mod.getCoerced( 20607 try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits, mod), 20608 dest_ty, 20609 )); 20610 } 20611 const elems = try sema.arena.alloc(InternPool.Index, operand_ty.vectorLen(mod)); 20612 for (elems, 0..) |*elem, i| { 20613 const elem_val = try val.elemValue(mod, i); 20614 elem.* = try (try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits, mod)).intern(dest_scalar_ty, mod); 20615 } 20616 return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{ 20617 .ty = dest_ty.toIntern(), 20618 .storage = .{ .elems = elems }, 20619 } })).toValue()); 20620 } 20621 20622 try sema.requireRuntimeBlock(block, src, operand_src); 20623 return block.addTyOp(.trunc, dest_ty, operand); 20624 } 20625 20626 fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20627 const mod = sema.mod; 20628 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 20629 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 20630 const align_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 20631 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 20632 const dest_align = try sema.resolveAlign(block, align_src, extra.lhs); 20633 const ptr = try sema.resolveInst(extra.rhs); 20634 const ptr_ty = sema.typeOf(ptr); 20635 20636 try sema.checkPtrOperand(block, ptr_src, ptr_ty); 20637 20638 var ptr_info = ptr_ty.ptrInfo(mod); 20639 ptr_info.@"align" = dest_align; 20640 var dest_ty = try Type.ptr(sema.arena, mod, ptr_info); 20641 if (ptr_ty.zigTypeTag(mod) == .Optional) { 20642 dest_ty = try mod.optionalType(dest_ty.toIntern()); 20643 } 20644 20645 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |val| { 20646 if (try val.getUnsignedIntAdvanced(mod, null)) |addr| { 20647 if (addr % dest_align != 0) { 20648 return sema.fail(block, ptr_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align }); 20649 } 20650 } 20651 return sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty)); 20652 } 20653 20654 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); 20655 if (block.wantSafety() and dest_align > 1 and 20656 try sema.typeHasRuntimeBits(ptr_info.pointee_type)) 20657 { 20658 const align_minus_1 = try sema.addConstant( 20659 Type.usize, 20660 try mod.intValue(Type.usize, dest_align - 1), 20661 ); 20662 const actual_ptr = if (ptr_ty.isSlice(mod)) 20663 try sema.analyzeSlicePtr(block, ptr_src, ptr, ptr_ty) 20664 else 20665 ptr; 20666 const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr); 20667 const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1); 20668 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); 20669 const ok = if (ptr_ty.isSlice(mod)) ok: { 20670 const len = try sema.analyzeSliceLen(block, ptr_src, ptr); 20671 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); 20672 break :ok try block.addBinOp(.bit_or, len_zero, is_aligned); 20673 } else is_aligned; 20674 try sema.addSafetyCheck(block, ok, .incorrect_alignment); 20675 } 20676 return sema.bitCast(block, dest_ty, ptr, ptr_src, null); 20677 } 20678 20679 fn zirBitCount( 20680 sema: *Sema, 20681 block: *Block, 20682 inst: Zir.Inst.Index, 20683 air_tag: Air.Inst.Tag, 20684 comptime comptimeOp: fn (val: Value, ty: Type, mod: *Module) u64, 20685 ) CompileError!Air.Inst.Ref { 20686 const mod = sema.mod; 20687 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 20688 const src = inst_data.src(); 20689 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 20690 const operand = try sema.resolveInst(inst_data.operand); 20691 const operand_ty = sema.typeOf(operand); 20692 _ = try sema.checkIntOrVector(block, operand, operand_src); 20693 const bits = operand_ty.intInfo(mod).bits; 20694 20695 if (try sema.typeHasOnePossibleValue(operand_ty)) |val| { 20696 return sema.addConstant(operand_ty, val); 20697 } 20698 20699 const result_scalar_ty = try mod.smallestUnsignedInt(bits); 20700 switch (operand_ty.zigTypeTag(mod)) { 20701 .Vector => { 20702 const vec_len = operand_ty.vectorLen(mod); 20703 const result_ty = try mod.vectorType(.{ 20704 .len = vec_len, 20705 .child = result_scalar_ty.toIntern(), 20706 }); 20707 if (try sema.resolveMaybeUndefVal(operand)) |val| { 20708 if (val.isUndef(mod)) return sema.addConstUndef(result_ty); 20709 20710 const elems = try sema.arena.alloc(InternPool.Index, vec_len); 20711 const scalar_ty = operand_ty.scalarType(mod); 20712 for (elems, 0..) |*elem, i| { 20713 const elem_val = try val.elemValue(mod, i); 20714 const count = comptimeOp(elem_val, scalar_ty, mod); 20715 elem.* = (try mod.intValue(result_scalar_ty, count)).toIntern(); 20716 } 20717 return sema.addConstant(result_ty, (try mod.intern(.{ .aggregate = .{ 20718 .ty = result_ty.toIntern(), 20719 .storage = .{ .elems = elems }, 20720 } })).toValue()); 20721 } else { 20722 try sema.requireRuntimeBlock(block, src, operand_src); 20723 return block.addTyOp(air_tag, result_ty, operand); 20724 } 20725 }, 20726 .Int => { 20727 if (try sema.resolveMaybeUndefLazyVal(operand)) |val| { 20728 if (val.isUndef(mod)) return sema.addConstUndef(result_scalar_ty); 20729 return sema.addIntUnsigned(result_scalar_ty, comptimeOp(val, operand_ty, mod)); 20730 } else { 20731 try sema.requireRuntimeBlock(block, src, operand_src); 20732 return block.addTyOp(air_tag, result_scalar_ty, operand); 20733 } 20734 }, 20735 else => unreachable, 20736 } 20737 } 20738 20739 fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20740 const mod = sema.mod; 20741 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 20742 const src = inst_data.src(); 20743 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 20744 const operand = try sema.resolveInst(inst_data.operand); 20745 const operand_ty = sema.typeOf(operand); 20746 const scalar_ty = try sema.checkIntOrVector(block, operand, operand_src); 20747 const bits = scalar_ty.intInfo(mod).bits; 20748 if (bits % 8 != 0) { 20749 return sema.fail( 20750 block, 20751 operand_src, 20752 "@byteSwap requires the number of bits to be evenly divisible by 8, but {} has {} bits", 20753 .{ scalar_ty.fmt(mod), bits }, 20754 ); 20755 } 20756 20757 if (try sema.typeHasOnePossibleValue(operand_ty)) |val| { 20758 return sema.addConstant(operand_ty, val); 20759 } 20760 20761 switch (operand_ty.zigTypeTag(mod)) { 20762 .Int => { 20763 const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { 20764 if (val.isUndef(mod)) return sema.addConstUndef(operand_ty); 20765 const result_val = try val.byteSwap(operand_ty, mod, sema.arena); 20766 return sema.addConstant(operand_ty, result_val); 20767 } else operand_src; 20768 20769 try sema.requireRuntimeBlock(block, src, runtime_src); 20770 return block.addTyOp(.byte_swap, operand_ty, operand); 20771 }, 20772 .Vector => { 20773 const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { 20774 if (val.isUndef(mod)) 20775 return sema.addConstUndef(operand_ty); 20776 20777 const vec_len = operand_ty.vectorLen(mod); 20778 const elems = try sema.arena.alloc(InternPool.Index, vec_len); 20779 for (elems, 0..) |*elem, i| { 20780 const elem_val = try val.elemValue(mod, i); 20781 elem.* = try (try elem_val.byteSwap(scalar_ty, mod, sema.arena)).intern(scalar_ty, mod); 20782 } 20783 return sema.addConstant(operand_ty, (try mod.intern(.{ .aggregate = .{ 20784 .ty = operand_ty.toIntern(), 20785 .storage = .{ .elems = elems }, 20786 } })).toValue()); 20787 } else operand_src; 20788 20789 try sema.requireRuntimeBlock(block, src, runtime_src); 20790 return block.addTyOp(.byte_swap, operand_ty, operand); 20791 }, 20792 else => unreachable, 20793 } 20794 } 20795 20796 fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20797 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 20798 const src = inst_data.src(); 20799 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 20800 const operand = try sema.resolveInst(inst_data.operand); 20801 const operand_ty = sema.typeOf(operand); 20802 const scalar_ty = try sema.checkIntOrVector(block, operand, operand_src); 20803 20804 if (try sema.typeHasOnePossibleValue(operand_ty)) |val| { 20805 return sema.addConstant(operand_ty, val); 20806 } 20807 20808 const mod = sema.mod; 20809 switch (operand_ty.zigTypeTag(mod)) { 20810 .Int => { 20811 const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { 20812 if (val.isUndef(mod)) return sema.addConstUndef(operand_ty); 20813 const result_val = try val.bitReverse(operand_ty, mod, sema.arena); 20814 return sema.addConstant(operand_ty, result_val); 20815 } else operand_src; 20816 20817 try sema.requireRuntimeBlock(block, src, runtime_src); 20818 return block.addTyOp(.bit_reverse, operand_ty, operand); 20819 }, 20820 .Vector => { 20821 const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { 20822 if (val.isUndef(mod)) 20823 return sema.addConstUndef(operand_ty); 20824 20825 const vec_len = operand_ty.vectorLen(mod); 20826 const elems = try sema.arena.alloc(InternPool.Index, vec_len); 20827 for (elems, 0..) |*elem, i| { 20828 const elem_val = try val.elemValue(mod, i); 20829 elem.* = try (try elem_val.bitReverse(scalar_ty, mod, sema.arena)).intern(scalar_ty, mod); 20830 } 20831 return sema.addConstant(operand_ty, (try mod.intern(.{ .aggregate = .{ 20832 .ty = operand_ty.toIntern(), 20833 .storage = .{ .elems = elems }, 20834 } })).toValue()); 20835 } else operand_src; 20836 20837 try sema.requireRuntimeBlock(block, src, runtime_src); 20838 return block.addTyOp(.bit_reverse, operand_ty, operand); 20839 }, 20840 else => unreachable, 20841 } 20842 } 20843 20844 fn zirBitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20845 const offset = try sema.bitOffsetOf(block, inst); 20846 return sema.addIntUnsigned(Type.comptime_int, offset); 20847 } 20848 20849 fn zirOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20850 const offset = try sema.bitOffsetOf(block, inst); 20851 // TODO reminder to make this a compile error for packed structs 20852 return sema.addIntUnsigned(Type.comptime_int, offset / 8); 20853 } 20854 20855 fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u64 { 20856 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 20857 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 20858 sema.src = src; 20859 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 20860 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 20861 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 20862 20863 const ty = try sema.resolveType(block, lhs_src, extra.lhs); 20864 const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "name of field must be comptime-known"); 20865 20866 const mod = sema.mod; 20867 try sema.resolveTypeLayout(ty); 20868 switch (ty.zigTypeTag(mod)) { 20869 .Struct => {}, 20870 else => { 20871 const msg = msg: { 20872 const msg = try sema.errMsg(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(mod)}); 20873 errdefer msg.destroy(sema.gpa); 20874 try sema.addDeclaredHereNote(msg, ty); 20875 break :msg msg; 20876 }; 20877 return sema.failWithOwnedErrorMsg(msg); 20878 }, 20879 } 20880 20881 const field_index = if (ty.isTuple(mod)) blk: { 20882 if (mem.eql(u8, field_name, "len")) { 20883 return sema.fail(block, src, "no offset available for 'len' field of tuple", .{}); 20884 } 20885 break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src); 20886 } else try sema.structFieldIndex(block, ty, field_name, rhs_src); 20887 20888 if (ty.structFieldIsComptime(field_index, mod)) { 20889 return sema.fail(block, src, "no offset available for comptime field", .{}); 20890 } 20891 20892 switch (ty.containerLayout(mod)) { 20893 .Packed => { 20894 var bit_sum: u64 = 0; 20895 const fields = ty.structFields(mod); 20896 for (fields.values(), 0..) |field, i| { 20897 if (i == field_index) { 20898 return bit_sum; 20899 } 20900 bit_sum += field.ty.bitSize(mod); 20901 } else unreachable; 20902 }, 20903 else => return ty.structFieldOffset(field_index, mod) * 8, 20904 } 20905 } 20906 20907 fn checkNamespaceType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { 20908 const mod = sema.mod; 20909 switch (ty.zigTypeTag(mod)) { 20910 .Struct, .Enum, .Union, .Opaque => return, 20911 else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{}'", .{ty.fmt(mod)}), 20912 } 20913 } 20914 20915 /// Returns `true` if the type was a comptime_int. 20916 fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { 20917 const mod = sema.mod; 20918 switch (try ty.zigTypeTagOrPoison(mod)) { 20919 .ComptimeInt => return true, 20920 .Int => return false, 20921 else => return sema.fail(block, src, "expected integer type, found '{}'", .{ty.fmt(mod)}), 20922 } 20923 } 20924 20925 fn checkInvalidPtrArithmetic( 20926 sema: *Sema, 20927 block: *Block, 20928 src: LazySrcLoc, 20929 ty: Type, 20930 ) CompileError!void { 20931 const mod = sema.mod; 20932 switch (try ty.zigTypeTagOrPoison(mod)) { 20933 .Pointer => switch (ty.ptrSize(mod)) { 20934 .One, .Slice => return, 20935 .Many, .C => return sema.fail( 20936 block, 20937 src, 20938 "invalid pointer arithmetic operator", 20939 .{}, 20940 ), 20941 }, 20942 else => return, 20943 } 20944 } 20945 20946 fn checkArithmeticOp( 20947 sema: *Sema, 20948 block: *Block, 20949 src: LazySrcLoc, 20950 scalar_tag: std.builtin.TypeId, 20951 lhs_zig_ty_tag: std.builtin.TypeId, 20952 rhs_zig_ty_tag: std.builtin.TypeId, 20953 zir_tag: Zir.Inst.Tag, 20954 ) CompileError!void { 20955 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 20956 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat; 20957 20958 if (!is_int and !(is_float and floatOpAllowed(zir_tag))) { 20959 return sema.fail(block, src, "invalid operands to binary expression: '{s}' and '{s}'", .{ 20960 @tagName(lhs_zig_ty_tag), @tagName(rhs_zig_ty_tag), 20961 }); 20962 } 20963 } 20964 20965 fn checkPtrOperand( 20966 sema: *Sema, 20967 block: *Block, 20968 ty_src: LazySrcLoc, 20969 ty: Type, 20970 ) CompileError!void { 20971 const mod = sema.mod; 20972 switch (ty.zigTypeTag(mod)) { 20973 .Pointer => return, 20974 .Fn => { 20975 const msg = msg: { 20976 const msg = try sema.errMsg( 20977 block, 20978 ty_src, 20979 "expected pointer, found '{}'", 20980 .{ty.fmt(mod)}, 20981 ); 20982 errdefer msg.destroy(sema.gpa); 20983 20984 try sema.errNote(block, ty_src, msg, "use '&' to obtain a function pointer", .{}); 20985 20986 break :msg msg; 20987 }; 20988 return sema.failWithOwnedErrorMsg(msg); 20989 }, 20990 .Optional => if (ty.isPtrLikeOptional(mod)) return, 20991 else => {}, 20992 } 20993 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(mod)}); 20994 } 20995 20996 fn checkPtrType( 20997 sema: *Sema, 20998 block: *Block, 20999 ty_src: LazySrcLoc, 21000 ty: Type, 21001 ) CompileError!void { 21002 const mod = sema.mod; 21003 switch (ty.zigTypeTag(mod)) { 21004 .Pointer => return, 21005 .Fn => { 21006 const msg = msg: { 21007 const msg = try sema.errMsg( 21008 block, 21009 ty_src, 21010 "expected pointer type, found '{}'", 21011 .{ty.fmt(mod)}, 21012 ); 21013 errdefer msg.destroy(sema.gpa); 21014 21015 try sema.errNote(block, ty_src, msg, "use '*const ' to make a function pointer type", .{}); 21016 21017 break :msg msg; 21018 }; 21019 return sema.failWithOwnedErrorMsg(msg); 21020 }, 21021 .Optional => if (ty.isPtrLikeOptional(mod)) return, 21022 else => {}, 21023 } 21024 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(mod)}); 21025 } 21026 21027 fn checkVectorElemType( 21028 sema: *Sema, 21029 block: *Block, 21030 ty_src: LazySrcLoc, 21031 ty: Type, 21032 ) CompileError!void { 21033 const mod = sema.mod; 21034 switch (ty.zigTypeTag(mod)) { 21035 .Int, .Float, .Bool => return, 21036 else => if (ty.isPtrAtRuntime(mod)) return, 21037 } 21038 return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{}'", .{ty.fmt(mod)}); 21039 } 21040 21041 fn checkFloatType( 21042 sema: *Sema, 21043 block: *Block, 21044 ty_src: LazySrcLoc, 21045 ty: Type, 21046 ) CompileError!void { 21047 const mod = sema.mod; 21048 switch (ty.zigTypeTag(mod)) { 21049 .ComptimeInt, .ComptimeFloat, .Float => {}, 21050 else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty.fmt(mod)}), 21051 } 21052 } 21053 21054 fn checkNumericType( 21055 sema: *Sema, 21056 block: *Block, 21057 ty_src: LazySrcLoc, 21058 ty: Type, 21059 ) CompileError!void { 21060 const mod = sema.mod; 21061 switch (ty.zigTypeTag(mod)) { 21062 .ComptimeFloat, .Float, .ComptimeInt, .Int => {}, 21063 .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { 21064 .ComptimeFloat, .Float, .ComptimeInt, .Int => {}, 21065 else => |t| return sema.fail(block, ty_src, "expected number, found '{}'", .{t}), 21066 }, 21067 else => return sema.fail(block, ty_src, "expected number, found '{}'", .{ty.fmt(mod)}), 21068 } 21069 } 21070 21071 /// Returns the casted pointer. 21072 fn checkAtomicPtrOperand( 21073 sema: *Sema, 21074 block: *Block, 21075 elem_ty: Type, 21076 elem_ty_src: LazySrcLoc, 21077 ptr: Air.Inst.Ref, 21078 ptr_src: LazySrcLoc, 21079 ptr_const: bool, 21080 ) CompileError!Air.Inst.Ref { 21081 const mod = sema.mod; 21082 var diag: Module.AtomicPtrAlignmentDiagnostics = .{}; 21083 const alignment = mod.atomicPtrAlignment(elem_ty, &diag) catch |err| switch (err) { 21084 error.OutOfMemory => return error.OutOfMemory, 21085 error.FloatTooBig => return sema.fail( 21086 block, 21087 elem_ty_src, 21088 "expected {d}-bit float type or smaller; found {d}-bit float type", 21089 .{ diag.max_bits, diag.bits }, 21090 ), 21091 error.IntTooBig => return sema.fail( 21092 block, 21093 elem_ty_src, 21094 "expected {d}-bit integer type or smaller; found {d}-bit integer type", 21095 .{ diag.max_bits, diag.bits }, 21096 ), 21097 error.BadType => return sema.fail( 21098 block, 21099 elem_ty_src, 21100 "expected bool, integer, float, enum, or pointer type; found '{}'", 21101 .{elem_ty.fmt(mod)}, 21102 ), 21103 }; 21104 21105 var wanted_ptr_data: Type.Payload.Pointer.Data = .{ 21106 .pointee_type = elem_ty, 21107 .@"align" = alignment, 21108 .@"addrspace" = .generic, 21109 .mutable = !ptr_const, 21110 }; 21111 21112 const ptr_ty = sema.typeOf(ptr); 21113 const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison(mod)) { 21114 .Pointer => ptr_ty.ptrInfo(mod), 21115 else => { 21116 const wanted_ptr_ty = try Type.ptr(sema.arena, mod, wanted_ptr_data); 21117 _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); 21118 unreachable; 21119 }, 21120 }; 21121 21122 wanted_ptr_data.@"addrspace" = ptr_data.@"addrspace"; 21123 wanted_ptr_data.@"allowzero" = ptr_data.@"allowzero"; 21124 wanted_ptr_data.@"volatile" = ptr_data.@"volatile"; 21125 21126 const wanted_ptr_ty = try Type.ptr(sema.arena, mod, wanted_ptr_data); 21127 const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); 21128 21129 return casted_ptr; 21130 } 21131 21132 fn checkPtrIsNotComptimeMutable( 21133 sema: *Sema, 21134 block: *Block, 21135 ptr_val: Value, 21136 ptr_src: LazySrcLoc, 21137 operand_src: LazySrcLoc, 21138 ) CompileError!void { 21139 _ = operand_src; 21140 if (ptr_val.isComptimeMutablePtr(sema.mod)) { 21141 return sema.fail(block, ptr_src, "cannot store runtime value in compile time variable", .{}); 21142 } 21143 } 21144 21145 fn checkComptimeVarStore( 21146 sema: *Sema, 21147 block: *Block, 21148 src: LazySrcLoc, 21149 decl_ref_mut: InternPool.Key.Ptr.Addr.MutDecl, 21150 ) CompileError!void { 21151 if (@enumToInt(decl_ref_mut.runtime_index) < @enumToInt(block.runtime_index)) { 21152 if (block.runtime_cond) |cond_src| { 21153 const msg = msg: { 21154 const msg = try sema.errMsg(block, src, "store to comptime variable depends on runtime condition", .{}); 21155 errdefer msg.destroy(sema.gpa); 21156 try sema.errNote(block, cond_src, msg, "runtime condition here", .{}); 21157 break :msg msg; 21158 }; 21159 return sema.failWithOwnedErrorMsg(msg); 21160 } 21161 if (block.runtime_loop) |loop_src| { 21162 const msg = msg: { 21163 const msg = try sema.errMsg(block, src, "cannot store to comptime variable in non-inline loop", .{}); 21164 errdefer msg.destroy(sema.gpa); 21165 try sema.errNote(block, loop_src, msg, "non-inline loop here", .{}); 21166 break :msg msg; 21167 }; 21168 return sema.failWithOwnedErrorMsg(msg); 21169 } 21170 unreachable; 21171 } 21172 } 21173 21174 fn checkIntOrVector( 21175 sema: *Sema, 21176 block: *Block, 21177 operand: Air.Inst.Ref, 21178 operand_src: LazySrcLoc, 21179 ) CompileError!Type { 21180 const mod = sema.mod; 21181 const operand_ty = sema.typeOf(operand); 21182 switch (try operand_ty.zigTypeTagOrPoison(mod)) { 21183 .Int => return operand_ty, 21184 .Vector => { 21185 const elem_ty = operand_ty.childType(mod); 21186 switch (try elem_ty.zigTypeTagOrPoison(mod)) { 21187 .Int => return elem_ty, 21188 else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ 21189 elem_ty.fmt(mod), 21190 }), 21191 } 21192 }, 21193 else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{ 21194 operand_ty.fmt(mod), 21195 }), 21196 } 21197 } 21198 21199 fn checkIntOrVectorAllowComptime( 21200 sema: *Sema, 21201 block: *Block, 21202 operand_ty: Type, 21203 operand_src: LazySrcLoc, 21204 ) CompileError!Type { 21205 const mod = sema.mod; 21206 switch (try operand_ty.zigTypeTagOrPoison(mod)) { 21207 .Int, .ComptimeInt => return operand_ty, 21208 .Vector => { 21209 const elem_ty = operand_ty.childType(mod); 21210 switch (try elem_ty.zigTypeTagOrPoison(mod)) { 21211 .Int, .ComptimeInt => return elem_ty, 21212 else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ 21213 elem_ty.fmt(mod), 21214 }), 21215 } 21216 }, 21217 else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{ 21218 operand_ty.fmt(mod), 21219 }), 21220 } 21221 } 21222 21223 fn checkErrorSetType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { 21224 const mod = sema.mod; 21225 switch (ty.zigTypeTag(mod)) { 21226 .ErrorSet => return, 21227 else => return sema.fail(block, src, "expected error set type, found '{}'", .{ty.fmt(mod)}), 21228 } 21229 } 21230 21231 const SimdBinOp = struct { 21232 len: ?usize, 21233 /// Coerced to `result_ty`. 21234 lhs: Air.Inst.Ref, 21235 /// Coerced to `result_ty`. 21236 rhs: Air.Inst.Ref, 21237 lhs_val: ?Value, 21238 rhs_val: ?Value, 21239 /// Only different than `scalar_ty` when it is a vector operation. 21240 result_ty: Type, 21241 scalar_ty: Type, 21242 }; 21243 21244 fn checkSimdBinOp( 21245 sema: *Sema, 21246 block: *Block, 21247 src: LazySrcLoc, 21248 uncasted_lhs: Air.Inst.Ref, 21249 uncasted_rhs: Air.Inst.Ref, 21250 lhs_src: LazySrcLoc, 21251 rhs_src: LazySrcLoc, 21252 ) CompileError!SimdBinOp { 21253 const mod = sema.mod; 21254 const lhs_ty = sema.typeOf(uncasted_lhs); 21255 const rhs_ty = sema.typeOf(uncasted_rhs); 21256 21257 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 21258 var vec_len: ?usize = if (lhs_ty.zigTypeTag(mod) == .Vector) lhs_ty.vectorLen(mod) else null; 21259 const result_ty = try sema.resolvePeerTypes(block, src, &.{ uncasted_lhs, uncasted_rhs }, .{ 21260 .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, 21261 }); 21262 const lhs = try sema.coerce(block, result_ty, uncasted_lhs, lhs_src); 21263 const rhs = try sema.coerce(block, result_ty, uncasted_rhs, rhs_src); 21264 21265 return SimdBinOp{ 21266 .len = vec_len, 21267 .lhs = lhs, 21268 .rhs = rhs, 21269 .lhs_val = try sema.resolveMaybeUndefVal(lhs), 21270 .rhs_val = try sema.resolveMaybeUndefVal(rhs), 21271 .result_ty = result_ty, 21272 .scalar_ty = result_ty.scalarType(mod), 21273 }; 21274 } 21275 21276 fn checkVectorizableBinaryOperands( 21277 sema: *Sema, 21278 block: *Block, 21279 src: LazySrcLoc, 21280 lhs_ty: Type, 21281 rhs_ty: Type, 21282 lhs_src: LazySrcLoc, 21283 rhs_src: LazySrcLoc, 21284 ) CompileError!void { 21285 const mod = sema.mod; 21286 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); 21287 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); 21288 if (lhs_zig_ty_tag != .Vector and rhs_zig_ty_tag != .Vector) return; 21289 21290 const lhs_is_vector = switch (lhs_zig_ty_tag) { 21291 .Vector, .Array => true, 21292 else => false, 21293 }; 21294 const rhs_is_vector = switch (rhs_zig_ty_tag) { 21295 .Vector, .Array => true, 21296 else => false, 21297 }; 21298 21299 if (lhs_is_vector and rhs_is_vector) { 21300 const lhs_len = lhs_ty.arrayLen(mod); 21301 const rhs_len = rhs_ty.arrayLen(mod); 21302 if (lhs_len != rhs_len) { 21303 const msg = msg: { 21304 const msg = try sema.errMsg(block, src, "vector length mismatch", .{}); 21305 errdefer msg.destroy(sema.gpa); 21306 try sema.errNote(block, lhs_src, msg, "length {d} here", .{lhs_len}); 21307 try sema.errNote(block, rhs_src, msg, "length {d} here", .{rhs_len}); 21308 break :msg msg; 21309 }; 21310 return sema.failWithOwnedErrorMsg(msg); 21311 } 21312 } else { 21313 const msg = msg: { 21314 const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: '{}' and '{}'", .{ 21315 lhs_ty.fmt(mod), rhs_ty.fmt(mod), 21316 }); 21317 errdefer msg.destroy(sema.gpa); 21318 if (lhs_is_vector) { 21319 try sema.errNote(block, lhs_src, msg, "vector here", .{}); 21320 try sema.errNote(block, rhs_src, msg, "scalar here", .{}); 21321 } else { 21322 try sema.errNote(block, lhs_src, msg, "scalar here", .{}); 21323 try sema.errNote(block, rhs_src, msg, "vector here", .{}); 21324 } 21325 break :msg msg; 21326 }; 21327 return sema.failWithOwnedErrorMsg(msg); 21328 } 21329 } 21330 21331 fn maybeOptionsSrc(sema: *Sema, block: *Block, base_src: LazySrcLoc, wanted: []const u8) LazySrcLoc { 21332 if (base_src == .unneeded) return .unneeded; 21333 const mod = sema.mod; 21334 return mod.optionsSrc(mod.declPtr(block.src_decl), base_src, wanted); 21335 } 21336 21337 fn resolveExportOptions( 21338 sema: *Sema, 21339 block: *Block, 21340 src: LazySrcLoc, 21341 zir_ref: Zir.Inst.Ref, 21342 ) CompileError!std.builtin.ExportOptions { 21343 const mod = sema.mod; 21344 const export_options_ty = try sema.getBuiltinType("ExportOptions"); 21345 const air_ref = try sema.resolveInst(zir_ref); 21346 const options = try sema.coerce(block, export_options_ty, air_ref, src); 21347 21348 const name_src = sema.maybeOptionsSrc(block, src, "name"); 21349 const linkage_src = sema.maybeOptionsSrc(block, src, "linkage"); 21350 const section_src = sema.maybeOptionsSrc(block, src, "section"); 21351 const visibility_src = sema.maybeOptionsSrc(block, src, "visibility"); 21352 21353 const name_operand = try sema.fieldVal(block, src, options, "name", name_src); 21354 const name_val = try sema.resolveConstValue(block, name_src, name_operand, "name of exported value must be comptime-known"); 21355 const name_ty = Type.slice_const_u8; 21356 const name = try name_val.toAllocatedBytes(name_ty, sema.arena, mod); 21357 21358 const linkage_operand = try sema.fieldVal(block, src, options, "linkage", linkage_src); 21359 const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_operand, "linkage of exported value must be comptime-known"); 21360 const linkage = mod.toEnum(std.builtin.GlobalLinkage, linkage_val); 21361 21362 const section_operand = try sema.fieldVal(block, src, options, "section", section_src); 21363 const section_opt_val = try sema.resolveConstValue(block, section_src, section_operand, "linksection of exported value must be comptime-known"); 21364 const section_ty = Type.slice_const_u8; 21365 const section = if (section_opt_val.optionalValue(mod)) |section_val| 21366 try section_val.toAllocatedBytes(section_ty, sema.arena, mod) 21367 else 21368 null; 21369 21370 const visibility_operand = try sema.fieldVal(block, src, options, "visibility", visibility_src); 21371 const visibility_val = try sema.resolveConstValue(block, visibility_src, visibility_operand, "visibility of exported value must be comptime-known"); 21372 const visibility = mod.toEnum(std.builtin.SymbolVisibility, visibility_val); 21373 21374 if (name.len < 1) { 21375 return sema.fail(block, name_src, "exported symbol name cannot be empty", .{}); 21376 } 21377 21378 if (visibility != .default and linkage == .Internal) { 21379 return sema.fail(block, visibility_src, "symbol '{s}' exported with internal linkage has non-default visibility {s}", .{ 21380 name, @tagName(visibility), 21381 }); 21382 } 21383 21384 return std.builtin.ExportOptions{ 21385 .name = name, 21386 .linkage = linkage, 21387 .section = section, 21388 .visibility = visibility, 21389 }; 21390 } 21391 21392 fn resolveBuiltinEnum( 21393 sema: *Sema, 21394 block: *Block, 21395 src: LazySrcLoc, 21396 zir_ref: Zir.Inst.Ref, 21397 comptime name: []const u8, 21398 reason: []const u8, 21399 ) CompileError!@field(std.builtin, name) { 21400 const mod = sema.mod; 21401 const ty = try sema.getBuiltinType(name); 21402 const air_ref = try sema.resolveInst(zir_ref); 21403 const coerced = try sema.coerce(block, ty, air_ref, src); 21404 const val = try sema.resolveConstValue(block, src, coerced, reason); 21405 return mod.toEnum(@field(std.builtin, name), val); 21406 } 21407 21408 fn resolveAtomicOrder( 21409 sema: *Sema, 21410 block: *Block, 21411 src: LazySrcLoc, 21412 zir_ref: Zir.Inst.Ref, 21413 reason: []const u8, 21414 ) CompileError!std.builtin.AtomicOrder { 21415 return sema.resolveBuiltinEnum(block, src, zir_ref, "AtomicOrder", reason); 21416 } 21417 21418 fn resolveAtomicRmwOp( 21419 sema: *Sema, 21420 block: *Block, 21421 src: LazySrcLoc, 21422 zir_ref: Zir.Inst.Ref, 21423 ) CompileError!std.builtin.AtomicRmwOp { 21424 return sema.resolveBuiltinEnum(block, src, zir_ref, "AtomicRmwOp", "@atomicRmW operation must be comptime-known"); 21425 } 21426 21427 fn zirCmpxchg( 21428 sema: *Sema, 21429 block: *Block, 21430 extended: Zir.Inst.Extended.InstData, 21431 ) CompileError!Air.Inst.Ref { 21432 const mod = sema.mod; 21433 const extra = sema.code.extraData(Zir.Inst.Cmpxchg, extended.operand).data; 21434 const air_tag: Air.Inst.Tag = switch (extended.small) { 21435 0 => .cmpxchg_weak, 21436 1 => .cmpxchg_strong, 21437 else => unreachable, 21438 }; 21439 const src = LazySrcLoc.nodeOffset(extra.node); 21440 // zig fmt: off 21441 const elem_ty_src : LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 21442 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 21443 const expected_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node }; 21444 const new_value_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = extra.node }; 21445 const success_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg4 = extra.node }; 21446 const failure_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg5 = extra.node }; 21447 // zig fmt: on 21448 const expected_value = try sema.resolveInst(extra.expected_value); 21449 const elem_ty = sema.typeOf(expected_value); 21450 if (elem_ty.zigTypeTag(mod) == .Float) { 21451 return sema.fail( 21452 block, 21453 elem_ty_src, 21454 "expected bool, integer, enum, or pointer type; found '{}'", 21455 .{elem_ty.fmt(mod)}, 21456 ); 21457 } 21458 const uncasted_ptr = try sema.resolveInst(extra.ptr); 21459 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false); 21460 const new_value = try sema.coerce(block, elem_ty, try sema.resolveInst(extra.new_value), new_value_src); 21461 const success_order = try sema.resolveAtomicOrder(block, success_order_src, extra.success_order, "atomic order of cmpxchg success must be comptime-known"); 21462 const failure_order = try sema.resolveAtomicOrder(block, failure_order_src, extra.failure_order, "atomic order of cmpxchg failure must be comptime-known"); 21463 21464 if (@enumToInt(success_order) < @enumToInt(std.builtin.AtomicOrder.Monotonic)) { 21465 return sema.fail(block, success_order_src, "success atomic ordering must be Monotonic or stricter", .{}); 21466 } 21467 if (@enumToInt(failure_order) < @enumToInt(std.builtin.AtomicOrder.Monotonic)) { 21468 return sema.fail(block, failure_order_src, "failure atomic ordering must be Monotonic or stricter", .{}); 21469 } 21470 if (@enumToInt(failure_order) > @enumToInt(success_order)) { 21471 return sema.fail(block, failure_order_src, "failure atomic ordering must be no stricter than success", .{}); 21472 } 21473 if (failure_order == .Release or failure_order == .AcqRel) { 21474 return sema.fail(block, failure_order_src, "failure atomic ordering must not be Release or AcqRel", .{}); 21475 } 21476 21477 const result_ty = try Type.optional(sema.arena, elem_ty, mod); 21478 21479 // special case zero bit types 21480 if ((try sema.typeHasOnePossibleValue(elem_ty)) != null) { 21481 return sema.addConstant(result_ty, (try mod.intern(.{ .opt = .{ 21482 .ty = result_ty.toIntern(), 21483 .val = .none, 21484 } })).toValue()); 21485 } 21486 21487 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { 21488 if (try sema.resolveMaybeUndefVal(expected_value)) |expected_val| { 21489 if (try sema.resolveMaybeUndefVal(new_value)) |new_val| { 21490 if (expected_val.isUndef(mod) or new_val.isUndef(mod)) { 21491 // TODO: this should probably cause the memory stored at the pointer 21492 // to become undef as well 21493 return sema.addConstUndef(result_ty); 21494 } 21495 const ptr_ty = sema.typeOf(ptr); 21496 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; 21497 const result_val = try mod.intern(.{ .opt = .{ 21498 .ty = result_ty.toIntern(), 21499 .val = if (stored_val.eql(expected_val, elem_ty, mod)) blk: { 21500 try sema.storePtr(block, src, ptr, new_value); 21501 break :blk .none; 21502 } else stored_val.toIntern(), 21503 } }); 21504 return sema.addConstant(result_ty, result_val.toValue()); 21505 } else break :rs new_value_src; 21506 } else break :rs expected_src; 21507 } else ptr_src; 21508 21509 const flags: u32 = @as(u32, @enumToInt(success_order)) | 21510 (@as(u32, @enumToInt(failure_order)) << 3); 21511 21512 try sema.requireRuntimeBlock(block, src, runtime_src); 21513 return block.addInst(.{ 21514 .tag = air_tag, 21515 .data = .{ .ty_pl = .{ 21516 .ty = try sema.addType(result_ty), 21517 .payload = try sema.addExtra(Air.Cmpxchg{ 21518 .ptr = ptr, 21519 .expected_value = expected_value, 21520 .new_value = new_value, 21521 .flags = flags, 21522 }), 21523 } }, 21524 }); 21525 } 21526 21527 fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 21528 const mod = sema.mod; 21529 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 21530 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 21531 const len_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 21532 const scalar_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 21533 const len = @intCast(u32, try sema.resolveInt(block, len_src, extra.lhs, Type.u32, "vector splat destination length must be comptime-known")); 21534 const scalar = try sema.resolveInst(extra.rhs); 21535 const scalar_ty = sema.typeOf(scalar); 21536 try sema.checkVectorElemType(block, scalar_src, scalar_ty); 21537 const vector_ty = try mod.vectorType(.{ 21538 .len = len, 21539 .child = scalar_ty.toIntern(), 21540 }); 21541 if (try sema.resolveMaybeUndefVal(scalar)) |scalar_val| { 21542 if (scalar_val.isUndef(mod)) return sema.addConstUndef(vector_ty); 21543 return sema.addConstant(vector_ty, try sema.splat(vector_ty, scalar_val)); 21544 } 21545 21546 try sema.requireRuntimeBlock(block, inst_data.src(), scalar_src); 21547 return block.addTyOp(.splat, vector_ty, scalar); 21548 } 21549 21550 fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 21551 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 21552 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 21553 const op_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 21554 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 21555 const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, "ReduceOp", "@reduce operation must be comptime-known"); 21556 const operand = try sema.resolveInst(extra.rhs); 21557 const operand_ty = sema.typeOf(operand); 21558 const mod = sema.mod; 21559 21560 if (operand_ty.zigTypeTag(mod) != .Vector) { 21561 return sema.fail(block, operand_src, "expected vector, found '{}'", .{operand_ty.fmt(mod)}); 21562 } 21563 21564 const scalar_ty = operand_ty.childType(mod); 21565 21566 // Type-check depending on operation. 21567 switch (operation) { 21568 .And, .Or, .Xor => switch (scalar_ty.zigTypeTag(mod)) { 21569 .Int, .Bool => {}, 21570 else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found '{}'", .{ 21571 @tagName(operation), operand_ty.fmt(mod), 21572 }), 21573 }, 21574 .Min, .Max, .Add, .Mul => switch (scalar_ty.zigTypeTag(mod)) { 21575 .Int, .Float => {}, 21576 else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found '{}'", .{ 21577 @tagName(operation), operand_ty.fmt(mod), 21578 }), 21579 }, 21580 } 21581 21582 const vec_len = operand_ty.vectorLen(mod); 21583 if (vec_len == 0) { 21584 // TODO re-evaluate if we should introduce a "neutral value" for some operations, 21585 // e.g. zero for add and one for mul. 21586 return sema.fail(block, operand_src, "@reduce operation requires a vector with nonzero length", .{}); 21587 } 21588 21589 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { 21590 if (operand_val.isUndef(mod)) return sema.addConstUndef(scalar_ty); 21591 21592 var accum: Value = try operand_val.elemValue(mod, 0); 21593 var i: u32 = 1; 21594 while (i < vec_len) : (i += 1) { 21595 const elem_val = try operand_val.elemValue(mod, i); 21596 switch (operation) { 21597 .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena, mod), 21598 .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena, mod), 21599 .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena, mod), 21600 .Min => accum = accum.numberMin(elem_val, mod), 21601 .Max => accum = accum.numberMax(elem_val, mod), 21602 .Add => accum = try sema.numberAddWrapScalar(accum, elem_val, scalar_ty), 21603 .Mul => accum = try accum.numberMulWrap(elem_val, scalar_ty, sema.arena, mod), 21604 } 21605 } 21606 return sema.addConstant(scalar_ty, accum); 21607 } 21608 21609 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); 21610 return block.addInst(.{ 21611 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, 21612 .data = .{ .reduce = .{ 21613 .operand = operand, 21614 .operation = operation, 21615 } }, 21616 }); 21617 } 21618 21619 fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 21620 const mod = sema.mod; 21621 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 21622 const extra = sema.code.extraData(Zir.Inst.Shuffle, inst_data.payload_index).data; 21623 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 21624 const mask_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node }; 21625 21626 const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type); 21627 try sema.checkVectorElemType(block, elem_ty_src, elem_ty); 21628 var a = try sema.resolveInst(extra.a); 21629 var b = try sema.resolveInst(extra.b); 21630 var mask = try sema.resolveInst(extra.mask); 21631 var mask_ty = sema.typeOf(mask); 21632 21633 const mask_len = switch (sema.typeOf(mask).zigTypeTag(mod)) { 21634 .Array, .Vector => sema.typeOf(mask).arrayLen(mod), 21635 else => return sema.fail(block, mask_src, "expected vector or array, found '{}'", .{sema.typeOf(mask).fmt(sema.mod)}), 21636 }; 21637 mask_ty = try mod.vectorType(.{ 21638 .len = @intCast(u32, mask_len), 21639 .child = .i32_type, 21640 }); 21641 mask = try sema.coerce(block, mask_ty, mask, mask_src); 21642 const mask_val = try sema.resolveConstMaybeUndefVal(block, mask_src, mask, "shuffle mask must be comptime-known"); 21643 return sema.analyzeShuffle(block, inst_data.src_node, elem_ty, a, b, mask_val, @intCast(u32, mask_len)); 21644 } 21645 21646 fn analyzeShuffle( 21647 sema: *Sema, 21648 block: *Block, 21649 src_node: i32, 21650 elem_ty: Type, 21651 a_arg: Air.Inst.Ref, 21652 b_arg: Air.Inst.Ref, 21653 mask: Value, 21654 mask_len: u32, 21655 ) CompileError!Air.Inst.Ref { 21656 const mod = sema.mod; 21657 const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = src_node }; 21658 const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = src_node }; 21659 const mask_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = src_node }; 21660 var a = a_arg; 21661 var b = b_arg; 21662 21663 const res_ty = try mod.vectorType(.{ 21664 .len = mask_len, 21665 .child = elem_ty.toIntern(), 21666 }); 21667 21668 var maybe_a_len = switch (sema.typeOf(a).zigTypeTag(mod)) { 21669 .Array, .Vector => sema.typeOf(a).arrayLen(mod), 21670 .Undefined => null, 21671 else => return sema.fail(block, a_src, "expected vector or array with element type '{}', found '{}'", .{ 21672 elem_ty.fmt(sema.mod), 21673 sema.typeOf(a).fmt(sema.mod), 21674 }), 21675 }; 21676 var maybe_b_len = switch (sema.typeOf(b).zigTypeTag(mod)) { 21677 .Array, .Vector => sema.typeOf(b).arrayLen(mod), 21678 .Undefined => null, 21679 else => return sema.fail(block, b_src, "expected vector or array with element type '{}', found '{}'", .{ 21680 elem_ty.fmt(sema.mod), 21681 sema.typeOf(b).fmt(sema.mod), 21682 }), 21683 }; 21684 if (maybe_a_len == null and maybe_b_len == null) { 21685 return sema.addConstUndef(res_ty); 21686 } 21687 const a_len = @intCast(u32, maybe_a_len orelse maybe_b_len.?); 21688 const b_len = @intCast(u32, maybe_b_len orelse a_len); 21689 21690 const a_ty = try mod.vectorType(.{ 21691 .len = a_len, 21692 .child = elem_ty.toIntern(), 21693 }); 21694 const b_ty = try mod.vectorType(.{ 21695 .len = b_len, 21696 .child = elem_ty.toIntern(), 21697 }); 21698 21699 if (maybe_a_len == null) a = try sema.addConstUndef(a_ty) else a = try sema.coerce(block, a_ty, a, a_src); 21700 if (maybe_b_len == null) b = try sema.addConstUndef(b_ty) else b = try sema.coerce(block, b_ty, b, b_src); 21701 21702 const operand_info = [2]std.meta.Tuple(&.{ u64, LazySrcLoc, Type }){ 21703 .{ a_len, a_src, a_ty }, 21704 .{ b_len, b_src, b_ty }, 21705 }; 21706 21707 for (0..@intCast(usize, mask_len)) |i| { 21708 const elem = try mask.elemValue(sema.mod, i); 21709 if (elem.isUndef(mod)) continue; 21710 const int = elem.toSignedInt(mod); 21711 var unsigned: u32 = undefined; 21712 var chosen: u32 = undefined; 21713 if (int >= 0) { 21714 unsigned = @intCast(u32, int); 21715 chosen = 0; 21716 } else { 21717 unsigned = @intCast(u32, ~int); 21718 chosen = 1; 21719 } 21720 if (unsigned >= operand_info[chosen][0]) { 21721 const msg = msg: { 21722 const msg = try sema.errMsg(block, mask_src, "mask index '{d}' has out-of-bounds selection", .{i}); 21723 errdefer msg.destroy(sema.gpa); 21724 21725 try sema.errNote(block, operand_info[chosen][1], msg, "selected index '{d}' out of bounds of '{}'", .{ 21726 unsigned, 21727 operand_info[chosen][2].fmt(sema.mod), 21728 }); 21729 21730 if (chosen == 0) { 21731 try sema.errNote(block, b_src, msg, "selections from the second vector are specified with negative numbers", .{}); 21732 } 21733 21734 break :msg msg; 21735 }; 21736 return sema.failWithOwnedErrorMsg(msg); 21737 } 21738 } 21739 21740 if (try sema.resolveMaybeUndefVal(a)) |a_val| { 21741 if (try sema.resolveMaybeUndefVal(b)) |b_val| { 21742 const values = try sema.arena.alloc(InternPool.Index, mask_len); 21743 for (values, 0..) |*value, i| { 21744 const mask_elem_val = try mask.elemValue(sema.mod, i); 21745 if (mask_elem_val.isUndef(mod)) { 21746 value.* = try mod.intern(.{ .undef = elem_ty.toIntern() }); 21747 continue; 21748 } 21749 const int = mask_elem_val.toSignedInt(mod); 21750 const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int); 21751 values[i] = try (try (if (int >= 0) a_val else b_val).elemValue(mod, unsigned)).intern(elem_ty, mod); 21752 } 21753 return sema.addConstant(res_ty, (try mod.intern(.{ .aggregate = .{ 21754 .ty = res_ty.toIntern(), 21755 .storage = .{ .elems = values }, 21756 } })).toValue()); 21757 } 21758 } 21759 21760 // All static analysis passed, and not comptime. 21761 // For runtime codegen, vectors a and b must be the same length. Here we 21762 // recursively @shuffle the smaller vector to append undefined elements 21763 // to it up to the length of the longer vector. This recursion terminates 21764 // in 1 call because these calls to analyzeShuffle guarantee a_len == b_len. 21765 if (a_len != b_len) { 21766 const min_len = std.math.min(a_len, b_len); 21767 const max_src = if (a_len > b_len) a_src else b_src; 21768 const max_len = try sema.usizeCast(block, max_src, std.math.max(a_len, b_len)); 21769 21770 const expand_mask_values = try sema.arena.alloc(InternPool.Index, max_len); 21771 for (@intCast(usize, 0)..@intCast(usize, min_len)) |i| { 21772 expand_mask_values[i] = (try mod.intValue(Type.comptime_int, i)).toIntern(); 21773 } 21774 for (@intCast(usize, min_len)..@intCast(usize, max_len)) |i| { 21775 expand_mask_values[i] = (try mod.intValue(Type.comptime_int, -1)).toIntern(); 21776 } 21777 const expand_mask = try mod.intern(.{ .aggregate = .{ 21778 .ty = (try mod.vectorType(.{ .len = @intCast(u32, max_len), .child = .comptime_int_type })).toIntern(), 21779 .storage = .{ .elems = expand_mask_values }, 21780 } }); 21781 21782 if (a_len < b_len) { 21783 const undef = try sema.addConstUndef(a_ty); 21784 a = try sema.analyzeShuffle(block, src_node, elem_ty, a, undef, expand_mask.toValue(), @intCast(u32, max_len)); 21785 } else { 21786 const undef = try sema.addConstUndef(b_ty); 21787 b = try sema.analyzeShuffle(block, src_node, elem_ty, b, undef, expand_mask.toValue(), @intCast(u32, max_len)); 21788 } 21789 } 21790 21791 return block.addInst(.{ 21792 .tag = .shuffle, 21793 .data = .{ .ty_pl = .{ 21794 .ty = try sema.addType(res_ty), 21795 .payload = try block.sema.addExtra(Air.Shuffle{ 21796 .a = a, 21797 .b = b, 21798 .mask = mask.toIntern(), 21799 .mask_len = mask_len, 21800 }), 21801 } }, 21802 }); 21803 } 21804 21805 fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 21806 const mod = sema.mod; 21807 const extra = sema.code.extraData(Zir.Inst.Select, extended.operand).data; 21808 21809 const src = LazySrcLoc.nodeOffset(extra.node); 21810 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 21811 const pred_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 21812 const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node }; 21813 const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = extra.node }; 21814 21815 const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type); 21816 try sema.checkVectorElemType(block, elem_ty_src, elem_ty); 21817 const pred_uncoerced = try sema.resolveInst(extra.pred); 21818 const pred_ty = sema.typeOf(pred_uncoerced); 21819 21820 const vec_len_u64 = switch (try pred_ty.zigTypeTagOrPoison(mod)) { 21821 .Vector, .Array => pred_ty.arrayLen(mod), 21822 else => return sema.fail(block, pred_src, "expected vector or array, found '{}'", .{pred_ty.fmt(mod)}), 21823 }; 21824 const vec_len = @intCast(u32, try sema.usizeCast(block, pred_src, vec_len_u64)); 21825 21826 const bool_vec_ty = try mod.vectorType(.{ 21827 .len = vec_len, 21828 .child = .bool_type, 21829 }); 21830 const pred = try sema.coerce(block, bool_vec_ty, pred_uncoerced, pred_src); 21831 21832 const vec_ty = try mod.vectorType(.{ 21833 .len = vec_len, 21834 .child = elem_ty.toIntern(), 21835 }); 21836 const a = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.a), a_src); 21837 const b = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.b), b_src); 21838 21839 const maybe_pred = try sema.resolveMaybeUndefVal(pred); 21840 const maybe_a = try sema.resolveMaybeUndefVal(a); 21841 const maybe_b = try sema.resolveMaybeUndefVal(b); 21842 21843 const runtime_src = if (maybe_pred) |pred_val| rs: { 21844 if (pred_val.isUndef(mod)) return sema.addConstUndef(vec_ty); 21845 21846 if (maybe_a) |a_val| { 21847 if (a_val.isUndef(mod)) return sema.addConstUndef(vec_ty); 21848 21849 if (maybe_b) |b_val| { 21850 if (b_val.isUndef(mod)) return sema.addConstUndef(vec_ty); 21851 21852 const elems = try sema.gpa.alloc(InternPool.Index, vec_len); 21853 for (elems, 0..) |*elem, i| { 21854 const pred_elem_val = try pred_val.elemValue(mod, i); 21855 const should_choose_a = pred_elem_val.toBool(); 21856 elem.* = try (try (if (should_choose_a) a_val else b_val).elemValue(mod, i)).intern(elem_ty, mod); 21857 } 21858 21859 return sema.addConstant(vec_ty, (try mod.intern(.{ .aggregate = .{ 21860 .ty = vec_ty.toIntern(), 21861 .storage = .{ .elems = elems }, 21862 } })).toValue()); 21863 } else { 21864 break :rs b_src; 21865 } 21866 } else { 21867 if (maybe_b) |b_val| { 21868 if (b_val.isUndef(mod)) return sema.addConstUndef(vec_ty); 21869 } 21870 break :rs a_src; 21871 } 21872 } else rs: { 21873 if (maybe_a) |a_val| { 21874 if (a_val.isUndef(mod)) return sema.addConstUndef(vec_ty); 21875 } 21876 if (maybe_b) |b_val| { 21877 if (b_val.isUndef(mod)) return sema.addConstUndef(vec_ty); 21878 } 21879 break :rs pred_src; 21880 }; 21881 21882 try sema.requireRuntimeBlock(block, src, runtime_src); 21883 return block.addInst(.{ 21884 .tag = .select, 21885 .data = .{ .pl_op = .{ 21886 .operand = pred, 21887 .payload = try block.sema.addExtra(Air.Bin{ 21888 .lhs = a, 21889 .rhs = b, 21890 }), 21891 } }, 21892 }); 21893 } 21894 21895 fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 21896 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 21897 const extra = sema.code.extraData(Zir.Inst.AtomicLoad, inst_data.payload_index).data; 21898 // zig fmt: off 21899 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 21900 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 21901 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 21902 // zig fmt: on 21903 const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type); 21904 const uncasted_ptr = try sema.resolveInst(extra.ptr); 21905 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true); 21906 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicLoad must be comptime-known"); 21907 21908 switch (order) { 21909 .Release, .AcqRel => { 21910 return sema.fail( 21911 block, 21912 order_src, 21913 "@atomicLoad atomic ordering must not be Release or AcqRel", 21914 .{}, 21915 ); 21916 }, 21917 else => {}, 21918 } 21919 21920 if (try sema.typeHasOnePossibleValue(elem_ty)) |val| { 21921 return sema.addConstant(elem_ty, val); 21922 } 21923 21924 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { 21925 if (try sema.pointerDeref(block, ptr_src, ptr_val, sema.typeOf(ptr))) |elem_val| { 21926 return sema.addConstant(elem_ty, elem_val); 21927 } 21928 } 21929 21930 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); 21931 return block.addInst(.{ 21932 .tag = .atomic_load, 21933 .data = .{ .atomic_load = .{ 21934 .ptr = ptr, 21935 .order = order, 21936 } }, 21937 }); 21938 } 21939 21940 fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 21941 const mod = sema.mod; 21942 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 21943 const extra = sema.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data; 21944 const src = inst_data.src(); 21945 // zig fmt: off 21946 const elem_ty_src : LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 21947 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 21948 const op_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 21949 const operand_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node }; 21950 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg4 = inst_data.src_node }; 21951 // zig fmt: on 21952 const operand = try sema.resolveInst(extra.operand); 21953 const elem_ty = sema.typeOf(operand); 21954 const uncasted_ptr = try sema.resolveInst(extra.ptr); 21955 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false); 21956 const op = try sema.resolveAtomicRmwOp(block, op_src, extra.operation); 21957 21958 switch (elem_ty.zigTypeTag(mod)) { 21959 .Enum => if (op != .Xchg) { 21960 return sema.fail(block, op_src, "@atomicRmw with enum only allowed with .Xchg", .{}); 21961 }, 21962 .Bool => if (op != .Xchg) { 21963 return sema.fail(block, op_src, "@atomicRmw with bool only allowed with .Xchg", .{}); 21964 }, 21965 .Float => switch (op) { 21966 .Xchg, .Add, .Sub, .Max, .Min => {}, 21967 else => return sema.fail(block, op_src, "@atomicRmw with float only allowed with .Xchg, .Add, .Sub, .Max, and .Min", .{}), 21968 }, 21969 else => {}, 21970 } 21971 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicRmW must be comptime-known"); 21972 21973 if (order == .Unordered) { 21974 return sema.fail(block, order_src, "@atomicRmw atomic ordering must not be Unordered", .{}); 21975 } 21976 21977 // special case zero bit types 21978 if (try sema.typeHasOnePossibleValue(elem_ty)) |val| { 21979 return sema.addConstant(elem_ty, val); 21980 } 21981 21982 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { 21983 const maybe_operand_val = try sema.resolveMaybeUndefVal(operand); 21984 const operand_val = maybe_operand_val orelse { 21985 try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); 21986 break :rs operand_src; 21987 }; 21988 if (ptr_val.isComptimeMutablePtr(mod)) { 21989 const ptr_ty = sema.typeOf(ptr); 21990 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; 21991 const new_val = switch (op) { 21992 // zig fmt: off 21993 .Xchg => operand_val, 21994 .Add => try sema.numberAddWrapScalar(stored_val, operand_val, elem_ty), 21995 .Sub => try sema.numberSubWrapScalar(stored_val, operand_val, elem_ty), 21996 .And => try stored_val.bitwiseAnd (operand_val, elem_ty, sema.arena, mod), 21997 .Nand => try stored_val.bitwiseNand (operand_val, elem_ty, sema.arena, mod), 21998 .Or => try stored_val.bitwiseOr (operand_val, elem_ty, sema.arena, mod), 21999 .Xor => try stored_val.bitwiseXor (operand_val, elem_ty, sema.arena, mod), 22000 .Max => stored_val.numberMax (operand_val, mod), 22001 .Min => stored_val.numberMin (operand_val, mod), 22002 // zig fmt: on 22003 }; 22004 try sema.storePtrVal(block, src, ptr_val, new_val, elem_ty); 22005 return sema.addConstant(elem_ty, stored_val); 22006 } else break :rs ptr_src; 22007 } else ptr_src; 22008 22009 const flags: u32 = @as(u32, @enumToInt(order)) | (@as(u32, @enumToInt(op)) << 3); 22010 22011 try sema.requireRuntimeBlock(block, src, runtime_src); 22012 return block.addInst(.{ 22013 .tag = .atomic_rmw, 22014 .data = .{ .pl_op = .{ 22015 .operand = ptr, 22016 .payload = try sema.addExtra(Air.AtomicRmw{ 22017 .operand = operand, 22018 .flags = flags, 22019 }), 22020 } }, 22021 }); 22022 } 22023 22024 fn zirAtomicStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 22025 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 22026 const extra = sema.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data; 22027 const src = inst_data.src(); 22028 // zig fmt: off 22029 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 22030 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 22031 const operand_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 22032 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node }; 22033 // zig fmt: on 22034 const operand = try sema.resolveInst(extra.operand); 22035 const elem_ty = sema.typeOf(operand); 22036 const uncasted_ptr = try sema.resolveInst(extra.ptr); 22037 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false); 22038 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicStore must be comptime-known"); 22039 22040 const air_tag: Air.Inst.Tag = switch (order) { 22041 .Acquire, .AcqRel => { 22042 return sema.fail( 22043 block, 22044 order_src, 22045 "@atomicStore atomic ordering must not be Acquire or AcqRel", 22046 .{}, 22047 ); 22048 }, 22049 .Unordered => .atomic_store_unordered, 22050 .Monotonic => .atomic_store_monotonic, 22051 .Release => .atomic_store_release, 22052 .SeqCst => .atomic_store_seq_cst, 22053 }; 22054 22055 return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag); 22056 } 22057 22058 fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 22059 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 22060 const extra = sema.code.extraData(Zir.Inst.MulAdd, inst_data.payload_index).data; 22061 const src = inst_data.src(); 22062 22063 const mulend1_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 22064 const mulend2_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 22065 const addend_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node }; 22066 22067 const addend = try sema.resolveInst(extra.addend); 22068 const ty = sema.typeOf(addend); 22069 const mulend1 = try sema.coerce(block, ty, try sema.resolveInst(extra.mulend1), mulend1_src); 22070 const mulend2 = try sema.coerce(block, ty, try sema.resolveInst(extra.mulend2), mulend2_src); 22071 22072 const maybe_mulend1 = try sema.resolveMaybeUndefVal(mulend1); 22073 const maybe_mulend2 = try sema.resolveMaybeUndefVal(mulend2); 22074 const maybe_addend = try sema.resolveMaybeUndefVal(addend); 22075 const mod = sema.mod; 22076 22077 switch (ty.zigTypeTag(mod)) { 22078 .ComptimeFloat, .Float, .Vector => {}, 22079 else => return sema.fail(block, src, "expected vector of floats or float type, found '{}'", .{ty.fmt(sema.mod)}), 22080 } 22081 22082 const runtime_src = if (maybe_mulend1) |mulend1_val| rs: { 22083 if (maybe_mulend2) |mulend2_val| { 22084 if (mulend2_val.isUndef(mod)) return sema.addConstUndef(ty); 22085 22086 if (maybe_addend) |addend_val| { 22087 if (addend_val.isUndef(mod)) return sema.addConstUndef(ty); 22088 const result_val = try Value.mulAdd(ty, mulend1_val, mulend2_val, addend_val, sema.arena, sema.mod); 22089 return sema.addConstant(ty, result_val); 22090 } else { 22091 break :rs addend_src; 22092 } 22093 } else { 22094 if (maybe_addend) |addend_val| { 22095 if (addend_val.isUndef(mod)) return sema.addConstUndef(ty); 22096 } 22097 break :rs mulend2_src; 22098 } 22099 } else rs: { 22100 if (maybe_mulend2) |mulend2_val| { 22101 if (mulend2_val.isUndef(mod)) return sema.addConstUndef(ty); 22102 } 22103 if (maybe_addend) |addend_val| { 22104 if (addend_val.isUndef(mod)) return sema.addConstUndef(ty); 22105 } 22106 break :rs mulend1_src; 22107 }; 22108 22109 try sema.requireRuntimeBlock(block, src, runtime_src); 22110 return block.addInst(.{ 22111 .tag = .mul_add, 22112 .data = .{ .pl_op = .{ 22113 .operand = addend, 22114 .payload = try sema.addExtra(Air.Bin{ 22115 .lhs = mulend1, 22116 .rhs = mulend2, 22117 }), 22118 } }, 22119 }); 22120 } 22121 22122 fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 22123 const tracy = trace(@src()); 22124 defer tracy.end(); 22125 22126 const mod = sema.mod; 22127 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 22128 const modifier_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 22129 const func_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 22130 const args_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 22131 const call_src = inst_data.src(); 22132 22133 const extra = sema.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data; 22134 var func = try sema.resolveInst(extra.callee); 22135 22136 const modifier_ty = try sema.getBuiltinType("CallModifier"); 22137 const air_ref = try sema.resolveInst(extra.modifier); 22138 const modifier_ref = try sema.coerce(block, modifier_ty, air_ref, modifier_src); 22139 const modifier_val = try sema.resolveConstValue(block, modifier_src, modifier_ref, "call modifier must be comptime-known"); 22140 var modifier = mod.toEnum(std.builtin.CallModifier, modifier_val); 22141 switch (modifier) { 22142 // These can be upgraded to comptime or nosuspend calls. 22143 .auto, .never_tail, .no_async => { 22144 if (block.is_comptime) { 22145 if (modifier == .never_tail) { 22146 return sema.fail(block, modifier_src, "unable to perform 'never_tail' call at compile-time", .{}); 22147 } 22148 modifier = .compile_time; 22149 } else if (extra.flags.is_nosuspend) { 22150 modifier = .no_async; 22151 } 22152 }, 22153 // These can be upgraded to comptime. nosuspend bit can be safely ignored. 22154 .always_inline, .compile_time => { 22155 _ = (try sema.resolveDefinedValue(block, func_src, func)) orelse { 22156 return sema.fail(block, func_src, "modifier '{s}' requires a comptime-known function", .{@tagName(modifier)}); 22157 }; 22158 22159 if (block.is_comptime) { 22160 modifier = .compile_time; 22161 } 22162 }, 22163 .always_tail => { 22164 if (block.is_comptime) { 22165 modifier = .compile_time; 22166 } 22167 }, 22168 .async_kw => { 22169 if (extra.flags.is_nosuspend) { 22170 return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{}); 22171 } 22172 if (block.is_comptime) { 22173 return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used in combination with comptime function call", .{}); 22174 } 22175 }, 22176 .never_inline => { 22177 if (block.is_comptime) { 22178 return sema.fail(block, modifier_src, "unable to perform 'never_inline' call at compile-time", .{}); 22179 } 22180 }, 22181 } 22182 22183 const args = try sema.resolveInst(extra.args); 22184 22185 const args_ty = sema.typeOf(args); 22186 if (!args_ty.isTuple(mod) and args_ty.toIntern() != .empty_struct_type) { 22187 return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(sema.mod)}); 22188 } 22189 22190 var resolved_args: []Air.Inst.Ref = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount(mod)); 22191 for (resolved_args, 0..) |*resolved, i| { 22192 resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty); 22193 } 22194 22195 const callee_ty = sema.typeOf(func); 22196 const func_ty = try sema.checkCallArgumentCount(block, func, func_src, callee_ty, resolved_args.len, false); 22197 const ensure_result_used = extra.flags.ensure_result_used; 22198 return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null); 22199 } 22200 22201 fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 22202 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 22203 const extra = sema.code.extraData(Zir.Inst.FieldParentPtr, inst_data.payload_index).data; 22204 const src = inst_data.src(); 22205 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 22206 const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 22207 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 22208 22209 const parent_ty = try sema.resolveType(block, ty_src, extra.parent_type); 22210 const field_name = try sema.resolveConstString(block, name_src, extra.field_name, "field name must be comptime-known"); 22211 const field_ptr = try sema.resolveInst(extra.field_ptr); 22212 const field_ptr_ty = sema.typeOf(field_ptr); 22213 const mod = sema.mod; 22214 22215 if (parent_ty.zigTypeTag(mod) != .Struct and parent_ty.zigTypeTag(mod) != .Union) { 22216 return sema.fail(block, ty_src, "expected struct or union type, found '{}'", .{parent_ty.fmt(sema.mod)}); 22217 } 22218 try sema.resolveTypeLayout(parent_ty); 22219 22220 const field_index = switch (parent_ty.zigTypeTag(mod)) { 22221 .Struct => blk: { 22222 if (parent_ty.isTuple(mod)) { 22223 if (mem.eql(u8, field_name, "len")) { 22224 return sema.fail(block, src, "cannot get @fieldParentPtr of 'len' field of tuple", .{}); 22225 } 22226 break :blk try sema.tupleFieldIndex(block, parent_ty, field_name, name_src); 22227 } else { 22228 break :blk try sema.structFieldIndex(block, parent_ty, field_name, name_src); 22229 } 22230 }, 22231 .Union => try sema.unionFieldIndex(block, parent_ty, field_name, name_src), 22232 else => unreachable, 22233 }; 22234 22235 if (parent_ty.zigTypeTag(mod) == .Struct and parent_ty.structFieldIsComptime(field_index, mod)) { 22236 return sema.fail(block, src, "cannot get @fieldParentPtr of a comptime field", .{}); 22237 } 22238 22239 try sema.checkPtrOperand(block, ptr_src, field_ptr_ty); 22240 const field_ptr_ty_info = field_ptr_ty.ptrInfo(mod); 22241 22242 var ptr_ty_data: Type.Payload.Pointer.Data = .{ 22243 .pointee_type = parent_ty.structFieldType(field_index, mod), 22244 .mutable = field_ptr_ty_info.mutable, 22245 .@"addrspace" = field_ptr_ty_info.@"addrspace", 22246 }; 22247 22248 if (parent_ty.containerLayout(mod) == .Packed) { 22249 return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{}); 22250 } else { 22251 ptr_ty_data.@"align" = blk: { 22252 if (mod.typeToStruct(parent_ty)) |struct_obj| { 22253 break :blk struct_obj.fields.values()[field_index].abi_align; 22254 } else if (mod.typeToUnion(parent_ty)) |union_obj| { 22255 break :blk union_obj.fields.values()[field_index].abi_align; 22256 } else { 22257 break :blk 0; 22258 } 22259 }; 22260 } 22261 22262 const actual_field_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_ty_data); 22263 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, ptr_src); 22264 22265 ptr_ty_data.pointee_type = parent_ty; 22266 const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data); 22267 22268 if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| { 22269 const field = switch (mod.intern_pool.indexToKey(field_ptr_val.toIntern())) { 22270 .ptr => |ptr| switch (ptr.addr) { 22271 .field => |field| field, 22272 else => null, 22273 }, 22274 else => null, 22275 } orelse return sema.fail(block, ptr_src, "pointer value not based on parent struct", .{}); 22276 22277 if (field.index != field_index) { 22278 const msg = msg: { 22279 const msg = try sema.errMsg( 22280 block, 22281 src, 22282 "field '{s}' has index '{d}' but pointer value is index '{d}' of struct '{}'", 22283 .{ 22284 field_name, 22285 field_index, 22286 field.index, 22287 parent_ty.fmt(sema.mod), 22288 }, 22289 ); 22290 errdefer msg.destroy(sema.gpa); 22291 try sema.addDeclaredHereNote(msg, parent_ty); 22292 break :msg msg; 22293 }; 22294 return sema.failWithOwnedErrorMsg(msg); 22295 } 22296 return sema.addConstant(result_ptr, field.base.toValue()); 22297 } 22298 22299 try sema.requireRuntimeBlock(block, src, ptr_src); 22300 try sema.queueFullTypeResolution(result_ptr); 22301 return block.addInst(.{ 22302 .tag = .field_parent_ptr, 22303 .data = .{ .ty_pl = .{ 22304 .ty = try sema.addType(result_ptr), 22305 .payload = try block.sema.addExtra(Air.FieldParentPtr{ 22306 .field_ptr = casted_field_ptr, 22307 .field_index = @intCast(u32, field_index), 22308 }), 22309 } }, 22310 }); 22311 } 22312 22313 fn zirMinMax( 22314 sema: *Sema, 22315 block: *Block, 22316 inst: Zir.Inst.Index, 22317 comptime air_tag: Air.Inst.Tag, 22318 ) CompileError!Air.Inst.Ref { 22319 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 22320 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 22321 const src = inst_data.src(); 22322 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 22323 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 22324 const lhs = try sema.resolveInst(extra.lhs); 22325 const rhs = try sema.resolveInst(extra.rhs); 22326 try sema.checkNumericType(block, lhs_src, sema.typeOf(lhs)); 22327 try sema.checkNumericType(block, rhs_src, sema.typeOf(rhs)); 22328 return sema.analyzeMinMax(block, src, air_tag, &.{ lhs, rhs }, &.{ lhs_src, rhs_src }); 22329 } 22330 22331 fn zirMinMaxMulti( 22332 sema: *Sema, 22333 block: *Block, 22334 extended: Zir.Inst.Extended.InstData, 22335 comptime air_tag: Air.Inst.Tag, 22336 ) CompileError!Air.Inst.Ref { 22337 const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand); 22338 const src_node = extra.data.src_node; 22339 const src = LazySrcLoc.nodeOffset(src_node); 22340 const operands = sema.code.refSlice(extra.end, extended.small); 22341 22342 const air_refs = try sema.arena.alloc(Air.Inst.Ref, operands.len); 22343 const operand_srcs = try sema.arena.alloc(LazySrcLoc, operands.len); 22344 22345 for (operands, air_refs, operand_srcs, 0..) |zir_ref, *air_ref, *op_src, i| { 22346 op_src.* = switch (i) { 22347 0 => .{ .node_offset_builtin_call_arg0 = src_node }, 22348 1 => .{ .node_offset_builtin_call_arg1 = src_node }, 22349 2 => .{ .node_offset_builtin_call_arg2 = src_node }, 22350 3 => .{ .node_offset_builtin_call_arg3 = src_node }, 22351 4 => .{ .node_offset_builtin_call_arg4 = src_node }, 22352 5 => .{ .node_offset_builtin_call_arg5 = src_node }, 22353 else => src, // TODO: better source location 22354 }; 22355 air_ref.* = try sema.resolveInst(zir_ref); 22356 try sema.checkNumericType(block, op_src.*, sema.typeOf(air_ref.*)); 22357 } 22358 22359 return sema.analyzeMinMax(block, src, air_tag, air_refs, operand_srcs); 22360 } 22361 22362 fn analyzeMinMax( 22363 sema: *Sema, 22364 block: *Block, 22365 src: LazySrcLoc, 22366 comptime air_tag: Air.Inst.Tag, 22367 operands: []const Air.Inst.Ref, 22368 operand_srcs: []const LazySrcLoc, 22369 ) CompileError!Air.Inst.Ref { 22370 assert(operands.len == operand_srcs.len); 22371 assert(operands.len > 0); 22372 const mod = sema.mod; 22373 22374 if (operands.len == 1) return operands[0]; 22375 22376 const opFunc = switch (air_tag) { 22377 .min => Value.numberMin, 22378 .max => Value.numberMax, 22379 else => @compileError("unreachable"), 22380 }; 22381 22382 // First, find all comptime-known arguments, and get their min/max 22383 var runtime_known = try std.DynamicBitSet.initFull(sema.arena, operands.len); 22384 var cur_minmax: ?Air.Inst.Ref = null; 22385 var cur_minmax_src: LazySrcLoc = undefined; // defined if cur_minmax not null 22386 for (operands, operand_srcs, 0..) |operand, operand_src, operand_idx| { 22387 // Resolve the value now to avoid redundant calls to `checkSimdBinOp` - we'll have to call 22388 // it in the runtime path anyway since the result type may have been refined 22389 const uncasted_operand_val = (try sema.resolveMaybeUndefVal(operand)) orelse continue; 22390 if (cur_minmax) |cur| { 22391 const simd_op = try sema.checkSimdBinOp(block, src, cur, operand, cur_minmax_src, operand_src); 22392 const cur_val = simd_op.lhs_val.?; // cur_minmax is comptime-known 22393 const operand_val = simd_op.rhs_val.?; // we checked the operand was resolvable above 22394 22395 runtime_known.unset(operand_idx); 22396 22397 if (cur_val.isUndef(mod)) continue; // result is also undef 22398 if (operand_val.isUndef(mod)) { 22399 cur_minmax = try sema.addConstUndef(simd_op.result_ty); 22400 continue; 22401 } 22402 22403 const resolved_cur_val = try sema.resolveLazyValue(cur_val); 22404 const resolved_operand_val = try sema.resolveLazyValue(operand_val); 22405 22406 const vec_len = simd_op.len orelse { 22407 const result_val = opFunc(resolved_cur_val, resolved_operand_val, mod); 22408 cur_minmax = try sema.addConstant(simd_op.result_ty, result_val); 22409 continue; 22410 }; 22411 const elems = try sema.arena.alloc(InternPool.Index, vec_len); 22412 for (elems, 0..) |*elem, i| { 22413 const lhs_elem_val = try resolved_cur_val.elemValue(mod, i); 22414 const rhs_elem_val = try resolved_operand_val.elemValue(mod, i); 22415 elem.* = try opFunc(lhs_elem_val, rhs_elem_val, mod).intern(simd_op.scalar_ty, mod); 22416 } 22417 cur_minmax = try sema.addConstant(simd_op.result_ty, (try mod.intern(.{ .aggregate = .{ 22418 .ty = simd_op.result_ty.toIntern(), 22419 .storage = .{ .elems = elems }, 22420 } })).toValue()); 22421 } else { 22422 runtime_known.unset(operand_idx); 22423 cur_minmax = try sema.addConstant(sema.typeOf(operand), uncasted_operand_val); 22424 cur_minmax_src = operand_src; 22425 } 22426 } 22427 22428 const opt_runtime_idx = runtime_known.findFirstSet(); 22429 22430 const comptime_refined_ty: ?Type = if (cur_minmax) |ct_minmax_ref| refined: { 22431 // Refine the comptime-known result type based on the operation 22432 const val = (try sema.resolveMaybeUndefVal(ct_minmax_ref)).?; 22433 const orig_ty = sema.typeOf(ct_minmax_ref); 22434 22435 if (opt_runtime_idx == null and orig_ty.eql(Type.comptime_int, mod)) { 22436 // If all arguments were `comptime_int`, and there are no runtime args, we'll preserve that type 22437 break :refined orig_ty; 22438 } 22439 22440 const refined_ty = if (orig_ty.zigTypeTag(mod) == .Vector) blk: { 22441 const elem_ty = orig_ty.childType(mod); 22442 const len = orig_ty.vectorLen(mod); 22443 22444 if (len == 0) break :blk orig_ty; 22445 if (elem_ty.isAnyFloat()) break :blk orig_ty; // can't refine floats 22446 22447 var cur_min: Value = try val.elemValue(mod, 0); 22448 var cur_max: Value = cur_min; 22449 for (1..len) |idx| { 22450 const elem_val = try val.elemValue(mod, idx); 22451 if (elem_val.isUndef(mod)) break :blk orig_ty; // can't refine undef 22452 if (Value.order(elem_val, cur_min, mod).compare(.lt)) cur_min = elem_val; 22453 if (Value.order(elem_val, cur_max, mod).compare(.gt)) cur_max = elem_val; 22454 } 22455 22456 const refined_elem_ty = try mod.intFittingRange(cur_min, cur_max); 22457 break :blk try mod.vectorType(.{ 22458 .len = len, 22459 .child = refined_elem_ty.toIntern(), 22460 }); 22461 } else blk: { 22462 if (orig_ty.isAnyFloat()) break :blk orig_ty; // can't refine floats 22463 if (val.isUndef(mod)) break :blk orig_ty; // can't refine undef 22464 break :blk try mod.intFittingRange(val, val); 22465 }; 22466 22467 // Apply the refined type to the current value - this isn't strictly necessary in the 22468 // runtime case since we'll refine again afterwards, but keeping things as small as possible 22469 // will allow us to emit more optimal AIR (if all the runtime operands have smaller types 22470 // than the non-refined comptime type). 22471 if (!refined_ty.eql(orig_ty, mod)) { 22472 if (std.debug.runtime_safety) { 22473 assert(try sema.intFitsInType(val, refined_ty, null)); 22474 } 22475 cur_minmax = try sema.addConstant(refined_ty, (try sema.resolveMaybeUndefVal( 22476 try sema.coerceInMemory(block, val, orig_ty, refined_ty, src), 22477 )).?); 22478 } 22479 22480 break :refined refined_ty; 22481 } else null; 22482 22483 const runtime_idx = opt_runtime_idx orelse return cur_minmax.?; 22484 const runtime_src = operand_srcs[runtime_idx]; 22485 try sema.requireRuntimeBlock(block, src, runtime_src); 22486 22487 // Now, iterate over runtime operands, emitting a min/max instruction for each. We'll refine the 22488 // type again at the end, based on the comptime-known bound. 22489 22490 // If the comptime-known part is undef we can avoid emitting actual instructions later 22491 const known_undef = if (cur_minmax) |operand| blk: { 22492 const val = (try sema.resolveMaybeUndefVal(operand)).?; 22493 break :blk val.isUndef(mod); 22494 } else false; 22495 22496 if (cur_minmax == null) { 22497 // No comptime operands - use the first operand as the starting value 22498 assert(runtime_idx == 0); 22499 cur_minmax = operands[0]; 22500 cur_minmax_src = runtime_src; 22501 runtime_known.unset(0); // don't look at this operand in the loop below 22502 } 22503 22504 var it = runtime_known.iterator(.{}); 22505 while (it.next()) |idx| { 22506 const lhs = cur_minmax.?; 22507 const lhs_src = cur_minmax_src; 22508 const rhs = operands[idx]; 22509 const rhs_src = operand_srcs[idx]; 22510 const simd_op = try sema.checkSimdBinOp(block, src, lhs, rhs, lhs_src, rhs_src); 22511 if (known_undef) { 22512 cur_minmax = try sema.addConstant(simd_op.result_ty, Value.undef); 22513 } else { 22514 cur_minmax = try block.addBinOp(air_tag, simd_op.lhs, simd_op.rhs); 22515 } 22516 } 22517 22518 if (comptime_refined_ty) |comptime_ty| refine: { 22519 // Finally, refine the type based on the comptime-known bound. 22520 if (known_undef) break :refine; // can't refine undef 22521 const unrefined_ty = sema.typeOf(cur_minmax.?); 22522 const is_vector = unrefined_ty.zigTypeTag(mod) == .Vector; 22523 const comptime_elem_ty = if (is_vector) comptime_ty.childType(mod) else comptime_ty; 22524 const unrefined_elem_ty = if (is_vector) unrefined_ty.childType(mod) else unrefined_ty; 22525 22526 if (unrefined_elem_ty.isAnyFloat()) break :refine; // we can't refine floats 22527 22528 // Compute the final bounds based on the runtime type and the comptime-known bound type 22529 const min_val = switch (air_tag) { 22530 .min => try unrefined_elem_ty.minInt(mod, unrefined_elem_ty), 22531 .max => try comptime_elem_ty.minInt(mod, comptime_elem_ty), // @max(ct, rt) >= ct 22532 else => unreachable, 22533 }; 22534 const max_val = switch (air_tag) { 22535 .min => try comptime_elem_ty.maxInt(mod, comptime_elem_ty), // @min(ct, rt) <= ct 22536 .max => try unrefined_elem_ty.maxInt(mod, unrefined_elem_ty), 22537 else => unreachable, 22538 }; 22539 22540 // Find the smallest type which can contain these bounds 22541 const final_elem_ty = try mod.intFittingRange(min_val, max_val); 22542 22543 const final_ty = if (is_vector) 22544 try mod.vectorType(.{ 22545 .len = unrefined_ty.vectorLen(mod), 22546 .child = final_elem_ty.toIntern(), 22547 }) 22548 else 22549 final_elem_ty; 22550 22551 if (!final_ty.eql(unrefined_ty, mod)) { 22552 // We've reduced the type - cast the result down 22553 return block.addTyOp(.intcast, final_ty, cur_minmax.?); 22554 } 22555 } 22556 22557 return cur_minmax.?; 22558 } 22559 22560 fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !Air.Inst.Ref { 22561 const mod = sema.mod; 22562 const info = sema.typeOf(ptr).ptrInfo(mod); 22563 if (info.size == .One) { 22564 // Already an array pointer. 22565 return ptr; 22566 } 22567 const new_ty = try Type.ptr(sema.arena, mod, .{ 22568 .pointee_type = try Type.array(sema.arena, len, info.sentinel, info.pointee_type, mod), 22569 .sentinel = null, 22570 .@"align" = info.@"align", 22571 .@"addrspace" = info.@"addrspace", 22572 .mutable = info.mutable, 22573 .@"allowzero" = info.@"allowzero", 22574 .@"volatile" = info.@"volatile", 22575 .size = .One, 22576 }); 22577 if (info.size == .Slice) { 22578 return block.addTyOp(.slice_ptr, new_ty, ptr); 22579 } 22580 return block.addBitCast(new_ty, ptr); 22581 } 22582 22583 fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 22584 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 22585 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 22586 const src = inst_data.src(); 22587 const dest_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 22588 const src_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 22589 const dest_ptr = try sema.resolveInst(extra.lhs); 22590 const src_ptr = try sema.resolveInst(extra.rhs); 22591 const dest_ty = sema.typeOf(dest_ptr); 22592 const src_ty = sema.typeOf(src_ptr); 22593 const dest_len = try indexablePtrLenOrNone(sema, block, dest_src, dest_ptr); 22594 const src_len = try indexablePtrLenOrNone(sema, block, src_src, src_ptr); 22595 const target = sema.mod.getTarget(); 22596 const mod = sema.mod; 22597 22598 if (dest_ty.isConstPtr(mod)) { 22599 return sema.fail(block, dest_src, "cannot memcpy to constant pointer", .{}); 22600 } 22601 22602 if (dest_len == .none and src_len == .none) { 22603 const msg = msg: { 22604 const msg = try sema.errMsg(block, src, "unknown @memcpy length", .{}); 22605 errdefer msg.destroy(sema.gpa); 22606 try sema.errNote(block, dest_src, msg, "destination type '{}' provides no length", .{ 22607 dest_ty.fmt(sema.mod), 22608 }); 22609 try sema.errNote(block, src_src, msg, "source type '{}' provides no length", .{ 22610 src_ty.fmt(sema.mod), 22611 }); 22612 break :msg msg; 22613 }; 22614 return sema.failWithOwnedErrorMsg(msg); 22615 } 22616 22617 var len_val: ?Value = null; 22618 22619 if (dest_len != .none and src_len != .none) check: { 22620 // If we can check at compile-time, no need for runtime safety. 22621 if (try sema.resolveDefinedValue(block, dest_src, dest_len)) |dest_len_val| { 22622 len_val = dest_len_val; 22623 if (try sema.resolveDefinedValue(block, src_src, src_len)) |src_len_val| { 22624 if (!(try sema.valuesEqual(dest_len_val, src_len_val, Type.usize))) { 22625 const msg = msg: { 22626 const msg = try sema.errMsg(block, src, "non-matching @memcpy lengths", .{}); 22627 errdefer msg.destroy(sema.gpa); 22628 try sema.errNote(block, dest_src, msg, "length {} here", .{ 22629 dest_len_val.fmtValue(Type.usize, sema.mod), 22630 }); 22631 try sema.errNote(block, src_src, msg, "length {} here", .{ 22632 src_len_val.fmtValue(Type.usize, sema.mod), 22633 }); 22634 break :msg msg; 22635 }; 22636 return sema.failWithOwnedErrorMsg(msg); 22637 } 22638 break :check; 22639 } 22640 } else if (try sema.resolveDefinedValue(block, src_src, src_len)) |src_len_val| { 22641 len_val = src_len_val; 22642 } 22643 22644 if (block.wantSafety()) { 22645 const ok = try block.addBinOp(.cmp_eq, dest_len, src_len); 22646 try sema.addSafetyCheck(block, ok, .memcpy_len_mismatch); 22647 } 22648 } else if (dest_len != .none) { 22649 if (try sema.resolveDefinedValue(block, dest_src, dest_len)) |dest_len_val| { 22650 len_val = dest_len_val; 22651 } 22652 } else if (src_len != .none) { 22653 if (try sema.resolveDefinedValue(block, src_src, src_len)) |src_len_val| { 22654 len_val = src_len_val; 22655 } 22656 } 22657 22658 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: { 22659 if (!dest_ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src; 22660 if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |_| { 22661 const len_u64 = (try len_val.?.getUnsignedIntAdvanced(mod, sema)).?; 22662 const len = try sema.usizeCast(block, dest_src, len_u64); 22663 for (0..len) |i| { 22664 const elem_index = try sema.addIntUnsigned(Type.usize, i); 22665 const dest_elem_ptr = try sema.elemPtrOneLayerOnly( 22666 block, 22667 src, 22668 dest_ptr, 22669 elem_index, 22670 src, 22671 true, // init 22672 false, // oob_safety 22673 ); 22674 const src_elem_ptr = try sema.elemPtrOneLayerOnly( 22675 block, 22676 src, 22677 src_ptr, 22678 elem_index, 22679 src, 22680 false, // init 22681 false, // oob_safety 22682 ); 22683 const uncoerced_elem = try sema.analyzeLoad(block, src, src_elem_ptr, src_src); 22684 try sema.storePtr2( 22685 block, 22686 src, 22687 dest_elem_ptr, 22688 dest_src, 22689 uncoerced_elem, 22690 src_src, 22691 .store, 22692 ); 22693 } 22694 return; 22695 } else break :rs src_src; 22696 } else dest_src; 22697 22698 // If in-memory coercion is not allowed, explode this memcpy call into a 22699 // for loop that copies element-wise. 22700 // Likewise if this is an iterable rather than a pointer, do the same 22701 // lowering. The AIR instruction requires pointers with element types of 22702 // equal ABI size. 22703 22704 if (dest_ty.zigTypeTag(mod) != .Pointer or src_ty.zigTypeTag(mod) != .Pointer) { 22705 return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the source or destination iterable is a tuple", .{}); 22706 } 22707 22708 const dest_elem_ty = dest_ty.elemType2(mod); 22709 const src_elem_ty = src_ty.elemType2(mod); 22710 if (.ok != try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, true, target, dest_src, src_src)) { 22711 return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the element types have different ABI sizes", .{}); 22712 } 22713 22714 // If the length is comptime-known, then upgrade src and destination types 22715 // into pointer-to-array. At this point we know they are both pointers 22716 // already. 22717 var new_dest_ptr = dest_ptr; 22718 var new_src_ptr = src_ptr; 22719 if (len_val) |val| { 22720 const len = val.toUnsignedInt(mod); 22721 if (len == 0) { 22722 // This AIR instruction guarantees length > 0 if it is comptime-known. 22723 return; 22724 } 22725 new_dest_ptr = try upgradeToArrayPtr(sema, block, dest_ptr, len); 22726 new_src_ptr = try upgradeToArrayPtr(sema, block, src_ptr, len); 22727 } 22728 22729 if (dest_len != .none) { 22730 // Change the src from slice to a many pointer, to avoid multiple ptr 22731 // slice extractions in AIR instructions. 22732 const new_src_ptr_ty = sema.typeOf(new_src_ptr); 22733 if (new_src_ptr_ty.isSlice(mod)) { 22734 new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty); 22735 } 22736 } else if (dest_len == .none and len_val == null) { 22737 // Change the dest to a slice, since its type must have the length. 22738 const dest_ptr_ptr = try sema.analyzeRef(block, dest_src, new_dest_ptr); 22739 new_dest_ptr = try sema.analyzeSlice(block, dest_src, dest_ptr_ptr, .zero, src_len, .none, .unneeded, dest_src, dest_src, dest_src, false); 22740 const new_src_ptr_ty = sema.typeOf(new_src_ptr); 22741 if (new_src_ptr_ty.isSlice(mod)) { 22742 new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty); 22743 } 22744 } 22745 22746 try sema.requireRuntimeBlock(block, src, runtime_src); 22747 22748 // Aliasing safety check. 22749 if (block.wantSafety()) { 22750 const len = if (len_val) |v| 22751 try sema.addConstant(Type.usize, v) 22752 else if (dest_len != .none) 22753 dest_len 22754 else 22755 src_len; 22756 22757 // Extract raw pointer from dest slice. The AIR instructions could support them, but 22758 // it would cause redundant machine code instructions. 22759 const new_dest_ptr_ty = sema.typeOf(new_dest_ptr); 22760 const raw_dest_ptr = if (new_dest_ptr_ty.isSlice(mod)) 22761 try sema.analyzeSlicePtr(block, dest_src, new_dest_ptr, new_dest_ptr_ty) 22762 else if (new_dest_ptr_ty.ptrSize(mod) == .One) ptr: { 22763 var dest_manyptr_ty_key = mod.intern_pool.indexToKey(new_dest_ptr_ty.toIntern()).ptr_type; 22764 assert(dest_manyptr_ty_key.flags.size == .One); 22765 dest_manyptr_ty_key.child = dest_elem_ty.toIntern(); 22766 dest_manyptr_ty_key.flags.size = .Many; 22767 break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(dest_manyptr_ty_key), new_dest_ptr, dest_src); 22768 } else new_dest_ptr; 22769 22770 const new_src_ptr_ty = sema.typeOf(new_src_ptr); 22771 const raw_src_ptr = if (new_src_ptr_ty.isSlice(mod)) 22772 try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty) 22773 else if (new_src_ptr_ty.ptrSize(mod) == .One) ptr: { 22774 var src_manyptr_ty_key = mod.intern_pool.indexToKey(new_src_ptr_ty.toIntern()).ptr_type; 22775 assert(src_manyptr_ty_key.flags.size == .One); 22776 src_manyptr_ty_key.child = src_elem_ty.toIntern(); 22777 src_manyptr_ty_key.flags.size = .Many; 22778 break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(src_manyptr_ty_key), new_src_ptr, src_src); 22779 } else new_src_ptr; 22780 22781 // ok1: dest >= src + len 22782 // ok2: src >= dest + len 22783 const src_plus_len = try sema.analyzePtrArithmetic(block, src, raw_src_ptr, len, .ptr_add, src_src, src); 22784 const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src); 22785 const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len); 22786 const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len); 22787 const ok = try block.addBinOp(.bit_or, ok1, ok2); 22788 try sema.addSafetyCheck(block, ok, .memcpy_alias); 22789 } 22790 22791 _ = try block.addInst(.{ 22792 .tag = .memcpy, 22793 .data = .{ .bin_op = .{ 22794 .lhs = new_dest_ptr, 22795 .rhs = new_src_ptr, 22796 } }, 22797 }); 22798 } 22799 22800 fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 22801 const mod = sema.mod; 22802 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 22803 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 22804 const src = inst_data.src(); 22805 const dest_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 22806 const value_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 22807 const dest_ptr = try sema.resolveInst(extra.lhs); 22808 const uncoerced_elem = try sema.resolveInst(extra.rhs); 22809 const dest_ptr_ty = sema.typeOf(dest_ptr); 22810 try checkMemOperand(sema, block, dest_src, dest_ptr_ty); 22811 22812 if (dest_ptr_ty.isConstPtr(mod)) { 22813 return sema.fail(block, dest_src, "cannot memset constant pointer", .{}); 22814 } 22815 22816 const dest_elem_ty = dest_ptr_ty.elemType2(mod); 22817 22818 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: { 22819 const len_air_ref = try sema.fieldVal(block, src, dest_ptr, "len", dest_src); 22820 const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse 22821 break :rs dest_src; 22822 const len_u64 = (try len_val.getUnsignedIntAdvanced(mod, sema)).?; 22823 const len = try sema.usizeCast(block, dest_src, len_u64); 22824 if (len == 0) { 22825 // This AIR instruction guarantees length > 0 if it is comptime-known. 22826 return; 22827 } 22828 22829 if (!ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src; 22830 if (try sema.resolveMaybeUndefVal(uncoerced_elem)) |_| { 22831 for (0..len) |i| { 22832 const elem_index = try sema.addIntUnsigned(Type.usize, i); 22833 const elem_ptr = try sema.elemPtrOneLayerOnly( 22834 block, 22835 src, 22836 dest_ptr, 22837 elem_index, 22838 src, 22839 true, // init 22840 false, // oob_safety 22841 ); 22842 try sema.storePtr2( 22843 block, 22844 src, 22845 elem_ptr, 22846 dest_src, 22847 uncoerced_elem, 22848 value_src, 22849 .store, 22850 ); 22851 } 22852 return; 22853 } else break :rs value_src; 22854 } else dest_src; 22855 22856 const elem = try sema.coerce(block, dest_elem_ty, uncoerced_elem, value_src); 22857 22858 try sema.requireRuntimeBlock(block, src, runtime_src); 22859 _ = try block.addInst(.{ 22860 .tag = if (block.wantSafety()) .memset_safe else .memset, 22861 .data = .{ .bin_op = .{ 22862 .lhs = dest_ptr, 22863 .rhs = elem, 22864 } }, 22865 }); 22866 } 22867 22868 fn zirBuiltinAsyncCall(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 22869 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 22870 const src = LazySrcLoc.nodeOffset(extra.node); 22871 return sema.failWithUseOfAsync(block, src); 22872 } 22873 22874 fn zirResume(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 22875 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 22876 const src = inst_data.src(); 22877 return sema.failWithUseOfAsync(block, src); 22878 } 22879 22880 fn zirAwait( 22881 sema: *Sema, 22882 block: *Block, 22883 inst: Zir.Inst.Index, 22884 ) CompileError!Air.Inst.Ref { 22885 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 22886 const src = inst_data.src(); 22887 22888 return sema.failWithUseOfAsync(block, src); 22889 } 22890 22891 fn zirAwaitNosuspend( 22892 sema: *Sema, 22893 block: *Block, 22894 extended: Zir.Inst.Extended.InstData, 22895 ) CompileError!Air.Inst.Ref { 22896 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 22897 const src = LazySrcLoc.nodeOffset(extra.node); 22898 22899 return sema.failWithUseOfAsync(block, src); 22900 } 22901 22902 fn zirVarExtended( 22903 sema: *Sema, 22904 block: *Block, 22905 extended: Zir.Inst.Extended.InstData, 22906 ) CompileError!Air.Inst.Ref { 22907 const mod = sema.mod; 22908 const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand); 22909 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 }; 22910 const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 }; 22911 const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small); 22912 22913 var extra_index: usize = extra.end; 22914 22915 const lib_name: ?[]const u8 = if (small.has_lib_name) blk: { 22916 const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]); 22917 extra_index += 1; 22918 break :blk lib_name; 22919 } else null; 22920 22921 // ZIR supports encoding this information but it is not used; the information 22922 // is encoded via the Decl entry. 22923 assert(!small.has_align); 22924 22925 const uncasted_init: Air.Inst.Ref = if (small.has_init) blk: { 22926 const init_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 22927 extra_index += 1; 22928 break :blk try sema.resolveInst(init_ref); 22929 } else .none; 22930 22931 const have_ty = extra.data.var_type != .none; 22932 const var_ty = if (have_ty) 22933 try sema.resolveType(block, ty_src, extra.data.var_type) 22934 else 22935 sema.typeOf(uncasted_init); 22936 22937 const init_val = if (uncasted_init != .none) blk: { 22938 const init = if (have_ty) 22939 try sema.coerce(block, var_ty, uncasted_init, init_src) 22940 else 22941 uncasted_init; 22942 22943 break :blk ((try sema.resolveMaybeUndefVal(init)) orelse 22944 return sema.failWithNeededComptime(block, init_src, "container level variable initializers must be comptime-known")).toIntern(); 22945 } else .none; 22946 22947 try sema.validateVarType(block, ty_src, var_ty, small.is_extern); 22948 22949 return sema.addConstant(var_ty, (try mod.intern(.{ .variable = .{ 22950 .ty = var_ty.toIntern(), 22951 .init = init_val, 22952 .decl = sema.owner_decl_index, 22953 .lib_name = if (lib_name) |lname| (try mod.intern_pool.getOrPutString( 22954 sema.gpa, 22955 try sema.handleExternLibName(block, ty_src, lname), 22956 )).toOptional() else .none, 22957 .is_extern = small.is_extern, 22958 .is_threadlocal = small.is_threadlocal, 22959 } })).toValue()); 22960 } 22961 22962 fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 22963 const tracy = trace(@src()); 22964 defer tracy.end(); 22965 22966 const mod = sema.mod; 22967 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 22968 const extra = sema.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index); 22969 const target = mod.getTarget(); 22970 22971 const align_src: LazySrcLoc = .{ .node_offset_fn_type_align = inst_data.src_node }; 22972 const addrspace_src: LazySrcLoc = .{ .node_offset_fn_type_addrspace = inst_data.src_node }; 22973 const section_src: LazySrcLoc = .{ .node_offset_fn_type_section = inst_data.src_node }; 22974 const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node }; 22975 const ret_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = inst_data.src_node }; 22976 const has_body = extra.data.body_len != 0; 22977 22978 var extra_index: usize = extra.end; 22979 22980 const lib_name: ?[]const u8 = if (extra.data.bits.has_lib_name) blk: { 22981 const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]); 22982 extra_index += 1; 22983 break :blk lib_name; 22984 } else null; 22985 22986 if (has_body and 22987 (extra.data.bits.has_align_body or extra.data.bits.has_align_ref) and 22988 !target_util.supportsFunctionAlignment(target)) 22989 { 22990 return sema.fail(block, align_src, "target does not support function alignment", .{}); 22991 } 22992 22993 const @"align": ?u32 = if (extra.data.bits.has_align_body) blk: { 22994 const body_len = sema.code.extra[extra_index]; 22995 extra_index += 1; 22996 const body = sema.code.extra[extra_index..][0..body_len]; 22997 extra_index += body.len; 22998 22999 const val = try sema.resolveGenericBody(block, align_src, body, inst, Type.u29, "alignment must be comptime-known"); 23000 if (val.isGenericPoison()) { 23001 break :blk null; 23002 } 23003 const alignment = @intCast(u32, val.toUnsignedInt(mod)); 23004 try sema.validateAlign(block, align_src, alignment); 23005 if (alignment == target_util.defaultFunctionAlignment(target)) { 23006 break :blk 0; 23007 } else { 23008 break :blk alignment; 23009 } 23010 } else if (extra.data.bits.has_align_ref) blk: { 23011 const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 23012 extra_index += 1; 23013 const align_tv = sema.resolveInstConst(block, align_src, align_ref, "alignment must be comptime-known") catch |err| switch (err) { 23014 error.GenericPoison => { 23015 break :blk null; 23016 }, 23017 else => |e| return e, 23018 }; 23019 const alignment = @intCast(u32, align_tv.val.toUnsignedInt(mod)); 23020 try sema.validateAlign(block, align_src, alignment); 23021 if (alignment == target_util.defaultFunctionAlignment(target)) { 23022 break :blk 0; 23023 } else { 23024 break :blk alignment; 23025 } 23026 } else 0; 23027 23028 const @"addrspace": ?std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: { 23029 const body_len = sema.code.extra[extra_index]; 23030 extra_index += 1; 23031 const body = sema.code.extra[extra_index..][0..body_len]; 23032 extra_index += body.len; 23033 23034 const addrspace_ty = try sema.getBuiltinType("AddressSpace"); 23035 const val = try sema.resolveGenericBody(block, addrspace_src, body, inst, addrspace_ty, "addrespace must be comptime-known"); 23036 if (val.isGenericPoison()) { 23037 break :blk null; 23038 } 23039 break :blk mod.toEnum(std.builtin.AddressSpace, val); 23040 } else if (extra.data.bits.has_addrspace_ref) blk: { 23041 const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 23042 extra_index += 1; 23043 const addrspace_tv = sema.resolveInstConst(block, addrspace_src, addrspace_ref, "addrespace must be comptime-known") catch |err| switch (err) { 23044 error.GenericPoison => { 23045 break :blk null; 23046 }, 23047 else => |e| return e, 23048 }; 23049 break :blk mod.toEnum(std.builtin.AddressSpace, addrspace_tv.val); 23050 } else target_util.defaultAddressSpace(target, .function); 23051 23052 const @"linksection": FuncLinkSection = if (extra.data.bits.has_section_body) blk: { 23053 const body_len = sema.code.extra[extra_index]; 23054 extra_index += 1; 23055 const body = sema.code.extra[extra_index..][0..body_len]; 23056 extra_index += body.len; 23057 23058 const ty = Type.slice_const_u8; 23059 const val = try sema.resolveGenericBody(block, section_src, body, inst, ty, "linksection must be comptime-known"); 23060 if (val.isGenericPoison()) { 23061 break :blk FuncLinkSection{ .generic = {} }; 23062 } 23063 break :blk FuncLinkSection{ .explicit = try val.toAllocatedBytes(ty, sema.arena, sema.mod) }; 23064 } else if (extra.data.bits.has_section_ref) blk: { 23065 const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 23066 extra_index += 1; 23067 const section_name = sema.resolveConstString(block, section_src, section_ref, "linksection must be comptime-known") catch |err| switch (err) { 23068 error.GenericPoison => { 23069 break :blk FuncLinkSection{ .generic = {} }; 23070 }, 23071 else => |e| return e, 23072 }; 23073 break :blk FuncLinkSection{ .explicit = section_name }; 23074 } else FuncLinkSection{ .default = {} }; 23075 23076 const cc: ?std.builtin.CallingConvention = if (extra.data.bits.has_cc_body) blk: { 23077 const body_len = sema.code.extra[extra_index]; 23078 extra_index += 1; 23079 const body = sema.code.extra[extra_index..][0..body_len]; 23080 extra_index += body.len; 23081 23082 const cc_ty = try sema.getBuiltinType("CallingConvention"); 23083 const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty, "calling convention must be comptime-known"); 23084 if (val.isGenericPoison()) { 23085 break :blk null; 23086 } 23087 break :blk mod.toEnum(std.builtin.CallingConvention, val); 23088 } else if (extra.data.bits.has_cc_ref) blk: { 23089 const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 23090 extra_index += 1; 23091 const cc_tv = sema.resolveInstConst(block, cc_src, cc_ref, "calling convention must be comptime-known") catch |err| switch (err) { 23092 error.GenericPoison => { 23093 break :blk null; 23094 }, 23095 else => |e| return e, 23096 }; 23097 break :blk mod.toEnum(std.builtin.CallingConvention, cc_tv.val); 23098 } else if (sema.owner_decl.is_exported and has_body) 23099 .C 23100 else 23101 .Unspecified; 23102 23103 const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: { 23104 const body_len = sema.code.extra[extra_index]; 23105 extra_index += 1; 23106 const body = sema.code.extra[extra_index..][0..body_len]; 23107 extra_index += body.len; 23108 23109 const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type, "return type must be comptime-known"); 23110 const ty = val.toType(); 23111 break :blk ty; 23112 } else if (extra.data.bits.has_ret_ty_ref) blk: { 23113 const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 23114 extra_index += 1; 23115 const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref, "return type must be comptime-known") catch |err| switch (err) { 23116 error.GenericPoison => { 23117 break :blk Type.generic_poison; 23118 }, 23119 else => |e| return e, 23120 }; 23121 const ty = ret_ty_tv.val.toType(); 23122 break :blk ty; 23123 } else Type.void; 23124 23125 const noalias_bits: u32 = if (extra.data.bits.has_any_noalias) blk: { 23126 const x = sema.code.extra[extra_index]; 23127 extra_index += 1; 23128 break :blk x; 23129 } else 0; 23130 23131 var src_locs: Zir.Inst.Func.SrcLocs = undefined; 23132 if (has_body) { 23133 extra_index += extra.data.body_len; 23134 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; 23135 } 23136 23137 const is_var_args = extra.data.bits.is_var_args; 23138 const is_inferred_error = extra.data.bits.is_inferred_error; 23139 const is_extern = extra.data.bits.is_extern; 23140 const is_noinline = extra.data.bits.is_noinline; 23141 23142 return sema.funcCommon( 23143 block, 23144 inst_data.src_node, 23145 inst, 23146 @"align", 23147 @"addrspace", 23148 @"linksection", 23149 cc, 23150 ret_ty, 23151 is_var_args, 23152 is_inferred_error, 23153 is_extern, 23154 has_body, 23155 src_locs, 23156 lib_name, 23157 noalias_bits, 23158 is_noinline, 23159 ); 23160 } 23161 23162 fn zirCUndef( 23163 sema: *Sema, 23164 block: *Block, 23165 extended: Zir.Inst.Extended.InstData, 23166 ) CompileError!Air.Inst.Ref { 23167 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 23168 const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 23169 23170 const name = try sema.resolveConstString(block, src, extra.operand, "name of macro being undefined must be comptime-known"); 23171 try block.c_import_buf.?.writer().print("#undef {s}\n", .{name}); 23172 return Air.Inst.Ref.void_value; 23173 } 23174 23175 fn zirCInclude( 23176 sema: *Sema, 23177 block: *Block, 23178 extended: Zir.Inst.Extended.InstData, 23179 ) CompileError!Air.Inst.Ref { 23180 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 23181 const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 23182 23183 const name = try sema.resolveConstString(block, src, extra.operand, "path being included must be comptime-known"); 23184 try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name}); 23185 return Air.Inst.Ref.void_value; 23186 } 23187 23188 fn zirCDefine( 23189 sema: *Sema, 23190 block: *Block, 23191 extended: Zir.Inst.Extended.InstData, 23192 ) CompileError!Air.Inst.Ref { 23193 const mod = sema.mod; 23194 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; 23195 const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 23196 const val_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 23197 23198 const name = try sema.resolveConstString(block, name_src, extra.lhs, "name of macro being undefined must be comptime-known"); 23199 const rhs = try sema.resolveInst(extra.rhs); 23200 if (sema.typeOf(rhs).zigTypeTag(mod) != .Void) { 23201 const value = try sema.resolveConstString(block, val_src, extra.rhs, "value of macro being undefined must be comptime-known"); 23202 try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value }); 23203 } else { 23204 try block.c_import_buf.?.writer().print("#define {s}\n", .{name}); 23205 } 23206 return Air.Inst.Ref.void_value; 23207 } 23208 23209 fn zirWasmMemorySize( 23210 sema: *Sema, 23211 block: *Block, 23212 extended: Zir.Inst.Extended.InstData, 23213 ) CompileError!Air.Inst.Ref { 23214 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 23215 const index_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 23216 const builtin_src = LazySrcLoc.nodeOffset(extra.node); 23217 const target = sema.mod.getTarget(); 23218 if (!target.isWasm()) { 23219 return sema.fail(block, builtin_src, "builtin @wasmMemorySize is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)}); 23220 } 23221 23222 const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.operand, Type.u32, "wasm memory size index must be comptime-known")); 23223 try sema.requireRuntimeBlock(block, builtin_src, null); 23224 return block.addInst(.{ 23225 .tag = .wasm_memory_size, 23226 .data = .{ .pl_op = .{ 23227 .operand = .none, 23228 .payload = index, 23229 } }, 23230 }); 23231 } 23232 23233 fn zirWasmMemoryGrow( 23234 sema: *Sema, 23235 block: *Block, 23236 extended: Zir.Inst.Extended.InstData, 23237 ) CompileError!Air.Inst.Ref { 23238 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; 23239 const builtin_src = LazySrcLoc.nodeOffset(extra.node); 23240 const index_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 23241 const delta_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 23242 const target = sema.mod.getTarget(); 23243 if (!target.isWasm()) { 23244 return sema.fail(block, builtin_src, "builtin @wasmMemoryGrow is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)}); 23245 } 23246 23247 const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.lhs, Type.u32, "wasm memory size index must be comptime-known")); 23248 const delta = try sema.coerce(block, Type.u32, try sema.resolveInst(extra.rhs), delta_src); 23249 23250 try sema.requireRuntimeBlock(block, builtin_src, null); 23251 return block.addInst(.{ 23252 .tag = .wasm_memory_grow, 23253 .data = .{ .pl_op = .{ 23254 .operand = delta, 23255 .payload = index, 23256 } }, 23257 }); 23258 } 23259 23260 fn resolvePrefetchOptions( 23261 sema: *Sema, 23262 block: *Block, 23263 src: LazySrcLoc, 23264 zir_ref: Zir.Inst.Ref, 23265 ) CompileError!std.builtin.PrefetchOptions { 23266 const mod = sema.mod; 23267 const options_ty = try sema.getBuiltinType("PrefetchOptions"); 23268 const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src); 23269 23270 const rw_src = sema.maybeOptionsSrc(block, src, "rw"); 23271 const locality_src = sema.maybeOptionsSrc(block, src, "locality"); 23272 const cache_src = sema.maybeOptionsSrc(block, src, "cache"); 23273 23274 const rw = try sema.fieldVal(block, src, options, "rw", rw_src); 23275 const rw_val = try sema.resolveConstValue(block, rw_src, rw, "prefetch read/write must be comptime-known"); 23276 23277 const locality = try sema.fieldVal(block, src, options, "locality", locality_src); 23278 const locality_val = try sema.resolveConstValue(block, locality_src, locality, "prefetch locality must be comptime-known"); 23279 23280 const cache = try sema.fieldVal(block, src, options, "cache", cache_src); 23281 const cache_val = try sema.resolveConstValue(block, cache_src, cache, "prefetch cache must be comptime-known"); 23282 23283 return std.builtin.PrefetchOptions{ 23284 .rw = mod.toEnum(std.builtin.PrefetchOptions.Rw, rw_val), 23285 .locality = @intCast(u2, locality_val.toUnsignedInt(mod)), 23286 .cache = mod.toEnum(std.builtin.PrefetchOptions.Cache, cache_val), 23287 }; 23288 } 23289 23290 fn zirPrefetch( 23291 sema: *Sema, 23292 block: *Block, 23293 extended: Zir.Inst.Extended.InstData, 23294 ) CompileError!Air.Inst.Ref { 23295 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; 23296 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 23297 const opts_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 23298 const ptr = try sema.resolveInst(extra.lhs); 23299 try sema.checkPtrOperand(block, ptr_src, sema.typeOf(ptr)); 23300 23301 const options = sema.resolvePrefetchOptions(block, .unneeded, extra.rhs) catch |err| switch (err) { 23302 error.NeededSourceLocation => { 23303 _ = try sema.resolvePrefetchOptions(block, opts_src, extra.rhs); 23304 unreachable; 23305 }, 23306 else => |e| return e, 23307 }; 23308 23309 if (!block.is_comptime) { 23310 _ = try block.addInst(.{ 23311 .tag = .prefetch, 23312 .data = .{ .prefetch = .{ 23313 .ptr = ptr, 23314 .rw = options.rw, 23315 .locality = options.locality, 23316 .cache = options.cache, 23317 } }, 23318 }); 23319 } 23320 23321 return Air.Inst.Ref.void_value; 23322 } 23323 23324 fn resolveExternOptions( 23325 sema: *Sema, 23326 block: *Block, 23327 src: LazySrcLoc, 23328 zir_ref: Zir.Inst.Ref, 23329 ) CompileError!std.builtin.ExternOptions { 23330 const mod = sema.mod; 23331 const options_inst = try sema.resolveInst(zir_ref); 23332 const extern_options_ty = try sema.getBuiltinType("ExternOptions"); 23333 const options = try sema.coerce(block, extern_options_ty, options_inst, src); 23334 23335 const name_src = sema.maybeOptionsSrc(block, src, "name"); 23336 const library_src = sema.maybeOptionsSrc(block, src, "library"); 23337 const linkage_src = sema.maybeOptionsSrc(block, src, "linkage"); 23338 const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local"); 23339 23340 const name_ref = try sema.fieldVal(block, src, options, "name", name_src); 23341 const name_val = try sema.resolveConstValue(block, name_src, name_ref, "name of the extern symbol must be comptime-known"); 23342 const name = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); 23343 23344 const library_name_inst = try sema.fieldVal(block, src, options, "library_name", library_src); 23345 const library_name_val = try sema.resolveConstValue(block, library_src, library_name_inst, "library in which extern symbol is must be comptime-known"); 23346 23347 const linkage_ref = try sema.fieldVal(block, src, options, "linkage", linkage_src); 23348 const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_ref, "linkage of the extern symbol must be comptime-known"); 23349 const linkage = mod.toEnum(std.builtin.GlobalLinkage, linkage_val); 23350 23351 const is_thread_local = try sema.fieldVal(block, src, options, "is_thread_local", thread_local_src); 23352 const is_thread_local_val = try sema.resolveConstValue(block, thread_local_src, is_thread_local, "threadlocality of the extern symbol must be comptime-known"); 23353 23354 const library_name = if (library_name_val.optionalValue(mod)) |payload| blk: { 23355 const library_name = try payload.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); 23356 if (library_name.len == 0) { 23357 return sema.fail(block, library_src, "library name cannot be empty", .{}); 23358 } 23359 break :blk try sema.handleExternLibName(block, library_src, library_name); 23360 } else null; 23361 23362 if (name.len == 0) { 23363 return sema.fail(block, name_src, "extern symbol name cannot be empty", .{}); 23364 } 23365 23366 if (linkage != .Weak and linkage != .Strong) { 23367 return sema.fail(block, linkage_src, "extern symbol must use strong or weak linkage", .{}); 23368 } 23369 23370 return std.builtin.ExternOptions{ 23371 .name = name, 23372 .library_name = library_name, 23373 .linkage = linkage, 23374 .is_thread_local = is_thread_local_val.toBool(), 23375 }; 23376 } 23377 23378 fn zirBuiltinExtern( 23379 sema: *Sema, 23380 block: *Block, 23381 extended: Zir.Inst.Extended.InstData, 23382 ) CompileError!Air.Inst.Ref { 23383 const mod = sema.mod; 23384 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; 23385 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 23386 const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 23387 23388 var ty = try sema.resolveType(block, ty_src, extra.lhs); 23389 if (!ty.isPtrAtRuntime(mod)) { 23390 return sema.fail(block, ty_src, "expected (optional) pointer", .{}); 23391 } 23392 if (!try sema.validateExternType(ty.childType(mod), .other)) { 23393 const msg = msg: { 23394 const msg = try sema.errMsg(block, ty_src, "extern symbol cannot have type '{}'", .{ty.fmt(mod)}); 23395 errdefer msg.destroy(sema.gpa); 23396 const src_decl = sema.mod.declPtr(block.src_decl); 23397 try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl, mod), ty, .other); 23398 break :msg msg; 23399 }; 23400 return sema.failWithOwnedErrorMsg(msg); 23401 } 23402 23403 const options = sema.resolveExternOptions(block, .unneeded, extra.rhs) catch |err| switch (err) { 23404 error.NeededSourceLocation => { 23405 _ = try sema.resolveExternOptions(block, options_src, extra.rhs); 23406 unreachable; 23407 }, 23408 else => |e| return e, 23409 }; 23410 23411 if (options.linkage == .Weak and !ty.ptrAllowsZero(mod)) { 23412 ty = try Type.optional(sema.arena, ty, mod); 23413 } 23414 23415 // TODO check duplicate extern 23416 23417 const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, null); 23418 errdefer mod.destroyDecl(new_decl_index); 23419 const new_decl = mod.declPtr(new_decl_index); 23420 new_decl.name = try sema.gpa.dupeZ(u8, options.name); 23421 23422 { 23423 const new_var = try mod.intern(.{ .variable = .{ 23424 .ty = ty.toIntern(), 23425 .init = .none, 23426 .decl = sema.owner_decl_index, 23427 .is_extern = true, 23428 .is_const = true, 23429 .is_threadlocal = options.is_thread_local, 23430 .is_weak_linkage = options.linkage == .Weak, 23431 } }); 23432 23433 new_decl.src_line = sema.owner_decl.src_line; 23434 // We only access this decl through the decl_ref with the correct type created 23435 // below, so this type doesn't matter 23436 new_decl.ty = ty; 23437 new_decl.val = new_var.toValue(); 23438 new_decl.@"align" = 0; 23439 new_decl.@"linksection" = null; 23440 new_decl.has_tv = true; 23441 new_decl.analysis = .complete; 23442 new_decl.generation = mod.generation; 23443 } 23444 23445 try mod.declareDeclDependency(sema.owner_decl_index, new_decl_index); 23446 try sema.ensureDeclAnalyzed(new_decl_index); 23447 23448 return sema.addConstant(ty, try mod.getCoerced((try mod.intern(.{ .ptr = .{ 23449 .ty = switch (mod.intern_pool.indexToKey(ty.toIntern())) { 23450 .ptr_type => ty.toIntern(), 23451 .opt_type => |child_type| child_type, 23452 else => unreachable, 23453 }, 23454 .addr = .{ .decl = new_decl_index }, 23455 } })).toValue(), ty)); 23456 } 23457 23458 fn zirWorkItem( 23459 sema: *Sema, 23460 block: *Block, 23461 extended: Zir.Inst.Extended.InstData, 23462 zir_tag: Zir.Inst.Extended, 23463 ) CompileError!Air.Inst.Ref { 23464 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 23465 const dimension_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 23466 const builtin_src = LazySrcLoc.nodeOffset(extra.node); 23467 const target = sema.mod.getTarget(); 23468 23469 switch (target.cpu.arch) { 23470 // TODO: Allow for other GPU targets. 23471 .amdgcn => {}, 23472 else => { 23473 return sema.fail(block, builtin_src, "builtin only available on GPU targets; targeted architecture is {s}", .{@tagName(target.cpu.arch)}); 23474 }, 23475 } 23476 23477 const dimension = @intCast(u32, try sema.resolveInt(block, dimension_src, extra.operand, Type.u32, "dimension must be comptime-known")); 23478 try sema.requireRuntimeBlock(block, builtin_src, null); 23479 23480 return block.addInst(.{ 23481 .tag = switch (zir_tag) { 23482 .work_item_id => .work_item_id, 23483 .work_group_size => .work_group_size, 23484 .work_group_id => .work_group_id, 23485 else => unreachable, 23486 }, 23487 .data = .{ .pl_op = .{ 23488 .operand = .none, 23489 .payload = dimension, 23490 } }, 23491 }); 23492 } 23493 23494 fn zirInComptime( 23495 sema: *Sema, 23496 block: *Block, 23497 ) CompileError!Air.Inst.Ref { 23498 _ = sema; 23499 if (block.is_comptime) { 23500 return Air.Inst.Ref.bool_true; 23501 } else { 23502 return Air.Inst.Ref.bool_false; 23503 } 23504 } 23505 23506 fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: ?LazySrcLoc) !void { 23507 if (block.is_comptime) { 23508 const msg = msg: { 23509 const msg = try sema.errMsg(block, src, "unable to evaluate comptime expression", .{}); 23510 errdefer msg.destroy(sema.gpa); 23511 23512 if (runtime_src) |some| { 23513 try sema.errNote(block, some, msg, "operation is runtime due to this operand", .{}); 23514 } 23515 if (block.comptime_reason) |some| { 23516 try some.explain(sema, msg); 23517 } 23518 break :msg msg; 23519 }; 23520 return sema.failWithOwnedErrorMsg(msg); 23521 } 23522 } 23523 23524 /// Emit a compile error if type cannot be used for a runtime variable. 23525 fn validateVarType( 23526 sema: *Sema, 23527 block: *Block, 23528 src: LazySrcLoc, 23529 var_ty: Type, 23530 is_extern: bool, 23531 ) CompileError!void { 23532 const mod = sema.mod; 23533 if (is_extern and !try sema.validateExternType(var_ty, .other)) { 23534 const msg = msg: { 23535 const msg = try sema.errMsg(block, src, "extern variable cannot have type '{}'", .{var_ty.fmt(mod)}); 23536 errdefer msg.destroy(sema.gpa); 23537 const src_decl = mod.declPtr(block.src_decl); 23538 try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), var_ty, .other); 23539 break :msg msg; 23540 }; 23541 return sema.failWithOwnedErrorMsg(msg); 23542 } 23543 23544 if (try sema.validateRunTimeType(var_ty, is_extern)) return; 23545 23546 const msg = msg: { 23547 const msg = try sema.errMsg(block, src, "variable of type '{}' must be const or comptime", .{var_ty.fmt(mod)}); 23548 errdefer msg.destroy(sema.gpa); 23549 23550 const src_decl = mod.declPtr(block.src_decl); 23551 try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), var_ty); 23552 if (var_ty.zigTypeTag(mod) == .ComptimeInt or var_ty.zigTypeTag(mod) == .ComptimeFloat) { 23553 try sema.errNote(block, src, msg, "to modify this variable at runtime, it must be given an explicit fixed-size number type", .{}); 23554 } 23555 23556 break :msg msg; 23557 }; 23558 return sema.failWithOwnedErrorMsg(msg); 23559 } 23560 23561 fn validateRunTimeType( 23562 sema: *Sema, 23563 var_ty: Type, 23564 is_extern: bool, 23565 ) CompileError!bool { 23566 const mod = sema.mod; 23567 var ty = var_ty; 23568 while (true) switch (ty.zigTypeTag(mod)) { 23569 .Bool, 23570 .Int, 23571 .Float, 23572 .ErrorSet, 23573 .Frame, 23574 .AnyFrame, 23575 .Void, 23576 => return true, 23577 23578 .Enum => return !(try sema.typeRequiresComptime(ty)), 23579 23580 .ComptimeFloat, 23581 .ComptimeInt, 23582 .EnumLiteral, 23583 .NoReturn, 23584 .Type, 23585 .Undefined, 23586 .Null, 23587 .Fn, 23588 => return false, 23589 23590 .Pointer => { 23591 const elem_ty = ty.childType(mod); 23592 switch (elem_ty.zigTypeTag(mod)) { 23593 .Opaque => return true, 23594 .Fn => return elem_ty.isFnOrHasRuntimeBits(mod), 23595 else => ty = elem_ty, 23596 } 23597 }, 23598 .Opaque => return is_extern, 23599 23600 .Optional => { 23601 const child_ty = ty.optionalChild(mod); 23602 return sema.validateRunTimeType(child_ty, is_extern); 23603 }, 23604 .Array, .Vector => ty = ty.childType(mod), 23605 23606 .ErrorUnion => ty = ty.errorUnionPayload(mod), 23607 23608 .Struct, .Union => { 23609 const resolved_ty = try sema.resolveTypeFields(ty); 23610 const needs_comptime = try sema.typeRequiresComptime(resolved_ty); 23611 return !needs_comptime; 23612 }, 23613 }; 23614 } 23615 23616 const TypeSet = std.AutoHashMapUnmanaged(InternPool.Index, void); 23617 23618 fn explainWhyTypeIsComptime( 23619 sema: *Sema, 23620 msg: *Module.ErrorMsg, 23621 src_loc: Module.SrcLoc, 23622 ty: Type, 23623 ) CompileError!void { 23624 var type_set = TypeSet{}; 23625 defer type_set.deinit(sema.gpa); 23626 23627 try sema.resolveTypeFully(ty); 23628 return sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty, &type_set); 23629 } 23630 23631 fn explainWhyTypeIsComptimeInner( 23632 sema: *Sema, 23633 msg: *Module.ErrorMsg, 23634 src_loc: Module.SrcLoc, 23635 ty: Type, 23636 type_set: *TypeSet, 23637 ) CompileError!void { 23638 const mod = sema.mod; 23639 switch (ty.zigTypeTag(mod)) { 23640 .Bool, 23641 .Int, 23642 .Float, 23643 .ErrorSet, 23644 .Enum, 23645 .Frame, 23646 .AnyFrame, 23647 .Void, 23648 => return, 23649 23650 .Fn => { 23651 try mod.errNoteNonLazy(src_loc, msg, "use '*const {}' for a function pointer type", .{ 23652 ty.fmt(sema.mod), 23653 }); 23654 }, 23655 23656 .Type => { 23657 try mod.errNoteNonLazy(src_loc, msg, "types are not available at runtime", .{}); 23658 }, 23659 23660 .ComptimeFloat, 23661 .ComptimeInt, 23662 .EnumLiteral, 23663 .NoReturn, 23664 .Undefined, 23665 .Null, 23666 => return, 23667 23668 .Opaque => { 23669 try mod.errNoteNonLazy(src_loc, msg, "opaque type '{}' has undefined size", .{ty.fmt(sema.mod)}); 23670 }, 23671 23672 .Array, .Vector => { 23673 try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.childType(mod), type_set); 23674 }, 23675 .Pointer => { 23676 const elem_ty = ty.elemType2(mod); 23677 if (elem_ty.zigTypeTag(mod) == .Fn) { 23678 const fn_info = mod.typeToFunc(elem_ty).?; 23679 if (fn_info.is_generic) { 23680 try mod.errNoteNonLazy(src_loc, msg, "function is generic", .{}); 23681 } 23682 switch (fn_info.cc) { 23683 .Inline => try mod.errNoteNonLazy(src_loc, msg, "function has inline calling convention", .{}), 23684 else => {}, 23685 } 23686 if (fn_info.return_type.toType().comptimeOnly(mod)) { 23687 try mod.errNoteNonLazy(src_loc, msg, "function has a comptime-only return type", .{}); 23688 } 23689 return; 23690 } 23691 try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.childType(mod), type_set); 23692 }, 23693 23694 .Optional => { 23695 try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.optionalChild(mod), type_set); 23696 }, 23697 .ErrorUnion => { 23698 try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.errorUnionPayload(mod), type_set); 23699 }, 23700 23701 .Struct => { 23702 if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return; 23703 23704 if (mod.typeToStruct(ty)) |struct_obj| { 23705 for (struct_obj.fields.values(), 0..) |field, i| { 23706 const field_src_loc = mod.fieldSrcLoc(struct_obj.owner_decl, .{ 23707 .index = i, 23708 .range = .type, 23709 }); 23710 23711 if (try sema.typeRequiresComptime(field.ty)) { 23712 try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{}); 23713 try sema.explainWhyTypeIsComptimeInner(msg, field_src_loc, field.ty, type_set); 23714 } 23715 } 23716 } 23717 // TODO tuples 23718 }, 23719 23720 .Union => { 23721 if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return; 23722 23723 if (mod.typeToUnion(ty)) |union_obj| { 23724 for (union_obj.fields.values(), 0..) |field, i| { 23725 const field_src_loc = mod.fieldSrcLoc(union_obj.owner_decl, .{ 23726 .index = i, 23727 .range = .type, 23728 }); 23729 23730 if (try sema.typeRequiresComptime(field.ty)) { 23731 try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{}); 23732 try sema.explainWhyTypeIsComptimeInner(msg, field_src_loc, field.ty, type_set); 23733 } 23734 } 23735 } 23736 }, 23737 } 23738 } 23739 23740 const ExternPosition = enum { 23741 ret_ty, 23742 param_ty, 23743 union_field, 23744 struct_field, 23745 element, 23746 other, 23747 }; 23748 23749 /// Returns true if `ty` is allowed in extern types. 23750 /// Does *NOT* require `ty` to be resolved in any way. 23751 /// Calls `resolveTypeLayout` for packed containers. 23752 fn validateExternType( 23753 sema: *Sema, 23754 ty: Type, 23755 position: ExternPosition, 23756 ) !bool { 23757 const mod = sema.mod; 23758 switch (ty.zigTypeTag(mod)) { 23759 .Type, 23760 .ComptimeFloat, 23761 .ComptimeInt, 23762 .EnumLiteral, 23763 .Undefined, 23764 .Null, 23765 .ErrorUnion, 23766 .ErrorSet, 23767 .Frame, 23768 => return false, 23769 .Void => return position == .union_field or position == .ret_ty, 23770 .NoReturn => return position == .ret_ty, 23771 .Opaque, 23772 .Bool, 23773 .Float, 23774 .AnyFrame, 23775 => return true, 23776 .Pointer => return !(ty.isSlice(mod) or try sema.typeRequiresComptime(ty)), 23777 .Int => switch (ty.intInfo(mod).bits) { 23778 8, 16, 32, 64, 128 => return true, 23779 else => return false, 23780 }, 23781 .Fn => { 23782 if (position != .other) return false; 23783 const target = sema.mod.getTarget(); 23784 // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI. 23785 // The goal is to experiment with more integrated CPU/GPU code. 23786 if (ty.fnCallingConvention(mod) == .Kernel and (target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64)) { 23787 return true; 23788 } 23789 return !target_util.fnCallConvAllowsZigTypes(target, ty.fnCallingConvention(mod)); 23790 }, 23791 .Enum => { 23792 return sema.validateExternType(ty.intTagType(mod), position); 23793 }, 23794 .Struct, .Union => switch (ty.containerLayout(mod)) { 23795 .Extern => return true, 23796 .Packed => { 23797 const bit_size = try ty.bitSizeAdvanced(mod, sema); 23798 switch (bit_size) { 23799 8, 16, 32, 64, 128 => return true, 23800 else => return false, 23801 } 23802 }, 23803 .Auto => return false, 23804 }, 23805 .Array => { 23806 if (position == .ret_ty or position == .param_ty) return false; 23807 return sema.validateExternType(ty.elemType2(mod), .element); 23808 }, 23809 .Vector => return sema.validateExternType(ty.elemType2(mod), .element), 23810 .Optional => return ty.isPtrLikeOptional(mod), 23811 } 23812 } 23813 23814 fn explainWhyTypeIsNotExtern( 23815 sema: *Sema, 23816 msg: *Module.ErrorMsg, 23817 src_loc: Module.SrcLoc, 23818 ty: Type, 23819 position: ExternPosition, 23820 ) CompileError!void { 23821 const mod = sema.mod; 23822 switch (ty.zigTypeTag(mod)) { 23823 .Opaque, 23824 .Bool, 23825 .Float, 23826 .AnyFrame, 23827 => return, 23828 23829 .Type, 23830 .ComptimeFloat, 23831 .ComptimeInt, 23832 .EnumLiteral, 23833 .Undefined, 23834 .Null, 23835 .ErrorUnion, 23836 .ErrorSet, 23837 .Frame, 23838 => return, 23839 23840 .Pointer => { 23841 if (ty.isSlice(mod)) { 23842 try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{}); 23843 } else { 23844 const pointee_ty = ty.childType(mod); 23845 try mod.errNoteNonLazy(src_loc, msg, "pointer to comptime-only type '{}'", .{pointee_ty.fmt(sema.mod)}); 23846 try sema.explainWhyTypeIsComptime(msg, src_loc, pointee_ty); 23847 } 23848 }, 23849 .Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}), 23850 .NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}), 23851 .Int => if (!std.math.isPowerOfTwo(ty.intInfo(mod).bits)) { 23852 try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{}); 23853 } else { 23854 try mod.errNoteNonLazy(src_loc, msg, "only integers with 8, 16, 32, 64 and 128 bits are extern compatible", .{}); 23855 }, 23856 .Fn => { 23857 if (position != .other) { 23858 try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{}); 23859 try mod.errNoteNonLazy(src_loc, msg, "use '*const ' to make a function pointer type", .{}); 23860 return; 23861 } 23862 switch (ty.fnCallingConvention(mod)) { 23863 .Unspecified => try mod.errNoteNonLazy(src_loc, msg, "extern function must specify calling convention", .{}), 23864 .Async => try mod.errNoteNonLazy(src_loc, msg, "async function cannot be extern", .{}), 23865 .Inline => try mod.errNoteNonLazy(src_loc, msg, "inline function cannot be extern", .{}), 23866 else => return, 23867 } 23868 }, 23869 .Enum => { 23870 const tag_ty = ty.intTagType(mod); 23871 try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)}); 23872 try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); 23873 }, 23874 .Struct => try mod.errNoteNonLazy(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}), 23875 .Union => try mod.errNoteNonLazy(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}), 23876 .Array => { 23877 if (position == .ret_ty) { 23878 return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a return type", .{}); 23879 } else if (position == .param_ty) { 23880 return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a parameter type", .{}); 23881 } 23882 try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(mod), .element); 23883 }, 23884 .Vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(mod), .element), 23885 .Optional => try mod.errNoteNonLazy(src_loc, msg, "only pointer like optionals are extern compatible", .{}), 23886 } 23887 } 23888 23889 /// Returns true if `ty` is allowed in packed types. 23890 /// Does *NOT* require `ty` to be resolved in any way. 23891 fn validatePackedType(ty: Type, mod: *Module) bool { 23892 switch (ty.zigTypeTag(mod)) { 23893 .Type, 23894 .ComptimeFloat, 23895 .ComptimeInt, 23896 .EnumLiteral, 23897 .Undefined, 23898 .Null, 23899 .ErrorUnion, 23900 .ErrorSet, 23901 .Frame, 23902 .NoReturn, 23903 .Opaque, 23904 .AnyFrame, 23905 .Fn, 23906 .Array, 23907 => return false, 23908 .Optional => return ty.isPtrLikeOptional(mod), 23909 .Void, 23910 .Bool, 23911 .Float, 23912 .Int, 23913 .Vector, 23914 .Enum, 23915 => return true, 23916 .Pointer => return !ty.isSlice(mod), 23917 .Struct, .Union => return ty.containerLayout(mod) == .Packed, 23918 } 23919 } 23920 23921 fn explainWhyTypeIsNotPacked( 23922 sema: *Sema, 23923 msg: *Module.ErrorMsg, 23924 src_loc: Module.SrcLoc, 23925 ty: Type, 23926 ) CompileError!void { 23927 const mod = sema.mod; 23928 switch (ty.zigTypeTag(mod)) { 23929 .Void, 23930 .Bool, 23931 .Float, 23932 .Int, 23933 .Vector, 23934 .Enum, 23935 => return, 23936 .Type, 23937 .ComptimeFloat, 23938 .ComptimeInt, 23939 .EnumLiteral, 23940 .Undefined, 23941 .Null, 23942 .Frame, 23943 .NoReturn, 23944 .Opaque, 23945 .ErrorUnion, 23946 .ErrorSet, 23947 .AnyFrame, 23948 .Optional, 23949 .Array, 23950 => try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{}), 23951 .Pointer => try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{}), 23952 .Fn => { 23953 try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{}); 23954 try mod.errNoteNonLazy(src_loc, msg, "use '*const ' to make a function pointer type", .{}); 23955 }, 23956 .Struct => try mod.errNoteNonLazy(src_loc, msg, "only packed structs layout are allowed in packed types", .{}), 23957 .Union => try mod.errNoteNonLazy(src_loc, msg, "only packed unions layout are allowed in packed types", .{}), 23958 } 23959 } 23960 23961 pub const PanicId = enum { 23962 unreach, 23963 unwrap_null, 23964 cast_to_null, 23965 incorrect_alignment, 23966 invalid_error_code, 23967 cast_truncated_data, 23968 negative_to_unsigned, 23969 integer_overflow, 23970 shl_overflow, 23971 shr_overflow, 23972 divide_by_zero, 23973 exact_division_remainder, 23974 inactive_union_field, 23975 integer_part_out_of_bounds, 23976 corrupt_switch, 23977 shift_rhs_too_big, 23978 invalid_enum_value, 23979 sentinel_mismatch, 23980 unwrap_error, 23981 index_out_of_bounds, 23982 start_index_greater_than_end, 23983 for_len_mismatch, 23984 memcpy_len_mismatch, 23985 memcpy_alias, 23986 noreturn_returned, 23987 }; 23988 23989 fn addSafetyCheck( 23990 sema: *Sema, 23991 parent_block: *Block, 23992 ok: Air.Inst.Ref, 23993 panic_id: PanicId, 23994 ) !void { 23995 const gpa = sema.gpa; 23996 assert(!parent_block.is_comptime); 23997 23998 var fail_block: Block = .{ 23999 .parent = parent_block, 24000 .sema = sema, 24001 .src_decl = parent_block.src_decl, 24002 .namespace = parent_block.namespace, 24003 .wip_capture_scope = parent_block.wip_capture_scope, 24004 .instructions = .{}, 24005 .inlining = parent_block.inlining, 24006 .is_comptime = false, 24007 }; 24008 24009 defer fail_block.instructions.deinit(gpa); 24010 24011 try sema.safetyPanic(&fail_block, panic_id); 24012 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); 24013 } 24014 24015 fn addSafetyCheckExtra( 24016 sema: *Sema, 24017 parent_block: *Block, 24018 ok: Air.Inst.Ref, 24019 fail_block: *Block, 24020 ) !void { 24021 const gpa = sema.gpa; 24022 24023 try parent_block.instructions.ensureUnusedCapacity(gpa, 1); 24024 24025 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + 24026 1 + // The main block only needs space for the cond_br. 24027 @typeInfo(Air.CondBr).Struct.fields.len + 24028 1 + // The ok branch of the cond_br only needs space for the br. 24029 fail_block.instructions.items.len); 24030 24031 try sema.air_instructions.ensureUnusedCapacity(gpa, 3); 24032 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 24033 const cond_br_inst = block_inst + 1; 24034 const br_inst = cond_br_inst + 1; 24035 sema.air_instructions.appendAssumeCapacity(.{ 24036 .tag = .block, 24037 .data = .{ .ty_pl = .{ 24038 .ty = .void_type, 24039 .payload = sema.addExtraAssumeCapacity(Air.Block{ 24040 .body_len = 1, 24041 }), 24042 } }, 24043 }); 24044 sema.air_extra.appendAssumeCapacity(cond_br_inst); 24045 24046 sema.air_instructions.appendAssumeCapacity(.{ 24047 .tag = .cond_br, 24048 .data = .{ .pl_op = .{ 24049 .operand = ok, 24050 .payload = sema.addExtraAssumeCapacity(Air.CondBr{ 24051 .then_body_len = 1, 24052 .else_body_len = @intCast(u32, fail_block.instructions.items.len), 24053 }), 24054 } }, 24055 }); 24056 sema.air_extra.appendAssumeCapacity(br_inst); 24057 sema.air_extra.appendSliceAssumeCapacity(fail_block.instructions.items); 24058 24059 sema.air_instructions.appendAssumeCapacity(.{ 24060 .tag = .br, 24061 .data = .{ .br = .{ 24062 .block_inst = block_inst, 24063 .operand = .void_value, 24064 } }, 24065 }); 24066 24067 parent_block.instructions.appendAssumeCapacity(block_inst); 24068 } 24069 24070 fn panicWithMsg( 24071 sema: *Sema, 24072 block: *Block, 24073 msg_inst: Air.Inst.Ref, 24074 ) !void { 24075 const mod = sema.mod; 24076 24077 if (!mod.backendSupportsFeature(.panic_fn)) { 24078 _ = try block.addNoOp(.trap); 24079 return; 24080 } 24081 const panic_fn = try sema.getBuiltin("panic"); 24082 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); 24083 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); 24084 const target = mod.getTarget(); 24085 const ptr_stack_trace_ty = try mod.ptrType(.{ 24086 .child = stack_trace_ty.toIntern(), 24087 .flags = .{ 24088 .address_space = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic 24089 }, 24090 }); 24091 const opt_ptr_stack_trace_ty = try mod.optionalType(ptr_stack_trace_ty.toIntern()); 24092 const null_stack_trace = try sema.addConstant(opt_ptr_stack_trace_ty, (try mod.intern(.{ .opt = .{ 24093 .ty = opt_ptr_stack_trace_ty.toIntern(), 24094 .val = .none, 24095 } })).toValue()); 24096 24097 const opt_usize_ty = try mod.optionalType(.usize_type); 24098 const null_ret_addr = try sema.addConstant(opt_usize_ty, (try mod.intern(.{ .opt = .{ 24099 .ty = opt_usize_ty.toIntern(), 24100 .val = .none, 24101 } })).toValue()); 24102 try sema.callBuiltin(block, panic_fn, .auto, &.{ msg_inst, null_stack_trace, null_ret_addr }); 24103 } 24104 24105 fn panicUnwrapError( 24106 sema: *Sema, 24107 parent_block: *Block, 24108 operand: Air.Inst.Ref, 24109 unwrap_err_tag: Air.Inst.Tag, 24110 is_non_err_tag: Air.Inst.Tag, 24111 ) !void { 24112 assert(!parent_block.is_comptime); 24113 const ok = try parent_block.addUnOp(is_non_err_tag, operand); 24114 if (!sema.mod.comp.formatted_panics) { 24115 return sema.addSafetyCheck(parent_block, ok, .unwrap_error); 24116 } 24117 const gpa = sema.gpa; 24118 24119 var fail_block: Block = .{ 24120 .parent = parent_block, 24121 .sema = sema, 24122 .src_decl = parent_block.src_decl, 24123 .namespace = parent_block.namespace, 24124 .wip_capture_scope = parent_block.wip_capture_scope, 24125 .instructions = .{}, 24126 .inlining = parent_block.inlining, 24127 .is_comptime = false, 24128 }; 24129 24130 defer fail_block.instructions.deinit(gpa); 24131 24132 { 24133 if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) { 24134 _ = try fail_block.addNoOp(.trap); 24135 } else { 24136 const panic_fn = try sema.getBuiltin("panicUnwrapError"); 24137 const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand); 24138 const err_return_trace = try sema.getErrorReturnTrace(&fail_block); 24139 const args: [2]Air.Inst.Ref = .{ err_return_trace, err }; 24140 try sema.callBuiltin(&fail_block, panic_fn, .auto, &args); 24141 } 24142 } 24143 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); 24144 } 24145 24146 fn panicIndexOutOfBounds( 24147 sema: *Sema, 24148 parent_block: *Block, 24149 index: Air.Inst.Ref, 24150 len: Air.Inst.Ref, 24151 cmp_op: Air.Inst.Tag, 24152 ) !void { 24153 assert(!parent_block.is_comptime); 24154 const ok = try parent_block.addBinOp(cmp_op, index, len); 24155 if (!sema.mod.comp.formatted_panics) { 24156 return sema.addSafetyCheck(parent_block, ok, .index_out_of_bounds); 24157 } 24158 try sema.safetyCheckFormatted(parent_block, ok, "panicOutOfBounds", &.{ index, len }); 24159 } 24160 24161 fn panicInactiveUnionField( 24162 sema: *Sema, 24163 parent_block: *Block, 24164 active_tag: Air.Inst.Ref, 24165 wanted_tag: Air.Inst.Ref, 24166 ) !void { 24167 assert(!parent_block.is_comptime); 24168 const ok = try parent_block.addBinOp(.cmp_eq, active_tag, wanted_tag); 24169 if (!sema.mod.comp.formatted_panics) { 24170 return sema.addSafetyCheck(parent_block, ok, .inactive_union_field); 24171 } 24172 try sema.safetyCheckFormatted(parent_block, ok, "panicInactiveUnionField", &.{ active_tag, wanted_tag }); 24173 } 24174 24175 fn panicSentinelMismatch( 24176 sema: *Sema, 24177 parent_block: *Block, 24178 maybe_sentinel: ?Value, 24179 sentinel_ty: Type, 24180 ptr: Air.Inst.Ref, 24181 sentinel_index: Air.Inst.Ref, 24182 ) !void { 24183 assert(!parent_block.is_comptime); 24184 const mod = sema.mod; 24185 const expected_sentinel_val = maybe_sentinel orelse return; 24186 const expected_sentinel = try sema.addConstant(sentinel_ty, expected_sentinel_val); 24187 24188 const ptr_ty = sema.typeOf(ptr); 24189 const actual_sentinel = if (ptr_ty.isSlice(mod)) 24190 try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index) 24191 else blk: { 24192 const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null); 24193 const sentinel_ptr = try parent_block.addPtrElemPtr(ptr, sentinel_index, elem_ptr_ty); 24194 break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr); 24195 }; 24196 24197 const ok = if (sentinel_ty.zigTypeTag(mod) == .Vector) ok: { 24198 const eql = 24199 try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq); 24200 break :ok try parent_block.addInst(.{ 24201 .tag = .reduce, 24202 .data = .{ .reduce = .{ 24203 .operand = eql, 24204 .operation = .And, 24205 } }, 24206 }); 24207 } else if (sentinel_ty.isSelfComparable(mod, true)) 24208 try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel) 24209 else { 24210 const panic_fn = try sema.getBuiltin("checkNonScalarSentinel"); 24211 const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel }; 24212 try sema.callBuiltin(parent_block, panic_fn, .auto, &args); 24213 return; 24214 }; 24215 24216 if (!sema.mod.comp.formatted_panics) { 24217 return sema.addSafetyCheck(parent_block, ok, .sentinel_mismatch); 24218 } 24219 try sema.safetyCheckFormatted(parent_block, ok, "panicSentinelMismatch", &.{ expected_sentinel, actual_sentinel }); 24220 } 24221 24222 fn safetyCheckFormatted( 24223 sema: *Sema, 24224 parent_block: *Block, 24225 ok: Air.Inst.Ref, 24226 func: []const u8, 24227 args: []const Air.Inst.Ref, 24228 ) CompileError!void { 24229 assert(sema.mod.comp.formatted_panics); 24230 const gpa = sema.gpa; 24231 24232 var fail_block: Block = .{ 24233 .parent = parent_block, 24234 .sema = sema, 24235 .src_decl = parent_block.src_decl, 24236 .namespace = parent_block.namespace, 24237 .wip_capture_scope = parent_block.wip_capture_scope, 24238 .instructions = .{}, 24239 .inlining = parent_block.inlining, 24240 .is_comptime = false, 24241 }; 24242 24243 defer fail_block.instructions.deinit(gpa); 24244 24245 if (!sema.mod.backendSupportsFeature(.safety_check_formatted)) { 24246 _ = try fail_block.addNoOp(.trap); 24247 } else { 24248 const panic_fn = try sema.getBuiltin(func); 24249 try sema.callBuiltin(&fail_block, panic_fn, .auto, args); 24250 } 24251 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); 24252 } 24253 24254 fn safetyPanic( 24255 sema: *Sema, 24256 block: *Block, 24257 panic_id: PanicId, 24258 ) CompileError!void { 24259 const mod = sema.mod; 24260 const panic_messages_ty = try sema.getBuiltinType("panic_messages"); 24261 const msg_decl_index = (try sema.namespaceLookup( 24262 block, 24263 sema.src, 24264 panic_messages_ty.getNamespaceIndex(mod).unwrap().?, 24265 @tagName(panic_id), 24266 )).?; 24267 24268 const msg_inst = try sema.analyzeDeclVal(block, sema.src, msg_decl_index); 24269 try sema.panicWithMsg(block, msg_inst); 24270 } 24271 24272 fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void { 24273 sema.branch_count += 1; 24274 if (sema.branch_count > sema.branch_quota) { 24275 const msg = try sema.errMsg( 24276 block, 24277 src, 24278 "evaluation exceeded {d} backwards branches", 24279 .{sema.branch_quota}, 24280 ); 24281 try sema.errNote( 24282 block, 24283 src, 24284 msg, 24285 "use @setEvalBranchQuota() to raise the branch limit from {d}", 24286 .{sema.branch_quota}, 24287 ); 24288 return sema.failWithOwnedErrorMsg(msg); 24289 } 24290 } 24291 24292 fn fieldVal( 24293 sema: *Sema, 24294 block: *Block, 24295 src: LazySrcLoc, 24296 object: Air.Inst.Ref, 24297 field_name: []const u8, 24298 field_name_src: LazySrcLoc, 24299 ) CompileError!Air.Inst.Ref { 24300 // When editing this function, note that there is corresponding logic to be edited 24301 // in `fieldPtr`. This function takes a value and returns a value. 24302 24303 const mod = sema.mod; 24304 const gpa = sema.gpa; 24305 const ip = &mod.intern_pool; 24306 const object_src = src; // TODO better source location 24307 const object_ty = sema.typeOf(object); 24308 24309 // Zig allows dereferencing a single pointer during field lookup. Note that 24310 // we don't actually need to generate the dereference some field lookups, like the 24311 // length of arrays and other comptime operations. 24312 const is_pointer_to = object_ty.isSinglePointer(mod); 24313 24314 const inner_ty = if (is_pointer_to) 24315 object_ty.childType(mod) 24316 else 24317 object_ty; 24318 24319 switch (inner_ty.zigTypeTag(mod)) { 24320 .Array => { 24321 if (mem.eql(u8, field_name, "len")) { 24322 return sema.addConstant( 24323 Type.usize, 24324 try mod.intValue(Type.usize, inner_ty.arrayLen(mod)), 24325 ); 24326 } else if (mem.eql(u8, field_name, "ptr") and is_pointer_to) { 24327 const ptr_info = object_ty.ptrInfo(mod); 24328 const result_ty = try Type.ptr(sema.arena, mod, .{ 24329 .pointee_type = ptr_info.pointee_type.childType(mod), 24330 .sentinel = ptr_info.sentinel, 24331 .@"align" = ptr_info.@"align", 24332 .@"addrspace" = ptr_info.@"addrspace", 24333 .bit_offset = ptr_info.bit_offset, 24334 .host_size = ptr_info.host_size, 24335 .vector_index = ptr_info.vector_index, 24336 .@"allowzero" = ptr_info.@"allowzero", 24337 .mutable = ptr_info.mutable, 24338 .@"volatile" = ptr_info.@"volatile", 24339 .size = .Many, 24340 }); 24341 return sema.coerce(block, result_ty, object, src); 24342 } else { 24343 return sema.fail( 24344 block, 24345 field_name_src, 24346 "no member named '{s}' in '{}'", 24347 .{ field_name, object_ty.fmt(mod) }, 24348 ); 24349 } 24350 }, 24351 .Pointer => { 24352 const ptr_info = inner_ty.ptrInfo(mod); 24353 if (ptr_info.size == .Slice) { 24354 if (mem.eql(u8, field_name, "ptr")) { 24355 const slice = if (is_pointer_to) 24356 try sema.analyzeLoad(block, src, object, object_src) 24357 else 24358 object; 24359 return sema.analyzeSlicePtr(block, object_src, slice, inner_ty); 24360 } else if (mem.eql(u8, field_name, "len")) { 24361 const slice = if (is_pointer_to) 24362 try sema.analyzeLoad(block, src, object, object_src) 24363 else 24364 object; 24365 return sema.analyzeSliceLen(block, src, slice); 24366 } else { 24367 return sema.fail( 24368 block, 24369 field_name_src, 24370 "no member named '{s}' in '{}'", 24371 .{ field_name, object_ty.fmt(mod) }, 24372 ); 24373 } 24374 } 24375 }, 24376 .Type => { 24377 const dereffed_type = if (is_pointer_to) 24378 try sema.analyzeLoad(block, src, object, object_src) 24379 else 24380 object; 24381 24382 const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?; 24383 const child_type = val.toType(); 24384 24385 switch (try child_type.zigTypeTagOrPoison(mod)) { 24386 .ErrorSet => { 24387 const name = try ip.getOrPutString(gpa, field_name); 24388 switch (ip.indexToKey(child_type.toIntern())) { 24389 .error_set_type => |error_set_type| blk: { 24390 if (error_set_type.nameIndex(ip, name) != null) break :blk; 24391 const msg = msg: { 24392 const msg = try sema.errMsg(block, src, "no error named '{s}' in '{}'", .{ 24393 field_name, child_type.fmt(mod), 24394 }); 24395 errdefer msg.destroy(sema.gpa); 24396 try sema.addDeclaredHereNote(msg, child_type); 24397 break :msg msg; 24398 }; 24399 return sema.failWithOwnedErrorMsg(msg); 24400 }, 24401 .inferred_error_set_type => { 24402 return sema.fail(block, src, "TODO handle inferred error sets here", .{}); 24403 }, 24404 .simple_type => |t| { 24405 assert(t == .anyerror); 24406 _ = try mod.getErrorValue(field_name); 24407 }, 24408 else => unreachable, 24409 } 24410 24411 const error_set_type = if (!child_type.isAnyError(mod)) 24412 child_type 24413 else 24414 try mod.singleErrorSetTypeNts(name); 24415 return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ 24416 .ty = error_set_type.toIntern(), 24417 .name = name, 24418 } })).toValue()); 24419 }, 24420 .Union => { 24421 if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { 24422 if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { 24423 return inst; 24424 } 24425 } 24426 const union_ty = try sema.resolveTypeFields(child_type); 24427 if (union_ty.unionTagType(mod)) |enum_ty| { 24428 if (enum_ty.enumFieldIndex(field_name, mod)) |field_index_usize| { 24429 const field_index = @intCast(u32, field_index_usize); 24430 return sema.addConstant( 24431 enum_ty, 24432 try mod.enumValueFieldIndex(enum_ty, field_index), 24433 ); 24434 } 24435 } 24436 return sema.failWithBadMemberAccess(block, union_ty, field_name_src, field_name); 24437 }, 24438 .Enum => { 24439 if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { 24440 if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { 24441 return inst; 24442 } 24443 } 24444 const field_index_usize = child_type.enumFieldIndex(field_name, mod) orelse 24445 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); 24446 const field_index = @intCast(u32, field_index_usize); 24447 const enum_val = try mod.enumValueFieldIndex(child_type, field_index); 24448 return sema.addConstant(child_type, enum_val); 24449 }, 24450 .Struct, .Opaque => { 24451 if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { 24452 if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { 24453 return inst; 24454 } 24455 } 24456 return sema.failWithBadMemberAccess(block, child_type, src, field_name); 24457 }, 24458 else => { 24459 const msg = msg: { 24460 const msg = try sema.errMsg(block, src, "type '{}' has no members", .{child_type.fmt(mod)}); 24461 errdefer msg.destroy(sema.gpa); 24462 if (child_type.isSlice(mod)) try sema.errNote(block, src, msg, "slice values have 'len' and 'ptr' members", .{}); 24463 if (child_type.zigTypeTag(mod) == .Array) try sema.errNote(block, src, msg, "array values have 'len' member", .{}); 24464 break :msg msg; 24465 }; 24466 return sema.failWithOwnedErrorMsg(msg); 24467 }, 24468 } 24469 }, 24470 .Struct => if (is_pointer_to) { 24471 // Avoid loading the entire struct by fetching a pointer and loading that 24472 const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false); 24473 return sema.analyzeLoad(block, src, field_ptr, object_src); 24474 } else { 24475 return sema.structFieldVal(block, src, object, field_name, field_name_src, inner_ty); 24476 }, 24477 .Union => if (is_pointer_to) { 24478 // Avoid loading the entire union by fetching a pointer and loading that 24479 const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false); 24480 return sema.analyzeLoad(block, src, field_ptr, object_src); 24481 } else { 24482 return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty); 24483 }, 24484 else => {}, 24485 } 24486 return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name); 24487 } 24488 24489 fn fieldPtr( 24490 sema: *Sema, 24491 block: *Block, 24492 src: LazySrcLoc, 24493 object_ptr: Air.Inst.Ref, 24494 field_name: []const u8, 24495 field_name_src: LazySrcLoc, 24496 initializing: bool, 24497 ) CompileError!Air.Inst.Ref { 24498 // When editing this function, note that there is corresponding logic to be edited 24499 // in `fieldVal`. This function takes a pointer and returns a pointer. 24500 24501 const mod = sema.mod; 24502 const gpa = sema.gpa; 24503 const ip = &mod.intern_pool; 24504 const object_ptr_src = src; // TODO better source location 24505 const object_ptr_ty = sema.typeOf(object_ptr); 24506 const object_ty = switch (object_ptr_ty.zigTypeTag(mod)) { 24507 .Pointer => object_ptr_ty.childType(mod), 24508 else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty.fmt(mod)}), 24509 }; 24510 24511 // Zig allows dereferencing a single pointer during field lookup. Note that 24512 // we don't actually need to generate the dereference some field lookups, like the 24513 // length of arrays and other comptime operations. 24514 const is_pointer_to = object_ty.isSinglePointer(mod); 24515 24516 const inner_ty = if (is_pointer_to) 24517 object_ty.childType(mod) 24518 else 24519 object_ty; 24520 24521 switch (inner_ty.zigTypeTag(mod)) { 24522 .Array => { 24523 if (mem.eql(u8, field_name, "len")) { 24524 var anon_decl = try block.startAnonDecl(); 24525 defer anon_decl.deinit(); 24526 return sema.analyzeDeclRef(try anon_decl.finish( 24527 Type.usize, 24528 try mod.intValue(Type.usize, inner_ty.arrayLen(mod)), 24529 0, // default alignment 24530 )); 24531 } else { 24532 return sema.fail( 24533 block, 24534 field_name_src, 24535 "no member named '{s}' in '{}'", 24536 .{ field_name, object_ty.fmt(mod) }, 24537 ); 24538 } 24539 }, 24540 .Pointer => if (inner_ty.isSlice(mod)) { 24541 const inner_ptr = if (is_pointer_to) 24542 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) 24543 else 24544 object_ptr; 24545 24546 const attr_ptr_ty = if (is_pointer_to) object_ty else object_ptr_ty; 24547 24548 if (mem.eql(u8, field_name, "ptr")) { 24549 const slice_ptr_ty = inner_ty.slicePtrFieldType(mod); 24550 24551 const result_ty = try Type.ptr(sema.arena, mod, .{ 24552 .pointee_type = slice_ptr_ty, 24553 .mutable = attr_ptr_ty.ptrIsMutable(mod), 24554 .@"volatile" = attr_ptr_ty.isVolatilePtr(mod), 24555 .@"addrspace" = attr_ptr_ty.ptrAddressSpace(mod), 24556 }); 24557 24558 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { 24559 return sema.addConstant(result_ty, (try mod.intern(.{ .ptr = .{ 24560 .ty = result_ty.toIntern(), 24561 .addr = .{ .field = .{ 24562 .base = val.toIntern(), 24563 .index = Value.slice_ptr_index, 24564 } }, 24565 } })).toValue()); 24566 } 24567 try sema.requireRuntimeBlock(block, src, null); 24568 24569 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr); 24570 } else if (mem.eql(u8, field_name, "len")) { 24571 const result_ty = try Type.ptr(sema.arena, mod, .{ 24572 .pointee_type = Type.usize, 24573 .mutable = attr_ptr_ty.ptrIsMutable(mod), 24574 .@"volatile" = attr_ptr_ty.isVolatilePtr(mod), 24575 .@"addrspace" = attr_ptr_ty.ptrAddressSpace(mod), 24576 }); 24577 24578 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { 24579 return sema.addConstant(result_ty, (try mod.intern(.{ .ptr = .{ 24580 .ty = result_ty.toIntern(), 24581 .addr = .{ .field = .{ 24582 .base = val.toIntern(), 24583 .index = Value.slice_len_index, 24584 } }, 24585 } })).toValue()); 24586 } 24587 try sema.requireRuntimeBlock(block, src, null); 24588 24589 return block.addTyOp(.ptr_slice_len_ptr, result_ty, inner_ptr); 24590 } else { 24591 return sema.fail( 24592 block, 24593 field_name_src, 24594 "no member named '{s}' in '{}'", 24595 .{ field_name, object_ty.fmt(mod) }, 24596 ); 24597 } 24598 }, 24599 .Type => { 24600 _ = try sema.resolveConstValue(block, .unneeded, object_ptr, ""); 24601 const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src); 24602 const inner = if (is_pointer_to) 24603 try sema.analyzeLoad(block, src, result, object_ptr_src) 24604 else 24605 result; 24606 24607 const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?; 24608 const child_type = val.toType(); 24609 24610 switch (child_type.zigTypeTag(mod)) { 24611 .ErrorSet => { 24612 const name = try ip.getOrPutString(gpa, field_name); 24613 switch (ip.indexToKey(child_type.toIntern())) { 24614 .error_set_type => |error_set_type| blk: { 24615 if (error_set_type.nameIndex(ip, name) != null) { 24616 break :blk; 24617 } 24618 return sema.fail(block, src, "no error named '{s}' in '{}'", .{ 24619 field_name, child_type.fmt(mod), 24620 }); 24621 }, 24622 .inferred_error_set_type => { 24623 return sema.fail(block, src, "TODO handle inferred error sets here", .{}); 24624 }, 24625 .simple_type => |t| { 24626 assert(t == .anyerror); 24627 _ = try mod.getErrorValue(field_name); 24628 }, 24629 else => unreachable, 24630 } 24631 24632 var anon_decl = try block.startAnonDecl(); 24633 defer anon_decl.deinit(); 24634 const error_set_type = if (!child_type.isAnyError(mod)) 24635 child_type 24636 else 24637 try mod.singleErrorSetTypeNts(name); 24638 return sema.analyzeDeclRef(try anon_decl.finish( 24639 error_set_type, 24640 (try mod.intern(.{ .err = .{ 24641 .ty = error_set_type.toIntern(), 24642 .name = name, 24643 } })).toValue(), 24644 0, // default alignment 24645 )); 24646 }, 24647 .Union => { 24648 if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { 24649 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { 24650 return inst; 24651 } 24652 } 24653 const union_ty = try sema.resolveTypeFields(child_type); 24654 if (union_ty.unionTagType(mod)) |enum_ty| { 24655 if (enum_ty.enumFieldIndex(field_name, mod)) |field_index| { 24656 const field_index_u32 = @intCast(u32, field_index); 24657 var anon_decl = try block.startAnonDecl(); 24658 defer anon_decl.deinit(); 24659 return sema.analyzeDeclRef(try anon_decl.finish( 24660 enum_ty, 24661 try mod.enumValueFieldIndex(enum_ty, field_index_u32), 24662 0, // default alignment 24663 )); 24664 } 24665 } 24666 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); 24667 }, 24668 .Enum => { 24669 if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { 24670 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { 24671 return inst; 24672 } 24673 } 24674 const field_index = child_type.enumFieldIndex(field_name, mod) orelse { 24675 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); 24676 }; 24677 const field_index_u32 = @intCast(u32, field_index); 24678 var anon_decl = try block.startAnonDecl(); 24679 defer anon_decl.deinit(); 24680 return sema.analyzeDeclRef(try anon_decl.finish( 24681 child_type, 24682 try mod.enumValueFieldIndex(child_type, field_index_u32), 24683 0, // default alignment 24684 )); 24685 }, 24686 .Struct, .Opaque => { 24687 if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { 24688 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { 24689 return inst; 24690 } 24691 } 24692 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); 24693 }, 24694 else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(mod)}), 24695 } 24696 }, 24697 .Struct => { 24698 const inner_ptr = if (is_pointer_to) 24699 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) 24700 else 24701 object_ptr; 24702 return sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing); 24703 }, 24704 .Union => { 24705 const inner_ptr = if (is_pointer_to) 24706 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) 24707 else 24708 object_ptr; 24709 return sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing); 24710 }, 24711 else => {}, 24712 } 24713 return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name); 24714 } 24715 24716 const ResolvedFieldCallee = union(enum) { 24717 /// The LHS of the call was an actual field with this value. 24718 direct: Air.Inst.Ref, 24719 /// This is a method call, with the function and first argument given. 24720 method: struct { 24721 func_inst: Air.Inst.Ref, 24722 arg0_inst: Air.Inst.Ref, 24723 }, 24724 }; 24725 24726 fn fieldCallBind( 24727 sema: *Sema, 24728 block: *Block, 24729 src: LazySrcLoc, 24730 raw_ptr: Air.Inst.Ref, 24731 field_name: []const u8, 24732 field_name_src: LazySrcLoc, 24733 ) CompileError!ResolvedFieldCallee { 24734 // When editing this function, note that there is corresponding logic to be edited 24735 // in `fieldVal`. This function takes a pointer and returns a pointer. 24736 24737 const mod = sema.mod; 24738 const raw_ptr_src = src; // TODO better source location 24739 const raw_ptr_ty = sema.typeOf(raw_ptr); 24740 const inner_ty = if (raw_ptr_ty.zigTypeTag(mod) == .Pointer and (raw_ptr_ty.ptrSize(mod) == .One or raw_ptr_ty.ptrSize(mod) == .C)) 24741 raw_ptr_ty.childType(mod) 24742 else 24743 return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(mod)}); 24744 24745 // Optionally dereference a second pointer to get the concrete type. 24746 const is_double_ptr = inner_ty.zigTypeTag(mod) == .Pointer and inner_ty.ptrSize(mod) == .One; 24747 const concrete_ty = if (is_double_ptr) inner_ty.childType(mod) else inner_ty; 24748 const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty; 24749 const object_ptr = if (is_double_ptr) 24750 try sema.analyzeLoad(block, src, raw_ptr, src) 24751 else 24752 raw_ptr; 24753 24754 find_field: { 24755 switch (concrete_ty.zigTypeTag(mod)) { 24756 .Struct => { 24757 const struct_ty = try sema.resolveTypeFields(concrete_ty); 24758 if (mod.typeToStruct(struct_ty)) |struct_obj| { 24759 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse 24760 break :find_field; 24761 const field_index = @intCast(u32, field_index_usize); 24762 const field = struct_obj.fields.values()[field_index]; 24763 24764 return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr); 24765 } else if (struct_ty.isTuple(mod)) { 24766 if (mem.eql(u8, field_name, "len")) { 24767 return .{ .direct = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount(mod)) }; 24768 } 24769 if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| { 24770 if (field_index >= struct_ty.structFieldCount(mod)) break :find_field; 24771 return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(field_index, mod), field_index, object_ptr); 24772 } else |_| {} 24773 } else { 24774 const max = struct_ty.structFieldCount(mod); 24775 var i: u32 = 0; 24776 while (i < max) : (i += 1) { 24777 if (mem.eql(u8, struct_ty.structFieldName(i, mod), field_name)) { 24778 return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(i, mod), i, object_ptr); 24779 } 24780 } 24781 } 24782 }, 24783 .Union => { 24784 const union_ty = try sema.resolveTypeFields(concrete_ty); 24785 const fields = union_ty.unionFields(mod); 24786 const field_index_usize = fields.getIndex(field_name) orelse break :find_field; 24787 const field_index = @intCast(u32, field_index_usize); 24788 const field = fields.values()[field_index]; 24789 24790 return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr); 24791 }, 24792 .Type => { 24793 const namespace = try sema.analyzeLoad(block, src, object_ptr, src); 24794 return .{ .direct = try sema.fieldVal(block, src, namespace, field_name, field_name_src) }; 24795 }, 24796 else => {}, 24797 } 24798 } 24799 24800 // If we get here, we need to look for a decl in the struct type instead. 24801 const found_decl = switch (concrete_ty.zigTypeTag(mod)) { 24802 .Struct, .Opaque, .Union, .Enum => found_decl: { 24803 if (concrete_ty.getNamespaceIndex(mod).unwrap()) |namespace| { 24804 if (try sema.namespaceLookup(block, src, namespace, field_name)) |decl_idx| { 24805 try sema.addReferencedBy(block, src, decl_idx); 24806 const decl_val = try sema.analyzeDeclVal(block, src, decl_idx); 24807 const decl_type = sema.typeOf(decl_val); 24808 if (mod.typeToFunc(decl_type)) |func_type| f: { 24809 if (func_type.param_types.len == 0) break :f; 24810 24811 const first_param_type = func_type.param_types[0].toType(); 24812 // zig fmt: off 24813 if (first_param_type.isGenericPoison() or ( 24814 first_param_type.zigTypeTag(mod) == .Pointer and 24815 (first_param_type.ptrSize(mod) == .One or 24816 first_param_type.ptrSize(mod) == .C) and 24817 first_param_type.childType(mod).eql(concrete_ty, mod))) 24818 { 24819 // zig fmt: on 24820 // Note that if the param type is generic poison, we know that it must 24821 // specifically be `anytype` since it's the first parameter, meaning we 24822 // can safely assume it can be a pointer. 24823 // TODO: bound fn calls on rvalues should probably 24824 // generate a by-value argument somehow. 24825 return .{ .method = .{ 24826 .func_inst = decl_val, 24827 .arg0_inst = object_ptr, 24828 } }; 24829 } else if (first_param_type.eql(concrete_ty, mod)) { 24830 const deref = try sema.analyzeLoad(block, src, object_ptr, src); 24831 return .{ .method = .{ 24832 .func_inst = decl_val, 24833 .arg0_inst = deref, 24834 } }; 24835 } else if (first_param_type.zigTypeTag(mod) == .Optional) { 24836 const child = first_param_type.optionalChild(mod); 24837 if (child.eql(concrete_ty, mod)) { 24838 const deref = try sema.analyzeLoad(block, src, object_ptr, src); 24839 return .{ .method = .{ 24840 .func_inst = decl_val, 24841 .arg0_inst = deref, 24842 } }; 24843 } else if (child.zigTypeTag(mod) == .Pointer and 24844 child.ptrSize(mod) == .One and 24845 child.childType(mod).eql(concrete_ty, mod)) 24846 { 24847 return .{ .method = .{ 24848 .func_inst = decl_val, 24849 .arg0_inst = object_ptr, 24850 } }; 24851 } 24852 } else if (first_param_type.zigTypeTag(mod) == .ErrorUnion and 24853 first_param_type.errorUnionPayload(mod).eql(concrete_ty, mod)) 24854 { 24855 const deref = try sema.analyzeLoad(block, src, object_ptr, src); 24856 return .{ .method = .{ 24857 .func_inst = decl_val, 24858 .arg0_inst = deref, 24859 } }; 24860 } 24861 } 24862 break :found_decl decl_idx; 24863 } 24864 } 24865 break :found_decl null; 24866 }, 24867 else => null, 24868 }; 24869 24870 const msg = msg: { 24871 const msg = try sema.errMsg(block, src, "no field or member function named '{s}' in '{}'", .{ field_name, concrete_ty.fmt(mod) }); 24872 errdefer msg.destroy(sema.gpa); 24873 try sema.addDeclaredHereNote(msg, concrete_ty); 24874 if (found_decl) |decl_idx| { 24875 const decl = mod.declPtr(decl_idx); 24876 try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "'{s}' is not a member function", .{field_name}); 24877 } 24878 break :msg msg; 24879 }; 24880 return sema.failWithOwnedErrorMsg(msg); 24881 } 24882 24883 fn finishFieldCallBind( 24884 sema: *Sema, 24885 block: *Block, 24886 src: LazySrcLoc, 24887 ptr_ty: Type, 24888 field_ty: Type, 24889 field_index: u32, 24890 object_ptr: Air.Inst.Ref, 24891 ) CompileError!ResolvedFieldCallee { 24892 const mod = sema.mod; 24893 const arena = sema.arena; 24894 const ptr_field_ty = try Type.ptr(arena, mod, .{ 24895 .pointee_type = field_ty, 24896 .mutable = ptr_ty.ptrIsMutable(mod), 24897 .@"addrspace" = ptr_ty.ptrAddressSpace(mod), 24898 }); 24899 24900 const container_ty = ptr_ty.childType(mod); 24901 if (container_ty.zigTypeTag(mod) == .Struct) { 24902 if (try container_ty.structFieldValueComptime(mod, field_index)) |default_val| { 24903 return .{ .direct = try sema.addConstant(field_ty, default_val) }; 24904 } 24905 } 24906 24907 if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| { 24908 const pointer = try sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ 24909 .ty = ptr_field_ty.toIntern(), 24910 .addr = .{ .field = .{ 24911 .base = struct_ptr_val.toIntern(), 24912 .index = field_index, 24913 } }, 24914 } })).toValue()); 24915 return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) }; 24916 } 24917 24918 try sema.requireRuntimeBlock(block, src, null); 24919 const ptr_inst = try block.addStructFieldPtr(object_ptr, field_index, ptr_field_ty); 24920 return .{ .direct = try sema.analyzeLoad(block, src, ptr_inst, src) }; 24921 } 24922 24923 fn namespaceLookup( 24924 sema: *Sema, 24925 block: *Block, 24926 src: LazySrcLoc, 24927 namespace: Namespace.Index, 24928 decl_name: []const u8, 24929 ) CompileError!?Decl.Index { 24930 const mod = sema.mod; 24931 const gpa = sema.gpa; 24932 if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| { 24933 const decl = mod.declPtr(decl_index); 24934 if (!decl.is_pub and decl.getFileScope(mod) != block.getFileScope(mod)) { 24935 const msg = msg: { 24936 const msg = try sema.errMsg(block, src, "'{s}' is not marked 'pub'", .{ 24937 decl_name, 24938 }); 24939 errdefer msg.destroy(gpa); 24940 try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "declared here", .{}); 24941 break :msg msg; 24942 }; 24943 return sema.failWithOwnedErrorMsg(msg); 24944 } 24945 return decl_index; 24946 } 24947 return null; 24948 } 24949 24950 fn namespaceLookupRef( 24951 sema: *Sema, 24952 block: *Block, 24953 src: LazySrcLoc, 24954 namespace: Namespace.Index, 24955 decl_name: []const u8, 24956 ) CompileError!?Air.Inst.Ref { 24957 const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; 24958 try sema.addReferencedBy(block, src, decl); 24959 return try sema.analyzeDeclRef(decl); 24960 } 24961 24962 fn namespaceLookupVal( 24963 sema: *Sema, 24964 block: *Block, 24965 src: LazySrcLoc, 24966 namespace: Namespace.Index, 24967 decl_name: []const u8, 24968 ) CompileError!?Air.Inst.Ref { 24969 const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; 24970 return try sema.analyzeDeclVal(block, src, decl); 24971 } 24972 24973 fn structFieldPtr( 24974 sema: *Sema, 24975 block: *Block, 24976 src: LazySrcLoc, 24977 struct_ptr: Air.Inst.Ref, 24978 field_name: []const u8, 24979 field_name_src: LazySrcLoc, 24980 unresolved_struct_ty: Type, 24981 initializing: bool, 24982 ) CompileError!Air.Inst.Ref { 24983 const mod = sema.mod; 24984 assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct); 24985 24986 const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); 24987 try sema.resolveStructLayout(struct_ty); 24988 24989 if (struct_ty.isTuple(mod)) { 24990 if (mem.eql(u8, field_name, "len")) { 24991 const len_inst = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount(mod)); 24992 return sema.analyzeRef(block, src, len_inst); 24993 } 24994 const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src); 24995 return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); 24996 } else if (struct_ty.isAnonStruct(mod)) { 24997 const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); 24998 return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); 24999 } 25000 25001 const struct_obj = mod.typeToStruct(struct_ty).?; 25002 25003 const field_index_big = struct_obj.fields.getIndex(field_name) orelse 25004 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); 25005 const field_index = @intCast(u32, field_index_big); 25006 25007 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, field_name_src, struct_ty, initializing); 25008 } 25009 25010 fn structFieldPtrByIndex( 25011 sema: *Sema, 25012 block: *Block, 25013 src: LazySrcLoc, 25014 struct_ptr: Air.Inst.Ref, 25015 field_index: u32, 25016 field_src: LazySrcLoc, 25017 struct_ty: Type, 25018 initializing: bool, 25019 ) CompileError!Air.Inst.Ref { 25020 const mod = sema.mod; 25021 if (struct_ty.isAnonStruct(mod)) { 25022 return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing); 25023 } 25024 25025 const struct_obj = mod.typeToStruct(struct_ty).?; 25026 const field = struct_obj.fields.values()[field_index]; 25027 const struct_ptr_ty = sema.typeOf(struct_ptr); 25028 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod); 25029 25030 var ptr_ty_data: Type.Payload.Pointer.Data = .{ 25031 .pointee_type = field.ty, 25032 .mutable = struct_ptr_ty_info.mutable, 25033 .@"volatile" = struct_ptr_ty_info.@"volatile", 25034 .@"addrspace" = struct_ptr_ty_info.@"addrspace", 25035 }; 25036 25037 const target = mod.getTarget(); 25038 25039 if (struct_obj.layout == .Packed) { 25040 comptime assert(Type.packed_struct_layout_version == 2); 25041 25042 var running_bits: u16 = 0; 25043 for (struct_obj.fields.values(), 0..) |f, i| { 25044 if (!(try sema.typeHasRuntimeBits(f.ty))) continue; 25045 25046 if (i == field_index) { 25047 ptr_ty_data.bit_offset = running_bits; 25048 } 25049 running_bits += @intCast(u16, f.ty.bitSize(mod)); 25050 } 25051 ptr_ty_data.host_size = (running_bits + 7) / 8; 25052 25053 // If this is a packed struct embedded in another one, we need to offset 25054 // the bits against each other. 25055 if (struct_ptr_ty_info.host_size != 0) { 25056 ptr_ty_data.host_size = struct_ptr_ty_info.host_size; 25057 ptr_ty_data.bit_offset += struct_ptr_ty_info.bit_offset; 25058 } 25059 25060 const parent_align = if (struct_ptr_ty_info.@"align" != 0) 25061 struct_ptr_ty_info.@"align" 25062 else 25063 struct_ptr_ty_info.pointee_type.abiAlignment(mod); 25064 ptr_ty_data.@"align" = parent_align; 25065 25066 // If the field happens to be byte-aligned, simplify the pointer type. 25067 // The pointee type bit size must match its ABI byte size so that loads and stores 25068 // do not interfere with the surrounding packed bits. 25069 // We do not attempt this with big-endian targets yet because of nested 25070 // structs and floats. I need to double-check the desired behavior for big endian 25071 // targets before adding the necessary complications to this code. This will not 25072 // cause miscompilations; it only means the field pointer uses bit masking when it 25073 // might not be strictly necessary. 25074 if (parent_align != 0 and ptr_ty_data.bit_offset % 8 == 0 and 25075 target.cpu.arch.endian() == .Little) 25076 { 25077 const elem_size_bytes = ptr_ty_data.pointee_type.abiSize(mod); 25078 const elem_size_bits = ptr_ty_data.pointee_type.bitSize(mod); 25079 if (elem_size_bytes * 8 == elem_size_bits) { 25080 const byte_offset = ptr_ty_data.bit_offset / 8; 25081 const new_align = @as(u32, 1) << @intCast(u5, @ctz(byte_offset | parent_align)); 25082 ptr_ty_data.bit_offset = 0; 25083 ptr_ty_data.host_size = 0; 25084 ptr_ty_data.@"align" = new_align; 25085 } 25086 } 25087 } else { 25088 ptr_ty_data.@"align" = field.abi_align; 25089 } 25090 25091 const ptr_field_ty = try Type.ptr(sema.arena, mod, ptr_ty_data); 25092 25093 if (field.is_comptime) { 25094 const val = try mod.intern(.{ .ptr = .{ 25095 .ty = ptr_field_ty.toIntern(), 25096 .addr = .{ .comptime_field = try field.default_val.intern(field.ty, mod) }, 25097 } }); 25098 return sema.addConstant(ptr_field_ty, val.toValue()); 25099 } 25100 25101 if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| { 25102 const val = try mod.intern(.{ .ptr = .{ 25103 .ty = ptr_field_ty.toIntern(), 25104 .addr = .{ .field = .{ 25105 .base = try struct_ptr_val.intern(struct_ptr_ty, mod), 25106 .index = field_index, 25107 } }, 25108 } }); 25109 return sema.addConstant(ptr_field_ty, val.toValue()); 25110 } 25111 25112 try sema.requireRuntimeBlock(block, src, null); 25113 return block.addStructFieldPtr(struct_ptr, field_index, ptr_field_ty); 25114 } 25115 25116 fn structFieldVal( 25117 sema: *Sema, 25118 block: *Block, 25119 src: LazySrcLoc, 25120 struct_byval: Air.Inst.Ref, 25121 field_name: []const u8, 25122 field_name_src: LazySrcLoc, 25123 unresolved_struct_ty: Type, 25124 ) CompileError!Air.Inst.Ref { 25125 const mod = sema.mod; 25126 assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct); 25127 25128 const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); 25129 switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { 25130 .struct_type => |struct_type| { 25131 const struct_obj = mod.structPtrUnwrap(struct_type.index).?; 25132 if (struct_obj.is_tuple) return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); 25133 25134 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse 25135 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); 25136 const field_index = @intCast(u32, field_index_usize); 25137 const field = struct_obj.fields.values()[field_index]; 25138 25139 if (field.is_comptime) { 25140 return sema.addConstant(field.ty, field.default_val); 25141 } 25142 25143 if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| { 25144 if (struct_val.isUndef(mod)) return sema.addConstUndef(field.ty); 25145 if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| { 25146 return sema.addConstant(field.ty, opv); 25147 } 25148 return sema.addConstant(field.ty, try struct_val.fieldValue(mod, field_index)); 25149 } 25150 25151 try sema.requireRuntimeBlock(block, src, null); 25152 return block.addStructFieldVal(struct_byval, field_index, field.ty); 25153 }, 25154 .anon_struct_type => |anon_struct| { 25155 if (anon_struct.names.len == 0) { 25156 return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); 25157 } else { 25158 const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); 25159 return sema.tupleFieldValByIndex(block, src, struct_byval, field_index, struct_ty); 25160 } 25161 }, 25162 else => unreachable, 25163 } 25164 } 25165 25166 fn tupleFieldVal( 25167 sema: *Sema, 25168 block: *Block, 25169 src: LazySrcLoc, 25170 tuple_byval: Air.Inst.Ref, 25171 field_name: []const u8, 25172 field_name_src: LazySrcLoc, 25173 tuple_ty: Type, 25174 ) CompileError!Air.Inst.Ref { 25175 const mod = sema.mod; 25176 if (mem.eql(u8, field_name, "len")) { 25177 return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount(mod)); 25178 } 25179 const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_name_src); 25180 return sema.tupleFieldValByIndex(block, src, tuple_byval, field_index, tuple_ty); 25181 } 25182 25183 /// Asserts that `field_name` is not "len". 25184 fn tupleFieldIndex( 25185 sema: *Sema, 25186 block: *Block, 25187 tuple_ty: Type, 25188 field_name: []const u8, 25189 field_name_src: LazySrcLoc, 25190 ) CompileError!u32 { 25191 const mod = sema.mod; 25192 assert(!mem.eql(u8, field_name, "len")); 25193 if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| { 25194 if (field_index < tuple_ty.structFieldCount(mod)) return field_index; 25195 return sema.fail(block, field_name_src, "index '{s}' out of bounds of tuple '{}'", .{ 25196 field_name, tuple_ty.fmt(mod), 25197 }); 25198 } else |_| {} 25199 25200 return sema.fail(block, field_name_src, "no field named '{s}' in tuple '{}'", .{ 25201 field_name, tuple_ty.fmt(mod), 25202 }); 25203 } 25204 25205 fn tupleFieldValByIndex( 25206 sema: *Sema, 25207 block: *Block, 25208 src: LazySrcLoc, 25209 tuple_byval: Air.Inst.Ref, 25210 field_index: u32, 25211 tuple_ty: Type, 25212 ) CompileError!Air.Inst.Ref { 25213 const mod = sema.mod; 25214 const field_ty = tuple_ty.structFieldType(field_index, mod); 25215 25216 if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_value| { 25217 return sema.addConstant(field_ty, default_value); 25218 } 25219 25220 if (try sema.resolveMaybeUndefVal(tuple_byval)) |tuple_val| { 25221 if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| { 25222 return sema.addConstant(field_ty, opv); 25223 } 25224 return switch (mod.intern_pool.indexToKey(tuple_val.toIntern())) { 25225 .undef => sema.addConstUndef(field_ty), 25226 .aggregate => |aggregate| sema.addConstant(field_ty, switch (aggregate.storage) { 25227 .bytes => |bytes| try mod.intValue(Type.u8, bytes[0]), 25228 .elems => |elems| elems[field_index].toValue(), 25229 .repeated_elem => |elem| elem.toValue(), 25230 }), 25231 else => unreachable, 25232 }; 25233 } 25234 25235 if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| { 25236 return sema.addConstant(field_ty, default_val); 25237 } 25238 25239 try sema.requireRuntimeBlock(block, src, null); 25240 return block.addStructFieldVal(tuple_byval, field_index, field_ty); 25241 } 25242 25243 fn unionFieldPtr( 25244 sema: *Sema, 25245 block: *Block, 25246 src: LazySrcLoc, 25247 union_ptr: Air.Inst.Ref, 25248 field_name: []const u8, 25249 field_name_src: LazySrcLoc, 25250 unresolved_union_ty: Type, 25251 initializing: bool, 25252 ) CompileError!Air.Inst.Ref { 25253 const arena = sema.arena; 25254 const mod = sema.mod; 25255 25256 assert(unresolved_union_ty.zigTypeTag(mod) == .Union); 25257 25258 const union_ptr_ty = sema.typeOf(union_ptr); 25259 const union_ty = try sema.resolveTypeFields(unresolved_union_ty); 25260 const union_obj = mod.typeToUnion(union_ty).?; 25261 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); 25262 const field = union_obj.fields.values()[field_index]; 25263 const ptr_field_ty = try Type.ptr(arena, mod, .{ 25264 .pointee_type = field.ty, 25265 .mutable = union_ptr_ty.ptrIsMutable(mod), 25266 .@"volatile" = union_ptr_ty.isVolatilePtr(mod), 25267 .@"addrspace" = union_ptr_ty.ptrAddressSpace(mod), 25268 }); 25269 const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name, mod).?); 25270 25271 if (initializing and field.ty.zigTypeTag(mod) == .NoReturn) { 25272 const msg = msg: { 25273 const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{}); 25274 errdefer msg.destroy(sema.gpa); 25275 25276 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); 25277 try sema.addDeclaredHereNote(msg, union_ty); 25278 break :msg msg; 25279 }; 25280 return sema.failWithOwnedErrorMsg(msg); 25281 } 25282 25283 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: { 25284 switch (union_obj.layout) { 25285 .Auto => if (!initializing) { 25286 const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse 25287 break :ct; 25288 if (union_val.isUndef(mod)) { 25289 return sema.failWithUseOfUndef(block, src); 25290 } 25291 const un = mod.intern_pool.indexToKey(union_val.toIntern()).un; 25292 const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index); 25293 const tag_matches = un.tag == field_tag.toIntern(); 25294 if (!tag_matches) { 25295 const msg = msg: { 25296 const active_index = union_obj.tag_ty.enumTagFieldIndex(un.tag.toValue(), mod).?; 25297 const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod); 25298 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); 25299 errdefer msg.destroy(sema.gpa); 25300 try sema.addDeclaredHereNote(msg, union_ty); 25301 break :msg msg; 25302 }; 25303 return sema.failWithOwnedErrorMsg(msg); 25304 } 25305 }, 25306 .Packed, .Extern => {}, 25307 } 25308 return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ 25309 .ty = ptr_field_ty.toIntern(), 25310 .addr = .{ .field = .{ 25311 .base = union_ptr_val.toIntern(), 25312 .index = field_index, 25313 } }, 25314 } })).toValue()); 25315 } 25316 25317 try sema.requireRuntimeBlock(block, src, null); 25318 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and 25319 union_ty.unionTagTypeSafety(mod) != null and union_obj.fields.count() > 1) 25320 { 25321 const wanted_tag_val = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index); 25322 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); 25323 // TODO would it be better if get_union_tag supported pointers to unions? 25324 const union_val = try block.addTyOp(.load, union_ty, union_ptr); 25325 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val); 25326 try sema.panicInactiveUnionField(block, active_tag, wanted_tag); 25327 } 25328 if (field.ty.zigTypeTag(mod) == .NoReturn) { 25329 _ = try block.addNoOp(.unreach); 25330 return Air.Inst.Ref.unreachable_value; 25331 } 25332 return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty); 25333 } 25334 25335 fn unionFieldVal( 25336 sema: *Sema, 25337 block: *Block, 25338 src: LazySrcLoc, 25339 union_byval: Air.Inst.Ref, 25340 field_name: []const u8, 25341 field_name_src: LazySrcLoc, 25342 unresolved_union_ty: Type, 25343 ) CompileError!Air.Inst.Ref { 25344 const mod = sema.mod; 25345 assert(unresolved_union_ty.zigTypeTag(mod) == .Union); 25346 25347 const union_ty = try sema.resolveTypeFields(unresolved_union_ty); 25348 const union_obj = mod.typeToUnion(union_ty).?; 25349 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); 25350 const field = union_obj.fields.values()[field_index]; 25351 const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name, mod).?); 25352 25353 if (try sema.resolveMaybeUndefVal(union_byval)) |union_val| { 25354 if (union_val.isUndef(mod)) return sema.addConstUndef(field.ty); 25355 25356 const un = mod.intern_pool.indexToKey(union_val.toIntern()).un; 25357 const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index); 25358 const tag_matches = un.tag == field_tag.toIntern(); 25359 switch (union_obj.layout) { 25360 .Auto => { 25361 if (tag_matches) { 25362 return sema.addConstant(field.ty, un.val.toValue()); 25363 } else { 25364 const msg = msg: { 25365 const active_index = union_obj.tag_ty.enumTagFieldIndex(un.tag.toValue(), mod).?; 25366 const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod); 25367 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); 25368 errdefer msg.destroy(sema.gpa); 25369 try sema.addDeclaredHereNote(msg, union_ty); 25370 break :msg msg; 25371 }; 25372 return sema.failWithOwnedErrorMsg(msg); 25373 } 25374 }, 25375 .Packed, .Extern => { 25376 if (tag_matches) { 25377 return sema.addConstant(field.ty, un.val.toValue()); 25378 } else { 25379 const old_ty = union_ty.unionFieldType(un.tag.toValue(), mod); 25380 if (try sema.bitCastVal(block, src, un.val.toValue(), old_ty, field.ty, 0)) |new_val| { 25381 return sema.addConstant(field.ty, new_val); 25382 } 25383 } 25384 }, 25385 } 25386 } 25387 25388 try sema.requireRuntimeBlock(block, src, null); 25389 if (union_obj.layout == .Auto and block.wantSafety() and 25390 union_ty.unionTagTypeSafety(mod) != null and union_obj.fields.count() > 1) 25391 { 25392 const wanted_tag_val = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index); 25393 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); 25394 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval); 25395 try sema.panicInactiveUnionField(block, active_tag, wanted_tag); 25396 } 25397 if (field.ty.zigTypeTag(mod) == .NoReturn) { 25398 _ = try block.addNoOp(.unreach); 25399 return Air.Inst.Ref.unreachable_value; 25400 } 25401 return block.addStructFieldVal(union_byval, field_index, field.ty); 25402 } 25403 25404 fn elemPtr( 25405 sema: *Sema, 25406 block: *Block, 25407 src: LazySrcLoc, 25408 indexable_ptr: Air.Inst.Ref, 25409 elem_index: Air.Inst.Ref, 25410 elem_index_src: LazySrcLoc, 25411 init: bool, 25412 oob_safety: bool, 25413 ) CompileError!Air.Inst.Ref { 25414 const mod = sema.mod; 25415 const indexable_ptr_src = src; // TODO better source location 25416 const indexable_ptr_ty = sema.typeOf(indexable_ptr); 25417 25418 const indexable_ty = switch (indexable_ptr_ty.zigTypeTag(mod)) { 25419 .Pointer => indexable_ptr_ty.childType(mod), 25420 else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(mod)}), 25421 }; 25422 try checkIndexable(sema, block, src, indexable_ty); 25423 25424 switch (indexable_ty.zigTypeTag(mod)) { 25425 .Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), 25426 .Struct => { 25427 // Tuple field access. 25428 const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known"); 25429 const index = @intCast(u32, index_val.toUnsignedInt(mod)); 25430 return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init); 25431 }, 25432 else => { 25433 const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); 25434 return elemPtrOneLayerOnly(sema, block, src, indexable, elem_index, elem_index_src, init, oob_safety); 25435 }, 25436 } 25437 } 25438 25439 /// Asserts that the type of indexable is pointer. 25440 fn elemPtrOneLayerOnly( 25441 sema: *Sema, 25442 block: *Block, 25443 src: LazySrcLoc, 25444 indexable: Air.Inst.Ref, 25445 elem_index: Air.Inst.Ref, 25446 elem_index_src: LazySrcLoc, 25447 init: bool, 25448 oob_safety: bool, 25449 ) CompileError!Air.Inst.Ref { 25450 const indexable_src = src; // TODO better source location 25451 const indexable_ty = sema.typeOf(indexable); 25452 const mod = sema.mod; 25453 25454 try checkIndexable(sema, block, src, indexable_ty); 25455 25456 switch (indexable_ty.ptrSize(mod)) { 25457 .Slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), 25458 .Many, .C => { 25459 const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable); 25460 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); 25461 const runtime_src = rs: { 25462 const ptr_val = maybe_ptr_val orelse break :rs indexable_src; 25463 const index_val = maybe_index_val orelse break :rs elem_index_src; 25464 const index = @intCast(usize, index_val.toUnsignedInt(mod)); 25465 const result_ty = try sema.elemPtrType(indexable_ty, index); 25466 const elem_ptr = try ptr_val.elemPtr(result_ty, index, mod); 25467 return sema.addConstant(result_ty, elem_ptr); 25468 }; 25469 const result_ty = try sema.elemPtrType(indexable_ty, null); 25470 25471 try sema.requireRuntimeBlock(block, src, runtime_src); 25472 return block.addPtrElemPtr(indexable, elem_index, result_ty); 25473 }, 25474 .One => { 25475 assert(indexable_ty.childType(mod).zigTypeTag(mod) == .Array); // Guaranteed by checkIndexable 25476 return sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety); 25477 }, 25478 } 25479 } 25480 25481 fn elemVal( 25482 sema: *Sema, 25483 block: *Block, 25484 src: LazySrcLoc, 25485 indexable: Air.Inst.Ref, 25486 elem_index_uncasted: Air.Inst.Ref, 25487 elem_index_src: LazySrcLoc, 25488 oob_safety: bool, 25489 ) CompileError!Air.Inst.Ref { 25490 const indexable_src = src; // TODO better source location 25491 const indexable_ty = sema.typeOf(indexable); 25492 const mod = sema.mod; 25493 25494 try checkIndexable(sema, block, src, indexable_ty); 25495 25496 // TODO in case of a vector of pointers, we need to detect whether the element 25497 // index is a scalar or vector instead of unconditionally casting to usize. 25498 const elem_index = try sema.coerce(block, Type.usize, elem_index_uncasted, elem_index_src); 25499 25500 switch (indexable_ty.zigTypeTag(mod)) { 25501 .Pointer => switch (indexable_ty.ptrSize(mod)) { 25502 .Slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), 25503 .Many, .C => { 25504 const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable); 25505 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); 25506 25507 const runtime_src = rs: { 25508 const indexable_val = maybe_indexable_val orelse break :rs indexable_src; 25509 const index_val = maybe_index_val orelse break :rs elem_index_src; 25510 const index = @intCast(usize, index_val.toUnsignedInt(mod)); 25511 const elem_ty = indexable_ty.elemType2(mod); 25512 const many_ptr_ty = try mod.manyConstPtrType(elem_ty); 25513 const many_ptr_val = try mod.getCoerced(indexable_val, many_ptr_ty); 25514 const elem_ptr_ty = try mod.singleConstPtrType(elem_ty); 25515 const elem_ptr_val = try many_ptr_val.elemPtr(elem_ptr_ty, index, mod); 25516 if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| { 25517 return sema.addConstant(elem_ty, try mod.getCoerced(elem_val, elem_ty)); 25518 } 25519 break :rs indexable_src; 25520 }; 25521 25522 try sema.requireRuntimeBlock(block, src, runtime_src); 25523 return block.addBinOp(.ptr_elem_val, indexable, elem_index); 25524 }, 25525 .One => { 25526 const array_ty = indexable_ty.childType(mod); // Guaranteed by checkIndexable 25527 assert(array_ty.zigTypeTag(mod) == .Array); 25528 25529 if (array_ty.sentinel(mod)) |sentinel| { 25530 // index must be defined since it can access out of bounds 25531 if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| { 25532 const index = @intCast(usize, index_val.toUnsignedInt(mod)); 25533 if (index == array_ty.arrayLen(mod)) { 25534 return sema.addConstant(array_ty.childType(mod), sentinel); 25535 } 25536 } 25537 } 25538 25539 const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety); 25540 return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src); 25541 }, 25542 }, 25543 .Array => return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), 25544 .Vector => { 25545 // TODO: If the index is a vector, the result should be a vector. 25546 return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety); 25547 }, 25548 .Struct => { 25549 // Tuple field access. 25550 const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known"); 25551 const index = @intCast(u32, index_val.toUnsignedInt(mod)); 25552 return sema.tupleField(block, indexable_src, indexable, elem_index_src, index); 25553 }, 25554 else => unreachable, 25555 } 25556 } 25557 25558 fn validateRuntimeElemAccess( 25559 sema: *Sema, 25560 block: *Block, 25561 elem_index_src: LazySrcLoc, 25562 elem_ty: Type, 25563 parent_ty: Type, 25564 parent_src: LazySrcLoc, 25565 ) CompileError!void { 25566 const mod = sema.mod; 25567 const valid_rt = try sema.validateRunTimeType(elem_ty, false); 25568 if (!valid_rt) { 25569 const msg = msg: { 25570 const msg = try sema.errMsg( 25571 block, 25572 elem_index_src, 25573 "values of type '{}' must be comptime-known, but index value is runtime-known", 25574 .{parent_ty.fmt(mod)}, 25575 ); 25576 errdefer msg.destroy(sema.gpa); 25577 25578 const src_decl = mod.declPtr(block.src_decl); 25579 try sema.explainWhyTypeIsComptime(msg, parent_src.toSrcLoc(src_decl, mod), parent_ty); 25580 25581 break :msg msg; 25582 }; 25583 return sema.failWithOwnedErrorMsg(msg); 25584 } 25585 } 25586 25587 fn tupleFieldPtr( 25588 sema: *Sema, 25589 block: *Block, 25590 tuple_ptr_src: LazySrcLoc, 25591 tuple_ptr: Air.Inst.Ref, 25592 field_index_src: LazySrcLoc, 25593 field_index: u32, 25594 init: bool, 25595 ) CompileError!Air.Inst.Ref { 25596 const mod = sema.mod; 25597 const tuple_ptr_ty = sema.typeOf(tuple_ptr); 25598 const tuple_ty = tuple_ptr_ty.childType(mod); 25599 _ = try sema.resolveTypeFields(tuple_ty); 25600 const field_count = tuple_ty.structFieldCount(mod); 25601 25602 if (field_count == 0) { 25603 return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{}); 25604 } 25605 25606 if (field_index >= field_count) { 25607 return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ 25608 field_index, field_count, 25609 }); 25610 } 25611 25612 const field_ty = tuple_ty.structFieldType(field_index, mod); 25613 const ptr_field_ty = try Type.ptr(sema.arena, mod, .{ 25614 .pointee_type = field_ty, 25615 .mutable = tuple_ptr_ty.ptrIsMutable(mod), 25616 .@"volatile" = tuple_ptr_ty.isVolatilePtr(mod), 25617 .@"addrspace" = tuple_ptr_ty.ptrAddressSpace(mod), 25618 }); 25619 25620 if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| { 25621 return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ 25622 .ty = ptr_field_ty.toIntern(), 25623 .addr = .{ .comptime_field = default_val.toIntern() }, 25624 } })).toValue()); 25625 } 25626 25627 if (try sema.resolveMaybeUndefVal(tuple_ptr)) |tuple_ptr_val| { 25628 return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ 25629 .ty = ptr_field_ty.toIntern(), 25630 .addr = .{ .field = .{ 25631 .base = tuple_ptr_val.toIntern(), 25632 .index = field_index, 25633 } }, 25634 } })).toValue()); 25635 } 25636 25637 if (!init) { 25638 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_ptr_src); 25639 } 25640 25641 try sema.requireRuntimeBlock(block, tuple_ptr_src, null); 25642 return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty); 25643 } 25644 25645 fn tupleField( 25646 sema: *Sema, 25647 block: *Block, 25648 tuple_src: LazySrcLoc, 25649 tuple: Air.Inst.Ref, 25650 field_index_src: LazySrcLoc, 25651 field_index: u32, 25652 ) CompileError!Air.Inst.Ref { 25653 const mod = sema.mod; 25654 const tuple_ty = try sema.resolveTypeFields(sema.typeOf(tuple)); 25655 const field_count = tuple_ty.structFieldCount(mod); 25656 25657 if (field_count == 0) { 25658 return sema.fail(block, tuple_src, "indexing into empty tuple is not allowed", .{}); 25659 } 25660 25661 if (field_index >= field_count) { 25662 return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ 25663 field_index, field_count, 25664 }); 25665 } 25666 25667 const field_ty = tuple_ty.structFieldType(field_index, mod); 25668 25669 if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_value| { 25670 return sema.addConstant(field_ty, default_value); // comptime field 25671 } 25672 25673 if (try sema.resolveMaybeUndefVal(tuple)) |tuple_val| { 25674 if (tuple_val.isUndef(mod)) return sema.addConstUndef(field_ty); 25675 return sema.addConstant(field_ty, try tuple_val.fieldValue(mod, field_index)); 25676 } 25677 25678 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src); 25679 25680 try sema.requireRuntimeBlock(block, tuple_src, null); 25681 return block.addStructFieldVal(tuple, field_index, field_ty); 25682 } 25683 25684 fn elemValArray( 25685 sema: *Sema, 25686 block: *Block, 25687 src: LazySrcLoc, 25688 array_src: LazySrcLoc, 25689 array: Air.Inst.Ref, 25690 elem_index_src: LazySrcLoc, 25691 elem_index: Air.Inst.Ref, 25692 oob_safety: bool, 25693 ) CompileError!Air.Inst.Ref { 25694 const mod = sema.mod; 25695 const array_ty = sema.typeOf(array); 25696 const array_sent = array_ty.sentinel(mod); 25697 const array_len = array_ty.arrayLen(mod); 25698 const array_len_s = array_len + @boolToInt(array_sent != null); 25699 const elem_ty = array_ty.childType(mod); 25700 25701 if (array_len_s == 0) { 25702 return sema.fail(block, array_src, "indexing into empty array is not allowed", .{}); 25703 } 25704 25705 const maybe_undef_array_val = try sema.resolveMaybeUndefVal(array); 25706 // index must be defined since it can access out of bounds 25707 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); 25708 25709 if (maybe_index_val) |index_val| { 25710 const index = @intCast(usize, index_val.toUnsignedInt(mod)); 25711 if (array_sent) |s| { 25712 if (index == array_len) { 25713 return sema.addConstant(elem_ty, s); 25714 } 25715 } 25716 if (index >= array_len_s) { 25717 const sentinel_label: []const u8 = if (array_sent != null) " +1 (sentinel)" else ""; 25718 return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); 25719 } 25720 } 25721 if (maybe_undef_array_val) |array_val| { 25722 if (array_val.isUndef(mod)) { 25723 return sema.addConstUndef(elem_ty); 25724 } 25725 if (maybe_index_val) |index_val| { 25726 const index = @intCast(usize, index_val.toUnsignedInt(mod)); 25727 const elem_val = try array_val.elemValue(mod, index); 25728 return sema.addConstant(elem_ty, elem_val); 25729 } 25730 } 25731 25732 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src); 25733 25734 const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src; 25735 try sema.requireRuntimeBlock(block, src, runtime_src); 25736 if (oob_safety and block.wantSafety()) { 25737 // Runtime check is only needed if unable to comptime check 25738 if (maybe_index_val == null) { 25739 const len_inst = try sema.addIntUnsigned(Type.usize, array_len); 25740 const cmp_op: Air.Inst.Tag = if (array_sent != null) .cmp_lte else .cmp_lt; 25741 try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op); 25742 } 25743 } 25744 return block.addBinOp(.array_elem_val, array, elem_index); 25745 } 25746 25747 fn elemPtrArray( 25748 sema: *Sema, 25749 block: *Block, 25750 src: LazySrcLoc, 25751 array_ptr_src: LazySrcLoc, 25752 array_ptr: Air.Inst.Ref, 25753 elem_index_src: LazySrcLoc, 25754 elem_index: Air.Inst.Ref, 25755 init: bool, 25756 oob_safety: bool, 25757 ) CompileError!Air.Inst.Ref { 25758 const mod = sema.mod; 25759 const array_ptr_ty = sema.typeOf(array_ptr); 25760 const array_ty = array_ptr_ty.childType(mod); 25761 const array_sent = array_ty.sentinel(mod) != null; 25762 const array_len = array_ty.arrayLen(mod); 25763 const array_len_s = array_len + @boolToInt(array_sent); 25764 25765 if (array_len_s == 0) { 25766 return sema.fail(block, array_ptr_src, "indexing into empty array is not allowed", .{}); 25767 } 25768 25769 const maybe_undef_array_ptr_val = try sema.resolveMaybeUndefVal(array_ptr); 25770 // The index must not be undefined since it can be out of bounds. 25771 const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { 25772 const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(mod)); 25773 if (index >= array_len_s) { 25774 const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; 25775 return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); 25776 } 25777 break :o index; 25778 } else null; 25779 25780 const elem_ptr_ty = try sema.elemPtrType(array_ptr_ty, offset); 25781 25782 if (maybe_undef_array_ptr_val) |array_ptr_val| { 25783 if (array_ptr_val.isUndef(mod)) { 25784 return sema.addConstUndef(elem_ptr_ty); 25785 } 25786 if (offset) |index| { 25787 const elem_ptr = try array_ptr_val.elemPtr(elem_ptr_ty, index, mod); 25788 return sema.addConstant(elem_ptr_ty, elem_ptr); 25789 } 25790 } 25791 25792 if (!init) { 25793 try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(mod), array_ty, array_ptr_src); 25794 } 25795 25796 const runtime_src = if (maybe_undef_array_ptr_val != null) elem_index_src else array_ptr_src; 25797 try sema.requireRuntimeBlock(block, src, runtime_src); 25798 25799 // Runtime check is only needed if unable to comptime check. 25800 if (oob_safety and block.wantSafety() and offset == null) { 25801 const len_inst = try sema.addIntUnsigned(Type.usize, array_len); 25802 const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt; 25803 try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op); 25804 } 25805 25806 return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty); 25807 } 25808 25809 fn elemValSlice( 25810 sema: *Sema, 25811 block: *Block, 25812 src: LazySrcLoc, 25813 slice_src: LazySrcLoc, 25814 slice: Air.Inst.Ref, 25815 elem_index_src: LazySrcLoc, 25816 elem_index: Air.Inst.Ref, 25817 oob_safety: bool, 25818 ) CompileError!Air.Inst.Ref { 25819 const mod = sema.mod; 25820 const slice_ty = sema.typeOf(slice); 25821 const slice_sent = slice_ty.sentinel(mod) != null; 25822 const elem_ty = slice_ty.elemType2(mod); 25823 var runtime_src = slice_src; 25824 25825 // slice must be defined since it can dereferenced as null 25826 const maybe_slice_val = try sema.resolveDefinedValue(block, slice_src, slice); 25827 // index must be defined since it can index out of bounds 25828 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); 25829 25830 if (maybe_slice_val) |slice_val| { 25831 runtime_src = elem_index_src; 25832 const slice_len = slice_val.sliceLen(mod); 25833 const slice_len_s = slice_len + @boolToInt(slice_sent); 25834 if (slice_len_s == 0) { 25835 return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); 25836 } 25837 if (maybe_index_val) |index_val| { 25838 const index = @intCast(usize, index_val.toUnsignedInt(mod)); 25839 if (index >= slice_len_s) { 25840 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; 25841 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); 25842 } 25843 const elem_ptr_ty = try sema.elemPtrType(slice_ty, index); 25844 const elem_ptr_val = try slice_val.elemPtr(elem_ptr_ty, index, mod); 25845 if (try sema.pointerDeref(block, slice_src, elem_ptr_val, elem_ptr_ty)) |elem_val| { 25846 return sema.addConstant(elem_ty, elem_val); 25847 } 25848 runtime_src = slice_src; 25849 } 25850 } 25851 25852 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src); 25853 25854 try sema.requireRuntimeBlock(block, src, runtime_src); 25855 if (oob_safety and block.wantSafety()) { 25856 const len_inst = if (maybe_slice_val) |slice_val| 25857 try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(mod)) 25858 else 25859 try block.addTyOp(.slice_len, Type.usize, slice); 25860 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; 25861 try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op); 25862 } 25863 try sema.queueFullTypeResolution(sema.typeOf(slice)); 25864 return block.addBinOp(.slice_elem_val, slice, elem_index); 25865 } 25866 25867 fn elemPtrSlice( 25868 sema: *Sema, 25869 block: *Block, 25870 src: LazySrcLoc, 25871 slice_src: LazySrcLoc, 25872 slice: Air.Inst.Ref, 25873 elem_index_src: LazySrcLoc, 25874 elem_index: Air.Inst.Ref, 25875 oob_safety: bool, 25876 ) CompileError!Air.Inst.Ref { 25877 const mod = sema.mod; 25878 const slice_ty = sema.typeOf(slice); 25879 const slice_sent = slice_ty.sentinel(mod) != null; 25880 25881 const maybe_undef_slice_val = try sema.resolveMaybeUndefVal(slice); 25882 // The index must not be undefined since it can be out of bounds. 25883 const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { 25884 const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(mod)); 25885 break :o index; 25886 } else null; 25887 25888 const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset); 25889 25890 if (maybe_undef_slice_val) |slice_val| { 25891 if (slice_val.isUndef(mod)) { 25892 return sema.addConstUndef(elem_ptr_ty); 25893 } 25894 const slice_len = slice_val.sliceLen(mod); 25895 const slice_len_s = slice_len + @boolToInt(slice_sent); 25896 if (slice_len_s == 0) { 25897 return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); 25898 } 25899 if (offset) |index| { 25900 if (index >= slice_len_s) { 25901 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; 25902 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); 25903 } 25904 const elem_ptr_val = try slice_val.elemPtr(elem_ptr_ty, index, mod); 25905 return sema.addConstant(elem_ptr_ty, elem_ptr_val); 25906 } 25907 } 25908 25909 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ptr_ty, slice_ty, slice_src); 25910 25911 const runtime_src = if (maybe_undef_slice_val != null) elem_index_src else slice_src; 25912 try sema.requireRuntimeBlock(block, src, runtime_src); 25913 if (oob_safety and block.wantSafety()) { 25914 const len_inst = len: { 25915 if (maybe_undef_slice_val) |slice_val| 25916 if (!slice_val.isUndef(mod)) 25917 break :len try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(mod)); 25918 break :len try block.addTyOp(.slice_len, Type.usize, slice); 25919 }; 25920 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; 25921 try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op); 25922 } 25923 return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty); 25924 } 25925 25926 fn coerce( 25927 sema: *Sema, 25928 block: *Block, 25929 dest_ty_unresolved: Type, 25930 inst: Air.Inst.Ref, 25931 inst_src: LazySrcLoc, 25932 ) CompileError!Air.Inst.Ref { 25933 return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, .{}) catch |err| switch (err) { 25934 error.NotCoercible => unreachable, 25935 else => |e| return e, 25936 }; 25937 } 25938 25939 const CoersionError = CompileError || error{ 25940 /// When coerce is called recursively, this error should be returned instead of using `fail` 25941 /// to ensure correct types in compile errors. 25942 NotCoercible, 25943 }; 25944 25945 const CoerceOpts = struct { 25946 /// Should coerceExtra emit error messages. 25947 report_err: bool = true, 25948 /// Ignored if `report_err == false`. 25949 is_ret: bool = false, 25950 /// Should coercion to comptime_int ermit an error message. 25951 no_cast_to_comptime_int: bool = false, 25952 25953 param_src: struct { 25954 func_inst: Air.Inst.Ref = .none, 25955 param_i: u32 = undefined, 25956 25957 fn get(info: @This(), sema: *Sema) !?Module.SrcLoc { 25958 if (info.func_inst == .none) return null; 25959 const mod = sema.mod; 25960 const fn_decl = (try sema.funcDeclSrc(info.func_inst)) orelse return null; 25961 const param_src = Module.paramSrc(0, mod, fn_decl, info.param_i); 25962 if (param_src == .node_offset_param) { 25963 return Module.SrcLoc{ 25964 .file_scope = fn_decl.getFileScope(mod), 25965 .parent_decl_node = fn_decl.src_node, 25966 .lazy = LazySrcLoc.nodeOffset(param_src.node_offset_param), 25967 }; 25968 } 25969 return param_src.toSrcLoc(fn_decl, mod); 25970 } 25971 } = .{}, 25972 }; 25973 25974 fn coerceExtra( 25975 sema: *Sema, 25976 block: *Block, 25977 dest_ty_unresolved: Type, 25978 inst: Air.Inst.Ref, 25979 inst_src: LazySrcLoc, 25980 opts: CoerceOpts, 25981 ) CoersionError!Air.Inst.Ref { 25982 if (dest_ty_unresolved.isGenericPoison()) return inst; 25983 const mod = sema.mod; 25984 const dest_ty_src = inst_src; // TODO better source location 25985 const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved); 25986 const inst_ty = try sema.resolveTypeFields(sema.typeOf(inst)); 25987 const target = mod.getTarget(); 25988 // If the types are the same, we can return the operand. 25989 if (dest_ty.eql(inst_ty, mod)) 25990 return inst; 25991 25992 const maybe_inst_val = try sema.resolveMaybeUndefVal(inst); 25993 25994 var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src); 25995 if (in_memory_result == .ok) { 25996 if (maybe_inst_val) |val| { 25997 return sema.coerceInMemory(block, val, inst_ty, dest_ty, dest_ty_src); 25998 } 25999 try sema.requireRuntimeBlock(block, inst_src, null); 26000 return block.addBitCast(dest_ty, inst); 26001 } 26002 26003 const is_undef = inst_ty.zigTypeTag(mod) == .Undefined; 26004 26005 switch (dest_ty.zigTypeTag(mod)) { 26006 .Optional => optional: { 26007 // undefined sets the optional bit also to undefined. 26008 if (is_undef) { 26009 return sema.addConstUndef(dest_ty); 26010 } 26011 26012 // null to ?T 26013 if (inst_ty.zigTypeTag(mod) == .Null) { 26014 return sema.addConstant(dest_ty, (try mod.intern(.{ .opt = .{ 26015 .ty = dest_ty.toIntern(), 26016 .val = .none, 26017 } })).toValue()); 26018 } 26019 26020 // cast from ?*T and ?[*]T to ?*anyopaque 26021 // but don't do it if the source type is a double pointer 26022 if (dest_ty.isPtrLikeOptional(mod) and 26023 dest_ty.elemType2(mod).toIntern() == .anyopaque_type and 26024 inst_ty.isPtrAtRuntime(mod)) 26025 anyopaque_check: { 26026 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional; 26027 const elem_ty = inst_ty.elemType2(mod); 26028 if (elem_ty.zigTypeTag(mod) == .Pointer or elem_ty.isPtrLikeOptional(mod)) { 26029 in_memory_result = .{ .double_ptr_to_anyopaque = .{ 26030 .actual = inst_ty, 26031 .wanted = dest_ty, 26032 } }; 26033 break :optional; 26034 } 26035 // Let the logic below handle wrapping the optional now that 26036 // it has been checked to correctly coerce. 26037 if (!inst_ty.isPtrLikeOptional(mod)) break :anyopaque_check; 26038 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); 26039 } 26040 26041 // T to ?T 26042 const child_type = dest_ty.optionalChild(mod); 26043 const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) { 26044 error.NotCoercible => { 26045 if (in_memory_result == .no_match) { 26046 // Try to give more useful notes 26047 in_memory_result = try sema.coerceInMemoryAllowed(block, child_type, inst_ty, false, target, dest_ty_src, inst_src); 26048 } 26049 break :optional; 26050 }, 26051 else => |e| return e, 26052 }; 26053 return try sema.wrapOptional(block, dest_ty, intermediate, inst_src); 26054 }, 26055 .Pointer => pointer: { 26056 const dest_info = dest_ty.ptrInfo(mod); 26057 26058 // Function body to function pointer. 26059 if (inst_ty.zigTypeTag(mod) == .Fn) { 26060 const fn_val = try sema.resolveConstValue(block, .unneeded, inst, ""); 26061 const fn_decl = fn_val.pointerDecl(mod).?; 26062 const inst_as_ptr = try sema.analyzeDeclRef(fn_decl); 26063 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src); 26064 } 26065 26066 // *T to *[1]T 26067 single_item: { 26068 if (dest_info.size != .One) break :single_item; 26069 if (!inst_ty.isSinglePointer(mod)) break :single_item; 26070 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; 26071 const ptr_elem_ty = inst_ty.childType(mod); 26072 const array_ty = dest_info.pointee_type; 26073 if (array_ty.zigTypeTag(mod) != .Array) break :single_item; 26074 const array_elem_ty = array_ty.childType(mod); 26075 if (array_ty.arrayLen(mod) != 1) break :single_item; 26076 const dest_is_mut = dest_info.mutable; 26077 switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { 26078 .ok => {}, 26079 else => break :single_item, 26080 } 26081 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); 26082 } 26083 26084 // Coercions where the source is a single pointer to an array. 26085 src_array_ptr: { 26086 if (!inst_ty.isSinglePointer(mod)) break :src_array_ptr; 26087 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; 26088 const array_ty = inst_ty.childType(mod); 26089 if (array_ty.zigTypeTag(mod) != .Array) break :src_array_ptr; 26090 const array_elem_type = array_ty.childType(mod); 26091 const dest_is_mut = dest_info.mutable; 26092 26093 const dst_elem_type = dest_info.pointee_type; 26094 const elem_res = try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src); 26095 switch (elem_res) { 26096 .ok => {}, 26097 else => { 26098 in_memory_result = .{ .ptr_child = .{ 26099 .child = try elem_res.dupe(sema.arena), 26100 .actual = array_elem_type, 26101 .wanted = dst_elem_type, 26102 } }; 26103 break :src_array_ptr; 26104 }, 26105 } 26106 26107 if (dest_info.sentinel) |dest_sent| { 26108 if (array_ty.sentinel(mod)) |inst_sent| { 26109 if (!dest_sent.eql(inst_sent, dst_elem_type, mod)) { 26110 in_memory_result = .{ .ptr_sentinel = .{ 26111 .actual = inst_sent, 26112 .wanted = dest_sent, 26113 .ty = dst_elem_type, 26114 } }; 26115 break :src_array_ptr; 26116 } 26117 } else { 26118 in_memory_result = .{ .ptr_sentinel = .{ 26119 .actual = Value.@"unreachable", 26120 .wanted = dest_sent, 26121 .ty = dst_elem_type, 26122 } }; 26123 break :src_array_ptr; 26124 } 26125 } 26126 26127 switch (dest_info.size) { 26128 .Slice => { 26129 // *[N]T to []T 26130 return sema.coerceArrayPtrToSlice(block, dest_ty, inst, inst_src); 26131 }, 26132 .C => { 26133 // *[N]T to [*c]T 26134 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); 26135 }, 26136 .Many => { 26137 // *[N]T to [*]T 26138 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); 26139 }, 26140 .One => {}, 26141 } 26142 } 26143 26144 // coercion from C pointer 26145 if (inst_ty.isCPtr(mod)) src_c_ptr: { 26146 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :src_c_ptr; 26147 // In this case we must add a safety check because the C pointer 26148 // could be null. 26149 const src_elem_ty = inst_ty.childType(mod); 26150 const dest_is_mut = dest_info.mutable; 26151 const dst_elem_type = dest_info.pointee_type; 26152 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { 26153 .ok => {}, 26154 else => break :src_c_ptr, 26155 } 26156 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); 26157 } 26158 26159 // cast from *T and [*]T to *anyopaque 26160 // but don't do it if the source type is a double pointer 26161 if (dest_info.pointee_type.toIntern() == .anyopaque_type and inst_ty.zigTypeTag(mod) == .Pointer) to_anyopaque: { 26162 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; 26163 const elem_ty = inst_ty.elemType2(mod); 26164 if (elem_ty.zigTypeTag(mod) == .Pointer or elem_ty.isPtrLikeOptional(mod)) { 26165 in_memory_result = .{ .double_ptr_to_anyopaque = .{ 26166 .actual = inst_ty, 26167 .wanted = dest_ty, 26168 } }; 26169 break :pointer; 26170 } 26171 if (dest_ty.isSlice(mod)) break :to_anyopaque; 26172 if (inst_ty.isSlice(mod)) { 26173 in_memory_result = .{ .slice_to_anyopaque = .{ 26174 .actual = inst_ty, 26175 .wanted = dest_ty, 26176 } }; 26177 break :pointer; 26178 } 26179 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); 26180 } 26181 26182 switch (dest_info.size) { 26183 // coercion to C pointer 26184 .C => switch (inst_ty.zigTypeTag(mod)) { 26185 .Null => { 26186 return sema.addConstant(dest_ty, try mod.getCoerced(Value.null, dest_ty)); 26187 }, 26188 .ComptimeInt => { 26189 const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) { 26190 error.NotCoercible => break :pointer, 26191 else => |e| return e, 26192 }; 26193 return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); 26194 }, 26195 .Int => { 26196 const ptr_size_ty = switch (inst_ty.intInfo(mod).signedness) { 26197 .signed => Type.isize, 26198 .unsigned => Type.usize, 26199 }; 26200 const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) { 26201 error.NotCoercible => { 26202 // Try to give more useful notes 26203 in_memory_result = try sema.coerceInMemoryAllowed(block, ptr_size_ty, inst_ty, false, target, dest_ty_src, inst_src); 26204 break :pointer; 26205 }, 26206 else => |e| return e, 26207 }; 26208 return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); 26209 }, 26210 .Pointer => p: { 26211 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p; 26212 const inst_info = inst_ty.ptrInfo(mod); 26213 switch (try sema.coerceInMemoryAllowed( 26214 block, 26215 dest_info.pointee_type, 26216 inst_info.pointee_type, 26217 dest_info.mutable, 26218 target, 26219 dest_ty_src, 26220 inst_src, 26221 )) { 26222 .ok => {}, 26223 else => break :p, 26224 } 26225 if (inst_info.size == .Slice) { 26226 assert(dest_info.sentinel == null); 26227 if (inst_info.sentinel == null or 26228 !inst_info.sentinel.?.eql(try mod.intValue(dest_info.pointee_type, 0), dest_info.pointee_type, mod)) 26229 break :p; 26230 26231 const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); 26232 return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src); 26233 } 26234 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); 26235 }, 26236 else => {}, 26237 }, 26238 .One => switch (dest_info.pointee_type.zigTypeTag(mod)) { 26239 .Union => { 26240 // pointer to anonymous struct to pointer to union 26241 if (inst_ty.isSinglePointer(mod) and 26242 inst_ty.childType(mod).isAnonStruct(mod) and 26243 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) 26244 { 26245 return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src); 26246 } 26247 }, 26248 .Struct => { 26249 // pointer to anonymous struct to pointer to struct 26250 if (inst_ty.isSinglePointer(mod) and 26251 inst_ty.childType(mod).isAnonStruct(mod) and 26252 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) 26253 { 26254 return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src) catch |err| switch (err) { 26255 error.NotCoercible => break :pointer, 26256 else => |e| return e, 26257 }; 26258 } 26259 }, 26260 .Array => { 26261 // pointer to tuple to pointer to array 26262 if (inst_ty.isSinglePointer(mod) and 26263 inst_ty.childType(mod).isTuple(mod) and 26264 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) 26265 { 26266 return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src); 26267 } 26268 }, 26269 else => {}, 26270 }, 26271 .Slice => to_slice: { 26272 if (inst_ty.zigTypeTag(mod) == .Array) { 26273 return sema.fail( 26274 block, 26275 inst_src, 26276 "array literal requires address-of operator (&) to coerce to slice type '{}'", 26277 .{dest_ty.fmt(mod)}, 26278 ); 26279 } 26280 26281 if (!inst_ty.isSinglePointer(mod)) break :to_slice; 26282 const inst_child_ty = inst_ty.childType(mod); 26283 if (!inst_child_ty.isTuple(mod)) break :to_slice; 26284 26285 // empty tuple to zero-length slice 26286 // note that this allows coercing to a mutable slice. 26287 if (inst_child_ty.structFieldCount(mod) == 0) { 26288 // Optional slice is represented with a null pointer so 26289 // we use a dummy pointer value with the required alignment. 26290 return sema.addConstant(dest_ty, (try mod.intern(.{ .ptr = .{ 26291 .ty = dest_ty.toIntern(), 26292 .addr = .{ .int = (if (dest_info.@"align" != 0) 26293 try mod.intValue(Type.usize, dest_info.@"align") 26294 else 26295 try mod.getCoerced(try dest_info.pointee_type.lazyAbiAlignment(mod), Type.usize)).toIntern() }, 26296 .len = (try mod.intValue(Type.usize, 0)).toIntern(), 26297 } })).toValue()); 26298 } 26299 26300 // pointer to tuple to slice 26301 if (dest_info.mutable) { 26302 const err_msg = err_msg: { 26303 const err_msg = try sema.errMsg(block, inst_src, "cannot cast pointer to tuple to '{}'", .{dest_ty.fmt(mod)}); 26304 errdefer err_msg.deinit(sema.gpa); 26305 try sema.errNote(block, dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{}); 26306 break :err_msg err_msg; 26307 }; 26308 return sema.failWithOwnedErrorMsg(err_msg); 26309 } 26310 return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src); 26311 }, 26312 .Many => p: { 26313 if (!inst_ty.isSlice(mod)) break :p; 26314 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p; 26315 const inst_info = inst_ty.ptrInfo(mod); 26316 26317 switch (try sema.coerceInMemoryAllowed( 26318 block, 26319 dest_info.pointee_type, 26320 inst_info.pointee_type, 26321 dest_info.mutable, 26322 target, 26323 dest_ty_src, 26324 inst_src, 26325 )) { 26326 .ok => {}, 26327 else => break :p, 26328 } 26329 26330 if (dest_info.sentinel == null or inst_info.sentinel == null or 26331 !dest_info.sentinel.?.eql(inst_info.sentinel.?, dest_info.pointee_type, mod)) 26332 break :p; 26333 26334 const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); 26335 return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src); 26336 }, 26337 } 26338 }, 26339 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag(mod)) { 26340 .Float, .ComptimeFloat => float: { 26341 if (is_undef) { 26342 return sema.addConstUndef(dest_ty); 26343 } 26344 const val = (try sema.resolveMaybeUndefVal(inst)) orelse { 26345 if (dest_ty.zigTypeTag(mod) == .ComptimeInt) { 26346 if (!opts.report_err) return error.NotCoercible; 26347 return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime-known"); 26348 } 26349 break :float; 26350 }; 26351 26352 if (val.floatHasFraction(mod)) { 26353 return sema.fail( 26354 block, 26355 inst_src, 26356 "fractional component prevents float value '{}' from coercion to type '{}'", 26357 .{ val.fmtValue(inst_ty, mod), dest_ty.fmt(mod) }, 26358 ); 26359 } 26360 const result_val = try sema.floatToInt(block, inst_src, val, inst_ty, dest_ty); 26361 return try sema.addConstant(dest_ty, result_val); 26362 }, 26363 .Int, .ComptimeInt => { 26364 if (is_undef) { 26365 return sema.addConstUndef(dest_ty); 26366 } 26367 if (try sema.resolveMaybeUndefVal(inst)) |val| { 26368 // comptime-known integer to other number 26369 if (!(try sema.intFitsInType(val, dest_ty, null))) { 26370 if (!opts.report_err) return error.NotCoercible; 26371 return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) }); 26372 } 26373 return try sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty)); 26374 } 26375 if (dest_ty.zigTypeTag(mod) == .ComptimeInt) { 26376 if (!opts.report_err) return error.NotCoercible; 26377 if (opts.no_cast_to_comptime_int) return inst; 26378 return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime-known"); 26379 } 26380 26381 // integer widening 26382 const dst_info = dest_ty.intInfo(mod); 26383 const src_info = inst_ty.intInfo(mod); 26384 if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or 26385 // small enough unsigned ints can get casted to large enough signed ints 26386 (dst_info.signedness == .signed and dst_info.bits > src_info.bits)) 26387 { 26388 try sema.requireRuntimeBlock(block, inst_src, null); 26389 return block.addTyOp(.intcast, dest_ty, inst); 26390 } 26391 }, 26392 .Undefined => { 26393 return sema.addConstUndef(dest_ty); 26394 }, 26395 else => {}, 26396 }, 26397 .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(mod)) { 26398 .ComptimeFloat => { 26399 const val = try sema.resolveConstValue(block, .unneeded, inst, ""); 26400 const result_val = try val.floatCast(dest_ty, mod); 26401 return try sema.addConstant(dest_ty, result_val); 26402 }, 26403 .Float => { 26404 if (is_undef) { 26405 return sema.addConstUndef(dest_ty); 26406 } 26407 if (try sema.resolveMaybeUndefVal(inst)) |val| { 26408 const result_val = try val.floatCast(dest_ty, mod); 26409 if (!val.eql(try result_val.floatCast(inst_ty, mod), inst_ty, mod)) { 26410 return sema.fail( 26411 block, 26412 inst_src, 26413 "type '{}' cannot represent float value '{}'", 26414 .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) }, 26415 ); 26416 } 26417 return try sema.addConstant(dest_ty, result_val); 26418 } else if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) { 26419 if (!opts.report_err) return error.NotCoercible; 26420 return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime-known"); 26421 } 26422 26423 // float widening 26424 const src_bits = inst_ty.floatBits(target); 26425 const dst_bits = dest_ty.floatBits(target); 26426 if (dst_bits >= src_bits) { 26427 try sema.requireRuntimeBlock(block, inst_src, null); 26428 return block.addTyOp(.fpext, dest_ty, inst); 26429 } 26430 }, 26431 .Int, .ComptimeInt => int: { 26432 if (is_undef) { 26433 return sema.addConstUndef(dest_ty); 26434 } 26435 const val = (try sema.resolveMaybeUndefVal(inst)) orelse { 26436 if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) { 26437 if (!opts.report_err) return error.NotCoercible; 26438 return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime-known"); 26439 } 26440 break :int; 26441 }; 26442 const result_val = try val.intToFloatAdvanced(sema.arena, inst_ty, dest_ty, mod, sema); 26443 // TODO implement this compile error 26444 //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty); 26445 //if (!int_again_val.eql(val, inst_ty, mod)) { 26446 // return sema.fail( 26447 // block, 26448 // inst_src, 26449 // "type '{}' cannot represent integer value '{}'", 26450 // .{ dest_ty.fmt(mod), val }, 26451 // ); 26452 //} 26453 return try sema.addConstant(dest_ty, result_val); 26454 }, 26455 .Undefined => { 26456 return sema.addConstUndef(dest_ty); 26457 }, 26458 else => {}, 26459 }, 26460 .Enum => switch (inst_ty.zigTypeTag(mod)) { 26461 .EnumLiteral => { 26462 // enum literal to enum 26463 const val = try sema.resolveConstValue(block, .unneeded, inst, ""); 26464 const string = mod.intern_pool.indexToKey(val.toIntern()).enum_literal; 26465 const bytes = mod.intern_pool.stringToSlice(string); 26466 const field_index = dest_ty.enumFieldIndex(bytes, mod) orelse { 26467 const msg = msg: { 26468 const msg = try sema.errMsg( 26469 block, 26470 inst_src, 26471 "no field named '{s}' in enum '{}'", 26472 .{ bytes, dest_ty.fmt(mod) }, 26473 ); 26474 errdefer msg.destroy(sema.gpa); 26475 try sema.addDeclaredHereNote(msg, dest_ty); 26476 break :msg msg; 26477 }; 26478 return sema.failWithOwnedErrorMsg(msg); 26479 }; 26480 return sema.addConstant( 26481 dest_ty, 26482 try mod.enumValueFieldIndex(dest_ty, @intCast(u32, field_index)), 26483 ); 26484 }, 26485 .Union => blk: { 26486 // union to its own tag type 26487 const union_tag_ty = inst_ty.unionTagType(mod) orelse break :blk; 26488 if (union_tag_ty.eql(dest_ty, mod)) { 26489 return sema.unionToTag(block, dest_ty, inst, inst_src); 26490 } 26491 }, 26492 .Undefined => { 26493 return sema.addConstUndef(dest_ty); 26494 }, 26495 else => {}, 26496 }, 26497 .ErrorUnion => switch (inst_ty.zigTypeTag(mod)) { 26498 .ErrorUnion => eu: { 26499 if (maybe_inst_val) |inst_val| { 26500 switch (inst_val.toIntern()) { 26501 .undef => return sema.addConstUndef(dest_ty), 26502 else => switch (mod.intern_pool.indexToKey(inst_val.toIntern())) { 26503 .error_union => |error_union| switch (error_union.val) { 26504 .err_name => |err_name| { 26505 const error_set_ty = inst_ty.errorUnionSet(mod); 26506 const error_set_val = try sema.addConstant(error_set_ty, (try mod.intern(.{ .err = .{ 26507 .ty = error_set_ty.toIntern(), 26508 .name = err_name, 26509 } })).toValue()); 26510 return sema.wrapErrorUnionSet(block, dest_ty, error_set_val, inst_src); 26511 }, 26512 .payload => |payload| { 26513 const payload_val = try sema.addConstant( 26514 inst_ty.errorUnionPayload(mod), 26515 payload.toValue(), 26516 ); 26517 return sema.wrapErrorUnionPayload(block, dest_ty, payload_val, inst_src) catch |err| switch (err) { 26518 error.NotCoercible => break :eu, 26519 else => |e| return e, 26520 }; 26521 }, 26522 }, 26523 else => unreachable, 26524 }, 26525 } 26526 } 26527 }, 26528 .ErrorSet => { 26529 // E to E!T 26530 return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src); 26531 }, 26532 .Undefined => { 26533 return sema.addConstUndef(dest_ty); 26534 }, 26535 else => eu: { 26536 // T to E!T 26537 return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src) catch |err| switch (err) { 26538 error.NotCoercible => break :eu, 26539 else => |e| return e, 26540 }; 26541 }, 26542 }, 26543 .Union => switch (inst_ty.zigTypeTag(mod)) { 26544 .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src), 26545 .Struct => { 26546 if (inst_ty.isAnonStruct(mod)) { 26547 return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src); 26548 } 26549 }, 26550 .Undefined => { 26551 return sema.addConstUndef(dest_ty); 26552 }, 26553 else => {}, 26554 }, 26555 .Array => switch (inst_ty.zigTypeTag(mod)) { 26556 .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src), 26557 .Struct => { 26558 if (inst == .empty_struct) { 26559 return sema.arrayInitEmpty(block, inst_src, dest_ty); 26560 } 26561 if (inst_ty.isTuple(mod)) { 26562 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src); 26563 } 26564 }, 26565 .Undefined => { 26566 return sema.addConstUndef(dest_ty); 26567 }, 26568 else => {}, 26569 }, 26570 .Vector => switch (inst_ty.zigTypeTag(mod)) { 26571 .Array, .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src), 26572 .Struct => { 26573 if (inst_ty.isTuple(mod)) { 26574 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src); 26575 } 26576 }, 26577 .Undefined => { 26578 return sema.addConstUndef(dest_ty); 26579 }, 26580 else => {}, 26581 }, 26582 .Struct => blk: { 26583 if (inst == .empty_struct) { 26584 return sema.structInitEmpty(block, dest_ty, dest_ty_src, inst_src); 26585 } 26586 if (inst_ty.isTupleOrAnonStruct(mod)) { 26587 return sema.coerceTupleToStruct(block, dest_ty, inst, inst_src) catch |err| switch (err) { 26588 error.NotCoercible => break :blk, 26589 else => |e| return e, 26590 }; 26591 } 26592 }, 26593 else => {}, 26594 } 26595 26596 // undefined to anything. We do this after the big switch above so that 26597 // special logic has a chance to run first, such as `*[N]T` to `[]T` which 26598 // should initialize the length field of the slice. 26599 if (is_undef) { 26600 return sema.addConstUndef(dest_ty); 26601 } 26602 26603 if (!opts.report_err) return error.NotCoercible; 26604 26605 if (opts.is_ret and dest_ty.zigTypeTag(mod) == .NoReturn) { 26606 const msg = msg: { 26607 const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{}); 26608 errdefer msg.destroy(sema.gpa); 26609 26610 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; 26611 const src_decl = mod.declPtr(sema.func.?.owner_decl); 26612 try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "'noreturn' declared here", .{}); 26613 break :msg msg; 26614 }; 26615 return sema.failWithOwnedErrorMsg(msg); 26616 } 26617 26618 const msg = msg: { 26619 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(mod), inst_ty.fmt(mod) }); 26620 errdefer msg.destroy(sema.gpa); 26621 26622 // E!T to T 26623 if (inst_ty.zigTypeTag(mod) == .ErrorUnion and 26624 (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) 26625 { 26626 try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{}); 26627 try sema.errNote(block, inst_src, msg, "consider using 'try', 'catch', or 'if'", .{}); 26628 } 26629 26630 // ?T to T 26631 if (inst_ty.zigTypeTag(mod) == .Optional and 26632 (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) 26633 { 26634 try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{}); 26635 try sema.errNote(block, inst_src, msg, "consider using '.?', 'orelse', or 'if'", .{}); 26636 } 26637 26638 try in_memory_result.report(sema, block, inst_src, msg); 26639 26640 // Add notes about function return type 26641 if (opts.is_ret and mod.test_functions.get(sema.func.?.owner_decl) == null) { 26642 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; 26643 const src_decl = mod.declPtr(sema.func.?.owner_decl); 26644 if (inst_ty.isError(mod) and !dest_ty.isError(mod)) { 26645 try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function cannot return an error", .{}); 26646 } else { 26647 try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function return type declared here", .{}); 26648 } 26649 } 26650 26651 if (try opts.param_src.get(sema)) |param_src| { 26652 try mod.errNoteNonLazy(param_src, msg, "parameter type declared here", .{}); 26653 } 26654 26655 // TODO maybe add "cannot store an error in type '{}'" note 26656 26657 break :msg msg; 26658 }; 26659 return sema.failWithOwnedErrorMsg(msg); 26660 } 26661 26662 fn coerceInMemory( 26663 sema: *Sema, 26664 block: *Block, 26665 val: Value, 26666 src_ty: Type, 26667 dst_ty: Type, 26668 dst_ty_src: LazySrcLoc, 26669 ) CompileError!Air.Inst.Ref { 26670 const mod = sema.mod; 26671 switch (mod.intern_pool.indexToKey(val.toIntern())) { 26672 .aggregate => |aggregate| { 26673 const dst_ty_key = mod.intern_pool.indexToKey(dst_ty.toIntern()); 26674 const dest_len = try sema.usizeCast( 26675 block, 26676 dst_ty_src, 26677 mod.intern_pool.aggregateTypeLen(dst_ty.toIntern()), 26678 ); 26679 direct: { 26680 const src_ty_child = switch (mod.intern_pool.indexToKey(src_ty.toIntern())) { 26681 inline .array_type, .vector_type => |seq_type| seq_type.child, 26682 .anon_struct_type, .struct_type => break :direct, 26683 else => unreachable, 26684 }; 26685 const dst_ty_child = switch (dst_ty_key) { 26686 inline .array_type, .vector_type => |seq_type| seq_type.child, 26687 .anon_struct_type, .struct_type => break :direct, 26688 else => unreachable, 26689 }; 26690 if (src_ty_child != dst_ty_child) break :direct; 26691 return try sema.addConstant(dst_ty, (try mod.intern(.{ .aggregate = .{ 26692 .ty = dst_ty.toIntern(), 26693 .storage = switch (aggregate.storage) { 26694 .bytes => |bytes| .{ .bytes = bytes[0..dest_len] }, 26695 .elems => |elems| .{ .elems = elems[0..dest_len] }, 26696 .repeated_elem => |elem| .{ .repeated_elem = elem }, 26697 }, 26698 } })).toValue()); 26699 } 26700 const dest_elems = try sema.arena.alloc(InternPool.Index, dest_len); 26701 for (dest_elems, 0..) |*dest_elem, i| { 26702 const elem_ty = switch (dst_ty_key) { 26703 inline .array_type, .vector_type => |seq_type| seq_type.child, 26704 .anon_struct_type => |anon_struct_type| anon_struct_type.types[i], 26705 .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).? 26706 .fields.values()[i].ty.toIntern(), 26707 else => unreachable, 26708 }; 26709 dest_elem.* = try mod.intern_pool.getCoerced(mod.gpa, switch (aggregate.storage) { 26710 .bytes => |bytes| (try mod.intValue(Type.u8, bytes[i])).toIntern(), 26711 .elems => |elems| elems[i], 26712 .repeated_elem => |elem| elem, 26713 }, elem_ty); 26714 } 26715 return sema.addConstant(dst_ty, (try mod.intern(.{ .aggregate = .{ 26716 .ty = dst_ty.toIntern(), 26717 .storage = .{ .elems = dest_elems }, 26718 } })).toValue()); 26719 }, 26720 .float => |float| return sema.addConstant(dst_ty, (try mod.intern(.{ .float = .{ 26721 .ty = dst_ty.toIntern(), 26722 .storage = float.storage, 26723 } })).toValue()), 26724 else => return sema.addConstant(dst_ty, try mod.getCoerced(val, dst_ty)), 26725 } 26726 } 26727 26728 const InMemoryCoercionResult = union(enum) { 26729 ok, 26730 no_match: Pair, 26731 int_not_coercible: Int, 26732 error_union_payload: PairAndChild, 26733 array_len: IntPair, 26734 array_sentinel: Sentinel, 26735 array_elem: PairAndChild, 26736 vector_len: IntPair, 26737 vector_elem: PairAndChild, 26738 optional_shape: Pair, 26739 optional_child: PairAndChild, 26740 from_anyerror, 26741 missing_error: []const InternPool.NullTerminatedString, 26742 /// true if wanted is var args 26743 fn_var_args: bool, 26744 /// true if wanted is generic 26745 fn_generic: bool, 26746 fn_param_count: IntPair, 26747 fn_param_noalias: IntPair, 26748 fn_param_comptime: ComptimeParam, 26749 fn_param: Param, 26750 fn_cc: CC, 26751 fn_return_type: PairAndChild, 26752 ptr_child: PairAndChild, 26753 ptr_addrspace: AddressSpace, 26754 ptr_sentinel: Sentinel, 26755 ptr_size: Size, 26756 ptr_qualifiers: Qualifiers, 26757 ptr_allowzero: Pair, 26758 ptr_bit_range: BitRange, 26759 ptr_alignment: IntPair, 26760 double_ptr_to_anyopaque: Pair, 26761 slice_to_anyopaque: Pair, 26762 26763 const Pair = struct { 26764 actual: Type, 26765 wanted: Type, 26766 }; 26767 26768 const PairAndChild = struct { 26769 child: *InMemoryCoercionResult, 26770 actual: Type, 26771 wanted: Type, 26772 }; 26773 26774 const Param = struct { 26775 child: *InMemoryCoercionResult, 26776 actual: Type, 26777 wanted: Type, 26778 index: u64, 26779 }; 26780 26781 const ComptimeParam = struct { 26782 index: u64, 26783 wanted: bool, 26784 }; 26785 26786 const Sentinel = struct { 26787 // unreachable_value indicates no sentinel 26788 actual: Value, 26789 wanted: Value, 26790 ty: Type, 26791 }; 26792 26793 const Int = struct { 26794 actual_signedness: std.builtin.Signedness, 26795 wanted_signedness: std.builtin.Signedness, 26796 actual_bits: u16, 26797 wanted_bits: u16, 26798 }; 26799 26800 const IntPair = struct { 26801 actual: u64, 26802 wanted: u64, 26803 }; 26804 26805 const Size = struct { 26806 actual: std.builtin.Type.Pointer.Size, 26807 wanted: std.builtin.Type.Pointer.Size, 26808 }; 26809 26810 const Qualifiers = struct { 26811 actual_const: bool, 26812 wanted_const: bool, 26813 actual_volatile: bool, 26814 wanted_volatile: bool, 26815 }; 26816 26817 const AddressSpace = struct { 26818 actual: std.builtin.AddressSpace, 26819 wanted: std.builtin.AddressSpace, 26820 }; 26821 26822 const CC = struct { 26823 actual: std.builtin.CallingConvention, 26824 wanted: std.builtin.CallingConvention, 26825 }; 26826 26827 const BitRange = struct { 26828 actual_host: u16, 26829 wanted_host: u16, 26830 actual_offset: u16, 26831 wanted_offset: u16, 26832 }; 26833 26834 fn dupe(child: *const InMemoryCoercionResult, arena: Allocator) !*InMemoryCoercionResult { 26835 const res = try arena.create(InMemoryCoercionResult); 26836 res.* = child.*; 26837 return res; 26838 } 26839 26840 fn report(res: *const InMemoryCoercionResult, sema: *Sema, block: *Block, src: LazySrcLoc, msg: *Module.ErrorMsg) !void { 26841 const mod = sema.mod; 26842 var cur = res; 26843 while (true) switch (cur.*) { 26844 .ok => unreachable, 26845 .no_match => |types| { 26846 try sema.addDeclaredHereNote(msg, types.wanted); 26847 try sema.addDeclaredHereNote(msg, types.actual); 26848 break; 26849 }, 26850 .int_not_coercible => |int| { 26851 try sema.errNote(block, src, msg, "{s} {d}-bit int cannot represent all possible {s} {d}-bit values", .{ 26852 @tagName(int.wanted_signedness), int.wanted_bits, @tagName(int.actual_signedness), int.actual_bits, 26853 }); 26854 break; 26855 }, 26856 .error_union_payload => |pair| { 26857 try sema.errNote(block, src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{ 26858 pair.actual.fmt(mod), pair.wanted.fmt(mod), 26859 }); 26860 cur = pair.child; 26861 }, 26862 .array_len => |lens| { 26863 try sema.errNote(block, src, msg, "array of length {d} cannot cast into an array of length {d}", .{ 26864 lens.actual, lens.wanted, 26865 }); 26866 break; 26867 }, 26868 .array_sentinel => |sentinel| { 26869 if (sentinel.actual.toIntern() != .unreachable_value) { 26870 try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{ 26871 sentinel.actual.fmtValue(sentinel.ty, mod), sentinel.wanted.fmtValue(sentinel.ty, mod), 26872 }); 26873 } else { 26874 try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{ 26875 sentinel.wanted.fmtValue(sentinel.ty, mod), 26876 }); 26877 } 26878 break; 26879 }, 26880 .array_elem => |pair| { 26881 try sema.errNote(block, src, msg, "array element type '{}' cannot cast into array element type '{}'", .{ 26882 pair.actual.fmt(mod), pair.wanted.fmt(mod), 26883 }); 26884 cur = pair.child; 26885 }, 26886 .vector_len => |lens| { 26887 try sema.errNote(block, src, msg, "vector of length {d} cannot cast into a vector of length {d}", .{ 26888 lens.actual, lens.wanted, 26889 }); 26890 break; 26891 }, 26892 .vector_elem => |pair| { 26893 try sema.errNote(block, src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{ 26894 pair.actual.fmt(mod), pair.wanted.fmt(mod), 26895 }); 26896 cur = pair.child; 26897 }, 26898 .optional_shape => |pair| { 26899 try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ 26900 pair.actual.optionalChild(mod).fmt(mod), pair.wanted.optionalChild(mod).fmt(mod), 26901 }); 26902 break; 26903 }, 26904 .optional_child => |pair| { 26905 try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ 26906 pair.actual.fmt(mod), pair.wanted.fmt(mod), 26907 }); 26908 cur = pair.child; 26909 }, 26910 .from_anyerror => { 26911 try sema.errNote(block, src, msg, "global error set cannot cast into a smaller set", .{}); 26912 break; 26913 }, 26914 .missing_error => |missing_errors| { 26915 for (missing_errors) |err_index| { 26916 const err = mod.intern_pool.stringToSlice(err_index); 26917 try sema.errNote(block, src, msg, "'error.{s}' not a member of destination error set", .{err}); 26918 } 26919 break; 26920 }, 26921 .fn_var_args => |wanted_var_args| { 26922 if (wanted_var_args) { 26923 try sema.errNote(block, src, msg, "non-variadic function cannot cast into a variadic function", .{}); 26924 } else { 26925 try sema.errNote(block, src, msg, "variadic function cannot cast into a non-variadic function", .{}); 26926 } 26927 break; 26928 }, 26929 .fn_generic => |wanted_generic| { 26930 if (wanted_generic) { 26931 try sema.errNote(block, src, msg, "non-generic function cannot cast into a generic function", .{}); 26932 } else { 26933 try sema.errNote(block, src, msg, "generic function cannot cast into a non-generic function", .{}); 26934 } 26935 break; 26936 }, 26937 .fn_param_count => |lens| { 26938 try sema.errNote(block, src, msg, "function with {d} parameters cannot cast into a function with {d} parameters", .{ 26939 lens.actual, lens.wanted, 26940 }); 26941 break; 26942 }, 26943 .fn_param_noalias => |param| { 26944 var index: u6 = 0; 26945 var actual_noalias = false; 26946 while (true) : (index += 1) { 26947 const actual = @truncate(u1, param.actual >> index); 26948 const wanted = @truncate(u1, param.wanted >> index); 26949 if (actual != wanted) { 26950 actual_noalias = actual == 1; 26951 break; 26952 } 26953 } 26954 if (!actual_noalias) { 26955 try sema.errNote(block, src, msg, "regular parameter {d} cannot cast into a noalias parameter", .{index}); 26956 } else { 26957 try sema.errNote(block, src, msg, "noalias parameter {d} cannot cast into a regular parameter", .{index}); 26958 } 26959 break; 26960 }, 26961 .fn_param_comptime => |param| { 26962 if (param.wanted) { 26963 try sema.errNote(block, src, msg, "non-comptime parameter {d} cannot cast into a comptime parameter", .{param.index}); 26964 } else { 26965 try sema.errNote(block, src, msg, "comptime parameter {d} cannot cast into a non-comptime parameter", .{param.index}); 26966 } 26967 break; 26968 }, 26969 .fn_param => |param| { 26970 try sema.errNote(block, src, msg, "parameter {d} '{}' cannot cast into '{}'", .{ 26971 param.index, param.actual.fmt(mod), param.wanted.fmt(mod), 26972 }); 26973 cur = param.child; 26974 }, 26975 .fn_cc => |cc| { 26976 try sema.errNote(block, src, msg, "calling convention '{s}' cannot cast into calling convention '{s}'", .{ @tagName(cc.actual), @tagName(cc.wanted) }); 26977 break; 26978 }, 26979 .fn_return_type => |pair| { 26980 try sema.errNote(block, src, msg, "return type '{}' cannot cast into return type '{}'", .{ 26981 pair.actual.fmt(mod), pair.wanted.fmt(mod), 26982 }); 26983 cur = pair.child; 26984 }, 26985 .ptr_child => |pair| { 26986 try sema.errNote(block, src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{ 26987 pair.actual.fmt(mod), pair.wanted.fmt(mod), 26988 }); 26989 cur = pair.child; 26990 }, 26991 .ptr_addrspace => |@"addrspace"| { 26992 try sema.errNote(block, src, msg, "address space '{s}' cannot cast into address space '{s}'", .{ @tagName(@"addrspace".actual), @tagName(@"addrspace".wanted) }); 26993 break; 26994 }, 26995 .ptr_sentinel => |sentinel| { 26996 if (sentinel.actual.toIntern() != .unreachable_value) { 26997 try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{ 26998 sentinel.actual.fmtValue(sentinel.ty, mod), sentinel.wanted.fmtValue(sentinel.ty, mod), 26999 }); 27000 } else { 27001 try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{ 27002 sentinel.wanted.fmtValue(sentinel.ty, mod), 27003 }); 27004 } 27005 break; 27006 }, 27007 .ptr_size => |size| { 27008 try sema.errNote(block, src, msg, "a {s} pointer cannot cast into a {s} pointer", .{ pointerSizeString(size.actual), pointerSizeString(size.wanted) }); 27009 break; 27010 }, 27011 .ptr_qualifiers => |qualifiers| { 27012 const ok_const = !qualifiers.actual_const or qualifiers.wanted_const; 27013 const ok_volatile = !qualifiers.actual_volatile or qualifiers.wanted_volatile; 27014 if (!ok_const) { 27015 try sema.errNote(block, src, msg, "cast discards const qualifier", .{}); 27016 } else if (!ok_volatile) { 27017 try sema.errNote(block, src, msg, "cast discards volatile qualifier", .{}); 27018 } 27019 break; 27020 }, 27021 .ptr_allowzero => |pair| { 27022 const wanted_allow_zero = pair.wanted.ptrAllowsZero(mod); 27023 const actual_allow_zero = pair.actual.ptrAllowsZero(mod); 27024 if (actual_allow_zero and !wanted_allow_zero) { 27025 try sema.errNote(block, src, msg, "'{}' could have null values which are illegal in type '{}'", .{ 27026 pair.actual.fmt(mod), pair.wanted.fmt(mod), 27027 }); 27028 } else { 27029 try sema.errNote(block, src, msg, "mutable '{}' allows illegal null values stored to type '{}'", .{ 27030 pair.actual.fmt(mod), pair.wanted.fmt(mod), 27031 }); 27032 } 27033 break; 27034 }, 27035 .ptr_bit_range => |bit_range| { 27036 if (bit_range.actual_host != bit_range.wanted_host) { 27037 try sema.errNote(block, src, msg, "pointer host size '{}' cannot cast into pointer host size '{}'", .{ 27038 bit_range.actual_host, bit_range.wanted_host, 27039 }); 27040 } 27041 if (bit_range.actual_offset != bit_range.wanted_offset) { 27042 try sema.errNote(block, src, msg, "pointer bit offset '{}' cannot cast into pointer bit offset '{}'", .{ 27043 bit_range.actual_offset, bit_range.wanted_offset, 27044 }); 27045 } 27046 break; 27047 }, 27048 .ptr_alignment => |pair| { 27049 try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{ 27050 pair.actual, pair.wanted, 27051 }); 27052 break; 27053 }, 27054 .double_ptr_to_anyopaque => |pair| { 27055 try sema.errNote(block, src, msg, "cannot implicitly cast double pointer '{}' to anyopaque pointer '{}'", .{ 27056 pair.actual.fmt(mod), pair.wanted.fmt(mod), 27057 }); 27058 break; 27059 }, 27060 .slice_to_anyopaque => |pair| { 27061 try sema.errNote(block, src, msg, "cannot implicitly cast slice '{}' to anyopaque pointer '{}'", .{ 27062 pair.actual.fmt(mod), pair.wanted.fmt(mod), 27063 }); 27064 try sema.errNote(block, src, msg, "consider using '.ptr'", .{}); 27065 break; 27066 }, 27067 }; 27068 } 27069 }; 27070 27071 fn pointerSizeString(size: std.builtin.Type.Pointer.Size) []const u8 { 27072 return switch (size) { 27073 .One => "single", 27074 .Many => "many", 27075 .C => "C", 27076 .Slice => unreachable, 27077 }; 27078 } 27079 27080 /// If pointers have the same representation in runtime memory, a bitcast AIR instruction 27081 /// may be used for the coercion. 27082 /// * `const` attribute can be gained 27083 /// * `volatile` attribute can be gained 27084 /// * `allowzero` attribute can be gained (whether from explicit attribute, C pointer, or optional pointer) but only if !dest_is_mut 27085 /// * alignment can be decreased 27086 /// * bit offset attributes must match exactly 27087 /// * `*`/`[*]` must match exactly, but `[*c]` matches either one 27088 /// * sentinel-terminated pointers can coerce into `[*]` 27089 fn coerceInMemoryAllowed( 27090 sema: *Sema, 27091 block: *Block, 27092 dest_ty: Type, 27093 src_ty: Type, 27094 dest_is_mut: bool, 27095 target: std.Target, 27096 dest_src: LazySrcLoc, 27097 src_src: LazySrcLoc, 27098 ) CompileError!InMemoryCoercionResult { 27099 const mod = sema.mod; 27100 27101 if (dest_ty.eql(src_ty, mod)) 27102 return .ok; 27103 27104 const dest_tag = dest_ty.zigTypeTag(mod); 27105 const src_tag = src_ty.zigTypeTag(mod); 27106 27107 // Differently-named integers with the same number of bits. 27108 if (dest_tag == .Int and src_tag == .Int) { 27109 const dest_info = dest_ty.intInfo(mod); 27110 const src_info = src_ty.intInfo(mod); 27111 27112 if (dest_info.signedness == src_info.signedness and 27113 dest_info.bits == src_info.bits) 27114 { 27115 return .ok; 27116 } 27117 27118 if ((src_info.signedness == dest_info.signedness and dest_info.bits < src_info.bits) or 27119 // small enough unsigned ints can get casted to large enough signed ints 27120 (dest_info.signedness == .signed and (src_info.signedness == .unsigned or dest_info.bits <= src_info.bits)) or 27121 (dest_info.signedness == .unsigned and src_info.signedness == .signed)) 27122 { 27123 return InMemoryCoercionResult{ .int_not_coercible = .{ 27124 .actual_signedness = src_info.signedness, 27125 .wanted_signedness = dest_info.signedness, 27126 .actual_bits = src_info.bits, 27127 .wanted_bits = dest_info.bits, 27128 } }; 27129 } 27130 } 27131 27132 // Differently-named floats with the same number of bits. 27133 if (dest_tag == .Float and src_tag == .Float) { 27134 const dest_bits = dest_ty.floatBits(target); 27135 const src_bits = src_ty.floatBits(target); 27136 if (dest_bits == src_bits) { 27137 return .ok; 27138 } 27139 } 27140 27141 // Pointers / Pointer-like Optionals 27142 const maybe_dest_ptr_ty = try sema.typePtrOrOptionalPtrTy(dest_ty); 27143 const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(src_ty); 27144 if (maybe_dest_ptr_ty) |dest_ptr_ty| { 27145 if (maybe_src_ptr_ty) |src_ptr_ty| { 27146 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target, dest_src, src_src); 27147 } 27148 } 27149 27150 // Slices 27151 if (dest_ty.isSlice(mod) and src_ty.isSlice(mod)) { 27152 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src); 27153 } 27154 27155 // Functions 27156 if (dest_tag == .Fn and src_tag == .Fn) { 27157 return try sema.coerceInMemoryAllowedFns(block, dest_ty, src_ty, target, dest_src, src_src); 27158 } 27159 27160 // Error Unions 27161 if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) { 27162 const dest_payload = dest_ty.errorUnionPayload(mod); 27163 const src_payload = src_ty.errorUnionPayload(mod); 27164 const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src); 27165 if (child != .ok) { 27166 return InMemoryCoercionResult{ .error_union_payload = .{ 27167 .child = try child.dupe(sema.arena), 27168 .actual = src_payload, 27169 .wanted = dest_payload, 27170 } }; 27171 } 27172 return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(mod), src_ty.errorUnionSet(mod), dest_is_mut, target, dest_src, src_src); 27173 } 27174 27175 // Error Sets 27176 if (dest_tag == .ErrorSet and src_tag == .ErrorSet) { 27177 return try sema.coerceInMemoryAllowedErrorSets(block, dest_ty, src_ty, dest_src, src_src); 27178 } 27179 27180 // Arrays 27181 if (dest_tag == .Array and src_tag == .Array) { 27182 const dest_info = dest_ty.arrayInfo(mod); 27183 const src_info = src_ty.arrayInfo(mod); 27184 if (dest_info.len != src_info.len) { 27185 return InMemoryCoercionResult{ .array_len = .{ 27186 .actual = src_info.len, 27187 .wanted = dest_info.len, 27188 } }; 27189 } 27190 27191 const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src); 27192 if (child != .ok) { 27193 return InMemoryCoercionResult{ .array_elem = .{ 27194 .child = try child.dupe(sema.arena), 27195 .actual = src_info.elem_type, 27196 .wanted = dest_info.elem_type, 27197 } }; 27198 } 27199 const ok_sent = dest_info.sentinel == null or 27200 (src_info.sentinel != null and 27201 dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, mod)); 27202 if (!ok_sent) { 27203 return InMemoryCoercionResult{ .array_sentinel = .{ 27204 .actual = src_info.sentinel orelse Value.@"unreachable", 27205 .wanted = dest_info.sentinel orelse Value.@"unreachable", 27206 .ty = dest_info.elem_type, 27207 } }; 27208 } 27209 return .ok; 27210 } 27211 27212 // Vectors 27213 if (dest_tag == .Vector and src_tag == .Vector) { 27214 const dest_len = dest_ty.vectorLen(mod); 27215 const src_len = src_ty.vectorLen(mod); 27216 if (dest_len != src_len) { 27217 return InMemoryCoercionResult{ .vector_len = .{ 27218 .actual = src_len, 27219 .wanted = dest_len, 27220 } }; 27221 } 27222 27223 const dest_elem_ty = dest_ty.scalarType(mod); 27224 const src_elem_ty = src_ty.scalarType(mod); 27225 const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src); 27226 if (child != .ok) { 27227 return InMemoryCoercionResult{ .vector_elem = .{ 27228 .child = try child.dupe(sema.arena), 27229 .actual = src_elem_ty, 27230 .wanted = dest_elem_ty, 27231 } }; 27232 } 27233 27234 return .ok; 27235 } 27236 27237 // Optionals 27238 if (dest_tag == .Optional and src_tag == .Optional) { 27239 if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) { 27240 return InMemoryCoercionResult{ .optional_shape = .{ 27241 .actual = src_ty, 27242 .wanted = dest_ty, 27243 } }; 27244 } 27245 const dest_child_type = dest_ty.optionalChild(mod); 27246 const src_child_type = src_ty.optionalChild(mod); 27247 27248 const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src); 27249 if (child != .ok) { 27250 return InMemoryCoercionResult{ .optional_child = .{ 27251 .child = try child.dupe(sema.arena), 27252 .actual = src_child_type, 27253 .wanted = dest_child_type, 27254 } }; 27255 } 27256 27257 return .ok; 27258 } 27259 27260 return InMemoryCoercionResult{ .no_match = .{ 27261 .actual = dest_ty, 27262 .wanted = src_ty, 27263 } }; 27264 } 27265 27266 fn coerceInMemoryAllowedErrorSets( 27267 sema: *Sema, 27268 block: *Block, 27269 dest_ty: Type, 27270 src_ty: Type, 27271 dest_src: LazySrcLoc, 27272 src_src: LazySrcLoc, 27273 ) !InMemoryCoercionResult { 27274 const mod = sema.mod; 27275 const gpa = sema.gpa; 27276 const ip = &mod.intern_pool; 27277 27278 // Coercion to `anyerror`. Note that this check can return false negatives 27279 // in case the error sets did not get resolved. 27280 if (dest_ty.isAnyError(mod)) { 27281 return .ok; 27282 } 27283 27284 if (mod.typeToInferredErrorSetIndex(dest_ty).unwrap()) |dst_ies_index| { 27285 const dst_ies = mod.inferredErrorSetPtr(dst_ies_index); 27286 // We will make an effort to return `ok` without resolving either error set, to 27287 // avoid unnecessary "unable to resolve error set" dependency loop errors. 27288 switch (src_ty.toIntern()) { 27289 .anyerror_type => {}, 27290 else => switch (ip.indexToKey(src_ty.toIntern())) { 27291 .inferred_error_set_type => |src_index| { 27292 // If both are inferred error sets of functions, and 27293 // the dest includes the source function, the coercion is OK. 27294 // This check is important because it works without forcing a full resolution 27295 // of inferred error sets. 27296 if (dst_ies.inferred_error_sets.contains(src_index)) { 27297 return .ok; 27298 } 27299 }, 27300 .error_set_type => |error_set_type| { 27301 for (error_set_type.names) |name| { 27302 if (!dst_ies.errors.contains(name)) break; 27303 } else return .ok; 27304 }, 27305 else => unreachable, 27306 }, 27307 } 27308 27309 if (dst_ies.func == sema.owner_func_index.unwrap()) { 27310 // We are trying to coerce an error set to the current function's 27311 // inferred error set. 27312 try dst_ies.addErrorSet(src_ty, ip, gpa); 27313 return .ok; 27314 } 27315 27316 try sema.resolveInferredErrorSet(block, dest_src, dst_ies_index); 27317 // isAnyError might have changed from a false negative to a true positive after resolution. 27318 if (dest_ty.isAnyError(mod)) { 27319 return .ok; 27320 } 27321 } 27322 27323 var missing_error_buf = std.ArrayList(InternPool.NullTerminatedString).init(gpa); 27324 defer missing_error_buf.deinit(); 27325 27326 switch (src_ty.toIntern()) { 27327 .anyerror_type => switch (ip.indexToKey(dest_ty.toIntern())) { 27328 .inferred_error_set_type => unreachable, // Caught by dest_ty.isAnyError(mod) above. 27329 .simple_type => unreachable, // filtered out above 27330 .error_set_type => return .from_anyerror, 27331 else => unreachable, 27332 }, 27333 27334 else => switch (ip.indexToKey(src_ty.toIntern())) { 27335 .inferred_error_set_type => |src_index| { 27336 const src_data = mod.inferredErrorSetPtr(src_index); 27337 27338 try sema.resolveInferredErrorSet(block, src_src, src_index); 27339 // src anyerror status might have changed after the resolution. 27340 if (src_ty.isAnyError(mod)) { 27341 // dest_ty.isAnyError(mod) == true is already checked for at this point. 27342 return .from_anyerror; 27343 } 27344 27345 for (src_data.errors.keys()) |key| { 27346 if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), key)) { 27347 try missing_error_buf.append(key); 27348 } 27349 } 27350 27351 if (missing_error_buf.items.len != 0) { 27352 return InMemoryCoercionResult{ 27353 .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items), 27354 }; 27355 } 27356 27357 return .ok; 27358 }, 27359 .error_set_type => |error_set_type| { 27360 for (error_set_type.names) |name| { 27361 if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), name)) { 27362 try missing_error_buf.append(name); 27363 } 27364 } 27365 27366 if (missing_error_buf.items.len != 0) { 27367 return InMemoryCoercionResult{ 27368 .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items), 27369 }; 27370 } 27371 27372 return .ok; 27373 }, 27374 else => unreachable, 27375 }, 27376 } 27377 27378 unreachable; 27379 } 27380 27381 fn coerceInMemoryAllowedFns( 27382 sema: *Sema, 27383 block: *Block, 27384 dest_ty: Type, 27385 src_ty: Type, 27386 target: std.Target, 27387 dest_src: LazySrcLoc, 27388 src_src: LazySrcLoc, 27389 ) !InMemoryCoercionResult { 27390 const mod = sema.mod; 27391 27392 { 27393 const dest_info = mod.typeToFunc(dest_ty).?; 27394 const src_info = mod.typeToFunc(src_ty).?; 27395 27396 if (dest_info.is_var_args != src_info.is_var_args) { 27397 return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args }; 27398 } 27399 27400 if (dest_info.is_generic != src_info.is_generic) { 27401 return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic }; 27402 } 27403 27404 if (dest_info.cc != src_info.cc) { 27405 return InMemoryCoercionResult{ .fn_cc = .{ 27406 .actual = src_info.cc, 27407 .wanted = dest_info.cc, 27408 } }; 27409 } 27410 27411 if (src_info.return_type != .noreturn_type) { 27412 const dest_return_type = dest_info.return_type.toType(); 27413 const src_return_type = src_info.return_type.toType(); 27414 const rt = try sema.coerceInMemoryAllowed(block, dest_return_type, src_return_type, false, target, dest_src, src_src); 27415 if (rt != .ok) { 27416 return InMemoryCoercionResult{ .fn_return_type = .{ 27417 .child = try rt.dupe(sema.arena), 27418 .actual = dest_return_type, 27419 .wanted = src_return_type, 27420 } }; 27421 } 27422 } 27423 } 27424 27425 const params_len = params_len: { 27426 const dest_info = mod.typeToFunc(dest_ty).?; 27427 const src_info = mod.typeToFunc(src_ty).?; 27428 27429 if (dest_info.param_types.len != src_info.param_types.len) { 27430 return InMemoryCoercionResult{ .fn_param_count = .{ 27431 .actual = src_info.param_types.len, 27432 .wanted = dest_info.param_types.len, 27433 } }; 27434 } 27435 27436 if (dest_info.noalias_bits != src_info.noalias_bits) { 27437 return InMemoryCoercionResult{ .fn_param_noalias = .{ 27438 .actual = src_info.noalias_bits, 27439 .wanted = dest_info.noalias_bits, 27440 } }; 27441 } 27442 27443 break :params_len dest_info.param_types.len; 27444 }; 27445 27446 for (0..params_len) |param_i| { 27447 const dest_info = mod.typeToFunc(dest_ty).?; 27448 const src_info = mod.typeToFunc(src_ty).?; 27449 27450 const dest_param_ty = dest_info.param_types[param_i].toType(); 27451 const src_param_ty = src_info.param_types[param_i].toType(); 27452 27453 const param_i_small = @intCast(u5, param_i); 27454 if (dest_info.paramIsComptime(param_i_small) != src_info.paramIsComptime(param_i_small)) { 27455 return InMemoryCoercionResult{ .fn_param_comptime = .{ 27456 .index = param_i, 27457 .wanted = dest_info.paramIsComptime(param_i_small), 27458 } }; 27459 } 27460 27461 // Note: Cast direction is reversed here. 27462 const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src); 27463 if (param != .ok) { 27464 return InMemoryCoercionResult{ .fn_param = .{ 27465 .child = try param.dupe(sema.arena), 27466 .actual = src_param_ty, 27467 .wanted = dest_param_ty, 27468 .index = param_i, 27469 } }; 27470 } 27471 } 27472 27473 return .ok; 27474 } 27475 27476 fn coerceInMemoryAllowedPtrs( 27477 sema: *Sema, 27478 block: *Block, 27479 dest_ty: Type, 27480 src_ty: Type, 27481 dest_ptr_ty: Type, 27482 src_ptr_ty: Type, 27483 dest_is_mut: bool, 27484 target: std.Target, 27485 dest_src: LazySrcLoc, 27486 src_src: LazySrcLoc, 27487 ) !InMemoryCoercionResult { 27488 const mod = sema.mod; 27489 const dest_info = dest_ptr_ty.ptrInfo(mod); 27490 const src_info = src_ptr_ty.ptrInfo(mod); 27491 27492 const ok_ptr_size = src_info.size == dest_info.size or 27493 src_info.size == .C or dest_info.size == .C; 27494 if (!ok_ptr_size) { 27495 return InMemoryCoercionResult{ .ptr_size = .{ 27496 .actual = src_info.size, 27497 .wanted = dest_info.size, 27498 } }; 27499 } 27500 27501 const ok_cv_qualifiers = 27502 (src_info.mutable or !dest_info.mutable) and 27503 (!src_info.@"volatile" or dest_info.@"volatile"); 27504 27505 if (!ok_cv_qualifiers) { 27506 return InMemoryCoercionResult{ .ptr_qualifiers = .{ 27507 .actual_const = !src_info.mutable, 27508 .wanted_const = !dest_info.mutable, 27509 .actual_volatile = src_info.@"volatile", 27510 .wanted_volatile = dest_info.@"volatile", 27511 } }; 27512 } 27513 27514 if (dest_info.@"addrspace" != src_info.@"addrspace") { 27515 return InMemoryCoercionResult{ .ptr_addrspace = .{ 27516 .actual = src_info.@"addrspace", 27517 .wanted = dest_info.@"addrspace", 27518 } }; 27519 } 27520 27521 const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src); 27522 if (child != .ok) { 27523 return InMemoryCoercionResult{ .ptr_child = .{ 27524 .child = try child.dupe(sema.arena), 27525 .actual = src_info.pointee_type, 27526 .wanted = dest_info.pointee_type, 27527 } }; 27528 } 27529 27530 const dest_allow_zero = dest_ty.ptrAllowsZero(mod); 27531 const src_allow_zero = src_ty.ptrAllowsZero(mod); 27532 27533 const ok_allows_zero = (dest_allow_zero and 27534 (src_allow_zero or !dest_is_mut)) or 27535 (!dest_allow_zero and !src_allow_zero); 27536 if (!ok_allows_zero) { 27537 return InMemoryCoercionResult{ .ptr_allowzero = .{ 27538 .actual = src_ty, 27539 .wanted = dest_ty, 27540 } }; 27541 } 27542 27543 if (src_info.host_size != dest_info.host_size or 27544 src_info.bit_offset != dest_info.bit_offset) 27545 { 27546 return InMemoryCoercionResult{ .ptr_bit_range = .{ 27547 .actual_host = src_info.host_size, 27548 .wanted_host = dest_info.host_size, 27549 .actual_offset = src_info.bit_offset, 27550 .wanted_offset = dest_info.bit_offset, 27551 } }; 27552 } 27553 27554 const ok_sent = dest_info.sentinel == null or src_info.size == .C or 27555 (src_info.sentinel != null and 27556 dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod)); 27557 if (!ok_sent) { 27558 return InMemoryCoercionResult{ .ptr_sentinel = .{ 27559 .actual = src_info.sentinel orelse Value.@"unreachable", 27560 .wanted = dest_info.sentinel orelse Value.@"unreachable", 27561 .ty = dest_info.pointee_type, 27562 } }; 27563 } 27564 27565 // If both pointers have alignment 0, it means they both want ABI alignment. 27566 // In this case, if they share the same child type, no need to resolve 27567 // pointee type alignment. Otherwise both pointee types must have their alignment 27568 // resolved and we compare the alignment numerically. 27569 alignment: { 27570 if (src_info.@"align" == 0 and dest_info.@"align" == 0 and 27571 dest_info.pointee_type.eql(src_info.pointee_type, sema.mod)) 27572 { 27573 break :alignment; 27574 } 27575 27576 const src_align = if (src_info.@"align" != 0) 27577 src_info.@"align" 27578 else 27579 src_info.pointee_type.abiAlignment(mod); 27580 27581 const dest_align = if (dest_info.@"align" != 0) 27582 dest_info.@"align" 27583 else 27584 dest_info.pointee_type.abiAlignment(mod); 27585 27586 if (dest_align > src_align) { 27587 return InMemoryCoercionResult{ .ptr_alignment = .{ 27588 .actual = src_align, 27589 .wanted = dest_align, 27590 } }; 27591 } 27592 27593 break :alignment; 27594 } 27595 27596 return .ok; 27597 } 27598 27599 fn coerceVarArgParam( 27600 sema: *Sema, 27601 block: *Block, 27602 inst: Air.Inst.Ref, 27603 inst_src: LazySrcLoc, 27604 ) !Air.Inst.Ref { 27605 if (block.is_typeof) return inst; 27606 27607 const mod = sema.mod; 27608 const uncasted_ty = sema.typeOf(inst); 27609 const coerced = switch (uncasted_ty.zigTypeTag(mod)) { 27610 // TODO consider casting to c_int/f64 if they fit 27611 .ComptimeInt, .ComptimeFloat => return sema.fail( 27612 block, 27613 inst_src, 27614 "integer and float literals passed to variadic function must be casted to a fixed-size number type", 27615 .{}, 27616 ), 27617 .Fn => blk: { 27618 const fn_val = try sema.resolveConstValue(block, .unneeded, inst, ""); 27619 const fn_decl = fn_val.pointerDecl(mod).?; 27620 break :blk try sema.analyzeDeclRef(fn_decl); 27621 }, 27622 .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), 27623 .Float => float: { 27624 const target = sema.mod.getTarget(); 27625 const double_bits = target.c_type_bit_size(.double); 27626 const inst_bits = uncasted_ty.floatBits(sema.mod.getTarget()); 27627 if (inst_bits >= double_bits) break :float inst; 27628 switch (double_bits) { 27629 32 => break :float try sema.coerce(block, Type.f32, inst, inst_src), 27630 64 => break :float try sema.coerce(block, Type.f64, inst, inst_src), 27631 else => unreachable, 27632 } 27633 }, 27634 else => inst, 27635 }; 27636 27637 const coerced_ty = sema.typeOf(coerced); 27638 if (!try sema.validateExternType(coerced_ty, .param_ty)) { 27639 const msg = msg: { 27640 const msg = try sema.errMsg(block, inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(sema.mod)}); 27641 errdefer msg.destroy(sema.gpa); 27642 27643 const src_decl = sema.mod.declPtr(block.src_decl); 27644 try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl, mod), coerced_ty, .param_ty); 27645 27646 try sema.addDeclaredHereNote(msg, coerced_ty); 27647 break :msg msg; 27648 }; 27649 return sema.failWithOwnedErrorMsg(msg); 27650 } 27651 return coerced; 27652 } 27653 27654 // TODO migrate callsites to use storePtr2 instead. 27655 fn storePtr( 27656 sema: *Sema, 27657 block: *Block, 27658 src: LazySrcLoc, 27659 ptr: Air.Inst.Ref, 27660 uncasted_operand: Air.Inst.Ref, 27661 ) CompileError!void { 27662 const air_tag: Air.Inst.Tag = if (block.wantSafety()) .store_safe else .store; 27663 return sema.storePtr2(block, src, ptr, src, uncasted_operand, src, air_tag); 27664 } 27665 27666 fn storePtr2( 27667 sema: *Sema, 27668 block: *Block, 27669 src: LazySrcLoc, 27670 ptr: Air.Inst.Ref, 27671 ptr_src: LazySrcLoc, 27672 uncasted_operand: Air.Inst.Ref, 27673 operand_src: LazySrcLoc, 27674 air_tag: Air.Inst.Tag, 27675 ) CompileError!void { 27676 const mod = sema.mod; 27677 const ptr_ty = sema.typeOf(ptr); 27678 if (ptr_ty.isConstPtr(mod)) 27679 return sema.fail(block, ptr_src, "cannot assign to constant", .{}); 27680 27681 const elem_ty = ptr_ty.childType(mod); 27682 27683 // To generate better code for tuples, we detect a tuple operand here, and 27684 // analyze field loads and stores directly. This avoids an extra allocation + memcpy 27685 // which would occur if we used `coerce`. 27686 // However, we avoid this mechanism if the destination element type is a tuple, 27687 // because the regular store will be better for this case. 27688 // If the destination type is a struct we don't want this mechanism to trigger, because 27689 // this code does not handle tuple-to-struct coercion which requires dealing with missing 27690 // fields. 27691 const operand_ty = sema.typeOf(uncasted_operand); 27692 if (operand_ty.isTuple(mod) and elem_ty.zigTypeTag(mod) == .Array) { 27693 const field_count = operand_ty.structFieldCount(mod); 27694 var i: u32 = 0; 27695 while (i < field_count) : (i += 1) { 27696 const elem_src = operand_src; // TODO better source location 27697 const elem = try sema.tupleField(block, operand_src, uncasted_operand, elem_src, i); 27698 const elem_index = try sema.addIntUnsigned(Type.usize, i); 27699 const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src, false, true); 27700 try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store); 27701 } 27702 return; 27703 } 27704 27705 // TODO do the same thing for anon structs as for tuples above. 27706 // However, beware of the need to handle missing/extra fields. 27707 27708 const is_ret = air_tag == .ret_ptr; 27709 27710 // Detect if we are storing an array operand to a bitcasted vector pointer. 27711 // If so, we instead reach through the bitcasted pointer to the vector pointer, 27712 // bitcast the array operand to a vector, and then lower this as a store of 27713 // a vector value to a vector pointer. This generally results in better code, 27714 // as well as working around an LLVM bug: 27715 // https://github.com/ziglang/zig/issues/11154 27716 if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| { 27717 const vector_ty = sema.typeOf(vector_ptr).childType(mod); 27718 const vector = sema.coerceExtra(block, vector_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) { 27719 error.NotCoercible => unreachable, 27720 else => |e| return e, 27721 }; 27722 try sema.storePtr2(block, src, vector_ptr, ptr_src, vector, operand_src, .store); 27723 return; 27724 } 27725 27726 const operand = sema.coerceExtra(block, elem_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) { 27727 error.NotCoercible => unreachable, 27728 else => |e| return e, 27729 }; 27730 const maybe_operand_val = try sema.resolveMaybeUndefVal(operand); 27731 27732 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { 27733 const operand_val = maybe_operand_val orelse { 27734 try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); 27735 break :rs operand_src; 27736 }; 27737 if (ptr_val.isComptimeMutablePtr(mod)) { 27738 try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty); 27739 return; 27740 } else break :rs ptr_src; 27741 } else ptr_src; 27742 27743 // We do this after the possible comptime store above, for the case of field_ptr stores 27744 // to unions because we want the comptime tag to be set, even if the field type is void. 27745 if ((try sema.typeHasOnePossibleValue(elem_ty)) != null) 27746 return; 27747 27748 if (air_tag == .bitcast) { 27749 // `air_tag == .bitcast` is used as a special case for `zirCoerceResultPtr` 27750 // to avoid calling `requireRuntimeBlock` for the dummy block. 27751 _ = try block.addBinOp(.store, ptr, operand); 27752 return; 27753 } 27754 27755 try sema.requireRuntimeBlock(block, src, runtime_src); 27756 try sema.queueFullTypeResolution(elem_ty); 27757 27758 if (ptr_ty.ptrInfo(mod).vector_index == .runtime) { 27759 const ptr_inst = Air.refToIndex(ptr).?; 27760 const air_tags = sema.air_instructions.items(.tag); 27761 if (air_tags[ptr_inst] == .ptr_elem_ptr) { 27762 const ty_pl = sema.air_instructions.items(.data)[ptr_inst].ty_pl; 27763 const bin_op = sema.getTmpAir().extraData(Air.Bin, ty_pl.payload).data; 27764 _ = try block.addInst(.{ 27765 .tag = .vector_store_elem, 27766 .data = .{ .vector_store_elem = .{ 27767 .vector_ptr = bin_op.lhs, 27768 .payload = try block.sema.addExtra(Air.Bin{ 27769 .lhs = bin_op.rhs, 27770 .rhs = operand, 27771 }), 27772 } }, 27773 }); 27774 return; 27775 } 27776 return sema.fail(block, ptr_src, "unable to determine vector element index of type '{}'", .{ 27777 ptr_ty.fmt(sema.mod), 27778 }); 27779 } 27780 27781 if (is_ret) { 27782 _ = try block.addBinOp(.store, ptr, operand); 27783 } else { 27784 _ = try block.addBinOp(air_tag, ptr, operand); 27785 } 27786 } 27787 27788 /// Traverse an arbitrary number of bitcasted pointers and return the underyling vector 27789 /// pointer. Only if the final element type matches the vector element type, and the 27790 /// lengths match. 27791 fn obtainBitCastedVectorPtr(sema: *Sema, ptr: Air.Inst.Ref) ?Air.Inst.Ref { 27792 const mod = sema.mod; 27793 const array_ty = sema.typeOf(ptr).childType(mod); 27794 if (array_ty.zigTypeTag(mod) != .Array) return null; 27795 var ptr_ref = ptr; 27796 var ptr_inst = Air.refToIndex(ptr_ref) orelse return null; 27797 const air_datas = sema.air_instructions.items(.data); 27798 const air_tags = sema.air_instructions.items(.tag); 27799 const vector_ty = while (air_tags[ptr_inst] == .bitcast) { 27800 ptr_ref = air_datas[ptr_inst].ty_op.operand; 27801 if (!sema.isKnownZigType(ptr_ref, .Pointer)) return null; 27802 const child_ty = sema.typeOf(ptr_ref).childType(mod); 27803 if (child_ty.zigTypeTag(mod) == .Vector) break child_ty; 27804 ptr_inst = Air.refToIndex(ptr_ref) orelse return null; 27805 } else return null; 27806 27807 // We have a pointer-to-array and a pointer-to-vector. If the elements and 27808 // lengths match, return the result. 27809 if (array_ty.childType(mod).eql(vector_ty.childType(mod), sema.mod) and 27810 array_ty.arrayLen(mod) == vector_ty.vectorLen(mod)) 27811 { 27812 return ptr_ref; 27813 } else { 27814 return null; 27815 } 27816 } 27817 27818 /// Call when you have Value objects rather than Air instructions, and you want to 27819 /// assert the store must be done at comptime. 27820 fn storePtrVal( 27821 sema: *Sema, 27822 block: *Block, 27823 src: LazySrcLoc, 27824 ptr_val: Value, 27825 operand_val: Value, 27826 operand_ty: Type, 27827 ) !void { 27828 const mod = sema.mod; 27829 var mut_kit = try sema.beginComptimePtrMutation(block, src, ptr_val, operand_ty); 27830 try sema.checkComptimeVarStore(block, src, mut_kit.mut_decl); 27831 27832 switch (mut_kit.pointee) { 27833 .direct => |val_ptr| { 27834 if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) { 27835 if (!operand_val.eql(val_ptr.*, operand_ty, mod)) { 27836 // TODO use failWithInvalidComptimeFieldStore 27837 return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{}); 27838 } 27839 return; 27840 } 27841 val_ptr.* = (try operand_val.intern(operand_ty, mod)).toValue(); 27842 }, 27843 .reinterpret => |reinterpret| { 27844 const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod)); 27845 const buffer = try sema.gpa.alloc(u8, abi_size); 27846 defer sema.gpa.free(buffer); 27847 reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, mod, buffer) catch |err| switch (err) { 27848 error.OutOfMemory => return error.OutOfMemory, 27849 error.ReinterpretDeclRef => unreachable, 27850 error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already 27851 error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(mod)}), 27852 }; 27853 operand_val.writeToMemory(operand_ty, mod, buffer[reinterpret.byte_offset..]) catch |err| switch (err) { 27854 error.OutOfMemory => return error.OutOfMemory, 27855 error.ReinterpretDeclRef => unreachable, 27856 error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already 27857 error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(mod)}), 27858 }; 27859 27860 const arena = mut_kit.beginArena(mod); 27861 defer mut_kit.finishArena(mod); 27862 27863 reinterpret.val_ptr.* = (try (try Value.readFromMemory(mut_kit.ty, mod, buffer, arena)).intern(mut_kit.ty, mod)).toValue(); 27864 }, 27865 .bad_decl_ty, .bad_ptr_ty => { 27866 // TODO show the decl declaration site in a note and explain whether the decl 27867 // or the pointer is the problematic type 27868 return sema.fail(block, src, "comptime mutation of a reinterpreted pointer requires type '{}' to have a well-defined memory layout", .{mut_kit.ty.fmt(mod)}); 27869 }, 27870 } 27871 } 27872 27873 const ComptimePtrMutationKit = struct { 27874 mut_decl: InternPool.Key.Ptr.Addr.MutDecl, 27875 pointee: union(enum) { 27876 /// The pointer type matches the actual comptime Value so a direct 27877 /// modification is possible. 27878 direct: *Value, 27879 /// The largest parent Value containing pointee and having a well-defined memory layout. 27880 /// This is used for bitcasting, if direct dereferencing failed. 27881 reinterpret: struct { 27882 val_ptr: *Value, 27883 byte_offset: usize, 27884 }, 27885 /// If the root decl could not be used as parent, this means `ty` is the type that 27886 /// caused that by not having a well-defined layout. 27887 /// This one means the Decl that owns the value trying to be modified does not 27888 /// have a well defined memory layout. 27889 bad_decl_ty, 27890 /// If the root decl could not be used as parent, this means `ty` is the type that 27891 /// caused that by not having a well-defined layout. 27892 /// This one means the pointer type that is being stored through does not 27893 /// have a well defined memory layout. 27894 bad_ptr_ty, 27895 }, 27896 ty: Type, 27897 decl_arena: std.heap.ArenaAllocator = undefined, 27898 27899 fn beginArena(self: *ComptimePtrMutationKit, mod: *Module) Allocator { 27900 const decl = mod.declPtr(self.mut_decl.decl); 27901 return decl.value_arena.?.acquire(mod.gpa, &self.decl_arena); 27902 } 27903 27904 fn finishArena(self: *ComptimePtrMutationKit, mod: *Module) void { 27905 const decl = mod.declPtr(self.mut_decl.decl); 27906 decl.value_arena.?.release(&self.decl_arena); 27907 self.decl_arena = undefined; 27908 } 27909 }; 27910 27911 fn beginComptimePtrMutation( 27912 sema: *Sema, 27913 block: *Block, 27914 src: LazySrcLoc, 27915 ptr_val: Value, 27916 ptr_elem_ty: Type, 27917 ) CompileError!ComptimePtrMutationKit { 27918 const mod = sema.mod; 27919 const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr; 27920 switch (ptr.addr) { 27921 .decl, .int => unreachable, // isComptimeMutablePtr has been checked already 27922 .mut_decl => |mut_decl| { 27923 const decl = mod.declPtr(mut_decl.decl); 27924 return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl); 27925 }, 27926 .comptime_field => |comptime_field| { 27927 const duped = try sema.arena.create(Value); 27928 duped.* = comptime_field.toValue(); 27929 return sema.beginComptimePtrMutationInner(block, src, mod.intern_pool.typeOf(comptime_field).toType(), duped, ptr_elem_ty, .{ 27930 .decl = undefined, 27931 .runtime_index = .comptime_field_ptr, 27932 }); 27933 }, 27934 .eu_payload => |eu_ptr| { 27935 const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod); 27936 var parent = try sema.beginComptimePtrMutation(block, src, eu_ptr.toValue(), eu_ty); 27937 switch (parent.pointee) { 27938 .direct => |val_ptr| { 27939 const payload_ty = parent.ty.errorUnionPayload(mod); 27940 if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) { 27941 return ComptimePtrMutationKit{ 27942 .mut_decl = parent.mut_decl, 27943 .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data }, 27944 .ty = payload_ty, 27945 }; 27946 } else { 27947 // An error union has been initialized to undefined at comptime and now we 27948 // are for the first time setting the payload. We must change the 27949 // representation of the error union from `undef` to `opt_payload`. 27950 const arena = parent.beginArena(sema.mod); 27951 defer parent.finishArena(sema.mod); 27952 27953 const payload = try arena.create(Value.Payload.SubValue); 27954 payload.* = .{ 27955 .base = .{ .tag = .eu_payload }, 27956 .data = (try mod.intern(.{ .undef = payload_ty.toIntern() })).toValue(), 27957 }; 27958 27959 val_ptr.* = Value.initPayload(&payload.base); 27960 27961 return ComptimePtrMutationKit{ 27962 .mut_decl = parent.mut_decl, 27963 .pointee = .{ .direct = &payload.data }, 27964 .ty = payload_ty, 27965 }; 27966 } 27967 }, 27968 .bad_decl_ty, .bad_ptr_ty => return parent, 27969 // Even though the parent value type has well-defined memory layout, our 27970 // pointer type does not. 27971 .reinterpret => return ComptimePtrMutationKit{ 27972 .mut_decl = parent.mut_decl, 27973 .pointee = .bad_ptr_ty, 27974 .ty = eu_ty, 27975 }, 27976 } 27977 }, 27978 .opt_payload => |opt_ptr| { 27979 const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod); 27980 var parent = try sema.beginComptimePtrMutation(block, src, opt_ptr.toValue(), opt_ty); 27981 switch (parent.pointee) { 27982 .direct => |val_ptr| { 27983 const payload_ty = parent.ty.optionalChild(mod); 27984 switch (val_ptr.ip_index) { 27985 .none => return ComptimePtrMutationKit{ 27986 .mut_decl = parent.mut_decl, 27987 .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data }, 27988 .ty = payload_ty, 27989 }, 27990 else => { 27991 const payload_val = switch (mod.intern_pool.indexToKey(val_ptr.ip_index)) { 27992 .undef => try mod.intern(.{ .undef = payload_ty.toIntern() }), 27993 .opt => |opt| switch (opt.val) { 27994 .none => try mod.intern(.{ .undef = payload_ty.toIntern() }), 27995 else => |payload| payload, 27996 }, 27997 else => unreachable, 27998 }; 27999 28000 // An optional has been initialized to undefined at comptime and now we 28001 // are for the first time setting the payload. We must change the 28002 // representation of the optional from `undef` to `opt_payload`. 28003 const arena = parent.beginArena(sema.mod); 28004 defer parent.finishArena(sema.mod); 28005 28006 const payload = try arena.create(Value.Payload.SubValue); 28007 payload.* = .{ 28008 .base = .{ .tag = .opt_payload }, 28009 .data = payload_val.toValue(), 28010 }; 28011 28012 val_ptr.* = Value.initPayload(&payload.base); 28013 28014 return ComptimePtrMutationKit{ 28015 .mut_decl = parent.mut_decl, 28016 .pointee = .{ .direct = &payload.data }, 28017 .ty = payload_ty, 28018 }; 28019 }, 28020 } 28021 }, 28022 .bad_decl_ty, .bad_ptr_ty => return parent, 28023 // Even though the parent value type has well-defined memory layout, our 28024 // pointer type does not. 28025 .reinterpret => return ComptimePtrMutationKit{ 28026 .mut_decl = parent.mut_decl, 28027 .pointee = .bad_ptr_ty, 28028 .ty = opt_ty, 28029 }, 28030 } 28031 }, 28032 .elem => |elem_ptr| { 28033 const base_elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod); 28034 var parent = try sema.beginComptimePtrMutation(block, src, elem_ptr.base.toValue(), base_elem_ty); 28035 28036 switch (parent.pointee) { 28037 .direct => |val_ptr| switch (parent.ty.zigTypeTag(mod)) { 28038 .Array, .Vector => { 28039 const check_len = parent.ty.arrayLenIncludingSentinel(mod); 28040 if (elem_ptr.index >= check_len) { 28041 // TODO have the parent include the decl so we can say "declared here" 28042 return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{ 28043 elem_ptr.index, check_len, 28044 }); 28045 } 28046 const elem_ty = parent.ty.childType(mod); 28047 28048 // We might have a pointer to multiple elements of the array (e.g. a pointer 28049 // to a sub-array). In this case, we just have to reinterpret the relevant 28050 // bytes of the whole array rather than any single element. 28051 const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty); 28052 if (elem_abi_size_u64 < try sema.typeAbiSize(ptr_elem_ty)) { 28053 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); 28054 return .{ 28055 .mut_decl = parent.mut_decl, 28056 .pointee = .{ .reinterpret = .{ 28057 .val_ptr = val_ptr, 28058 .byte_offset = elem_abi_size * elem_ptr.index, 28059 } }, 28060 .ty = parent.ty, 28061 }; 28062 } 28063 28064 switch (val_ptr.ip_index) { 28065 .none => switch (val_ptr.tag()) { 28066 .bytes => { 28067 // An array is memory-optimized to store a slice of bytes, but we are about 28068 // to modify an individual field and the representation has to change. 28069 // If we wanted to avoid this, there would need to be special detection 28070 // elsewhere to identify when writing a value to an array element that is stored 28071 // using the `bytes` tag, and handle it without making a call to this function. 28072 const arena = parent.beginArena(sema.mod); 28073 defer parent.finishArena(sema.mod); 28074 28075 const bytes = val_ptr.castTag(.bytes).?.data; 28076 const dest_len = parent.ty.arrayLenIncludingSentinel(mod); 28077 // bytes.len may be one greater than dest_len because of the case when 28078 // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. 28079 assert(bytes.len >= dest_len); 28080 const elems = try arena.alloc(Value, @intCast(usize, dest_len)); 28081 for (elems, 0..) |*elem, i| { 28082 elem.* = try mod.intValue(elem_ty, bytes[i]); 28083 } 28084 28085 val_ptr.* = try Value.Tag.aggregate.create(arena, elems); 28086 28087 return beginComptimePtrMutationInner( 28088 sema, 28089 block, 28090 src, 28091 elem_ty, 28092 &elems[elem_ptr.index], 28093 ptr_elem_ty, 28094 parent.mut_decl, 28095 ); 28096 }, 28097 .repeated => { 28098 // An array is memory-optimized to store only a single element value, and 28099 // that value is understood to be the same for the entire length of the array. 28100 // However, now we want to modify an individual field and so the 28101 // representation has to change. If we wanted to avoid this, there would 28102 // need to be special detection elsewhere to identify when writing a value to an 28103 // array element that is stored using the `repeated` tag, and handle it 28104 // without making a call to this function. 28105 const arena = parent.beginArena(sema.mod); 28106 defer parent.finishArena(sema.mod); 28107 28108 const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena); 28109 const array_len_including_sentinel = 28110 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); 28111 const elems = try arena.alloc(Value, array_len_including_sentinel); 28112 if (elems.len > 0) elems[0] = repeated_val; 28113 for (elems[1..]) |*elem| { 28114 elem.* = try repeated_val.copy(arena); 28115 } 28116 28117 val_ptr.* = try Value.Tag.aggregate.create(arena, elems); 28118 28119 return beginComptimePtrMutationInner( 28120 sema, 28121 block, 28122 src, 28123 elem_ty, 28124 &elems[elem_ptr.index], 28125 ptr_elem_ty, 28126 parent.mut_decl, 28127 ); 28128 }, 28129 28130 .aggregate => return beginComptimePtrMutationInner( 28131 sema, 28132 block, 28133 src, 28134 elem_ty, 28135 &val_ptr.castTag(.aggregate).?.data[elem_ptr.index], 28136 ptr_elem_ty, 28137 parent.mut_decl, 28138 ), 28139 28140 else => unreachable, 28141 }, 28142 else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) { 28143 .undef => { 28144 // An array has been initialized to undefined at comptime and now we 28145 // are for the first time setting an element. We must change the representation 28146 // of the array from `undef` to `array`. 28147 const arena = parent.beginArena(sema.mod); 28148 defer parent.finishArena(sema.mod); 28149 28150 const array_len_including_sentinel = 28151 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); 28152 const elems = try arena.alloc(Value, array_len_including_sentinel); 28153 @memset(elems, (try mod.intern(.{ .undef = elem_ty.toIntern() })).toValue()); 28154 28155 val_ptr.* = try Value.Tag.aggregate.create(arena, elems); 28156 28157 return beginComptimePtrMutationInner( 28158 sema, 28159 block, 28160 src, 28161 elem_ty, 28162 &elems[elem_ptr.index], 28163 ptr_elem_ty, 28164 parent.mut_decl, 28165 ); 28166 }, 28167 else => unreachable, 28168 }, 28169 } 28170 }, 28171 else => { 28172 if (elem_ptr.index != 0) { 28173 // TODO include a "declared here" note for the decl 28174 return sema.fail(block, src, "out of bounds comptime store of index {d}", .{ 28175 elem_ptr.index, 28176 }); 28177 } 28178 return beginComptimePtrMutationInner( 28179 sema, 28180 block, 28181 src, 28182 parent.ty, 28183 val_ptr, 28184 ptr_elem_ty, 28185 parent.mut_decl, 28186 ); 28187 }, 28188 }, 28189 .reinterpret => |reinterpret| { 28190 if (!base_elem_ty.hasWellDefinedLayout(mod)) { 28191 // Even though the parent value type has well-defined memory layout, our 28192 // pointer type does not. 28193 return ComptimePtrMutationKit{ 28194 .mut_decl = parent.mut_decl, 28195 .pointee = .bad_ptr_ty, 28196 .ty = base_elem_ty, 28197 }; 28198 } 28199 28200 const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty); 28201 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); 28202 return ComptimePtrMutationKit{ 28203 .mut_decl = parent.mut_decl, 28204 .pointee = .{ .reinterpret = .{ 28205 .val_ptr = reinterpret.val_ptr, 28206 .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_ptr.index, 28207 } }, 28208 .ty = parent.ty, 28209 }; 28210 }, 28211 .bad_decl_ty, .bad_ptr_ty => return parent, 28212 } 28213 }, 28214 .field => |field_ptr| { 28215 const base_child_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); 28216 const field_index = @intCast(u32, field_ptr.index); 28217 28218 var parent = try sema.beginComptimePtrMutation(block, src, field_ptr.base.toValue(), base_child_ty); 28219 switch (parent.pointee) { 28220 .direct => |val_ptr| switch (val_ptr.ip_index) { 28221 .empty_struct => { 28222 const duped = try sema.arena.create(Value); 28223 duped.* = val_ptr.*; 28224 return beginComptimePtrMutationInner( 28225 sema, 28226 block, 28227 src, 28228 parent.ty.structFieldType(field_index, mod), 28229 duped, 28230 ptr_elem_ty, 28231 parent.mut_decl, 28232 ); 28233 }, 28234 .none => switch (val_ptr.tag()) { 28235 .aggregate => return beginComptimePtrMutationInner( 28236 sema, 28237 block, 28238 src, 28239 parent.ty.structFieldType(field_index, mod), 28240 &val_ptr.castTag(.aggregate).?.data[field_index], 28241 ptr_elem_ty, 28242 parent.mut_decl, 28243 ), 28244 .repeated => { 28245 const arena = parent.beginArena(sema.mod); 28246 defer parent.finishArena(sema.mod); 28247 28248 const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod)); 28249 @memset(elems, val_ptr.castTag(.repeated).?.data); 28250 val_ptr.* = try Value.Tag.aggregate.create(arena, elems); 28251 28252 return beginComptimePtrMutationInner( 28253 sema, 28254 block, 28255 src, 28256 parent.ty.structFieldType(field_index, mod), 28257 &elems[field_index], 28258 ptr_elem_ty, 28259 parent.mut_decl, 28260 ); 28261 }, 28262 .@"union" => { 28263 // We need to set the active field of the union. 28264 const union_tag_ty = base_child_ty.unionTagTypeHypothetical(mod); 28265 28266 const payload = &val_ptr.castTag(.@"union").?.data; 28267 payload.tag = try mod.enumValueFieldIndex(union_tag_ty, field_index); 28268 28269 return beginComptimePtrMutationInner( 28270 sema, 28271 block, 28272 src, 28273 parent.ty.structFieldType(field_index, mod), 28274 &payload.val, 28275 ptr_elem_ty, 28276 parent.mut_decl, 28277 ); 28278 }, 28279 .slice => switch (field_index) { 28280 Value.slice_ptr_index => return beginComptimePtrMutationInner( 28281 sema, 28282 block, 28283 src, 28284 parent.ty.slicePtrFieldType(mod), 28285 &val_ptr.castTag(.slice).?.data.ptr, 28286 ptr_elem_ty, 28287 parent.mut_decl, 28288 ), 28289 28290 Value.slice_len_index => return beginComptimePtrMutationInner( 28291 sema, 28292 block, 28293 src, 28294 Type.usize, 28295 &val_ptr.castTag(.slice).?.data.len, 28296 ptr_elem_ty, 28297 parent.mut_decl, 28298 ), 28299 28300 else => unreachable, 28301 }, 28302 else => unreachable, 28303 }, 28304 else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) { 28305 .undef => { 28306 // A struct or union has been initialized to undefined at comptime and now we 28307 // are for the first time setting a field. We must change the representation 28308 // of the struct/union from `undef` to `struct`/`union`. 28309 const arena = parent.beginArena(sema.mod); 28310 defer parent.finishArena(sema.mod); 28311 28312 switch (parent.ty.zigTypeTag(mod)) { 28313 .Struct => { 28314 const fields = try arena.alloc(Value, parent.ty.structFieldCount(mod)); 28315 for (fields, 0..) |*field, i| field.* = (try mod.intern(.{ 28316 .undef = parent.ty.structFieldType(i, mod).toIntern(), 28317 })).toValue(); 28318 28319 val_ptr.* = try Value.Tag.aggregate.create(arena, fields); 28320 28321 return beginComptimePtrMutationInner( 28322 sema, 28323 block, 28324 src, 28325 parent.ty.structFieldType(field_index, mod), 28326 &fields[field_index], 28327 ptr_elem_ty, 28328 parent.mut_decl, 28329 ); 28330 }, 28331 .Union => { 28332 const payload = try arena.create(Value.Payload.Union); 28333 const tag_ty = parent.ty.unionTagTypeHypothetical(mod); 28334 const payload_ty = parent.ty.structFieldType(field_index, mod); 28335 payload.* = .{ .data = .{ 28336 .tag = try mod.enumValueFieldIndex(tag_ty, field_index), 28337 .val = (try mod.intern(.{ .undef = payload_ty.toIntern() })).toValue(), 28338 } }; 28339 28340 val_ptr.* = Value.initPayload(&payload.base); 28341 28342 return beginComptimePtrMutationInner( 28343 sema, 28344 block, 28345 src, 28346 payload_ty, 28347 &payload.data.val, 28348 ptr_elem_ty, 28349 parent.mut_decl, 28350 ); 28351 }, 28352 .Pointer => { 28353 assert(parent.ty.isSlice(mod)); 28354 const ptr_ty = parent.ty.slicePtrFieldType(mod); 28355 val_ptr.* = try Value.Tag.slice.create(arena, .{ 28356 .ptr = (try mod.intern(.{ .undef = ptr_ty.toIntern() })).toValue(), 28357 .len = (try mod.intern(.{ .undef = .usize_type })).toValue(), 28358 }); 28359 28360 switch (field_index) { 28361 Value.slice_ptr_index => return beginComptimePtrMutationInner( 28362 sema, 28363 block, 28364 src, 28365 ptr_ty, 28366 &val_ptr.castTag(.slice).?.data.ptr, 28367 ptr_elem_ty, 28368 parent.mut_decl, 28369 ), 28370 Value.slice_len_index => return beginComptimePtrMutationInner( 28371 sema, 28372 block, 28373 src, 28374 Type.usize, 28375 &val_ptr.castTag(.slice).?.data.len, 28376 ptr_elem_ty, 28377 parent.mut_decl, 28378 ), 28379 28380 else => unreachable, 28381 } 28382 }, 28383 else => unreachable, 28384 } 28385 }, 28386 else => unreachable, 28387 }, 28388 }, 28389 .reinterpret => |reinterpret| { 28390 const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod); 28391 const field_offset = try sema.usizeCast(block, src, field_offset_u64); 28392 return ComptimePtrMutationKit{ 28393 .mut_decl = parent.mut_decl, 28394 .pointee = .{ .reinterpret = .{ 28395 .val_ptr = reinterpret.val_ptr, 28396 .byte_offset = reinterpret.byte_offset + field_offset, 28397 } }, 28398 .ty = parent.ty, 28399 }; 28400 }, 28401 .bad_decl_ty, .bad_ptr_ty => return parent, 28402 } 28403 }, 28404 } 28405 } 28406 28407 fn beginComptimePtrMutationInner( 28408 sema: *Sema, 28409 block: *Block, 28410 src: LazySrcLoc, 28411 decl_ty: Type, 28412 decl_val: *Value, 28413 ptr_elem_ty: Type, 28414 mut_decl: InternPool.Key.Ptr.Addr.MutDecl, 28415 ) CompileError!ComptimePtrMutationKit { 28416 const mod = sema.mod; 28417 const target = mod.getTarget(); 28418 const coerce_ok = (try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_ty, true, target, src, src)) == .ok; 28419 28420 const decl = mod.declPtr(mut_decl.decl); 28421 var decl_arena: std.heap.ArenaAllocator = undefined; 28422 const allocator = decl.value_arena.?.acquire(sema.gpa, &decl_arena); 28423 defer decl.value_arena.?.release(&decl_arena); 28424 decl_val.* = try decl_val.unintern(allocator, mod); 28425 28426 if (coerce_ok) { 28427 return ComptimePtrMutationKit{ 28428 .mut_decl = mut_decl, 28429 .pointee = .{ .direct = decl_val }, 28430 .ty = decl_ty, 28431 }; 28432 } 28433 28434 // Handle the case that the decl is an array and we're actually trying to point to an element. 28435 if (decl_ty.isArrayOrVector(mod)) { 28436 const decl_elem_ty = decl_ty.childType(mod); 28437 if ((try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_elem_ty, true, target, src, src)) == .ok) { 28438 return ComptimePtrMutationKit{ 28439 .mut_decl = mut_decl, 28440 .pointee = .{ .direct = decl_val }, 28441 .ty = decl_ty, 28442 }; 28443 } 28444 } 28445 28446 if (!decl_ty.hasWellDefinedLayout(mod)) { 28447 return ComptimePtrMutationKit{ 28448 .mut_decl = mut_decl, 28449 .pointee = .bad_decl_ty, 28450 .ty = decl_ty, 28451 }; 28452 } 28453 if (!ptr_elem_ty.hasWellDefinedLayout(mod)) { 28454 return ComptimePtrMutationKit{ 28455 .mut_decl = mut_decl, 28456 .pointee = .bad_ptr_ty, 28457 .ty = ptr_elem_ty, 28458 }; 28459 } 28460 return ComptimePtrMutationKit{ 28461 .mut_decl = mut_decl, 28462 .pointee = .{ .reinterpret = .{ 28463 .val_ptr = decl_val, 28464 .byte_offset = 0, 28465 } }, 28466 .ty = decl_ty, 28467 }; 28468 } 28469 28470 const TypedValueAndOffset = struct { 28471 tv: TypedValue, 28472 byte_offset: usize, 28473 }; 28474 28475 const ComptimePtrLoadKit = struct { 28476 /// The Value and Type corresponding to the pointee of the provided pointer. 28477 /// If a direct dereference is not possible, this is null. 28478 pointee: ?TypedValue, 28479 /// The largest parent Value containing `pointee` and having a well-defined memory layout. 28480 /// This is used for bitcasting, if direct dereferencing failed (i.e. `pointee` is null). 28481 parent: ?TypedValueAndOffset, 28482 /// Whether the `pointee` could be mutated by further 28483 /// semantic analysis and a copy must be performed. 28484 is_mutable: bool, 28485 /// If the root decl could not be used as `parent`, this is the type that 28486 /// caused that by not having a well-defined layout 28487 ty_without_well_defined_layout: ?Type, 28488 }; 28489 28490 const ComptimePtrLoadError = CompileError || error{ 28491 RuntimeLoad, 28492 }; 28493 28494 /// If `maybe_array_ty` is provided, it will be used to directly dereference an 28495 /// .elem_ptr of type T to a value of [N]T, if necessary. 28496 fn beginComptimePtrLoad( 28497 sema: *Sema, 28498 block: *Block, 28499 src: LazySrcLoc, 28500 ptr_val: Value, 28501 maybe_array_ty: ?Type, 28502 ) ComptimePtrLoadError!ComptimePtrLoadKit { 28503 const mod = sema.mod; 28504 const target = mod.getTarget(); 28505 28506 var deref: ComptimePtrLoadKit = switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) { 28507 .ptr => |ptr| switch (ptr.addr) { 28508 .decl, .mut_decl => blk: { 28509 const decl_index = switch (ptr.addr) { 28510 .decl => |decl| decl, 28511 .mut_decl => |mut_decl| mut_decl.decl, 28512 else => unreachable, 28513 }; 28514 const is_mutable = ptr.addr == .mut_decl; 28515 const decl = mod.declPtr(decl_index); 28516 const decl_tv = try decl.typedValue(); 28517 if (decl.val.getVariable(mod) != null) return error.RuntimeLoad; 28518 28519 const layout_defined = decl.ty.hasWellDefinedLayout(mod); 28520 break :blk ComptimePtrLoadKit{ 28521 .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, 28522 .pointee = decl_tv, 28523 .is_mutable = is_mutable, 28524 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, 28525 }; 28526 }, 28527 .int => return error.RuntimeLoad, 28528 .eu_payload, .opt_payload => |container_ptr| blk: { 28529 const container_ty = mod.intern_pool.typeOf(container_ptr).toType().childType(mod); 28530 const payload_ty = switch (ptr.addr) { 28531 .eu_payload => container_ty.errorUnionPayload(mod), 28532 .opt_payload => container_ty.optionalChild(mod), 28533 else => unreachable, 28534 }; 28535 var deref = try sema.beginComptimePtrLoad(block, src, container_ptr.toValue(), container_ty); 28536 28537 // eu_payload and opt_payload never have a well-defined layout 28538 if (deref.parent != null) { 28539 deref.parent = null; 28540 deref.ty_without_well_defined_layout = container_ty; 28541 } 28542 28543 if (deref.pointee) |*tv| { 28544 const coerce_in_mem_ok = 28545 (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or 28546 (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; 28547 if (coerce_in_mem_ok) { 28548 const payload_val = switch (tv.val.ip_index) { 28549 .none => tv.val.cast(Value.Payload.SubValue).?.data, 28550 .null_value => return sema.fail(block, src, "attempt to use null value", .{}), 28551 else => switch (mod.intern_pool.indexToKey(tv.val.toIntern())) { 28552 .error_union => |error_union| switch (error_union.val) { 28553 .err_name => |err_name| return sema.fail(block, src, "attempt to unwrap error: {s}", .{mod.intern_pool.stringToSlice(err_name)}), 28554 .payload => |payload| payload, 28555 }, 28556 .opt => |opt| switch (opt.val) { 28557 .none => return sema.fail(block, src, "attempt to use null value", .{}), 28558 else => |payload| payload, 28559 }, 28560 else => unreachable, 28561 }.toValue(), 28562 }; 28563 tv.* = TypedValue{ .ty = payload_ty, .val = payload_val }; 28564 break :blk deref; 28565 } 28566 } 28567 deref.pointee = null; 28568 break :blk deref; 28569 }, 28570 .comptime_field => |comptime_field| blk: { 28571 const field_ty = mod.intern_pool.typeOf(comptime_field).toType(); 28572 break :blk ComptimePtrLoadKit{ 28573 .parent = null, 28574 .pointee = .{ .ty = field_ty, .val = comptime_field.toValue() }, 28575 .is_mutable = false, 28576 .ty_without_well_defined_layout = field_ty, 28577 }; 28578 }, 28579 .elem => |elem_ptr| blk: { 28580 const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod); 28581 var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.base.toValue(), null); 28582 28583 // This code assumes that elem_ptrs have been "flattened" in order for direct dereference 28584 // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that 28585 // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened" 28586 switch (mod.intern_pool.indexToKey(elem_ptr.base)) { 28587 .ptr => |base_ptr| switch (base_ptr.addr) { 28588 .elem => |base_elem| assert(!mod.intern_pool.typeOf(base_elem.base).toType().elemType2(mod).eql(elem_ty, mod)), 28589 else => {}, 28590 }, 28591 else => {}, 28592 } 28593 28594 if (elem_ptr.index != 0) { 28595 if (elem_ty.hasWellDefinedLayout(mod)) { 28596 if (deref.parent) |*parent| { 28597 // Update the byte offset (in-place) 28598 const elem_size = try sema.typeAbiSize(elem_ty); 28599 const offset = parent.byte_offset + elem_size * elem_ptr.index; 28600 parent.byte_offset = try sema.usizeCast(block, src, offset); 28601 } 28602 } else { 28603 deref.parent = null; 28604 deref.ty_without_well_defined_layout = elem_ty; 28605 } 28606 } 28607 28608 // If we're loading an elem that was derived from a different type 28609 // than the true type of the underlying decl, we cannot deref directly 28610 const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector(mod)) x: { 28611 const deref_elem_ty = deref.pointee.?.ty.childType(mod); 28612 break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or 28613 (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok; 28614 } else false; 28615 if (!ty_matches) { 28616 deref.pointee = null; 28617 break :blk deref; 28618 } 28619 28620 var array_tv = deref.pointee.?; 28621 const check_len = array_tv.ty.arrayLenIncludingSentinel(mod); 28622 if (maybe_array_ty) |load_ty| { 28623 // It's possible that we're loading a [N]T, in which case we'd like to slice 28624 // the pointee array directly from our parent array. 28625 if (load_ty.isArrayOrVector(mod) and load_ty.childType(mod).eql(elem_ty, mod)) { 28626 const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel(mod)); 28627 deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{ 28628 .ty = try Type.array(sema.arena, N, null, elem_ty, mod), 28629 .val = try array_tv.val.sliceArray(mod, sema.arena, elem_ptr.index, elem_ptr.index + N), 28630 } else null; 28631 break :blk deref; 28632 } 28633 } 28634 28635 if (elem_ptr.index >= check_len) { 28636 deref.pointee = null; 28637 break :blk deref; 28638 } 28639 if (elem_ptr.index == check_len - 1) { 28640 if (array_tv.ty.sentinel(mod)) |sent| { 28641 deref.pointee = TypedValue{ 28642 .ty = elem_ty, 28643 .val = sent, 28644 }; 28645 break :blk deref; 28646 } 28647 } 28648 deref.pointee = TypedValue{ 28649 .ty = elem_ty, 28650 .val = try array_tv.val.elemValue(mod, elem_ptr.index), 28651 }; 28652 break :blk deref; 28653 }, 28654 .field => |field_ptr| blk: { 28655 const field_index = @intCast(u32, field_ptr.index); 28656 const container_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); 28657 var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.base.toValue(), container_ty); 28658 28659 if (container_ty.hasWellDefinedLayout(mod)) { 28660 const struct_obj = mod.typeToStruct(container_ty); 28661 if (struct_obj != null and struct_obj.?.layout == .Packed) { 28662 // packed structs are not byte addressable 28663 deref.parent = null; 28664 } else if (deref.parent) |*parent| { 28665 // Update the byte offset (in-place) 28666 try sema.resolveTypeLayout(container_ty); 28667 const field_offset = container_ty.structFieldOffset(field_index, mod); 28668 parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset); 28669 } 28670 } else { 28671 deref.parent = null; 28672 deref.ty_without_well_defined_layout = container_ty; 28673 } 28674 28675 const tv = deref.pointee orelse { 28676 deref.pointee = null; 28677 break :blk deref; 28678 }; 28679 const coerce_in_mem_ok = 28680 (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or 28681 (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; 28682 if (!coerce_in_mem_ok) { 28683 deref.pointee = null; 28684 break :blk deref; 28685 } 28686 28687 if (container_ty.isSlice(mod)) { 28688 deref.pointee = switch (field_index) { 28689 Value.slice_ptr_index => TypedValue{ 28690 .ty = container_ty.slicePtrFieldType(mod), 28691 .val = tv.val.slicePtr(mod), 28692 }, 28693 Value.slice_len_index => TypedValue{ 28694 .ty = Type.usize, 28695 .val = mod.intern_pool.indexToKey(tv.val.toIntern()).ptr.len.toValue(), 28696 }, 28697 else => unreachable, 28698 }; 28699 } else { 28700 const field_ty = container_ty.structFieldType(field_index, mod); 28701 deref.pointee = TypedValue{ 28702 .ty = field_ty, 28703 .val = try tv.val.fieldValue(mod, field_index), 28704 }; 28705 } 28706 break :blk deref; 28707 }, 28708 }, 28709 .opt => |opt| switch (opt.val) { 28710 .none => return sema.fail(block, src, "attempt to use null value", .{}), 28711 else => |payload| try sema.beginComptimePtrLoad(block, src, payload.toValue(), null), 28712 }, 28713 else => unreachable, 28714 }; 28715 28716 if (deref.pointee) |tv| { 28717 if (deref.parent == null and tv.ty.hasWellDefinedLayout(mod)) { 28718 deref.parent = .{ .tv = tv, .byte_offset = 0 }; 28719 } 28720 } 28721 return deref; 28722 } 28723 28724 fn bitCast( 28725 sema: *Sema, 28726 block: *Block, 28727 dest_ty_unresolved: Type, 28728 inst: Air.Inst.Ref, 28729 inst_src: LazySrcLoc, 28730 operand_src: ?LazySrcLoc, 28731 ) CompileError!Air.Inst.Ref { 28732 const mod = sema.mod; 28733 const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved); 28734 try sema.resolveTypeLayout(dest_ty); 28735 28736 const old_ty = try sema.resolveTypeFields(sema.typeOf(inst)); 28737 try sema.resolveTypeLayout(old_ty); 28738 28739 const dest_bits = dest_ty.bitSize(mod); 28740 const old_bits = old_ty.bitSize(mod); 28741 28742 if (old_bits != dest_bits) { 28743 return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{}' has {d} bits but source type '{}' has {d} bits", .{ 28744 dest_ty.fmt(mod), 28745 dest_bits, 28746 old_ty.fmt(mod), 28747 old_bits, 28748 }); 28749 } 28750 28751 if (try sema.resolveMaybeUndefVal(inst)) |val| { 28752 if (try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0)) |result_val| { 28753 return sema.addConstant(dest_ty, result_val); 28754 } 28755 } 28756 try sema.requireRuntimeBlock(block, inst_src, operand_src); 28757 return block.addBitCast(dest_ty, inst); 28758 } 28759 28760 fn bitCastVal( 28761 sema: *Sema, 28762 block: *Block, 28763 src: LazySrcLoc, 28764 val: Value, 28765 old_ty: Type, 28766 new_ty: Type, 28767 buffer_offset: usize, 28768 ) !?Value { 28769 const mod = sema.mod; 28770 if (old_ty.eql(new_ty, mod)) return val; 28771 28772 // For types with well-defined memory layouts, we serialize them a byte buffer, 28773 // then deserialize to the new type. 28774 const abi_size = try sema.usizeCast(block, src, old_ty.abiSize(mod)); 28775 const buffer = try sema.gpa.alloc(u8, abi_size); 28776 defer sema.gpa.free(buffer); 28777 val.writeToMemory(old_ty, mod, buffer) catch |err| switch (err) { 28778 error.OutOfMemory => return error.OutOfMemory, 28779 error.ReinterpretDeclRef => return null, 28780 error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already 28781 error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{old_ty.fmt(mod)}), 28782 }; 28783 return try Value.readFromMemory(new_ty, mod, buffer[buffer_offset..], sema.arena); 28784 } 28785 28786 fn coerceArrayPtrToSlice( 28787 sema: *Sema, 28788 block: *Block, 28789 dest_ty: Type, 28790 inst: Air.Inst.Ref, 28791 inst_src: LazySrcLoc, 28792 ) CompileError!Air.Inst.Ref { 28793 const mod = sema.mod; 28794 if (try sema.resolveMaybeUndefVal(inst)) |val| { 28795 const ptr_array_ty = sema.typeOf(inst); 28796 const array_ty = ptr_array_ty.childType(mod); 28797 const slice_val = try mod.intern(.{ .ptr = .{ 28798 .ty = dest_ty.toIntern(), 28799 .addr = switch (mod.intern_pool.indexToKey(val.toIntern())) { 28800 .undef => .{ .int = try mod.intern(.{ .undef = .usize_type }) }, 28801 .ptr => |ptr| ptr.addr, 28802 else => unreachable, 28803 }, 28804 .len = (try mod.intValue(Type.usize, array_ty.arrayLen(mod))).toIntern(), 28805 } }); 28806 return sema.addConstant(dest_ty, slice_val.toValue()); 28807 } 28808 try sema.requireRuntimeBlock(block, inst_src, null); 28809 return block.addTyOp(.array_to_slice, dest_ty, inst); 28810 } 28811 28812 fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_result: *InMemoryCoercionResult) bool { 28813 const mod = sema.mod; 28814 const dest_info = dest_ty.ptrInfo(mod); 28815 const inst_info = inst_ty.ptrInfo(mod); 28816 const len0 = (inst_info.pointee_type.zigTypeTag(mod) == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel(mod) == 0 or 28817 (inst_info.pointee_type.arrayLen(mod) == 0 and dest_info.sentinel == null and dest_info.size != .C and dest_info.size != .Many))) or 28818 (inst_info.pointee_type.isTuple(mod) and inst_info.pointee_type.structFieldCount(mod) == 0); 28819 28820 const ok_cv_qualifiers = 28821 ((inst_info.mutable or !dest_info.mutable) or len0) and 28822 (!inst_info.@"volatile" or dest_info.@"volatile"); 28823 28824 if (!ok_cv_qualifiers) { 28825 in_memory_result.* = .{ .ptr_qualifiers = .{ 28826 .actual_const = !inst_info.mutable, 28827 .wanted_const = !dest_info.mutable, 28828 .actual_volatile = inst_info.@"volatile", 28829 .wanted_volatile = dest_info.@"volatile", 28830 } }; 28831 return false; 28832 } 28833 if (dest_info.@"addrspace" != inst_info.@"addrspace") { 28834 in_memory_result.* = .{ .ptr_addrspace = .{ 28835 .actual = inst_info.@"addrspace", 28836 .wanted = dest_info.@"addrspace", 28837 } }; 28838 return false; 28839 } 28840 if (inst_info.@"align" == 0 and dest_info.@"align" == 0) return true; 28841 if (len0) return true; 28842 28843 const inst_align = if (inst_info.@"align" != 0) 28844 inst_info.@"align" 28845 else 28846 inst_info.pointee_type.abiAlignment(mod); 28847 28848 const dest_align = if (dest_info.@"align" != 0) 28849 dest_info.@"align" 28850 else 28851 dest_info.pointee_type.abiAlignment(mod); 28852 28853 if (dest_align > inst_align) { 28854 in_memory_result.* = .{ .ptr_alignment = .{ 28855 .actual = inst_align, 28856 .wanted = dest_align, 28857 } }; 28858 return false; 28859 } 28860 return true; 28861 } 28862 28863 fn coerceCompatiblePtrs( 28864 sema: *Sema, 28865 block: *Block, 28866 dest_ty: Type, 28867 inst: Air.Inst.Ref, 28868 inst_src: LazySrcLoc, 28869 ) !Air.Inst.Ref { 28870 const mod = sema.mod; 28871 const inst_ty = sema.typeOf(inst); 28872 if (try sema.resolveMaybeUndefVal(inst)) |val| { 28873 if (!val.isUndef(mod) and val.isNull(mod) and !dest_ty.isAllowzeroPtr(mod)) { 28874 return sema.fail(block, inst_src, "null pointer casted to type '{}'", .{dest_ty.fmt(sema.mod)}); 28875 } 28876 // The comptime Value representation is compatible with both types. 28877 return sema.addConstant( 28878 dest_ty, 28879 try mod.getCoerced((try val.intern(inst_ty, mod)).toValue(), dest_ty), 28880 ); 28881 } 28882 try sema.requireRuntimeBlock(block, inst_src, null); 28883 const inst_allows_zero = inst_ty.zigTypeTag(mod) != .Pointer or inst_ty.ptrAllowsZero(mod); 28884 if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(mod) and 28885 (try sema.typeHasRuntimeBits(dest_ty.elemType2(mod)) or dest_ty.elemType2(mod).zigTypeTag(mod) == .Fn)) 28886 { 28887 const actual_ptr = if (inst_ty.isSlice(mod)) 28888 try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty) 28889 else 28890 inst; 28891 const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr); 28892 const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize); 28893 const ok = if (inst_ty.isSlice(mod)) ok: { 28894 const len = try sema.analyzeSliceLen(block, inst_src, inst); 28895 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); 28896 break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero); 28897 } else is_non_zero; 28898 try sema.addSafetyCheck(block, ok, .cast_to_null); 28899 } 28900 return sema.bitCast(block, dest_ty, inst, inst_src, null); 28901 } 28902 28903 fn coerceEnumToUnion( 28904 sema: *Sema, 28905 block: *Block, 28906 union_ty: Type, 28907 union_ty_src: LazySrcLoc, 28908 inst: Air.Inst.Ref, 28909 inst_src: LazySrcLoc, 28910 ) !Air.Inst.Ref { 28911 const mod = sema.mod; 28912 const inst_ty = sema.typeOf(inst); 28913 28914 const tag_ty = union_ty.unionTagType(mod) orelse { 28915 const msg = msg: { 28916 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ 28917 union_ty.fmt(sema.mod), inst_ty.fmt(sema.mod), 28918 }); 28919 errdefer msg.destroy(sema.gpa); 28920 try sema.errNote(block, union_ty_src, msg, "cannot coerce enum to untagged union", .{}); 28921 try sema.addDeclaredHereNote(msg, union_ty); 28922 break :msg msg; 28923 }; 28924 return sema.failWithOwnedErrorMsg(msg); 28925 }; 28926 28927 const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src); 28928 if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| { 28929 const field_index = union_ty.unionTagFieldIndex(val, sema.mod) orelse { 28930 const msg = msg: { 28931 const msg = try sema.errMsg(block, inst_src, "union '{}' has no tag with value '{}'", .{ 28932 union_ty.fmt(sema.mod), val.fmtValue(tag_ty, sema.mod), 28933 }); 28934 errdefer msg.destroy(sema.gpa); 28935 try sema.addDeclaredHereNote(msg, union_ty); 28936 break :msg msg; 28937 }; 28938 return sema.failWithOwnedErrorMsg(msg); 28939 }; 28940 28941 const union_obj = mod.typeToUnion(union_ty).?; 28942 const field = union_obj.fields.values()[field_index]; 28943 const field_ty = try sema.resolveTypeFields(field.ty); 28944 if (field_ty.zigTypeTag(mod) == .NoReturn) { 28945 const msg = msg: { 28946 const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{}); 28947 errdefer msg.destroy(sema.gpa); 28948 28949 const field_name = union_obj.fields.keys()[field_index]; 28950 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); 28951 try sema.addDeclaredHereNote(msg, union_ty); 28952 break :msg msg; 28953 }; 28954 return sema.failWithOwnedErrorMsg(msg); 28955 } 28956 const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse { 28957 const msg = msg: { 28958 const field_name = union_obj.fields.keys()[field_index]; 28959 const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{s}'", .{ 28960 inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod), field_ty.fmt(sema.mod), field_name, 28961 }); 28962 errdefer msg.destroy(sema.gpa); 28963 28964 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); 28965 try sema.addDeclaredHereNote(msg, union_ty); 28966 break :msg msg; 28967 }; 28968 return sema.failWithOwnedErrorMsg(msg); 28969 }; 28970 28971 return sema.addConstant(union_ty, try mod.unionValue(union_ty, val, opv)); 28972 } 28973 28974 try sema.requireRuntimeBlock(block, inst_src, null); 28975 28976 if (tag_ty.isNonexhaustiveEnum(mod)) { 28977 const msg = msg: { 28978 const msg = try sema.errMsg(block, inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{ 28979 union_ty.fmt(sema.mod), 28980 }); 28981 errdefer msg.destroy(sema.gpa); 28982 try sema.addDeclaredHereNote(msg, tag_ty); 28983 break :msg msg; 28984 }; 28985 return sema.failWithOwnedErrorMsg(msg); 28986 } 28987 28988 const union_obj = mod.typeToUnion(union_ty).?; 28989 { 28990 var msg: ?*Module.ErrorMsg = null; 28991 errdefer if (msg) |some| some.destroy(sema.gpa); 28992 28993 for (union_obj.fields.values(), 0..) |field, i| { 28994 if (field.ty.zigTypeTag(mod) == .NoReturn) { 28995 const err_msg = msg orelse try sema.errMsg( 28996 block, 28997 inst_src, 28998 "runtime coercion from enum '{}' to union '{}' which has a 'noreturn' field", 28999 .{ tag_ty.fmt(sema.mod), union_ty.fmt(sema.mod) }, 29000 ); 29001 msg = err_msg; 29002 29003 try sema.addFieldErrNote(union_ty, i, err_msg, "'noreturn' field here", .{}); 29004 } 29005 } 29006 if (msg) |some| { 29007 msg = null; 29008 try sema.addDeclaredHereNote(some, union_ty); 29009 return sema.failWithOwnedErrorMsg(some); 29010 } 29011 } 29012 29013 // If the union has all fields 0 bits, the union value is just the enum value. 29014 if (union_ty.unionHasAllZeroBitFieldTypes(mod)) { 29015 return block.addBitCast(union_ty, enum_tag); 29016 } 29017 29018 const msg = msg: { 29019 const msg = try sema.errMsg( 29020 block, 29021 inst_src, 29022 "runtime coercion from enum '{}' to union '{}' which has non-void fields", 29023 .{ tag_ty.fmt(sema.mod), union_ty.fmt(sema.mod) }, 29024 ); 29025 errdefer msg.destroy(sema.gpa); 29026 29027 var it = union_obj.fields.iterator(); 29028 var field_index: usize = 0; 29029 while (it.next()) |field| : (field_index += 1) { 29030 const field_name = field.key_ptr.*; 29031 const field_ty = field.value_ptr.ty; 29032 if (!(try sema.typeHasRuntimeBits(field_ty))) continue; 29033 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) }); 29034 } 29035 try sema.addDeclaredHereNote(msg, union_ty); 29036 break :msg msg; 29037 }; 29038 return sema.failWithOwnedErrorMsg(msg); 29039 } 29040 29041 fn coerceAnonStructToUnion( 29042 sema: *Sema, 29043 block: *Block, 29044 union_ty: Type, 29045 union_ty_src: LazySrcLoc, 29046 inst: Air.Inst.Ref, 29047 inst_src: LazySrcLoc, 29048 ) !Air.Inst.Ref { 29049 const mod = sema.mod; 29050 const inst_ty = sema.typeOf(inst); 29051 const field_info: union(enum) { 29052 name: []const u8, 29053 count: usize, 29054 } = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) { 29055 .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 1) 29056 .{ .name = mod.intern_pool.stringToSlice(anon_struct_type.names[0]) } 29057 else 29058 .{ .count = anon_struct_type.names.len }, 29059 .struct_type => |struct_type| name: { 29060 const field_names = mod.structPtrUnwrap(struct_type.index).?.fields.keys(); 29061 break :name if (field_names.len == 1) 29062 .{ .name = field_names[0] } 29063 else 29064 .{ .count = field_names.len }; 29065 }, 29066 else => unreachable, 29067 }; 29068 switch (field_info) { 29069 .name => |field_name| { 29070 const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty); 29071 return sema.unionInit(block, init, inst_src, union_ty, union_ty_src, field_name, inst_src); 29072 }, 29073 .count => |field_count| { 29074 assert(field_count != 1); 29075 const msg = msg: { 29076 const msg = if (field_count > 1) try sema.errMsg( 29077 block, 29078 inst_src, 29079 "cannot initialize multiple union fields at once; unions can only have one active field", 29080 .{}, 29081 ) else try sema.errMsg( 29082 block, 29083 inst_src, 29084 "union initializer must initialize one field", 29085 .{}, 29086 ); 29087 errdefer msg.destroy(sema.gpa); 29088 29089 // TODO add notes for where the anon struct was created to point out 29090 // the extra fields. 29091 29092 try sema.addDeclaredHereNote(msg, union_ty); 29093 break :msg msg; 29094 }; 29095 return sema.failWithOwnedErrorMsg(msg); 29096 }, 29097 } 29098 } 29099 29100 fn coerceAnonStructToUnionPtrs( 29101 sema: *Sema, 29102 block: *Block, 29103 ptr_union_ty: Type, 29104 union_ty_src: LazySrcLoc, 29105 ptr_anon_struct: Air.Inst.Ref, 29106 anon_struct_src: LazySrcLoc, 29107 ) !Air.Inst.Ref { 29108 const mod = sema.mod; 29109 const union_ty = ptr_union_ty.childType(mod); 29110 const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src); 29111 const union_inst = try sema.coerceAnonStructToUnion(block, union_ty, union_ty_src, anon_struct, anon_struct_src); 29112 return sema.analyzeRef(block, union_ty_src, union_inst); 29113 } 29114 29115 fn coerceAnonStructToStructPtrs( 29116 sema: *Sema, 29117 block: *Block, 29118 ptr_struct_ty: Type, 29119 struct_ty_src: LazySrcLoc, 29120 ptr_anon_struct: Air.Inst.Ref, 29121 anon_struct_src: LazySrcLoc, 29122 ) !Air.Inst.Ref { 29123 const mod = sema.mod; 29124 const struct_ty = ptr_struct_ty.childType(mod); 29125 const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src); 29126 const struct_inst = try sema.coerceTupleToStruct(block, struct_ty, anon_struct, anon_struct_src); 29127 return sema.analyzeRef(block, struct_ty_src, struct_inst); 29128 } 29129 29130 /// If the lengths match, coerces element-wise. 29131 fn coerceArrayLike( 29132 sema: *Sema, 29133 block: *Block, 29134 dest_ty: Type, 29135 dest_ty_src: LazySrcLoc, 29136 inst: Air.Inst.Ref, 29137 inst_src: LazySrcLoc, 29138 ) !Air.Inst.Ref { 29139 const mod = sema.mod; 29140 const inst_ty = sema.typeOf(inst); 29141 const inst_len = inst_ty.arrayLen(mod); 29142 const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen(mod)); 29143 const target = mod.getTarget(); 29144 29145 if (dest_len != inst_len) { 29146 const msg = msg: { 29147 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ 29148 dest_ty.fmt(mod), inst_ty.fmt(mod), 29149 }); 29150 errdefer msg.destroy(sema.gpa); 29151 try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len}); 29152 try sema.errNote(block, inst_src, msg, "source has length {d}", .{inst_len}); 29153 break :msg msg; 29154 }; 29155 return sema.failWithOwnedErrorMsg(msg); 29156 } 29157 29158 const dest_elem_ty = dest_ty.childType(mod); 29159 const inst_elem_ty = inst_ty.childType(mod); 29160 const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_elem_ty, inst_elem_ty, false, target, dest_ty_src, inst_src); 29161 if (in_memory_result == .ok) { 29162 if (try sema.resolveMaybeUndefVal(inst)) |inst_val| { 29163 // These types share the same comptime value representation. 29164 return sema.coerceInMemory(block, inst_val, inst_ty, dest_ty, dest_ty_src); 29165 } 29166 try sema.requireRuntimeBlock(block, inst_src, null); 29167 return block.addBitCast(dest_ty, inst); 29168 } 29169 29170 const element_vals = try sema.arena.alloc(InternPool.Index, dest_len); 29171 const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_len); 29172 var runtime_src: ?LazySrcLoc = null; 29173 29174 for (element_vals, element_refs, 0..) |*val, *ref, i| { 29175 const index_ref = try sema.addConstant(Type.usize, try mod.intValue(Type.usize, i)); 29176 const src = inst_src; // TODO better source location 29177 const elem_src = inst_src; // TODO better source location 29178 const elem_ref = try sema.elemValArray(block, src, inst_src, inst, elem_src, index_ref, true); 29179 const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); 29180 ref.* = coerced; 29181 if (runtime_src == null) { 29182 if (try sema.resolveMaybeUndefVal(coerced)) |elem_val| { 29183 val.* = try elem_val.intern(dest_elem_ty, mod); 29184 } else { 29185 runtime_src = elem_src; 29186 } 29187 } 29188 } 29189 29190 if (runtime_src) |rs| { 29191 try sema.requireRuntimeBlock(block, inst_src, rs); 29192 return block.addAggregateInit(dest_ty, element_refs); 29193 } 29194 29195 return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{ 29196 .ty = dest_ty.toIntern(), 29197 .storage = .{ .elems = element_vals }, 29198 } })).toValue()); 29199 } 29200 29201 /// If the lengths match, coerces element-wise. 29202 fn coerceTupleToArray( 29203 sema: *Sema, 29204 block: *Block, 29205 dest_ty: Type, 29206 dest_ty_src: LazySrcLoc, 29207 inst: Air.Inst.Ref, 29208 inst_src: LazySrcLoc, 29209 ) !Air.Inst.Ref { 29210 const mod = sema.mod; 29211 const inst_ty = sema.typeOf(inst); 29212 const inst_len = inst_ty.arrayLen(mod); 29213 const dest_len = dest_ty.arrayLen(mod); 29214 29215 if (dest_len != inst_len) { 29216 const msg = msg: { 29217 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ 29218 dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod), 29219 }); 29220 errdefer msg.destroy(sema.gpa); 29221 try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len}); 29222 try sema.errNote(block, inst_src, msg, "source has length {d}", .{inst_len}); 29223 break :msg msg; 29224 }; 29225 return sema.failWithOwnedErrorMsg(msg); 29226 } 29227 29228 const dest_elems = try sema.usizeCast(block, dest_ty_src, dest_len); 29229 const element_vals = try sema.arena.alloc(InternPool.Index, dest_elems); 29230 const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_elems); 29231 const dest_elem_ty = dest_ty.childType(mod); 29232 29233 var runtime_src: ?LazySrcLoc = null; 29234 for (element_vals, element_refs, 0..) |*val, *ref, i_usize| { 29235 const i = @intCast(u32, i_usize); 29236 if (i_usize == inst_len) { 29237 const sentinel_val = dest_ty.sentinel(mod).?; 29238 val.* = sentinel_val.toIntern(); 29239 ref.* = try sema.addConstant(dest_elem_ty, sentinel_val); 29240 break; 29241 } 29242 const elem_src = inst_src; // TODO better source location 29243 const elem_ref = try sema.tupleField(block, inst_src, inst, elem_src, i); 29244 const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); 29245 ref.* = coerced; 29246 if (runtime_src == null) { 29247 if (try sema.resolveMaybeUndefVal(coerced)) |elem_val| { 29248 val.* = try elem_val.intern(dest_elem_ty, mod); 29249 } else { 29250 runtime_src = elem_src; 29251 } 29252 } 29253 } 29254 29255 if (runtime_src) |rs| { 29256 try sema.requireRuntimeBlock(block, inst_src, rs); 29257 return block.addAggregateInit(dest_ty, element_refs); 29258 } 29259 29260 return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{ 29261 .ty = dest_ty.toIntern(), 29262 .storage = .{ .elems = element_vals }, 29263 } })).toValue()); 29264 } 29265 29266 /// If the lengths match, coerces element-wise. 29267 fn coerceTupleToSlicePtrs( 29268 sema: *Sema, 29269 block: *Block, 29270 slice_ty: Type, 29271 slice_ty_src: LazySrcLoc, 29272 ptr_tuple: Air.Inst.Ref, 29273 tuple_src: LazySrcLoc, 29274 ) !Air.Inst.Ref { 29275 const mod = sema.mod; 29276 const tuple_ty = sema.typeOf(ptr_tuple).childType(mod); 29277 const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src); 29278 const slice_info = slice_ty.ptrInfo(mod); 29279 const array_ty = try Type.array(sema.arena, tuple_ty.structFieldCount(mod), slice_info.sentinel, slice_info.pointee_type, sema.mod); 29280 const array_inst = try sema.coerceTupleToArray(block, array_ty, slice_ty_src, tuple, tuple_src); 29281 if (slice_info.@"align" != 0) { 29282 return sema.fail(block, slice_ty_src, "TODO: override the alignment of the array decl we create here", .{}); 29283 } 29284 const ptr_array = try sema.analyzeRef(block, slice_ty_src, array_inst); 29285 return sema.coerceArrayPtrToSlice(block, slice_ty, ptr_array, slice_ty_src); 29286 } 29287 29288 /// If the lengths match, coerces element-wise. 29289 fn coerceTupleToArrayPtrs( 29290 sema: *Sema, 29291 block: *Block, 29292 ptr_array_ty: Type, 29293 array_ty_src: LazySrcLoc, 29294 ptr_tuple: Air.Inst.Ref, 29295 tuple_src: LazySrcLoc, 29296 ) !Air.Inst.Ref { 29297 const mod = sema.mod; 29298 const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src); 29299 const ptr_info = ptr_array_ty.ptrInfo(mod); 29300 const array_ty = ptr_info.pointee_type; 29301 const array_inst = try sema.coerceTupleToArray(block, array_ty, array_ty_src, tuple, tuple_src); 29302 if (ptr_info.@"align" != 0) { 29303 return sema.fail(block, array_ty_src, "TODO: override the alignment of the array decl we create here", .{}); 29304 } 29305 const ptr_array = try sema.analyzeRef(block, array_ty_src, array_inst); 29306 return ptr_array; 29307 } 29308 29309 /// Handles both tuples and anon struct literals. Coerces field-wise. Reports 29310 /// errors for both extra fields and missing fields. 29311 fn coerceTupleToStruct( 29312 sema: *Sema, 29313 block: *Block, 29314 dest_ty: Type, 29315 inst: Air.Inst.Ref, 29316 inst_src: LazySrcLoc, 29317 ) !Air.Inst.Ref { 29318 const mod = sema.mod; 29319 const struct_ty = try sema.resolveTypeFields(dest_ty); 29320 29321 if (struct_ty.isTupleOrAnonStruct(mod)) { 29322 return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src); 29323 } 29324 29325 const fields = struct_ty.structFields(mod); 29326 const field_vals = try sema.arena.alloc(InternPool.Index, fields.count()); 29327 const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); 29328 @memset(field_refs, .none); 29329 29330 const inst_ty = sema.typeOf(inst); 29331 var runtime_src: ?LazySrcLoc = null; 29332 const field_count = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) { 29333 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, 29334 .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| 29335 struct_obj.fields.count() 29336 else 29337 0, 29338 else => unreachable, 29339 }; 29340 for (0..field_count) |field_index_usize| { 29341 const field_i = @intCast(u32, field_index_usize); 29342 const field_src = inst_src; // TODO better source location 29343 // https://github.com/ziglang/zig/issues/15709 29344 const field_name: []const u8 = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) { 29345 .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len > 0) 29346 mod.intern_pool.stringToSlice(anon_struct_type.names[field_i]) 29347 else 29348 try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}), 29349 .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[field_i], 29350 else => unreachable, 29351 }; 29352 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src); 29353 const field = fields.values()[field_index]; 29354 const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); 29355 const coerced = try sema.coerce(block, field.ty, elem_ref, field_src); 29356 field_refs[field_index] = coerced; 29357 if (field.is_comptime) { 29358 const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { 29359 return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known"); 29360 }; 29361 29362 if (!init_val.eql(field.default_val, field.ty, sema.mod)) { 29363 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); 29364 } 29365 } 29366 if (runtime_src == null) { 29367 if (try sema.resolveMaybeUndefVal(coerced)) |field_val| { 29368 field_vals[field_index] = field_val.toIntern(); 29369 } else { 29370 runtime_src = field_src; 29371 } 29372 } 29373 } 29374 29375 // Populate default field values and report errors for missing fields. 29376 var root_msg: ?*Module.ErrorMsg = null; 29377 errdefer if (root_msg) |msg| msg.destroy(sema.gpa); 29378 29379 for (field_refs, 0..) |*field_ref, i| { 29380 if (field_ref.* != .none) continue; 29381 29382 const field_name = fields.keys()[i]; 29383 const field = fields.values()[i]; 29384 const field_src = inst_src; // TODO better source location 29385 if (field.default_val.toIntern() == .unreachable_value) { 29386 const template = "missing struct field: {s}"; 29387 const args = .{field_name}; 29388 if (root_msg) |msg| { 29389 try sema.errNote(block, field_src, msg, template, args); 29390 } else { 29391 root_msg = try sema.errMsg(block, field_src, template, args); 29392 } 29393 continue; 29394 } 29395 if (runtime_src == null) { 29396 field_vals[i] = field.default_val.toIntern(); 29397 } else { 29398 field_ref.* = try sema.addConstant(field.ty, field.default_val); 29399 } 29400 } 29401 29402 if (root_msg) |msg| { 29403 try sema.addDeclaredHereNote(msg, struct_ty); 29404 root_msg = null; 29405 return sema.failWithOwnedErrorMsg(msg); 29406 } 29407 29408 if (runtime_src) |rs| { 29409 try sema.requireRuntimeBlock(block, inst_src, rs); 29410 return block.addAggregateInit(struct_ty, field_refs); 29411 } 29412 29413 const struct_val = try mod.intern(.{ .aggregate = .{ 29414 .ty = struct_ty.toIntern(), 29415 .storage = .{ .elems = field_vals }, 29416 } }); 29417 errdefer mod.intern_pool.remove(struct_val); 29418 29419 return sema.addConstant(struct_ty, struct_val.toValue()); 29420 } 29421 29422 fn coerceTupleToTuple( 29423 sema: *Sema, 29424 block: *Block, 29425 tuple_ty: Type, 29426 inst: Air.Inst.Ref, 29427 inst_src: LazySrcLoc, 29428 ) !Air.Inst.Ref { 29429 const mod = sema.mod; 29430 const dest_field_count = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) { 29431 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, 29432 .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| 29433 struct_obj.fields.count() 29434 else 29435 0, 29436 else => unreachable, 29437 }; 29438 const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count); 29439 const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); 29440 @memset(field_refs, .none); 29441 29442 const inst_ty = sema.typeOf(inst); 29443 const src_field_count = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) { 29444 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, 29445 .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| 29446 struct_obj.fields.count() 29447 else 29448 0, 29449 else => unreachable, 29450 }; 29451 if (src_field_count > dest_field_count) return error.NotCoercible; 29452 29453 var runtime_src: ?LazySrcLoc = null; 29454 for (0..dest_field_count) |field_index_usize| { 29455 const field_i = @intCast(u32, field_index_usize); 29456 const field_src = inst_src; // TODO better source location 29457 // https://github.com/ziglang/zig/issues/15709 29458 const field_name: []const u8 = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) { 29459 .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len > 0) 29460 mod.intern_pool.stringToSlice(anon_struct_type.names[field_i]) 29461 else 29462 try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}), 29463 .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[field_i], 29464 else => unreachable, 29465 }; 29466 29467 if (mem.eql(u8, field_name, "len")) { 29468 return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{}); 29469 } 29470 29471 const field_ty = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) { 29472 .anon_struct_type => |anon_struct_type| anon_struct_type.types[field_index_usize].toType(), 29473 .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].ty, 29474 else => unreachable, 29475 }; 29476 const default_val = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) { 29477 .anon_struct_type => |anon_struct_type| anon_struct_type.values[field_index_usize], 29478 .struct_type => |struct_type| switch (mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].default_val.toIntern()) { 29479 .unreachable_value => .none, 29480 else => |default_val| default_val, 29481 }, 29482 else => unreachable, 29483 }; 29484 29485 const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src); 29486 29487 const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); 29488 const coerced = try sema.coerce(block, field_ty, elem_ref, field_src); 29489 field_refs[field_index] = coerced; 29490 if (default_val != .none) { 29491 const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { 29492 return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known"); 29493 }; 29494 29495 if (!init_val.eql(default_val.toValue(), field_ty, sema.mod)) { 29496 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); 29497 } 29498 } 29499 if (runtime_src == null) { 29500 if (try sema.resolveMaybeUndefVal(coerced)) |field_val| { 29501 field_vals[field_index] = field_val.toIntern(); 29502 } else { 29503 runtime_src = field_src; 29504 } 29505 } 29506 } 29507 29508 // Populate default field values and report errors for missing fields. 29509 var root_msg: ?*Module.ErrorMsg = null; 29510 errdefer if (root_msg) |msg| msg.destroy(sema.gpa); 29511 29512 for (field_refs, 0..) |*field_ref, i| { 29513 if (field_ref.* != .none) continue; 29514 29515 const default_val = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) { 29516 .anon_struct_type => |anon_struct_type| anon_struct_type.values[i], 29517 .struct_type => |struct_type| switch (mod.structPtrUnwrap(struct_type.index).?.fields.values()[i].default_val.toIntern()) { 29518 .unreachable_value => .none, 29519 else => |default_val| default_val, 29520 }, 29521 else => unreachable, 29522 }; 29523 29524 const field_src = inst_src; // TODO better source location 29525 if (default_val == .none) { 29526 if (tuple_ty.isTuple(mod)) { 29527 const template = "missing tuple field: {d}"; 29528 if (root_msg) |msg| { 29529 try sema.errNote(block, field_src, msg, template, .{i}); 29530 } else { 29531 root_msg = try sema.errMsg(block, field_src, template, .{i}); 29532 } 29533 continue; 29534 } 29535 const template = "missing struct field: {s}"; 29536 const args = .{tuple_ty.structFieldName(i, mod)}; 29537 if (root_msg) |msg| { 29538 try sema.errNote(block, field_src, msg, template, args); 29539 } else { 29540 root_msg = try sema.errMsg(block, field_src, template, args); 29541 } 29542 continue; 29543 } 29544 if (runtime_src == null) { 29545 field_vals[i] = default_val; 29546 } else { 29547 const field_ty = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) { 29548 .anon_struct_type => |anon_struct_type| anon_struct_type.types[i].toType(), 29549 .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[i].ty, 29550 else => unreachable, 29551 }; 29552 field_ref.* = try sema.addConstant(field_ty, default_val.toValue()); 29553 } 29554 } 29555 29556 if (root_msg) |msg| { 29557 try sema.addDeclaredHereNote(msg, tuple_ty); 29558 root_msg = null; 29559 return sema.failWithOwnedErrorMsg(msg); 29560 } 29561 29562 if (runtime_src) |rs| { 29563 try sema.requireRuntimeBlock(block, inst_src, rs); 29564 return block.addAggregateInit(tuple_ty, field_refs); 29565 } 29566 29567 return sema.addConstant( 29568 tuple_ty, 29569 (try mod.intern(.{ .aggregate = .{ 29570 .ty = tuple_ty.toIntern(), 29571 .storage = .{ .elems = field_vals }, 29572 } })).toValue(), 29573 ); 29574 } 29575 29576 fn analyzeDeclVal( 29577 sema: *Sema, 29578 block: *Block, 29579 src: LazySrcLoc, 29580 decl_index: Decl.Index, 29581 ) CompileError!Air.Inst.Ref { 29582 try sema.addReferencedBy(block, src, decl_index); 29583 if (sema.decl_val_table.get(decl_index)) |result| { 29584 return result; 29585 } 29586 const decl_ref = try sema.analyzeDeclRefInner(decl_index, false); 29587 const result = try sema.analyzeLoad(block, src, decl_ref, src); 29588 if (Air.refToIndex(result)) |index| { 29589 if (sema.air_instructions.items(.tag)[index] == .interned and !block.is_typeof) { 29590 try sema.decl_val_table.put(sema.gpa, decl_index, result); 29591 } 29592 } 29593 return result; 29594 } 29595 29596 fn addReferencedBy( 29597 sema: *Sema, 29598 block: *Block, 29599 src: LazySrcLoc, 29600 decl_index: Decl.Index, 29601 ) !void { 29602 if (sema.mod.comp.reference_trace == @as(u32, 0)) return; 29603 try sema.mod.reference_table.put(sema.gpa, decl_index, .{ 29604 .referencer = block.src_decl, 29605 .src = src, 29606 }); 29607 } 29608 29609 fn ensureDeclAnalyzed(sema: *Sema, decl_index: Decl.Index) CompileError!void { 29610 const mod = sema.mod; 29611 const decl = mod.declPtr(decl_index); 29612 if (decl.analysis == .in_progress) { 29613 const msg = try Module.ErrorMsg.create(sema.gpa, decl.srcLoc(mod), "dependency loop detected", .{}); 29614 return sema.failWithOwnedErrorMsg(msg); 29615 } 29616 29617 mod.ensureDeclAnalyzed(decl_index) catch |err| { 29618 if (sema.owner_func) |owner_func| { 29619 owner_func.state = .dependency_failure; 29620 } else { 29621 sema.owner_decl.analysis = .dependency_failure; 29622 } 29623 return err; 29624 }; 29625 } 29626 29627 fn ensureFuncBodyAnalyzed(sema: *Sema, func: Module.Fn.Index) CompileError!void { 29628 sema.mod.ensureFuncBodyAnalyzed(func) catch |err| { 29629 if (sema.owner_func) |owner_func| { 29630 owner_func.state = .dependency_failure; 29631 } else { 29632 sema.owner_decl.analysis = .dependency_failure; 29633 } 29634 return err; 29635 }; 29636 } 29637 29638 fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value { 29639 const mod = sema.mod; 29640 var anon_decl = try block.startAnonDecl(); 29641 defer anon_decl.deinit(); 29642 const decl = try anon_decl.finish( 29643 ty, 29644 try val.copy(anon_decl.arena()), 29645 0, // default alignment 29646 ); 29647 try sema.maybeQueueFuncBodyAnalysis(decl); 29648 try mod.declareDeclDependency(sema.owner_decl_index, decl); 29649 const result = try mod.intern(.{ .ptr = .{ 29650 .ty = (try mod.singleConstPtrType(ty)).toIntern(), 29651 .addr = .{ .decl = decl }, 29652 } }); 29653 return result.toValue(); 29654 } 29655 29656 fn optRefValue(sema: *Sema, block: *Block, ty: Type, opt_val: ?Value) !Value { 29657 const mod = sema.mod; 29658 const ptr_anyopaque_ty = try mod.singleConstPtrType(Type.anyopaque); 29659 return (try mod.intern(.{ .opt = .{ 29660 .ty = (try mod.optionalType(ptr_anyopaque_ty.toIntern())).toIntern(), 29661 .val = if (opt_val) |val| (try mod.getCoerced( 29662 try sema.refValue(block, ty, val), 29663 ptr_anyopaque_ty, 29664 )).toIntern() else .none, 29665 } })).toValue(); 29666 } 29667 29668 fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref { 29669 return sema.analyzeDeclRefInner(decl_index, true); 29670 } 29671 29672 /// Analyze a reference to the decl at the given index. Ensures the underlying decl is analyzed, but 29673 /// only triggers analysis for function bodies if `analyze_fn_body` is true. If it's possible for a 29674 /// decl_ref to end up in runtime code, the function body must be analyzed: `analyzeDeclRef` wraps 29675 /// this function with `analyze_fn_body` set to true. 29676 fn analyzeDeclRefInner(sema: *Sema, decl_index: Decl.Index, analyze_fn_body: bool) CompileError!Air.Inst.Ref { 29677 const mod = sema.mod; 29678 try mod.declareDeclDependency(sema.owner_decl_index, decl_index); 29679 try sema.ensureDeclAnalyzed(decl_index); 29680 29681 const decl = mod.declPtr(decl_index); 29682 const decl_tv = try decl.typedValue(); 29683 const ptr_ty = try mod.ptrType(.{ 29684 .child = decl_tv.ty.toIntern(), 29685 .flags = .{ 29686 .alignment = InternPool.Alignment.fromByteUnits(decl.@"align"), 29687 .is_const = if (decl.val.getVariable(mod)) |variable| variable.is_const else true, 29688 .address_space = decl.@"addrspace", 29689 }, 29690 }); 29691 if (analyze_fn_body) { 29692 try sema.maybeQueueFuncBodyAnalysis(decl_index); 29693 } 29694 return sema.addConstant(ptr_ty, (try mod.intern(.{ .ptr = .{ 29695 .ty = ptr_ty.toIntern(), 29696 .addr = .{ .decl = decl_index }, 29697 } })).toValue()); 29698 } 29699 29700 fn maybeQueueFuncBodyAnalysis(sema: *Sema, decl_index: Decl.Index) !void { 29701 const mod = sema.mod; 29702 const decl = mod.declPtr(decl_index); 29703 const tv = try decl.typedValue(); 29704 if (tv.ty.zigTypeTag(mod) != .Fn) return; 29705 if (!try sema.fnHasRuntimeBits(tv.ty)) return; 29706 const func_index = mod.intern_pool.indexToFunc(tv.val.toIntern()).unwrap() orelse return; // undef or extern_fn 29707 try mod.ensureFuncBodyAnalysisQueued(func_index); 29708 } 29709 29710 fn analyzeRef( 29711 sema: *Sema, 29712 block: *Block, 29713 src: LazySrcLoc, 29714 operand: Air.Inst.Ref, 29715 ) CompileError!Air.Inst.Ref { 29716 const operand_ty = sema.typeOf(operand); 29717 29718 if (try sema.resolveMaybeUndefVal(operand)) |val| { 29719 switch (sema.mod.intern_pool.indexToKey(val.toIntern())) { 29720 .extern_func => |extern_func| return sema.analyzeDeclRef(extern_func.decl), 29721 .func => |func| return sema.analyzeDeclRef(sema.mod.funcPtr(func.index).owner_decl), 29722 else => {}, 29723 } 29724 var anon_decl = try block.startAnonDecl(); 29725 defer anon_decl.deinit(); 29726 return sema.analyzeDeclRef(try anon_decl.finish( 29727 operand_ty, 29728 try val.copy(anon_decl.arena()), 29729 0, // default alignment 29730 )); 29731 } 29732 29733 try sema.requireRuntimeBlock(block, src, null); 29734 const address_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local); 29735 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{ 29736 .pointee_type = operand_ty, 29737 .mutable = false, 29738 .@"addrspace" = address_space, 29739 }); 29740 const mut_ptr_type = try Type.ptr(sema.arena, sema.mod, .{ 29741 .pointee_type = operand_ty, 29742 .@"addrspace" = address_space, 29743 }); 29744 const alloc = try block.addTy(.alloc, mut_ptr_type); 29745 try sema.storePtr(block, src, alloc, operand); 29746 29747 // TODO: Replace with sema.coerce when that supports adding pointer constness. 29748 return sema.bitCast(block, ptr_type, alloc, src, null); 29749 } 29750 29751 fn analyzeLoad( 29752 sema: *Sema, 29753 block: *Block, 29754 src: LazySrcLoc, 29755 ptr: Air.Inst.Ref, 29756 ptr_src: LazySrcLoc, 29757 ) CompileError!Air.Inst.Ref { 29758 const mod = sema.mod; 29759 const ptr_ty = sema.typeOf(ptr); 29760 const elem_ty = switch (ptr_ty.zigTypeTag(mod)) { 29761 .Pointer => ptr_ty.childType(mod), 29762 else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}), 29763 }; 29764 29765 if (try sema.typeHasOnePossibleValue(elem_ty)) |opv| { 29766 return sema.addConstant(elem_ty, opv); 29767 } 29768 29769 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { 29770 if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| { 29771 return sema.addConstant(elem_ty, try mod.getCoerced(elem_val, elem_ty)); 29772 } 29773 } 29774 29775 if (ptr_ty.ptrInfo(mod).vector_index == .runtime) { 29776 const ptr_inst = Air.refToIndex(ptr).?; 29777 const air_tags = sema.air_instructions.items(.tag); 29778 if (air_tags[ptr_inst] == .ptr_elem_ptr) { 29779 const ty_pl = sema.air_instructions.items(.data)[ptr_inst].ty_pl; 29780 const bin_op = sema.getTmpAir().extraData(Air.Bin, ty_pl.payload).data; 29781 return block.addBinOp(.ptr_elem_val, bin_op.lhs, bin_op.rhs); 29782 } 29783 return sema.fail(block, ptr_src, "unable to determine vector element index of type '{}'", .{ 29784 ptr_ty.fmt(sema.mod), 29785 }); 29786 } 29787 29788 return block.addTyOp(.load, elem_ty, ptr); 29789 } 29790 29791 fn analyzeSlicePtr( 29792 sema: *Sema, 29793 block: *Block, 29794 slice_src: LazySrcLoc, 29795 slice: Air.Inst.Ref, 29796 slice_ty: Type, 29797 ) CompileError!Air.Inst.Ref { 29798 const mod = sema.mod; 29799 const result_ty = slice_ty.slicePtrFieldType(mod); 29800 if (try sema.resolveMaybeUndefVal(slice)) |val| { 29801 if (val.isUndef(mod)) return sema.addConstUndef(result_ty); 29802 return sema.addConstant(result_ty, val.slicePtr(mod)); 29803 } 29804 try sema.requireRuntimeBlock(block, slice_src, null); 29805 return block.addTyOp(.slice_ptr, result_ty, slice); 29806 } 29807 29808 fn analyzeSliceLen( 29809 sema: *Sema, 29810 block: *Block, 29811 src: LazySrcLoc, 29812 slice_inst: Air.Inst.Ref, 29813 ) CompileError!Air.Inst.Ref { 29814 const mod = sema.mod; 29815 if (try sema.resolveMaybeUndefVal(slice_inst)) |slice_val| { 29816 if (slice_val.isUndef(mod)) { 29817 return sema.addConstUndef(Type.usize); 29818 } 29819 return sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod)); 29820 } 29821 try sema.requireRuntimeBlock(block, src, null); 29822 return block.addTyOp(.slice_len, Type.usize, slice_inst); 29823 } 29824 29825 fn analyzeIsNull( 29826 sema: *Sema, 29827 block: *Block, 29828 src: LazySrcLoc, 29829 operand: Air.Inst.Ref, 29830 invert_logic: bool, 29831 ) CompileError!Air.Inst.Ref { 29832 const mod = sema.mod; 29833 const result_ty = Type.bool; 29834 if (try sema.resolveMaybeUndefVal(operand)) |opt_val| { 29835 if (opt_val.isUndef(mod)) { 29836 return sema.addConstUndef(result_ty); 29837 } 29838 const is_null = opt_val.isNull(mod); 29839 const bool_value = if (invert_logic) !is_null else is_null; 29840 if (bool_value) { 29841 return Air.Inst.Ref.bool_true; 29842 } else { 29843 return Air.Inst.Ref.bool_false; 29844 } 29845 } 29846 29847 const inverted_non_null_res = if (invert_logic) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; 29848 const operand_ty = sema.typeOf(operand); 29849 if (operand_ty.zigTypeTag(mod) == .Optional and operand_ty.optionalChild(mod).zigTypeTag(mod) == .NoReturn) { 29850 return inverted_non_null_res; 29851 } 29852 if (operand_ty.zigTypeTag(mod) != .Optional and !operand_ty.isPtrLikeOptional(mod)) { 29853 return inverted_non_null_res; 29854 } 29855 try sema.requireRuntimeBlock(block, src, null); 29856 const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null; 29857 return block.addUnOp(air_tag, operand); 29858 } 29859 29860 fn analyzePtrIsNonErrComptimeOnly( 29861 sema: *Sema, 29862 block: *Block, 29863 src: LazySrcLoc, 29864 operand: Air.Inst.Ref, 29865 ) CompileError!Air.Inst.Ref { 29866 const mod = sema.mod; 29867 const ptr_ty = sema.typeOf(operand); 29868 assert(ptr_ty.zigTypeTag(mod) == .Pointer); 29869 const child_ty = ptr_ty.childType(mod); 29870 29871 const child_tag = child_ty.zigTypeTag(mod); 29872 if (child_tag != .ErrorSet and child_tag != .ErrorUnion) return Air.Inst.Ref.bool_true; 29873 if (child_tag == .ErrorSet) return Air.Inst.Ref.bool_false; 29874 assert(child_tag == .ErrorUnion); 29875 29876 _ = block; 29877 _ = src; 29878 29879 return Air.Inst.Ref.none; 29880 } 29881 29882 fn analyzeIsNonErrComptimeOnly( 29883 sema: *Sema, 29884 block: *Block, 29885 src: LazySrcLoc, 29886 operand: Air.Inst.Ref, 29887 ) CompileError!Air.Inst.Ref { 29888 const mod = sema.mod; 29889 const operand_ty = sema.typeOf(operand); 29890 const ot = operand_ty.zigTypeTag(mod); 29891 if (ot != .ErrorSet and ot != .ErrorUnion) return Air.Inst.Ref.bool_true; 29892 if (ot == .ErrorSet) return Air.Inst.Ref.bool_false; 29893 assert(ot == .ErrorUnion); 29894 29895 const payload_ty = operand_ty.errorUnionPayload(mod); 29896 if (payload_ty.zigTypeTag(mod) == .NoReturn) { 29897 return Air.Inst.Ref.bool_false; 29898 } 29899 29900 if (Air.refToIndex(operand)) |operand_inst| { 29901 switch (sema.air_instructions.items(.tag)[operand_inst]) { 29902 .wrap_errunion_payload => return Air.Inst.Ref.bool_true, 29903 .wrap_errunion_err => return Air.Inst.Ref.bool_false, 29904 else => {}, 29905 } 29906 } else if (operand == .undef) { 29907 return sema.addConstUndef(Type.bool); 29908 } else { 29909 // None of the ref tags can be errors. 29910 return Air.Inst.Ref.bool_true; 29911 } 29912 29913 const maybe_operand_val = try sema.resolveMaybeUndefVal(operand); 29914 29915 // exception if the error union error set is known to be empty, 29916 // we allow the comparison but always make it comptime-known. 29917 const set_ty = operand_ty.errorUnionSet(mod); 29918 switch (set_ty.toIntern()) { 29919 .anyerror_type => {}, 29920 else => switch (mod.intern_pool.indexToKey(set_ty.toIntern())) { 29921 .error_set_type => |error_set_type| { 29922 if (error_set_type.names.len == 0) return Air.Inst.Ref.bool_true; 29923 }, 29924 .inferred_error_set_type => |ies_index| blk: { 29925 // If the error set is empty, we must return a comptime true or false. 29926 // However we want to avoid unnecessarily resolving an inferred error set 29927 // in case it is already non-empty. 29928 const ies = mod.inferredErrorSetPtr(ies_index); 29929 if (ies.is_anyerror) break :blk; 29930 if (ies.errors.count() != 0) break :blk; 29931 if (maybe_operand_val == null) { 29932 // Try to avoid resolving inferred error set if possible. 29933 if (ies.errors.count() != 0) break :blk; 29934 if (ies.is_anyerror) break :blk; 29935 for (ies.inferred_error_sets.keys()) |other_ies_index| { 29936 if (ies_index == other_ies_index) continue; 29937 try sema.resolveInferredErrorSet(block, src, other_ies_index); 29938 const other_ies = mod.inferredErrorSetPtr(other_ies_index); 29939 if (other_ies.is_anyerror) { 29940 ies.is_anyerror = true; 29941 ies.is_resolved = true; 29942 break :blk; 29943 } 29944 29945 if (other_ies.errors.count() != 0) break :blk; 29946 } 29947 if (ies.func == sema.owner_func_index.unwrap()) { 29948 // We're checking the inferred errorset of the current function and none of 29949 // its child inferred error sets contained any errors meaning that any value 29950 // so far with this type can't contain errors either. 29951 return Air.Inst.Ref.bool_true; 29952 } 29953 try sema.resolveInferredErrorSet(block, src, ies_index); 29954 if (ies.is_anyerror) break :blk; 29955 if (ies.errors.count() == 0) return Air.Inst.Ref.bool_true; 29956 } 29957 }, 29958 else => unreachable, 29959 }, 29960 } 29961 29962 if (maybe_operand_val) |err_union| { 29963 if (err_union.isUndef(mod)) { 29964 return sema.addConstUndef(Type.bool); 29965 } 29966 if (err_union.getError(mod) == null) { 29967 return Air.Inst.Ref.bool_true; 29968 } else { 29969 return Air.Inst.Ref.bool_false; 29970 } 29971 } 29972 return Air.Inst.Ref.none; 29973 } 29974 29975 fn analyzeIsNonErr( 29976 sema: *Sema, 29977 block: *Block, 29978 src: LazySrcLoc, 29979 operand: Air.Inst.Ref, 29980 ) CompileError!Air.Inst.Ref { 29981 const result = try sema.analyzeIsNonErrComptimeOnly(block, src, operand); 29982 if (result == .none) { 29983 try sema.requireRuntimeBlock(block, src, null); 29984 return block.addUnOp(.is_non_err, operand); 29985 } else { 29986 return result; 29987 } 29988 } 29989 29990 fn analyzePtrIsNonErr( 29991 sema: *Sema, 29992 block: *Block, 29993 src: LazySrcLoc, 29994 operand: Air.Inst.Ref, 29995 ) CompileError!Air.Inst.Ref { 29996 const result = try sema.analyzePtrIsNonErrComptimeOnly(block, src, operand); 29997 if (result == .none) { 29998 try sema.requireRuntimeBlock(block, src, null); 29999 return block.addUnOp(.is_non_err_ptr, operand); 30000 } else { 30001 return result; 30002 } 30003 } 30004 30005 fn analyzeSlice( 30006 sema: *Sema, 30007 block: *Block, 30008 src: LazySrcLoc, 30009 ptr_ptr: Air.Inst.Ref, 30010 uncasted_start: Air.Inst.Ref, 30011 uncasted_end_opt: Air.Inst.Ref, 30012 sentinel_opt: Air.Inst.Ref, 30013 sentinel_src: LazySrcLoc, 30014 ptr_src: LazySrcLoc, 30015 start_src: LazySrcLoc, 30016 end_src: LazySrcLoc, 30017 by_length: bool, 30018 ) CompileError!Air.Inst.Ref { 30019 const mod = sema.mod; 30020 // Slice expressions can operate on a variable whose type is an array. This requires 30021 // the slice operand to be a pointer. In the case of a non-array, it will be a double pointer. 30022 const ptr_ptr_ty = sema.typeOf(ptr_ptr); 30023 const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag(mod)) { 30024 .Pointer => ptr_ptr_ty.childType(mod), 30025 else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(mod)}), 30026 }; 30027 30028 var array_ty = ptr_ptr_child_ty; 30029 var slice_ty = ptr_ptr_ty; 30030 var ptr_or_slice = ptr_ptr; 30031 var elem_ty: Type = undefined; 30032 var ptr_sentinel: ?Value = null; 30033 switch (ptr_ptr_child_ty.zigTypeTag(mod)) { 30034 .Array => { 30035 ptr_sentinel = ptr_ptr_child_ty.sentinel(mod); 30036 elem_ty = ptr_ptr_child_ty.childType(mod); 30037 }, 30038 .Pointer => switch (ptr_ptr_child_ty.ptrSize(mod)) { 30039 .One => { 30040 const double_child_ty = ptr_ptr_child_ty.childType(mod); 30041 if (double_child_ty.zigTypeTag(mod) == .Array) { 30042 ptr_sentinel = double_child_ty.sentinel(mod); 30043 ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); 30044 slice_ty = ptr_ptr_child_ty; 30045 array_ty = double_child_ty; 30046 elem_ty = double_child_ty.childType(mod); 30047 } else { 30048 return sema.fail(block, src, "slice of single-item pointer", .{}); 30049 } 30050 }, 30051 .Many, .C => { 30052 ptr_sentinel = ptr_ptr_child_ty.sentinel(mod); 30053 ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); 30054 slice_ty = ptr_ptr_child_ty; 30055 array_ty = ptr_ptr_child_ty; 30056 elem_ty = ptr_ptr_child_ty.childType(mod); 30057 30058 if (ptr_ptr_child_ty.ptrSize(mod) == .C) { 30059 if (try sema.resolveDefinedValue(block, ptr_src, ptr_or_slice)) |ptr_val| { 30060 if (ptr_val.isNull(mod)) { 30061 return sema.fail(block, src, "slice of null pointer", .{}); 30062 } 30063 } 30064 } 30065 }, 30066 .Slice => { 30067 ptr_sentinel = ptr_ptr_child_ty.sentinel(mod); 30068 ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); 30069 slice_ty = ptr_ptr_child_ty; 30070 array_ty = ptr_ptr_child_ty; 30071 elem_ty = ptr_ptr_child_ty.childType(mod); 30072 }, 30073 }, 30074 else => return sema.fail(block, src, "slice of non-array type '{}'", .{ptr_ptr_child_ty.fmt(mod)}), 30075 } 30076 30077 const ptr = if (slice_ty.isSlice(mod)) 30078 try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty) 30079 else if (array_ty.zigTypeTag(mod) == .Array) ptr: { 30080 var manyptr_ty_key = mod.intern_pool.indexToKey(slice_ty.toIntern()).ptr_type; 30081 assert(manyptr_ty_key.child == array_ty.toIntern()); 30082 assert(manyptr_ty_key.flags.size == .One); 30083 manyptr_ty_key.child = elem_ty.toIntern(); 30084 manyptr_ty_key.flags.size = .Many; 30085 break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(manyptr_ty_key), ptr_or_slice, ptr_src); 30086 } else ptr_or_slice; 30087 30088 const start = try sema.coerce(block, Type.usize, uncasted_start, start_src); 30089 const new_ptr = try sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src); 30090 const new_ptr_ty = sema.typeOf(new_ptr); 30091 30092 // true if and only if the end index of the slice, implicitly or explicitly, equals 30093 // the length of the underlying object being sliced. we might learn the length of the 30094 // underlying object because it is an array (which has the length in the type), or 30095 // we might learn of the length because it is a comptime-known slice value. 30096 var end_is_len = uncasted_end_opt == .none; 30097 const end = e: { 30098 if (array_ty.zigTypeTag(mod) == .Array) { 30099 const len_val = try mod.intValue(Type.usize, array_ty.arrayLen(mod)); 30100 30101 if (!end_is_len) { 30102 const end = if (by_length) end: { 30103 const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); 30104 const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false); 30105 break :end try sema.coerce(block, Type.usize, uncasted_end, end_src); 30106 } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); 30107 if (try sema.resolveMaybeUndefVal(end)) |end_val| { 30108 const len_s_val = try mod.intValue( 30109 Type.usize, 30110 array_ty.arrayLenIncludingSentinel(mod), 30111 ); 30112 if (!(try sema.compareAll(end_val, .lte, len_s_val, Type.usize))) { 30113 const sentinel_label: []const u8 = if (array_ty.sentinel(mod) != null) 30114 " +1 (sentinel)" 30115 else 30116 ""; 30117 30118 return sema.fail( 30119 block, 30120 end_src, 30121 "end index {} out of bounds for array of length {}{s}", 30122 .{ 30123 end_val.fmtValue(Type.usize, mod), 30124 len_val.fmtValue(Type.usize, mod), 30125 sentinel_label, 30126 }, 30127 ); 30128 } 30129 30130 // end_is_len is only true if we are NOT using the sentinel 30131 // length. For sentinel-length, we don't want the type to 30132 // contain the sentinel. 30133 if (end_val.eql(len_val, Type.usize, mod)) { 30134 end_is_len = true; 30135 } 30136 } 30137 break :e end; 30138 } 30139 30140 break :e try sema.addConstant(Type.usize, len_val); 30141 } else if (slice_ty.isSlice(mod)) { 30142 if (!end_is_len) { 30143 const end = if (by_length) end: { 30144 const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); 30145 const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false); 30146 break :end try sema.coerce(block, Type.usize, uncasted_end, end_src); 30147 } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); 30148 if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { 30149 if (try sema.resolveMaybeUndefVal(ptr_or_slice)) |slice_val| { 30150 if (slice_val.isUndef(mod)) { 30151 return sema.fail(block, src, "slice of undefined", .{}); 30152 } 30153 const has_sentinel = slice_ty.sentinel(mod) != null; 30154 const slice_len = slice_val.sliceLen(mod); 30155 const len_plus_sent = slice_len + @boolToInt(has_sentinel); 30156 const slice_len_val_with_sentinel = try mod.intValue(Type.usize, len_plus_sent); 30157 if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, Type.usize))) { 30158 const sentinel_label: []const u8 = if (has_sentinel) 30159 " +1 (sentinel)" 30160 else 30161 ""; 30162 30163 return sema.fail( 30164 block, 30165 end_src, 30166 "end index {} out of bounds for slice of length {d}{s}", 30167 .{ 30168 end_val.fmtValue(Type.usize, mod), 30169 slice_val.sliceLen(mod), 30170 sentinel_label, 30171 }, 30172 ); 30173 } 30174 30175 // If the slice has a sentinel, we consider end_is_len 30176 // is only true if it equals the length WITHOUT the 30177 // sentinel, so we don't add a sentinel type. 30178 const slice_len_val = try mod.intValue(Type.usize, slice_len); 30179 if (end_val.eql(slice_len_val, Type.usize, mod)) { 30180 end_is_len = true; 30181 } 30182 } 30183 } 30184 break :e end; 30185 } 30186 break :e try sema.analyzeSliceLen(block, src, ptr_or_slice); 30187 } 30188 if (!end_is_len) { 30189 if (by_length) { 30190 const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); 30191 const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false); 30192 break :e try sema.coerce(block, Type.usize, uncasted_end, end_src); 30193 } else break :e try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); 30194 } 30195 return sema.fail(block, src, "slice of pointer must include end value", .{}); 30196 }; 30197 30198 const sentinel = s: { 30199 if (sentinel_opt != .none) { 30200 const casted = try sema.coerce(block, elem_ty, sentinel_opt, sentinel_src); 30201 break :s try sema.resolveConstValue(block, sentinel_src, casted, "slice sentinel must be comptime-known"); 30202 } 30203 // If we are slicing to the end of something that is sentinel-terminated 30204 // then the resulting slice type is also sentinel-terminated. 30205 if (end_is_len) { 30206 if (ptr_sentinel) |sent| { 30207 break :s sent; 30208 } 30209 } 30210 break :s null; 30211 }; 30212 const slice_sentinel = if (sentinel_opt != .none) sentinel else null; 30213 30214 var checked_start_lte_end = by_length; 30215 var runtime_src: ?LazySrcLoc = null; 30216 30217 // requirement: start <= end 30218 if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { 30219 if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { 30220 if (!by_length and !(try sema.compareAll(start_val, .lte, end_val, Type.usize))) { 30221 return sema.fail( 30222 block, 30223 start_src, 30224 "start index {} is larger than end index {}", 30225 .{ 30226 start_val.fmtValue(Type.usize, mod), 30227 end_val.fmtValue(Type.usize, mod), 30228 }, 30229 ); 30230 } 30231 checked_start_lte_end = true; 30232 if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: { 30233 const expected_sentinel = sentinel orelse break :sentinel_check; 30234 const start_int = start_val.getUnsignedInt(mod).?; 30235 const end_int = end_val.getUnsignedInt(mod).?; 30236 const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); 30237 30238 const many_ptr_ty = try mod.manyConstPtrType(elem_ty); 30239 const many_ptr_val = try mod.getCoerced(ptr_val, many_ptr_ty); 30240 const elem_ptr_ty = try mod.singleConstPtrType(elem_ty); 30241 const elem_ptr = try many_ptr_val.elemPtr(elem_ptr_ty, sentinel_index, mod); 30242 const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty); 30243 const actual_sentinel = switch (res) { 30244 .runtime_load => break :sentinel_check, 30245 .val => |v| v, 30246 .needed_well_defined => |ty| return sema.fail( 30247 block, 30248 src, 30249 "comptime dereference requires '{}' to have a well-defined layout, but it does not.", 30250 .{ty.fmt(mod)}, 30251 ), 30252 .out_of_bounds => |ty| return sema.fail( 30253 block, 30254 end_src, 30255 "slice end index {d} exceeds bounds of containing decl of type '{}'", 30256 .{ end_int, ty.fmt(mod) }, 30257 ), 30258 }; 30259 30260 if (!actual_sentinel.eql(expected_sentinel, elem_ty, mod)) { 30261 const msg = msg: { 30262 const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); 30263 errdefer msg.destroy(sema.gpa); 30264 try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ 30265 expected_sentinel.fmtValue(elem_ty, mod), 30266 actual_sentinel.fmtValue(elem_ty, mod), 30267 }); 30268 30269 break :msg msg; 30270 }; 30271 return sema.failWithOwnedErrorMsg(msg); 30272 } 30273 } else { 30274 runtime_src = ptr_src; 30275 } 30276 } else { 30277 runtime_src = start_src; 30278 } 30279 } else { 30280 runtime_src = end_src; 30281 } 30282 30283 if (!checked_start_lte_end and block.wantSafety() and !block.is_comptime) { 30284 // requirement: start <= end 30285 assert(!block.is_comptime); 30286 try sema.requireRuntimeBlock(block, src, runtime_src.?); 30287 const ok = try block.addBinOp(.cmp_lte, start, end); 30288 if (!sema.mod.comp.formatted_panics) { 30289 try sema.addSafetyCheck(block, ok, .start_index_greater_than_end); 30290 } else { 30291 try sema.safetyCheckFormatted(block, ok, "panicStartGreaterThanEnd", &.{ start, end }); 30292 } 30293 } 30294 const new_len = if (by_length) 30295 try sema.coerce(block, Type.usize, uncasted_end_opt, end_src) 30296 else 30297 try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false); 30298 const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len); 30299 30300 const new_ptr_ty_info = new_ptr_ty.ptrInfo(mod); 30301 const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize(mod) != .C; 30302 30303 if (opt_new_len_val) |new_len_val| { 30304 const new_len_int = new_len_val.toUnsignedInt(mod); 30305 30306 const return_ty = try Type.ptr(sema.arena, mod, .{ 30307 .pointee_type = try Type.array(sema.arena, new_len_int, sentinel, elem_ty, mod), 30308 .sentinel = null, 30309 .@"align" = new_ptr_ty_info.@"align", 30310 .@"addrspace" = new_ptr_ty_info.@"addrspace", 30311 .mutable = new_ptr_ty_info.mutable, 30312 .@"allowzero" = new_allowzero, 30313 .@"volatile" = new_ptr_ty_info.@"volatile", 30314 .size = .One, 30315 }); 30316 30317 const opt_new_ptr_val = try sema.resolveMaybeUndefVal(new_ptr); 30318 const new_ptr_val = opt_new_ptr_val orelse { 30319 const result = try block.addBitCast(return_ty, new_ptr); 30320 if (block.wantSafety()) { 30321 // requirement: slicing C ptr is non-null 30322 if (ptr_ptr_child_ty.isCPtr(mod)) { 30323 const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true); 30324 try sema.addSafetyCheck(block, is_non_null, .unwrap_null); 30325 } 30326 30327 if (slice_ty.isSlice(mod)) { 30328 const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice); 30329 const actual_len = if (slice_ty.sentinel(mod) == null) 30330 slice_len_inst 30331 else 30332 try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true); 30333 30334 const actual_end = if (slice_sentinel != null) 30335 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src, true) 30336 else 30337 end; 30338 30339 try sema.panicIndexOutOfBounds(block, actual_end, actual_len, .cmp_lte); 30340 } 30341 30342 // requirement: result[new_len] == slice_sentinel 30343 try sema.panicSentinelMismatch(block, slice_sentinel, elem_ty, result, new_len); 30344 } 30345 return result; 30346 }; 30347 30348 if (!new_ptr_val.isUndef(mod)) { 30349 return sema.addConstant(return_ty, try mod.getCoerced( 30350 (try new_ptr_val.intern(new_ptr_ty, mod)).toValue(), 30351 return_ty, 30352 )); 30353 } 30354 30355 // Special case: @as([]i32, undefined)[x..x] 30356 if (new_len_int == 0) { 30357 return sema.addConstUndef(return_ty); 30358 } 30359 30360 return sema.fail(block, src, "non-zero length slice of undefined pointer", .{}); 30361 } 30362 30363 const return_ty = try Type.ptr(sema.arena, mod, .{ 30364 .pointee_type = elem_ty, 30365 .sentinel = sentinel, 30366 .@"align" = new_ptr_ty_info.@"align", 30367 .@"addrspace" = new_ptr_ty_info.@"addrspace", 30368 .mutable = new_ptr_ty_info.mutable, 30369 .@"allowzero" = new_allowzero, 30370 .@"volatile" = new_ptr_ty_info.@"volatile", 30371 .size = .Slice, 30372 }); 30373 30374 try sema.requireRuntimeBlock(block, src, runtime_src.?); 30375 if (block.wantSafety()) { 30376 // requirement: slicing C ptr is non-null 30377 if (ptr_ptr_child_ty.isCPtr(mod)) { 30378 const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true); 30379 try sema.addSafetyCheck(block, is_non_null, .unwrap_null); 30380 } 30381 30382 // requirement: end <= len 30383 const opt_len_inst = if (array_ty.zigTypeTag(mod) == .Array) 30384 try sema.addIntUnsigned(Type.usize, array_ty.arrayLenIncludingSentinel(mod)) 30385 else if (slice_ty.isSlice(mod)) blk: { 30386 if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { 30387 // we don't need to add one for sentinels because the 30388 // underlying value data includes the sentinel 30389 break :blk try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(mod)); 30390 } 30391 30392 const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice); 30393 if (slice_ty.sentinel(mod) == null) break :blk slice_len_inst; 30394 30395 // we have to add one because slice lengths don't include the sentinel 30396 break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true); 30397 } else null; 30398 if (opt_len_inst) |len_inst| { 30399 const actual_end = if (slice_sentinel != null) 30400 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src, true) 30401 else 30402 end; 30403 try sema.panicIndexOutOfBounds(block, actual_end, len_inst, .cmp_lte); 30404 } 30405 30406 // requirement: start <= end 30407 try sema.panicIndexOutOfBounds(block, start, end, .cmp_lte); 30408 } 30409 const result = try block.addInst(.{ 30410 .tag = .slice, 30411 .data = .{ .ty_pl = .{ 30412 .ty = try sema.addType(return_ty), 30413 .payload = try sema.addExtra(Air.Bin{ 30414 .lhs = new_ptr, 30415 .rhs = new_len, 30416 }), 30417 } }, 30418 }); 30419 if (block.wantSafety()) { 30420 // requirement: result[new_len] == slice_sentinel 30421 try sema.panicSentinelMismatch(block, slice_sentinel, elem_ty, result, new_len); 30422 } 30423 return result; 30424 } 30425 30426 /// Asserts that lhs and rhs types are both numeric. 30427 fn cmpNumeric( 30428 sema: *Sema, 30429 block: *Block, 30430 src: LazySrcLoc, 30431 uncasted_lhs: Air.Inst.Ref, 30432 uncasted_rhs: Air.Inst.Ref, 30433 op: std.math.CompareOperator, 30434 lhs_src: LazySrcLoc, 30435 rhs_src: LazySrcLoc, 30436 ) CompileError!Air.Inst.Ref { 30437 const mod = sema.mod; 30438 const lhs_ty = sema.typeOf(uncasted_lhs); 30439 const rhs_ty = sema.typeOf(uncasted_rhs); 30440 30441 assert(lhs_ty.isNumeric(mod)); 30442 assert(rhs_ty.isNumeric(mod)); 30443 30444 const lhs_ty_tag = lhs_ty.zigTypeTag(mod); 30445 const rhs_ty_tag = rhs_ty.zigTypeTag(mod); 30446 const target = mod.getTarget(); 30447 30448 // One exception to heterogeneous comparison: comptime_float needs to 30449 // coerce to fixed-width float. 30450 30451 const lhs = if (lhs_ty_tag == .ComptimeFloat and rhs_ty_tag == .Float) 30452 try sema.coerce(block, rhs_ty, uncasted_lhs, lhs_src) 30453 else 30454 uncasted_lhs; 30455 30456 const rhs = if (lhs_ty_tag == .Float and rhs_ty_tag == .ComptimeFloat) 30457 try sema.coerce(block, lhs_ty, uncasted_rhs, rhs_src) 30458 else 30459 uncasted_rhs; 30460 30461 const runtime_src: LazySrcLoc = src: { 30462 if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| { 30463 if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { 30464 // Compare ints: const vs. undefined (or vice versa) 30465 if (!lhs_val.isUndef(mod) and (lhs_ty.isInt(mod) or lhs_ty_tag == .ComptimeInt) and rhs_ty.isInt(mod) and rhs_val.isUndef(mod)) { 30466 if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(lhs_val), op, rhs_ty)) |res| { 30467 return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; 30468 } 30469 } else if (!rhs_val.isUndef(mod) and (rhs_ty.isInt(mod) or rhs_ty_tag == .ComptimeInt) and lhs_ty.isInt(mod) and lhs_val.isUndef(mod)) { 30470 if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(rhs_val), op.reverse(), lhs_ty)) |res| { 30471 return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; 30472 } 30473 } 30474 30475 if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) { 30476 return sema.addConstUndef(Type.bool); 30477 } 30478 if (lhs_val.isNan(mod) or rhs_val.isNan(mod)) { 30479 if (op == std.math.CompareOperator.neq) { 30480 return Air.Inst.Ref.bool_true; 30481 } else { 30482 return Air.Inst.Ref.bool_false; 30483 } 30484 } 30485 if (try Value.compareHeteroAdvanced(lhs_val, op, rhs_val, mod, sema)) { 30486 return Air.Inst.Ref.bool_true; 30487 } else { 30488 return Air.Inst.Ref.bool_false; 30489 } 30490 } else { 30491 if (!lhs_val.isUndef(mod) and (lhs_ty.isInt(mod) or lhs_ty_tag == .ComptimeInt) and rhs_ty.isInt(mod)) { 30492 // Compare ints: const vs. var 30493 if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(lhs_val), op, rhs_ty)) |res| { 30494 return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; 30495 } 30496 } 30497 break :src rhs_src; 30498 } 30499 } else { 30500 if (try sema.resolveMaybeUndefLazyVal(rhs)) |rhs_val| { 30501 if (!rhs_val.isUndef(mod) and (rhs_ty.isInt(mod) or rhs_ty_tag == .ComptimeInt) and lhs_ty.isInt(mod)) { 30502 // Compare ints: var vs. const 30503 if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(rhs_val), op.reverse(), lhs_ty)) |res| { 30504 return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; 30505 } 30506 } 30507 } 30508 break :src lhs_src; 30509 } 30510 }; 30511 30512 // TODO handle comparisons against lazy zero values 30513 // Some values can be compared against zero without being runtime-known or without forcing 30514 // a full resolution of their value, for example `@sizeOf(@Frame(function))` is known to 30515 // always be nonzero, and we benefit from not forcing the full evaluation and stack frame layout 30516 // of this function if we don't need to. 30517 try sema.requireRuntimeBlock(block, src, runtime_src); 30518 30519 // For floats, emit a float comparison instruction. 30520 const lhs_is_float = switch (lhs_ty_tag) { 30521 .Float, .ComptimeFloat => true, 30522 else => false, 30523 }; 30524 const rhs_is_float = switch (rhs_ty_tag) { 30525 .Float, .ComptimeFloat => true, 30526 else => false, 30527 }; 30528 30529 if (lhs_is_float and rhs_is_float) { 30530 // Smaller fixed-width floats coerce to larger fixed-width floats. 30531 // comptime_float coerces to fixed-width float. 30532 const dest_ty = x: { 30533 if (lhs_ty_tag == .ComptimeFloat) { 30534 break :x rhs_ty; 30535 } else if (rhs_ty_tag == .ComptimeFloat) { 30536 break :x lhs_ty; 30537 } 30538 if (lhs_ty.floatBits(target) >= rhs_ty.floatBits(target)) { 30539 break :x lhs_ty; 30540 } else { 30541 break :x rhs_ty; 30542 } 30543 }; 30544 const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src); 30545 const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src); 30546 return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs); 30547 } 30548 // For mixed unsigned integer sizes, implicit cast both operands to the larger integer. 30549 // For mixed signed and unsigned integers, implicit cast both operands to a signed 30550 // integer with + 1 bit. 30551 // For mixed floats and integers, extract the integer part from the float, cast that to 30552 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float, 30553 // add/subtract 1. 30554 const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| 30555 !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema)) 30556 else 30557 (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt(mod)); 30558 const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| 30559 !(try rhs_val.compareAllWithZeroAdvanced(.gte, sema)) 30560 else 30561 (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt(mod)); 30562 const dest_int_is_signed = lhs_is_signed or rhs_is_signed; 30563 30564 var dest_float_type: ?Type = null; 30565 30566 var lhs_bits: usize = undefined; 30567 if (try sema.resolveMaybeUndefLazyVal(lhs)) |lhs_val| { 30568 if (lhs_val.isUndef(mod)) 30569 return sema.addConstUndef(Type.bool); 30570 if (lhs_val.isNan(mod)) switch (op) { 30571 .neq => return Air.Inst.Ref.bool_true, 30572 else => return Air.Inst.Ref.bool_false, 30573 }; 30574 if (lhs_val.isInf(mod)) switch (op) { 30575 .neq => return Air.Inst.Ref.bool_true, 30576 .eq => return Air.Inst.Ref.bool_false, 30577 .gt, .gte => return if (lhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true, 30578 .lt, .lte => return if (lhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false, 30579 }; 30580 if (!rhs_is_signed) { 30581 switch (lhs_val.orderAgainstZero(mod)) { 30582 .gt => {}, 30583 .eq => switch (op) { // LHS = 0, RHS is unsigned 30584 .lte => return Air.Inst.Ref.bool_true, 30585 .gt => return Air.Inst.Ref.bool_false, 30586 else => {}, 30587 }, 30588 .lt => switch (op) { // LHS < 0, RHS is unsigned 30589 .neq, .lt, .lte => return Air.Inst.Ref.bool_true, 30590 .eq, .gt, .gte => return Air.Inst.Ref.bool_false, 30591 }, 30592 } 30593 } 30594 if (lhs_is_float) { 30595 if (lhs_val.floatHasFraction(mod)) { 30596 switch (op) { 30597 .eq => return Air.Inst.Ref.bool_false, 30598 .neq => return Air.Inst.Ref.bool_true, 30599 else => {}, 30600 } 30601 } 30602 30603 var bigint = try float128IntPartToBigInt(sema.gpa, lhs_val.toFloat(f128, mod)); 30604 defer bigint.deinit(); 30605 if (lhs_val.floatHasFraction(mod)) { 30606 if (lhs_is_signed) { 30607 try bigint.addScalar(&bigint, -1); 30608 } else { 30609 try bigint.addScalar(&bigint, 1); 30610 } 30611 } 30612 lhs_bits = bigint.toConst().bitCountTwosComp(); 30613 } else { 30614 lhs_bits = lhs_val.intBitCountTwosComp(mod); 30615 } 30616 lhs_bits += @boolToInt(!lhs_is_signed and dest_int_is_signed); 30617 } else if (lhs_is_float) { 30618 dest_float_type = lhs_ty; 30619 } else { 30620 const int_info = lhs_ty.intInfo(mod); 30621 lhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed); 30622 } 30623 30624 var rhs_bits: usize = undefined; 30625 if (try sema.resolveMaybeUndefLazyVal(rhs)) |rhs_val| { 30626 if (rhs_val.isUndef(mod)) 30627 return sema.addConstUndef(Type.bool); 30628 if (rhs_val.isNan(mod)) switch (op) { 30629 .neq => return Air.Inst.Ref.bool_true, 30630 else => return Air.Inst.Ref.bool_false, 30631 }; 30632 if (rhs_val.isInf(mod)) switch (op) { 30633 .neq => return Air.Inst.Ref.bool_true, 30634 .eq => return Air.Inst.Ref.bool_false, 30635 .gt, .gte => return if (rhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false, 30636 .lt, .lte => return if (rhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true, 30637 }; 30638 if (!lhs_is_signed) { 30639 switch (rhs_val.orderAgainstZero(mod)) { 30640 .gt => {}, 30641 .eq => switch (op) { // RHS = 0, LHS is unsigned 30642 .gte => return Air.Inst.Ref.bool_true, 30643 .lt => return Air.Inst.Ref.bool_false, 30644 else => {}, 30645 }, 30646 .lt => switch (op) { // RHS < 0, LHS is unsigned 30647 .neq, .gt, .gte => return Air.Inst.Ref.bool_true, 30648 .eq, .lt, .lte => return Air.Inst.Ref.bool_false, 30649 }, 30650 } 30651 } 30652 if (rhs_is_float) { 30653 if (rhs_val.floatHasFraction(mod)) { 30654 switch (op) { 30655 .eq => return Air.Inst.Ref.bool_false, 30656 .neq => return Air.Inst.Ref.bool_true, 30657 else => {}, 30658 } 30659 } 30660 30661 var bigint = try float128IntPartToBigInt(sema.gpa, rhs_val.toFloat(f128, mod)); 30662 defer bigint.deinit(); 30663 if (rhs_val.floatHasFraction(mod)) { 30664 if (rhs_is_signed) { 30665 try bigint.addScalar(&bigint, -1); 30666 } else { 30667 try bigint.addScalar(&bigint, 1); 30668 } 30669 } 30670 rhs_bits = bigint.toConst().bitCountTwosComp(); 30671 } else { 30672 rhs_bits = rhs_val.intBitCountTwosComp(mod); 30673 } 30674 rhs_bits += @boolToInt(!rhs_is_signed and dest_int_is_signed); 30675 } else if (rhs_is_float) { 30676 dest_float_type = rhs_ty; 30677 } else { 30678 const int_info = rhs_ty.intInfo(mod); 30679 rhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed); 30680 } 30681 30682 const dest_ty = if (dest_float_type) |ft| ft else blk: { 30683 const max_bits = std.math.max(lhs_bits, rhs_bits); 30684 const casted_bits = std.math.cast(u16, max_bits) orelse return sema.fail(block, src, "{d} exceeds maximum integer bit count", .{max_bits}); 30685 const signedness: std.builtin.Signedness = if (dest_int_is_signed) .signed else .unsigned; 30686 break :blk try mod.intType(signedness, casted_bits); 30687 }; 30688 const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src); 30689 const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src); 30690 30691 return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs); 30692 } 30693 30694 /// Asserts that LHS value is an int or comptime int and not undefined, and 30695 /// that RHS type is an int. Given a const LHS and an unknown RHS, attempt to 30696 /// determine whether `op` has a guaranteed result. 30697 /// If it cannot be determined, returns null. 30698 /// Otherwise returns a bool for the guaranteed comparison operation. 30699 fn compareIntsOnlyPossibleResult( 30700 sema: *Sema, 30701 lhs_val: Value, 30702 op: std.math.CompareOperator, 30703 rhs_ty: Type, 30704 ) Allocator.Error!?bool { 30705 const mod = sema.mod; 30706 const rhs_info = rhs_ty.intInfo(mod); 30707 const vs_zero = lhs_val.orderAgainstZeroAdvanced(mod, sema) catch unreachable; 30708 const is_zero = vs_zero == .eq; 30709 const is_negative = vs_zero == .lt; 30710 const is_positive = vs_zero == .gt; 30711 30712 // Anything vs. zero-sized type has guaranteed outcome. 30713 if (rhs_info.bits == 0) return switch (op) { 30714 .eq, .lte, .gte => is_zero, 30715 .neq, .lt, .gt => !is_zero, 30716 }; 30717 30718 // Special case for i1, which can only be 0 or -1. 30719 // Zero and positive ints have guaranteed outcome. 30720 if (rhs_info.bits == 1 and rhs_info.signedness == .signed) { 30721 if (is_positive) return switch (op) { 30722 .gt, .gte, .neq => true, 30723 .lt, .lte, .eq => false, 30724 }; 30725 if (is_zero) return switch (op) { 30726 .gte => true, 30727 .lt => false, 30728 .gt, .lte, .eq, .neq => null, 30729 }; 30730 } 30731 30732 // Negative vs. unsigned has guaranteed outcome. 30733 if (rhs_info.signedness == .unsigned and is_negative) return switch (op) { 30734 .eq, .gt, .gte => false, 30735 .neq, .lt, .lte => true, 30736 }; 30737 30738 const sign_adj = @boolToInt(!is_negative and rhs_info.signedness == .signed); 30739 const req_bits = lhs_val.intBitCountTwosComp(mod) + sign_adj; 30740 30741 // No sized type can have more than 65535 bits. 30742 // The RHS type operand is either a runtime value or sized (but undefined) constant. 30743 if (req_bits > 65535) return switch (op) { 30744 .lt, .lte => is_negative, 30745 .gt, .gte => is_positive, 30746 .eq => false, 30747 .neq => true, 30748 }; 30749 const fits = req_bits <= rhs_info.bits; 30750 30751 // Oversized int has guaranteed outcome. 30752 switch (op) { 30753 .eq => return if (!fits) false else null, 30754 .neq => return if (!fits) true else null, 30755 .lt, .lte => if (!fits) return is_negative, 30756 .gt, .gte => if (!fits) return !is_negative, 30757 } 30758 30759 // For any other comparison, we need to know if the LHS value is 30760 // equal to the maximum or minimum possible value of the RHS type. 30761 const edge: struct { min: bool, max: bool } = edge: { 30762 if (is_zero and rhs_info.signedness == .unsigned) break :edge .{ 30763 .min = true, 30764 .max = false, 30765 }; 30766 30767 if (req_bits != rhs_info.bits) break :edge .{ 30768 .min = false, 30769 .max = false, 30770 }; 30771 30772 const ty = try mod.intType( 30773 if (is_negative) .signed else .unsigned, 30774 @intCast(u16, req_bits), 30775 ); 30776 const pop_count = lhs_val.popCount(ty, mod); 30777 30778 if (is_negative) { 30779 break :edge .{ 30780 .min = pop_count == 1, 30781 .max = false, 30782 }; 30783 } else { 30784 break :edge .{ 30785 .min = false, 30786 .max = pop_count == req_bits - sign_adj, 30787 }; 30788 } 30789 }; 30790 30791 assert(fits); 30792 return switch (op) { 30793 .lt => if (edge.max) false else null, 30794 .lte => if (edge.min) true else null, 30795 .gt => if (edge.min) false else null, 30796 .gte => if (edge.max) true else null, 30797 .eq, .neq => unreachable, 30798 }; 30799 } 30800 30801 /// Asserts that lhs and rhs types are both vectors. 30802 fn cmpVector( 30803 sema: *Sema, 30804 block: *Block, 30805 src: LazySrcLoc, 30806 lhs: Air.Inst.Ref, 30807 rhs: Air.Inst.Ref, 30808 op: std.math.CompareOperator, 30809 lhs_src: LazySrcLoc, 30810 rhs_src: LazySrcLoc, 30811 ) CompileError!Air.Inst.Ref { 30812 const mod = sema.mod; 30813 const lhs_ty = sema.typeOf(lhs); 30814 const rhs_ty = sema.typeOf(rhs); 30815 assert(lhs_ty.zigTypeTag(mod) == .Vector); 30816 assert(rhs_ty.zigTypeTag(mod) == .Vector); 30817 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 30818 30819 const resolved_ty = try sema.resolvePeerTypes(block, src, &.{ lhs, rhs }, .{ .override = &.{ lhs_src, rhs_src } }); 30820 const casted_lhs = try sema.coerce(block, resolved_ty, lhs, lhs_src); 30821 const casted_rhs = try sema.coerce(block, resolved_ty, rhs, rhs_src); 30822 30823 const result_ty = try mod.vectorType(.{ 30824 .len = lhs_ty.vectorLen(mod), 30825 .child = .bool_type, 30826 }); 30827 30828 const runtime_src: LazySrcLoc = src: { 30829 if (try sema.resolveMaybeUndefVal(casted_lhs)) |lhs_val| { 30830 if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| { 30831 if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) { 30832 return sema.addConstUndef(result_ty); 30833 } 30834 const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_ty); 30835 return sema.addConstant(result_ty, cmp_val); 30836 } else { 30837 break :src rhs_src; 30838 } 30839 } else { 30840 break :src lhs_src; 30841 } 30842 }; 30843 30844 try sema.requireRuntimeBlock(block, src, runtime_src); 30845 return block.addCmpVector(casted_lhs, casted_rhs, op); 30846 } 30847 30848 fn wrapOptional( 30849 sema: *Sema, 30850 block: *Block, 30851 dest_ty: Type, 30852 inst: Air.Inst.Ref, 30853 inst_src: LazySrcLoc, 30854 ) !Air.Inst.Ref { 30855 if (try sema.resolveMaybeUndefVal(inst)) |val| { 30856 return sema.addConstant(dest_ty, (try sema.mod.intern(.{ .opt = .{ 30857 .ty = dest_ty.toIntern(), 30858 .val = val.toIntern(), 30859 } })).toValue()); 30860 } 30861 30862 try sema.requireRuntimeBlock(block, inst_src, null); 30863 return block.addTyOp(.wrap_optional, dest_ty, inst); 30864 } 30865 30866 fn wrapErrorUnionPayload( 30867 sema: *Sema, 30868 block: *Block, 30869 dest_ty: Type, 30870 inst: Air.Inst.Ref, 30871 inst_src: LazySrcLoc, 30872 ) !Air.Inst.Ref { 30873 const mod = sema.mod; 30874 const dest_payload_ty = dest_ty.errorUnionPayload(mod); 30875 const coerced = try sema.coerceExtra(block, dest_payload_ty, inst, inst_src, .{ .report_err = false }); 30876 if (try sema.resolveMaybeUndefVal(coerced)) |val| { 30877 return sema.addConstant(dest_ty, (try mod.intern(.{ .error_union = .{ 30878 .ty = dest_ty.toIntern(), 30879 .val = .{ .payload = try val.intern(dest_payload_ty, mod) }, 30880 } })).toValue()); 30881 } 30882 try sema.requireRuntimeBlock(block, inst_src, null); 30883 try sema.queueFullTypeResolution(dest_payload_ty); 30884 return block.addTyOp(.wrap_errunion_payload, dest_ty, coerced); 30885 } 30886 30887 fn wrapErrorUnionSet( 30888 sema: *Sema, 30889 block: *Block, 30890 dest_ty: Type, 30891 inst: Air.Inst.Ref, 30892 inst_src: LazySrcLoc, 30893 ) !Air.Inst.Ref { 30894 const mod = sema.mod; 30895 const ip = &mod.intern_pool; 30896 const inst_ty = sema.typeOf(inst); 30897 const dest_err_set_ty = dest_ty.errorUnionSet(mod); 30898 if (try sema.resolveMaybeUndefVal(inst)) |val| { 30899 switch (dest_err_set_ty.toIntern()) { 30900 .anyerror_type => {}, 30901 else => switch (ip.indexToKey(dest_err_set_ty.toIntern())) { 30902 .error_set_type => |error_set_type| ok: { 30903 const expected_name = mod.intern_pool.indexToKey(val.toIntern()).err.name; 30904 if (error_set_type.nameIndex(ip, expected_name) != null) break :ok; 30905 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); 30906 }, 30907 .inferred_error_set_type => |ies_index| ok: { 30908 const ies = mod.inferredErrorSetPtr(ies_index); 30909 const expected_name = mod.intern_pool.indexToKey(val.toIntern()).err.name; 30910 30911 // We carefully do this in an order that avoids unnecessarily 30912 // resolving the destination error set type. 30913 if (ies.is_anyerror) break :ok; 30914 30915 if (ies.errors.contains(expected_name)) break :ok; 30916 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) break :ok; 30917 30918 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); 30919 }, 30920 else => unreachable, 30921 }, 30922 } 30923 return sema.addConstant(dest_ty, (try mod.intern(.{ .error_union = .{ 30924 .ty = dest_ty.toIntern(), 30925 .val = .{ 30926 .err_name = mod.intern_pool.indexToKey(try val.intern(dest_err_set_ty, mod)).err.name, 30927 }, 30928 } })).toValue()); 30929 } 30930 30931 try sema.requireRuntimeBlock(block, inst_src, null); 30932 const coerced = try sema.coerce(block, dest_err_set_ty, inst, inst_src); 30933 return block.addTyOp(.wrap_errunion_err, dest_ty, coerced); 30934 } 30935 30936 fn unionToTag( 30937 sema: *Sema, 30938 block: *Block, 30939 enum_ty: Type, 30940 un: Air.Inst.Ref, 30941 un_src: LazySrcLoc, 30942 ) !Air.Inst.Ref { 30943 const mod = sema.mod; 30944 if ((try sema.typeHasOnePossibleValue(enum_ty))) |opv| { 30945 return sema.addConstant(enum_ty, opv); 30946 } 30947 if (try sema.resolveMaybeUndefVal(un)) |un_val| { 30948 return sema.addConstant(enum_ty, un_val.unionTag(mod)); 30949 } 30950 try sema.requireRuntimeBlock(block, un_src, null); 30951 return block.addTyOp(.get_union_tag, enum_ty, un); 30952 } 30953 30954 fn resolvePeerTypes( 30955 sema: *Sema, 30956 block: *Block, 30957 src: LazySrcLoc, 30958 instructions: []const Air.Inst.Ref, 30959 candidate_srcs: Module.PeerTypeCandidateSrc, 30960 ) !Type { 30961 const mod = sema.mod; 30962 switch (instructions.len) { 30963 0 => return Type.noreturn, 30964 1 => return sema.typeOf(instructions[0]), 30965 else => {}, 30966 } 30967 30968 const target = mod.getTarget(); 30969 30970 var chosen = instructions[0]; 30971 // If this is non-null then it does the following thing, depending on the chosen zigTypeTag(mod). 30972 // * ErrorSet: this is an override 30973 // * ErrorUnion: this is an override of the error set only 30974 // * other: at the end we make an ErrorUnion with the other thing and this 30975 var err_set_ty: ?Type = null; 30976 var any_are_null = false; 30977 var seen_const = false; 30978 var convert_to_slice = false; 30979 var chosen_i: usize = 0; 30980 for (instructions[1..], 0..) |candidate, candidate_i| { 30981 const candidate_ty = sema.typeOf(candidate); 30982 const chosen_ty = sema.typeOf(chosen); 30983 30984 const candidate_ty_tag = try candidate_ty.zigTypeTagOrPoison(mod); 30985 const chosen_ty_tag = try chosen_ty.zigTypeTagOrPoison(mod); 30986 30987 // If the candidate can coerce into our chosen type, we're done. 30988 // If the chosen type can coerce into the candidate, use that. 30989 if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) { 30990 continue; 30991 } 30992 if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) { 30993 chosen = candidate; 30994 chosen_i = candidate_i + 1; 30995 continue; 30996 } 30997 30998 switch (candidate_ty_tag) { 30999 .NoReturn, .Undefined => continue, 31000 31001 .Null => { 31002 any_are_null = true; 31003 continue; 31004 }, 31005 31006 .Int => switch (chosen_ty_tag) { 31007 .ComptimeInt => { 31008 chosen = candidate; 31009 chosen_i = candidate_i + 1; 31010 continue; 31011 }, 31012 .Int => { 31013 const chosen_info = chosen_ty.intInfo(mod); 31014 const candidate_info = candidate_ty.intInfo(mod); 31015 31016 if (chosen_info.bits < candidate_info.bits) { 31017 chosen = candidate; 31018 chosen_i = candidate_i + 1; 31019 } 31020 continue; 31021 }, 31022 .Pointer => if (chosen_ty.ptrSize(mod) == .C) continue, 31023 else => {}, 31024 }, 31025 .ComptimeInt => switch (chosen_ty_tag) { 31026 .Int, .Float, .ComptimeFloat => continue, 31027 .Pointer => if (chosen_ty.ptrSize(mod) == .C) continue, 31028 else => {}, 31029 }, 31030 .Float => switch (chosen_ty_tag) { 31031 .Float => { 31032 if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) { 31033 chosen = candidate; 31034 chosen_i = candidate_i + 1; 31035 } 31036 continue; 31037 }, 31038 .ComptimeFloat, .ComptimeInt => { 31039 chosen = candidate; 31040 chosen_i = candidate_i + 1; 31041 continue; 31042 }, 31043 else => {}, 31044 }, 31045 .ComptimeFloat => switch (chosen_ty_tag) { 31046 .Float => continue, 31047 .ComptimeInt => { 31048 chosen = candidate; 31049 chosen_i = candidate_i + 1; 31050 continue; 31051 }, 31052 else => {}, 31053 }, 31054 .Enum => switch (chosen_ty_tag) { 31055 .EnumLiteral => { 31056 chosen = candidate; 31057 chosen_i = candidate_i + 1; 31058 continue; 31059 }, 31060 .Union => continue, 31061 else => {}, 31062 }, 31063 .EnumLiteral => switch (chosen_ty_tag) { 31064 .Enum, .Union => continue, 31065 else => {}, 31066 }, 31067 .Union => switch (chosen_ty_tag) { 31068 .Enum, .EnumLiteral => { 31069 chosen = candidate; 31070 chosen_i = candidate_i + 1; 31071 continue; 31072 }, 31073 else => {}, 31074 }, 31075 .ErrorSet => switch (chosen_ty_tag) { 31076 .ErrorSet => { 31077 // If chosen is superset of candidate, keep it. 31078 // If candidate is superset of chosen, switch it. 31079 // If neither is a superset, merge errors. 31080 const chosen_set_ty = err_set_ty orelse chosen_ty; 31081 31082 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) { 31083 continue; 31084 } 31085 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) { 31086 err_set_ty = null; 31087 chosen = candidate; 31088 chosen_i = candidate_i + 1; 31089 continue; 31090 } 31091 31092 err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_ty); 31093 continue; 31094 }, 31095 .ErrorUnion => { 31096 const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(mod); 31097 31098 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) { 31099 continue; 31100 } 31101 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) { 31102 err_set_ty = candidate_ty; 31103 continue; 31104 } 31105 31106 err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_ty); 31107 continue; 31108 }, 31109 else => { 31110 if (err_set_ty) |chosen_set_ty| { 31111 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) { 31112 continue; 31113 } 31114 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) { 31115 err_set_ty = candidate_ty; 31116 continue; 31117 } 31118 31119 err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_ty); 31120 continue; 31121 } else { 31122 err_set_ty = candidate_ty; 31123 continue; 31124 } 31125 }, 31126 }, 31127 .ErrorUnion => switch (chosen_ty_tag) { 31128 .ErrorSet => { 31129 const chosen_set_ty = err_set_ty orelse chosen_ty; 31130 const candidate_set_ty = candidate_ty.errorUnionSet(mod); 31131 31132 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { 31133 err_set_ty = chosen_set_ty; 31134 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { 31135 err_set_ty = null; 31136 } else { 31137 err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_set_ty); 31138 } 31139 chosen = candidate; 31140 chosen_i = candidate_i + 1; 31141 continue; 31142 }, 31143 31144 .ErrorUnion => { 31145 const chosen_payload_ty = chosen_ty.errorUnionPayload(mod); 31146 const candidate_payload_ty = candidate_ty.errorUnionPayload(mod); 31147 31148 const coerce_chosen = (try sema.coerceInMemoryAllowed(block, chosen_payload_ty, candidate_payload_ty, false, target, src, src)) == .ok; 31149 const coerce_candidate = (try sema.coerceInMemoryAllowed(block, candidate_payload_ty, chosen_payload_ty, false, target, src, src)) == .ok; 31150 31151 if (coerce_chosen or coerce_candidate) { 31152 // If we can coerce to the candidate, we switch to that 31153 // type. This is the same logic as the bare (non-union) 31154 // coercion check we do at the top of this func. 31155 if (coerce_candidate) { 31156 chosen = candidate; 31157 chosen_i = candidate_i + 1; 31158 } 31159 31160 const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(mod); 31161 const candidate_set_ty = candidate_ty.errorUnionSet(mod); 31162 31163 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { 31164 err_set_ty = chosen_set_ty; 31165 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { 31166 err_set_ty = candidate_set_ty; 31167 } else { 31168 err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_set_ty); 31169 } 31170 continue; 31171 } 31172 }, 31173 31174 else => { 31175 if (err_set_ty) |chosen_set_ty| { 31176 const candidate_set_ty = candidate_ty.errorUnionSet(mod); 31177 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { 31178 err_set_ty = chosen_set_ty; 31179 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { 31180 err_set_ty = null; 31181 } else { 31182 err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_set_ty); 31183 } 31184 } 31185 seen_const = seen_const or chosen_ty.isConstPtr(mod); 31186 chosen = candidate; 31187 chosen_i = candidate_i + 1; 31188 continue; 31189 }, 31190 }, 31191 .Pointer => { 31192 const cand_info = candidate_ty.ptrInfo(mod); 31193 switch (chosen_ty_tag) { 31194 .Pointer => { 31195 const chosen_info = chosen_ty.ptrInfo(mod); 31196 31197 seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; 31198 31199 // *[N]T to [*]T 31200 // *[N]T to []T 31201 if ((cand_info.size == .Many or cand_info.size == .Slice) and 31202 chosen_info.size == .One and 31203 chosen_info.pointee_type.zigTypeTag(mod) == .Array) 31204 { 31205 // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T` 31206 convert_to_slice = false; 31207 chosen = candidate; 31208 chosen_i = candidate_i + 1; 31209 continue; 31210 } 31211 if (cand_info.size == .One and 31212 cand_info.pointee_type.zigTypeTag(mod) == .Array and 31213 (chosen_info.size == .Many or chosen_info.size == .Slice)) 31214 { 31215 // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T` 31216 convert_to_slice = false; 31217 continue; 31218 } 31219 31220 // *[N]T and *[M]T 31221 // Verify both are single-pointers to arrays. 31222 // Keep the one whose element type can be coerced into. 31223 if (chosen_info.size == .One and 31224 cand_info.size == .One and 31225 chosen_info.pointee_type.zigTypeTag(mod) == .Array and 31226 cand_info.pointee_type.zigTypeTag(mod) == .Array) 31227 { 31228 const chosen_elem_ty = chosen_info.pointee_type.childType(mod); 31229 const cand_elem_ty = cand_info.pointee_type.childType(mod); 31230 31231 const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_elem_ty, cand_elem_ty, chosen_info.mutable, target, src, src); 31232 if (chosen_ok) { 31233 convert_to_slice = true; 31234 continue; 31235 } 31236 31237 const cand_ok = .ok == try sema.coerceInMemoryAllowed(block, cand_elem_ty, chosen_elem_ty, cand_info.mutable, target, src, src); 31238 if (cand_ok) { 31239 convert_to_slice = true; 31240 chosen = candidate; 31241 chosen_i = candidate_i + 1; 31242 continue; 31243 } 31244 31245 // They're both bad. Report error. 31246 // In the future we probably want to use the 31247 // coerceInMemoryAllowed error reporting mechanism, 31248 // however, for now we just fall through for the 31249 // "incompatible types" error below. 31250 } 31251 31252 // [*c]T and any other pointer size 31253 // Whichever element type can coerce to the other one, is 31254 // the one we will keep. If they're both OK then we keep the 31255 // C pointer since it matches both single and many pointers. 31256 if (cand_info.size == .C or chosen_info.size == .C) { 31257 const cand_ok = .ok == try sema.coerceInMemoryAllowed(block, cand_info.pointee_type, chosen_info.pointee_type, cand_info.mutable, target, src, src); 31258 const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_info.pointee_type, cand_info.pointee_type, chosen_info.mutable, target, src, src); 31259 31260 if (cand_ok) { 31261 if (chosen_ok) { 31262 if (chosen_info.size == .C) { 31263 continue; 31264 } else { 31265 chosen = candidate; 31266 chosen_i = candidate_i + 1; 31267 continue; 31268 } 31269 } else { 31270 chosen = candidate; 31271 chosen_i = candidate_i + 1; 31272 continue; 31273 } 31274 } else { 31275 if (chosen_ok) { 31276 continue; 31277 } else { 31278 // They're both bad. Report error. 31279 // In the future we probably want to use the 31280 // coerceInMemoryAllowed error reporting mechanism, 31281 // however, for now we just fall through for the 31282 // "incompatible types" error below. 31283 } 31284 } 31285 } 31286 }, 31287 .Int, .ComptimeInt => { 31288 if (cand_info.size == .C) { 31289 chosen = candidate; 31290 chosen_i = candidate_i + 1; 31291 continue; 31292 } 31293 }, 31294 .Optional => { 31295 const chosen_ptr_ty = chosen_ty.optionalChild(mod); 31296 if (chosen_ptr_ty.zigTypeTag(mod) == .Pointer) { 31297 const chosen_info = chosen_ptr_ty.ptrInfo(mod); 31298 31299 seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; 31300 31301 // *[N]T to ?![*]T 31302 // *[N]T to ?![]T 31303 if (cand_info.size == .One and 31304 cand_info.pointee_type.zigTypeTag(mod) == .Array and 31305 (chosen_info.size == .Many or chosen_info.size == .Slice)) 31306 { 31307 continue; 31308 } 31309 } 31310 }, 31311 .ErrorUnion => { 31312 const chosen_ptr_ty = chosen_ty.errorUnionPayload(mod); 31313 if (chosen_ptr_ty.zigTypeTag(mod) == .Pointer) { 31314 const chosen_info = chosen_ptr_ty.ptrInfo(mod); 31315 31316 seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; 31317 31318 // *[N]T to E![*]T 31319 // *[N]T to E![]T 31320 if (cand_info.size == .One and 31321 cand_info.pointee_type.zigTypeTag(mod) == .Array and 31322 (chosen_info.size == .Many or chosen_info.size == .Slice)) 31323 { 31324 continue; 31325 } 31326 } 31327 }, 31328 .Fn => { 31329 if (!cand_info.mutable and cand_info.pointee_type.zigTypeTag(mod) == .Fn and .ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty, cand_info.pointee_type, target, src, src)) { 31330 chosen = candidate; 31331 chosen_i = candidate_i + 1; 31332 continue; 31333 } 31334 }, 31335 else => {}, 31336 } 31337 }, 31338 .Optional => { 31339 const opt_child_ty = candidate_ty.optionalChild(mod); 31340 if ((try sema.coerceInMemoryAllowed(block, chosen_ty, opt_child_ty, false, target, src, src)) == .ok) { 31341 seen_const = seen_const or opt_child_ty.isConstPtr(mod); 31342 any_are_null = true; 31343 continue; 31344 } 31345 31346 seen_const = seen_const or chosen_ty.isConstPtr(mod); 31347 any_are_null = false; 31348 chosen = candidate; 31349 chosen_i = candidate_i + 1; 31350 continue; 31351 }, 31352 .Vector => switch (chosen_ty_tag) { 31353 .Vector => { 31354 const chosen_len = chosen_ty.vectorLen(mod); 31355 const candidate_len = candidate_ty.vectorLen(mod); 31356 if (chosen_len != candidate_len) 31357 continue; 31358 31359 const chosen_child_ty = chosen_ty.childType(mod); 31360 const candidate_child_ty = candidate_ty.childType(mod); 31361 if (chosen_child_ty.zigTypeTag(mod) == .Int and candidate_child_ty.zigTypeTag(mod) == .Int) { 31362 const chosen_info = chosen_child_ty.intInfo(mod); 31363 const candidate_info = candidate_child_ty.intInfo(mod); 31364 if (chosen_info.bits < candidate_info.bits) { 31365 chosen = candidate; 31366 chosen_i = candidate_i + 1; 31367 } 31368 continue; 31369 } 31370 if (chosen_child_ty.zigTypeTag(mod) == .Float and candidate_child_ty.zigTypeTag(mod) == .Float) { 31371 if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) { 31372 chosen = candidate; 31373 chosen_i = candidate_i + 1; 31374 } 31375 continue; 31376 } 31377 }, 31378 .Array => { 31379 chosen = candidate; 31380 chosen_i = candidate_i + 1; 31381 continue; 31382 }, 31383 else => {}, 31384 }, 31385 .Array => switch (chosen_ty_tag) { 31386 .Vector => continue, 31387 else => {}, 31388 }, 31389 .Fn => if (chosen_ty.isSinglePointer(mod) and chosen_ty.isConstPtr(mod) and chosen_ty.childType(mod).zigTypeTag(mod) == .Fn) { 31390 if (.ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty.childType(mod), candidate_ty, target, src, src)) { 31391 continue; 31392 } 31393 }, 31394 else => {}, 31395 } 31396 31397 switch (chosen_ty_tag) { 31398 .NoReturn, .Undefined => { 31399 chosen = candidate; 31400 chosen_i = candidate_i + 1; 31401 continue; 31402 }, 31403 .Null => { 31404 any_are_null = true; 31405 chosen = candidate; 31406 chosen_i = candidate_i + 1; 31407 continue; 31408 }, 31409 .Optional => { 31410 const opt_child_ty = chosen_ty.optionalChild(mod); 31411 if ((try sema.coerceInMemoryAllowed(block, opt_child_ty, candidate_ty, false, target, src, src)) == .ok) { 31412 continue; 31413 } 31414 if ((try sema.coerceInMemoryAllowed(block, candidate_ty, opt_child_ty, false, target, src, src)) == .ok) { 31415 any_are_null = true; 31416 chosen = candidate; 31417 chosen_i = candidate_i + 1; 31418 continue; 31419 } 31420 }, 31421 .ErrorUnion => { 31422 const payload_ty = chosen_ty.errorUnionPayload(mod); 31423 if ((try sema.coerceInMemoryAllowed(block, payload_ty, candidate_ty, false, target, src, src)) == .ok) { 31424 continue; 31425 } 31426 }, 31427 .ErrorSet => { 31428 chosen = candidate; 31429 chosen_i = candidate_i + 1; 31430 if (err_set_ty) |chosen_set_ty| { 31431 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, chosen_ty, src, src)) { 31432 continue; 31433 } 31434 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_ty, chosen_set_ty, src, src)) { 31435 err_set_ty = chosen_ty; 31436 continue; 31437 } 31438 31439 err_set_ty = try sema.errorSetMerge(chosen_set_ty, chosen_ty); 31440 continue; 31441 } else { 31442 err_set_ty = chosen_ty; 31443 continue; 31444 } 31445 }, 31446 else => {}, 31447 } 31448 31449 // At this point, we hit a compile error. We need to recover 31450 // the source locations. 31451 const chosen_src = candidate_srcs.resolve( 31452 mod, 31453 mod.declPtr(block.src_decl), 31454 chosen_i, 31455 ); 31456 const candidate_src = candidate_srcs.resolve( 31457 mod, 31458 mod.declPtr(block.src_decl), 31459 candidate_i + 1, 31460 ); 31461 31462 const msg = msg: { 31463 const msg = try sema.errMsg(block, src, "incompatible types: '{}' and '{}'", .{ 31464 chosen_ty.fmt(mod), 31465 candidate_ty.fmt(mod), 31466 }); 31467 errdefer msg.destroy(sema.gpa); 31468 31469 if (chosen_src) |src_loc| 31470 try sema.errNote(block, src_loc, msg, "type '{}' here", .{chosen_ty.fmt(mod)}); 31471 31472 if (candidate_src) |src_loc| 31473 try sema.errNote(block, src_loc, msg, "type '{}' here", .{candidate_ty.fmt(mod)}); 31474 31475 break :msg msg; 31476 }; 31477 return sema.failWithOwnedErrorMsg(msg); 31478 } 31479 31480 const chosen_ty = sema.typeOf(chosen); 31481 31482 if (convert_to_slice) { 31483 // turn *[N]T => []T 31484 const chosen_child_ty = chosen_ty.childType(mod); 31485 var info = chosen_ty.ptrInfo(mod); 31486 info.sentinel = chosen_child_ty.sentinel(mod); 31487 info.size = .Slice; 31488 info.mutable = !(seen_const or chosen_child_ty.isConstPtr(mod)); 31489 info.pointee_type = chosen_child_ty.elemType2(mod); 31490 31491 const new_ptr_ty = try Type.ptr(sema.arena, mod, info); 31492 const opt_ptr_ty = if (any_are_null) 31493 try Type.optional(sema.arena, new_ptr_ty, mod) 31494 else 31495 new_ptr_ty; 31496 const set_ty = err_set_ty orelse return opt_ptr_ty; 31497 return try mod.errorUnionType(set_ty, opt_ptr_ty); 31498 } 31499 31500 if (seen_const) { 31501 // turn []T => []const T 31502 switch (chosen_ty.zigTypeTag(mod)) { 31503 .ErrorUnion => { 31504 const ptr_ty = chosen_ty.errorUnionPayload(mod); 31505 var info = ptr_ty.ptrInfo(mod); 31506 info.mutable = false; 31507 const new_ptr_ty = try Type.ptr(sema.arena, mod, info); 31508 const opt_ptr_ty = if (any_are_null) 31509 try Type.optional(sema.arena, new_ptr_ty, mod) 31510 else 31511 new_ptr_ty; 31512 const set_ty = err_set_ty orelse chosen_ty.errorUnionSet(mod); 31513 return try mod.errorUnionType(set_ty, opt_ptr_ty); 31514 }, 31515 .Pointer => { 31516 var info = chosen_ty.ptrInfo(mod); 31517 info.mutable = false; 31518 const new_ptr_ty = try Type.ptr(sema.arena, mod, info); 31519 const opt_ptr_ty = if (any_are_null) 31520 try Type.optional(sema.arena, new_ptr_ty, mod) 31521 else 31522 new_ptr_ty; 31523 const set_ty = err_set_ty orelse return opt_ptr_ty; 31524 return try mod.errorUnionType(set_ty, opt_ptr_ty); 31525 }, 31526 else => return chosen_ty, 31527 } 31528 } 31529 31530 if (any_are_null) { 31531 const opt_ty = switch (chosen_ty.zigTypeTag(mod)) { 31532 .Null, .Optional => chosen_ty, 31533 else => try Type.optional(sema.arena, chosen_ty, mod), 31534 }; 31535 const set_ty = err_set_ty orelse return opt_ty; 31536 return try mod.errorUnionType(set_ty, opt_ty); 31537 } 31538 31539 if (err_set_ty) |ty| switch (chosen_ty.zigTypeTag(mod)) { 31540 .ErrorSet => return ty, 31541 .ErrorUnion => { 31542 const payload_ty = chosen_ty.errorUnionPayload(mod); 31543 return try mod.errorUnionType(ty, payload_ty); 31544 }, 31545 else => return try mod.errorUnionType(ty, chosen_ty), 31546 }; 31547 31548 return chosen_ty; 31549 } 31550 31551 pub fn resolveFnTypes(sema: *Sema, fn_info: InternPool.Key.FuncType) CompileError!void { 31552 const mod = sema.mod; 31553 try sema.resolveTypeFully(fn_info.return_type.toType()); 31554 31555 if (mod.comp.bin_file.options.error_return_tracing and fn_info.return_type.toType().isError(mod)) { 31556 // Ensure the type exists so that backends can assume that. 31557 _ = try sema.getBuiltinType("StackTrace"); 31558 } 31559 31560 for (fn_info.param_types) |param_ty| { 31561 try sema.resolveTypeFully(param_ty.toType()); 31562 } 31563 } 31564 31565 /// Make it so that calling hash() and eql() on `val` will not assert due 31566 /// to a type not having its layout resolved. 31567 fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value { 31568 const mod = sema.mod; 31569 switch (mod.intern_pool.indexToKey(val.toIntern())) { 31570 .int => |int| switch (int.storage) { 31571 .u64, .i64, .big_int => return val, 31572 .lazy_align, .lazy_size => return (try mod.intern(.{ .int = .{ 31573 .ty = int.ty, 31574 .storage = .{ .u64 = (try val.getUnsignedIntAdvanced(mod, sema)).? }, 31575 } })).toValue(), 31576 }, 31577 .ptr => |ptr| { 31578 const resolved_len = switch (ptr.len) { 31579 .none => .none, 31580 else => (try sema.resolveLazyValue(ptr.len.toValue())).toIntern(), 31581 }; 31582 switch (ptr.addr) { 31583 .decl, .mut_decl => return if (resolved_len == ptr.len) 31584 val 31585 else 31586 (try mod.intern(.{ .ptr = .{ 31587 .ty = ptr.ty, 31588 .addr = switch (ptr.addr) { 31589 .decl => |decl| .{ .decl = decl }, 31590 .mut_decl => |mut_decl| .{ .mut_decl = mut_decl }, 31591 else => unreachable, 31592 }, 31593 .len = resolved_len, 31594 } })).toValue(), 31595 .comptime_field => |field_val| { 31596 const resolved_field_val = 31597 (try sema.resolveLazyValue(field_val.toValue())).toIntern(); 31598 return if (resolved_field_val == field_val and resolved_len == ptr.len) 31599 val 31600 else 31601 (try mod.intern(.{ .ptr = .{ 31602 .ty = ptr.ty, 31603 .addr = .{ .comptime_field = resolved_field_val }, 31604 .len = resolved_len, 31605 } })).toValue(); 31606 }, 31607 .int => |int| { 31608 const resolved_int = (try sema.resolveLazyValue(int.toValue())).toIntern(); 31609 return if (resolved_int == int and resolved_len == ptr.len) 31610 val 31611 else 31612 (try mod.intern(.{ .ptr = .{ 31613 .ty = ptr.ty, 31614 .addr = .{ .int = resolved_int }, 31615 .len = resolved_len, 31616 } })).toValue(); 31617 }, 31618 .eu_payload, .opt_payload => |base| { 31619 const resolved_base = (try sema.resolveLazyValue(base.toValue())).toIntern(); 31620 return if (resolved_base == base and resolved_len == ptr.len) 31621 val 31622 else 31623 (try mod.intern(.{ .ptr = .{ 31624 .ty = ptr.ty, 31625 .addr = switch (ptr.addr) { 31626 .eu_payload => .{ .eu_payload = resolved_base }, 31627 .opt_payload => .{ .opt_payload = resolved_base }, 31628 else => unreachable, 31629 }, 31630 .len = ptr.len, 31631 } })).toValue(); 31632 }, 31633 .elem, .field => |base_index| { 31634 const resolved_base = (try sema.resolveLazyValue(base_index.base.toValue())).toIntern(); 31635 return if (resolved_base == base_index.base and resolved_len == ptr.len) 31636 val 31637 else 31638 (try mod.intern(.{ .ptr = .{ 31639 .ty = ptr.ty, 31640 .addr = switch (ptr.addr) { 31641 .elem => .{ .elem = .{ 31642 .base = resolved_base, 31643 .index = base_index.index, 31644 } }, 31645 .field => .{ .field = .{ 31646 .base = resolved_base, 31647 .index = base_index.index, 31648 } }, 31649 else => unreachable, 31650 }, 31651 .len = ptr.len, 31652 } })).toValue(); 31653 }, 31654 } 31655 }, 31656 .aggregate => |aggregate| switch (aggregate.storage) { 31657 .bytes => return val, 31658 .elems => |elems| { 31659 var resolved_elems: []InternPool.Index = &.{}; 31660 for (elems, 0..) |elem, i| { 31661 const resolved_elem = (try sema.resolveLazyValue(elem.toValue())).toIntern(); 31662 if (resolved_elems.len == 0 and resolved_elem != elem) { 31663 resolved_elems = try sema.arena.alloc(InternPool.Index, elems.len); 31664 @memcpy(resolved_elems[0..i], elems[0..i]); 31665 } 31666 if (resolved_elems.len > 0) resolved_elems[i] = resolved_elem; 31667 } 31668 return if (resolved_elems.len == 0) val else (try mod.intern(.{ .aggregate = .{ 31669 .ty = aggregate.ty, 31670 .storage = .{ .elems = resolved_elems }, 31671 } })).toValue(); 31672 }, 31673 .repeated_elem => |elem| { 31674 const resolved_elem = (try sema.resolveLazyValue(elem.toValue())).toIntern(); 31675 return if (resolved_elem == elem) val else (try mod.intern(.{ .aggregate = .{ 31676 .ty = aggregate.ty, 31677 .storage = .{ .repeated_elem = resolved_elem }, 31678 } })).toValue(); 31679 }, 31680 }, 31681 .un => |un| { 31682 const resolved_tag = (try sema.resolveLazyValue(un.tag.toValue())).toIntern(); 31683 const resolved_val = (try sema.resolveLazyValue(un.val.toValue())).toIntern(); 31684 return if (resolved_tag == un.tag and resolved_val == un.val) 31685 val 31686 else 31687 (try mod.intern(.{ .un = .{ 31688 .ty = un.ty, 31689 .tag = resolved_tag, 31690 .val = resolved_val, 31691 } })).toValue(); 31692 }, 31693 else => return val, 31694 } 31695 } 31696 31697 pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void { 31698 const mod = sema.mod; 31699 switch (ty.zigTypeTag(mod)) { 31700 .Struct => return sema.resolveStructLayout(ty), 31701 .Union => return sema.resolveUnionLayout(ty), 31702 .Array => { 31703 if (ty.arrayLenIncludingSentinel(mod) == 0) return; 31704 const elem_ty = ty.childType(mod); 31705 return sema.resolveTypeLayout(elem_ty); 31706 }, 31707 .Optional => { 31708 const payload_ty = ty.optionalChild(mod); 31709 // In case of querying the ABI alignment of this optional, we will ask 31710 // for hasRuntimeBits() of the payload type, so we need "requires comptime" 31711 // to be known already before this function returns. 31712 _ = try sema.typeRequiresComptime(payload_ty); 31713 return sema.resolveTypeLayout(payload_ty); 31714 }, 31715 .ErrorUnion => { 31716 const payload_ty = ty.errorUnionPayload(mod); 31717 return sema.resolveTypeLayout(payload_ty); 31718 }, 31719 .Fn => { 31720 const info = mod.typeToFunc(ty).?; 31721 if (info.is_generic) { 31722 // Resolving of generic function types is deferred to when 31723 // the function is instantiated. 31724 return; 31725 } 31726 for (info.param_types) |param_ty| { 31727 try sema.resolveTypeLayout(param_ty.toType()); 31728 } 31729 try sema.resolveTypeLayout(info.return_type.toType()); 31730 }, 31731 else => {}, 31732 } 31733 } 31734 31735 fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { 31736 const mod = sema.mod; 31737 const resolved_ty = try sema.resolveTypeFields(ty); 31738 if (mod.typeToStruct(resolved_ty)) |struct_obj| { 31739 switch (struct_obj.status) { 31740 .none, .have_field_types => {}, 31741 .field_types_wip, .layout_wip => { 31742 const msg = try Module.ErrorMsg.create( 31743 sema.gpa, 31744 struct_obj.srcLoc(mod), 31745 "struct '{}' depends on itself", 31746 .{ty.fmt(mod)}, 31747 ); 31748 return sema.failWithOwnedErrorMsg(msg); 31749 }, 31750 .have_layout, .fully_resolved_wip, .fully_resolved => return, 31751 } 31752 const prev_status = struct_obj.status; 31753 errdefer if (struct_obj.status == .layout_wip) { 31754 struct_obj.status = prev_status; 31755 }; 31756 31757 struct_obj.status = .layout_wip; 31758 for (struct_obj.fields.values(), 0..) |field, i| { 31759 sema.resolveTypeLayout(field.ty) catch |err| switch (err) { 31760 error.AnalysisFail => { 31761 const msg = sema.err orelse return err; 31762 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); 31763 return err; 31764 }, 31765 else => return err, 31766 }; 31767 } 31768 31769 if (struct_obj.layout == .Packed) { 31770 try semaBackingIntType(mod, struct_obj); 31771 } 31772 31773 struct_obj.status = .have_layout; 31774 _ = try sema.resolveTypeRequiresComptime(resolved_ty); 31775 31776 if (struct_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(resolved_ty))) { 31777 const msg = try Module.ErrorMsg.create( 31778 sema.gpa, 31779 struct_obj.srcLoc(mod), 31780 "struct layout depends on it having runtime bits", 31781 .{}, 31782 ); 31783 return sema.failWithOwnedErrorMsg(msg); 31784 } 31785 31786 if (struct_obj.layout == .Auto and mod.backendSupportsFeature(.field_reordering)) { 31787 const optimized_order = if (struct_obj.owner_decl == sema.owner_decl_index) 31788 try sema.perm_arena.alloc(u32, struct_obj.fields.count()) 31789 else blk: { 31790 const decl = mod.declPtr(struct_obj.owner_decl); 31791 var decl_arena: std.heap.ArenaAllocator = undefined; 31792 const decl_arena_allocator = decl.value_arena.?.acquire(sema.gpa, &decl_arena); 31793 defer decl.value_arena.?.release(&decl_arena); 31794 break :blk try decl_arena_allocator.alloc(u32, struct_obj.fields.count()); 31795 }; 31796 31797 for (struct_obj.fields.values(), 0..) |field, i| { 31798 optimized_order[i] = if (try sema.typeHasRuntimeBits(field.ty)) 31799 @intCast(u32, i) 31800 else 31801 Module.Struct.omitted_field; 31802 } 31803 31804 const AlignSortContext = struct { 31805 struct_obj: *Module.Struct, 31806 sema: *Sema, 31807 31808 fn lessThan(ctx: @This(), a: u32, b: u32) bool { 31809 const m = ctx.sema.mod; 31810 if (a == Module.Struct.omitted_field) return false; 31811 if (b == Module.Struct.omitted_field) return true; 31812 return ctx.struct_obj.fields.values()[a].ty.abiAlignment(m) > 31813 ctx.struct_obj.fields.values()[b].ty.abiAlignment(m); 31814 } 31815 }; 31816 mem.sort(u32, optimized_order, AlignSortContext{ 31817 .struct_obj = struct_obj, 31818 .sema = sema, 31819 }, AlignSortContext.lessThan); 31820 struct_obj.optimized_order = optimized_order.ptr; 31821 } 31822 } 31823 // otherwise it's a tuple; no need to resolve anything 31824 } 31825 31826 fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void { 31827 const gpa = mod.gpa; 31828 31829 var fields_bit_sum: u64 = 0; 31830 for (struct_obj.fields.values()) |field| { 31831 fields_bit_sum += field.ty.bitSize(mod); 31832 } 31833 31834 const decl_index = struct_obj.owner_decl; 31835 const decl = mod.declPtr(decl_index); 31836 var decl_arena: std.heap.ArenaAllocator = undefined; 31837 const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena); 31838 defer decl.value_arena.?.release(&decl_arena); 31839 31840 const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir; 31841 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; 31842 assert(extended.opcode == .struct_decl); 31843 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); 31844 31845 if (small.has_backing_int) { 31846 var extra_index: usize = extended.operand; 31847 extra_index += @boolToInt(small.has_src_node); 31848 extra_index += @boolToInt(small.has_fields_len); 31849 extra_index += @boolToInt(small.has_decls_len); 31850 31851 const backing_int_body_len = zir.extra[extra_index]; 31852 extra_index += 1; 31853 31854 var analysis_arena = std.heap.ArenaAllocator.init(gpa); 31855 defer analysis_arena.deinit(); 31856 31857 var sema: Sema = .{ .mod = mod, .gpa = gpa, .arena = analysis_arena.allocator(), .perm_arena = decl_arena_allocator, .code = zir, .owner_decl = decl, .owner_decl_index = decl_index, .func = null, .func_index = .none, .fn_ret_ty = Type.void, .owner_func = null, .owner_func_index = .none }; 31858 defer sema.deinit(); 31859 31860 var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope); 31861 defer wip_captures.deinit(); 31862 31863 var block: Block = .{ 31864 .parent = null, 31865 .sema = &sema, 31866 .src_decl = decl_index, 31867 .namespace = struct_obj.namespace, 31868 .wip_capture_scope = wip_captures.scope, 31869 .instructions = .{}, 31870 .inlining = null, 31871 .is_comptime = true, 31872 }; 31873 defer { 31874 assert(block.instructions.items.len == 0); 31875 block.params.deinit(gpa); 31876 } 31877 31878 const backing_int_src: LazySrcLoc = .{ .node_offset_container_tag = 0 }; 31879 const backing_int_ty = blk: { 31880 if (backing_int_body_len == 0) { 31881 const backing_int_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 31882 break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref); 31883 } else { 31884 const body = zir.extra[extra_index..][0..backing_int_body_len]; 31885 const ty_ref = try sema.resolveBody(&block, body, struct_obj.zir_index); 31886 break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref); 31887 } 31888 }; 31889 31890 try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum); 31891 struct_obj.backing_int_ty = backing_int_ty; 31892 try wip_captures.finalize(); 31893 } else { 31894 if (fields_bit_sum > std.math.maxInt(u16)) { 31895 var sema: Sema = .{ 31896 .mod = mod, 31897 .gpa = gpa, 31898 .arena = undefined, 31899 .perm_arena = decl_arena_allocator, 31900 .code = zir, 31901 .owner_decl = decl, 31902 .owner_decl_index = decl_index, 31903 .func = null, 31904 .func_index = .none, 31905 .fn_ret_ty = Type.void, 31906 .owner_func = null, 31907 .owner_func_index = .none, 31908 }; 31909 defer sema.deinit(); 31910 31911 var block: Block = .{ 31912 .parent = null, 31913 .sema = &sema, 31914 .src_decl = decl_index, 31915 .namespace = struct_obj.namespace, 31916 .wip_capture_scope = undefined, 31917 .instructions = .{}, 31918 .inlining = null, 31919 .is_comptime = true, 31920 }; 31921 return sema.fail(&block, LazySrcLoc.nodeOffset(0), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum}); 31922 } 31923 struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(u16, fields_bit_sum)); 31924 } 31925 } 31926 31927 fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void { 31928 const mod = sema.mod; 31929 31930 if (!backing_int_ty.isInt(mod)) { 31931 return sema.fail(block, src, "expected backing integer type, found '{}'", .{backing_int_ty.fmt(sema.mod)}); 31932 } 31933 if (backing_int_ty.bitSize(mod) != fields_bit_sum) { 31934 return sema.fail( 31935 block, 31936 src, 31937 "backing integer type '{}' has bit size {} but the struct fields have a total bit size of {}", 31938 .{ backing_int_ty.fmt(sema.mod), backing_int_ty.bitSize(mod), fields_bit_sum }, 31939 ); 31940 } 31941 } 31942 31943 fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { 31944 const mod = sema.mod; 31945 if (!ty.isIndexable(mod)) { 31946 const msg = msg: { 31947 const msg = try sema.errMsg(block, src, "type '{}' does not support indexing", .{ty.fmt(sema.mod)}); 31948 errdefer msg.destroy(sema.gpa); 31949 try sema.errNote(block, src, msg, "operand must be an array, slice, tuple, or vector", .{}); 31950 break :msg msg; 31951 }; 31952 return sema.failWithOwnedErrorMsg(msg); 31953 } 31954 } 31955 31956 fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { 31957 const mod = sema.mod; 31958 if (ty.zigTypeTag(mod) == .Pointer) { 31959 switch (ty.ptrSize(mod)) { 31960 .Slice, .Many, .C => return, 31961 .One => { 31962 const elem_ty = ty.childType(mod); 31963 if (elem_ty.zigTypeTag(mod) == .Array) return; 31964 // TODO https://github.com/ziglang/zig/issues/15479 31965 // if (elem_ty.isTuple()) return; 31966 }, 31967 } 31968 } 31969 const msg = msg: { 31970 const msg = try sema.errMsg(block, src, "type '{}' is not an indexable pointer", .{ty.fmt(sema.mod)}); 31971 errdefer msg.destroy(sema.gpa); 31972 try sema.errNote(block, src, msg, "operand must be a slice, a many pointer or a pointer to an array", .{}); 31973 break :msg msg; 31974 }; 31975 return sema.failWithOwnedErrorMsg(msg); 31976 } 31977 31978 fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { 31979 const mod = sema.mod; 31980 const resolved_ty = try sema.resolveTypeFields(ty); 31981 const union_obj = mod.typeToUnion(resolved_ty).?; 31982 switch (union_obj.status) { 31983 .none, .have_field_types => {}, 31984 .field_types_wip, .layout_wip => { 31985 const msg = try Module.ErrorMsg.create( 31986 sema.gpa, 31987 union_obj.srcLoc(sema.mod), 31988 "union '{}' depends on itself", 31989 .{ty.fmt(sema.mod)}, 31990 ); 31991 return sema.failWithOwnedErrorMsg(msg); 31992 }, 31993 .have_layout, .fully_resolved_wip, .fully_resolved => return, 31994 } 31995 const prev_status = union_obj.status; 31996 errdefer if (union_obj.status == .layout_wip) { 31997 union_obj.status = prev_status; 31998 }; 31999 32000 union_obj.status = .layout_wip; 32001 for (union_obj.fields.values(), 0..) |field, i| { 32002 sema.resolveTypeLayout(field.ty) catch |err| switch (err) { 32003 error.AnalysisFail => { 32004 const msg = sema.err orelse return err; 32005 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); 32006 return err; 32007 }, 32008 else => return err, 32009 }; 32010 } 32011 union_obj.status = .have_layout; 32012 _ = try sema.resolveTypeRequiresComptime(resolved_ty); 32013 32014 if (union_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(resolved_ty))) { 32015 const msg = try Module.ErrorMsg.create( 32016 sema.gpa, 32017 union_obj.srcLoc(sema.mod), 32018 "union layout depends on it having runtime bits", 32019 .{}, 32020 ); 32021 return sema.failWithOwnedErrorMsg(msg); 32022 } 32023 } 32024 32025 // In case of querying the ABI alignment of this struct, we will ask 32026 // for hasRuntimeBits() of each field, so we need "requires comptime" 32027 // to be known already before this function returns. 32028 pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { 32029 const mod = sema.mod; 32030 32031 return switch (ty.toIntern()) { 32032 .empty_struct_type => false, 32033 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { 32034 .int_type => false, 32035 .ptr_type => |ptr_type| { 32036 const child_ty = ptr_type.child.toType(); 32037 if (child_ty.zigTypeTag(mod) == .Fn) { 32038 return mod.typeToFunc(child_ty).?.is_generic; 32039 } else { 32040 return sema.resolveTypeRequiresComptime(child_ty); 32041 } 32042 }, 32043 .anyframe_type => |child| { 32044 if (child == .none) return false; 32045 return sema.resolveTypeRequiresComptime(child.toType()); 32046 }, 32047 .array_type => |array_type| return sema.resolveTypeRequiresComptime(array_type.child.toType()), 32048 .vector_type => |vector_type| return sema.resolveTypeRequiresComptime(vector_type.child.toType()), 32049 .opt_type => |child| return sema.resolveTypeRequiresComptime(child.toType()), 32050 .error_union_type => |error_union_type| return sema.resolveTypeRequiresComptime(error_union_type.payload_type.toType()), 32051 .error_set_type, .inferred_error_set_type => false, 32052 32053 .func_type => true, 32054 32055 .simple_type => |t| switch (t) { 32056 .f16, 32057 .f32, 32058 .f64, 32059 .f80, 32060 .f128, 32061 .usize, 32062 .isize, 32063 .c_char, 32064 .c_short, 32065 .c_ushort, 32066 .c_int, 32067 .c_uint, 32068 .c_long, 32069 .c_ulong, 32070 .c_longlong, 32071 .c_ulonglong, 32072 .c_longdouble, 32073 .anyopaque, 32074 .bool, 32075 .void, 32076 .anyerror, 32077 .noreturn, 32078 .generic_poison, 32079 .atomic_order, 32080 .atomic_rmw_op, 32081 .calling_convention, 32082 .address_space, 32083 .float_mode, 32084 .reduce_op, 32085 .call_modifier, 32086 .prefetch_options, 32087 .export_options, 32088 .extern_options, 32089 => false, 32090 32091 .type, 32092 .comptime_int, 32093 .comptime_float, 32094 .null, 32095 .undefined, 32096 .enum_literal, 32097 .type_info, 32098 => true, 32099 }, 32100 .struct_type => |struct_type| { 32101 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; 32102 switch (struct_obj.requires_comptime) { 32103 .no, .wip => return false, 32104 .yes => return true, 32105 .unknown => { 32106 var requires_comptime = false; 32107 struct_obj.requires_comptime = .wip; 32108 for (struct_obj.fields.values()) |field| { 32109 if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true; 32110 } 32111 if (requires_comptime) { 32112 struct_obj.requires_comptime = .yes; 32113 } else { 32114 struct_obj.requires_comptime = .no; 32115 } 32116 return requires_comptime; 32117 }, 32118 } 32119 }, 32120 32121 .anon_struct_type => |tuple| { 32122 for (tuple.types, tuple.values) |field_ty, field_val| { 32123 const have_comptime_val = field_val != .none; 32124 if (!have_comptime_val and try sema.resolveTypeRequiresComptime(field_ty.toType())) { 32125 return true; 32126 } 32127 } 32128 return false; 32129 }, 32130 32131 .union_type => |union_type| { 32132 const union_obj = mod.unionPtr(union_type.index); 32133 switch (union_obj.requires_comptime) { 32134 .no, .wip => return false, 32135 .yes => return true, 32136 .unknown => { 32137 var requires_comptime = false; 32138 union_obj.requires_comptime = .wip; 32139 for (union_obj.fields.values()) |field| { 32140 if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true; 32141 } 32142 if (requires_comptime) { 32143 union_obj.requires_comptime = .yes; 32144 } else { 32145 union_obj.requires_comptime = .no; 32146 } 32147 return requires_comptime; 32148 }, 32149 } 32150 }, 32151 32152 .opaque_type => false, 32153 32154 .enum_type => |enum_type| try sema.resolveTypeRequiresComptime(enum_type.tag_ty.toType()), 32155 32156 // values, not types 32157 .undef, 32158 .runtime_value, 32159 .simple_value, 32160 .variable, 32161 .extern_func, 32162 .func, 32163 .int, 32164 .err, 32165 .error_union, 32166 .enum_literal, 32167 .enum_tag, 32168 .empty_enum_value, 32169 .float, 32170 .ptr, 32171 .opt, 32172 .aggregate, 32173 .un, 32174 // memoization, not types 32175 .memoized_call, 32176 => unreachable, 32177 }, 32178 }; 32179 } 32180 32181 /// Returns `error.AnalysisFail` if any of the types (recursively) failed to 32182 /// be resolved. 32183 pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { 32184 const mod = sema.mod; 32185 switch (ty.zigTypeTag(mod)) { 32186 .Pointer => { 32187 const child_ty = try sema.resolveTypeFields(ty.childType(mod)); 32188 return sema.resolveTypeFully(child_ty); 32189 }, 32190 .Struct => switch (mod.intern_pool.indexToKey(ty.toIntern())) { 32191 .struct_type => return sema.resolveStructFully(ty), 32192 .anon_struct_type => |tuple| { 32193 for (tuple.types) |field_ty| { 32194 try sema.resolveTypeFully(field_ty.toType()); 32195 } 32196 }, 32197 else => {}, 32198 }, 32199 .Union => return sema.resolveUnionFully(ty), 32200 .Array => return sema.resolveTypeFully(ty.childType(mod)), 32201 .Optional => { 32202 return sema.resolveTypeFully(ty.optionalChild(mod)); 32203 }, 32204 .ErrorUnion => return sema.resolveTypeFully(ty.errorUnionPayload(mod)), 32205 .Fn => { 32206 const info = mod.typeToFunc(ty).?; 32207 if (info.is_generic) { 32208 // Resolving of generic function types is deferred to when 32209 // the function is instantiated. 32210 return; 32211 } 32212 for (info.param_types) |param_ty| { 32213 try sema.resolveTypeFully(param_ty.toType()); 32214 } 32215 try sema.resolveTypeFully(info.return_type.toType()); 32216 }, 32217 else => {}, 32218 } 32219 } 32220 32221 fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void { 32222 try sema.resolveStructLayout(ty); 32223 32224 const mod = sema.mod; 32225 const resolved_ty = try sema.resolveTypeFields(ty); 32226 const struct_obj = mod.typeToStruct(resolved_ty).?; 32227 32228 switch (struct_obj.status) { 32229 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, 32230 .fully_resolved_wip, .fully_resolved => return, 32231 } 32232 32233 { 32234 // After we have resolve struct layout we have to go over the fields again to 32235 // make sure pointer fields get their child types resolved as well. 32236 // See also similar code for unions. 32237 const prev_status = struct_obj.status; 32238 errdefer struct_obj.status = prev_status; 32239 32240 struct_obj.status = .fully_resolved_wip; 32241 for (struct_obj.fields.values()) |field| { 32242 try sema.resolveTypeFully(field.ty); 32243 } 32244 struct_obj.status = .fully_resolved; 32245 } 32246 32247 // And let's not forget comptime-only status. 32248 _ = try sema.typeRequiresComptime(ty); 32249 } 32250 32251 fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { 32252 try sema.resolveUnionLayout(ty); 32253 32254 const mod = sema.mod; 32255 const resolved_ty = try sema.resolveTypeFields(ty); 32256 const union_obj = mod.typeToUnion(resolved_ty).?; 32257 switch (union_obj.status) { 32258 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, 32259 .fully_resolved_wip, .fully_resolved => return, 32260 } 32261 32262 { 32263 // After we have resolve union layout we have to go over the fields again to 32264 // make sure pointer fields get their child types resolved as well. 32265 // See also similar code for structs. 32266 const prev_status = union_obj.status; 32267 errdefer union_obj.status = prev_status; 32268 32269 union_obj.status = .fully_resolved_wip; 32270 for (union_obj.fields.values()) |field| { 32271 try sema.resolveTypeFully(field.ty); 32272 } 32273 union_obj.status = .fully_resolved; 32274 } 32275 32276 // And let's not forget comptime-only status. 32277 _ = try sema.typeRequiresComptime(ty); 32278 } 32279 32280 pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type { 32281 const mod = sema.mod; 32282 32283 switch (ty.toIntern()) { 32284 .var_args_param_type => unreachable, 32285 32286 .none => unreachable, 32287 32288 .u1_type, 32289 .u8_type, 32290 .i8_type, 32291 .u16_type, 32292 .i16_type, 32293 .u29_type, 32294 .u32_type, 32295 .i32_type, 32296 .u64_type, 32297 .i64_type, 32298 .u80_type, 32299 .u128_type, 32300 .i128_type, 32301 .usize_type, 32302 .isize_type, 32303 .c_char_type, 32304 .c_short_type, 32305 .c_ushort_type, 32306 .c_int_type, 32307 .c_uint_type, 32308 .c_long_type, 32309 .c_ulong_type, 32310 .c_longlong_type, 32311 .c_ulonglong_type, 32312 .c_longdouble_type, 32313 .f16_type, 32314 .f32_type, 32315 .f64_type, 32316 .f80_type, 32317 .f128_type, 32318 .anyopaque_type, 32319 .bool_type, 32320 .void_type, 32321 .type_type, 32322 .anyerror_type, 32323 .comptime_int_type, 32324 .comptime_float_type, 32325 .noreturn_type, 32326 .anyframe_type, 32327 .null_type, 32328 .undefined_type, 32329 .enum_literal_type, 32330 .manyptr_u8_type, 32331 .manyptr_const_u8_type, 32332 .manyptr_const_u8_sentinel_0_type, 32333 .single_const_pointer_to_comptime_int_type, 32334 .slice_const_u8_type, 32335 .slice_const_u8_sentinel_0_type, 32336 .anyerror_void_error_union_type, 32337 .generic_poison_type, 32338 .empty_struct_type, 32339 => return ty, 32340 32341 .undef => unreachable, 32342 .zero => unreachable, 32343 .zero_usize => unreachable, 32344 .zero_u8 => unreachable, 32345 .one => unreachable, 32346 .one_usize => unreachable, 32347 .one_u8 => unreachable, 32348 .four_u8 => unreachable, 32349 .negative_one => unreachable, 32350 .calling_convention_c => unreachable, 32351 .calling_convention_inline => unreachable, 32352 .void_value => unreachable, 32353 .unreachable_value => unreachable, 32354 .null_value => unreachable, 32355 .bool_true => unreachable, 32356 .bool_false => unreachable, 32357 .empty_struct => unreachable, 32358 .generic_poison => unreachable, 32359 32360 .type_info_type => return sema.getBuiltinType("Type"), 32361 .extern_options_type => return sema.getBuiltinType("ExternOptions"), 32362 .export_options_type => return sema.getBuiltinType("ExportOptions"), 32363 .atomic_order_type => return sema.getBuiltinType("AtomicOrder"), 32364 .atomic_rmw_op_type => return sema.getBuiltinType("AtomicRmwOp"), 32365 .calling_convention_type => return sema.getBuiltinType("CallingConvention"), 32366 .address_space_type => return sema.getBuiltinType("AddressSpace"), 32367 .float_mode_type => return sema.getBuiltinType("FloatMode"), 32368 .reduce_op_type => return sema.getBuiltinType("ReduceOp"), 32369 .call_modifier_type => return sema.getBuiltinType("CallModifier"), 32370 .prefetch_options_type => return sema.getBuiltinType("PrefetchOptions"), 32371 32372 _ => switch (mod.intern_pool.indexToKey(ty.toIntern())) { 32373 .struct_type => |struct_type| { 32374 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return ty; 32375 try sema.resolveTypeFieldsStruct(ty, struct_obj); 32376 return ty; 32377 }, 32378 .union_type => |union_type| { 32379 const union_obj = mod.unionPtr(union_type.index); 32380 try sema.resolveTypeFieldsUnion(ty, union_obj); 32381 return ty; 32382 }, 32383 32384 else => return ty, 32385 }, 32386 } 32387 } 32388 32389 fn resolveTypeFieldsStruct( 32390 sema: *Sema, 32391 ty: Type, 32392 struct_obj: *Module.Struct, 32393 ) CompileError!void { 32394 switch (sema.mod.declPtr(struct_obj.owner_decl).analysis) { 32395 .file_failure, 32396 .dependency_failure, 32397 .sema_failure, 32398 .sema_failure_retryable, 32399 => { 32400 sema.owner_decl.analysis = .dependency_failure; 32401 sema.owner_decl.generation = sema.mod.generation; 32402 return error.AnalysisFail; 32403 }, 32404 else => {}, 32405 } 32406 switch (struct_obj.status) { 32407 .none => {}, 32408 .field_types_wip => { 32409 const msg = try Module.ErrorMsg.create( 32410 sema.gpa, 32411 struct_obj.srcLoc(sema.mod), 32412 "struct '{}' depends on itself", 32413 .{ty.fmt(sema.mod)}, 32414 ); 32415 return sema.failWithOwnedErrorMsg(msg); 32416 }, 32417 .have_field_types, 32418 .have_layout, 32419 .layout_wip, 32420 .fully_resolved_wip, 32421 .fully_resolved, 32422 => return, 32423 } 32424 32425 struct_obj.status = .field_types_wip; 32426 errdefer struct_obj.status = .none; 32427 try semaStructFields(sema.mod, struct_obj); 32428 } 32429 32430 fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_obj: *Module.Union) CompileError!void { 32431 switch (sema.mod.declPtr(union_obj.owner_decl).analysis) { 32432 .file_failure, 32433 .dependency_failure, 32434 .sema_failure, 32435 .sema_failure_retryable, 32436 => { 32437 sema.owner_decl.analysis = .dependency_failure; 32438 sema.owner_decl.generation = sema.mod.generation; 32439 return error.AnalysisFail; 32440 }, 32441 else => {}, 32442 } 32443 switch (union_obj.status) { 32444 .none => {}, 32445 .field_types_wip => { 32446 const msg = try Module.ErrorMsg.create( 32447 sema.gpa, 32448 union_obj.srcLoc(sema.mod), 32449 "union '{}' depends on itself", 32450 .{ty.fmt(sema.mod)}, 32451 ); 32452 return sema.failWithOwnedErrorMsg(msg); 32453 }, 32454 .have_field_types, 32455 .have_layout, 32456 .layout_wip, 32457 .fully_resolved_wip, 32458 .fully_resolved, 32459 => return, 32460 } 32461 32462 union_obj.status = .field_types_wip; 32463 errdefer union_obj.status = .none; 32464 try semaUnionFields(sema.mod, union_obj); 32465 union_obj.status = .have_field_types; 32466 } 32467 32468 fn resolveInferredErrorSet( 32469 sema: *Sema, 32470 block: *Block, 32471 src: LazySrcLoc, 32472 ies_index: Module.Fn.InferredErrorSet.Index, 32473 ) CompileError!void { 32474 const mod = sema.mod; 32475 const ies = mod.inferredErrorSetPtr(ies_index); 32476 32477 if (ies.is_resolved) return; 32478 32479 const func = mod.funcPtr(ies.func); 32480 if (func.state == .in_progress) { 32481 return sema.fail(block, src, "unable to resolve inferred error set", .{}); 32482 } 32483 32484 // In order to ensure that all dependencies are properly added to the set, we 32485 // need to ensure the function body is analyzed of the inferred error set. 32486 // However, in the case of comptime/inline function calls with inferred error sets, 32487 // each call gets a new InferredErrorSet object, which contains the same 32488 // `Module.Fn.Index`. Not only is the function not relevant to the inferred error set 32489 // in this case, it may be a generic function which would cause an assertion failure 32490 // if we called `ensureFuncBodyAnalyzed` on it here. 32491 const ies_func_owner_decl = mod.declPtr(func.owner_decl); 32492 const ies_func_info = mod.typeToFunc(ies_func_owner_decl.ty).?; 32493 // if ies declared by a inline function with generic return type, the return_type should be generic_poison, 32494 // because inline function does not create a new declaration, and the ies has been filled with analyzeCall, 32495 // so here we can simply skip this case. 32496 if (ies_func_info.return_type == .generic_poison_type) { 32497 assert(ies_func_info.cc == .Inline); 32498 } else if (mod.typeToInferredErrorSet(ies_func_info.return_type.toType().errorUnionSet(mod)).? == ies) { 32499 if (ies_func_info.is_generic) { 32500 const msg = msg: { 32501 const msg = try sema.errMsg(block, src, "unable to resolve inferred error set of generic function", .{}); 32502 errdefer msg.destroy(sema.gpa); 32503 32504 try sema.mod.errNoteNonLazy(ies_func_owner_decl.srcLoc(mod), msg, "generic function declared here", .{}); 32505 break :msg msg; 32506 }; 32507 return sema.failWithOwnedErrorMsg(msg); 32508 } 32509 // In this case we are dealing with the actual InferredErrorSet object that 32510 // corresponds to the function, not one created to track an inline/comptime call. 32511 try sema.ensureFuncBodyAnalyzed(ies.func); 32512 } 32513 32514 ies.is_resolved = true; 32515 32516 for (ies.inferred_error_sets.keys()) |other_ies_index| { 32517 if (ies_index == other_ies_index) continue; 32518 try sema.resolveInferredErrorSet(block, src, other_ies_index); 32519 32520 const other_ies = mod.inferredErrorSetPtr(other_ies_index); 32521 for (other_ies.errors.keys()) |key| { 32522 try ies.errors.put(sema.gpa, key, {}); 32523 } 32524 if (other_ies.is_anyerror) 32525 ies.is_anyerror = true; 32526 } 32527 } 32528 32529 fn resolveInferredErrorSetTy( 32530 sema: *Sema, 32531 block: *Block, 32532 src: LazySrcLoc, 32533 ty: Type, 32534 ) CompileError!void { 32535 const mod = sema.mod; 32536 if (mod.typeToInferredErrorSetIndex(ty).unwrap()) |ies_index| { 32537 try sema.resolveInferredErrorSet(block, src, ies_index); 32538 } 32539 } 32540 32541 fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void { 32542 const gpa = mod.gpa; 32543 const decl_index = struct_obj.owner_decl; 32544 const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir; 32545 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; 32546 assert(extended.opcode == .struct_decl); 32547 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); 32548 var extra_index: usize = extended.operand; 32549 32550 const src = LazySrcLoc.nodeOffset(0); 32551 extra_index += @boolToInt(small.has_src_node); 32552 32553 const fields_len = if (small.has_fields_len) blk: { 32554 const fields_len = zir.extra[extra_index]; 32555 extra_index += 1; 32556 break :blk fields_len; 32557 } else 0; 32558 32559 const decls_len = if (small.has_decls_len) decls_len: { 32560 const decls_len = zir.extra[extra_index]; 32561 extra_index += 1; 32562 break :decls_len decls_len; 32563 } else 0; 32564 32565 // The backing integer cannot be handled until `resolveStructLayout()`. 32566 if (small.has_backing_int) { 32567 const backing_int_body_len = zir.extra[extra_index]; 32568 extra_index += 1; // backing_int_body_len 32569 if (backing_int_body_len == 0) { 32570 extra_index += 1; // backing_int_ref 32571 } else { 32572 extra_index += backing_int_body_len; // backing_int_body_inst 32573 } 32574 } 32575 32576 // Skip over decls. 32577 var decls_it = zir.declIteratorInner(extra_index, decls_len); 32578 while (decls_it.next()) |_| {} 32579 extra_index = decls_it.extra_index; 32580 32581 if (fields_len == 0) { 32582 if (struct_obj.layout == .Packed) { 32583 try semaBackingIntType(mod, struct_obj); 32584 } 32585 struct_obj.status = .have_layout; 32586 return; 32587 } 32588 32589 const decl = mod.declPtr(decl_index); 32590 var decl_arena: std.heap.ArenaAllocator = undefined; 32591 const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena); 32592 defer decl.value_arena.?.release(&decl_arena); 32593 32594 var analysis_arena = std.heap.ArenaAllocator.init(gpa); 32595 defer analysis_arena.deinit(); 32596 32597 var sema: Sema = .{ 32598 .mod = mod, 32599 .gpa = gpa, 32600 .arena = analysis_arena.allocator(), 32601 .perm_arena = decl_arena_allocator, 32602 .code = zir, 32603 .owner_decl = decl, 32604 .owner_decl_index = decl_index, 32605 .func = null, 32606 .func_index = .none, 32607 .fn_ret_ty = Type.void, 32608 .owner_func = null, 32609 .owner_func_index = .none, 32610 }; 32611 defer sema.deinit(); 32612 32613 var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope); 32614 defer wip_captures.deinit(); 32615 32616 var block_scope: Block = .{ 32617 .parent = null, 32618 .sema = &sema, 32619 .src_decl = decl_index, 32620 .namespace = struct_obj.namespace, 32621 .wip_capture_scope = wip_captures.scope, 32622 .instructions = .{}, 32623 .inlining = null, 32624 .is_comptime = true, 32625 }; 32626 defer { 32627 assert(block_scope.instructions.items.len == 0); 32628 block_scope.params.deinit(gpa); 32629 } 32630 32631 struct_obj.fields = .{}; 32632 try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len); 32633 32634 const Field = struct { 32635 type_body_len: u32 = 0, 32636 align_body_len: u32 = 0, 32637 init_body_len: u32 = 0, 32638 type_ref: Zir.Inst.Ref = .none, 32639 }; 32640 const fields = try sema.arena.alloc(Field, fields_len); 32641 var any_inits = false; 32642 32643 { 32644 const bits_per_field = 4; 32645 const fields_per_u32 = 32 / bits_per_field; 32646 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; 32647 const flags_index = extra_index; 32648 var bit_bag_index: usize = flags_index; 32649 extra_index += bit_bags_count; 32650 var cur_bit_bag: u32 = undefined; 32651 var field_i: u32 = 0; 32652 while (field_i < fields_len) : (field_i += 1) { 32653 if (field_i % fields_per_u32 == 0) { 32654 cur_bit_bag = zir.extra[bit_bag_index]; 32655 bit_bag_index += 1; 32656 } 32657 const has_align = @truncate(u1, cur_bit_bag) != 0; 32658 cur_bit_bag >>= 1; 32659 const has_init = @truncate(u1, cur_bit_bag) != 0; 32660 cur_bit_bag >>= 1; 32661 const is_comptime = @truncate(u1, cur_bit_bag) != 0; 32662 cur_bit_bag >>= 1; 32663 const has_type_body = @truncate(u1, cur_bit_bag) != 0; 32664 cur_bit_bag >>= 1; 32665 32666 var field_name_zir: ?[:0]const u8 = null; 32667 if (!small.is_tuple) { 32668 field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]); 32669 extra_index += 1; 32670 } 32671 extra_index += 1; // doc_comment 32672 32673 fields[field_i] = .{}; 32674 32675 if (has_type_body) { 32676 fields[field_i].type_body_len = zir.extra[extra_index]; 32677 } else { 32678 fields[field_i].type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 32679 } 32680 extra_index += 1; 32681 32682 // This string needs to outlive the ZIR code. 32683 const field_name = if (field_name_zir) |some| 32684 try decl_arena_allocator.dupe(u8, some) 32685 else 32686 try std.fmt.allocPrint(decl_arena_allocator, "{d}", .{field_i}); 32687 32688 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); 32689 if (gop.found_existing) { 32690 const msg = msg: { 32691 const field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = field_i }).lazy; 32692 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name}); 32693 errdefer msg.destroy(gpa); 32694 32695 const prev_field_index = struct_obj.fields.getIndex(field_name).?; 32696 const prev_field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = prev_field_index }); 32697 try mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{}); 32698 try sema.errNote(&block_scope, src, msg, "struct declared here", .{}); 32699 break :msg msg; 32700 }; 32701 return sema.failWithOwnedErrorMsg(msg); 32702 } 32703 gop.value_ptr.* = .{ 32704 .ty = Type.noreturn, 32705 .abi_align = 0, 32706 .default_val = Value.@"unreachable", 32707 .is_comptime = is_comptime, 32708 .offset = undefined, 32709 }; 32710 32711 if (has_align) { 32712 fields[field_i].align_body_len = zir.extra[extra_index]; 32713 extra_index += 1; 32714 } 32715 if (has_init) { 32716 fields[field_i].init_body_len = zir.extra[extra_index]; 32717 extra_index += 1; 32718 any_inits = true; 32719 } 32720 } 32721 } 32722 32723 // Next we do only types and alignments, saving the inits for a second pass, 32724 // so that init values may depend on type layout. 32725 const bodies_index = extra_index; 32726 32727 for (fields, 0..) |zir_field, field_i| { 32728 const field_ty: Type = ty: { 32729 if (zir_field.type_ref != .none) { 32730 break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) { 32731 error.NeededSourceLocation => { 32732 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ 32733 .index = field_i, 32734 .range = .type, 32735 }).lazy; 32736 _ = try sema.resolveType(&block_scope, ty_src, zir_field.type_ref); 32737 unreachable; 32738 }, 32739 else => |e| return e, 32740 }; 32741 } 32742 assert(zir_field.type_body_len != 0); 32743 const body = zir.extra[extra_index..][0..zir_field.type_body_len]; 32744 extra_index += body.len; 32745 const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); 32746 break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) { 32747 error.NeededSourceLocation => { 32748 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ 32749 .index = field_i, 32750 .range = .type, 32751 }).lazy; 32752 _ = try sema.analyzeAsType(&block_scope, ty_src, ty_ref); 32753 unreachable; 32754 }, 32755 else => |e| return e, 32756 }; 32757 }; 32758 if (field_ty.isGenericPoison()) { 32759 return error.GenericPoison; 32760 } 32761 32762 const field = &struct_obj.fields.values()[field_i]; 32763 field.ty = field_ty; 32764 32765 if (field_ty.zigTypeTag(mod) == .Opaque) { 32766 const msg = msg: { 32767 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ 32768 .index = field_i, 32769 .range = .type, 32770 }).lazy; 32771 const msg = try sema.errMsg(&block_scope, ty_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); 32772 errdefer msg.destroy(sema.gpa); 32773 32774 try sema.addDeclaredHereNote(msg, field_ty); 32775 break :msg msg; 32776 }; 32777 return sema.failWithOwnedErrorMsg(msg); 32778 } 32779 if (field_ty.zigTypeTag(mod) == .NoReturn) { 32780 const msg = msg: { 32781 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ 32782 .index = field_i, 32783 .range = .type, 32784 }).lazy; 32785 const msg = try sema.errMsg(&block_scope, ty_src, "struct fields cannot be 'noreturn'", .{}); 32786 errdefer msg.destroy(sema.gpa); 32787 32788 try sema.addDeclaredHereNote(msg, field_ty); 32789 break :msg msg; 32790 }; 32791 return sema.failWithOwnedErrorMsg(msg); 32792 } 32793 if (struct_obj.layout == .Extern and !try sema.validateExternType(field.ty, .struct_field)) { 32794 const msg = msg: { 32795 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ 32796 .index = field_i, 32797 .range = .type, 32798 }); 32799 const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)}); 32800 errdefer msg.destroy(sema.gpa); 32801 32802 try sema.explainWhyTypeIsNotExtern(msg, ty_src, field.ty, .struct_field); 32803 32804 try sema.addDeclaredHereNote(msg, field.ty); 32805 break :msg msg; 32806 }; 32807 return sema.failWithOwnedErrorMsg(msg); 32808 } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty, mod))) { 32809 const msg = msg: { 32810 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ 32811 .index = field_i, 32812 .range = .type, 32813 }); 32814 const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)}); 32815 errdefer msg.destroy(sema.gpa); 32816 32817 try sema.explainWhyTypeIsNotPacked(msg, ty_src, field.ty); 32818 32819 try sema.addDeclaredHereNote(msg, field.ty); 32820 break :msg msg; 32821 }; 32822 return sema.failWithOwnedErrorMsg(msg); 32823 } 32824 32825 if (zir_field.align_body_len > 0) { 32826 const body = zir.extra[extra_index..][0..zir_field.align_body_len]; 32827 extra_index += body.len; 32828 const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); 32829 field.abi_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) { 32830 error.NeededSourceLocation => { 32831 const align_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ 32832 .index = field_i, 32833 .range = .alignment, 32834 }).lazy; 32835 _ = try sema.analyzeAsAlign(&block_scope, align_src, align_ref); 32836 unreachable; 32837 }, 32838 else => |e| return e, 32839 }; 32840 } 32841 32842 extra_index += zir_field.init_body_len; 32843 } 32844 32845 struct_obj.status = .have_field_types; 32846 32847 if (any_inits) { 32848 extra_index = bodies_index; 32849 for (fields, 0..) |zir_field, field_i| { 32850 extra_index += zir_field.type_body_len; 32851 extra_index += zir_field.align_body_len; 32852 if (zir_field.init_body_len > 0) { 32853 const body = zir.extra[extra_index..][0..zir_field.init_body_len]; 32854 extra_index += body.len; 32855 const init = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); 32856 const field = &struct_obj.fields.values()[field_i]; 32857 const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) { 32858 error.NeededSourceLocation => { 32859 const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ 32860 .index = field_i, 32861 .range = .value, 32862 }).lazy; 32863 _ = try sema.coerce(&block_scope, field.ty, init, init_src); 32864 unreachable; 32865 }, 32866 else => |e| return e, 32867 }; 32868 const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { 32869 const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ 32870 .index = field_i, 32871 .range = .value, 32872 }).lazy; 32873 return sema.failWithNeededComptime(&block_scope, init_src, "struct field default value must be comptime-known"); 32874 }; 32875 field.default_val = try default_val.copy(decl_arena_allocator); 32876 } 32877 } 32878 } 32879 try wip_captures.finalize(); 32880 32881 struct_obj.have_field_inits = true; 32882 } 32883 32884 fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { 32885 const tracy = trace(@src()); 32886 defer tracy.end(); 32887 32888 const gpa = mod.gpa; 32889 const decl_index = union_obj.owner_decl; 32890 const zir = mod.namespacePtr(union_obj.namespace).file_scope.zir; 32891 const extended = zir.instructions.items(.data)[union_obj.zir_index].extended; 32892 assert(extended.opcode == .union_decl); 32893 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); 32894 var extra_index: usize = extended.operand; 32895 32896 const src = LazySrcLoc.nodeOffset(0); 32897 extra_index += @boolToInt(small.has_src_node); 32898 32899 const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: { 32900 const ty_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 32901 extra_index += 1; 32902 break :blk ty_ref; 32903 } else .none; 32904 32905 const body_len = if (small.has_body_len) blk: { 32906 const body_len = zir.extra[extra_index]; 32907 extra_index += 1; 32908 break :blk body_len; 32909 } else 0; 32910 32911 const fields_len = if (small.has_fields_len) blk: { 32912 const fields_len = zir.extra[extra_index]; 32913 extra_index += 1; 32914 break :blk fields_len; 32915 } else 0; 32916 32917 const decls_len = if (small.has_decls_len) decls_len: { 32918 const decls_len = zir.extra[extra_index]; 32919 extra_index += 1; 32920 break :decls_len decls_len; 32921 } else 0; 32922 32923 // Skip over decls. 32924 var decls_it = zir.declIteratorInner(extra_index, decls_len); 32925 while (decls_it.next()) |_| {} 32926 extra_index = decls_it.extra_index; 32927 32928 const body = zir.extra[extra_index..][0..body_len]; 32929 extra_index += body.len; 32930 32931 const decl = mod.declPtr(decl_index); 32932 var decl_arena: std.heap.ArenaAllocator = undefined; 32933 const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena); 32934 defer decl.value_arena.?.release(&decl_arena); 32935 32936 var analysis_arena = std.heap.ArenaAllocator.init(gpa); 32937 defer analysis_arena.deinit(); 32938 32939 var sema: Sema = .{ 32940 .mod = mod, 32941 .gpa = gpa, 32942 .arena = analysis_arena.allocator(), 32943 .perm_arena = decl_arena_allocator, 32944 .code = zir, 32945 .owner_decl = decl, 32946 .owner_decl_index = decl_index, 32947 .func = null, 32948 .func_index = .none, 32949 .fn_ret_ty = Type.void, 32950 .owner_func = null, 32951 .owner_func_index = .none, 32952 }; 32953 defer sema.deinit(); 32954 32955 var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope); 32956 defer wip_captures.deinit(); 32957 32958 var block_scope: Block = .{ 32959 .parent = null, 32960 .sema = &sema, 32961 .src_decl = decl_index, 32962 .namespace = union_obj.namespace, 32963 .wip_capture_scope = wip_captures.scope, 32964 .instructions = .{}, 32965 .inlining = null, 32966 .is_comptime = true, 32967 }; 32968 defer { 32969 assert(block_scope.instructions.items.len == 0); 32970 block_scope.params.deinit(gpa); 32971 } 32972 32973 if (body.len != 0) { 32974 try sema.analyzeBody(&block_scope, body); 32975 } 32976 32977 try wip_captures.finalize(); 32978 32979 try union_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len); 32980 32981 var int_tag_ty: Type = undefined; 32982 var enum_field_names: []InternPool.NullTerminatedString = &.{}; 32983 var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{}; 32984 var explicit_tags_seen: []bool = &.{}; 32985 var explicit_enum_info: ?InternPool.Key.EnumType = null; 32986 if (tag_type_ref != .none) { 32987 const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x }; 32988 const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref); 32989 if (small.auto_enum_tag) { 32990 // The provided type is an integer type and we must construct the enum tag type here. 32991 int_tag_ty = provided_ty; 32992 if (int_tag_ty.zigTypeTag(mod) != .Int and int_tag_ty.zigTypeTag(mod) != .ComptimeInt) { 32993 return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{}'", .{int_tag_ty.fmt(mod)}); 32994 } 32995 32996 if (fields_len > 0) { 32997 const field_count_val = try mod.intValue(int_tag_ty, fields_len - 1); 32998 if (!(try sema.intFitsInType(field_count_val, int_tag_ty, null))) { 32999 const msg = msg: { 33000 const msg = try sema.errMsg(&block_scope, tag_ty_src, "specified integer tag type cannot represent every field", .{}); 33001 errdefer msg.destroy(sema.gpa); 33002 try sema.errNote(&block_scope, tag_ty_src, msg, "type '{}' cannot fit values in range 0...{d}", .{ 33003 int_tag_ty.fmt(mod), 33004 fields_len - 1, 33005 }); 33006 break :msg msg; 33007 }; 33008 return sema.failWithOwnedErrorMsg(msg); 33009 } 33010 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len); 33011 try enum_field_vals.ensureTotalCapacity(sema.arena, fields_len); 33012 } 33013 } else { 33014 // The provided type is the enum tag type. 33015 union_obj.tag_ty = provided_ty; 33016 const enum_type = switch (mod.intern_pool.indexToKey(union_obj.tag_ty.toIntern())) { 33017 .enum_type => |x| x, 33018 else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(mod)}), 33019 }; 33020 // The fields of the union must match the enum exactly. 33021 // A flag per field is used to check for missing and extraneous fields. 33022 explicit_enum_info = enum_type; 33023 explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len); 33024 @memset(explicit_tags_seen, false); 33025 } 33026 } else { 33027 // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis 33028 // purposes, we still auto-generate an enum tag type the same way. That the union is 33029 // untagged is represented by the Type tag (union vs union_tagged). 33030 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len); 33031 } 33032 33033 const bits_per_field = 4; 33034 const fields_per_u32 = 32 / bits_per_field; 33035 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; 33036 var bit_bag_index: usize = extra_index; 33037 extra_index += bit_bags_count; 33038 var cur_bit_bag: u32 = undefined; 33039 var field_i: u32 = 0; 33040 var last_tag_val: ?Value = null; 33041 while (field_i < fields_len) : (field_i += 1) { 33042 if (field_i % fields_per_u32 == 0) { 33043 cur_bit_bag = zir.extra[bit_bag_index]; 33044 bit_bag_index += 1; 33045 } 33046 const has_type = @truncate(u1, cur_bit_bag) != 0; 33047 cur_bit_bag >>= 1; 33048 const has_align = @truncate(u1, cur_bit_bag) != 0; 33049 cur_bit_bag >>= 1; 33050 const has_tag = @truncate(u1, cur_bit_bag) != 0; 33051 cur_bit_bag >>= 1; 33052 const unused = @truncate(u1, cur_bit_bag) != 0; 33053 cur_bit_bag >>= 1; 33054 _ = unused; 33055 33056 const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]); 33057 extra_index += 1; 33058 33059 // doc_comment 33060 extra_index += 1; 33061 33062 const field_type_ref: Zir.Inst.Ref = if (has_type) blk: { 33063 const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 33064 extra_index += 1; 33065 break :blk field_type_ref; 33066 } else .none; 33067 33068 const align_ref: Zir.Inst.Ref = if (has_align) blk: { 33069 const align_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 33070 extra_index += 1; 33071 break :blk align_ref; 33072 } else .none; 33073 33074 const tag_ref: Air.Inst.Ref = if (has_tag) blk: { 33075 const tag_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 33076 extra_index += 1; 33077 break :blk try sema.resolveInst(tag_ref); 33078 } else .none; 33079 33080 if (enum_field_vals.capacity() > 0) { 33081 const enum_tag_val = if (tag_ref != .none) blk: { 33082 const val = sema.semaUnionFieldVal(&block_scope, .unneeded, int_tag_ty, tag_ref) catch |err| switch (err) { 33083 error.NeededSourceLocation => { 33084 const val_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ 33085 .index = field_i, 33086 .range = .value, 33087 }).lazy; 33088 _ = try sema.semaUnionFieldVal(&block_scope, val_src, int_tag_ty, tag_ref); 33089 unreachable; 33090 }, 33091 else => |e| return e, 33092 }; 33093 last_tag_val = val; 33094 33095 break :blk val; 33096 } else blk: { 33097 const val = if (last_tag_val) |val| 33098 try sema.intAdd(val, Value.one_comptime_int, int_tag_ty) 33099 else 33100 try mod.intValue(int_tag_ty, 0); 33101 last_tag_val = val; 33102 33103 break :blk val; 33104 }; 33105 const gop = enum_field_vals.getOrPutAssumeCapacity(enum_tag_val.toIntern()); 33106 if (gop.found_existing) { 33107 const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy; 33108 const other_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = gop.index }).lazy; 33109 const msg = msg: { 33110 const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{enum_tag_val.fmtValue(int_tag_ty, mod)}); 33111 errdefer msg.destroy(gpa); 33112 try sema.errNote(&block_scope, other_field_src, msg, "other occurrence here", .{}); 33113 break :msg msg; 33114 }; 33115 return sema.failWithOwnedErrorMsg(msg); 33116 } 33117 } 33118 33119 // This string needs to outlive the ZIR code. 33120 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir); 33121 const field_name_ip = try mod.intern_pool.getOrPutString(gpa, field_name); 33122 if (enum_field_names.len != 0) { 33123 enum_field_names[field_i] = field_name_ip; 33124 } 33125 33126 const field_ty: Type = if (!has_type) 33127 Type.void 33128 else if (field_type_ref == .none) 33129 Type.noreturn 33130 else 33131 sema.resolveType(&block_scope, .unneeded, field_type_ref) catch |err| switch (err) { 33132 error.NeededSourceLocation => { 33133 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ 33134 .index = field_i, 33135 .range = .type, 33136 }).lazy; 33137 _ = try sema.resolveType(&block_scope, ty_src, field_type_ref); 33138 unreachable; 33139 }, 33140 else => |e| return e, 33141 }; 33142 33143 if (field_ty.isGenericPoison()) { 33144 return error.GenericPoison; 33145 } 33146 33147 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); 33148 if (gop.found_existing) { 33149 const msg = msg: { 33150 const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy; 33151 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name}); 33152 errdefer msg.destroy(gpa); 33153 33154 const prev_field_index = union_obj.fields.getIndex(field_name).?; 33155 const prev_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = prev_field_index }).lazy; 33156 try mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl, mod), msg, "other field here", .{}); 33157 try sema.errNote(&block_scope, src, msg, "union declared here", .{}); 33158 break :msg msg; 33159 }; 33160 return sema.failWithOwnedErrorMsg(msg); 33161 } 33162 33163 if (explicit_enum_info) |tag_info| { 33164 const enum_index = tag_info.nameIndex(&mod.intern_pool, field_name_ip) orelse { 33165 const msg = msg: { 33166 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ 33167 .index = field_i, 33168 .range = .type, 33169 }).lazy; 33170 const msg = try sema.errMsg(&block_scope, ty_src, "no field named '{s}' in enum '{}'", .{ 33171 field_name, union_obj.tag_ty.fmt(mod), 33172 }); 33173 errdefer msg.destroy(sema.gpa); 33174 try sema.addDeclaredHereNote(msg, union_obj.tag_ty); 33175 break :msg msg; 33176 }; 33177 return sema.failWithOwnedErrorMsg(msg); 33178 }; 33179 // No check for duplicate because the check already happened in order 33180 // to create the enum type in the first place. 33181 assert(!explicit_tags_seen[enum_index]); 33182 explicit_tags_seen[enum_index] = true; 33183 } 33184 33185 if (field_ty.zigTypeTag(mod) == .Opaque) { 33186 const msg = msg: { 33187 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ 33188 .index = field_i, 33189 .range = .type, 33190 }).lazy; 33191 const msg = try sema.errMsg(&block_scope, ty_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{}); 33192 errdefer msg.destroy(sema.gpa); 33193 33194 try sema.addDeclaredHereNote(msg, field_ty); 33195 break :msg msg; 33196 }; 33197 return sema.failWithOwnedErrorMsg(msg); 33198 } 33199 if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) { 33200 const msg = msg: { 33201 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ 33202 .index = field_i, 33203 .range = .type, 33204 }); 33205 const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)}); 33206 errdefer msg.destroy(sema.gpa); 33207 33208 try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .union_field); 33209 33210 try sema.addDeclaredHereNote(msg, field_ty); 33211 break :msg msg; 33212 }; 33213 return sema.failWithOwnedErrorMsg(msg); 33214 } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) { 33215 const msg = msg: { 33216 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ 33217 .index = field_i, 33218 .range = .type, 33219 }); 33220 const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)}); 33221 errdefer msg.destroy(sema.gpa); 33222 33223 try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty); 33224 33225 try sema.addDeclaredHereNote(msg, field_ty); 33226 break :msg msg; 33227 }; 33228 return sema.failWithOwnedErrorMsg(msg); 33229 } 33230 33231 gop.value_ptr.* = .{ 33232 .ty = field_ty, 33233 .abi_align = 0, 33234 }; 33235 33236 if (align_ref != .none) { 33237 gop.value_ptr.abi_align = sema.resolveAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) { 33238 error.NeededSourceLocation => { 33239 const align_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ 33240 .index = field_i, 33241 .range = .alignment, 33242 }).lazy; 33243 _ = try sema.resolveAlign(&block_scope, align_src, align_ref); 33244 unreachable; 33245 }, 33246 else => |e| return e, 33247 }; 33248 } else { 33249 gop.value_ptr.abi_align = 0; 33250 } 33251 } 33252 33253 if (explicit_enum_info) |tag_info| { 33254 if (tag_info.names.len > fields_len) { 33255 const msg = msg: { 33256 const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{}); 33257 errdefer msg.destroy(sema.gpa); 33258 33259 const enum_ty = union_obj.tag_ty; 33260 for (tag_info.names, 0..) |field_name, field_index| { 33261 if (explicit_tags_seen[field_index]) continue; 33262 try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{ 33263 mod.intern_pool.stringToSlice(field_name), 33264 }); 33265 } 33266 try sema.addDeclaredHereNote(msg, union_obj.tag_ty); 33267 break :msg msg; 33268 }; 33269 return sema.failWithOwnedErrorMsg(msg); 33270 } 33271 } else if (enum_field_vals.count() > 0) { 33272 union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), union_obj); 33273 } else { 33274 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_obj); 33275 } 33276 } 33277 33278 fn semaUnionFieldVal(sema: *Sema, block: *Block, src: LazySrcLoc, int_tag_ty: Type, tag_ref: Air.Inst.Ref) CompileError!Value { 33279 const coerced = try sema.coerce(block, int_tag_ty, tag_ref, src); 33280 return sema.resolveConstValue(block, src, coerced, "enum tag value must be comptime-known"); 33281 } 33282 33283 fn generateUnionTagTypeNumbered( 33284 sema: *Sema, 33285 block: *Block, 33286 enum_field_names: []const InternPool.NullTerminatedString, 33287 enum_field_vals: []const InternPool.Index, 33288 union_obj: *Module.Union, 33289 ) !Type { 33290 const mod = sema.mod; 33291 33292 const src_decl = mod.declPtr(block.src_decl); 33293 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); 33294 errdefer mod.destroyDecl(new_decl_index); 33295 const name = name: { 33296 const fqn = try union_obj.getFullyQualifiedName(mod); 33297 defer sema.gpa.free(fqn); 33298 break :name try std.fmt.allocPrintZ(sema.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn}); 33299 }; 33300 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{ 33301 .ty = Type.type, 33302 .val = undefined, 33303 }, name); 33304 errdefer mod.abortAnonDecl(new_decl_index); 33305 33306 const new_decl = mod.declPtr(new_decl_index); 33307 new_decl.name_fully_qualified = true; 33308 new_decl.owns_tv = true; 33309 new_decl.name_fully_qualified = true; 33310 33311 const enum_ty = try mod.intern(.{ .enum_type = .{ 33312 .decl = new_decl_index, 33313 .namespace = .none, 33314 .tag_ty = if (enum_field_vals.len == 0) 33315 (try mod.intType(.unsigned, 0)).toIntern() 33316 else 33317 mod.intern_pool.typeOf(enum_field_vals[0]), 33318 .names = enum_field_names, 33319 .values = enum_field_vals, 33320 .tag_mode = .explicit, 33321 } }); 33322 33323 new_decl.val = enum_ty.toValue(); 33324 33325 try mod.finalizeAnonDecl(new_decl_index); 33326 return enum_ty.toType(); 33327 } 33328 33329 fn generateUnionTagTypeSimple( 33330 sema: *Sema, 33331 block: *Block, 33332 enum_field_names: []const InternPool.NullTerminatedString, 33333 maybe_union_obj: ?*Module.Union, 33334 ) !Type { 33335 const mod = sema.mod; 33336 33337 const new_decl_index = new_decl_index: { 33338 const union_obj = maybe_union_obj orelse { 33339 break :new_decl_index try mod.createAnonymousDecl(block, .{ 33340 .ty = Type.type, 33341 .val = undefined, 33342 }); 33343 }; 33344 const src_decl = mod.declPtr(block.src_decl); 33345 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); 33346 errdefer mod.destroyDecl(new_decl_index); 33347 const name = name: { 33348 const fqn = try union_obj.getFullyQualifiedName(mod); 33349 defer sema.gpa.free(fqn); 33350 break :name try std.fmt.allocPrintZ(sema.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn}); 33351 }; 33352 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{ 33353 .ty = Type.type, 33354 .val = undefined, 33355 }, name); 33356 mod.declPtr(new_decl_index).name_fully_qualified = true; 33357 break :new_decl_index new_decl_index; 33358 }; 33359 errdefer mod.abortAnonDecl(new_decl_index); 33360 33361 const enum_ty = try mod.intern(.{ .enum_type = .{ 33362 .decl = new_decl_index, 33363 .namespace = .none, 33364 .tag_ty = if (enum_field_names.len == 0) 33365 (try mod.intType(.unsigned, 0)).toIntern() 33366 else 33367 (try mod.smallestUnsignedInt(enum_field_names.len - 1)).toIntern(), 33368 .names = enum_field_names, 33369 .values = &.{}, 33370 .tag_mode = .auto, 33371 } }); 33372 33373 const new_decl = mod.declPtr(new_decl_index); 33374 new_decl.owns_tv = true; 33375 new_decl.val = enum_ty.toValue(); 33376 33377 try mod.finalizeAnonDecl(new_decl_index); 33378 return enum_ty.toType(); 33379 } 33380 33381 fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { 33382 var wip_captures = try WipCaptureScope.init(sema.gpa, sema.owner_decl.src_scope); 33383 defer wip_captures.deinit(); 33384 33385 var block: Block = .{ 33386 .parent = null, 33387 .sema = sema, 33388 .src_decl = sema.owner_decl_index, 33389 .namespace = sema.owner_decl.src_namespace, 33390 .wip_capture_scope = wip_captures.scope, 33391 .instructions = .{}, 33392 .inlining = null, 33393 .is_comptime = true, 33394 }; 33395 defer { 33396 block.instructions.deinit(sema.gpa); 33397 block.params.deinit(sema.gpa); 33398 } 33399 const src = LazySrcLoc.nodeOffset(0); 33400 33401 const mod = sema.mod; 33402 const std_pkg = mod.main_pkg.table.get("std").?; 33403 const std_file = (mod.importPkg(std_pkg) catch unreachable).file; 33404 const opt_builtin_inst = (try sema.namespaceLookupRef( 33405 &block, 33406 src, 33407 mod.declPtr(std_file.root_decl.unwrap().?).src_namespace, 33408 "builtin", 33409 )) orelse @panic("lib/std.zig is corrupt and missing 'builtin'"); 33410 const builtin_inst = try sema.analyzeLoad(&block, src, opt_builtin_inst, src); 33411 const builtin_ty = sema.analyzeAsType(&block, src, builtin_inst) catch |err| switch (err) { 33412 error.AnalysisFail => std.debug.panic("std.builtin is corrupt", .{}), 33413 else => |e| return e, 33414 }; 33415 const opt_ty_decl = (try sema.namespaceLookup( 33416 &block, 33417 src, 33418 builtin_ty.getNamespaceIndex(mod).unwrap().?, 33419 name, 33420 )) orelse std.debug.panic("lib/std/builtin.zig is corrupt and missing '{s}'", .{name}); 33421 return sema.analyzeDeclVal(&block, src, opt_ty_decl); 33422 } 33423 33424 fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type { 33425 const ty_inst = try sema.getBuiltin(name); 33426 33427 var wip_captures = try WipCaptureScope.init(sema.gpa, sema.owner_decl.src_scope); 33428 defer wip_captures.deinit(); 33429 33430 var block: Block = .{ 33431 .parent = null, 33432 .sema = sema, 33433 .src_decl = sema.owner_decl_index, 33434 .namespace = sema.owner_decl.src_namespace, 33435 .wip_capture_scope = wip_captures.scope, 33436 .instructions = .{}, 33437 .inlining = null, 33438 .is_comptime = true, 33439 }; 33440 defer { 33441 block.instructions.deinit(sema.gpa); 33442 block.params.deinit(sema.gpa); 33443 } 33444 const src = LazySrcLoc.nodeOffset(0); 33445 33446 const result_ty = sema.analyzeAsType(&block, src, ty_inst) catch |err| switch (err) { 33447 error.AnalysisFail => std.debug.panic("std.builtin.{s} is corrupt", .{name}), 33448 else => |e| return e, 33449 }; 33450 try sema.resolveTypeFully(result_ty); // Should not fail 33451 return result_ty; 33452 } 33453 33454 /// There is another implementation of this in `Type.onePossibleValue`. This one 33455 /// in `Sema` is for calling during semantic analysis, and performs field resolution 33456 /// to get the answer. The one in `Type` is for calling during codegen and asserts 33457 /// that the types are already resolved. 33458 /// TODO assert the return value matches `ty.onePossibleValue` 33459 pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { 33460 const mod = sema.mod; 33461 return switch (ty.toIntern()) { 33462 .empty_struct_type => Value.empty_struct, 33463 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { 33464 .int_type => |int_type| { 33465 if (int_type.bits == 0) { 33466 return try mod.intValue(ty, 0); 33467 } else { 33468 return null; 33469 } 33470 }, 33471 33472 .ptr_type, 33473 .error_union_type, 33474 .func_type, 33475 .anyframe_type, 33476 .error_set_type, 33477 .inferred_error_set_type, 33478 => null, 33479 33480 inline .array_type, .vector_type => |seq_type, seq_tag| { 33481 const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none; 33482 if (seq_type.len + @boolToInt(has_sentinel) == 0) return (try mod.intern(.{ .aggregate = .{ 33483 .ty = ty.toIntern(), 33484 .storage = .{ .elems = &.{} }, 33485 } })).toValue(); 33486 33487 if (try sema.typeHasOnePossibleValue(seq_type.child.toType())) |opv| { 33488 return (try mod.intern(.{ .aggregate = .{ 33489 .ty = ty.toIntern(), 33490 .storage = .{ .repeated_elem = opv.toIntern() }, 33491 } })).toValue(); 33492 } 33493 return null; 33494 }, 33495 .opt_type => |child| { 33496 if (child == .noreturn_type) { 33497 return try mod.nullValue(ty); 33498 } else { 33499 return null; 33500 } 33501 }, 33502 33503 .simple_type => |t| switch (t) { 33504 .f16, 33505 .f32, 33506 .f64, 33507 .f80, 33508 .f128, 33509 .usize, 33510 .isize, 33511 .c_char, 33512 .c_short, 33513 .c_ushort, 33514 .c_int, 33515 .c_uint, 33516 .c_long, 33517 .c_ulong, 33518 .c_longlong, 33519 .c_ulonglong, 33520 .c_longdouble, 33521 .anyopaque, 33522 .bool, 33523 .type, 33524 .anyerror, 33525 .comptime_int, 33526 .comptime_float, 33527 .enum_literal, 33528 .atomic_order, 33529 .atomic_rmw_op, 33530 .calling_convention, 33531 .address_space, 33532 .float_mode, 33533 .reduce_op, 33534 .call_modifier, 33535 .prefetch_options, 33536 .export_options, 33537 .extern_options, 33538 .type_info, 33539 => null, 33540 33541 .void => Value.void, 33542 .noreturn => Value.@"unreachable", 33543 .null => Value.null, 33544 .undefined => Value.undef, 33545 33546 .generic_poison => return error.GenericPoison, 33547 }, 33548 .struct_type => |struct_type| { 33549 const resolved_ty = try sema.resolveTypeFields(ty); 33550 if (mod.structPtrUnwrap(struct_type.index)) |s| { 33551 const field_vals = try sema.arena.alloc(InternPool.Index, s.fields.count()); 33552 for (field_vals, s.fields.values(), 0..) |*field_val, field, i| { 33553 if (field.is_comptime) { 33554 field_val.* = try field.default_val.intern(field.ty, mod); 33555 continue; 33556 } 33557 if (field.ty.eql(resolved_ty, sema.mod)) { 33558 const msg = try Module.ErrorMsg.create( 33559 sema.gpa, 33560 s.srcLoc(sema.mod), 33561 "struct '{}' depends on itself", 33562 .{ty.fmt(sema.mod)}, 33563 ); 33564 try sema.addFieldErrNote(resolved_ty, i, msg, "while checking this field", .{}); 33565 return sema.failWithOwnedErrorMsg(msg); 33566 } 33567 if (try sema.typeHasOnePossibleValue(field.ty)) |field_opv| { 33568 field_val.* = try field_opv.intern(field.ty, mod); 33569 } else return null; 33570 } 33571 33572 // In this case the struct has no runtime-known fields and 33573 // therefore has one possible value. 33574 return (try mod.intern(.{ .aggregate = .{ 33575 .ty = ty.toIntern(), 33576 .storage = .{ .elems = field_vals }, 33577 } })).toValue(); 33578 } 33579 33580 // In this case the struct has no fields at all and 33581 // therefore has one possible value. 33582 return (try mod.intern(.{ .aggregate = .{ 33583 .ty = ty.toIntern(), 33584 .storage = .{ .elems = &.{} }, 33585 } })).toValue(); 33586 }, 33587 33588 .anon_struct_type => |tuple| { 33589 for (tuple.values) |val| { 33590 if (val == .none) return null; 33591 } 33592 // In this case the struct has all comptime-known fields and 33593 // therefore has one possible value. 33594 return (try mod.intern(.{ .aggregate = .{ 33595 .ty = ty.toIntern(), 33596 .storage = .{ .elems = tuple.values }, 33597 } })).toValue(); 33598 }, 33599 33600 .union_type => |union_type| { 33601 const resolved_ty = try sema.resolveTypeFields(ty); 33602 const union_obj = mod.unionPtr(union_type.index); 33603 const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse 33604 return null; 33605 const fields = union_obj.fields.values(); 33606 if (fields.len == 0) { 33607 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() }); 33608 return only.toValue(); 33609 } 33610 const only_field = fields[0]; 33611 if (only_field.ty.eql(resolved_ty, sema.mod)) { 33612 const msg = try Module.ErrorMsg.create( 33613 sema.gpa, 33614 union_obj.srcLoc(sema.mod), 33615 "union '{}' depends on itself", 33616 .{ty.fmt(sema.mod)}, 33617 ); 33618 try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{}); 33619 return sema.failWithOwnedErrorMsg(msg); 33620 } 33621 const val_val = (try sema.typeHasOnePossibleValue(only_field.ty)) orelse 33622 return null; 33623 const only = try mod.intern(.{ .un = .{ 33624 .ty = resolved_ty.toIntern(), 33625 .tag = tag_val.toIntern(), 33626 .val = val_val.toIntern(), 33627 } }); 33628 return only.toValue(); 33629 }, 33630 .opaque_type => null, 33631 .enum_type => |enum_type| switch (enum_type.tag_mode) { 33632 .nonexhaustive => { 33633 if (enum_type.tag_ty == .comptime_int_type) return null; 33634 33635 if (try sema.typeHasOnePossibleValue(enum_type.tag_ty.toType())) |int_opv| { 33636 const only = try mod.intern(.{ .enum_tag = .{ 33637 .ty = ty.toIntern(), 33638 .int = int_opv.toIntern(), 33639 } }); 33640 return only.toValue(); 33641 } 33642 33643 return null; 33644 }, 33645 .auto, .explicit => { 33646 if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null; 33647 33648 switch (enum_type.names.len) { 33649 0 => { 33650 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() }); 33651 return only.toValue(); 33652 }, 33653 1 => return try mod.getCoerced((if (enum_type.values.len == 0) 33654 try mod.intern(.{ .int = .{ 33655 .ty = enum_type.tag_ty, 33656 .storage = .{ .u64 = 0 }, 33657 } }) 33658 else 33659 enum_type.values[0]).toValue(), ty), 33660 else => return null, 33661 } 33662 }, 33663 }, 33664 33665 // values, not types 33666 .undef, 33667 .runtime_value, 33668 .simple_value, 33669 .variable, 33670 .extern_func, 33671 .func, 33672 .int, 33673 .err, 33674 .error_union, 33675 .enum_literal, 33676 .enum_tag, 33677 .empty_enum_value, 33678 .float, 33679 .ptr, 33680 .opt, 33681 .aggregate, 33682 .un, 33683 // memoization, not types 33684 .memoized_call, 33685 => unreachable, 33686 }, 33687 }; 33688 } 33689 33690 /// Returns the type of the AIR instruction. 33691 fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type { 33692 return sema.getTmpAir().typeOf(inst, &sema.mod.intern_pool); 33693 } 33694 33695 pub fn getTmpAir(sema: Sema) Air { 33696 return .{ 33697 .instructions = sema.air_instructions.slice(), 33698 .extra = sema.air_extra.items, 33699 }; 33700 } 33701 33702 pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref { 33703 if (@enumToInt(ty.toIntern()) < Air.ref_start_index) 33704 return @intToEnum(Air.Inst.Ref, @enumToInt(ty.toIntern())); 33705 try sema.air_instructions.append(sema.gpa, .{ 33706 .tag = .interned, 33707 .data = .{ .interned = ty.toIntern() }, 33708 }); 33709 return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); 33710 } 33711 33712 fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref { 33713 const mod = sema.mod; 33714 return sema.addConstant(ty, try mod.intValue(ty, int)); 33715 } 33716 33717 fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref { 33718 return sema.addConstant(ty, (try sema.mod.intern(.{ .undef = ty.toIntern() })).toValue()); 33719 } 33720 33721 pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref { 33722 const mod = sema.mod; 33723 const gpa = sema.gpa; 33724 33725 // This assertion can be removed when the `ty` parameter is removed from 33726 // this function thanks to the InternPool transition being complete. 33727 if (std.debug.runtime_safety) { 33728 const val_ty = mod.intern_pool.typeOf(val.toIntern()); 33729 if (ty.toIntern() != val_ty) { 33730 std.debug.panic("addConstant type mismatch: '{}' vs '{}'\n", .{ 33731 ty.fmt(mod), val_ty.toType().fmt(mod), 33732 }); 33733 } 33734 } 33735 if (@enumToInt(val.toIntern()) < Air.ref_start_index) 33736 return @intToEnum(Air.Inst.Ref, @enumToInt(val.toIntern())); 33737 try sema.air_instructions.append(gpa, .{ 33738 .tag = .interned, 33739 .data = .{ .interned = val.toIntern() }, 33740 }); 33741 return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); 33742 } 33743 33744 pub fn addExtra(sema: *Sema, extra: anytype) Allocator.Error!u32 { 33745 const fields = std.meta.fields(@TypeOf(extra)); 33746 try sema.air_extra.ensureUnusedCapacity(sema.gpa, fields.len); 33747 return sema.addExtraAssumeCapacity(extra); 33748 } 33749 33750 pub fn addExtraAssumeCapacity(sema: *Sema, extra: anytype) u32 { 33751 const fields = std.meta.fields(@TypeOf(extra)); 33752 const result = @intCast(u32, sema.air_extra.items.len); 33753 inline for (fields) |field| { 33754 sema.air_extra.appendAssumeCapacity(switch (field.type) { 33755 u32 => @field(extra, field.name), 33756 Air.Inst.Ref => @enumToInt(@field(extra, field.name)), 33757 i32 => @bitCast(u32, @field(extra, field.name)), 33758 InternPool.Index => @enumToInt(@field(extra, field.name)), 33759 else => @compileError("bad field type: " ++ @typeName(field.type)), 33760 }); 33761 } 33762 return result; 33763 } 33764 33765 fn appendRefsAssumeCapacity(sema: *Sema, refs: []const Air.Inst.Ref) void { 33766 const coerced = @ptrCast([]const u32, refs); 33767 sema.air_extra.appendSliceAssumeCapacity(coerced); 33768 } 33769 33770 fn getBreakBlock(sema: *Sema, inst_index: Air.Inst.Index) ?Air.Inst.Index { 33771 const air_datas = sema.air_instructions.items(.data); 33772 const air_tags = sema.air_instructions.items(.tag); 33773 switch (air_tags[inst_index]) { 33774 .br => return air_datas[inst_index].br.block_inst, 33775 else => return null, 33776 } 33777 } 33778 33779 fn isComptimeKnown( 33780 sema: *Sema, 33781 inst: Air.Inst.Ref, 33782 ) !bool { 33783 return (try sema.resolveMaybeUndefVal(inst)) != null; 33784 } 33785 33786 fn analyzeComptimeAlloc( 33787 sema: *Sema, 33788 block: *Block, 33789 var_type: Type, 33790 alignment: u32, 33791 ) CompileError!Air.Inst.Ref { 33792 // Needed to make an anon decl with type `var_type` (the `finish()` call below). 33793 _ = try sema.typeHasOnePossibleValue(var_type); 33794 33795 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{ 33796 .pointee_type = var_type, 33797 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant), 33798 .@"align" = alignment, 33799 }); 33800 33801 var anon_decl = try block.startAnonDecl(); 33802 defer anon_decl.deinit(); 33803 33804 const decl_index = try anon_decl.finish( 33805 var_type, 33806 // There will be stores before the first load, but they may be to sub-elements or 33807 // sub-fields. So we need to initialize with undef to allow the mechanism to expand 33808 // into fields/elements and have those overridden with stored values. 33809 (try sema.mod.intern(.{ .undef = var_type.toIntern() })).toValue(), 33810 alignment, 33811 ); 33812 const decl = sema.mod.declPtr(decl_index); 33813 decl.@"align" = alignment; 33814 33815 try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index); 33816 return sema.addConstant(ptr_type, (try sema.mod.intern(.{ .ptr = .{ 33817 .ty = ptr_type.toIntern(), 33818 .addr = .{ .mut_decl = .{ 33819 .decl = decl_index, 33820 .runtime_index = block.runtime_index, 33821 } }, 33822 } })).toValue()); 33823 } 33824 33825 /// The places where a user can specify an address space attribute 33826 pub const AddressSpaceContext = enum { 33827 /// A function is specified to be placed in a certain address space. 33828 function, 33829 33830 /// A (global) variable is specified to be placed in a certain address space. 33831 /// In contrast to .constant, these values (and thus the address space they will be 33832 /// placed in) are required to be mutable. 33833 variable, 33834 33835 /// A (global) constant value is specified to be placed in a certain address space. 33836 /// In contrast to .variable, values placed in this address space are not required to be mutable. 33837 constant, 33838 33839 /// A pointer is ascripted to point into a certain address space. 33840 pointer, 33841 }; 33842 33843 pub fn analyzeAddressSpace( 33844 sema: *Sema, 33845 block: *Block, 33846 src: LazySrcLoc, 33847 zir_ref: Zir.Inst.Ref, 33848 ctx: AddressSpaceContext, 33849 ) !std.builtin.AddressSpace { 33850 const mod = sema.mod; 33851 const addrspace_tv = try sema.resolveInstConst(block, src, zir_ref, "addresspace must be comptime-known"); 33852 const address_space = mod.toEnum(std.builtin.AddressSpace, addrspace_tv.val); 33853 const target = sema.mod.getTarget(); 33854 const arch = target.cpu.arch; 33855 33856 const is_nv = arch == .nvptx or arch == .nvptx64; 33857 const is_amd = arch == .amdgcn; 33858 const is_spirv = arch == .spirv32 or arch == .spirv64; 33859 const is_gpu = is_nv or is_amd or is_spirv; 33860 33861 const supported = switch (address_space) { 33862 // TODO: on spir-v only when os is opencl. 33863 .generic => true, 33864 .gs, .fs, .ss => (arch == .x86 or arch == .x86_64) and ctx == .pointer, 33865 // TODO: check that .shared and .local are left uninitialized 33866 .param => is_nv, 33867 .global, .shared, .local => is_gpu, 33868 .constant => is_gpu and (ctx == .constant), 33869 // TODO this should also check how many flash banks the cpu has 33870 .flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr, 33871 }; 33872 33873 if (!supported) { 33874 // TODO error messages could be made more elaborate here 33875 const entity = switch (ctx) { 33876 .function => "functions", 33877 .variable => "mutable values", 33878 .constant => "constant values", 33879 .pointer => "pointers", 33880 }; 33881 return sema.fail( 33882 block, 33883 src, 33884 "{s} with address space '{s}' are not supported on {s}", 33885 .{ entity, @tagName(address_space), arch.genericName() }, 33886 ); 33887 } 33888 33889 return address_space; 33890 } 33891 33892 /// Asserts the value is a pointer and dereferences it. 33893 /// Returns `null` if the pointer contents cannot be loaded at comptime. 33894 fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value { 33895 const mod = sema.mod; 33896 const load_ty = ptr_ty.childType(mod); 33897 const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty); 33898 switch (res) { 33899 .runtime_load => return null, 33900 .val => |v| return v, 33901 .needed_well_defined => |ty| return sema.fail( 33902 block, 33903 src, 33904 "comptime dereference requires '{}' to have a well-defined layout, but it does not.", 33905 .{ty.fmt(sema.mod)}, 33906 ), 33907 .out_of_bounds => |ty| return sema.fail( 33908 block, 33909 src, 33910 "dereference of '{}' exceeds bounds of containing decl of type '{}'", 33911 .{ ptr_ty.fmt(sema.mod), ty.fmt(sema.mod) }, 33912 ), 33913 } 33914 } 33915 33916 const DerefResult = union(enum) { 33917 runtime_load, 33918 val: Value, 33919 needed_well_defined: Type, 33920 out_of_bounds: Type, 33921 }; 33922 33923 fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type) CompileError!DerefResult { 33924 const mod = sema.mod; 33925 const target = mod.getTarget(); 33926 const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) { 33927 error.RuntimeLoad => return DerefResult{ .runtime_load = {} }, 33928 else => |e| return e, 33929 }; 33930 33931 if (deref.pointee) |tv| { 33932 const coerce_in_mem_ok = 33933 (try sema.coerceInMemoryAllowed(block, load_ty, tv.ty, false, target, src, src)) == .ok or 33934 (try sema.coerceInMemoryAllowed(block, tv.ty, load_ty, false, target, src, src)) == .ok; 33935 if (coerce_in_mem_ok) { 33936 // We have a Value that lines up in virtual memory exactly with what we want to load, 33937 // and it is in-memory coercible to load_ty. It may be returned without modifications. 33938 // Move mutable decl values to the InternPool and assert other decls are already in the InternPool. 33939 return .{ .val = (if (deref.is_mutable) try tv.val.intern(tv.ty, mod) else tv.val.toIntern()).toValue() }; 33940 } 33941 } 33942 33943 // The type is not in-memory coercible or the direct dereference failed, so it must 33944 // be bitcast according to the pointer type we are performing the load through. 33945 if (!load_ty.hasWellDefinedLayout(mod)) { 33946 return DerefResult{ .needed_well_defined = load_ty }; 33947 } 33948 33949 const load_sz = try sema.typeAbiSize(load_ty); 33950 33951 // Try the smaller bit-cast first, since that's more efficient than using the larger `parent` 33952 if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(tv.ty)) 33953 return DerefResult{ .val = (try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0)) orelse return .runtime_load }; 33954 33955 // If that fails, try to bit-cast from the largest parent value with a well-defined layout 33956 if (deref.parent) |parent| if (load_sz + parent.byte_offset <= try sema.typeAbiSize(parent.tv.ty)) 33957 return DerefResult{ .val = (try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset)) orelse return .runtime_load }; 33958 33959 if (deref.ty_without_well_defined_layout) |bad_ty| { 33960 // We got no parent for bit-casting, or the parent we got was too small. Either way, the problem 33961 // is that some type we encountered when de-referencing does not have a well-defined layout. 33962 return DerefResult{ .needed_well_defined = bad_ty }; 33963 } else { 33964 // If all encountered types had well-defined layouts, the parent is the root decl and it just 33965 // wasn't big enough for the load. 33966 return DerefResult{ .out_of_bounds = deref.parent.?.tv.ty }; 33967 } 33968 } 33969 33970 /// Used to convert a u64 value to a usize value, emitting a compile error if the number 33971 /// is too big to fit. 33972 fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError!usize { 33973 if (@bitSizeOf(u64) <= @bitSizeOf(usize)) return int; 33974 return std.math.cast(usize, int) orelse return sema.fail(block, src, "expression produces integer value '{d}' which is too big for this compiler implementation to handle", .{int}); 33975 } 33976 33977 /// For pointer-like optionals, it returns the pointer type. For pointers, 33978 /// the type is returned unmodified. 33979 /// This can return `error.AnalysisFail` because it sometimes requires resolving whether 33980 /// a type has zero bits, which can cause a "foo depends on itself" compile error. 33981 /// This logic must be kept in sync with `Type.isPtrLikeOptional`. 33982 fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type { 33983 const mod = sema.mod; 33984 return switch (mod.intern_pool.indexToKey(ty.toIntern())) { 33985 .ptr_type => |ptr_type| switch (ptr_type.flags.size) { 33986 .One, .Many, .C => ty, 33987 .Slice => null, 33988 }, 33989 .opt_type => |opt_child| switch (mod.intern_pool.indexToKey(opt_child)) { 33990 .ptr_type => |ptr_type| switch (ptr_type.flags.size) { 33991 .Slice, .C => null, 33992 .Many, .One => { 33993 if (ptr_type.flags.is_allowzero) return null; 33994 33995 // optionals of zero sized types behave like bools, not pointers 33996 const payload_ty = opt_child.toType(); 33997 if ((try sema.typeHasOnePossibleValue(payload_ty)) != null) { 33998 return null; 33999 } 34000 34001 return payload_ty; 34002 }, 34003 }, 34004 else => null, 34005 }, 34006 else => null, 34007 }; 34008 } 34009 34010 /// `generic_poison` will return false. 34011 /// This function returns false negatives when structs and unions are having their 34012 /// field types resolved. 34013 /// TODO assert the return value matches `ty.comptimeOnly` 34014 /// TODO merge these implementations together with the "advanced"/opt_sema pattern seen 34015 /// elsewhere in value.zig 34016 pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { 34017 const mod = sema.mod; 34018 return switch (ty.toIntern()) { 34019 .empty_struct_type => false, 34020 34021 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { 34022 .int_type => return false, 34023 .ptr_type => |ptr_type| { 34024 const child_ty = ptr_type.child.toType(); 34025 if (child_ty.zigTypeTag(mod) == .Fn) { 34026 return mod.typeToFunc(child_ty).?.is_generic; 34027 } else { 34028 return sema.typeRequiresComptime(child_ty); 34029 } 34030 }, 34031 .anyframe_type => |child| { 34032 if (child == .none) return false; 34033 return sema.typeRequiresComptime(child.toType()); 34034 }, 34035 .array_type => |array_type| return sema.typeRequiresComptime(array_type.child.toType()), 34036 .vector_type => |vector_type| return sema.typeRequiresComptime(vector_type.child.toType()), 34037 .opt_type => |child| return sema.typeRequiresComptime(child.toType()), 34038 34039 .error_union_type => |error_union_type| { 34040 return sema.typeRequiresComptime(error_union_type.payload_type.toType()); 34041 }, 34042 34043 .error_set_type, .inferred_error_set_type => false, 34044 34045 .func_type => true, 34046 34047 .simple_type => |t| return switch (t) { 34048 .f16, 34049 .f32, 34050 .f64, 34051 .f80, 34052 .f128, 34053 .usize, 34054 .isize, 34055 .c_char, 34056 .c_short, 34057 .c_ushort, 34058 .c_int, 34059 .c_uint, 34060 .c_long, 34061 .c_ulong, 34062 .c_longlong, 34063 .c_ulonglong, 34064 .c_longdouble, 34065 .anyopaque, 34066 .bool, 34067 .void, 34068 .anyerror, 34069 .noreturn, 34070 .generic_poison, 34071 .atomic_order, 34072 .atomic_rmw_op, 34073 .calling_convention, 34074 .address_space, 34075 .float_mode, 34076 .reduce_op, 34077 .call_modifier, 34078 .prefetch_options, 34079 .export_options, 34080 .extern_options, 34081 => false, 34082 34083 .type, 34084 .comptime_int, 34085 .comptime_float, 34086 .null, 34087 .undefined, 34088 .enum_literal, 34089 .type_info, 34090 => true, 34091 }, 34092 .struct_type => |struct_type| { 34093 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; 34094 switch (struct_obj.requires_comptime) { 34095 .no, .wip => return false, 34096 .yes => return true, 34097 .unknown => { 34098 if (struct_obj.status == .field_types_wip) 34099 return false; 34100 34101 try sema.resolveTypeFieldsStruct(ty, struct_obj); 34102 34103 struct_obj.requires_comptime = .wip; 34104 for (struct_obj.fields.values()) |field| { 34105 if (field.is_comptime) continue; 34106 if (try sema.typeRequiresComptime(field.ty)) { 34107 struct_obj.requires_comptime = .yes; 34108 return true; 34109 } 34110 } 34111 struct_obj.requires_comptime = .no; 34112 return false; 34113 }, 34114 } 34115 }, 34116 .anon_struct_type => |tuple| { 34117 for (tuple.types, tuple.values) |field_ty, val| { 34118 const have_comptime_val = val != .none; 34119 if (!have_comptime_val and try sema.typeRequiresComptime(field_ty.toType())) { 34120 return true; 34121 } 34122 } 34123 return false; 34124 }, 34125 34126 .union_type => |union_type| { 34127 const union_obj = mod.unionPtr(union_type.index); 34128 switch (union_obj.requires_comptime) { 34129 .no, .wip => return false, 34130 .yes => return true, 34131 .unknown => { 34132 if (union_obj.status == .field_types_wip) 34133 return false; 34134 34135 try sema.resolveTypeFieldsUnion(ty, union_obj); 34136 34137 union_obj.requires_comptime = .wip; 34138 for (union_obj.fields.values()) |field| { 34139 if (try sema.typeRequiresComptime(field.ty)) { 34140 union_obj.requires_comptime = .yes; 34141 return true; 34142 } 34143 } 34144 union_obj.requires_comptime = .no; 34145 return false; 34146 }, 34147 } 34148 }, 34149 34150 .opaque_type => false, 34151 .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()), 34152 34153 // values, not types 34154 .undef, 34155 .runtime_value, 34156 .simple_value, 34157 .variable, 34158 .extern_func, 34159 .func, 34160 .int, 34161 .err, 34162 .error_union, 34163 .enum_literal, 34164 .enum_tag, 34165 .empty_enum_value, 34166 .float, 34167 .ptr, 34168 .opt, 34169 .aggregate, 34170 .un, 34171 // memoization, not types 34172 .memoized_call, 34173 => unreachable, 34174 }, 34175 }; 34176 } 34177 34178 pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { 34179 const mod = sema.mod; 34180 return ty.hasRuntimeBitsAdvanced(mod, false, .{ .sema = sema }) catch |err| switch (err) { 34181 error.NeedLazy => unreachable, 34182 else => |e| return e, 34183 }; 34184 } 34185 34186 fn typeAbiSize(sema: *Sema, ty: Type) !u64 { 34187 try sema.resolveTypeLayout(ty); 34188 return ty.abiSize(sema.mod); 34189 } 34190 34191 fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!u32 { 34192 return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar; 34193 } 34194 34195 /// Not valid to call for packed unions. 34196 /// Keep implementation in sync with `Module.Union.Field.normalAlignment`. 34197 fn unionFieldAlignment(sema: *Sema, field: Module.Union.Field) !u32 { 34198 const mod = sema.mod; 34199 if (field.ty.zigTypeTag(mod) == .NoReturn) { 34200 return @as(u32, 0); 34201 } else if (field.abi_align == 0) { 34202 return sema.typeAbiAlignment(field.ty); 34203 } else { 34204 return field.abi_align; 34205 } 34206 } 34207 34208 /// Synchronize logic with `Type.isFnOrHasRuntimeBits`. 34209 pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { 34210 const mod = sema.mod; 34211 const fn_info = mod.typeToFunc(ty).?; 34212 if (fn_info.is_generic) return false; 34213 if (fn_info.is_var_args) return true; 34214 switch (fn_info.cc) { 34215 // If there was a comptime calling convention, it should also return false here. 34216 .Inline => return false, 34217 else => {}, 34218 } 34219 if (try sema.typeRequiresComptime(fn_info.return_type.toType())) { 34220 return false; 34221 } 34222 return true; 34223 } 34224 34225 fn unionFieldIndex( 34226 sema: *Sema, 34227 block: *Block, 34228 unresolved_union_ty: Type, 34229 field_name: []const u8, 34230 field_src: LazySrcLoc, 34231 ) !u32 { 34232 const mod = sema.mod; 34233 const union_ty = try sema.resolveTypeFields(unresolved_union_ty); 34234 const union_obj = mod.typeToUnion(union_ty).?; 34235 const field_index_usize = union_obj.fields.getIndex(field_name) orelse 34236 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); 34237 return @intCast(u32, field_index_usize); 34238 } 34239 34240 fn structFieldIndex( 34241 sema: *Sema, 34242 block: *Block, 34243 unresolved_struct_ty: Type, 34244 field_name: []const u8, 34245 field_src: LazySrcLoc, 34246 ) !u32 { 34247 const mod = sema.mod; 34248 const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); 34249 if (struct_ty.isAnonStruct(mod)) { 34250 return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src); 34251 } else { 34252 const struct_obj = mod.typeToStruct(struct_ty).?; 34253 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse 34254 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); 34255 return @intCast(u32, field_index_usize); 34256 } 34257 } 34258 34259 fn anonStructFieldIndex( 34260 sema: *Sema, 34261 block: *Block, 34262 struct_ty: Type, 34263 field_name: []const u8, 34264 field_src: LazySrcLoc, 34265 ) !u32 { 34266 const mod = sema.mod; 34267 switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { 34268 .anon_struct_type => |anon_struct_type| for (anon_struct_type.names, 0..) |name, i| { 34269 if (mem.eql(u8, mod.intern_pool.stringToSlice(name), field_name)) { 34270 return @intCast(u32, i); 34271 } 34272 }, 34273 .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| { 34274 for (struct_obj.fields.keys(), 0..) |name, i| { 34275 if (mem.eql(u8, name, field_name)) { 34276 return @intCast(u32, i); 34277 } 34278 } 34279 }, 34280 else => unreachable, 34281 } 34282 return sema.fail(block, field_src, "no field named '{s}' in anonymous struct '{}'", .{ 34283 field_name, struct_ty.fmt(sema.mod), 34284 }); 34285 } 34286 34287 fn queueFullTypeResolution(sema: *Sema, ty: Type) !void { 34288 try sema.types_to_resolve.put(sema.gpa, ty.toIntern(), {}); 34289 } 34290 34291 fn intAdd(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value { 34292 const mod = sema.mod; 34293 if (ty.zigTypeTag(mod) == .Vector) { 34294 const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod)); 34295 const scalar_ty = ty.scalarType(mod); 34296 for (result_data, 0..) |*scalar, i| { 34297 const lhs_elem = try lhs.elemValue(mod, i); 34298 const rhs_elem = try rhs.elemValue(mod, i); 34299 scalar.* = try (try sema.intAddScalar(lhs_elem, rhs_elem, scalar_ty)).intern(scalar_ty, mod); 34300 } 34301 return (try mod.intern(.{ .aggregate = .{ 34302 .ty = ty.toIntern(), 34303 .storage = .{ .elems = result_data }, 34304 } })).toValue(); 34305 } 34306 return sema.intAddScalar(lhs, rhs, ty); 34307 } 34308 34309 fn intAddScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) !Value { 34310 const mod = sema.mod; 34311 // TODO is this a performance issue? maybe we should try the operation without 34312 // resorting to BigInt first. 34313 var lhs_space: Value.BigIntSpace = undefined; 34314 var rhs_space: Value.BigIntSpace = undefined; 34315 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); 34316 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); 34317 const limbs = try sema.arena.alloc( 34318 std.math.big.Limb, 34319 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, 34320 ); 34321 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; 34322 result_bigint.add(lhs_bigint, rhs_bigint); 34323 if (scalar_ty.toIntern() != .comptime_int_type) { 34324 const int_info = scalar_ty.intInfo(mod); 34325 result_bigint.truncate(result_bigint.toConst(), int_info.signedness, int_info.bits); 34326 } 34327 return mod.intValue_big(scalar_ty, result_bigint.toConst()); 34328 } 34329 34330 /// Supports both floats and ints; handles undefined. 34331 fn numberAddWrapScalar( 34332 sema: *Sema, 34333 lhs: Value, 34334 rhs: Value, 34335 ty: Type, 34336 ) !Value { 34337 const mod = sema.mod; 34338 if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.undef; 34339 34340 if (ty.zigTypeTag(mod) == .ComptimeInt) { 34341 return sema.intAdd(lhs, rhs, ty); 34342 } 34343 34344 if (ty.isAnyFloat()) { 34345 return Value.floatAdd(lhs, rhs, ty, sema.arena, mod); 34346 } 34347 34348 const overflow_result = try sema.intAddWithOverflow(lhs, rhs, ty); 34349 return overflow_result.wrapped_result; 34350 } 34351 34352 fn intSub(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value { 34353 const mod = sema.mod; 34354 if (ty.zigTypeTag(mod) == .Vector) { 34355 const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod)); 34356 const scalar_ty = ty.scalarType(mod); 34357 for (result_data, 0..) |*scalar, i| { 34358 const lhs_elem = try lhs.elemValue(sema.mod, i); 34359 const rhs_elem = try rhs.elemValue(sema.mod, i); 34360 scalar.* = try (try sema.intSubScalar(lhs_elem, rhs_elem, scalar_ty)).intern(scalar_ty, mod); 34361 } 34362 return (try mod.intern(.{ .aggregate = .{ 34363 .ty = ty.toIntern(), 34364 .storage = .{ .elems = result_data }, 34365 } })).toValue(); 34366 } 34367 return sema.intSubScalar(lhs, rhs, ty); 34368 } 34369 34370 fn intSubScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) !Value { 34371 const mod = sema.mod; 34372 // TODO is this a performance issue? maybe we should try the operation without 34373 // resorting to BigInt first. 34374 var lhs_space: Value.BigIntSpace = undefined; 34375 var rhs_space: Value.BigIntSpace = undefined; 34376 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); 34377 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); 34378 const limbs = try sema.arena.alloc( 34379 std.math.big.Limb, 34380 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, 34381 ); 34382 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; 34383 result_bigint.sub(lhs_bigint, rhs_bigint); 34384 return mod.intValue_big(scalar_ty, result_bigint.toConst()); 34385 } 34386 34387 /// Supports both floats and ints; handles undefined. 34388 fn numberSubWrapScalar( 34389 sema: *Sema, 34390 lhs: Value, 34391 rhs: Value, 34392 ty: Type, 34393 ) !Value { 34394 const mod = sema.mod; 34395 if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.undef; 34396 34397 if (ty.zigTypeTag(mod) == .ComptimeInt) { 34398 return sema.intSub(lhs, rhs, ty); 34399 } 34400 34401 if (ty.isAnyFloat()) { 34402 return Value.floatSub(lhs, rhs, ty, sema.arena, mod); 34403 } 34404 34405 const overflow_result = try sema.intSubWithOverflow(lhs, rhs, ty); 34406 return overflow_result.wrapped_result; 34407 } 34408 34409 fn intSubWithOverflow( 34410 sema: *Sema, 34411 lhs: Value, 34412 rhs: Value, 34413 ty: Type, 34414 ) !Value.OverflowArithmeticResult { 34415 const mod = sema.mod; 34416 if (ty.zigTypeTag(mod) == .Vector) { 34417 const vec_len = ty.vectorLen(mod); 34418 const overflowed_data = try sema.arena.alloc(InternPool.Index, vec_len); 34419 const result_data = try sema.arena.alloc(InternPool.Index, vec_len); 34420 const scalar_ty = ty.scalarType(mod); 34421 for (overflowed_data, result_data, 0..) |*of, *scalar, i| { 34422 const lhs_elem = try lhs.elemValue(sema.mod, i); 34423 const rhs_elem = try rhs.elemValue(sema.mod, i); 34424 const of_math_result = try sema.intSubWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty); 34425 of.* = try of_math_result.overflow_bit.intern(Type.u1, mod); 34426 scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod); 34427 } 34428 return Value.OverflowArithmeticResult{ 34429 .overflow_bit = (try mod.intern(.{ .aggregate = .{ 34430 .ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(), 34431 .storage = .{ .elems = overflowed_data }, 34432 } })).toValue(), 34433 .wrapped_result = (try mod.intern(.{ .aggregate = .{ 34434 .ty = ty.toIntern(), 34435 .storage = .{ .elems = result_data }, 34436 } })).toValue(), 34437 }; 34438 } 34439 return sema.intSubWithOverflowScalar(lhs, rhs, ty); 34440 } 34441 34442 fn intSubWithOverflowScalar( 34443 sema: *Sema, 34444 lhs: Value, 34445 rhs: Value, 34446 ty: Type, 34447 ) !Value.OverflowArithmeticResult { 34448 const mod = sema.mod; 34449 const info = ty.intInfo(mod); 34450 34451 var lhs_space: Value.BigIntSpace = undefined; 34452 var rhs_space: Value.BigIntSpace = undefined; 34453 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); 34454 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); 34455 const limbs = try sema.arena.alloc( 34456 std.math.big.Limb, 34457 std.math.big.int.calcTwosCompLimbCount(info.bits), 34458 ); 34459 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; 34460 const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); 34461 const wrapped_result = try mod.intValue_big(ty, result_bigint.toConst()); 34462 return Value.OverflowArithmeticResult{ 34463 .overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)), 34464 .wrapped_result = wrapped_result, 34465 }; 34466 } 34467 34468 fn floatToInt( 34469 sema: *Sema, 34470 block: *Block, 34471 src: LazySrcLoc, 34472 val: Value, 34473 float_ty: Type, 34474 int_ty: Type, 34475 ) CompileError!Value { 34476 const mod = sema.mod; 34477 if (float_ty.zigTypeTag(mod) == .Vector) { 34478 const elem_ty = float_ty.scalarType(mod); 34479 const result_data = try sema.arena.alloc(InternPool.Index, float_ty.vectorLen(mod)); 34480 const scalar_ty = int_ty.scalarType(mod); 34481 for (result_data, 0..) |*scalar, i| { 34482 const elem_val = try val.elemValue(sema.mod, i); 34483 scalar.* = try (try sema.floatToIntScalar(block, src, elem_val, elem_ty, int_ty.scalarType(mod))).intern(scalar_ty, mod); 34484 } 34485 return (try mod.intern(.{ .aggregate = .{ 34486 .ty = int_ty.toIntern(), 34487 .storage = .{ .elems = result_data }, 34488 } })).toValue(); 34489 } 34490 return sema.floatToIntScalar(block, src, val, float_ty, int_ty); 34491 } 34492 34493 // float is expected to be finite and non-NaN 34494 fn float128IntPartToBigInt( 34495 arena: Allocator, 34496 float: f128, 34497 ) !std.math.big.int.Managed { 34498 const is_negative = std.math.signbit(float); 34499 const floored = @floor(@fabs(float)); 34500 34501 var rational = try std.math.big.Rational.init(arena); 34502 defer rational.q.deinit(); 34503 rational.setFloat(f128, floored) catch |err| switch (err) { 34504 error.NonFiniteFloat => unreachable, 34505 error.OutOfMemory => return error.OutOfMemory, 34506 }; 34507 34508 // The float is reduced in rational.setFloat, so we assert that denominator is equal to one 34509 const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true }; 34510 assert(rational.q.toConst().eqAbs(big_one)); 34511 34512 if (is_negative) { 34513 rational.negate(); 34514 } 34515 return rational.p; 34516 } 34517 34518 fn floatToIntScalar( 34519 sema: *Sema, 34520 block: *Block, 34521 src: LazySrcLoc, 34522 val: Value, 34523 float_ty: Type, 34524 int_ty: Type, 34525 ) CompileError!Value { 34526 const mod = sema.mod; 34527 34528 const float = val.toFloat(f128, mod); 34529 if (std.math.isNan(float)) { 34530 return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{ 34531 int_ty.fmt(sema.mod), 34532 }); 34533 } 34534 if (std.math.isInf(float)) { 34535 return sema.fail(block, src, "float value Inf cannot be stored in integer type '{}'", .{ 34536 int_ty.fmt(sema.mod), 34537 }); 34538 } 34539 34540 var big_int = try float128IntPartToBigInt(sema.arena, float); 34541 defer big_int.deinit(); 34542 34543 const result = try mod.intValue_big(int_ty, big_int.toConst()); 34544 34545 if (!(try sema.intFitsInType(result, int_ty, null))) { 34546 return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{ 34547 val.fmtValue(float_ty, sema.mod), int_ty.fmt(sema.mod), 34548 }); 34549 } 34550 return result; 34551 } 34552 34553 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int. 34554 /// Vectors are also accepted. Vector results are reduced with AND. 34555 /// 34556 /// If provided, `vector_index` reports the first element that failed the range check. 34557 fn intFitsInType( 34558 sema: *Sema, 34559 val: Value, 34560 ty: Type, 34561 vector_index: ?*usize, 34562 ) CompileError!bool { 34563 const mod = sema.mod; 34564 if (ty.toIntern() == .comptime_int_type) return true; 34565 const info = ty.intInfo(mod); 34566 switch (val.toIntern()) { 34567 .zero_usize, .zero_u8 => return true, 34568 else => switch (mod.intern_pool.indexToKey(val.toIntern())) { 34569 .undef => return true, 34570 .variable, .extern_func, .func, .ptr => { 34571 const target = mod.getTarget(); 34572 const ptr_bits = target.ptrBitWidth(); 34573 return switch (info.signedness) { 34574 .signed => info.bits > ptr_bits, 34575 .unsigned => info.bits >= ptr_bits, 34576 }; 34577 }, 34578 .int => |int| switch (int.storage) { 34579 .u64, .i64, .big_int => { 34580 var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined; 34581 const big_int = int.storage.toBigInt(&buffer); 34582 return big_int.fitsInTwosComp(info.signedness, info.bits); 34583 }, 34584 .lazy_align => |lazy_ty| { 34585 const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed); 34586 // If it is u16 or bigger we know the alignment fits without resolving it. 34587 if (info.bits >= max_needed_bits) return true; 34588 const x = try sema.typeAbiAlignment(lazy_ty.toType()); 34589 if (x == 0) return true; 34590 const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); 34591 return info.bits >= actual_needed_bits; 34592 }, 34593 .lazy_size => |lazy_ty| { 34594 const max_needed_bits = @as(u16, 64) + @boolToInt(info.signedness == .signed); 34595 // If it is u64 or bigger we know the size fits without resolving it. 34596 if (info.bits >= max_needed_bits) return true; 34597 const x = try sema.typeAbiSize(lazy_ty.toType()); 34598 if (x == 0) return true; 34599 const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); 34600 return info.bits >= actual_needed_bits; 34601 }, 34602 }, 34603 .aggregate => |aggregate| { 34604 assert(ty.zigTypeTag(mod) == .Vector); 34605 return switch (aggregate.storage) { 34606 .bytes => |bytes| for (bytes, 0..) |byte, i| { 34607 if (byte == 0) continue; 34608 const actual_needed_bits = std.math.log2(byte) + 1 + @boolToInt(info.signedness == .signed); 34609 if (info.bits >= actual_needed_bits) continue; 34610 if (vector_index) |vi| vi.* = i; 34611 break false; 34612 } else true, 34613 .elems, .repeated_elem => for (switch (aggregate.storage) { 34614 .bytes => unreachable, 34615 .elems => |elems| elems, 34616 .repeated_elem => |elem| @as(*const [1]InternPool.Index, &elem), 34617 }, 0..) |elem, i| { 34618 if (try sema.intFitsInType(elem.toValue(), ty.scalarType(mod), null)) continue; 34619 if (vector_index) |vi| vi.* = i; 34620 break false; 34621 } else true, 34622 }; 34623 }, 34624 else => unreachable, 34625 }, 34626 } 34627 } 34628 34629 fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool { 34630 const mod = sema.mod; 34631 if (!(try int_val.compareAllWithZeroAdvanced(.gte, sema))) return false; 34632 const end_val = try mod.intValue(tag_ty, end); 34633 if (!(try sema.compareAll(int_val, .lt, end_val, tag_ty))) return false; 34634 return true; 34635 } 34636 34637 /// Asserts the type is an enum. 34638 fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool { 34639 const mod = sema.mod; 34640 const enum_type = mod.intern_pool.indexToKey(ty.toIntern()).enum_type; 34641 assert(enum_type.tag_mode != .nonexhaustive); 34642 // The `tagValueIndex` function call below relies on the type being the integer tag type. 34643 // `getCoerced` assumes the value will fit the new type. 34644 if (!(try sema.intFitsInType(int, enum_type.tag_ty.toType(), null))) return false; 34645 const int_coerced = try mod.getCoerced(int, enum_type.tag_ty.toType()); 34646 34647 return enum_type.tagValueIndex(&mod.intern_pool, int_coerced.toIntern()) != null; 34648 } 34649 34650 fn intAddWithOverflow( 34651 sema: *Sema, 34652 lhs: Value, 34653 rhs: Value, 34654 ty: Type, 34655 ) !Value.OverflowArithmeticResult { 34656 const mod = sema.mod; 34657 if (ty.zigTypeTag(mod) == .Vector) { 34658 const vec_len = ty.vectorLen(mod); 34659 const overflowed_data = try sema.arena.alloc(InternPool.Index, vec_len); 34660 const result_data = try sema.arena.alloc(InternPool.Index, vec_len); 34661 const scalar_ty = ty.scalarType(mod); 34662 for (overflowed_data, result_data, 0..) |*of, *scalar, i| { 34663 const lhs_elem = try lhs.elemValue(sema.mod, i); 34664 const rhs_elem = try rhs.elemValue(sema.mod, i); 34665 const of_math_result = try sema.intAddWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty); 34666 of.* = try of_math_result.overflow_bit.intern(Type.u1, mod); 34667 scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod); 34668 } 34669 return Value.OverflowArithmeticResult{ 34670 .overflow_bit = (try mod.intern(.{ .aggregate = .{ 34671 .ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(), 34672 .storage = .{ .elems = overflowed_data }, 34673 } })).toValue(), 34674 .wrapped_result = (try mod.intern(.{ .aggregate = .{ 34675 .ty = ty.toIntern(), 34676 .storage = .{ .elems = result_data }, 34677 } })).toValue(), 34678 }; 34679 } 34680 return sema.intAddWithOverflowScalar(lhs, rhs, ty); 34681 } 34682 34683 fn intAddWithOverflowScalar( 34684 sema: *Sema, 34685 lhs: Value, 34686 rhs: Value, 34687 ty: Type, 34688 ) !Value.OverflowArithmeticResult { 34689 const mod = sema.mod; 34690 const info = ty.intInfo(mod); 34691 34692 var lhs_space: Value.BigIntSpace = undefined; 34693 var rhs_space: Value.BigIntSpace = undefined; 34694 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); 34695 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); 34696 const limbs = try sema.arena.alloc( 34697 std.math.big.Limb, 34698 std.math.big.int.calcTwosCompLimbCount(info.bits), 34699 ); 34700 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; 34701 const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); 34702 const result = try mod.intValue_big(ty, result_bigint.toConst()); 34703 return Value.OverflowArithmeticResult{ 34704 .overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)), 34705 .wrapped_result = result, 34706 }; 34707 } 34708 34709 /// Asserts the values are comparable. Both operands have type `ty`. 34710 /// For vectors, returns true if the comparison is true for ALL elements. 34711 /// 34712 /// Note that `!compareAll(.eq, ...) != compareAll(.neq, ...)` 34713 fn compareAll( 34714 sema: *Sema, 34715 lhs: Value, 34716 op: std.math.CompareOperator, 34717 rhs: Value, 34718 ty: Type, 34719 ) CompileError!bool { 34720 const mod = sema.mod; 34721 if (ty.zigTypeTag(mod) == .Vector) { 34722 var i: usize = 0; 34723 while (i < ty.vectorLen(mod)) : (i += 1) { 34724 const lhs_elem = try lhs.elemValue(sema.mod, i); 34725 const rhs_elem = try rhs.elemValue(sema.mod, i); 34726 if (!(try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(mod)))) { 34727 return false; 34728 } 34729 } 34730 return true; 34731 } 34732 return sema.compareScalar(lhs, op, rhs, ty); 34733 } 34734 34735 /// Asserts the values are comparable. Both operands have type `ty`. 34736 fn compareScalar( 34737 sema: *Sema, 34738 lhs: Value, 34739 op: std.math.CompareOperator, 34740 rhs: Value, 34741 ty: Type, 34742 ) CompileError!bool { 34743 const mod = sema.mod; 34744 const coerced_lhs = try mod.getCoerced(lhs, ty); 34745 const coerced_rhs = try mod.getCoerced(rhs, ty); 34746 switch (op) { 34747 .eq => return sema.valuesEqual(coerced_lhs, coerced_rhs, ty), 34748 .neq => return !(try sema.valuesEqual(coerced_lhs, coerced_rhs, ty)), 34749 else => return Value.compareHeteroAdvanced(coerced_lhs, op, coerced_rhs, mod, sema), 34750 } 34751 } 34752 34753 fn valuesEqual( 34754 sema: *Sema, 34755 lhs: Value, 34756 rhs: Value, 34757 ty: Type, 34758 ) CompileError!bool { 34759 return Value.eqlAdvanced(lhs, ty, rhs, ty, sema.mod, sema); 34760 } 34761 34762 /// Asserts the values are comparable vectors of type `ty`. 34763 fn compareVector( 34764 sema: *Sema, 34765 lhs: Value, 34766 op: std.math.CompareOperator, 34767 rhs: Value, 34768 ty: Type, 34769 ) !Value { 34770 const mod = sema.mod; 34771 assert(ty.zigTypeTag(mod) == .Vector); 34772 const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod)); 34773 for (result_data, 0..) |*scalar, i| { 34774 const lhs_elem = try lhs.elemValue(sema.mod, i); 34775 const rhs_elem = try rhs.elemValue(sema.mod, i); 34776 const res_bool = try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(mod)); 34777 scalar.* = try Value.makeBool(res_bool).intern(Type.bool, mod); 34778 } 34779 return (try mod.intern(.{ .aggregate = .{ 34780 .ty = (try mod.vectorType(.{ .len = ty.vectorLen(mod), .child = .bool_type })).toIntern(), 34781 .storage = .{ .elems = result_data }, 34782 } })).toValue(); 34783 } 34784 34785 /// Returns the type of a pointer to an element. 34786 /// Asserts that the type is a pointer, and that the element type is indexable. 34787 /// For *[N]T, return *T 34788 /// For [*]T, returns *T 34789 /// For []T, returns *T 34790 /// Handles const-ness and address spaces in particular. 34791 /// This code is duplicated in `analyzePtrArithmetic`. 34792 fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { 34793 const mod = sema.mod; 34794 const ptr_info = ptr_ty.ptrInfo(mod); 34795 const elem_ty = ptr_ty.elemType2(mod); 34796 const allow_zero = ptr_info.@"allowzero" and (offset orelse 0) == 0; 34797 const parent_ty = ptr_ty.childType(mod); 34798 34799 const VI = Type.Payload.Pointer.Data.VectorIndex; 34800 34801 const vector_info: struct { 34802 host_size: u16 = 0, 34803 alignment: u32 = 0, 34804 vector_index: VI = .none, 34805 } = if (parent_ty.isVector(mod) and ptr_info.size == .One) blk: { 34806 const elem_bits = elem_ty.bitSize(mod); 34807 if (elem_bits == 0) break :blk .{}; 34808 const is_packed = elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits); 34809 if (!is_packed) break :blk .{}; 34810 34811 break :blk .{ 34812 .host_size = @intCast(u16, parent_ty.arrayLen(mod)), 34813 .alignment = @intCast(u16, parent_ty.abiAlignment(mod)), 34814 .vector_index = if (offset) |some| @intToEnum(VI, some) else .runtime, 34815 }; 34816 } else .{}; 34817 34818 const alignment: u32 = a: { 34819 // Calculate the new pointer alignment. 34820 if (ptr_info.@"align" == 0) { 34821 if (vector_info.alignment != 0) break :a vector_info.alignment; 34822 // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness. 34823 break :a 0; 34824 } 34825 // If the addend is not a comptime-known value we can still count on 34826 // it being a multiple of the type size. 34827 const elem_size = try sema.typeAbiSize(elem_ty); 34828 const addend = if (offset) |off| elem_size * off else elem_size; 34829 34830 // The resulting pointer is aligned to the lcd between the offset (an 34831 // arbitrary number) and the alignment factor (always a power of two, 34832 // non zero). 34833 const new_align = @as(u32, 1) << @intCast(u5, @ctz(addend | ptr_info.@"align")); 34834 break :a new_align; 34835 }; 34836 return try Type.ptr(sema.arena, sema.mod, .{ 34837 .pointee_type = elem_ty, 34838 .mutable = ptr_info.mutable, 34839 .@"addrspace" = ptr_info.@"addrspace", 34840 .@"allowzero" = allow_zero, 34841 .@"volatile" = ptr_info.@"volatile", 34842 .@"align" = alignment, 34843 .host_size = vector_info.host_size, 34844 .vector_index = vector_info.vector_index, 34845 }); 34846 } 34847 34848 /// Merge lhs with rhs. 34849 /// Asserts that lhs and rhs are both error sets and are resolved. 34850 fn errorSetMerge(sema: *Sema, lhs: Type, rhs: Type) !Type { 34851 const mod = sema.mod; 34852 const arena = sema.arena; 34853 const lhs_names = lhs.errorSetNames(mod); 34854 const rhs_names = rhs.errorSetNames(mod); 34855 var names: Module.Fn.InferredErrorSet.NameMap = .{}; 34856 try names.ensureUnusedCapacity(arena, lhs_names.len); 34857 34858 for (lhs_names) |name| { 34859 names.putAssumeCapacityNoClobber(name, {}); 34860 } 34861 for (rhs_names) |name| { 34862 try names.put(arena, name, {}); 34863 } 34864 34865 return mod.errorSetFromUnsortedNames(names.keys()); 34866 } 34867 34868 /// Avoids crashing the compiler when asking if inferred allocations are noreturn. 34869 fn isNoReturn(sema: *Sema, ref: Air.Inst.Ref) bool { 34870 if (ref == .unreachable_value) return true; 34871 if (Air.refToIndex(ref)) |inst| switch (sema.air_instructions.items(.tag)[inst]) { 34872 .inferred_alloc, .inferred_alloc_comptime => return false, 34873 else => {}, 34874 }; 34875 return sema.typeOf(ref).isNoReturn(sema.mod); 34876 } 34877 34878 /// Avoids crashing the compiler when asking if inferred allocations are known to be a certain zig type. 34879 fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool { 34880 if (Air.refToIndex(ref)) |inst| switch (sema.air_instructions.items(.tag)[inst]) { 34881 .inferred_alloc, .inferred_alloc_comptime => return false, 34882 else => {}, 34883 }; 34884 return sema.typeOf(ref).zigTypeTag(sema.mod) == tag; 34885 }