blob ae00a985 (1307370B) - Raw
1 //! Semantic analysis of ZIR instructions. 2 //! Shared to every Block. Stored on the stack. 3 //! State used for compiling a ZIR into AIR. 4 //! Transforms untyped ZIR instructions into semantically-analyzed AIR instructions. 5 //! Does type checking, comptime control flow, and safety-check generation. 6 //! This is the the heart of the Zig compiler. 7 8 mod: *Module, 9 /// Alias to `mod.gpa`. 10 gpa: Allocator, 11 /// Points to the temporary arena allocator of the Sema. 12 /// This arena will be cleared when the sema is destroyed. 13 arena: Allocator, 14 /// Points to the arena allocator for the owner_decl. 15 /// This arena will persist until the decl is invalidated. 16 perm_arena: Allocator, 17 code: Zir, 18 air_instructions: std.MultiArrayList(Air.Inst) = .{}, 19 air_extra: std.ArrayListUnmanaged(u32) = .{}, 20 air_values: std.ArrayListUnmanaged(Value) = .{}, 21 /// Maps ZIR to AIR. 22 inst_map: InstMap = .{}, 23 /// When analyzing an inline function call, owner_decl is the Decl of the caller 24 /// and `src_decl` of `Block` is the `Decl` of the callee. 25 /// This `Decl` owns the arena memory of this `Sema`. 26 owner_decl: *Decl, 27 owner_decl_index: Decl.Index, 28 /// For an inline or comptime function call, this will be the root parent function 29 /// which contains the callsite. Corresponds to `owner_decl`. 30 owner_func: ?*Module.Fn, 31 /// The function this ZIR code is the body of, according to the source code. 32 /// This starts out the same as `owner_func` and then diverges in the case of 33 /// an inline or comptime function call. 34 func: ?*Module.Fn, 35 /// When semantic analysis needs to know the return type of the function whose body 36 /// is being analyzed, this `Type` should be used instead of going through `func`. 37 /// This will correctly handle the case of a comptime/inline function call of a 38 /// generic function which uses a type expression for the return type. 39 /// The type will be `void` in the case that `func` is `null`. 40 fn_ret_ty: Type, 41 branch_quota: u32 = default_branch_quota, 42 branch_count: u32 = 0, 43 /// Populated when returning `error.ComptimeBreak`. Used to communicate the 44 /// break instruction up the stack to find the corresponding Block. 45 comptime_break_inst: Zir.Inst.Index = undefined, 46 /// This field is updated when a new source location becomes active, so that 47 /// instructions which do not have explicitly mapped source locations still have 48 /// access to the source location set by the previous instruction which did 49 /// contain a mapped source location. 50 src: LazySrcLoc = .{ .token_offset = 0 }, 51 decl_val_table: std.AutoHashMapUnmanaged(Decl.Index, Air.Inst.Ref) = .{}, 52 /// When doing a generic function instantiation, this array collects a 53 /// `Value` object for each parameter that is comptime known and thus elided 54 /// from the generated function. This memory is allocated by a parent `Sema` and 55 /// owned by the values arena of the Sema owner_decl. 56 comptime_args: []TypedValue = &.{}, 57 /// Marks the function instruction that `comptime_args` applies to so that we 58 /// don't accidentally apply it to a function prototype which is used in the 59 /// type expression of a generic function parameter. 60 comptime_args_fn_inst: Zir.Inst.Index = 0, 61 /// When `comptime_args` is provided, this field is also provided. It was used as 62 /// the key in the `monomorphed_funcs` set. The `func` instruction is supposed 63 /// to use this instead of allocating a fresh one. This avoids an unnecessary 64 /// extra hash table lookup in the `monomorphed_funcs` set. 65 /// Sema will set this to null when it takes ownership. 66 preallocated_new_func: ?*Module.Fn = null, 67 /// The key is `constant` AIR instructions to types that must be fully resolved 68 /// after the current function body analysis is done. 69 /// TODO: after upgrading to use InternPool change the key here to be an 70 /// InternPool value index. 71 types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{}, 72 /// These are lazily created runtime blocks from inline_block instructions. 73 /// They are created when an inline_break passes through a runtime condition, because 74 /// Sema must convert comptime control flow to runtime control flow, which means 75 /// breaking from a block. 76 post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{}, 77 /// Populated with the last compile error created. 78 err: ?*Module.ErrorMsg = null, 79 /// True when analyzing a generic instantiation. Used to suppress some errors. 80 is_generic_instantiation: bool = false, 81 /// Set to true when analyzing a func type instruction so that nested generic 82 /// function types will emit generic poison instead of a partial type. 83 no_partial_func_ty: bool = false, 84 85 const std = @import("std"); 86 const math = std.math; 87 const mem = std.mem; 88 const Allocator = std.mem.Allocator; 89 const assert = std.debug.assert; 90 const log = std.log.scoped(.sema); 91 92 const Sema = @This(); 93 const Value = @import("value.zig").Value; 94 const Type = @import("type.zig").Type; 95 const TypedValue = @import("TypedValue.zig"); 96 const Air = @import("Air.zig"); 97 const Zir = @import("Zir.zig"); 98 const Module = @import("Module.zig"); 99 const trace = @import("tracy.zig").trace; 100 const Namespace = Module.Namespace; 101 const CompileError = Module.CompileError; 102 const SemaError = Module.SemaError; 103 const Decl = Module.Decl; 104 const CaptureScope = Module.CaptureScope; 105 const WipCaptureScope = Module.WipCaptureScope; 106 const LazySrcLoc = Module.LazySrcLoc; 107 const RangeSet = @import("RangeSet.zig"); 108 const target_util = @import("target.zig"); 109 const Package = @import("Package.zig"); 110 const crash_report = @import("crash_report.zig"); 111 const build_options = @import("build_options"); 112 113 pub const default_branch_quota = 1000; 114 pub const default_reference_trace_len = 2; 115 116 pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref); 117 118 /// This is the context needed to semantically analyze ZIR instructions and 119 /// produce AIR instructions. 120 /// This is a temporary structure stored on the stack; references to it are valid only 121 /// during semantic analysis of the block. 122 pub const Block = struct { 123 parent: ?*Block, 124 /// Shared among all child blocks. 125 sema: *Sema, 126 /// The namespace to use for lookups from this source block 127 /// When analyzing fields, this is different from src_decl.src_namepsace. 128 namespace: *Namespace, 129 /// The AIR instructions generated for this block. 130 instructions: std.ArrayListUnmanaged(Air.Inst.Index), 131 // `param` instructions are collected here to be used by the `func` instruction. 132 params: std.ArrayListUnmanaged(Param) = .{}, 133 134 wip_capture_scope: *CaptureScope, 135 136 label: ?*Label = null, 137 inlining: ?*Inlining, 138 /// If runtime_index is not 0 then one of these is guaranteed to be non null. 139 runtime_cond: ?LazySrcLoc = null, 140 runtime_loop: ?LazySrcLoc = null, 141 /// This Decl is the Decl according to the Zig source code corresponding to this Block. 142 /// This can vary during inline or comptime function calls. See `Sema.owner_decl` 143 /// for the one that will be the same for all Block instances. 144 src_decl: Decl.Index, 145 /// Non zero if a non-inline loop or a runtime conditional have been encountered. 146 /// Stores to to comptime variables are only allowed when var.runtime_index <= runtime_index. 147 runtime_index: Value.RuntimeIndex = .zero, 148 inline_block: Zir.Inst.Index = 0, 149 150 is_comptime: bool, 151 is_typeof: bool = false, 152 is_coerce_result_ptr: bool = false, 153 154 /// when null, it is determined by build mode, changed by @setRuntimeSafety 155 want_safety: ?bool = null, 156 157 /// What mode to generate float operations in, set by @setFloatMode 158 float_mode: std.builtin.FloatMode = .Strict, 159 160 c_import_buf: ?*std.ArrayList(u8) = null, 161 162 /// type of `err` in `else => |err|` 163 switch_else_err_ty: ?Type = null, 164 165 const Param = struct { 166 /// `noreturn` means `anytype`. 167 ty: Type, 168 is_comptime: bool, 169 name: []const u8, 170 }; 171 172 /// This `Block` maps a block ZIR instruction to the corresponding 173 /// AIR instruction for break instruction analysis. 174 pub const Label = struct { 175 zir_block: Zir.Inst.Index, 176 merges: Merges, 177 }; 178 179 /// This `Block` indicates that an inline function call is happening 180 /// and return instructions should be analyzed as a break instruction 181 /// to this AIR block instruction. 182 /// It is shared among all the blocks in an inline or comptime called 183 /// function. 184 pub const Inlining = struct { 185 comptime_result: Air.Inst.Ref, 186 merges: Merges, 187 }; 188 189 pub const Merges = struct { 190 block_inst: Air.Inst.Index, 191 /// Separate array list from break_inst_list so that it can be passed directly 192 /// to resolvePeerTypes. 193 results: std.ArrayListUnmanaged(Air.Inst.Ref), 194 /// Keeps track of the break instructions so that the operand can be replaced 195 /// if we need to add type coercion at the end of block analysis. 196 /// Same indexes, capacity, length as `results`. 197 br_list: std.ArrayListUnmanaged(Air.Inst.Index), 198 }; 199 200 /// For debugging purposes. 201 pub fn dump(block: *Block, mod: Module) void { 202 Zir.dumpBlock(mod, block); 203 } 204 205 pub fn makeSubBlock(parent: *Block) Block { 206 return .{ 207 .parent = parent, 208 .sema = parent.sema, 209 .src_decl = parent.src_decl, 210 .namespace = parent.namespace, 211 .instructions = .{}, 212 .wip_capture_scope = parent.wip_capture_scope, 213 .label = null, 214 .inlining = parent.inlining, 215 .is_comptime = parent.is_comptime, 216 .is_typeof = parent.is_typeof, 217 .runtime_cond = parent.runtime_cond, 218 .runtime_loop = parent.runtime_loop, 219 .runtime_index = parent.runtime_index, 220 .want_safety = parent.want_safety, 221 .float_mode = parent.float_mode, 222 .c_import_buf = parent.c_import_buf, 223 .switch_else_err_ty = parent.switch_else_err_ty, 224 }; 225 } 226 227 pub fn wantSafety(block: *const Block) bool { 228 return block.want_safety orelse switch (block.sema.mod.optimizeMode()) { 229 .Debug => true, 230 .ReleaseSafe => true, 231 .ReleaseFast => false, 232 .ReleaseSmall => false, 233 }; 234 } 235 236 pub fn getFileScope(block: *Block) *Module.File { 237 return block.namespace.file_scope; 238 } 239 240 fn addTy( 241 block: *Block, 242 tag: Air.Inst.Tag, 243 ty: Type, 244 ) error{OutOfMemory}!Air.Inst.Ref { 245 return block.addInst(.{ 246 .tag = tag, 247 .data = .{ .ty = ty }, 248 }); 249 } 250 251 fn addTyOp( 252 block: *Block, 253 tag: Air.Inst.Tag, 254 ty: Type, 255 operand: Air.Inst.Ref, 256 ) error{OutOfMemory}!Air.Inst.Ref { 257 return block.addInst(.{ 258 .tag = tag, 259 .data = .{ .ty_op = .{ 260 .ty = try block.sema.addType(ty), 261 .operand = operand, 262 } }, 263 }); 264 } 265 266 fn addBitCast(block: *Block, ty: Type, operand: Air.Inst.Ref) Allocator.Error!Air.Inst.Ref { 267 return block.addInst(.{ 268 .tag = .bitcast, 269 .data = .{ .ty_op = .{ 270 .ty = try block.sema.addType(ty), 271 .operand = operand, 272 } }, 273 }); 274 } 275 276 fn addNoOp(block: *Block, tag: Air.Inst.Tag) error{OutOfMemory}!Air.Inst.Ref { 277 return block.addInst(.{ 278 .tag = tag, 279 .data = .{ .no_op = {} }, 280 }); 281 } 282 283 fn addUnOp( 284 block: *Block, 285 tag: Air.Inst.Tag, 286 operand: Air.Inst.Ref, 287 ) error{OutOfMemory}!Air.Inst.Ref { 288 return block.addInst(.{ 289 .tag = tag, 290 .data = .{ .un_op = operand }, 291 }); 292 } 293 294 fn addBr( 295 block: *Block, 296 target_block: Air.Inst.Index, 297 operand: Air.Inst.Ref, 298 ) error{OutOfMemory}!Air.Inst.Ref { 299 return block.addInst(.{ 300 .tag = .br, 301 .data = .{ .br = .{ 302 .block_inst = target_block, 303 .operand = operand, 304 } }, 305 }); 306 } 307 308 fn addBinOp( 309 block: *Block, 310 tag: Air.Inst.Tag, 311 lhs: Air.Inst.Ref, 312 rhs: Air.Inst.Ref, 313 ) error{OutOfMemory}!Air.Inst.Ref { 314 return block.addInst(.{ 315 .tag = tag, 316 .data = .{ .bin_op = .{ 317 .lhs = lhs, 318 .rhs = rhs, 319 } }, 320 }); 321 } 322 323 fn addArg(block: *Block, ty: Type) error{OutOfMemory}!Air.Inst.Ref { 324 return block.addInst(.{ 325 .tag = .arg, 326 .data = .{ .ty = ty }, 327 }); 328 } 329 330 fn addStructFieldPtr( 331 block: *Block, 332 struct_ptr: Air.Inst.Ref, 333 field_index: u32, 334 ptr_field_ty: Type, 335 ) !Air.Inst.Ref { 336 const ty = try block.sema.addType(ptr_field_ty); 337 const tag: Air.Inst.Tag = switch (field_index) { 338 0 => .struct_field_ptr_index_0, 339 1 => .struct_field_ptr_index_1, 340 2 => .struct_field_ptr_index_2, 341 3 => .struct_field_ptr_index_3, 342 else => { 343 return block.addInst(.{ 344 .tag = .struct_field_ptr, 345 .data = .{ .ty_pl = .{ 346 .ty = ty, 347 .payload = try block.sema.addExtra(Air.StructField{ 348 .struct_operand = struct_ptr, 349 .field_index = field_index, 350 }), 351 } }, 352 }); 353 }, 354 }; 355 return block.addInst(.{ 356 .tag = tag, 357 .data = .{ .ty_op = .{ 358 .ty = ty, 359 .operand = struct_ptr, 360 } }, 361 }); 362 } 363 364 fn addStructFieldVal( 365 block: *Block, 366 struct_val: Air.Inst.Ref, 367 field_index: u32, 368 field_ty: Type, 369 ) !Air.Inst.Ref { 370 return block.addInst(.{ 371 .tag = .struct_field_val, 372 .data = .{ .ty_pl = .{ 373 .ty = try block.sema.addType(field_ty), 374 .payload = try block.sema.addExtra(Air.StructField{ 375 .struct_operand = struct_val, 376 .field_index = field_index, 377 }), 378 } }, 379 }); 380 } 381 382 fn addSliceElemPtr( 383 block: *Block, 384 slice: Air.Inst.Ref, 385 elem_index: Air.Inst.Ref, 386 elem_ptr_ty: Type, 387 ) !Air.Inst.Ref { 388 return block.addInst(.{ 389 .tag = .slice_elem_ptr, 390 .data = .{ .ty_pl = .{ 391 .ty = try block.sema.addType(elem_ptr_ty), 392 .payload = try block.sema.addExtra(Air.Bin{ 393 .lhs = slice, 394 .rhs = elem_index, 395 }), 396 } }, 397 }); 398 } 399 400 fn addPtrElemPtr( 401 block: *Block, 402 array_ptr: Air.Inst.Ref, 403 elem_index: Air.Inst.Ref, 404 elem_ptr_ty: Type, 405 ) !Air.Inst.Ref { 406 const ty_ref = try block.sema.addType(elem_ptr_ty); 407 return block.addPtrElemPtrTypeRef(array_ptr, elem_index, ty_ref); 408 } 409 410 fn addPtrElemPtrTypeRef( 411 block: *Block, 412 array_ptr: Air.Inst.Ref, 413 elem_index: Air.Inst.Ref, 414 elem_ptr_ty: Air.Inst.Ref, 415 ) !Air.Inst.Ref { 416 return block.addInst(.{ 417 .tag = .ptr_elem_ptr, 418 .data = .{ .ty_pl = .{ 419 .ty = elem_ptr_ty, 420 .payload = try block.sema.addExtra(Air.Bin{ 421 .lhs = array_ptr, 422 .rhs = elem_index, 423 }), 424 } }, 425 }); 426 } 427 428 fn addCmpVector(block: *Block, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref, cmp_op: std.math.CompareOperator, vector_ty: Air.Inst.Ref) !Air.Inst.Ref { 429 return block.addInst(.{ 430 .tag = if (block.float_mode == .Optimized) .cmp_vector_optimized else .cmp_vector, 431 .data = .{ .ty_pl = .{ 432 .ty = vector_ty, 433 .payload = try block.sema.addExtra(Air.VectorCmp{ 434 .lhs = lhs, 435 .rhs = rhs, 436 .op = Air.VectorCmp.encodeOp(cmp_op), 437 }), 438 } }, 439 }); 440 } 441 442 fn addAggregateInit( 443 block: *Block, 444 aggregate_ty: Type, 445 elements: []const Air.Inst.Ref, 446 ) !Air.Inst.Ref { 447 const sema = block.sema; 448 const ty_ref = try sema.addType(aggregate_ty); 449 try sema.air_extra.ensureUnusedCapacity(sema.gpa, elements.len); 450 const extra_index = @intCast(u32, sema.air_extra.items.len); 451 sema.appendRefsAssumeCapacity(elements); 452 453 return block.addInst(.{ 454 .tag = .aggregate_init, 455 .data = .{ .ty_pl = .{ 456 .ty = ty_ref, 457 .payload = extra_index, 458 } }, 459 }); 460 } 461 462 fn addUnionInit( 463 block: *Block, 464 union_ty: Type, 465 field_index: u32, 466 init: Air.Inst.Ref, 467 ) !Air.Inst.Ref { 468 return block.addInst(.{ 469 .tag = .union_init, 470 .data = .{ .ty_pl = .{ 471 .ty = try block.sema.addType(union_ty), 472 .payload = try block.sema.addExtra(Air.UnionInit{ 473 .field_index = field_index, 474 .init = init, 475 }), 476 } }, 477 }); 478 } 479 480 pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref { 481 return Air.indexToRef(try block.addInstAsIndex(inst)); 482 } 483 484 pub fn addInstAsIndex(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Index { 485 const sema = block.sema; 486 const gpa = sema.gpa; 487 488 try sema.air_instructions.ensureUnusedCapacity(gpa, 1); 489 try block.instructions.ensureUnusedCapacity(gpa, 1); 490 491 const result_index = @intCast(Air.Inst.Index, sema.air_instructions.len); 492 sema.air_instructions.appendAssumeCapacity(inst); 493 block.instructions.appendAssumeCapacity(result_index); 494 return result_index; 495 } 496 497 fn addUnreachable(block: *Block, src: LazySrcLoc, safety_check: bool) !void { 498 if (safety_check and block.wantSafety()) { 499 _ = try block.sema.safetyPanic(block, src, .unreach); 500 } else { 501 _ = try block.addNoOp(.unreach); 502 } 503 } 504 505 pub fn startAnonDecl(block: *Block, src: LazySrcLoc) !WipAnonDecl { 506 return WipAnonDecl{ 507 .block = block, 508 .src = src, 509 .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa), 510 .finished = false, 511 }; 512 } 513 514 pub const WipAnonDecl = struct { 515 block: *Block, 516 src: LazySrcLoc, 517 new_decl_arena: std.heap.ArenaAllocator, 518 finished: bool, 519 520 pub fn arena(wad: *WipAnonDecl) Allocator { 521 return wad.new_decl_arena.allocator(); 522 } 523 524 pub fn deinit(wad: *WipAnonDecl) void { 525 if (!wad.finished) { 526 wad.new_decl_arena.deinit(); 527 } 528 wad.* = undefined; 529 } 530 531 /// `alignment` value of 0 means to use ABI alignment. 532 pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value, alignment: u32) !Decl.Index { 533 const sema = wad.block.sema; 534 // Do this ahead of time because `createAnonymousDecl` depends on calling 535 // `type.hasRuntimeBits()`. 536 _ = try sema.typeHasRuntimeBits(wad.block, wad.src, ty); 537 const new_decl_index = try sema.mod.createAnonymousDecl(wad.block, .{ 538 .ty = ty, 539 .val = val, 540 }); 541 const new_decl = sema.mod.declPtr(new_decl_index); 542 new_decl.@"align" = alignment; 543 errdefer sema.mod.abortAnonDecl(new_decl_index); 544 try new_decl.finalizeNewArena(&wad.new_decl_arena); 545 wad.finished = true; 546 return new_decl_index; 547 } 548 }; 549 }; 550 551 const LabeledBlock = struct { 552 block: Block, 553 label: Block.Label, 554 555 fn destroy(lb: *LabeledBlock, gpa: Allocator) void { 556 lb.block.instructions.deinit(gpa); 557 lb.label.merges.results.deinit(gpa); 558 lb.label.merges.br_list.deinit(gpa); 559 gpa.destroy(lb); 560 } 561 }; 562 563 pub fn deinit(sema: *Sema) void { 564 const gpa = sema.gpa; 565 sema.air_instructions.deinit(gpa); 566 sema.air_extra.deinit(gpa); 567 sema.air_values.deinit(gpa); 568 sema.inst_map.deinit(gpa); 569 sema.decl_val_table.deinit(gpa); 570 sema.types_to_resolve.deinit(gpa); 571 { 572 var it = sema.post_hoc_blocks.iterator(); 573 while (it.next()) |entry| { 574 const labeled_block = entry.value_ptr.*; 575 labeled_block.destroy(gpa); 576 } 577 sema.post_hoc_blocks.deinit(gpa); 578 } 579 sema.* = undefined; 580 } 581 582 /// Returns only the result from the body that is specified. 583 /// Only appropriate to call when it is determined at comptime that this body 584 /// has no peers. 585 fn resolveBody( 586 sema: *Sema, 587 block: *Block, 588 body: []const Zir.Inst.Index, 589 /// This is the instruction that a break instruction within `body` can 590 /// use to return from the body. 591 body_inst: Zir.Inst.Index, 592 ) CompileError!Air.Inst.Ref { 593 const break_data = (try sema.analyzeBodyBreak(block, body)) orelse 594 return Air.Inst.Ref.unreachable_value; 595 // For comptime control flow, we need to detect when `analyzeBody` reports 596 // that we need to break from an outer block. In such case we 597 // use Zig's error mechanism to send control flow up the stack until 598 // we find the corresponding block to this break. 599 if (block.is_comptime and break_data.block_inst != body_inst) { 600 sema.comptime_break_inst = break_data.inst; 601 return error.ComptimeBreak; 602 } 603 return try sema.resolveInst(break_data.operand); 604 } 605 606 pub fn analyzeBody( 607 sema: *Sema, 608 block: *Block, 609 body: []const Zir.Inst.Index, 610 ) !void { 611 _ = sema.analyzeBodyInner(block, body) catch |err| switch (err) { 612 error.ComptimeBreak => unreachable, // unexpected comptime control flow 613 else => |e| return e, 614 }; 615 } 616 617 const BreakData = struct { 618 block_inst: Zir.Inst.Index, 619 operand: Zir.Inst.Ref, 620 inst: Zir.Inst.Index, 621 }; 622 623 pub fn analyzeBodyBreak( 624 sema: *Sema, 625 block: *Block, 626 body: []const Zir.Inst.Index, 627 ) CompileError!?BreakData { 628 const break_inst = sema.analyzeBodyInner(block, body) catch |err| switch (err) { 629 error.ComptimeBreak => sema.comptime_break_inst, 630 else => |e| return e, 631 }; 632 if (block.instructions.items.len != 0 and 633 sema.typeOf(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1])).isNoReturn()) 634 return null; 635 const break_data = sema.code.instructions.items(.data)[break_inst].@"break"; 636 return BreakData{ 637 .block_inst = break_data.block_inst, 638 .operand = break_data.operand, 639 .inst = break_inst, 640 }; 641 } 642 643 /// ZIR instructions which are always `noreturn` return this. This matches the 644 /// return type of `analyzeBody` so that we can tail call them. 645 /// Only appropriate to return when the instruction is known to be NoReturn 646 /// solely based on the ZIR tag. 647 const always_noreturn: CompileError!Zir.Inst.Index = @as(Zir.Inst.Index, undefined); 648 649 /// This function is the main loop of `Sema` and it can be used in two different ways: 650 /// * The traditional way where there are N breaks out of the block and peer type 651 /// resolution is done on the break operands. In this case, the `Zir.Inst.Index` 652 /// part of the return value will be `undefined`, and callsites should ignore it, 653 /// finding the block result value via the block scope. 654 /// * The "flat" way. There is only 1 break out of the block, and it is with a `break_inline` 655 /// instruction. In this case, the `Zir.Inst.Index` part of the return value will be 656 /// the break instruction. This communicates both which block the break applies to, as 657 /// well as the operand. No block scope needs to be created for this strategy. 658 fn analyzeBodyInner( 659 sema: *Sema, 660 block: *Block, 661 body: []const Zir.Inst.Index, 662 ) CompileError!Zir.Inst.Index { 663 // No tracy calls here, to avoid interfering with the tail call mechanism. 664 665 const parent_capture_scope = block.wip_capture_scope; 666 667 var wip_captures = WipCaptureScope{ 668 .finalized = true, 669 .scope = parent_capture_scope, 670 .perm_arena = sema.perm_arena, 671 .gpa = sema.gpa, 672 }; 673 defer if (wip_captures.scope != parent_capture_scope) { 674 wip_captures.deinit(); 675 }; 676 677 const map = &sema.inst_map; 678 const tags = sema.code.instructions.items(.tag); 679 const datas = sema.code.instructions.items(.data); 680 681 var orig_captures: usize = parent_capture_scope.captures.count(); 682 683 var crash_info = crash_report.prepAnalyzeBody(sema, block, body); 684 crash_info.push(); 685 defer crash_info.pop(); 686 687 var dbg_block_begins: u32 = 0; 688 689 // We use a while(true) loop here to avoid a redundant way of breaking out of 690 // the loop. The only way to break out of the loop is with a `noreturn` 691 // instruction. 692 var i: usize = 0; 693 const result = while (true) { 694 crash_info.setBodyIndex(i); 695 const inst = body[i]; 696 std.log.scoped(.sema_zir).debug("sema ZIR {s} %{d}", .{ 697 sema.mod.declPtr(block.src_decl).src_namespace.file_scope.sub_file_path, inst, 698 }); 699 const air_inst: Air.Inst.Ref = switch (tags[inst]) { 700 // zig fmt: off 701 .alloc => try sema.zirAlloc(block, inst), 702 .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)), 703 .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)), 704 .alloc_inferred_comptime => try sema.zirAllocInferredComptime(inst, Type.initTag(.inferred_alloc_const)), 705 .alloc_inferred_comptime_mut => try sema.zirAllocInferredComptime(inst, Type.initTag(.inferred_alloc_mut)), 706 .alloc_mut => try sema.zirAllocMut(block, inst), 707 .alloc_comptime_mut => try sema.zirAllocComptime(block, inst), 708 .make_ptr_const => try sema.zirMakePtrConst(block, inst), 709 .anyframe_type => try sema.zirAnyframeType(block, inst), 710 .array_cat => try sema.zirArrayCat(block, inst), 711 .array_mul => try sema.zirArrayMul(block, inst), 712 .array_type => try sema.zirArrayType(block, inst), 713 .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst), 714 .vector_type => try sema.zirVectorType(block, inst), 715 .as => try sema.zirAs(block, inst), 716 .as_node => try sema.zirAsNode(block, inst), 717 .as_shift_operand => try sema.zirAsShiftOperand(block, inst), 718 .bit_and => try sema.zirBitwise(block, inst, .bit_and), 719 .bit_not => try sema.zirBitNot(block, inst), 720 .bit_or => try sema.zirBitwise(block, inst, .bit_or), 721 .bitcast => try sema.zirBitcast(block, inst), 722 .suspend_block => try sema.zirSuspendBlock(block, inst), 723 .bool_not => try sema.zirBoolNot(block, inst), 724 .bool_br_and => try sema.zirBoolBr(block, inst, false), 725 .bool_br_or => try sema.zirBoolBr(block, inst, true), 726 .c_import => try sema.zirCImport(block, inst), 727 .call => try sema.zirCall(block, inst), 728 .closure_get => try sema.zirClosureGet(block, inst), 729 .cmp_lt => try sema.zirCmp(block, inst, .lt), 730 .cmp_lte => try sema.zirCmp(block, inst, .lte), 731 .cmp_eq => try sema.zirCmpEq(block, inst, .eq, Air.Inst.Tag.fromCmpOp(.eq, block.float_mode == .Optimized)), 732 .cmp_gte => try sema.zirCmp(block, inst, .gte), 733 .cmp_gt => try sema.zirCmp(block, inst, .gt), 734 .cmp_neq => try sema.zirCmpEq(block, inst, .neq, Air.Inst.Tag.fromCmpOp(.neq, block.float_mode == .Optimized)), 735 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst), 736 .decl_ref => try sema.zirDeclRef(block, inst), 737 .decl_val => try sema.zirDeclVal(block, inst), 738 .load => try sema.zirLoad(block, inst), 739 .elem_ptr => try sema.zirElemPtr(block, inst), 740 .elem_ptr_node => try sema.zirElemPtrNode(block, inst), 741 .elem_ptr_imm => try sema.zirElemPtrImm(block, inst), 742 .elem_val => try sema.zirElemVal(block, inst), 743 .elem_val_node => try sema.zirElemValNode(block, inst), 744 .elem_type_index => try sema.zirElemTypeIndex(block, inst), 745 .enum_literal => try sema.zirEnumLiteral(block, inst), 746 .enum_to_int => try sema.zirEnumToInt(block, inst), 747 .int_to_enum => try sema.zirIntToEnum(block, inst), 748 .err_union_code => try sema.zirErrUnionCode(block, inst), 749 .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst), 750 .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst), 751 .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst), 752 .error_union_type => try sema.zirErrorUnionType(block, inst), 753 .error_value => try sema.zirErrorValue(block, inst), 754 .field_ptr => try sema.zirFieldPtr(block, inst, false), 755 .field_ptr_init => try sema.zirFieldPtr(block, inst, true), 756 .field_ptr_named => try sema.zirFieldPtrNamed(block, inst), 757 .field_val => try sema.zirFieldVal(block, inst), 758 .field_val_named => try sema.zirFieldValNamed(block, inst), 759 .field_call_bind => try sema.zirFieldCallBind(block, inst), 760 .func => try sema.zirFunc(block, inst, false), 761 .func_inferred => try sema.zirFunc(block, inst, true), 762 .func_fancy => try sema.zirFuncFancy(block, inst), 763 .import => try sema.zirImport(block, inst), 764 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst), 765 .int => try sema.zirInt(block, inst), 766 .int_big => try sema.zirIntBig(block, inst), 767 .float => try sema.zirFloat(block, inst), 768 .float128 => try sema.zirFloat128(block, inst), 769 .int_type => try sema.zirIntType(block, inst), 770 .is_non_err => try sema.zirIsNonErr(block, inst), 771 .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst), 772 .is_non_null => try sema.zirIsNonNull(block, inst), 773 .is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst), 774 .merge_error_sets => try sema.zirMergeErrorSets(block, inst), 775 .negate => try sema.zirNegate(block, inst), 776 .negate_wrap => try sema.zirNegateWrap(block, inst), 777 .optional_payload_safe => try sema.zirOptionalPayload(block, inst, true), 778 .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true), 779 .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false), 780 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false), 781 .optional_type => try sema.zirOptionalType(block, inst), 782 .ptr_type => try sema.zirPtrType(block, inst), 783 .overflow_arithmetic_ptr => try sema.zirOverflowArithmeticPtr(block, inst), 784 .ref => try sema.zirRef(block, inst), 785 .ret_err_value_code => try sema.zirRetErrValueCode(inst), 786 .shr => try sema.zirShr(block, inst, .shr), 787 .shr_exact => try sema.zirShr(block, inst, .shr_exact), 788 .slice_end => try sema.zirSliceEnd(block, inst), 789 .slice_sentinel => try sema.zirSliceSentinel(block, inst), 790 .slice_start => try sema.zirSliceStart(block, inst), 791 .str => try sema.zirStr(block, inst), 792 .switch_block => try sema.zirSwitchBlock(block, inst), 793 .switch_cond => try sema.zirSwitchCond(block, inst, false), 794 .switch_cond_ref => try sema.zirSwitchCond(block, inst, true), 795 .switch_capture => try sema.zirSwitchCapture(block, inst, false, false), 796 .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), 797 .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), 798 .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true), 799 .type_info => try sema.zirTypeInfo(block, inst), 800 .size_of => try sema.zirSizeOf(block, inst), 801 .bit_size_of => try sema.zirBitSizeOf(block, inst), 802 .typeof => try sema.zirTypeof(block, inst), 803 .typeof_builtin => try sema.zirTypeofBuiltin(block, inst), 804 .log2_int_type => try sema.zirLog2IntType(block, inst), 805 .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst), 806 .xor => try sema.zirBitwise(block, inst, .xor), 807 .struct_init_empty => try sema.zirStructInitEmpty(block, inst), 808 .struct_init => try sema.zirStructInit(block, inst, false), 809 .struct_init_ref => try sema.zirStructInit(block, inst, true), 810 .struct_init_anon => try sema.zirStructInitAnon(block, inst, false), 811 .struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true), 812 .array_init => try sema.zirArrayInit(block, inst, false), 813 .array_init_ref => try sema.zirArrayInit(block, inst, true), 814 .array_init_anon => try sema.zirArrayInitAnon(block, inst, false), 815 .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true), 816 .union_init => try sema.zirUnionInit(block, inst), 817 .field_type => try sema.zirFieldType(block, inst), 818 .field_type_ref => try sema.zirFieldTypeRef(block, inst), 819 .ptr_to_int => try sema.zirPtrToInt(block, inst), 820 .align_of => try sema.zirAlignOf(block, inst), 821 .bool_to_int => try sema.zirBoolToInt(block, inst), 822 .embed_file => try sema.zirEmbedFile(block, inst), 823 .error_name => try sema.zirErrorName(block, inst), 824 .tag_name => try sema.zirTagName(block, inst), 825 .type_name => try sema.zirTypeName(block, inst), 826 .frame_type => try sema.zirFrameType(block, inst), 827 .frame_size => try sema.zirFrameSize(block, inst), 828 .float_to_int => try sema.zirFloatToInt(block, inst), 829 .int_to_float => try sema.zirIntToFloat(block, inst), 830 .int_to_ptr => try sema.zirIntToPtr(block, inst), 831 .float_cast => try sema.zirFloatCast(block, inst), 832 .int_cast => try sema.zirIntCast(block, inst), 833 .ptr_cast => try sema.zirPtrCast(block, inst), 834 .truncate => try sema.zirTruncate(block, inst), 835 .align_cast => try sema.zirAlignCast(block, inst), 836 .has_decl => try sema.zirHasDecl(block, inst), 837 .has_field => try sema.zirHasField(block, inst), 838 .byte_swap => try sema.zirByteSwap(block, inst), 839 .bit_reverse => try sema.zirBitReverse(block, inst), 840 .bit_offset_of => try sema.zirBitOffsetOf(block, inst), 841 .offset_of => try sema.zirOffsetOf(block, inst), 842 .splat => try sema.zirSplat(block, inst), 843 .reduce => try sema.zirReduce(block, inst), 844 .shuffle => try sema.zirShuffle(block, inst), 845 .atomic_load => try sema.zirAtomicLoad(block, inst), 846 .atomic_rmw => try sema.zirAtomicRmw(block, inst), 847 .mul_add => try sema.zirMulAdd(block, inst), 848 .builtin_call => try sema.zirBuiltinCall(block, inst), 849 .field_parent_ptr => try sema.zirFieldParentPtr(block, inst), 850 .@"resume" => try sema.zirResume(block, inst), 851 .@"await" => try sema.zirAwait(block, inst), 852 .array_base_ptr => try sema.zirArrayBasePtr(block, inst), 853 .field_base_ptr => try sema.zirFieldBasePtr(block, inst), 854 855 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz), 856 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz), 857 .pop_count => try sema.zirBitCount(block, inst, .popcount, Value.popCount), 858 859 .sqrt => try sema.zirUnaryMath(block, inst, .sqrt, Value.sqrt), 860 .sin => try sema.zirUnaryMath(block, inst, .sin, Value.sin), 861 .cos => try sema.zirUnaryMath(block, inst, .cos, Value.cos), 862 .tan => try sema.zirUnaryMath(block, inst, .tan, Value.tan), 863 .exp => try sema.zirUnaryMath(block, inst, .exp, Value.exp), 864 .exp2 => try sema.zirUnaryMath(block, inst, .exp2, Value.exp2), 865 .log => try sema.zirUnaryMath(block, inst, .log, Value.log), 866 .log2 => try sema.zirUnaryMath(block, inst, .log2, Value.log2), 867 .log10 => try sema.zirUnaryMath(block, inst, .log10, Value.log10), 868 .fabs => try sema.zirUnaryMath(block, inst, .fabs, Value.fabs), 869 .floor => try sema.zirUnaryMath(block, inst, .floor, Value.floor), 870 .ceil => try sema.zirUnaryMath(block, inst, .ceil, Value.ceil), 871 .round => try sema.zirUnaryMath(block, inst, .round, Value.round), 872 .trunc => try sema.zirUnaryMath(block, inst, .trunc_float, Value.trunc), 873 874 .error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent), 875 .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon), 876 .error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func), 877 878 .add => try sema.zirArithmetic(block, inst, .add), 879 .addwrap => try sema.zirArithmetic(block, inst, .addwrap), 880 .add_sat => try sema.zirArithmetic(block, inst, .add_sat), 881 .mul => try sema.zirArithmetic(block, inst, .mul), 882 .mulwrap => try sema.zirArithmetic(block, inst, .mulwrap), 883 .mul_sat => try sema.zirArithmetic(block, inst, .mul_sat), 884 .sub => try sema.zirArithmetic(block, inst, .sub), 885 .subwrap => try sema.zirArithmetic(block, inst, .subwrap), 886 .sub_sat => try sema.zirArithmetic(block, inst, .sub_sat), 887 888 .div => try sema.zirDiv(block, inst), 889 .div_exact => try sema.zirDivExact(block, inst), 890 .div_floor => try sema.zirDivFloor(block, inst), 891 .div_trunc => try sema.zirDivTrunc(block, inst), 892 893 .mod_rem => try sema.zirModRem(block, inst), 894 .mod => try sema.zirMod(block, inst), 895 .rem => try sema.zirRem(block, inst), 896 897 .maximum => try sema.zirMinMax(block, inst, .max), 898 .minimum => try sema.zirMinMax(block, inst, .min), 899 900 .shl => try sema.zirShl(block, inst, .shl), 901 .shl_exact => try sema.zirShl(block, inst, .shl_exact), 902 .shl_sat => try sema.zirShl(block, inst, .shl_sat), 903 904 .ret_ptr => try sema.zirRetPtr(block, inst), 905 .ret_type => try sema.addType(sema.fn_ret_ty), 906 907 // Instructions that we know to *always* be noreturn based solely on their tag. 908 // These functions match the return type of analyzeBody so that we can 909 // tail call them here. 910 .compile_error => break sema.zirCompileError(block, inst), 911 .ret_tok => break sema.zirRetTok(block, inst), 912 .ret_node => break sema.zirRetNode(block, inst), 913 .ret_load => break sema.zirRetLoad(block, inst), 914 .ret_err_value => break sema.zirRetErrValue(block, inst), 915 .@"unreachable" => break sema.zirUnreachable(block, inst), 916 .panic => break sema.zirPanic(block, inst, false), 917 .panic_comptime => break sema.zirPanic(block, inst, true), 918 // zig fmt: on 919 920 .extended => ext: { 921 const extended = datas[inst].extended; 922 break :ext switch (extended.opcode) { 923 // zig fmt: off 924 .variable => try sema.zirVarExtended( block, extended), 925 .struct_decl => try sema.zirStructDecl( block, extended, inst), 926 .enum_decl => try sema.zirEnumDecl( block, extended, inst), 927 .union_decl => try sema.zirUnionDecl( block, extended, inst), 928 .opaque_decl => try sema.zirOpaqueDecl( block, extended, inst), 929 .this => try sema.zirThis( block, extended), 930 .ret_addr => try sema.zirRetAddr( block, extended), 931 .builtin_src => try sema.zirBuiltinSrc( block, extended), 932 .error_return_trace => try sema.zirErrorReturnTrace( block, extended), 933 .frame => try sema.zirFrame( block, extended), 934 .frame_address => try sema.zirFrameAddress( block, extended), 935 .alloc => try sema.zirAllocExtended( block, extended), 936 .builtin_extern => try sema.zirBuiltinExtern( block, extended), 937 .@"asm" => try sema.zirAsm( block, extended), 938 .typeof_peer => try sema.zirTypeofPeer( block, extended), 939 .compile_log => try sema.zirCompileLog( block, extended), 940 .add_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode), 941 .sub_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode), 942 .mul_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode), 943 .shl_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode), 944 .c_undef => try sema.zirCUndef( block, extended), 945 .c_include => try sema.zirCInclude( block, extended), 946 .c_define => try sema.zirCDefine( block, extended), 947 .wasm_memory_size => try sema.zirWasmMemorySize( block, extended), 948 .wasm_memory_grow => try sema.zirWasmMemoryGrow( block, extended), 949 .prefetch => try sema.zirPrefetch( block, extended), 950 .field_call_bind_named => try sema.zirFieldCallBindNamed(block, extended), 951 .err_set_cast => try sema.zirErrSetCast( block, extended), 952 .await_nosuspend => try sema.zirAwaitNosuspend( block, extended), 953 .select => try sema.zirSelect( block, extended), 954 .error_to_int => try sema.zirErrorToInt( block, extended), 955 .int_to_error => try sema.zirIntToError( block, extended), 956 .reify => try sema.zirReify( block, extended, inst), 957 .builtin_async_call => try sema.zirBuiltinAsyncCall( block, extended), 958 .cmpxchg => try sema.zirCmpxchg( block, extended), 959 960 // zig fmt: on 961 .fence => { 962 try sema.zirFence(block, extended); 963 i += 1; 964 continue; 965 }, 966 .set_float_mode => { 967 try sema.zirSetFloatMode(block, extended); 968 i += 1; 969 continue; 970 }, 971 .set_align_stack => { 972 try sema.zirSetAlignStack(block, extended); 973 i += 1; 974 continue; 975 }, 976 .breakpoint => { 977 if (!block.is_comptime) { 978 _ = try block.addNoOp(.breakpoint); 979 } 980 i += 1; 981 continue; 982 }, 983 }; 984 }, 985 986 // Instructions that we know can *never* be noreturn based solely on 987 // their tag. We avoid needlessly checking if they are noreturn and 988 // continue the loop. 989 // We also know that they cannot be referenced later, so we avoid 990 // putting them into the map. 991 .dbg_stmt => { 992 try sema.zirDbgStmt(block, inst); 993 i += 1; 994 continue; 995 }, 996 .dbg_var_ptr => { 997 try sema.zirDbgVar(block, inst, .dbg_var_ptr); 998 i += 1; 999 continue; 1000 }, 1001 .dbg_var_val => { 1002 try sema.zirDbgVar(block, inst, .dbg_var_val); 1003 i += 1; 1004 continue; 1005 }, 1006 .dbg_block_begin => { 1007 dbg_block_begins += 1; 1008 try sema.zirDbgBlockBegin(block); 1009 i += 1; 1010 continue; 1011 }, 1012 .dbg_block_end => { 1013 dbg_block_begins -= 1; 1014 try sema.zirDbgBlockEnd(block); 1015 i += 1; 1016 continue; 1017 }, 1018 .ensure_err_payload_void => { 1019 try sema.zirEnsureErrPayloadVoid(block, inst); 1020 i += 1; 1021 continue; 1022 }, 1023 .ensure_result_non_error => { 1024 try sema.zirEnsureResultNonError(block, inst); 1025 i += 1; 1026 continue; 1027 }, 1028 .ensure_result_used => { 1029 try sema.zirEnsureResultUsed(block, inst); 1030 i += 1; 1031 continue; 1032 }, 1033 .set_eval_branch_quota => { 1034 try sema.zirSetEvalBranchQuota(block, inst); 1035 i += 1; 1036 continue; 1037 }, 1038 .atomic_store => { 1039 try sema.zirAtomicStore(block, inst); 1040 i += 1; 1041 continue; 1042 }, 1043 .store => { 1044 try sema.zirStore(block, inst); 1045 i += 1; 1046 continue; 1047 }, 1048 .store_node => { 1049 try sema.zirStoreNode(block, inst); 1050 i += 1; 1051 continue; 1052 }, 1053 .store_to_block_ptr => { 1054 try sema.zirStoreToBlockPtr(block, inst); 1055 i += 1; 1056 continue; 1057 }, 1058 .store_to_inferred_ptr => { 1059 try sema.zirStoreToInferredPtr(block, inst); 1060 i += 1; 1061 continue; 1062 }, 1063 .resolve_inferred_alloc => { 1064 try sema.zirResolveInferredAlloc(block, inst); 1065 i += 1; 1066 continue; 1067 }, 1068 .validate_array_init_ty => { 1069 try sema.validateArrayInitTy(block, inst); 1070 i += 1; 1071 continue; 1072 }, 1073 .validate_struct_init_ty => { 1074 try sema.validateStructInitTy(block, inst); 1075 i += 1; 1076 continue; 1077 }, 1078 .validate_struct_init => { 1079 try sema.zirValidateStructInit(block, inst, false); 1080 i += 1; 1081 continue; 1082 }, 1083 .validate_struct_init_comptime => { 1084 try sema.zirValidateStructInit(block, inst, true); 1085 i += 1; 1086 continue; 1087 }, 1088 .validate_array_init => { 1089 try sema.zirValidateArrayInit(block, inst, false); 1090 i += 1; 1091 continue; 1092 }, 1093 .validate_array_init_comptime => { 1094 try sema.zirValidateArrayInit(block, inst, true); 1095 i += 1; 1096 continue; 1097 }, 1098 .validate_deref => { 1099 try sema.zirValidateDeref(block, inst); 1100 i += 1; 1101 continue; 1102 }, 1103 .@"export" => { 1104 try sema.zirExport(block, inst); 1105 i += 1; 1106 continue; 1107 }, 1108 .export_value => { 1109 try sema.zirExportValue(block, inst); 1110 i += 1; 1111 continue; 1112 }, 1113 .set_cold => { 1114 try sema.zirSetCold(block, inst); 1115 i += 1; 1116 continue; 1117 }, 1118 .set_runtime_safety => { 1119 try sema.zirSetRuntimeSafety(block, inst); 1120 i += 1; 1121 continue; 1122 }, 1123 .param => { 1124 try sema.zirParam(block, inst, false); 1125 i += 1; 1126 continue; 1127 }, 1128 .param_comptime => { 1129 try sema.zirParam(block, inst, true); 1130 i += 1; 1131 continue; 1132 }, 1133 .param_anytype => { 1134 try sema.zirParamAnytype(block, inst, false); 1135 i += 1; 1136 continue; 1137 }, 1138 .param_anytype_comptime => { 1139 try sema.zirParamAnytype(block, inst, true); 1140 i += 1; 1141 continue; 1142 }, 1143 .closure_capture => { 1144 try sema.zirClosureCapture(block, inst); 1145 i += 1; 1146 continue; 1147 }, 1148 .memcpy => { 1149 try sema.zirMemcpy(block, inst); 1150 i += 1; 1151 continue; 1152 }, 1153 .memset => { 1154 try sema.zirMemset(block, inst); 1155 i += 1; 1156 continue; 1157 }, 1158 .check_comptime_control_flow => { 1159 if (!block.is_comptime) { 1160 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 1161 const src = inst_data.src(); 1162 const inline_block = Zir.refToIndex(inst_data.operand).?; 1163 1164 var check_block = block; 1165 const target_runtime_index = while (true) { 1166 if (check_block.inline_block == inline_block) { 1167 break check_block.runtime_index; 1168 } 1169 check_block = check_block.parent.?; 1170 } else unreachable; 1171 1172 if (@enumToInt(target_runtime_index) < @enumToInt(block.runtime_index)) { 1173 const runtime_src = block.runtime_cond orelse block.runtime_loop.?; 1174 const msg = msg: { 1175 const msg = try sema.errMsg(block, src, "comptime control flow inside runtime block", .{}); 1176 errdefer msg.destroy(sema.gpa); 1177 1178 try sema.errNote(block, runtime_src, msg, "runtime control flow here", .{}); 1179 break :msg msg; 1180 }; 1181 return sema.failWithOwnedErrorMsg(msg); 1182 } 1183 } 1184 i += 1; 1185 continue; 1186 }, 1187 1188 // Special case instructions to handle comptime control flow. 1189 .@"break" => { 1190 if (block.is_comptime) { 1191 break inst; // same as break_inline 1192 } else { 1193 break sema.zirBreak(block, inst); 1194 } 1195 }, 1196 .break_inline => { 1197 if (block.is_comptime) { 1198 break inst; 1199 } else { 1200 sema.comptime_break_inst = inst; 1201 return error.ComptimeBreak; 1202 } 1203 }, 1204 .repeat => { 1205 if (block.is_comptime) { 1206 // Send comptime control flow back to the beginning of this block. 1207 const src = LazySrcLoc.nodeOffset(datas[inst].node); 1208 try sema.emitBackwardBranch(block, src); 1209 if (wip_captures.scope.captures.count() != orig_captures) { 1210 try wip_captures.reset(parent_capture_scope); 1211 block.wip_capture_scope = wip_captures.scope; 1212 orig_captures = 0; 1213 } 1214 i = 0; 1215 continue; 1216 } else { 1217 const src_node = sema.code.instructions.items(.data)[inst].node; 1218 const src = LazySrcLoc.nodeOffset(src_node); 1219 try sema.requireFunctionBlock(block, src); 1220 break always_noreturn; 1221 } 1222 }, 1223 .repeat_inline => { 1224 // Send comptime control flow back to the beginning of this block. 1225 const src = LazySrcLoc.nodeOffset(datas[inst].node); 1226 try sema.emitBackwardBranch(block, src); 1227 if (wip_captures.scope.captures.count() != orig_captures) { 1228 try wip_captures.reset(parent_capture_scope); 1229 block.wip_capture_scope = wip_captures.scope; 1230 orig_captures = 0; 1231 } 1232 i = 0; 1233 continue; 1234 }, 1235 .loop => blk: { 1236 if (!block.is_comptime) break :blk try sema.zirLoop(block, inst); 1237 // Same as `block_inline`. TODO https://github.com/ziglang/zig/issues/8220 1238 const inst_data = datas[inst].pl_node; 1239 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); 1240 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; 1241 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse 1242 break always_noreturn; 1243 if (inst == break_data.block_inst) { 1244 break :blk try sema.resolveInst(break_data.operand); 1245 } else { 1246 break break_data.inst; 1247 } 1248 }, 1249 .block => blk: { 1250 if (!block.is_comptime) break :blk try sema.zirBlock(block, inst); 1251 // Same as `block_inline`. TODO https://github.com/ziglang/zig/issues/8220 1252 const inst_data = datas[inst].pl_node; 1253 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); 1254 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; 1255 // If this block contains a function prototype, we need to reset the 1256 // current list of parameters and restore it later. 1257 // Note: this probably needs to be resolved in a more general manner. 1258 const prev_params = block.params; 1259 block.params = .{}; 1260 defer { 1261 block.params.deinit(sema.gpa); 1262 block.params = prev_params; 1263 } 1264 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse 1265 break always_noreturn; 1266 if (inst == break_data.block_inst) { 1267 break :blk try sema.resolveInst(break_data.operand); 1268 } else { 1269 break break_data.inst; 1270 } 1271 }, 1272 .block_inline => blk: { 1273 // Directly analyze the block body without introducing a new block. 1274 // However, in the case of a corresponding break_inline which reaches 1275 // through a runtime conditional branch, we must retroactively emit 1276 // a block, so we remember the block index here just in case. 1277 const block_index = block.instructions.items.len; 1278 const inst_data = datas[inst].pl_node; 1279 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); 1280 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; 1281 const gpa = sema.gpa; 1282 // If this block contains a function prototype, we need to reset the 1283 // current list of parameters and restore it later. 1284 // Note: this probably needs to be resolved in a more general manner. 1285 const prev_params = block.params; 1286 const prev_inline_block = block.inline_block; 1287 if (tags[inline_body[inline_body.len - 1]] == .repeat_inline) { 1288 block.inline_block = inline_body[0]; 1289 } 1290 block.params = .{}; 1291 defer { 1292 block.params.deinit(gpa); 1293 block.params = prev_params; 1294 block.inline_block = prev_inline_block; 1295 } 1296 const opt_break_data = try sema.analyzeBodyBreak(block, inline_body); 1297 // A runtime conditional branch that needs a post-hoc block to be 1298 // emitted communicates this by mapping the block index into the inst map. 1299 if (map.get(inst)) |new_block_ref| ph: { 1300 // Comptime control flow populates the map, so we don't actually know 1301 // if this is a post-hoc runtime block until we check the 1302 // post_hoc_block map. 1303 const new_block_inst = Air.refToIndex(new_block_ref) orelse break :ph; 1304 const labeled_block = sema.post_hoc_blocks.get(new_block_inst) orelse 1305 break :ph; 1306 1307 // In this case we need to move all the instructions starting at 1308 // block_index from the current block into this new one. 1309 1310 if (opt_break_data) |break_data| { 1311 // This is a comptime break which we now change to a runtime break 1312 // since it crosses a runtime branch. 1313 // It may pass through our currently being analyzed block_inline or it 1314 // may point directly to it. In the latter case, this modifies the 1315 // block that we are about to look up in the post_hoc_blocks map below. 1316 try sema.addRuntimeBreak(block, break_data); 1317 } else { 1318 // Here the comptime control flow ends with noreturn; however 1319 // we have runtime control flow continuing after this block. 1320 // This branch is therefore handled by the `i += 1; continue;` 1321 // logic below. 1322 } 1323 1324 try labeled_block.block.instructions.appendSlice(gpa, block.instructions.items[block_index..]); 1325 block.instructions.items.len = block_index; 1326 1327 const block_result = try sema.analyzeBlockBody(block, inst_data.src(), &labeled_block.block, &labeled_block.label.merges); 1328 { 1329 // Destroy the ad-hoc block entry so that it does not interfere with 1330 // the next iteration of comptime control flow, if any. 1331 labeled_block.destroy(gpa); 1332 assert(sema.post_hoc_blocks.remove(new_block_inst)); 1333 } 1334 try map.put(gpa, inst, block_result); 1335 i += 1; 1336 continue; 1337 } 1338 1339 const break_data = opt_break_data orelse break always_noreturn; 1340 if (inst == break_data.block_inst) { 1341 break :blk try sema.resolveInst(break_data.operand); 1342 } else { 1343 break break_data.inst; 1344 } 1345 }, 1346 .condbr => blk: { 1347 if (!block.is_comptime) break sema.zirCondbr(block, inst); 1348 // Same as condbr_inline. TODO https://github.com/ziglang/zig/issues/8220 1349 const inst_data = datas[inst].pl_node; 1350 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; 1351 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); 1352 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len]; 1353 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; 1354 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime known"); 1355 const inline_body = if (cond.val.toBool()) then_body else else_body; 1356 1357 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src); 1358 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse 1359 break always_noreturn; 1360 if (inst == break_data.block_inst) { 1361 break :blk try sema.resolveInst(break_data.operand); 1362 } else { 1363 break break_data.inst; 1364 } 1365 }, 1366 .condbr_inline => blk: { 1367 const inst_data = datas[inst].pl_node; 1368 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; 1369 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); 1370 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len]; 1371 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; 1372 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime known"); 1373 const inline_body = if (cond.val.toBool()) then_body else else_body; 1374 const old_runtime_index = block.runtime_index; 1375 defer block.runtime_index = old_runtime_index; 1376 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse 1377 break always_noreturn; 1378 if (inst == break_data.block_inst) { 1379 break :blk try sema.resolveInst(break_data.operand); 1380 } else { 1381 break break_data.inst; 1382 } 1383 }, 1384 .@"try" => blk: { 1385 if (!block.is_comptime) break :blk try sema.zirTry(block, inst); 1386 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 1387 const src = inst_data.src(); 1388 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 1389 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index); 1390 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; 1391 const err_union = try sema.resolveInst(extra.data.operand); 1392 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union); 1393 assert(is_non_err != .none); 1394 const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err, "try operand inside comptime block must be comptime known"); 1395 if (is_non_err_tv.val.toBool()) { 1396 const err_union_ty = sema.typeOf(err_union); 1397 break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false); 1398 } 1399 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse 1400 break always_noreturn; 1401 if (inst == break_data.block_inst) { 1402 break :blk try sema.resolveInst(break_data.operand); 1403 } else { 1404 break break_data.inst; 1405 } 1406 }, 1407 //.try_inline => blk: { 1408 // const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 1409 // const src = inst_data.src(); 1410 // const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 1411 // const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index); 1412 // const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; 1413 // const operand = try sema.resolveInst(extra.data.operand); 1414 // const operand_ty = sema.typeOf(operand); 1415 // const is_ptr = operand_ty.zigTypeTag() == .Pointer; 1416 // const err_union = if (is_ptr) 1417 // try sema.analyzeLoad(block, src, operand, operand_src) 1418 // else 1419 // operand; 1420 // const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union); 1421 // assert(is_non_err != .none); 1422 // const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err); 1423 // if (is_non_err_tv.val.toBool()) { 1424 // if (is_ptr) { 1425 // break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false); 1426 // } else { 1427 // const err_union_ty = sema.typeOf(err_union); 1428 // break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false); 1429 // } 1430 // } 1431 // const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse 1432 // break always_noreturn; 1433 // if (inst == break_data.block_inst) { 1434 // break :blk try sema.resolveInst(break_data.operand); 1435 // } else { 1436 // break break_data.inst; 1437 // } 1438 //}, 1439 .try_ptr => blk: { 1440 if (!block.is_comptime) break :blk try sema.zirTryPtr(block, inst); 1441 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 1442 const src = inst_data.src(); 1443 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 1444 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index); 1445 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; 1446 const operand = try sema.resolveInst(extra.data.operand); 1447 const err_union = try sema.analyzeLoad(block, src, operand, operand_src); 1448 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union); 1449 assert(is_non_err != .none); 1450 const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err, "try operand inside comptime block must be comptime known"); 1451 if (is_non_err_tv.val.toBool()) { 1452 break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false); 1453 } 1454 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse 1455 break always_noreturn; 1456 if (inst == break_data.block_inst) { 1457 break :blk try sema.resolveInst(break_data.operand); 1458 } else { 1459 break break_data.inst; 1460 } 1461 }, 1462 //.try_ptr_inline => blk: { 1463 // const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 1464 // const src = inst_data.src(); 1465 // const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 1466 // const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index); 1467 // const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; 1468 // const operand = try sema.resolveInst(extra.data.operand); 1469 // const err_union = try sema.analyzeLoad(block, src, operand, operand_src); 1470 // const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union); 1471 // assert(is_non_err != .none); 1472 // const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err); 1473 // if (is_non_err_tv.val.toBool()) { 1474 // break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false); 1475 // } 1476 // const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse 1477 // break always_noreturn; 1478 // if (inst == break_data.block_inst) { 1479 // break :blk try sema.resolveInst(break_data.operand); 1480 // } else { 1481 // break break_data.inst; 1482 // } 1483 //}, 1484 .@"defer" => blk: { 1485 const inst_data = sema.code.instructions.items(.data)[inst].@"defer"; 1486 const defer_body = sema.code.extra[inst_data.index..][0..inst_data.len]; 1487 const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) { 1488 error.ComptimeBreak => sema.comptime_break_inst, 1489 else => |e| return e, 1490 }; 1491 if (break_inst != defer_body[defer_body.len - 1]) break always_noreturn; 1492 break :blk Air.Inst.Ref.void_value; 1493 }, 1494 .defer_err_code => blk: { 1495 const inst_data = sema.code.instructions.items(.data)[inst].defer_err_code; 1496 const extra = sema.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data; 1497 const defer_body = sema.code.extra[extra.index..][0..extra.len]; 1498 const err_code = try sema.resolveInst(inst_data.err_code); 1499 try sema.inst_map.put(sema.gpa, extra.remapped_err_code, err_code); 1500 const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) { 1501 error.ComptimeBreak => sema.comptime_break_inst, 1502 else => |e| return e, 1503 }; 1504 if (break_inst != defer_body[defer_body.len - 1]) break always_noreturn; 1505 break :blk Air.Inst.Ref.void_value; 1506 }, 1507 }; 1508 if (sema.typeOf(air_inst).isNoReturn()) 1509 break always_noreturn; 1510 try map.put(sema.gpa, inst, air_inst); 1511 i += 1; 1512 } else unreachable; 1513 1514 // balance out dbg_block_begins in case of early noreturn 1515 const noreturn_inst = block.instructions.popOrNull(); 1516 while (dbg_block_begins > 0) { 1517 dbg_block_begins -= 1; 1518 if (block.is_comptime or sema.mod.comp.bin_file.options.strip) continue; 1519 1520 _ = try block.addInst(.{ 1521 .tag = .dbg_block_end, 1522 .data = undefined, 1523 }); 1524 } 1525 if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some); 1526 1527 if (!wip_captures.finalized) { 1528 try wip_captures.finalize(); 1529 block.wip_capture_scope = parent_capture_scope; 1530 } 1531 1532 return result; 1533 } 1534 1535 pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { 1536 var i: usize = @enumToInt(zir_ref); 1537 1538 // First section of indexes correspond to a set number of constant values. 1539 if (i < Zir.Inst.Ref.typed_value_map.len) { 1540 // We intentionally map the same indexes to the same values between ZIR and AIR. 1541 return zir_ref; 1542 } 1543 i -= Zir.Inst.Ref.typed_value_map.len; 1544 1545 // Finally, the last section of indexes refers to the map of ZIR=>AIR. 1546 const inst = sema.inst_map.get(@intCast(u32, i)).?; 1547 const ty = sema.typeOf(inst); 1548 if (ty.tag() == .generic_poison) return error.GenericPoison; 1549 return inst; 1550 } 1551 1552 fn resolveConstBool( 1553 sema: *Sema, 1554 block: *Block, 1555 src: LazySrcLoc, 1556 zir_ref: Zir.Inst.Ref, 1557 reason: []const u8, 1558 ) !bool { 1559 const air_inst = try sema.resolveInst(zir_ref); 1560 const wanted_type = Type.bool; 1561 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); 1562 const val = try sema.resolveConstValue(block, src, coerced_inst, reason); 1563 return val.toBool(); 1564 } 1565 1566 pub fn resolveConstString( 1567 sema: *Sema, 1568 block: *Block, 1569 src: LazySrcLoc, 1570 zir_ref: Zir.Inst.Ref, 1571 reason: []const u8, 1572 ) ![]u8 { 1573 const air_inst = try sema.resolveInst(zir_ref); 1574 const wanted_type = Type.initTag(.const_slice_u8); 1575 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); 1576 const val = try sema.resolveConstValue(block, src, coerced_inst, reason); 1577 return val.toAllocatedBytes(wanted_type, sema.arena, sema.mod); 1578 } 1579 1580 pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type { 1581 const air_inst = try sema.resolveInst(zir_ref); 1582 const ty = try sema.analyzeAsType(block, src, air_inst); 1583 if (ty.tag() == .generic_poison) return error.GenericPoison; 1584 return ty; 1585 } 1586 1587 fn analyzeAsType( 1588 sema: *Sema, 1589 block: *Block, 1590 src: LazySrcLoc, 1591 air_inst: Air.Inst.Ref, 1592 ) !Type { 1593 const wanted_type = Type.initTag(.@"type"); 1594 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); 1595 const val = try sema.resolveConstValue(block, src, coerced_inst, "types must be comptime known"); 1596 var buffer: Value.ToTypeBuffer = undefined; 1597 const ty = val.toType(&buffer); 1598 return ty.copy(sema.arena); 1599 } 1600 1601 pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void { 1602 const backend_supports_error_return_tracing = 1603 sema.mod.comp.bin_file.options.use_llvm; 1604 if (!backend_supports_error_return_tracing) { 1605 // TODO implement this feature in all the backends and then delete this branch 1606 return; 1607 } 1608 1609 var err_trace_block = block.makeSubBlock(); 1610 err_trace_block.is_comptime = false; 1611 defer err_trace_block.instructions.deinit(sema.gpa); 1612 1613 const src: LazySrcLoc = .unneeded; 1614 1615 // var addrs: [err_return_trace_addr_count]usize = undefined; 1616 const err_return_trace_addr_count = 32; 1617 const addr_arr_ty = try Type.array(sema.arena, err_return_trace_addr_count, null, Type.usize, sema.mod); 1618 const addrs_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, addr_arr_ty)); 1619 1620 // var st: StackTrace = undefined; 1621 const unresolved_stack_trace_ty = try sema.getBuiltinType(&err_trace_block, src, "StackTrace"); 1622 const stack_trace_ty = try sema.resolveTypeFields(&err_trace_block, src, unresolved_stack_trace_ty); 1623 const st_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty)); 1624 1625 // st.instruction_addresses = &addrs; 1626 const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "instruction_addresses", src, true); 1627 try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store); 1628 1629 // st.index = 0; 1630 const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src, true); 1631 try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, .zero_usize, src, .store); 1632 1633 // @errorReturnTrace() = &st; 1634 _ = try err_trace_block.addUnOp(.set_err_return_trace, st_ptr); 1635 1636 try block.instructions.insertSlice(sema.gpa, last_arg_index, err_trace_block.instructions.items); 1637 } 1638 1639 /// May return Value Tags: `variable`, `undef`. 1640 /// See `resolveConstValue` for an alternative. 1641 /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. 1642 fn resolveValue( 1643 sema: *Sema, 1644 block: *Block, 1645 src: LazySrcLoc, 1646 air_ref: Air.Inst.Ref, 1647 reason: []const u8, 1648 ) CompileError!Value { 1649 if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| { 1650 if (val.tag() == .generic_poison) return error.GenericPoison; 1651 return val; 1652 } 1653 return sema.failWithNeededComptime(block, src, reason); 1654 } 1655 1656 /// Value Tag `variable` will cause a compile error. 1657 /// Value Tag `undef` may be returned. 1658 fn resolveConstMaybeUndefVal( 1659 sema: *Sema, 1660 block: *Block, 1661 src: LazySrcLoc, 1662 inst: Air.Inst.Ref, 1663 reason: []const u8, 1664 ) CompileError!Value { 1665 if (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) |val| { 1666 switch (val.tag()) { 1667 .variable => return sema.failWithNeededComptime(block, src, reason), 1668 .generic_poison => return error.GenericPoison, 1669 else => return val, 1670 } 1671 } 1672 return sema.failWithNeededComptime(block, src, reason); 1673 } 1674 1675 /// Will not return Value Tags: `variable`, `undef`. Instead they will emit compile errors. 1676 /// See `resolveValue` for an alternative. 1677 fn resolveConstValue( 1678 sema: *Sema, 1679 block: *Block, 1680 src: LazySrcLoc, 1681 air_ref: Air.Inst.Ref, 1682 reason: []const u8, 1683 ) CompileError!Value { 1684 if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| { 1685 switch (val.tag()) { 1686 .undef => return sema.failWithUseOfUndef(block, src), 1687 .variable => return sema.failWithNeededComptime(block, src, reason), 1688 .generic_poison => return error.GenericPoison, 1689 else => return val, 1690 } 1691 } 1692 return sema.failWithNeededComptime(block, src, reason); 1693 } 1694 1695 /// Value Tag `variable` causes this function to return `null`. 1696 /// Value Tag `undef` causes this function to return a compile error. 1697 fn resolveDefinedValue( 1698 sema: *Sema, 1699 block: *Block, 1700 src: LazySrcLoc, 1701 air_ref: Air.Inst.Ref, 1702 ) CompileError!?Value { 1703 if (try sema.resolveMaybeUndefVal(block, src, air_ref)) |val| { 1704 if (val.isUndef()) { 1705 if (block.is_typeof) return null; 1706 return sema.failWithUseOfUndef(block, src); 1707 } 1708 return val; 1709 } 1710 return null; 1711 } 1712 1713 /// Value Tag `variable` causes this function to return `null`. 1714 /// Value Tag `undef` causes this function to return the Value. 1715 /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. 1716 fn resolveMaybeUndefVal( 1717 sema: *Sema, 1718 block: *Block, 1719 src: LazySrcLoc, 1720 inst: Air.Inst.Ref, 1721 ) CompileError!?Value { 1722 const val = (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) orelse return null; 1723 switch (val.tag()) { 1724 .variable => return null, 1725 .generic_poison => return error.GenericPoison, 1726 else => return val, 1727 } 1728 } 1729 1730 /// Value Tag `variable` results in `null`. 1731 /// Value Tag `undef` results in the Value. 1732 /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. 1733 /// Value Tag `decl_ref` and `decl_ref_mut` or any nested such value results in `null`. 1734 fn resolveMaybeUndefValIntable( 1735 sema: *Sema, 1736 block: *Block, 1737 src: LazySrcLoc, 1738 inst: Air.Inst.Ref, 1739 ) CompileError!?Value { 1740 const val = (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) orelse return null; 1741 var check = val; 1742 while (true) switch (check.tag()) { 1743 .variable, .decl_ref, .decl_ref_mut, .comptime_field_ptr => return null, 1744 .field_ptr => check = check.castTag(.field_ptr).?.data.container_ptr, 1745 .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr, 1746 .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr, 1747 .generic_poison => return error.GenericPoison, 1748 else => { 1749 try sema.resolveLazyValue(block, src, val); 1750 return val; 1751 }, 1752 }; 1753 } 1754 1755 /// Returns all Value tags including `variable` and `undef`. 1756 fn resolveMaybeUndefValAllowVariables( 1757 sema: *Sema, 1758 block: *Block, 1759 src: LazySrcLoc, 1760 inst: Air.Inst.Ref, 1761 ) CompileError!?Value { 1762 // First section of indexes correspond to a set number of constant values. 1763 var i: usize = @enumToInt(inst); 1764 if (i < Air.Inst.Ref.typed_value_map.len) { 1765 return Air.Inst.Ref.typed_value_map[i].val; 1766 } 1767 i -= Air.Inst.Ref.typed_value_map.len; 1768 1769 if (try sema.typeHasOnePossibleValue(block, src, sema.typeOf(inst))) |opv| { 1770 return opv; 1771 } 1772 const air_tags = sema.air_instructions.items(.tag); 1773 switch (air_tags[i]) { 1774 .constant => { 1775 const ty_pl = sema.air_instructions.items(.data)[i].ty_pl; 1776 const val = sema.air_values.items[ty_pl.payload]; 1777 if (val.tag() == .runtime_int) return null; 1778 return val; 1779 }, 1780 .const_ty => { 1781 return try sema.air_instructions.items(.data)[i].ty.toValue(sema.arena); 1782 }, 1783 else => return null, 1784 } 1785 } 1786 1787 fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: []const u8) CompileError { 1788 const msg = msg: { 1789 const msg = try sema.errMsg(block, src, "unable to resolve comptime value", .{}); 1790 errdefer msg.destroy(sema.gpa); 1791 1792 try sema.errNote(block, src, msg, "{s}", .{reason}); 1793 break :msg msg; 1794 }; 1795 return sema.failWithOwnedErrorMsg(msg); 1796 } 1797 1798 fn failWithUseOfUndef(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError { 1799 return sema.fail(block, src, "use of undefined value here causes undefined behavior", .{}); 1800 } 1801 1802 fn failWithDivideByZero(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError { 1803 return sema.fail(block, src, "division by zero here causes undefined behavior", .{}); 1804 } 1805 1806 fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: Type, rhs_ty: Type) CompileError { 1807 return sema.fail(block, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{ 1808 lhs_ty.fmt(sema.mod), rhs_ty.fmt(sema.mod), 1809 }); 1810 } 1811 1812 fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, optional_ty: Type) CompileError { 1813 return sema.fail(block, src, "expected optional type, found '{}'", .{optional_ty.fmt(sema.mod)}); 1814 } 1815 1816 fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { 1817 const msg = msg: { 1818 const msg = try sema.errMsg(block, src, "type '{}' does not support array initialization syntax", .{ 1819 ty.fmt(sema.mod), 1820 }); 1821 errdefer msg.destroy(sema.gpa); 1822 if (ty.isSlice()) { 1823 try sema.errNote(block, src, msg, "inferred array length is specified with an underscore: '[_]{}'", .{ty.elemType2().fmt(sema.mod)}); 1824 } 1825 break :msg msg; 1826 }; 1827 return sema.failWithOwnedErrorMsg(msg); 1828 } 1829 1830 fn failWithStructInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { 1831 return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{ 1832 ty.fmt(sema.mod), 1833 }); 1834 } 1835 1836 fn failWithErrorSetCodeMissing( 1837 sema: *Sema, 1838 block: *Block, 1839 src: LazySrcLoc, 1840 dest_err_set_ty: Type, 1841 src_err_set_ty: Type, 1842 ) CompileError { 1843 return sema.fail(block, src, "expected type '{}', found type '{}'", .{ 1844 dest_err_set_ty.fmt(sema.mod), src_err_set_ty.fmt(sema.mod), 1845 }); 1846 } 1847 1848 fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: usize) CompileError { 1849 if (int_ty.zigTypeTag() == .Vector) { 1850 const msg = msg: { 1851 const msg = try sema.errMsg(block, src, "overflow of vector type '{}' with value '{}'", .{ 1852 int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod), 1853 }); 1854 errdefer msg.destroy(sema.gpa); 1855 try sema.errNote(block, src, msg, "when computing vector element at index '{d}'", .{vector_index}); 1856 break :msg msg; 1857 }; 1858 return sema.failWithOwnedErrorMsg(msg); 1859 } 1860 return sema.fail(block, src, "overflow of integer type '{}' with value '{}'", .{ 1861 int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod), 1862 }); 1863 } 1864 1865 fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazySrcLoc, container_ty: Type, field_index: usize) CompileError { 1866 const msg = msg: { 1867 const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{}); 1868 errdefer msg.destroy(sema.gpa); 1869 1870 const decl_index = container_ty.getOwnerDeclOrNull() orelse break :msg msg; 1871 const decl = sema.mod.declPtr(decl_index); 1872 const tree = decl.getFileScope().getTree(sema.gpa) catch |err| { 1873 log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); 1874 return error.AnalysisFail; 1875 }; 1876 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index); 1877 const default_value_src: LazySrcLoc = .{ .node_offset_field_default = field_src.node_offset.x }; 1878 1879 try sema.mod.errNoteNonLazy(default_value_src.toSrcLoc(decl), msg, "default value set here", .{}); 1880 break :msg msg; 1881 }; 1882 return sema.failWithOwnedErrorMsg(msg); 1883 } 1884 1885 fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError { 1886 const msg = msg: { 1887 const msg = try sema.errMsg(block, src, "async has not been implemented in the self-hosted compiler yet", .{}); 1888 errdefer msg.destroy(sema.gpa); 1889 1890 try sema.errNote(block, src, msg, "to use async enable the stage1 compiler with either '-fstage1' or by setting '.use_stage1 = true` in your 'build.zig' script", .{}); 1891 break :msg msg; 1892 }; 1893 return sema.failWithOwnedErrorMsg(msg); 1894 } 1895 1896 /// We don't return a pointer to the new error note because the pointer 1897 /// becomes invalid when you add another one. 1898 fn errNote( 1899 sema: *Sema, 1900 block: *Block, 1901 src: LazySrcLoc, 1902 parent: *Module.ErrorMsg, 1903 comptime format: []const u8, 1904 args: anytype, 1905 ) error{OutOfMemory}!void { 1906 const mod = sema.mod; 1907 const src_decl = mod.declPtr(block.src_decl); 1908 return mod.errNoteNonLazy(src.toSrcLoc(src_decl), parent, format, args); 1909 } 1910 1911 fn addFieldErrNote( 1912 sema: *Sema, 1913 container_ty: Type, 1914 field_index: usize, 1915 parent: *Module.ErrorMsg, 1916 comptime format: []const u8, 1917 args: anytype, 1918 ) !void { 1919 const mod = sema.mod; 1920 const decl_index = container_ty.getOwnerDecl(); 1921 const decl = mod.declPtr(decl_index); 1922 const tree = decl.getFileScope().getTree(sema.gpa) catch |err| { 1923 log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); 1924 return error.AnalysisFail; 1925 }; 1926 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index); 1927 try mod.errNoteNonLazy(field_src.toSrcLoc(decl), parent, format, args); 1928 } 1929 1930 fn errMsg( 1931 sema: *Sema, 1932 block: *Block, 1933 src: LazySrcLoc, 1934 comptime format: []const u8, 1935 args: anytype, 1936 ) error{OutOfMemory}!*Module.ErrorMsg { 1937 const mod = sema.mod; 1938 const src_decl = mod.declPtr(block.src_decl); 1939 return Module.ErrorMsg.create(sema.gpa, src.toSrcLoc(src_decl), format, args); 1940 } 1941 1942 pub fn fail( 1943 sema: *Sema, 1944 block: *Block, 1945 src: LazySrcLoc, 1946 comptime format: []const u8, 1947 args: anytype, 1948 ) CompileError { 1949 const err_msg = try sema.errMsg(block, src, format, args); 1950 return sema.failWithOwnedErrorMsg(err_msg); 1951 } 1952 1953 fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { 1954 @setCold(true); 1955 1956 if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) { 1957 std.debug.print("compile error during Sema: {s}, src: {s}:{}\n", .{ 1958 err_msg.msg, 1959 err_msg.src_loc.file_scope.sub_file_path, 1960 err_msg.src_loc.lazy, 1961 }); 1962 crash_report.compilerPanic("unexpected compile error occurred", null, null); 1963 } 1964 1965 const mod = sema.mod; 1966 ref: { 1967 errdefer err_msg.destroy(mod.gpa); 1968 if (err_msg.src_loc.lazy == .unneeded) { 1969 return error.NeededSourceLocation; 1970 } 1971 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1); 1972 try mod.failed_files.ensureUnusedCapacity(mod.gpa, 1); 1973 1974 const max_references = blk: { 1975 if (sema.mod.comp.reference_trace) |num| break :blk num; 1976 // Do not add multiple traces without explicit request. 1977 if (sema.mod.failed_decls.count() != 0) break :ref; 1978 break :blk default_reference_trace_len; 1979 }; 1980 1981 var referenced_by = if (sema.func) |some| some.owner_decl else sema.owner_decl_index; 1982 var reference_stack = std.ArrayList(Module.ErrorMsg.Trace).init(sema.gpa); 1983 defer reference_stack.deinit(); 1984 1985 // Avoid infinite loops. 1986 var seen = std.AutoHashMap(Module.Decl.Index, void).init(sema.gpa); 1987 defer seen.deinit(); 1988 1989 var cur_reference_trace: u32 = 0; 1990 while (sema.mod.reference_table.get(referenced_by)) |ref| : (cur_reference_trace += 1) { 1991 const gop = try seen.getOrPut(ref.referencer); 1992 if (gop.found_existing) break; 1993 if (cur_reference_trace < max_references) { 1994 const decl = sema.mod.declPtr(ref.referencer); 1995 try reference_stack.append(.{ .decl = decl.name, .src_loc = ref.src.toSrcLoc(decl) }); 1996 } 1997 referenced_by = ref.referencer; 1998 } 1999 if (sema.mod.comp.reference_trace == null and cur_reference_trace > 0) { 2000 try reference_stack.append(.{ 2001 .decl = null, 2002 .src_loc = undefined, 2003 .hidden = 0, 2004 }); 2005 } else if (cur_reference_trace > max_references) { 2006 try reference_stack.append(.{ 2007 .decl = undefined, 2008 .src_loc = undefined, 2009 .hidden = cur_reference_trace - max_references, 2010 }); 2011 } 2012 err_msg.reference_trace = reference_stack.toOwnedSlice(); 2013 } 2014 if (sema.owner_func) |func| { 2015 func.state = .sema_failure; 2016 } else { 2017 sema.owner_decl.analysis = .sema_failure; 2018 sema.owner_decl.generation = mod.generation; 2019 } 2020 const gop = mod.failed_decls.getOrPutAssumeCapacity(sema.owner_decl_index); 2021 if (gop.found_existing) { 2022 // If there are multiple errors for the same Decl, prefer the first one added. 2023 sema.err = null; 2024 err_msg.destroy(mod.gpa); 2025 } else { 2026 sema.err = err_msg; 2027 gop.value_ptr.* = err_msg; 2028 } 2029 return error.AnalysisFail; 2030 } 2031 2032 const align_ty = Type.u29; 2033 2034 fn analyzeAsAlign( 2035 sema: *Sema, 2036 block: *Block, 2037 src: LazySrcLoc, 2038 air_ref: Air.Inst.Ref, 2039 ) !u32 { 2040 const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, "alignment must be comptime known"); 2041 const alignment = @intCast(u32, alignment_big); // We coerce to u16 in the prev line. 2042 try sema.validateAlign(block, src, alignment); 2043 return alignment; 2044 } 2045 2046 fn validateAlign( 2047 sema: *Sema, 2048 block: *Block, 2049 src: LazySrcLoc, 2050 alignment: u32, 2051 ) !void { 2052 if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{}); 2053 if (!std.math.isPowerOfTwo(alignment)) { 2054 return sema.fail(block, src, "alignment value '{d}' is not a power of two", .{ 2055 alignment, 2056 }); 2057 } 2058 } 2059 2060 pub fn resolveAlign( 2061 sema: *Sema, 2062 block: *Block, 2063 src: LazySrcLoc, 2064 zir_ref: Zir.Inst.Ref, 2065 ) !u32 { 2066 const air_ref = try sema.resolveInst(zir_ref); 2067 return analyzeAsAlign(sema, block, src, air_ref); 2068 } 2069 2070 fn resolveInt( 2071 sema: *Sema, 2072 block: *Block, 2073 src: LazySrcLoc, 2074 zir_ref: Zir.Inst.Ref, 2075 dest_ty: Type, 2076 reason: []const u8, 2077 ) !u64 { 2078 const air_ref = try sema.resolveInst(zir_ref); 2079 return analyzeAsInt(sema, block, src, air_ref, dest_ty, reason); 2080 } 2081 2082 fn analyzeAsInt( 2083 sema: *Sema, 2084 block: *Block, 2085 src: LazySrcLoc, 2086 air_ref: Air.Inst.Ref, 2087 dest_ty: Type, 2088 reason: []const u8, 2089 ) !u64 { 2090 const coerced = try sema.coerce(block, dest_ty, air_ref, src); 2091 const val = try sema.resolveConstValue(block, src, coerced, reason); 2092 const target = sema.mod.getTarget(); 2093 return (try val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?; 2094 } 2095 2096 // Returns a compile error if the value has tag `variable`. See `resolveInstValue` for 2097 // a function that does not. 2098 pub fn resolveInstConst( 2099 sema: *Sema, 2100 block: *Block, 2101 src: LazySrcLoc, 2102 zir_ref: Zir.Inst.Ref, 2103 reason: []const u8, 2104 ) CompileError!TypedValue { 2105 const air_ref = try sema.resolveInst(zir_ref); 2106 const val = try sema.resolveConstValue(block, src, air_ref, reason); 2107 return TypedValue{ 2108 .ty = sema.typeOf(air_ref), 2109 .val = val, 2110 }; 2111 } 2112 2113 // Value Tag may be `undef` or `variable`. 2114 // See `resolveInstConst` for an alternative. 2115 pub fn resolveInstValue( 2116 sema: *Sema, 2117 block: *Block, 2118 src: LazySrcLoc, 2119 zir_ref: Zir.Inst.Ref, 2120 reason: []const u8, 2121 ) CompileError!TypedValue { 2122 const air_ref = try sema.resolveInst(zir_ref); 2123 const val = try sema.resolveValue(block, src, air_ref, reason); 2124 return TypedValue{ 2125 .ty = sema.typeOf(air_ref), 2126 .val = val, 2127 }; 2128 } 2129 2130 fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 2131 const tracy = trace(@src()); 2132 defer tracy.end(); 2133 2134 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 2135 const src = inst_data.src(); 2136 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 2137 const pointee_ty = try sema.resolveType(block, src, extra.lhs); 2138 const ptr = try sema.resolveInst(extra.rhs); 2139 const target = sema.mod.getTarget(); 2140 const addr_space = target_util.defaultAddressSpace(target, .local); 2141 2142 if (Air.refToIndex(ptr)) |ptr_inst| { 2143 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) { 2144 const air_datas = sema.air_instructions.items(.data); 2145 const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; 2146 switch (ptr_val.tag()) { 2147 .inferred_alloc => { 2148 const inferred_alloc = &ptr_val.castTag(.inferred_alloc).?.data; 2149 // Add the stored instruction to the set we will use to resolve peer types 2150 // for the inferred allocation. 2151 // This instruction will not make it to codegen; it is only to participate 2152 // in the `stored_inst_list` of the `inferred_alloc`. 2153 var trash_block = block.makeSubBlock(); 2154 defer trash_block.instructions.deinit(sema.gpa); 2155 const operand = try trash_block.addBitCast(pointee_ty, .void_value); 2156 2157 try sema.requireFunctionBlock(block, src); 2158 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 2159 .pointee_type = pointee_ty, 2160 .@"align" = inferred_alloc.alignment, 2161 .@"addrspace" = addr_space, 2162 }); 2163 const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr); 2164 2165 try inferred_alloc.prongs.append(sema.arena, .{ 2166 .stored_inst = operand, 2167 .placeholder = Air.refToIndex(bitcasted_ptr).?, 2168 }); 2169 2170 return bitcasted_ptr; 2171 }, 2172 .inferred_alloc_comptime => { 2173 const iac = ptr_val.castTag(.inferred_alloc_comptime).?; 2174 // There will be only one coerce_result_ptr because we are running at comptime. 2175 // The alloc will turn into a Decl. 2176 var anon_decl = try block.startAnonDecl(src); 2177 defer anon_decl.deinit(); 2178 iac.data.decl_index = try anon_decl.finish( 2179 try pointee_ty.copy(anon_decl.arena()), 2180 Value.undef, 2181 iac.data.alignment, 2182 ); 2183 if (iac.data.alignment != 0) { 2184 try sema.resolveTypeLayout(block, src, pointee_ty); 2185 } 2186 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 2187 .pointee_type = pointee_ty, 2188 .@"align" = iac.data.alignment, 2189 .@"addrspace" = addr_space, 2190 }); 2191 return sema.addConstant( 2192 ptr_ty, 2193 try Value.Tag.decl_ref_mut.create(sema.arena, .{ 2194 .decl_index = iac.data.decl_index, 2195 .runtime_index = block.runtime_index, 2196 }), 2197 ); 2198 }, 2199 else => {}, 2200 } 2201 } 2202 } 2203 2204 // Make a dummy store through the pointer to test the coercion. 2205 // We will then use the generated instructions to decide what 2206 // kind of transformations to make on the result pointer. 2207 var trash_block = block.makeSubBlock(); 2208 trash_block.is_comptime = false; 2209 trash_block.is_coerce_result_ptr = true; 2210 defer trash_block.instructions.deinit(sema.gpa); 2211 2212 const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr)); 2213 const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value); 2214 return coerceResultPtr(sema, block, src, ptr, dummy_ptr, dummy_operand, &trash_block); 2215 } 2216 2217 fn coerceResultPtr( 2218 sema: *Sema, 2219 block: *Block, 2220 src: LazySrcLoc, 2221 ptr: Air.Inst.Ref, 2222 dummy_ptr: Air.Inst.Ref, 2223 dummy_operand: Air.Inst.Ref, 2224 trash_block: *Block, 2225 ) CompileError!Air.Inst.Ref { 2226 const target = sema.mod.getTarget(); 2227 const addr_space = target_util.defaultAddressSpace(target, .local); 2228 const pointee_ty = sema.typeOf(dummy_operand); 2229 const prev_trash_len = trash_block.instructions.items.len; 2230 2231 try sema.storePtr2(trash_block, src, dummy_ptr, src, dummy_operand, src, .bitcast); 2232 2233 { 2234 const air_tags = sema.air_instructions.items(.tag); 2235 2236 //std.debug.print("dummy storePtr instructions:\n", .{}); 2237 //for (trash_block.instructions.items) |item| { 2238 // std.debug.print(" {s}\n", .{@tagName(air_tags[item])}); 2239 //} 2240 2241 // The last one is always `store`. 2242 const trash_inst = trash_block.instructions.items[trash_block.instructions.items.len - 1]; 2243 if (air_tags[trash_inst] != .store) { 2244 // no store instruction is generated for zero sized types 2245 assert((try sema.typeHasOnePossibleValue(block, src, pointee_ty)) != null); 2246 } else { 2247 trash_block.instructions.items.len -= 1; 2248 assert(trash_inst == sema.air_instructions.len - 1); 2249 sema.air_instructions.len -= 1; 2250 } 2251 } 2252 2253 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 2254 .pointee_type = pointee_ty, 2255 .@"addrspace" = addr_space, 2256 }); 2257 2258 var new_ptr = ptr; 2259 2260 while (true) { 2261 const air_tags = sema.air_instructions.items(.tag); 2262 const air_datas = sema.air_instructions.items(.data); 2263 2264 if (trash_block.instructions.items.len == prev_trash_len) { 2265 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| { 2266 return sema.addConstant(ptr_ty, ptr_val); 2267 } 2268 if (pointee_ty.eql(Type.@"null", sema.mod)) { 2269 const opt_ty = sema.typeOf(new_ptr).childType(); 2270 const null_inst = try sema.addConstant(opt_ty, Value.@"null"); 2271 _ = try block.addBinOp(.store, new_ptr, null_inst); 2272 return Air.Inst.Ref.void_value; 2273 } 2274 return sema.bitCast(block, ptr_ty, new_ptr, src); 2275 } 2276 2277 const trash_inst = trash_block.instructions.pop(); 2278 2279 switch (air_tags[trash_inst]) { 2280 .bitcast => { 2281 const ty_op = air_datas[trash_inst].ty_op; 2282 const operand_ty = sema.typeOf(ty_op.operand); 2283 const ptr_operand_ty = try Type.ptr(sema.arena, sema.mod, .{ 2284 .pointee_type = operand_ty, 2285 .@"addrspace" = addr_space, 2286 }); 2287 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| { 2288 new_ptr = try sema.addConstant(ptr_operand_ty, ptr_val); 2289 } else { 2290 new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src); 2291 } 2292 }, 2293 .wrap_optional => { 2294 new_ptr = try sema.analyzeOptionalPayloadPtr(block, src, new_ptr, false, true); 2295 }, 2296 .wrap_errunion_err => { 2297 return sema.fail(block, src, "TODO coerce_result_ptr wrap_errunion_err", .{}); 2298 }, 2299 .wrap_errunion_payload => { 2300 new_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, new_ptr, false, true); 2301 }, 2302 else => { 2303 if (std.debug.runtime_safety) { 2304 std.debug.panic("unexpected AIR tag for coerce_result_ptr: {}", .{ 2305 air_tags[trash_inst], 2306 }); 2307 } else { 2308 unreachable; 2309 } 2310 }, 2311 } 2312 } 2313 } 2314 2315 pub fn analyzeStructDecl( 2316 sema: *Sema, 2317 new_decl: *Decl, 2318 inst: Zir.Inst.Index, 2319 struct_obj: *Module.Struct, 2320 ) SemaError!void { 2321 const extended = sema.code.instructions.items(.data)[inst].extended; 2322 assert(extended.opcode == .struct_decl); 2323 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); 2324 2325 struct_obj.known_non_opv = small.known_non_opv; 2326 if (small.known_comptime_only) { 2327 struct_obj.requires_comptime = .yes; 2328 } 2329 2330 var extra_index: usize = extended.operand; 2331 extra_index += @boolToInt(small.has_src_node); 2332 extra_index += @boolToInt(small.has_fields_len); 2333 const decls_len = if (small.has_decls_len) blk: { 2334 const decls_len = sema.code.extra[extra_index]; 2335 extra_index += 1; 2336 break :blk decls_len; 2337 } else 0; 2338 2339 if (small.has_backing_int) { 2340 const backing_int_body_len = sema.code.extra[extra_index]; 2341 extra_index += 1; // backing_int_body_len 2342 if (backing_int_body_len == 0) { 2343 extra_index += 1; // backing_int_ref 2344 } else { 2345 extra_index += backing_int_body_len; // backing_int_body_inst 2346 } 2347 } 2348 2349 _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra_index, decls_len, new_decl); 2350 } 2351 2352 fn zirStructDecl( 2353 sema: *Sema, 2354 block: *Block, 2355 extended: Zir.Inst.Extended.InstData, 2356 inst: Zir.Inst.Index, 2357 ) CompileError!Air.Inst.Ref { 2358 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); 2359 const src: LazySrcLoc = if (small.has_src_node) blk: { 2360 const node_offset = @bitCast(i32, sema.code.extra[extended.operand]); 2361 break :blk LazySrcLoc.nodeOffset(node_offset); 2362 } else sema.src; 2363 2364 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); 2365 errdefer new_decl_arena.deinit(); 2366 const new_decl_arena_allocator = new_decl_arena.allocator(); 2367 2368 const mod = sema.mod; 2369 const struct_obj = try new_decl_arena_allocator.create(Module.Struct); 2370 const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); 2371 const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); 2372 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 2373 .ty = Type.type, 2374 .val = struct_val, 2375 }, small.name_strategy, "struct", inst); 2376 const new_decl = mod.declPtr(new_decl_index); 2377 new_decl.owns_tv = true; 2378 errdefer mod.abortAnonDecl(new_decl_index); 2379 struct_obj.* = .{ 2380 .owner_decl = new_decl_index, 2381 .fields = .{}, 2382 .zir_index = inst, 2383 .layout = small.layout, 2384 .status = .none, 2385 .known_non_opv = undefined, 2386 .namespace = .{ 2387 .parent = block.namespace, 2388 .ty = struct_ty, 2389 .file_scope = block.getFileScope(), 2390 }, 2391 }; 2392 std.log.scoped(.module).debug("create struct {*} owned by {*} ({s})", .{ 2393 &struct_obj.namespace, new_decl, new_decl.name, 2394 }); 2395 try sema.analyzeStructDecl(new_decl, inst, struct_obj); 2396 try new_decl.finalizeNewArena(&new_decl_arena); 2397 return sema.analyzeDeclVal(block, src, new_decl_index); 2398 } 2399 2400 fn createAnonymousDeclTypeNamed( 2401 sema: *Sema, 2402 block: *Block, 2403 src: LazySrcLoc, 2404 typed_value: TypedValue, 2405 name_strategy: Zir.Inst.NameStrategy, 2406 anon_prefix: []const u8, 2407 inst: ?Zir.Inst.Index, 2408 ) !Decl.Index { 2409 const mod = sema.mod; 2410 const namespace = block.namespace; 2411 const src_scope = block.wip_capture_scope; 2412 const src_decl = mod.declPtr(block.src_decl); 2413 const src_node = src_decl.relativeToNodeIndex(src.node_offset.x); 2414 const new_decl_index = try mod.allocateNewDecl(namespace, src_node, src_scope); 2415 errdefer mod.destroyDecl(new_decl_index); 2416 2417 switch (name_strategy) { 2418 .anon => { 2419 // It would be neat to have "struct:line:column" but this name has 2420 // to survive incremental updates, where it may have been shifted down 2421 // or up to a different line, but unchanged, and thus not unnecessarily 2422 // semantically analyzed. 2423 // This name is also used as the key in the parent namespace so it cannot be 2424 // renamed. 2425 const name = try std.fmt.allocPrintZ(sema.gpa, "{s}__{s}_{d}", .{ 2426 src_decl.name, anon_prefix, @enumToInt(new_decl_index), 2427 }); 2428 errdefer sema.gpa.free(name); 2429 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); 2430 return new_decl_index; 2431 }, 2432 .parent => { 2433 const name = try sema.gpa.dupeZ(u8, mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0)); 2434 errdefer sema.gpa.free(name); 2435 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); 2436 return new_decl_index; 2437 }, 2438 .func => { 2439 const fn_info = sema.code.getFnInfo(sema.func.?.zir_body_inst); 2440 const zir_tags = sema.code.instructions.items(.tag); 2441 2442 var buf = std.ArrayList(u8).init(sema.gpa); 2443 defer buf.deinit(); 2444 try buf.appendSlice(mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0)); 2445 try buf.appendSlice("("); 2446 2447 var arg_i: usize = 0; 2448 for (fn_info.param_body) |zir_inst| switch (zir_tags[zir_inst]) { 2449 .param, .param_comptime, .param_anytype, .param_anytype_comptime => { 2450 const arg = sema.inst_map.get(zir_inst).?; 2451 // The comptime call code in analyzeCall already did this, so we're 2452 // just repeating it here and it's guaranteed to work. 2453 const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg, undefined) catch unreachable; 2454 2455 if (arg_i != 0) try buf.appendSlice(","); 2456 try buf.writer().print("{}", .{arg_val.fmtValue(sema.typeOf(arg), sema.mod)}); 2457 2458 arg_i += 1; 2459 continue; 2460 }, 2461 else => continue, 2462 }; 2463 2464 try buf.appendSlice(")"); 2465 const name = try buf.toOwnedSliceSentinel(0); 2466 errdefer sema.gpa.free(name); 2467 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); 2468 return new_decl_index; 2469 }, 2470 .dbg_var => { 2471 const ref = Zir.indexToRef(inst.?); 2472 const zir_tags = sema.code.instructions.items(.tag); 2473 const zir_data = sema.code.instructions.items(.data); 2474 var i = inst.?; 2475 while (i < zir_tags.len) : (i += 1) switch (zir_tags[i]) { 2476 .dbg_var_ptr, .dbg_var_val => { 2477 if (zir_data[i].str_op.operand != ref) continue; 2478 2479 const name = try std.fmt.allocPrintZ(sema.gpa, "{s}.{s}", .{ 2480 src_decl.name, zir_data[i].str_op.getStr(sema.code), 2481 }); 2482 errdefer sema.gpa.free(name); 2483 2484 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); 2485 return new_decl_index; 2486 }, 2487 else => {}, 2488 }; 2489 return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null); 2490 }, 2491 } 2492 } 2493 2494 fn zirEnumDecl( 2495 sema: *Sema, 2496 block: *Block, 2497 extended: Zir.Inst.Extended.InstData, 2498 inst: Zir.Inst.Index, 2499 ) CompileError!Air.Inst.Ref { 2500 const tracy = trace(@src()); 2501 defer tracy.end(); 2502 2503 const mod = sema.mod; 2504 const gpa = sema.gpa; 2505 const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small); 2506 var extra_index: usize = extended.operand; 2507 2508 const src: LazySrcLoc = if (small.has_src_node) blk: { 2509 const node_offset = @bitCast(i32, sema.code.extra[extra_index]); 2510 extra_index += 1; 2511 break :blk LazySrcLoc.nodeOffset(node_offset); 2512 } else sema.src; 2513 const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x }; 2514 2515 const tag_type_ref = if (small.has_tag_type) blk: { 2516 const tag_type_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 2517 extra_index += 1; 2518 break :blk tag_type_ref; 2519 } else .none; 2520 2521 const body_len = if (small.has_body_len) blk: { 2522 const body_len = sema.code.extra[extra_index]; 2523 extra_index += 1; 2524 break :blk body_len; 2525 } else 0; 2526 2527 const fields_len = if (small.has_fields_len) blk: { 2528 const fields_len = sema.code.extra[extra_index]; 2529 extra_index += 1; 2530 break :blk fields_len; 2531 } else 0; 2532 2533 const decls_len = if (small.has_decls_len) blk: { 2534 const decls_len = sema.code.extra[extra_index]; 2535 extra_index += 1; 2536 break :blk decls_len; 2537 } else 0; 2538 2539 var done = false; 2540 2541 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 2542 errdefer if (!done) new_decl_arena.deinit(); 2543 const new_decl_arena_allocator = new_decl_arena.allocator(); 2544 2545 const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull); 2546 const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumFull); 2547 enum_ty_payload.* = .{ 2548 .base = .{ .tag = if (small.nonexhaustive) .enum_nonexhaustive else .enum_full }, 2549 .data = enum_obj, 2550 }; 2551 const enum_ty = Type.initPayload(&enum_ty_payload.base); 2552 const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); 2553 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 2554 .ty = Type.type, 2555 .val = enum_val, 2556 }, small.name_strategy, "enum", inst); 2557 const new_decl = mod.declPtr(new_decl_index); 2558 new_decl.owns_tv = true; 2559 errdefer if (!done) mod.abortAnonDecl(new_decl_index); 2560 2561 enum_obj.* = .{ 2562 .owner_decl = new_decl_index, 2563 .tag_ty = Type.@"null", 2564 .tag_ty_inferred = true, 2565 .fields = .{}, 2566 .values = .{}, 2567 .namespace = .{ 2568 .parent = block.namespace, 2569 .ty = enum_ty, 2570 .file_scope = block.getFileScope(), 2571 }, 2572 }; 2573 std.log.scoped(.module).debug("create enum {*} owned by {*} ({s})", .{ 2574 &enum_obj.namespace, new_decl, new_decl.name, 2575 }); 2576 2577 try new_decl.finalizeNewArena(&new_decl_arena); 2578 const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index); 2579 done = true; 2580 2581 var decl_arena = new_decl.value_arena.?.promote(gpa); 2582 defer new_decl.value_arena.?.* = decl_arena.state; 2583 const decl_arena_allocator = decl_arena.allocator(); 2584 2585 extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl); 2586 2587 const body = sema.code.extra[extra_index..][0..body_len]; 2588 extra_index += body.len; 2589 2590 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; 2591 const body_end = extra_index; 2592 extra_index += bit_bags_count; 2593 2594 { 2595 // We create a block for the field type instructions because they 2596 // may need to reference Decls from inside the enum namespace. 2597 // Within the field type, default value, and alignment expressions, the "owner decl" 2598 // should be the enum itself. 2599 2600 const prev_owner_decl = sema.owner_decl; 2601 const prev_owner_decl_index = sema.owner_decl_index; 2602 sema.owner_decl = new_decl; 2603 sema.owner_decl_index = new_decl_index; 2604 defer { 2605 sema.owner_decl = prev_owner_decl; 2606 sema.owner_decl_index = prev_owner_decl_index; 2607 } 2608 2609 const prev_owner_func = sema.owner_func; 2610 sema.owner_func = null; 2611 defer sema.owner_func = prev_owner_func; 2612 2613 const prev_func = sema.func; 2614 sema.func = null; 2615 defer sema.func = prev_func; 2616 2617 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope); 2618 defer wip_captures.deinit(); 2619 2620 var enum_block: Block = .{ 2621 .parent = null, 2622 .sema = sema, 2623 .src_decl = new_decl_index, 2624 .namespace = &enum_obj.namespace, 2625 .wip_capture_scope = wip_captures.scope, 2626 .instructions = .{}, 2627 .inlining = null, 2628 .is_comptime = true, 2629 }; 2630 defer assert(enum_block.instructions.items.len == 0); // should all be comptime instructions 2631 2632 if (body.len != 0) { 2633 try sema.analyzeBody(&enum_block, body); 2634 } 2635 2636 try wip_captures.finalize(); 2637 2638 if (tag_type_ref != .none) { 2639 const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref); 2640 if (ty.zigTypeTag() != .Int and ty.zigTypeTag() != .ComptimeInt) { 2641 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)}); 2642 } 2643 enum_obj.tag_ty = try ty.copy(decl_arena_allocator); 2644 enum_obj.tag_ty_inferred = false; 2645 } else if (fields_len == 0) { 2646 enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, 0); 2647 enum_obj.tag_ty_inferred = true; 2648 } else { 2649 const bits = std.math.log2_int_ceil(usize, fields_len); 2650 enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, bits); 2651 enum_obj.tag_ty_inferred = true; 2652 } 2653 } 2654 2655 if (small.nonexhaustive and enum_obj.tag_ty.zigTypeTag() != .ComptimeInt) { 2656 if (fields_len > 1 and std.math.log2_int(u64, fields_len) == enum_obj.tag_ty.bitSize(sema.mod.getTarget())) { 2657 return sema.fail(block, src, "non-exhaustive enum specifies every value", .{}); 2658 } 2659 } 2660 2661 try enum_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len); 2662 const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| { 2663 if (bag != 0) break true; 2664 } else false; 2665 if (any_values) { 2666 try enum_obj.values.ensureTotalCapacityContext(decl_arena_allocator, fields_len, .{ 2667 .ty = enum_obj.tag_ty, 2668 .mod = mod, 2669 }); 2670 } 2671 2672 var bit_bag_index: usize = body_end; 2673 var cur_bit_bag: u32 = undefined; 2674 var field_i: u32 = 0; 2675 var last_tag_val: ?Value = null; 2676 var tag_val_buf: Value.Payload.U64 = undefined; 2677 while (field_i < fields_len) : (field_i += 1) { 2678 if (field_i % 32 == 0) { 2679 cur_bit_bag = sema.code.extra[bit_bag_index]; 2680 bit_bag_index += 1; 2681 } 2682 const has_tag_value = @truncate(u1, cur_bit_bag) != 0; 2683 cur_bit_bag >>= 1; 2684 2685 const field_name_zir = sema.code.nullTerminatedString(sema.code.extra[extra_index]); 2686 extra_index += 1; 2687 2688 // doc comment 2689 extra_index += 1; 2690 2691 // This string needs to outlive the ZIR code. 2692 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir); 2693 2694 const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name); 2695 if (gop_field.found_existing) { 2696 const tree = try sema.getAstTree(block); 2697 const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i); 2698 const other_tag_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_field.index); 2699 const msg = msg: { 2700 const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name}); 2701 errdefer msg.destroy(gpa); 2702 try sema.errNote(block, other_tag_src, msg, "other field here", .{}); 2703 break :msg msg; 2704 }; 2705 return sema.failWithOwnedErrorMsg(msg); 2706 } 2707 2708 if (has_tag_value) { 2709 const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 2710 extra_index += 1; 2711 // TODO: if we need to report an error here, use a source location 2712 // that points to this default value expression rather than the struct. 2713 // But only resolve the source location if we need to emit a compile error. 2714 const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref, "enum tag value must be comptime known")).val; 2715 last_tag_val = tag_val; 2716 const copied_tag_val = try tag_val.copy(decl_arena_allocator); 2717 const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{ 2718 .ty = enum_obj.tag_ty, 2719 .mod = mod, 2720 }); 2721 if (gop_val.found_existing) { 2722 const tree = try sema.getAstTree(block); 2723 const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i); 2724 const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_val.index); 2725 const msg = msg: { 2726 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)}); 2727 errdefer msg.destroy(gpa); 2728 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{}); 2729 break :msg msg; 2730 }; 2731 return sema.failWithOwnedErrorMsg(msg); 2732 } 2733 } else if (any_values) { 2734 const tag_val = if (last_tag_val) |val| 2735 try sema.intAdd(block, src, val, Value.one, enum_obj.tag_ty) 2736 else 2737 Value.zero; 2738 last_tag_val = tag_val; 2739 const copied_tag_val = try tag_val.copy(decl_arena_allocator); 2740 const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{ 2741 .ty = enum_obj.tag_ty, 2742 .mod = mod, 2743 }); 2744 if (gop_val.found_existing) { 2745 const tree = try sema.getAstTree(block); 2746 const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i); 2747 const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_val.index); 2748 const msg = msg: { 2749 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)}); 2750 errdefer msg.destroy(gpa); 2751 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{}); 2752 break :msg msg; 2753 }; 2754 return sema.failWithOwnedErrorMsg(msg); 2755 } 2756 } else { 2757 tag_val_buf = .{ 2758 .base = .{ .tag = .int_u64 }, 2759 .data = field_i, 2760 }; 2761 last_tag_val = Value.initPayload(&tag_val_buf.base); 2762 } 2763 2764 if (!(try sema.intFitsInType(block, src, last_tag_val.?, enum_obj.tag_ty, null))) { 2765 const tree = try sema.getAstTree(block); 2766 const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i); 2767 const msg = try sema.errMsg(block, field_src, "enumeration value '{}' too large for type '{}'", .{ 2768 last_tag_val.?.fmtValue(enum_obj.tag_ty, mod), enum_obj.tag_ty.fmt(mod), 2769 }); 2770 return sema.failWithOwnedErrorMsg(msg); 2771 } 2772 } 2773 return decl_val; 2774 } 2775 2776 fn zirUnionDecl( 2777 sema: *Sema, 2778 block: *Block, 2779 extended: Zir.Inst.Extended.InstData, 2780 inst: Zir.Inst.Index, 2781 ) CompileError!Air.Inst.Ref { 2782 const tracy = trace(@src()); 2783 defer tracy.end(); 2784 2785 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); 2786 var extra_index: usize = extended.operand; 2787 2788 const src: LazySrcLoc = if (small.has_src_node) blk: { 2789 const node_offset = @bitCast(i32, sema.code.extra[extra_index]); 2790 extra_index += 1; 2791 break :blk LazySrcLoc.nodeOffset(node_offset); 2792 } else sema.src; 2793 2794 extra_index += @boolToInt(small.has_tag_type); 2795 extra_index += @boolToInt(small.has_body_len); 2796 extra_index += @boolToInt(small.has_fields_len); 2797 2798 const decls_len = if (small.has_decls_len) blk: { 2799 const decls_len = sema.code.extra[extra_index]; 2800 extra_index += 1; 2801 break :blk decls_len; 2802 } else 0; 2803 2804 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); 2805 errdefer new_decl_arena.deinit(); 2806 const new_decl_arena_allocator = new_decl_arena.allocator(); 2807 2808 const union_obj = try new_decl_arena_allocator.create(Module.Union); 2809 const type_tag = if (small.has_tag_type or small.auto_enum_tag) 2810 Type.Tag.union_tagged 2811 else if (small.layout != .Auto) 2812 Type.Tag.@"union" 2813 else switch (block.sema.mod.optimizeMode()) { 2814 .Debug, .ReleaseSafe => Type.Tag.union_safety_tagged, 2815 .ReleaseFast, .ReleaseSmall => Type.Tag.@"union", 2816 }; 2817 const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union); 2818 union_payload.* = .{ 2819 .base = .{ .tag = type_tag }, 2820 .data = union_obj, 2821 }; 2822 const union_ty = Type.initPayload(&union_payload.base); 2823 const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty); 2824 const mod = sema.mod; 2825 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 2826 .ty = Type.type, 2827 .val = union_val, 2828 }, small.name_strategy, "union", inst); 2829 const new_decl = mod.declPtr(new_decl_index); 2830 new_decl.owns_tv = true; 2831 errdefer mod.abortAnonDecl(new_decl_index); 2832 union_obj.* = .{ 2833 .owner_decl = new_decl_index, 2834 .tag_ty = Type.initTag(.@"null"), 2835 .fields = .{}, 2836 .zir_index = inst, 2837 .layout = small.layout, 2838 .status = .none, 2839 .namespace = .{ 2840 .parent = block.namespace, 2841 .ty = union_ty, 2842 .file_scope = block.getFileScope(), 2843 }, 2844 }; 2845 std.log.scoped(.module).debug("create union {*} owned by {*} ({s})", .{ 2846 &union_obj.namespace, new_decl, new_decl.name, 2847 }); 2848 2849 _ = try mod.scanNamespace(&union_obj.namespace, extra_index, decls_len, new_decl); 2850 2851 try new_decl.finalizeNewArena(&new_decl_arena); 2852 return sema.analyzeDeclVal(block, src, new_decl_index); 2853 } 2854 2855 fn zirOpaqueDecl( 2856 sema: *Sema, 2857 block: *Block, 2858 extended: Zir.Inst.Extended.InstData, 2859 inst: Zir.Inst.Index, 2860 ) CompileError!Air.Inst.Ref { 2861 const tracy = trace(@src()); 2862 defer tracy.end(); 2863 2864 const mod = sema.mod; 2865 const gpa = sema.gpa; 2866 const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small); 2867 var extra_index: usize = extended.operand; 2868 2869 const src: LazySrcLoc = if (small.has_src_node) blk: { 2870 const node_offset = @bitCast(i32, sema.code.extra[extra_index]); 2871 extra_index += 1; 2872 break :blk LazySrcLoc.nodeOffset(node_offset); 2873 } else sema.src; 2874 2875 const decls_len = if (small.has_decls_len) blk: { 2876 const decls_len = sema.code.extra[extra_index]; 2877 extra_index += 1; 2878 break :blk decls_len; 2879 } else 0; 2880 2881 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 2882 errdefer new_decl_arena.deinit(); 2883 const new_decl_arena_allocator = new_decl_arena.allocator(); 2884 2885 const opaque_obj = try new_decl_arena_allocator.create(Module.Opaque); 2886 const opaque_ty_payload = try new_decl_arena_allocator.create(Type.Payload.Opaque); 2887 opaque_ty_payload.* = .{ 2888 .base = .{ .tag = .@"opaque" }, 2889 .data = opaque_obj, 2890 }; 2891 const opaque_ty = Type.initPayload(&opaque_ty_payload.base); 2892 const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty); 2893 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 2894 .ty = Type.type, 2895 .val = opaque_val, 2896 }, small.name_strategy, "opaque", inst); 2897 const new_decl = mod.declPtr(new_decl_index); 2898 new_decl.owns_tv = true; 2899 errdefer mod.abortAnonDecl(new_decl_index); 2900 2901 opaque_obj.* = .{ 2902 .owner_decl = new_decl_index, 2903 .namespace = .{ 2904 .parent = block.namespace, 2905 .ty = opaque_ty, 2906 .file_scope = block.getFileScope(), 2907 }, 2908 }; 2909 std.log.scoped(.module).debug("create opaque {*} owned by {*} ({s})", .{ 2910 &opaque_obj.namespace, new_decl, new_decl.name, 2911 }); 2912 2913 extra_index = try mod.scanNamespace(&opaque_obj.namespace, extra_index, decls_len, new_decl); 2914 2915 try new_decl.finalizeNewArena(&new_decl_arena); 2916 return sema.analyzeDeclVal(block, src, new_decl_index); 2917 } 2918 2919 fn zirErrorSetDecl( 2920 sema: *Sema, 2921 block: *Block, 2922 inst: Zir.Inst.Index, 2923 name_strategy: Zir.Inst.NameStrategy, 2924 ) CompileError!Air.Inst.Ref { 2925 const tracy = trace(@src()); 2926 defer tracy.end(); 2927 2928 const gpa = sema.gpa; 2929 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 2930 const src = inst_data.src(); 2931 const extra = sema.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index); 2932 2933 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 2934 errdefer new_decl_arena.deinit(); 2935 const new_decl_arena_allocator = new_decl_arena.allocator(); 2936 2937 const error_set = try new_decl_arena_allocator.create(Module.ErrorSet); 2938 const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set); 2939 const error_set_val = try Value.Tag.ty.create(new_decl_arena_allocator, error_set_ty); 2940 const mod = sema.mod; 2941 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 2942 .ty = Type.type, 2943 .val = error_set_val, 2944 }, name_strategy, "error", inst); 2945 const new_decl = mod.declPtr(new_decl_index); 2946 new_decl.owns_tv = true; 2947 errdefer mod.abortAnonDecl(new_decl_index); 2948 2949 var names = Module.ErrorSet.NameMap{}; 2950 try names.ensureUnusedCapacity(new_decl_arena_allocator, extra.data.fields_len); 2951 2952 var extra_index = @intCast(u32, extra.end); 2953 const extra_index_end = extra_index + (extra.data.fields_len * 2); 2954 while (extra_index < extra_index_end) : (extra_index += 2) { // +2 to skip over doc_string 2955 const str_index = sema.code.extra[extra_index]; 2956 const kv = try mod.getErrorValue(sema.code.nullTerminatedString(str_index)); 2957 const result = names.getOrPutAssumeCapacity(kv.key); 2958 assert(!result.found_existing); // verified in AstGen 2959 } 2960 2961 // names must be sorted. 2962 Module.ErrorSet.sortNames(&names); 2963 2964 error_set.* = .{ 2965 .owner_decl = new_decl_index, 2966 .names = names, 2967 }; 2968 try new_decl.finalizeNewArena(&new_decl_arena); 2969 return sema.analyzeDeclVal(block, src, new_decl_index); 2970 } 2971 2972 fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 2973 const tracy = trace(@src()); 2974 defer tracy.end(); 2975 2976 const inst_data = sema.code.instructions.items(.data)[inst].node; 2977 const src = LazySrcLoc.nodeOffset(inst_data); 2978 2979 if (block.is_comptime or try sema.typeRequiresComptime(sema.fn_ret_ty)) { 2980 const fn_ret_ty = try sema.resolveTypeFields(block, src, sema.fn_ret_ty); 2981 return sema.analyzeComptimeAlloc(block, fn_ret_ty, 0, src); 2982 } 2983 2984 const target = sema.mod.getTarget(); 2985 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{ 2986 .pointee_type = sema.fn_ret_ty, 2987 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 2988 }); 2989 2990 if (block.inlining != null) { 2991 // We are inlining a function call; this should be emitted as an alloc, not a ret_ptr. 2992 // TODO when functions gain result location support, the inlining struct in 2993 // Block should contain the return pointer, and we would pass that through here. 2994 return block.addTy(.alloc, ptr_type); 2995 } 2996 2997 return block.addTy(.ret_ptr, ptr_type); 2998 } 2999 3000 fn zirRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3001 const tracy = trace(@src()); 3002 defer tracy.end(); 3003 3004 const inst_data = sema.code.instructions.items(.data)[inst].un_tok; 3005 const operand = try sema.resolveInst(inst_data.operand); 3006 return sema.analyzeRef(block, inst_data.src(), operand); 3007 } 3008 3009 fn zirEnsureResultUsed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 3010 const tracy = trace(@src()); 3011 defer tracy.end(); 3012 3013 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3014 const operand = try sema.resolveInst(inst_data.operand); 3015 const src = inst_data.src(); 3016 3017 return sema.ensureResultUsed(block, operand, src); 3018 } 3019 3020 fn ensureResultUsed( 3021 sema: *Sema, 3022 block: *Block, 3023 operand: Air.Inst.Ref, 3024 src: LazySrcLoc, 3025 ) CompileError!void { 3026 const operand_ty = sema.typeOf(operand); 3027 switch (operand_ty.zigTypeTag()) { 3028 .Void, .NoReturn => return, 3029 .ErrorSet, .ErrorUnion => { 3030 const msg = msg: { 3031 const msg = try sema.errMsg(block, src, "error is ignored", .{}); 3032 errdefer msg.destroy(sema.gpa); 3033 try sema.errNote(block, src, msg, "consider using `try`, `catch`, or `if`", .{}); 3034 break :msg msg; 3035 }; 3036 return sema.failWithOwnedErrorMsg(msg); 3037 }, 3038 else => { 3039 const msg = msg: { 3040 const msg = try sema.errMsg(block, src, "value of type '{}' ignored", .{operand_ty.fmt(sema.mod)}); 3041 errdefer msg.destroy(sema.gpa); 3042 try sema.errNote(block, src, msg, "all non-void values must be used", .{}); 3043 try sema.errNote(block, src, msg, "this error can be suppressed by assigning the value to '_'", .{}); 3044 break :msg msg; 3045 }; 3046 return sema.failWithOwnedErrorMsg(msg); 3047 }, 3048 } 3049 } 3050 3051 fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 3052 const tracy = trace(@src()); 3053 defer tracy.end(); 3054 3055 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3056 const operand = try sema.resolveInst(inst_data.operand); 3057 const src = inst_data.src(); 3058 const operand_ty = sema.typeOf(operand); 3059 switch (operand_ty.zigTypeTag()) { 3060 .ErrorSet, .ErrorUnion => { 3061 const msg = msg: { 3062 const msg = try sema.errMsg(block, src, "error is discarded", .{}); 3063 errdefer msg.destroy(sema.gpa); 3064 try sema.errNote(block, src, msg, "consider using `try`, `catch`, or `if`", .{}); 3065 break :msg msg; 3066 }; 3067 return sema.failWithOwnedErrorMsg(msg); 3068 }, 3069 else => return, 3070 } 3071 } 3072 3073 fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3074 const tracy = trace(@src()); 3075 defer tracy.end(); 3076 3077 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3078 const src = inst_data.src(); 3079 const object = try sema.resolveInst(inst_data.operand); 3080 const object_ty = sema.typeOf(object); 3081 3082 const is_pointer_to = object_ty.isSinglePointer(); 3083 3084 const array_ty = if (is_pointer_to) 3085 object_ty.childType() 3086 else 3087 object_ty; 3088 3089 if (!array_ty.isIndexable()) { 3090 const msg = msg: { 3091 const msg = try sema.errMsg( 3092 block, 3093 src, 3094 "type '{}' does not support indexing", 3095 .{array_ty.fmt(sema.mod)}, 3096 ); 3097 errdefer msg.destroy(sema.gpa); 3098 try sema.errNote( 3099 block, 3100 src, 3101 msg, 3102 "for loop operand must be an array, slice, tuple, or vector", 3103 .{}, 3104 ); 3105 break :msg msg; 3106 }; 3107 return sema.failWithOwnedErrorMsg(msg); 3108 } 3109 3110 return sema.fieldVal(block, src, object, "len", src); 3111 } 3112 3113 fn zirAllocExtended( 3114 sema: *Sema, 3115 block: *Block, 3116 extended: Zir.Inst.Extended.InstData, 3117 ) CompileError!Air.Inst.Ref { 3118 const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand); 3119 const src = LazySrcLoc.nodeOffset(extra.data.src_node); 3120 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = extra.data.src_node }; 3121 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = extra.data.src_node }; 3122 const small = @bitCast(Zir.Inst.AllocExtended.Small, extended.small); 3123 3124 var extra_index: usize = extra.end; 3125 3126 const var_ty: Type = if (small.has_type) blk: { 3127 const type_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 3128 extra_index += 1; 3129 break :blk try sema.resolveType(block, ty_src, type_ref); 3130 } else undefined; 3131 3132 const alignment: u32 = if (small.has_align) blk: { 3133 const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 3134 extra_index += 1; 3135 const alignment = try sema.resolveAlign(block, align_src, align_ref); 3136 break :blk alignment; 3137 } else 0; 3138 3139 const inferred_alloc_ty = if (small.is_const) 3140 Type.initTag(.inferred_alloc_const) 3141 else 3142 Type.initTag(.inferred_alloc_mut); 3143 3144 if (block.is_comptime or small.is_comptime) { 3145 if (small.has_type) { 3146 return sema.analyzeComptimeAlloc(block, var_ty, alignment, ty_src); 3147 } else { 3148 return sema.addConstant( 3149 inferred_alloc_ty, 3150 try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ 3151 .decl_index = undefined, 3152 .alignment = alignment, 3153 }), 3154 ); 3155 } 3156 } 3157 3158 if (small.has_type) { 3159 if (!small.is_const) { 3160 try sema.validateVarType(block, ty_src, var_ty, false); 3161 } 3162 const target = sema.mod.getTarget(); 3163 try sema.requireFunctionBlock(block, src); 3164 try sema.resolveTypeLayout(block, src, var_ty); 3165 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{ 3166 .pointee_type = var_ty, 3167 .@"align" = alignment, 3168 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 3169 }); 3170 return block.addTy(.alloc, ptr_type); 3171 } 3172 3173 // `Sema.addConstant` does not add the instruction to the block because it is 3174 // not needed in the case of constant values. However here, we plan to "downgrade" 3175 // to a normal instruction when we hit `resolve_inferred_alloc`. So we append 3176 // to the block even though it is currently a `.constant`. 3177 const result = try sema.addConstant( 3178 inferred_alloc_ty, 3179 try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = alignment }), 3180 ); 3181 try sema.requireFunctionBlock(block, src); 3182 try block.instructions.append(sema.gpa, Air.refToIndex(result).?); 3183 return result; 3184 } 3185 3186 fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3187 const tracy = trace(@src()); 3188 defer tracy.end(); 3189 3190 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3191 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; 3192 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); 3193 return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src); 3194 } 3195 3196 fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3197 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3198 const src = inst_data.src(); 3199 const alloc = try sema.resolveInst(inst_data.operand); 3200 const alloc_ty = sema.typeOf(alloc); 3201 3202 var ptr_info = alloc_ty.ptrInfo().data; 3203 const elem_ty = ptr_info.pointee_type; 3204 3205 // Detect if all stores to an `.alloc` were comptime known. 3206 ct: { 3207 var search_index: usize = block.instructions.items.len; 3208 const air_tags = sema.air_instructions.items(.tag); 3209 const air_datas = sema.air_instructions.items(.data); 3210 3211 const store_inst = while (true) { 3212 if (search_index == 0) break :ct; 3213 search_index -= 1; 3214 3215 const candidate = block.instructions.items[search_index]; 3216 switch (air_tags[candidate]) { 3217 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue, 3218 .store => break candidate, 3219 else => break :ct, 3220 } 3221 } else unreachable; // TODO shouldn't need this 3222 3223 while (true) { 3224 if (search_index == 0) break :ct; 3225 search_index -= 1; 3226 3227 const candidate = block.instructions.items[search_index]; 3228 switch (air_tags[candidate]) { 3229 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue, 3230 .alloc => { 3231 if (Air.indexToRef(candidate) != alloc) break :ct; 3232 break; 3233 }, 3234 else => break :ct, 3235 } 3236 } 3237 3238 const store_op = air_datas[store_inst].bin_op; 3239 const store_val = (try sema.resolveMaybeUndefVal(block, src, store_op.rhs)) orelse break :ct; 3240 if (store_op.lhs != alloc) break :ct; 3241 3242 // Remove all the unnecessary runtime instructions. 3243 block.instructions.shrinkRetainingCapacity(search_index); 3244 3245 var anon_decl = try block.startAnonDecl(src); 3246 defer anon_decl.deinit(); 3247 return sema.analyzeDeclRef(try anon_decl.finish( 3248 try elem_ty.copy(anon_decl.arena()), 3249 try store_val.copy(anon_decl.arena()), 3250 ptr_info.@"align", 3251 )); 3252 } 3253 3254 ptr_info.mutable = false; 3255 const const_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); 3256 3257 // Detect if a comptime value simply needs to have its type changed. 3258 if (try sema.resolveMaybeUndefVal(block, inst_data.src(), alloc)) |val| { 3259 return sema.addConstant(const_ptr_ty, val); 3260 } 3261 3262 try sema.requireFunctionBlock(block, src); 3263 return block.addBitCast(const_ptr_ty, alloc); 3264 } 3265 3266 fn zirAllocInferredComptime( 3267 sema: *Sema, 3268 inst: Zir.Inst.Index, 3269 inferred_alloc_ty: Type, 3270 ) CompileError!Air.Inst.Ref { 3271 const src_node = sema.code.instructions.items(.data)[inst].node; 3272 const src = LazySrcLoc.nodeOffset(src_node); 3273 sema.src = src; 3274 return sema.addConstant( 3275 inferred_alloc_ty, 3276 try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ 3277 .decl_index = undefined, 3278 .alignment = 0, 3279 }), 3280 ); 3281 } 3282 3283 fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3284 const tracy = trace(@src()); 3285 defer tracy.end(); 3286 3287 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3288 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; 3289 const var_decl_src = inst_data.src(); 3290 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); 3291 if (block.is_comptime) { 3292 return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src); 3293 } 3294 const target = sema.mod.getTarget(); 3295 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{ 3296 .pointee_type = var_ty, 3297 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 3298 }); 3299 try sema.requireFunctionBlock(block, var_decl_src); 3300 try sema.queueFullTypeResolution(var_ty); 3301 return block.addTy(.alloc, ptr_type); 3302 } 3303 3304 fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3305 const tracy = trace(@src()); 3306 defer tracy.end(); 3307 3308 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3309 const var_decl_src = inst_data.src(); 3310 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; 3311 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); 3312 if (block.is_comptime) { 3313 return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src); 3314 } 3315 try sema.validateVarType(block, ty_src, var_ty, false); 3316 const target = sema.mod.getTarget(); 3317 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{ 3318 .pointee_type = var_ty, 3319 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 3320 }); 3321 try sema.requireFunctionBlock(block, var_decl_src); 3322 try sema.queueFullTypeResolution(var_ty); 3323 return block.addTy(.alloc, ptr_type); 3324 } 3325 3326 fn zirAllocInferred( 3327 sema: *Sema, 3328 block: *Block, 3329 inst: Zir.Inst.Index, 3330 inferred_alloc_ty: Type, 3331 ) CompileError!Air.Inst.Ref { 3332 const tracy = trace(@src()); 3333 defer tracy.end(); 3334 3335 const src_node = sema.code.instructions.items(.data)[inst].node; 3336 const src = LazySrcLoc.nodeOffset(src_node); 3337 sema.src = src; 3338 3339 if (block.is_comptime) { 3340 return sema.addConstant( 3341 inferred_alloc_ty, 3342 try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ 3343 .decl_index = undefined, 3344 .alignment = 0, 3345 }), 3346 ); 3347 } 3348 3349 // `Sema.addConstant` does not add the instruction to the block because it is 3350 // not needed in the case of constant values. However here, we plan to "downgrade" 3351 // to a normal instruction when we hit `resolve_inferred_alloc`. So we append 3352 // to the block even though it is currently a `.constant`. 3353 const result = try sema.addConstant( 3354 inferred_alloc_ty, 3355 try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = 0 }), 3356 ); 3357 try sema.requireFunctionBlock(block, src); 3358 try block.instructions.append(sema.gpa, Air.refToIndex(result).?); 3359 return result; 3360 } 3361 3362 fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 3363 const tracy = trace(@src()); 3364 defer tracy.end(); 3365 3366 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3367 const src = inst_data.src(); 3368 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; 3369 const ptr = try sema.resolveInst(inst_data.operand); 3370 const ptr_inst = Air.refToIndex(ptr).?; 3371 assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant); 3372 const value_index = sema.air_instructions.items(.data)[ptr_inst].ty_pl.payload; 3373 const ptr_val = sema.air_values.items[value_index]; 3374 const var_is_mut = switch (sema.typeOf(ptr).tag()) { 3375 .inferred_alloc_const => false, 3376 .inferred_alloc_mut => true, 3377 else => unreachable, 3378 }; 3379 const target = sema.mod.getTarget(); 3380 3381 switch (ptr_val.tag()) { 3382 .inferred_alloc_comptime => { 3383 const iac = ptr_val.castTag(.inferred_alloc_comptime).?; 3384 const decl_index = iac.data.decl_index; 3385 try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index); 3386 3387 const decl = sema.mod.declPtr(decl_index); 3388 const final_elem_ty = try decl.ty.copy(sema.arena); 3389 const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 3390 .pointee_type = final_elem_ty, 3391 .mutable = var_is_mut, 3392 .@"align" = iac.data.alignment, 3393 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 3394 }); 3395 const final_ptr_ty_inst = try sema.addType(final_ptr_ty); 3396 sema.air_instructions.items(.data)[ptr_inst].ty_pl.ty = final_ptr_ty_inst; 3397 3398 if (var_is_mut) { 3399 sema.air_values.items[value_index] = try Value.Tag.decl_ref_mut.create(sema.arena, .{ 3400 .decl_index = decl_index, 3401 .runtime_index = block.runtime_index, 3402 }); 3403 } else { 3404 sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, decl_index); 3405 } 3406 }, 3407 .inferred_alloc => { 3408 const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; 3409 const peer_inst_list = inferred_alloc.data.prongs.items(.stored_inst); 3410 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none); 3411 3412 const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 3413 .pointee_type = final_elem_ty, 3414 .mutable = var_is_mut, 3415 .@"align" = inferred_alloc.data.alignment, 3416 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 3417 }); 3418 3419 if (var_is_mut) { 3420 try sema.validateVarType(block, ty_src, final_elem_ty, false); 3421 } else ct: { 3422 // Detect if the value is comptime known. In such case, the 3423 // last 3 AIR instructions of the block will look like this: 3424 // 3425 // %a = constant 3426 // %b = bitcast(%a) 3427 // %c = store(%b, %d) 3428 // 3429 // If `%d` is comptime-known, then we want to store the value 3430 // inside an anonymous Decl and then erase these three AIR 3431 // instructions from the block, replacing the inst_map entry 3432 // corresponding to the ZIR alloc instruction with a constant 3433 // decl_ref pointing at our new Decl. 3434 // dbg_stmt instructions may be interspersed into this pattern 3435 // which must be ignored. 3436 if (block.instructions.items.len < 3) break :ct; 3437 var search_index: usize = block.instructions.items.len; 3438 const air_tags = sema.air_instructions.items(.tag); 3439 const air_datas = sema.air_instructions.items(.data); 3440 3441 const store_inst = while (true) { 3442 if (search_index == 0) break :ct; 3443 search_index -= 1; 3444 3445 const candidate = block.instructions.items[search_index]; 3446 switch (air_tags[candidate]) { 3447 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue, 3448 .store => break candidate, 3449 else => break :ct, 3450 } 3451 } else unreachable; // TODO shouldn't need this 3452 3453 const bitcast_inst = while (true) { 3454 if (search_index == 0) break :ct; 3455 search_index -= 1; 3456 3457 const candidate = block.instructions.items[search_index]; 3458 switch (air_tags[candidate]) { 3459 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue, 3460 .bitcast => break candidate, 3461 else => break :ct, 3462 } 3463 } else unreachable; // TODO shouldn't need this 3464 3465 const const_inst = while (true) { 3466 if (search_index == 0) break :ct; 3467 search_index -= 1; 3468 3469 const candidate = block.instructions.items[search_index]; 3470 switch (air_tags[candidate]) { 3471 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue, 3472 .constant => break candidate, 3473 else => break :ct, 3474 } 3475 } else unreachable; // TODO shouldn't need this 3476 3477 const store_op = air_datas[store_inst].bin_op; 3478 const store_val = (try sema.resolveMaybeUndefVal(block, src, store_op.rhs)) orelse break :ct; 3479 if (store_op.lhs != Air.indexToRef(bitcast_inst)) break :ct; 3480 if (air_datas[bitcast_inst].ty_op.operand != Air.indexToRef(const_inst)) break :ct; 3481 3482 const new_decl_index = d: { 3483 var anon_decl = try block.startAnonDecl(src); 3484 defer anon_decl.deinit(); 3485 const new_decl_index = try anon_decl.finish( 3486 try final_elem_ty.copy(anon_decl.arena()), 3487 try store_val.copy(anon_decl.arena()), 3488 inferred_alloc.data.alignment, 3489 ); 3490 break :d new_decl_index; 3491 }; 3492 try sema.mod.declareDeclDependency(sema.owner_decl_index, new_decl_index); 3493 3494 // Even though we reuse the constant instruction, we still remove it from the 3495 // block so that codegen does not see it. 3496 block.instructions.shrinkRetainingCapacity(search_index); 3497 sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, new_decl_index); 3498 // if bitcast ty ref needs to be made const, make_ptr_const 3499 // ZIR handles it later, so we can just use the ty ref here. 3500 air_datas[ptr_inst].ty_pl.ty = air_datas[bitcast_inst].ty_op.ty; 3501 3502 // Unless the block is comptime, `alloc_inferred` always produces 3503 // a runtime constant. The final inferred type needs to be 3504 // fully resolved so it can be lowered in codegen. 3505 try sema.resolveTypeFully(block, ty_src, final_elem_ty); 3506 3507 return; 3508 } 3509 3510 try sema.requireFunctionBlock(block, src); 3511 try sema.queueFullTypeResolution(final_elem_ty); 3512 3513 // Change it to a normal alloc. 3514 sema.air_instructions.set(ptr_inst, .{ 3515 .tag = .alloc, 3516 .data = .{ .ty = final_ptr_ty }, 3517 }); 3518 3519 // Now we need to go back over all the coerce_result_ptr instructions, which 3520 // previously inserted a bitcast as a placeholder, and do the logic as if 3521 // the new result ptr type was available. 3522 const placeholders = inferred_alloc.data.prongs.items(.placeholder); 3523 const gpa = sema.gpa; 3524 3525 var trash_block = block.makeSubBlock(); 3526 trash_block.is_comptime = false; 3527 trash_block.is_coerce_result_ptr = true; 3528 defer trash_block.instructions.deinit(gpa); 3529 3530 const mut_final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 3531 .pointee_type = final_elem_ty, 3532 .mutable = true, 3533 .@"align" = inferred_alloc.data.alignment, 3534 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 3535 }); 3536 const dummy_ptr = try trash_block.addTy(.alloc, mut_final_ptr_ty); 3537 const empty_trash_count = trash_block.instructions.items.len; 3538 3539 for (placeholders) |bitcast_inst, i| { 3540 const sub_ptr_ty = sema.typeOf(Air.indexToRef(bitcast_inst)); 3541 3542 if (mut_final_ptr_ty.eql(sub_ptr_ty, sema.mod)) { 3543 // New result location type is the same as the old one; nothing 3544 // to do here. 3545 continue; 3546 } 3547 3548 var bitcast_block = block.makeSubBlock(); 3549 defer bitcast_block.instructions.deinit(gpa); 3550 3551 trash_block.instructions.shrinkRetainingCapacity(empty_trash_count); 3552 const sub_ptr = try coerceResultPtr(sema, &bitcast_block, src, ptr, dummy_ptr, peer_inst_list[i], &trash_block); 3553 3554 assert(bitcast_block.instructions.items.len > 0); 3555 // If only one instruction is produced then we can replace the bitcast 3556 // placeholder instruction with this instruction; no need for an entire block. 3557 if (bitcast_block.instructions.items.len == 1) { 3558 const only_inst = bitcast_block.instructions.items[0]; 3559 sema.air_instructions.set(bitcast_inst, sema.air_instructions.get(only_inst)); 3560 continue; 3561 } 3562 3563 // Here we replace the placeholder bitcast instruction with a block 3564 // that does the coerce_result_ptr logic. 3565 _ = try bitcast_block.addBr(bitcast_inst, sub_ptr); 3566 const ty_inst = sema.air_instructions.items(.data)[bitcast_inst].ty_op.ty; 3567 try sema.air_extra.ensureUnusedCapacity( 3568 gpa, 3569 @typeInfo(Air.Block).Struct.fields.len + bitcast_block.instructions.items.len, 3570 ); 3571 sema.air_instructions.set(bitcast_inst, .{ 3572 .tag = .block, 3573 .data = .{ .ty_pl = .{ 3574 .ty = ty_inst, 3575 .payload = sema.addExtraAssumeCapacity(Air.Block{ 3576 .body_len = @intCast(u32, bitcast_block.instructions.items.len), 3577 }), 3578 } }, 3579 }); 3580 sema.air_extra.appendSliceAssumeCapacity(bitcast_block.instructions.items); 3581 } 3582 }, 3583 else => unreachable, 3584 } 3585 } 3586 3587 fn zirArrayBasePtr( 3588 sema: *Sema, 3589 block: *Block, 3590 inst: Zir.Inst.Index, 3591 ) CompileError!Air.Inst.Ref { 3592 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3593 const src = inst_data.src(); 3594 3595 const start_ptr = try sema.resolveInst(inst_data.operand); 3596 var base_ptr = start_ptr; 3597 while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) { 3598 .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), 3599 .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true), 3600 else => break, 3601 }; 3602 3603 const elem_ty = sema.typeOf(base_ptr).childType(); 3604 switch (elem_ty.zigTypeTag()) { 3605 .Array, .Vector => return base_ptr, 3606 .Struct => if (elem_ty.isTuple()) { 3607 // TODO validate element count 3608 return base_ptr; 3609 }, 3610 else => {}, 3611 } 3612 return sema.failWithArrayInitNotSupported(block, src, sema.typeOf(start_ptr).childType()); 3613 } 3614 3615 fn zirFieldBasePtr( 3616 sema: *Sema, 3617 block: *Block, 3618 inst: Zir.Inst.Index, 3619 ) CompileError!Air.Inst.Ref { 3620 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3621 const src = inst_data.src(); 3622 3623 const start_ptr = try sema.resolveInst(inst_data.operand); 3624 var base_ptr = start_ptr; 3625 while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) { 3626 .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), 3627 .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true), 3628 else => break, 3629 }; 3630 3631 const elem_ty = sema.typeOf(base_ptr).childType(); 3632 switch (elem_ty.zigTypeTag()) { 3633 .Struct, .Union => return base_ptr, 3634 else => {}, 3635 } 3636 return sema.failWithStructInitNotSupported(block, src, sema.typeOf(start_ptr).childType()); 3637 } 3638 3639 fn validateArrayInitTy( 3640 sema: *Sema, 3641 block: *Block, 3642 inst: Zir.Inst.Index, 3643 ) CompileError!void { 3644 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 3645 const src = inst_data.src(); 3646 const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node }; 3647 const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data; 3648 const ty = try sema.resolveType(block, ty_src, extra.ty); 3649 3650 switch (ty.zigTypeTag()) { 3651 .Array => { 3652 const array_len = ty.arrayLen(); 3653 if (extra.init_count != array_len) { 3654 return sema.fail(block, src, "expected {d} array elements; found {d}", .{ 3655 array_len, extra.init_count, 3656 }); 3657 } 3658 return; 3659 }, 3660 .Vector => { 3661 const array_len = ty.arrayLen(); 3662 if (extra.init_count != array_len) { 3663 return sema.fail(block, src, "expected {d} vector elements; found {d}", .{ 3664 array_len, extra.init_count, 3665 }); 3666 } 3667 return; 3668 }, 3669 .Struct => if (ty.isTuple()) { 3670 const array_len = ty.arrayLen(); 3671 if (extra.init_count > array_len) { 3672 return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{ 3673 array_len, extra.init_count, 3674 }); 3675 } 3676 return; 3677 }, 3678 else => {}, 3679 } 3680 return sema.failWithArrayInitNotSupported(block, ty_src, ty); 3681 } 3682 3683 fn validateStructInitTy( 3684 sema: *Sema, 3685 block: *Block, 3686 inst: Zir.Inst.Index, 3687 ) CompileError!void { 3688 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 3689 const src = inst_data.src(); 3690 const ty = try sema.resolveType(block, src, inst_data.operand); 3691 3692 switch (ty.zigTypeTag()) { 3693 .Struct, .Union => return, 3694 else => {}, 3695 } 3696 return sema.failWithStructInitNotSupported(block, src, ty); 3697 } 3698 3699 fn zirValidateStructInit( 3700 sema: *Sema, 3701 block: *Block, 3702 inst: Zir.Inst.Index, 3703 is_comptime: bool, 3704 ) CompileError!void { 3705 const tracy = trace(@src()); 3706 defer tracy.end(); 3707 3708 const validate_inst = sema.code.instructions.items(.data)[inst].pl_node; 3709 const init_src = validate_inst.src(); 3710 const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index); 3711 const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len]; 3712 const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; 3713 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; 3714 const object_ptr = try sema.resolveInst(field_ptr_extra.lhs); 3715 const agg_ty = sema.typeOf(object_ptr).childType(); 3716 switch (agg_ty.zigTypeTag()) { 3717 .Struct => return sema.validateStructInit( 3718 block, 3719 agg_ty, 3720 init_src, 3721 instrs, 3722 is_comptime, 3723 ), 3724 .Union => return sema.validateUnionInit( 3725 block, 3726 agg_ty, 3727 init_src, 3728 instrs, 3729 object_ptr, 3730 is_comptime, 3731 ), 3732 else => unreachable, 3733 } 3734 } 3735 3736 fn validateUnionInit( 3737 sema: *Sema, 3738 block: *Block, 3739 union_ty: Type, 3740 init_src: LazySrcLoc, 3741 instrs: []const Zir.Inst.Index, 3742 union_ptr: Air.Inst.Ref, 3743 is_comptime: bool, 3744 ) CompileError!void { 3745 if (instrs.len != 1) { 3746 const msg = msg: { 3747 const msg = try sema.errMsg( 3748 block, 3749 init_src, 3750 "cannot initialize multiple union fields at once, unions can only have one active field", 3751 .{}, 3752 ); 3753 errdefer msg.destroy(sema.gpa); 3754 3755 for (instrs[1..]) |inst| { 3756 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 3757 const inst_src: LazySrcLoc = .{ .node_offset_initializer = inst_data.src_node }; 3758 try sema.errNote(block, inst_src, msg, "additional initializer here", .{}); 3759 } 3760 try sema.addDeclaredHereNote(msg, union_ty); 3761 break :msg msg; 3762 }; 3763 return sema.failWithOwnedErrorMsg(msg); 3764 } 3765 3766 if ((is_comptime or block.is_comptime) and 3767 (try sema.resolveDefinedValue(block, init_src, union_ptr)) != null) 3768 { 3769 // In this case, comptime machinery already did everything. No work to do here. 3770 return; 3771 } 3772 3773 const field_ptr = instrs[0]; 3774 const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; 3775 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node }; 3776 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; 3777 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); 3778 // Validate the field access but ignore the index since we want the tag enum field index. 3779 _ = try sema.unionFieldIndex(block, union_ty, field_name, field_src); 3780 const air_tags = sema.air_instructions.items(.tag); 3781 const air_datas = sema.air_instructions.items(.data); 3782 const field_ptr_air_ref = sema.inst_map.get(field_ptr).?; 3783 const field_ptr_air_inst = Air.refToIndex(field_ptr_air_ref).?; 3784 3785 // Our task here is to determine if the union is comptime-known. In such case, 3786 // we erase the runtime AIR instructions for initializing the union, and replace 3787 // the mapping with the comptime value. Either way, we will need to populate the tag. 3788 3789 // We expect to see something like this in the current block AIR: 3790 // %a = alloc(*const U) 3791 // %b = bitcast(*U, %a) 3792 // %c = field_ptr(..., %b) 3793 // %e!= store(%c!, %d!) 3794 // If %d is a comptime operand, the union is comptime. 3795 // If the union is comptime, we want `first_block_index` 3796 // to point at %c so that the bitcast becomes the last instruction in the block. 3797 // 3798 // In the case of a comptime-known pointer to a union, the 3799 // the field_ptr instruction is missing, so we have to pattern-match 3800 // based only on the store instructions. 3801 // `first_block_index` needs to point to the `field_ptr` if it exists; 3802 // the `store` otherwise. 3803 // 3804 // It's also possible for there to be no store instruction, in the case 3805 // of nested `coerce_result_ptr` instructions. If we see the `field_ptr` 3806 // but we have not found a `store`, treat as a runtime-known field. 3807 var first_block_index = block.instructions.items.len; 3808 var block_index = block.instructions.items.len - 1; 3809 var init_val: ?Value = null; 3810 while (block_index > 0) : (block_index -= 1) { 3811 const store_inst = block.instructions.items[block_index]; 3812 if (store_inst == field_ptr_air_inst) break; 3813 if (air_tags[store_inst] != .store) continue; 3814 const bin_op = air_datas[store_inst].bin_op; 3815 var lhs = bin_op.lhs; 3816 if (Air.refToIndex(lhs)) |lhs_index| { 3817 if (air_tags[lhs_index] == .bitcast) { 3818 lhs = air_datas[lhs_index].ty_op.operand; 3819 block_index -= 1; 3820 } 3821 } 3822 if (lhs != field_ptr_air_ref) continue; 3823 while (block_index > 0) : (block_index -= 1) { 3824 const block_inst = block.instructions.items[block_index - 1]; 3825 if (air_tags[block_inst] != .dbg_stmt) break; 3826 } 3827 if (block_index > 0 and 3828 field_ptr_air_inst == block.instructions.items[block_index - 1]) 3829 { 3830 first_block_index = @minimum(first_block_index, block_index - 1); 3831 } else { 3832 first_block_index = @minimum(first_block_index, block_index); 3833 } 3834 init_val = try sema.resolveMaybeUndefValAllowVariables(block, init_src, bin_op.rhs); 3835 break; 3836 } 3837 3838 const tag_ty = union_ty.unionTagTypeHypothetical(); 3839 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?); 3840 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); 3841 3842 if (init_val) |val| { 3843 // Our task is to delete all the `field_ptr` and `store` instructions, and insert 3844 // instead a single `store` to the result ptr with a comptime union value. 3845 block.instructions.shrinkRetainingCapacity(first_block_index); 3846 3847 const union_val = try Value.Tag.@"union".create(sema.arena, .{ 3848 .tag = tag_val, 3849 .val = val, 3850 }); 3851 const union_init = try sema.addConstant(union_ty, union_val); 3852 try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store); 3853 return; 3854 } 3855 3856 try sema.requireFunctionBlock(block, init_src); 3857 const new_tag = try sema.addConstant(tag_ty, tag_val); 3858 _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag); 3859 } 3860 3861 fn validateStructInit( 3862 sema: *Sema, 3863 block: *Block, 3864 struct_ty: Type, 3865 init_src: LazySrcLoc, 3866 instrs: []const Zir.Inst.Index, 3867 is_comptime: bool, 3868 ) CompileError!void { 3869 const gpa = sema.gpa; 3870 3871 // Maps field index to field_ptr index of where it was already initialized. 3872 const found_fields = try gpa.alloc(Zir.Inst.Index, struct_ty.structFieldCount()); 3873 defer gpa.free(found_fields); 3874 mem.set(Zir.Inst.Index, found_fields, 0); 3875 3876 var struct_ptr_zir_ref: Zir.Inst.Ref = undefined; 3877 3878 for (instrs) |field_ptr| { 3879 const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; 3880 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node }; 3881 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; 3882 struct_ptr_zir_ref = field_ptr_extra.lhs; 3883 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); 3884 const field_index = if (struct_ty.isTuple()) 3885 try sema.tupleFieldIndex(block, struct_ty, field_name, field_src) 3886 else 3887 try sema.structFieldIndex(block, struct_ty, field_name, field_src); 3888 if (found_fields[field_index] != 0) { 3889 const other_field_ptr = found_fields[field_index]; 3890 const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node; 3891 const other_field_src: LazySrcLoc = .{ .node_offset_initializer = other_field_ptr_data.src_node }; 3892 const msg = msg: { 3893 const msg = try sema.errMsg(block, field_src, "duplicate field", .{}); 3894 errdefer msg.destroy(gpa); 3895 try sema.errNote(block, other_field_src, msg, "other field here", .{}); 3896 break :msg msg; 3897 }; 3898 return sema.failWithOwnedErrorMsg(msg); 3899 } 3900 found_fields[field_index] = field_ptr; 3901 } 3902 3903 var root_msg: ?*Module.ErrorMsg = null; 3904 errdefer if (root_msg) |msg| msg.destroy(sema.gpa); 3905 3906 const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref); 3907 if ((is_comptime or block.is_comptime) and 3908 (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null) 3909 { 3910 try sema.resolveStructLayout(block, init_src, struct_ty); 3911 // In this case the only thing we need to do is evaluate the implicit 3912 // store instructions for default field values, and report any missing fields. 3913 // Avoid the cost of the extra machinery for detecting a comptime struct init value. 3914 for (found_fields) |field_ptr, i| { 3915 if (field_ptr != 0) continue; 3916 3917 const default_val = struct_ty.structFieldDefaultValue(i); 3918 if (default_val.tag() == .unreachable_value) { 3919 if (struct_ty.isTuple()) { 3920 const template = "missing tuple field with index {d}"; 3921 if (root_msg) |msg| { 3922 try sema.errNote(block, init_src, msg, template, .{i}); 3923 } else { 3924 root_msg = try sema.errMsg(block, init_src, template, .{i}); 3925 } 3926 continue; 3927 } 3928 const field_name = struct_ty.structFieldName(i); 3929 const template = "missing struct field: {s}"; 3930 const args = .{field_name}; 3931 if (root_msg) |msg| { 3932 try sema.errNote(block, init_src, msg, template, args); 3933 } else { 3934 root_msg = try sema.errMsg(block, init_src, template, args); 3935 } 3936 continue; 3937 } 3938 3939 const field_src = init_src; // TODO better source location 3940 const default_field_ptr = if (struct_ty.isTuple()) 3941 try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true) 3942 else 3943 try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); 3944 const field_ty = sema.typeOf(default_field_ptr).childType(); 3945 const init = try sema.addConstant(field_ty, default_val); 3946 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); 3947 } 3948 3949 if (root_msg) |msg| { 3950 if (struct_ty.castTag(.@"struct")) |struct_obj| { 3951 const mod = sema.mod; 3952 const fqn = try struct_obj.data.getFullyQualifiedName(mod); 3953 defer gpa.free(fqn); 3954 try mod.errNoteNonLazy( 3955 struct_obj.data.srcLoc(mod), 3956 msg, 3957 "struct '{s}' declared here", 3958 .{fqn}, 3959 ); 3960 } 3961 return sema.failWithOwnedErrorMsg(msg); 3962 } 3963 3964 return; 3965 } 3966 3967 var struct_is_comptime = true; 3968 var first_block_index = block.instructions.items.len; 3969 3970 const air_tags = sema.air_instructions.items(.tag); 3971 const air_datas = sema.air_instructions.items(.data); 3972 3973 // We collect the comptime field values in case the struct initialization 3974 // ends up being comptime-known. 3975 const field_values = try sema.arena.alloc(Value, struct_ty.structFieldCount()); 3976 3977 field: for (found_fields) |field_ptr, i| { 3978 if (field_ptr != 0) { 3979 const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; 3980 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node }; 3981 3982 // Determine whether the value stored to this pointer is comptime-known. 3983 const field_ty = struct_ty.structFieldType(i); 3984 if (try sema.typeHasOnePossibleValue(block, field_src, field_ty)) |opv| { 3985 field_values[i] = opv; 3986 continue; 3987 } 3988 3989 const field_ptr_air_ref = sema.inst_map.get(field_ptr).?; 3990 const field_ptr_air_inst = Air.refToIndex(field_ptr_air_ref).?; 3991 3992 //std.debug.print("validateStructInit (field_ptr_air_inst=%{d}):\n", .{ 3993 // field_ptr_air_inst, 3994 //}); 3995 //for (block.instructions.items) |item| { 3996 // std.debug.print(" %{d} = {s}\n", .{item, @tagName(air_tags[item])}); 3997 //} 3998 3999 // We expect to see something like this in the current block AIR: 4000 // %a = field_ptr(...) 4001 // store(%a, %b) 4002 // If %b is a comptime operand, this field is comptime. 4003 // 4004 // However, in the case of a comptime-known pointer to a struct, the 4005 // the field_ptr instruction is missing, so we have to pattern-match 4006 // based only on the store instructions. 4007 // `first_block_index` needs to point to the `field_ptr` if it exists; 4008 // the `store` otherwise. 4009 // 4010 // It's also possible for there to be no store instruction, in the case 4011 // of nested `coerce_result_ptr` instructions. If we see the `field_ptr` 4012 // but we have not found a `store`, treat as a runtime-known field. 4013 4014 // Possible performance enhancement: save the `block_index` between iterations 4015 // of the for loop. 4016 var block_index = block.instructions.items.len - 1; 4017 while (block_index > 0) : (block_index -= 1) { 4018 const store_inst = block.instructions.items[block_index]; 4019 if (store_inst == field_ptr_air_inst) { 4020 struct_is_comptime = false; 4021 continue :field; 4022 } 4023 if (air_tags[store_inst] != .store) continue; 4024 const bin_op = air_datas[store_inst].bin_op; 4025 var lhs = bin_op.lhs; 4026 { 4027 const lhs_index = Air.refToIndex(lhs) orelse continue; 4028 if (air_tags[lhs_index] == .bitcast) { 4029 lhs = air_datas[lhs_index].ty_op.operand; 4030 block_index -= 1; 4031 } 4032 } 4033 if (lhs != field_ptr_air_ref) continue; 4034 while (block_index > 0) : (block_index -= 1) { 4035 const block_inst = block.instructions.items[block_index - 1]; 4036 if (air_tags[block_inst] != .dbg_stmt) break; 4037 } 4038 if (block_index > 0 and 4039 field_ptr_air_inst == block.instructions.items[block_index - 1]) 4040 { 4041 first_block_index = @minimum(first_block_index, block_index - 1); 4042 } else { 4043 first_block_index = @minimum(first_block_index, block_index); 4044 } 4045 if (try sema.resolveMaybeUndefValAllowVariables(block, field_src, bin_op.rhs)) |val| { 4046 field_values[i] = val; 4047 } else { 4048 struct_is_comptime = false; 4049 } 4050 continue :field; 4051 } 4052 struct_is_comptime = false; 4053 continue :field; 4054 } 4055 4056 const default_val = struct_ty.structFieldDefaultValue(i); 4057 if (default_val.tag() == .unreachable_value) { 4058 if (struct_ty.isTuple()) { 4059 const template = "missing tuple field with index {d}"; 4060 if (root_msg) |msg| { 4061 try sema.errNote(block, init_src, msg, template, .{i}); 4062 } else { 4063 root_msg = try sema.errMsg(block, init_src, template, .{i}); 4064 } 4065 continue; 4066 } 4067 const field_name = struct_ty.structFieldName(i); 4068 const template = "missing struct field: {s}"; 4069 const args = .{field_name}; 4070 if (root_msg) |msg| { 4071 try sema.errNote(block, init_src, msg, template, args); 4072 } else { 4073 root_msg = try sema.errMsg(block, init_src, template, args); 4074 } 4075 continue; 4076 } 4077 field_values[i] = default_val; 4078 } 4079 4080 if (root_msg) |msg| { 4081 root_msg = null; 4082 if (struct_ty.castTag(.@"struct")) |struct_obj| { 4083 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod); 4084 defer gpa.free(fqn); 4085 try sema.mod.errNoteNonLazy( 4086 struct_obj.data.srcLoc(sema.mod), 4087 msg, 4088 "struct '{s}' declared here", 4089 .{fqn}, 4090 ); 4091 } 4092 return sema.failWithOwnedErrorMsg(msg); 4093 } 4094 4095 if (struct_is_comptime) { 4096 // Our task is to delete all the `field_ptr` and `store` instructions, and insert 4097 // instead a single `store` to the struct_ptr with a comptime struct value. 4098 4099 block.instructions.shrinkRetainingCapacity(first_block_index); 4100 const struct_val = try Value.Tag.aggregate.create(sema.arena, field_values); 4101 const struct_init = try sema.addConstant(struct_ty, struct_val); 4102 try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store); 4103 return; 4104 } 4105 try sema.resolveStructLayout(block, init_src, struct_ty); 4106 4107 // Our task is to insert `store` instructions for all the default field values. 4108 for (found_fields) |field_ptr, i| { 4109 if (field_ptr != 0) continue; 4110 4111 const field_src = init_src; // TODO better source location 4112 const default_field_ptr = if (struct_ty.isTuple()) 4113 try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true) 4114 else 4115 try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); 4116 const field_ty = sema.typeOf(default_field_ptr).childType(); 4117 const init = try sema.addConstant(field_ty, field_values[i]); 4118 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); 4119 } 4120 } 4121 4122 fn zirValidateArrayInit( 4123 sema: *Sema, 4124 block: *Block, 4125 inst: Zir.Inst.Index, 4126 is_comptime: bool, 4127 ) CompileError!void { 4128 const validate_inst = sema.code.instructions.items(.data)[inst].pl_node; 4129 const init_src = validate_inst.src(); 4130 const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index); 4131 const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len]; 4132 const first_elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; 4133 const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data; 4134 const array_ptr = try sema.resolveInst(elem_ptr_extra.ptr); 4135 const array_ty = sema.typeOf(array_ptr).childType(); 4136 const array_len = array_ty.arrayLen(); 4137 4138 if (instrs.len != array_len and array_ty.isTuple()) { 4139 const struct_obj = array_ty.castTag(.tuple).?.data; 4140 var root_msg: ?*Module.ErrorMsg = null; 4141 errdefer if (root_msg) |msg| msg.destroy(sema.gpa); 4142 4143 for (struct_obj.values) |default_val, i| { 4144 if (i < instrs.len) continue; 4145 4146 if (default_val.tag() == .unreachable_value) { 4147 const template = "missing tuple field with index {d}"; 4148 if (root_msg) |msg| { 4149 try sema.errNote(block, init_src, msg, template, .{i}); 4150 } else { 4151 root_msg = try sema.errMsg(block, init_src, template, .{i}); 4152 } 4153 } 4154 } 4155 4156 if (root_msg) |msg| { 4157 root_msg = null; 4158 return sema.failWithOwnedErrorMsg(msg); 4159 } 4160 } 4161 4162 if ((is_comptime or block.is_comptime) and 4163 (try sema.resolveDefinedValue(block, init_src, array_ptr)) != null) 4164 { 4165 // In this case the comptime machinery will have evaluated the store instructions 4166 // at comptime so we have almost nothing to do here. However, in case of a 4167 // sentinel-terminated array, the sentinel will not have been populated by 4168 // any ZIR instructions at comptime; we need to do that here. 4169 if (array_ty.sentinel()) |sentinel_val| { 4170 const array_len_ref = try sema.addIntUnsigned(Type.usize, array_len); 4171 const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true); 4172 const sentinel = try sema.addConstant(array_ty.childType(), sentinel_val); 4173 try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store); 4174 } 4175 return; 4176 } 4177 4178 var array_is_comptime = true; 4179 var first_block_index = block.instructions.items.len; 4180 4181 // Collect the comptime element values in case the array literal ends up 4182 // being comptime-known. 4183 const array_len_s = try sema.usizeCast(block, init_src, array_ty.arrayLenIncludingSentinel()); 4184 const element_vals = try sema.arena.alloc(Value, array_len_s); 4185 const opt_opv = try sema.typeHasOnePossibleValue(block, init_src, array_ty); 4186 const air_tags = sema.air_instructions.items(.tag); 4187 const air_datas = sema.air_instructions.items(.data); 4188 4189 outer: for (instrs) |elem_ptr, i| { 4190 const elem_ptr_data = sema.code.instructions.items(.data)[elem_ptr].pl_node; 4191 const elem_src = LazySrcLoc.nodeOffset(elem_ptr_data.src_node); 4192 4193 // Determine whether the value stored to this pointer is comptime-known. 4194 4195 if (array_ty.isTuple()) { 4196 if (array_ty.structFieldValueComptime(i)) |opv| { 4197 element_vals[i] = opv; 4198 continue; 4199 } 4200 } else { 4201 // Array has one possible value, so value is always comptime-known 4202 if (opt_opv) |opv| { 4203 element_vals[i] = opv; 4204 continue; 4205 } 4206 } 4207 4208 const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?; 4209 const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?; 4210 // Find the block index of the elem_ptr so that we can look at the next 4211 // instruction after it within the same block. 4212 // Possible performance enhancement: save the `block_index` between iterations 4213 // of the for loop. 4214 var block_index = block.instructions.items.len - 1; 4215 while (block.instructions.items[block_index] != elem_ptr_air_inst) { 4216 if (block_index == 0) { 4217 array_is_comptime = true; 4218 continue :outer; 4219 } 4220 block_index -= 1; 4221 } 4222 first_block_index = @minimum(first_block_index, block_index); 4223 4224 // If the next instructon is a store with a comptime operand, this element 4225 // is comptime. 4226 const next_air_inst = block.instructions.items[block_index + 1]; 4227 switch (air_tags[next_air_inst]) { 4228 .store => { 4229 const bin_op = air_datas[next_air_inst].bin_op; 4230 var lhs = bin_op.lhs; 4231 if (Air.refToIndex(lhs)) |lhs_index| { 4232 if (air_tags[lhs_index] == .bitcast) { 4233 lhs = air_datas[lhs_index].ty_op.operand; 4234 block_index -= 1; 4235 } 4236 } 4237 if (lhs != elem_ptr_air_ref) { 4238 array_is_comptime = false; 4239 continue; 4240 } 4241 if (try sema.resolveMaybeUndefValAllowVariables(block, elem_src, bin_op.rhs)) |val| { 4242 element_vals[i] = val; 4243 } else { 4244 array_is_comptime = false; 4245 } 4246 continue; 4247 }, 4248 .bitcast => { 4249 // %a = bitcast(*arr_ty, %array_base) 4250 // %b = ptr_elem_ptr(%a, %index) 4251 // %c = bitcast(*elem_ty, %b) 4252 // %d = store(%c, %val) 4253 if (air_datas[next_air_inst].ty_op.operand != elem_ptr_air_ref) { 4254 array_is_comptime = false; 4255 continue; 4256 } 4257 const store_inst = block.instructions.items[block_index + 2]; 4258 if (air_tags[store_inst] != .store) { 4259 array_is_comptime = false; 4260 continue; 4261 } 4262 const bin_op = air_datas[store_inst].bin_op; 4263 if (bin_op.lhs != Air.indexToRef(next_air_inst)) { 4264 array_is_comptime = false; 4265 continue; 4266 } 4267 if (try sema.resolveMaybeUndefValAllowVariables(block, elem_src, bin_op.rhs)) |val| { 4268 element_vals[i] = val; 4269 } else { 4270 array_is_comptime = false; 4271 } 4272 continue; 4273 }, 4274 else => { 4275 array_is_comptime = false; 4276 continue; 4277 }, 4278 } 4279 } 4280 4281 if (array_is_comptime) { 4282 if (try sema.resolveDefinedValue(block, init_src, array_ptr)) |ptr_val| { 4283 if (ptr_val.tag() == .comptime_field_ptr) { 4284 // This store was validated by the individual elem ptrs. 4285 return; 4286 } 4287 } 4288 4289 // Our task is to delete all the `elem_ptr` and `store` instructions, and insert 4290 // instead a single `store` to the array_ptr with a comptime struct value. 4291 // Also to populate the sentinel value, if any. 4292 if (array_ty.sentinel()) |sentinel_val| { 4293 element_vals[instrs.len] = sentinel_val; 4294 } 4295 4296 block.instructions.shrinkRetainingCapacity(first_block_index); 4297 4298 const array_val = try Value.Tag.aggregate.create(sema.arena, element_vals); 4299 const array_init = try sema.addConstant(array_ty, array_val); 4300 try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store); 4301 } 4302 } 4303 4304 fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 4305 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 4306 const src = inst_data.src(); 4307 const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; 4308 const operand = try sema.resolveInst(inst_data.operand); 4309 const operand_ty = sema.typeOf(operand); 4310 4311 if (operand_ty.zigTypeTag() != .Pointer) { 4312 return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(sema.mod)}); 4313 } else switch (operand_ty.ptrSize()) { 4314 .One, .C => {}, 4315 .Many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(sema.mod)}), 4316 .Slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(sema.mod)}), 4317 } 4318 4319 const elem_ty = operand_ty.elemType2(); 4320 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { 4321 if (val.isUndef()) { 4322 return sema.fail(block, src, "cannot dereference undefined value", .{}); 4323 } 4324 } else if (!(try sema.validateRunTimeType(block, src, elem_ty, false))) { 4325 const msg = msg: { 4326 const msg = try sema.errMsg( 4327 block, 4328 src, 4329 "values of type '{}' must be comptime known, but operand value is runtime known", 4330 .{elem_ty.fmt(sema.mod)}, 4331 ); 4332 errdefer msg.destroy(sema.gpa); 4333 4334 const src_decl = sema.mod.declPtr(block.src_decl); 4335 try sema.explainWhyTypeIsComptime(block, src, msg, src.toSrcLoc(src_decl), elem_ty); 4336 break :msg msg; 4337 }; 4338 return sema.failWithOwnedErrorMsg(msg); 4339 } 4340 } 4341 4342 fn failWithBadMemberAccess( 4343 sema: *Sema, 4344 block: *Block, 4345 agg_ty: Type, 4346 field_src: LazySrcLoc, 4347 field_name: []const u8, 4348 ) CompileError { 4349 const kw_name = switch (agg_ty.zigTypeTag()) { 4350 .Union => "union", 4351 .Struct => "struct", 4352 .Opaque => "opaque", 4353 .Enum => "enum", 4354 else => unreachable, 4355 }; 4356 const msg = msg: { 4357 const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{s}'", .{ 4358 kw_name, agg_ty.fmt(sema.mod), field_name, 4359 }); 4360 errdefer msg.destroy(sema.gpa); 4361 try sema.addDeclaredHereNote(msg, agg_ty); 4362 break :msg msg; 4363 }; 4364 return sema.failWithOwnedErrorMsg(msg); 4365 } 4366 4367 fn failWithBadStructFieldAccess( 4368 sema: *Sema, 4369 block: *Block, 4370 struct_obj: *Module.Struct, 4371 field_src: LazySrcLoc, 4372 field_name: []const u8, 4373 ) CompileError { 4374 const gpa = sema.gpa; 4375 4376 const fqn = try struct_obj.getFullyQualifiedName(sema.mod); 4377 defer gpa.free(fqn); 4378 4379 const msg = msg: { 4380 const msg = try sema.errMsg( 4381 block, 4382 field_src, 4383 "no field named '{s}' in struct '{s}'", 4384 .{ field_name, fqn }, 4385 ); 4386 errdefer msg.destroy(gpa); 4387 try sema.mod.errNoteNonLazy(struct_obj.srcLoc(sema.mod), msg, "struct declared here", .{}); 4388 break :msg msg; 4389 }; 4390 return sema.failWithOwnedErrorMsg(msg); 4391 } 4392 4393 fn failWithBadUnionFieldAccess( 4394 sema: *Sema, 4395 block: *Block, 4396 union_obj: *Module.Union, 4397 field_src: LazySrcLoc, 4398 field_name: []const u8, 4399 ) CompileError { 4400 const gpa = sema.gpa; 4401 4402 const fqn = try union_obj.getFullyQualifiedName(sema.mod); 4403 defer gpa.free(fqn); 4404 4405 const msg = msg: { 4406 const msg = try sema.errMsg( 4407 block, 4408 field_src, 4409 "no field named '{s}' in union '{s}'", 4410 .{ field_name, fqn }, 4411 ); 4412 errdefer msg.destroy(gpa); 4413 try sema.mod.errNoteNonLazy(union_obj.srcLoc(sema.mod), msg, "union declared here", .{}); 4414 break :msg msg; 4415 }; 4416 return sema.failWithOwnedErrorMsg(msg); 4417 } 4418 4419 fn addDeclaredHereNote(sema: *Sema, parent: *Module.ErrorMsg, decl_ty: Type) !void { 4420 const src_loc = decl_ty.declSrcLocOrNull(sema.mod) orelse return; 4421 const category = switch (decl_ty.zigTypeTag()) { 4422 .Union => "union", 4423 .Struct => "struct", 4424 .Enum => "enum", 4425 .Opaque => "opaque", 4426 .ErrorSet => "error set", 4427 else => unreachable, 4428 }; 4429 try sema.mod.errNoteNonLazy(src_loc, parent, "{s} declared here", .{category}); 4430 } 4431 4432 fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 4433 const tracy = trace(@src()); 4434 defer tracy.end(); 4435 4436 const bin_inst = sema.code.instructions.items(.data)[inst].bin; 4437 const ptr = sema.inst_map.get(Zir.refToIndex(bin_inst.lhs).?) orelse { 4438 // This is an elided instruction, but AstGen was unable to omit it. 4439 return; 4440 }; 4441 const operand = try sema.resolveInst(bin_inst.rhs); 4442 const src: LazySrcLoc = sema.src; 4443 blk: { 4444 const ptr_inst = Air.refToIndex(ptr) orelse break :blk; 4445 if (sema.air_instructions.items(.tag)[ptr_inst] != .constant) break :blk; 4446 const air_datas = sema.air_instructions.items(.data); 4447 const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; 4448 switch (ptr_val.tag()) { 4449 .inferred_alloc_comptime => { 4450 const iac = ptr_val.castTag(.inferred_alloc_comptime).?; 4451 return sema.storeToInferredAllocComptime(block, src, operand, iac); 4452 }, 4453 .inferred_alloc => { 4454 const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; 4455 return sema.storeToInferredAlloc(block, src, ptr, operand, inferred_alloc); 4456 }, 4457 else => break :blk, 4458 } 4459 } 4460 4461 return sema.storePtr(block, src, ptr, operand); 4462 } 4463 4464 fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 4465 const tracy = trace(@src()); 4466 defer tracy.end(); 4467 4468 const src: LazySrcLoc = sema.src; 4469 const bin_inst = sema.code.instructions.items(.data)[inst].bin; 4470 const ptr = try sema.resolveInst(bin_inst.lhs); 4471 const operand = try sema.resolveInst(bin_inst.rhs); 4472 const ptr_inst = Air.refToIndex(ptr).?; 4473 assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant); 4474 const air_datas = sema.air_instructions.items(.data); 4475 const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; 4476 4477 switch (ptr_val.tag()) { 4478 .inferred_alloc_comptime => { 4479 const iac = ptr_val.castTag(.inferred_alloc_comptime).?; 4480 return sema.storeToInferredAllocComptime(block, src, operand, iac); 4481 }, 4482 .inferred_alloc => { 4483 const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; 4484 return sema.storeToInferredAlloc(block, src, ptr, operand, inferred_alloc); 4485 }, 4486 else => unreachable, 4487 } 4488 } 4489 4490 fn storeToInferredAlloc( 4491 sema: *Sema, 4492 block: *Block, 4493 src: LazySrcLoc, 4494 ptr: Air.Inst.Ref, 4495 operand: Air.Inst.Ref, 4496 inferred_alloc: *Value.Payload.InferredAlloc, 4497 ) CompileError!void { 4498 const operand_ty = sema.typeOf(operand); 4499 // Create a runtime bitcast instruction with exactly the type the pointer wants. 4500 const target = sema.mod.getTarget(); 4501 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 4502 .pointee_type = operand_ty, 4503 .@"align" = inferred_alloc.data.alignment, 4504 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 4505 }); 4506 const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr); 4507 // Add the stored instruction to the set we will use to resolve peer types 4508 // for the inferred allocation. 4509 try inferred_alloc.data.prongs.append(sema.arena, .{ 4510 .stored_inst = operand, 4511 .placeholder = Air.refToIndex(bitcasted_ptr).?, 4512 }); 4513 return sema.storePtr2(block, src, bitcasted_ptr, src, operand, src, .bitcast); 4514 } 4515 4516 fn storeToInferredAllocComptime( 4517 sema: *Sema, 4518 block: *Block, 4519 src: LazySrcLoc, 4520 operand: Air.Inst.Ref, 4521 iac: *Value.Payload.InferredAllocComptime, 4522 ) CompileError!void { 4523 const operand_ty = sema.typeOf(operand); 4524 // There will be only one store_to_inferred_ptr because we are running at comptime. 4525 // The alloc will turn into a Decl. 4526 if (try sema.resolveMaybeUndefValAllowVariables(block, src, operand)) |operand_val| store: { 4527 if (operand_val.tag() == .variable) break :store; 4528 var anon_decl = try block.startAnonDecl(src); 4529 defer anon_decl.deinit(); 4530 iac.data.decl_index = try anon_decl.finish( 4531 try operand_ty.copy(anon_decl.arena()), 4532 try operand_val.copy(anon_decl.arena()), 4533 iac.data.alignment, 4534 ); 4535 return; 4536 } 4537 4538 return sema.failWithNeededComptime(block, src, "value being stored to a comptime variable must be comptime known"); 4539 } 4540 4541 fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 4542 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 4543 const src = inst_data.src(); 4544 const quota = @intCast(u32, try sema.resolveInt(block, src, inst_data.operand, Type.u32, "eval branch quota must be comptime known")); 4545 sema.branch_quota = @maximum(sema.branch_quota, quota); 4546 } 4547 4548 fn zirStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 4549 const tracy = trace(@src()); 4550 defer tracy.end(); 4551 4552 const bin_inst = sema.code.instructions.items(.data)[inst].bin; 4553 const ptr = try sema.resolveInst(bin_inst.lhs); 4554 const value = try sema.resolveInst(bin_inst.rhs); 4555 return sema.storePtr(block, sema.src, ptr, value); 4556 } 4557 4558 fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 4559 const tracy = trace(@src()); 4560 defer tracy.end(); 4561 4562 const zir_tags = sema.code.instructions.items(.tag); 4563 const zir_datas = sema.code.instructions.items(.data); 4564 const inst_data = zir_datas[inst].pl_node; 4565 const src = inst_data.src(); 4566 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 4567 const ptr = try sema.resolveInst(extra.lhs); 4568 const operand = try sema.resolveInst(extra.rhs); 4569 4570 const is_ret = if (Zir.refToIndex(extra.lhs)) |ptr_index| 4571 zir_tags[ptr_index] == .ret_ptr 4572 else 4573 false; 4574 4575 // Check for the possibility of this pattern: 4576 // %a = ret_ptr 4577 // %b = store(%a, %c) 4578 // Where %c is an error union or error set. In such case we need to add 4579 // to the current function's inferred error set, if any. 4580 if (is_ret and (sema.typeOf(operand).zigTypeTag() == .ErrorUnion or 4581 sema.typeOf(operand).zigTypeTag() == .ErrorSet) and 4582 sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) 4583 { 4584 try sema.addToInferredErrorSet(operand); 4585 } 4586 4587 return sema.storePtr2(block, src, ptr, src, operand, src, if (is_ret) .ret_ptr else .store); 4588 } 4589 4590 fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4591 const tracy = trace(@src()); 4592 defer tracy.end(); 4593 4594 const bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code); 4595 return sema.addStrLit(block, bytes); 4596 } 4597 4598 fn addStrLit(sema: *Sema, block: *Block, zir_bytes: []const u8) CompileError!Air.Inst.Ref { 4599 // `zir_bytes` references memory inside the ZIR module, which can get deallocated 4600 // after semantic analysis is complete, for example in the case of the initialization 4601 // expression of a variable declaration. 4602 const mod = sema.mod; 4603 const gpa = sema.gpa; 4604 const string_bytes = &mod.string_literal_bytes; 4605 const StringLiteralAdapter = Module.StringLiteralAdapter; 4606 const StringLiteralContext = Module.StringLiteralContext; 4607 try string_bytes.ensureUnusedCapacity(gpa, zir_bytes.len); 4608 const gop = try mod.string_literal_table.getOrPutContextAdapted(gpa, zir_bytes, StringLiteralAdapter{ 4609 .bytes = string_bytes, 4610 }, StringLiteralContext{ 4611 .bytes = string_bytes, 4612 }); 4613 if (!gop.found_existing) { 4614 gop.key_ptr.* = .{ 4615 .index = @intCast(u32, string_bytes.items.len), 4616 .len = @intCast(u32, zir_bytes.len), 4617 }; 4618 string_bytes.appendSliceAssumeCapacity(zir_bytes); 4619 gop.value_ptr.* = .none; 4620 } 4621 const decl_index = gop.value_ptr.unwrap() orelse di: { 4622 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded); 4623 defer anon_decl.deinit(); 4624 4625 const decl_index = try anon_decl.finish( 4626 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), gop.key_ptr.len), 4627 try Value.Tag.str_lit.create(anon_decl.arena(), gop.key_ptr.*), 4628 0, // default alignment 4629 ); 4630 4631 // Needed so that `Decl.clearValues` will additionally set the corresponding 4632 // string literal table value back to `Decl.OptionalIndex.none`. 4633 mod.declPtr(decl_index).owns_tv = true; 4634 4635 gop.value_ptr.* = decl_index.toOptional(); 4636 break :di decl_index; 4637 }; 4638 return sema.analyzeDeclRef(decl_index); 4639 } 4640 4641 fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4642 _ = block; 4643 const tracy = trace(@src()); 4644 defer tracy.end(); 4645 4646 const int = sema.code.instructions.items(.data)[inst].int; 4647 return sema.addIntUnsigned(Type.initTag(.comptime_int), int); 4648 } 4649 4650 fn zirIntBig(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4651 _ = block; 4652 const tracy = trace(@src()); 4653 defer tracy.end(); 4654 4655 const arena = sema.arena; 4656 const int = sema.code.instructions.items(.data)[inst].str; 4657 const byte_count = int.len * @sizeOf(std.math.big.Limb); 4658 const limb_bytes = sema.code.string_bytes[int.start..][0..byte_count]; 4659 const limbs = try arena.alloc(std.math.big.Limb, int.len); 4660 mem.copy(u8, mem.sliceAsBytes(limbs), limb_bytes); 4661 4662 return sema.addConstant( 4663 Type.initTag(.comptime_int), 4664 try Value.Tag.int_big_positive.create(arena, limbs), 4665 ); 4666 } 4667 4668 fn zirFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4669 _ = block; 4670 const arena = sema.arena; 4671 const number = sema.code.instructions.items(.data)[inst].float; 4672 return sema.addConstant( 4673 Type.initTag(.comptime_float), 4674 try Value.Tag.float_64.create(arena, number), 4675 ); 4676 } 4677 4678 fn zirFloat128(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4679 _ = block; 4680 const arena = sema.arena; 4681 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 4682 const extra = sema.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data; 4683 const number = extra.get(); 4684 return sema.addConstant( 4685 Type.initTag(.comptime_float), 4686 try Value.Tag.float_128.create(arena, number), 4687 ); 4688 } 4689 4690 fn zirCompileError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { 4691 const tracy = trace(@src()); 4692 defer tracy.end(); 4693 4694 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 4695 const src = inst_data.src(); 4696 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 4697 const msg = try sema.resolveConstString(block, operand_src, inst_data.operand, "compile error string must be comptime known"); 4698 return sema.fail(block, src, "{s}", .{msg}); 4699 } 4700 4701 fn zirCompileLog( 4702 sema: *Sema, 4703 block: *Block, 4704 extended: Zir.Inst.Extended.InstData, 4705 ) CompileError!Air.Inst.Ref { 4706 var managed = sema.mod.compile_log_text.toManaged(sema.gpa); 4707 defer sema.mod.compile_log_text = managed.moveToUnmanaged(); 4708 const writer = managed.writer(); 4709 4710 const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand); 4711 const src_node = extra.data.src_node; 4712 const src = LazySrcLoc.nodeOffset(src_node); 4713 const args = sema.code.refSlice(extra.end, extended.small); 4714 4715 for (args) |arg_ref, i| { 4716 if (i != 0) try writer.print(", ", .{}); 4717 4718 const arg = try sema.resolveInst(arg_ref); 4719 const arg_ty = sema.typeOf(arg); 4720 if (try sema.resolveMaybeUndefVal(block, src, arg)) |val| { 4721 try sema.resolveLazyValue(block, src, val); 4722 try writer.print("@as({}, {})", .{ 4723 arg_ty.fmt(sema.mod), val.fmtValue(arg_ty, sema.mod), 4724 }); 4725 } else { 4726 try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(sema.mod)}); 4727 } 4728 } 4729 try writer.print("\n", .{}); 4730 4731 const decl_index = if (sema.func) |some| some.owner_decl else sema.owner_decl_index; 4732 const gop = try sema.mod.compile_log_decls.getOrPut(sema.gpa, decl_index); 4733 if (!gop.found_existing) { 4734 gop.value_ptr.* = src_node; 4735 } 4736 return Air.Inst.Ref.void_value; 4737 } 4738 4739 fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index, force_comptime: bool) CompileError!Zir.Inst.Index { 4740 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 4741 const src = inst_data.src(); 4742 const msg_inst = try sema.resolveInst(inst_data.operand); 4743 4744 if (block.is_comptime or force_comptime) { 4745 return sema.fail(block, src, "encountered @panic at comptime", .{}); 4746 } 4747 try sema.requireFunctionBlock(block, src); 4748 return sema.panicWithMsg(block, src, msg_inst); 4749 } 4750 4751 fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4752 const tracy = trace(@src()); 4753 defer tracy.end(); 4754 4755 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 4756 const src = inst_data.src(); 4757 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); 4758 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 4759 const gpa = sema.gpa; 4760 4761 // AIR expects a block outside the loop block too. 4762 // Reserve space for a Loop instruction so that generated Break instructions can 4763 // point to it, even if it doesn't end up getting used because the code ends up being 4764 // comptime evaluated. 4765 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 4766 const loop_inst = block_inst + 1; 4767 try sema.air_instructions.ensureUnusedCapacity(gpa, 2); 4768 sema.air_instructions.appendAssumeCapacity(.{ 4769 .tag = .block, 4770 .data = undefined, 4771 }); 4772 sema.air_instructions.appendAssumeCapacity(.{ 4773 .tag = .loop, 4774 .data = .{ .ty_pl = .{ 4775 .ty = .noreturn_type, 4776 .payload = undefined, 4777 } }, 4778 }); 4779 var label: Block.Label = .{ 4780 .zir_block = inst, 4781 .merges = .{ 4782 .results = .{}, 4783 .br_list = .{}, 4784 .block_inst = block_inst, 4785 }, 4786 }; 4787 var child_block = parent_block.makeSubBlock(); 4788 child_block.label = &label; 4789 child_block.runtime_cond = null; 4790 child_block.runtime_loop = src; 4791 child_block.runtime_index.increment(); 4792 const merges = &child_block.label.?.merges; 4793 4794 defer child_block.instructions.deinit(gpa); 4795 defer merges.results.deinit(gpa); 4796 defer merges.br_list.deinit(gpa); 4797 4798 var loop_block = child_block.makeSubBlock(); 4799 defer loop_block.instructions.deinit(gpa); 4800 4801 try sema.analyzeBody(&loop_block, body); 4802 4803 try child_block.instructions.append(gpa, loop_inst); 4804 4805 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + 4806 loop_block.instructions.items.len); 4807 sema.air_instructions.items(.data)[loop_inst].ty_pl.payload = sema.addExtraAssumeCapacity( 4808 Air.Block{ .body_len = @intCast(u32, loop_block.instructions.items.len) }, 4809 ); 4810 sema.air_extra.appendSliceAssumeCapacity(loop_block.instructions.items); 4811 return sema.analyzeBlockBody(parent_block, src, &child_block, merges); 4812 } 4813 4814 fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4815 const tracy = trace(@src()); 4816 defer tracy.end(); 4817 4818 const pl_node = sema.code.instructions.items(.data)[inst].pl_node; 4819 const src = pl_node.src(); 4820 const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index); 4821 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 4822 4823 // we check this here to avoid undefined symbols 4824 if (!@import("build_options").have_llvm) 4825 return sema.fail(parent_block, src, "cannot do C import on Zig compiler not built with LLVM-extension", .{}); 4826 4827 var c_import_buf = std.ArrayList(u8).init(sema.gpa); 4828 defer c_import_buf.deinit(); 4829 4830 var child_block: Block = .{ 4831 .parent = parent_block, 4832 .sema = sema, 4833 .src_decl = parent_block.src_decl, 4834 .namespace = parent_block.namespace, 4835 .wip_capture_scope = parent_block.wip_capture_scope, 4836 .instructions = .{}, 4837 .inlining = parent_block.inlining, 4838 .is_comptime = parent_block.is_comptime, 4839 .c_import_buf = &c_import_buf, 4840 .runtime_cond = parent_block.runtime_cond, 4841 .runtime_loop = parent_block.runtime_loop, 4842 .runtime_index = parent_block.runtime_index, 4843 }; 4844 defer child_block.instructions.deinit(sema.gpa); 4845 4846 // Ignore the result, all the relevant operations have written to c_import_buf already. 4847 _ = try sema.analyzeBodyBreak(&child_block, body); 4848 4849 const mod = sema.mod; 4850 const c_import_res = mod.comp.cImport(c_import_buf.items) catch |err| 4851 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); 4852 4853 if (c_import_res.errors.len != 0) { 4854 const msg = msg: { 4855 const msg = try sema.errMsg(&child_block, src, "C import failed", .{}); 4856 errdefer msg.destroy(sema.gpa); 4857 4858 if (!mod.comp.bin_file.options.link_libc) 4859 try sema.errNote(&child_block, src, msg, "libc headers not available; compilation does not link against libc", .{}); 4860 4861 for (c_import_res.errors) |_| { 4862 // TODO integrate with LazySrcLoc 4863 // try mod.errNoteNonLazy(.{}, msg, "{s}", .{clang_err.msg_ptr[0..clang_err.msg_len]}); 4864 // if (clang_err.filename_ptr) |p| p[0..clang_err.filename_len] else "(no file)", 4865 // clang_err.line + 1, 4866 // clang_err.column + 1, 4867 } 4868 @import("clang.zig").Stage2ErrorMsg.delete(c_import_res.errors.ptr, c_import_res.errors.len); 4869 break :msg msg; 4870 }; 4871 return sema.failWithOwnedErrorMsg(msg); 4872 } 4873 const c_import_pkg = Package.create( 4874 sema.gpa, 4875 null, 4876 c_import_res.out_zig_path, 4877 ) catch |err| switch (err) { 4878 error.OutOfMemory => return error.OutOfMemory, 4879 else => unreachable, // we pass null for root_src_dir_path 4880 }; 4881 4882 const result = mod.importPkg(c_import_pkg) catch |err| 4883 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); 4884 4885 mod.astGenFile(result.file) catch |err| 4886 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); 4887 4888 try mod.semaFile(result.file); 4889 const file_root_decl_index = result.file.root_decl.unwrap().?; 4890 const file_root_decl = mod.declPtr(file_root_decl_index); 4891 try mod.declareDeclDependency(sema.owner_decl_index, file_root_decl_index); 4892 return sema.addConstant(file_root_decl.ty, file_root_decl.val); 4893 } 4894 4895 fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4896 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 4897 const src = inst_data.src(); 4898 return sema.failWithUseOfAsync(parent_block, src); 4899 } 4900 4901 fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4902 const tracy = trace(@src()); 4903 defer tracy.end(); 4904 4905 const pl_node = sema.code.instructions.items(.data)[inst].pl_node; 4906 const src = pl_node.src(); 4907 const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index); 4908 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 4909 const gpa = sema.gpa; 4910 4911 // Reserve space for a Block instruction so that generated Break instructions can 4912 // point to it, even if it doesn't end up getting used because the code ends up being 4913 // comptime evaluated. 4914 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 4915 try sema.air_instructions.append(gpa, .{ 4916 .tag = .block, 4917 .data = undefined, 4918 }); 4919 4920 var label: Block.Label = .{ 4921 .zir_block = inst, 4922 .merges = .{ 4923 .results = .{}, 4924 .br_list = .{}, 4925 .block_inst = block_inst, 4926 }, 4927 }; 4928 4929 var child_block: Block = .{ 4930 .parent = parent_block, 4931 .sema = sema, 4932 .src_decl = parent_block.src_decl, 4933 .namespace = parent_block.namespace, 4934 .wip_capture_scope = parent_block.wip_capture_scope, 4935 .instructions = .{}, 4936 .label = &label, 4937 .inlining = parent_block.inlining, 4938 .is_comptime = parent_block.is_comptime, 4939 .want_safety = parent_block.want_safety, 4940 .float_mode = parent_block.float_mode, 4941 .runtime_cond = parent_block.runtime_cond, 4942 .runtime_loop = parent_block.runtime_loop, 4943 .runtime_index = parent_block.runtime_index, 4944 }; 4945 4946 defer child_block.instructions.deinit(gpa); 4947 defer label.merges.results.deinit(gpa); 4948 defer label.merges.br_list.deinit(gpa); 4949 4950 return sema.resolveBlockBody(parent_block, src, &child_block, body, inst, &label.merges); 4951 } 4952 4953 fn resolveBlockBody( 4954 sema: *Sema, 4955 parent_block: *Block, 4956 src: LazySrcLoc, 4957 child_block: *Block, 4958 body: []const Zir.Inst.Index, 4959 /// This is the instruction that a break instruction within `body` can 4960 /// use to return from the body. 4961 body_inst: Zir.Inst.Index, 4962 merges: *Block.Merges, 4963 ) CompileError!Air.Inst.Ref { 4964 if (child_block.is_comptime) { 4965 return sema.resolveBody(child_block, body, body_inst); 4966 } else { 4967 if (sema.analyzeBodyInner(child_block, body)) |_| { 4968 return sema.analyzeBlockBody(parent_block, src, child_block, merges); 4969 } else |err| switch (err) { 4970 error.ComptimeBreak => { 4971 // Comptime control flow is happening, however child_block may still contain 4972 // runtime instructions which need to be copied to the parent block. 4973 try parent_block.instructions.appendSlice(sema.gpa, child_block.instructions.items); 4974 4975 const break_inst = sema.comptime_break_inst; 4976 const break_data = sema.code.instructions.items(.data)[break_inst].@"break"; 4977 if (break_data.block_inst == body_inst) { 4978 return try sema.resolveInst(break_data.operand); 4979 } else { 4980 return error.ComptimeBreak; 4981 } 4982 }, 4983 else => |e| return e, 4984 } 4985 } 4986 } 4987 4988 fn analyzeBlockBody( 4989 sema: *Sema, 4990 parent_block: *Block, 4991 src: LazySrcLoc, 4992 child_block: *Block, 4993 merges: *Block.Merges, 4994 ) CompileError!Air.Inst.Ref { 4995 const tracy = trace(@src()); 4996 defer tracy.end(); 4997 4998 const gpa = sema.gpa; 4999 const mod = sema.mod; 5000 5001 // Blocks must terminate with noreturn instruction. 5002 assert(child_block.instructions.items.len != 0); 5003 assert(sema.typeOf(Air.indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1])).isNoReturn()); 5004 5005 if (merges.results.items.len == 0) { 5006 // No need for a block instruction. We can put the new instructions 5007 // directly into the parent block. 5008 try parent_block.instructions.appendSlice(gpa, child_block.instructions.items); 5009 return Air.indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1]); 5010 } 5011 if (merges.results.items.len == 1) { 5012 const last_inst_index = child_block.instructions.items.len - 1; 5013 const last_inst = child_block.instructions.items[last_inst_index]; 5014 if (sema.getBreakBlock(last_inst)) |br_block| { 5015 if (br_block == merges.block_inst) { 5016 // No need for a block instruction. We can put the new instructions directly 5017 // into the parent block. Here we omit the break instruction. 5018 const without_break = child_block.instructions.items[0..last_inst_index]; 5019 try parent_block.instructions.appendSlice(gpa, without_break); 5020 return merges.results.items[0]; 5021 } 5022 } 5023 } 5024 // It is impossible to have the number of results be > 1 in a comptime scope. 5025 assert(!child_block.is_comptime); // Should already got a compile error in the condbr condition. 5026 5027 // Need to set the type and emit the Block instruction. This allows machine code generation 5028 // to emit a jump instruction to after the block when it encounters the break. 5029 try parent_block.instructions.append(gpa, merges.block_inst); 5030 const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .none); 5031 // TODO add note "missing else causes void value" 5032 5033 const type_src = src; // TODO: better source location 5034 const valid_rt = try sema.validateRunTimeType(child_block, type_src, resolved_ty, false); 5035 if (!valid_rt) { 5036 const msg = msg: { 5037 const msg = try sema.errMsg(child_block, type_src, "value with comptime only type '{}' depends on runtime control flow", .{resolved_ty.fmt(mod)}); 5038 errdefer msg.destroy(sema.gpa); 5039 5040 const runtime_src = child_block.runtime_cond orelse child_block.runtime_loop.?; 5041 try sema.errNote(child_block, runtime_src, msg, "runtime control flow here", .{}); 5042 5043 const child_src_decl = mod.declPtr(child_block.src_decl); 5044 try sema.explainWhyTypeIsComptime(child_block, type_src, msg, type_src.toSrcLoc(child_src_decl), resolved_ty); 5045 5046 break :msg msg; 5047 }; 5048 return sema.failWithOwnedErrorMsg(msg); 5049 } 5050 const ty_inst = try sema.addType(resolved_ty); 5051 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + 5052 child_block.instructions.items.len); 5053 sema.air_instructions.items(.data)[merges.block_inst] = .{ .ty_pl = .{ 5054 .ty = ty_inst, 5055 .payload = sema.addExtraAssumeCapacity(Air.Block{ 5056 .body_len = @intCast(u32, child_block.instructions.items.len), 5057 }), 5058 } }; 5059 sema.air_extra.appendSliceAssumeCapacity(child_block.instructions.items); 5060 // Now that the block has its type resolved, we need to go back into all the break 5061 // instructions, and insert type coercion on the operands. 5062 for (merges.br_list.items) |br| { 5063 const br_operand = sema.air_instructions.items(.data)[br].br.operand; 5064 const br_operand_src = src; 5065 const br_operand_ty = sema.typeOf(br_operand); 5066 if (br_operand_ty.eql(resolved_ty, mod)) { 5067 // No type coercion needed. 5068 continue; 5069 } 5070 var coerce_block = parent_block.makeSubBlock(); 5071 defer coerce_block.instructions.deinit(gpa); 5072 const coerced_operand = try sema.coerce(&coerce_block, resolved_ty, br_operand, br_operand_src); 5073 // If no instructions were produced, such as in the case of a coercion of a 5074 // constant value to a new type, we can simply point the br operand to it. 5075 if (coerce_block.instructions.items.len == 0) { 5076 sema.air_instructions.items(.data)[br].br.operand = coerced_operand; 5077 continue; 5078 } 5079 assert(coerce_block.instructions.items[coerce_block.instructions.items.len - 1] == 5080 Air.refToIndex(coerced_operand).?); 5081 5082 // Convert the br instruction to a block instruction that has the coercion 5083 // and then a new br inside that returns the coerced instruction. 5084 const sub_block_len = @intCast(u32, coerce_block.instructions.items.len + 1); 5085 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + 5086 sub_block_len); 5087 try sema.air_instructions.ensureUnusedCapacity(gpa, 1); 5088 const sub_br_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 5089 5090 sema.air_instructions.items(.tag)[br] = .block; 5091 sema.air_instructions.items(.data)[br] = .{ .ty_pl = .{ 5092 .ty = Air.Inst.Ref.noreturn_type, 5093 .payload = sema.addExtraAssumeCapacity(Air.Block{ 5094 .body_len = sub_block_len, 5095 }), 5096 } }; 5097 sema.air_extra.appendSliceAssumeCapacity(coerce_block.instructions.items); 5098 sema.air_extra.appendAssumeCapacity(sub_br_inst); 5099 5100 sema.air_instructions.appendAssumeCapacity(.{ 5101 .tag = .br, 5102 .data = .{ .br = .{ 5103 .block_inst = merges.block_inst, 5104 .operand = coerced_operand, 5105 } }, 5106 }); 5107 } 5108 return Air.indexToRef(merges.block_inst); 5109 } 5110 5111 fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5112 const tracy = trace(@src()); 5113 defer tracy.end(); 5114 5115 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 5116 const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data; 5117 const src = inst_data.src(); 5118 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 5119 const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 5120 const decl_name = sema.code.nullTerminatedString(extra.decl_name); 5121 if (extra.namespace != .none) { 5122 return sema.fail(block, src, "TODO: implement exporting with field access", .{}); 5123 } 5124 const decl_index = try sema.lookupIdentifier(block, operand_src, decl_name); 5125 const options = sema.resolveExportOptions(block, .unneeded, extra.options) catch |err| switch (err) { 5126 error.NeededSourceLocation => { 5127 _ = try sema.resolveExportOptions(block, options_src, extra.options); 5128 return error.AnalysisFail; 5129 }, 5130 else => |e| return e, 5131 }; 5132 try sema.analyzeExport(block, src, options, decl_index); 5133 } 5134 5135 fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5136 const tracy = trace(@src()); 5137 defer tracy.end(); 5138 5139 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 5140 const extra = sema.code.extraData(Zir.Inst.ExportValue, inst_data.payload_index).data; 5141 const src = inst_data.src(); 5142 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 5143 const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 5144 const operand = try sema.resolveInstConst(block, operand_src, extra.operand, "export target must be comptime known"); 5145 const options = sema.resolveExportOptions(block, .unneeded, extra.options) catch |err| switch (err) { 5146 error.NeededSourceLocation => { 5147 _ = try sema.resolveExportOptions(block, options_src, extra.options); 5148 return error.AnalysisFail; 5149 }, 5150 else => |e| return e, 5151 }; 5152 const decl_index = switch (operand.val.tag()) { 5153 .function => operand.val.castTag(.function).?.data.owner_decl, 5154 else => return sema.fail(block, operand_src, "TODO implement exporting arbitrary Value objects", .{}), // TODO put this Value into an anonymous Decl and then export it. 5155 }; 5156 try sema.analyzeExport(block, src, options, decl_index); 5157 } 5158 5159 pub fn analyzeExport( 5160 sema: *Sema, 5161 block: *Block, 5162 src: LazySrcLoc, 5163 borrowed_options: std.builtin.ExportOptions, 5164 exported_decl_index: Decl.Index, 5165 ) !void { 5166 const Export = Module.Export; 5167 const mod = sema.mod; 5168 5169 if (borrowed_options.linkage == .Internal) { 5170 return; 5171 } 5172 5173 try mod.ensureDeclAnalyzed(exported_decl_index); 5174 const exported_decl = mod.declPtr(exported_decl_index); 5175 5176 if (!try sema.validateExternType(block, src, exported_decl.ty, .other)) { 5177 const msg = msg: { 5178 const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(sema.mod)}); 5179 errdefer msg.destroy(sema.gpa); 5180 5181 const src_decl = sema.mod.declPtr(block.src_decl); 5182 try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), exported_decl.ty, .other); 5183 5184 try sema.addDeclaredHereNote(msg, exported_decl.ty); 5185 break :msg msg; 5186 }; 5187 return sema.failWithOwnedErrorMsg(msg); 5188 } 5189 5190 const gpa = mod.gpa; 5191 5192 try mod.decl_exports.ensureUnusedCapacity(gpa, 1); 5193 try mod.export_owners.ensureUnusedCapacity(gpa, 1); 5194 5195 const new_export = try gpa.create(Export); 5196 errdefer gpa.destroy(new_export); 5197 5198 const symbol_name = try gpa.dupe(u8, borrowed_options.name); 5199 errdefer gpa.free(symbol_name); 5200 5201 const section: ?[]const u8 = if (borrowed_options.section) |s| try gpa.dupe(u8, s) else null; 5202 errdefer if (section) |s| gpa.free(s); 5203 5204 new_export.* = .{ 5205 .options = .{ 5206 .name = symbol_name, 5207 .linkage = borrowed_options.linkage, 5208 .section = section, 5209 .visibility = borrowed_options.visibility, 5210 }, 5211 .src = src, 5212 .link = switch (mod.comp.bin_file.tag) { 5213 .coff => .{ .coff = .{} }, 5214 .elf => .{ .elf = .{} }, 5215 .macho => .{ .macho = .{} }, 5216 .plan9 => .{ .plan9 = null }, 5217 .c => .{ .c = {} }, 5218 .wasm => .{ .wasm = .{} }, 5219 .spirv => .{ .spirv = {} }, 5220 .nvptx => .{ .nvptx = {} }, 5221 }, 5222 .owner_decl = sema.owner_decl_index, 5223 .src_decl = block.src_decl, 5224 .exported_decl = exported_decl_index, 5225 .status = .in_progress, 5226 }; 5227 5228 // Add to export_owners table. 5229 const eo_gop = mod.export_owners.getOrPutAssumeCapacity(sema.owner_decl_index); 5230 if (!eo_gop.found_existing) { 5231 eo_gop.value_ptr.* = &[0]*Export{}; 5232 } 5233 eo_gop.value_ptr.* = try gpa.realloc(eo_gop.value_ptr.*, eo_gop.value_ptr.len + 1); 5234 eo_gop.value_ptr.*[eo_gop.value_ptr.len - 1] = new_export; 5235 errdefer eo_gop.value_ptr.* = gpa.shrink(eo_gop.value_ptr.*, eo_gop.value_ptr.len - 1); 5236 5237 // Add to exported_decl table. 5238 const de_gop = mod.decl_exports.getOrPutAssumeCapacity(exported_decl_index); 5239 if (!de_gop.found_existing) { 5240 de_gop.value_ptr.* = &[0]*Export{}; 5241 } 5242 de_gop.value_ptr.* = try gpa.realloc(de_gop.value_ptr.*, de_gop.value_ptr.len + 1); 5243 de_gop.value_ptr.*[de_gop.value_ptr.len - 1] = new_export; 5244 errdefer de_gop.value_ptr.* = gpa.shrink(de_gop.value_ptr.*, de_gop.value_ptr.len - 1); 5245 } 5246 5247 fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { 5248 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 5249 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 5250 const src = LazySrcLoc.nodeOffset(extra.node); 5251 const alignment = try sema.resolveAlign(block, operand_src, extra.operand); 5252 if (alignment > 256) { 5253 return sema.fail(block, src, "attempt to @setAlignStack({d}); maximum is 256", .{ 5254 alignment, 5255 }); 5256 } 5257 const func = sema.func orelse 5258 return sema.fail(block, src, "@setAlignStack outside function body", .{}); 5259 5260 const fn_owner_decl = sema.mod.declPtr(func.owner_decl); 5261 switch (fn_owner_decl.ty.fnCallingConvention()) { 5262 .Naked => return sema.fail(block, src, "@setAlignStack in naked function", .{}), 5263 .Inline => return sema.fail(block, src, "@setAlignStack in inline function", .{}), 5264 else => if (block.inlining != null) { 5265 return sema.fail(block, src, "@setAlignStack in inline call", .{}); 5266 }, 5267 } 5268 5269 const gop = try sema.mod.align_stack_fns.getOrPut(sema.mod.gpa, func); 5270 if (gop.found_existing) { 5271 const msg = msg: { 5272 const msg = try sema.errMsg(block, src, "multiple @setAlignStack in the same function body", .{}); 5273 errdefer msg.destroy(sema.gpa); 5274 try sema.errNote(block, gop.value_ptr.src, msg, "other instance here", .{}); 5275 break :msg msg; 5276 }; 5277 return sema.failWithOwnedErrorMsg(msg); 5278 } 5279 gop.value_ptr.* = .{ .alignment = alignment, .src = src }; 5280 } 5281 5282 fn zirSetCold(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5283 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 5284 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 5285 const is_cold = try sema.resolveConstBool(block, operand_src, inst_data.operand, "operand to @setCold must be comptime known"); 5286 const func = sema.func orelse return; // does nothing outside a function 5287 func.is_cold = is_cold; 5288 } 5289 5290 fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { 5291 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 5292 const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 5293 block.float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, "FloatMode", "operand to @setFloatMode must be comptime known"); 5294 } 5295 5296 fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5297 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 5298 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 5299 block.want_safety = try sema.resolveConstBool(block, operand_src, inst_data.operand, "operand to @setRuntimeSafety must be comptime known"); 5300 } 5301 5302 fn zirFence(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { 5303 if (block.is_comptime) return; 5304 5305 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 5306 const order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 5307 const order = try sema.resolveAtomicOrder(block, order_src, extra.operand, "atomic order of @fence must be comptime known"); 5308 5309 if (@enumToInt(order) < @enumToInt(std.builtin.AtomicOrder.Acquire)) { 5310 return sema.fail(block, order_src, "atomic ordering must be Acquire or stricter", .{}); 5311 } 5312 5313 _ = try block.addInst(.{ 5314 .tag = .fence, 5315 .data = .{ .fence = order }, 5316 }); 5317 } 5318 5319 fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { 5320 const tracy = trace(@src()); 5321 defer tracy.end(); 5322 5323 const inst_data = sema.code.instructions.items(.data)[inst].@"break"; 5324 const operand = try sema.resolveInst(inst_data.operand); 5325 const zir_block = inst_data.block_inst; 5326 5327 var block = start_block; 5328 while (true) { 5329 if (block.label) |label| { 5330 if (label.zir_block == zir_block) { 5331 const br_ref = try start_block.addBr(label.merges.block_inst, operand); 5332 try label.merges.results.append(sema.gpa, operand); 5333 try label.merges.br_list.append(sema.gpa, Air.refToIndex(br_ref).?); 5334 block.runtime_index.increment(); 5335 if (block.runtime_cond == null and block.runtime_loop == null) { 5336 block.runtime_cond = start_block.runtime_cond orelse start_block.runtime_loop; 5337 block.runtime_loop = start_block.runtime_loop; 5338 } 5339 return inst; 5340 } 5341 } 5342 block = block.parent.?; 5343 } 5344 } 5345 5346 fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5347 // We do not set sema.src here because dbg_stmt instructions are only emitted for 5348 // ZIR code that possibly will need to generate runtime code. So error messages 5349 // and other source locations must not rely on sema.src being set from dbg_stmt 5350 // instructions. 5351 if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; 5352 5353 const inst_data = sema.code.instructions.items(.data)[inst].dbg_stmt; 5354 _ = try block.addInst(.{ 5355 .tag = .dbg_stmt, 5356 .data = .{ .dbg_stmt = .{ 5357 .line = inst_data.line, 5358 .column = inst_data.column, 5359 } }, 5360 }); 5361 } 5362 5363 fn zirDbgBlockBegin(sema: *Sema, block: *Block) CompileError!void { 5364 if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; 5365 5366 _ = try block.addInst(.{ 5367 .tag = .dbg_block_begin, 5368 .data = undefined, 5369 }); 5370 } 5371 5372 fn zirDbgBlockEnd(sema: *Sema, block: *Block) CompileError!void { 5373 if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; 5374 5375 _ = try block.addInst(.{ 5376 .tag = .dbg_block_end, 5377 .data = undefined, 5378 }); 5379 } 5380 5381 fn zirDbgVar( 5382 sema: *Sema, 5383 block: *Block, 5384 inst: Zir.Inst.Index, 5385 air_tag: Air.Inst.Tag, 5386 ) CompileError!void { 5387 if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; 5388 5389 const str_op = sema.code.instructions.items(.data)[inst].str_op; 5390 const operand = try sema.resolveInst(str_op.operand); 5391 const name = str_op.getStr(sema.code); 5392 try sema.addDbgVar(block, operand, air_tag, name); 5393 } 5394 5395 fn addDbgVar( 5396 sema: *Sema, 5397 block: *Block, 5398 operand: Air.Inst.Ref, 5399 air_tag: Air.Inst.Tag, 5400 name: []const u8, 5401 ) CompileError!void { 5402 const operand_ty = sema.typeOf(operand); 5403 switch (air_tag) { 5404 .dbg_var_ptr => { 5405 if (!(try sema.typeHasRuntimeBits(block, sema.src, operand_ty.childType()))) return; 5406 }, 5407 .dbg_var_val => { 5408 if (!(try sema.typeHasRuntimeBits(block, sema.src, operand_ty))) return; 5409 }, 5410 else => unreachable, 5411 } 5412 5413 try sema.queueFullTypeResolution(operand_ty); 5414 5415 // Add the name to the AIR. 5416 const name_extra_index = @intCast(u32, sema.air_extra.items.len); 5417 const elements_used = name.len / 4 + 1; 5418 try sema.air_extra.ensureUnusedCapacity(sema.gpa, elements_used); 5419 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); 5420 mem.copy(u8, buffer, name); 5421 buffer[name.len] = 0; 5422 sema.air_extra.items.len += elements_used; 5423 5424 _ = try block.addInst(.{ 5425 .tag = air_tag, 5426 .data = .{ .pl_op = .{ 5427 .payload = name_extra_index, 5428 .operand = operand, 5429 } }, 5430 }); 5431 } 5432 5433 fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5434 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 5435 const src = inst_data.src(); 5436 const decl_name = inst_data.get(sema.code); 5437 const decl_index = try sema.lookupIdentifier(block, src, decl_name); 5438 try sema.addReferencedBy(block, src, decl_index); 5439 return sema.analyzeDeclRef(decl_index); 5440 } 5441 5442 fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5443 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 5444 const src = inst_data.src(); 5445 const decl_name = inst_data.get(sema.code); 5446 const decl = try sema.lookupIdentifier(block, src, decl_name); 5447 return sema.analyzeDeclVal(block, src, decl); 5448 } 5449 5450 fn lookupIdentifier(sema: *Sema, block: *Block, src: LazySrcLoc, name: []const u8) !Decl.Index { 5451 var namespace = block.namespace; 5452 while (true) { 5453 if (try sema.lookupInNamespace(block, src, namespace, name, false)) |decl_index| { 5454 return decl_index; 5455 } 5456 namespace = namespace.parent orelse break; 5457 } 5458 unreachable; // AstGen detects use of undeclared identifier errors. 5459 } 5460 5461 /// This looks up a member of a specific namespace. It is affected by `usingnamespace` but 5462 /// only for ones in the specified namespace. 5463 fn lookupInNamespace( 5464 sema: *Sema, 5465 block: *Block, 5466 src: LazySrcLoc, 5467 namespace: *Namespace, 5468 ident_name: []const u8, 5469 observe_usingnamespace: bool, 5470 ) CompileError!?Decl.Index { 5471 const mod = sema.mod; 5472 5473 const namespace_decl_index = namespace.getDeclIndex(); 5474 const namespace_decl = sema.mod.declPtr(namespace_decl_index); 5475 if (namespace_decl.analysis == .file_failure) { 5476 try mod.declareDeclDependency(sema.owner_decl_index, namespace_decl_index); 5477 return error.AnalysisFail; 5478 } 5479 5480 if (observe_usingnamespace and namespace.usingnamespace_set.count() != 0) { 5481 const src_file = block.namespace.file_scope; 5482 5483 const gpa = sema.gpa; 5484 var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Namespace, void) = .{}; 5485 defer checked_namespaces.deinit(gpa); 5486 5487 // Keep track of name conflicts for error notes. 5488 var candidates: std.ArrayListUnmanaged(Decl.Index) = .{}; 5489 defer candidates.deinit(gpa); 5490 5491 try checked_namespaces.put(gpa, namespace, {}); 5492 var check_i: usize = 0; 5493 5494 while (check_i < checked_namespaces.count()) : (check_i += 1) { 5495 const check_ns = checked_namespaces.keys()[check_i]; 5496 if (check_ns.decls.getKeyAdapted(ident_name, Module.DeclAdapter{ .mod = mod })) |decl_index| { 5497 // Skip decls which are not marked pub, which are in a different 5498 // file than the `a.b`/`@hasDecl` syntax. 5499 const decl = mod.declPtr(decl_index); 5500 if (decl.is_pub or src_file == decl.getFileScope()) { 5501 try candidates.append(gpa, decl_index); 5502 } 5503 } 5504 var it = check_ns.usingnamespace_set.iterator(); 5505 while (it.next()) |entry| { 5506 const sub_usingnamespace_decl_index = entry.key_ptr.*; 5507 // Skip the decl we're currently analysing. 5508 if (sub_usingnamespace_decl_index == sema.owner_decl_index) continue; 5509 const sub_usingnamespace_decl = mod.declPtr(sub_usingnamespace_decl_index); 5510 const sub_is_pub = entry.value_ptr.*; 5511 if (!sub_is_pub and src_file != sub_usingnamespace_decl.getFileScope()) { 5512 // Skip usingnamespace decls which are not marked pub, which are in 5513 // a different file than the `a.b`/`@hasDecl` syntax. 5514 continue; 5515 } 5516 try sema.ensureDeclAnalyzed(sub_usingnamespace_decl_index); 5517 const ns_ty = sub_usingnamespace_decl.val.castTag(.ty).?.data; 5518 const sub_ns = ns_ty.getNamespace().?; 5519 try checked_namespaces.put(gpa, sub_ns, {}); 5520 } 5521 } 5522 5523 { 5524 var i: usize = 0; 5525 while (i < candidates.items.len) { 5526 if (candidates.items[i] == sema.owner_decl_index) { 5527 _ = candidates.orderedRemove(i); 5528 } else { 5529 i += 1; 5530 } 5531 } 5532 } 5533 5534 switch (candidates.items.len) { 5535 0 => {}, 5536 1 => { 5537 const decl_index = candidates.items[0]; 5538 try mod.declareDeclDependency(sema.owner_decl_index, decl_index); 5539 return decl_index; 5540 }, 5541 else => { 5542 const msg = msg: { 5543 const msg = try sema.errMsg(block, src, "ambiguous reference", .{}); 5544 errdefer msg.destroy(gpa); 5545 for (candidates.items) |candidate_index| { 5546 const candidate = mod.declPtr(candidate_index); 5547 const src_loc = candidate.srcLoc(); 5548 try mod.errNoteNonLazy(src_loc, msg, "declared here", .{}); 5549 } 5550 break :msg msg; 5551 }; 5552 return sema.failWithOwnedErrorMsg(msg); 5553 }, 5554 } 5555 } else if (namespace.decls.getKeyAdapted(ident_name, Module.DeclAdapter{ .mod = mod })) |decl_index| { 5556 try mod.declareDeclDependency(sema.owner_decl_index, decl_index); 5557 return decl_index; 5558 } 5559 5560 log.debug("{*} ({s}) depends on non-existence of '{s}' in {*} ({s})", .{ 5561 sema.owner_decl, sema.owner_decl.name, ident_name, namespace_decl, namespace_decl.name, 5562 }); 5563 // TODO This dependency is too strong. Really, it should only be a dependency 5564 // on the non-existence of `ident_name` in the namespace. We can lessen the number of 5565 // outdated declarations by making this dependency more sophisticated. 5566 try mod.declareDeclDependency(sema.owner_decl_index, namespace_decl_index); 5567 return null; 5568 } 5569 5570 fn funcDeclSrc(sema: *Sema, block: *Block, src: LazySrcLoc, func_inst: Air.Inst.Ref) !?Module.SrcLoc { 5571 const func_val = (try sema.resolveMaybeUndefVal(block, src, func_inst)) orelse return null; 5572 if (func_val.isUndef()) return null; 5573 const owner_decl_index = switch (func_val.tag()) { 5574 .extern_fn => func_val.castTag(.extern_fn).?.data.owner_decl, 5575 .function => func_val.castTag(.function).?.data.owner_decl, 5576 .decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl, 5577 else => return null, 5578 }; 5579 const owner_decl = sema.mod.declPtr(owner_decl_index); 5580 return owner_decl.srcLoc(); 5581 } 5582 5583 fn zirCall( 5584 sema: *Sema, 5585 block: *Block, 5586 inst: Zir.Inst.Index, 5587 ) CompileError!Air.Inst.Ref { 5588 const tracy = trace(@src()); 5589 defer tracy.end(); 5590 5591 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 5592 const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node }; 5593 const call_src = inst_data.src(); 5594 const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index); 5595 const args_len = extra.data.flags.args_len; 5596 5597 const modifier = @intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier); 5598 const ensure_result_used = extra.data.flags.ensure_result_used; 5599 5600 var func = try sema.resolveInst(extra.data.callee); 5601 var resolved_args: []Air.Inst.Ref = undefined; 5602 var arg_index: u32 = 0; 5603 5604 const func_type = sema.typeOf(func); 5605 5606 // Desugar bound functions here 5607 var bound_arg_src: ?LazySrcLoc = null; 5608 if (func_type.tag() == .bound_fn) { 5609 bound_arg_src = func_src; 5610 const bound_func = try sema.resolveValue(block, .unneeded, func, undefined); 5611 const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data; 5612 func = bound_data.func_inst; 5613 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1); 5614 resolved_args[arg_index] = bound_data.arg0_inst; 5615 arg_index += 1; 5616 } else { 5617 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len); 5618 } 5619 const total_args = args_len + @boolToInt(bound_arg_src != null); 5620 5621 const callee_ty = sema.typeOf(func); 5622 const func_ty = func_ty: { 5623 switch (callee_ty.zigTypeTag()) { 5624 .Fn => break :func_ty callee_ty, 5625 .Pointer => { 5626 const ptr_info = callee_ty.ptrInfo().data; 5627 if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) { 5628 break :func_ty ptr_info.pointee_type; 5629 } 5630 }, 5631 else => {}, 5632 } 5633 return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)}); 5634 }; 5635 const func_ty_info = func_ty.fnInfo(); 5636 5637 const fn_params_len = func_ty_info.param_types.len; 5638 check_args: { 5639 if (func_ty_info.is_var_args) { 5640 assert(func_ty_info.cc == .C); 5641 if (total_args >= fn_params_len) break :check_args; 5642 } else if (fn_params_len == total_args) { 5643 break :check_args; 5644 } 5645 5646 const decl_src = try sema.funcDeclSrc(block, func_src, func); 5647 const member_str = if (bound_arg_src != null) "member function " else ""; 5648 const variadic_str = if (func_ty_info.is_var_args) "at least " else ""; 5649 const msg = msg: { 5650 const msg = try sema.errMsg( 5651 block, 5652 func_src, 5653 "{s}expected {s}{d} argument(s), found {d}", 5654 .{ 5655 member_str, 5656 variadic_str, 5657 fn_params_len - @boolToInt(bound_arg_src != null), 5658 args_len, 5659 }, 5660 ); 5661 errdefer msg.destroy(sema.gpa); 5662 5663 if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{}); 5664 break :msg msg; 5665 }; 5666 return sema.failWithOwnedErrorMsg(msg); 5667 } 5668 5669 const args_body = sema.code.extra[extra.end..]; 5670 5671 const parent_comptime = block.is_comptime; 5672 // `extra_index` and `arg_index` are separate since the bound function is passed as the first argument. 5673 var extra_index: usize = 0; 5674 var arg_start: u32 = args_len; 5675 while (extra_index < args_len) : ({ 5676 extra_index += 1; 5677 arg_index += 1; 5678 }) { 5679 const arg_end = sema.code.extra[extra.end + extra_index]; 5680 defer arg_start = arg_end; 5681 5682 const param_ty = if (arg_index >= fn_params_len or 5683 func_ty_info.param_types[arg_index].tag() == .generic_poison) 5684 Type.initTag(.var_args_param) 5685 else 5686 func_ty_info.param_types[arg_index]; 5687 5688 const old_comptime = block.is_comptime; 5689 defer block.is_comptime = old_comptime; 5690 // Generate args to comptime params in comptime block. 5691 block.is_comptime = parent_comptime; 5692 if (arg_index < fn_params_len and func_ty_info.comptime_params[arg_index]) { 5693 block.is_comptime = true; 5694 } 5695 5696 const param_ty_inst = try sema.addType(param_ty); 5697 try sema.inst_map.put(sema.gpa, inst, param_ty_inst); 5698 5699 const resolved = try sema.resolveBody(block, args_body[arg_start..arg_end], inst); 5700 if (sema.typeOf(resolved).zigTypeTag() == .NoReturn) { 5701 return resolved; 5702 } 5703 resolved_args[arg_index] = resolved; 5704 } 5705 5706 return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src); 5707 } 5708 5709 const GenericCallAdapter = struct { 5710 generic_fn: *Module.Fn, 5711 precomputed_hash: u64, 5712 func_ty_info: Type.Payload.Function.Data, 5713 args: []const Arg, 5714 module: *Module, 5715 5716 const Arg = struct { 5717 ty: Type, 5718 val: Value, 5719 is_anytype: bool, 5720 }; 5721 5722 pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool { 5723 _ = adapted_key; 5724 // Checking for equality may happen on an item that has been inserted 5725 // into the map but is not yet fully initialized. In such case, the 5726 // two initialized fields are `hash` and `generic_owner_decl`. 5727 if (ctx.generic_fn.owner_decl != other_key.generic_owner_decl.unwrap().?) return false; 5728 5729 const other_comptime_args = other_key.comptime_args.?; 5730 for (other_comptime_args[0..ctx.func_ty_info.param_types.len]) |other_arg, i| { 5731 const this_arg = ctx.args[i]; 5732 const this_is_comptime = this_arg.val.tag() != .generic_poison; 5733 const other_is_comptime = other_arg.val.tag() != .generic_poison; 5734 const this_is_anytype = this_arg.is_anytype; 5735 const other_is_anytype = other_key.isAnytypeParam(ctx.module, @intCast(u32, i)); 5736 5737 if (other_is_anytype != this_is_anytype) return false; 5738 if (other_is_comptime != this_is_comptime) return false; 5739 5740 if (this_is_anytype) { 5741 // Both are anytype parameters. 5742 if (!this_arg.ty.eql(other_arg.ty, ctx.module)) { 5743 return false; 5744 } 5745 if (this_is_comptime) { 5746 // Both are comptime and anytype parameters with matching types. 5747 if (!this_arg.val.eql(other_arg.val, other_arg.ty, ctx.module)) { 5748 return false; 5749 } 5750 } 5751 } else if (this_is_comptime) { 5752 // Both are comptime parameters but not anytype parameters. 5753 // We assert no error is possible here because any lazy values must be resolved 5754 // before inserting into the generic function hash map. 5755 const is_eql = Value.eqlAdvanced( 5756 this_arg.val, 5757 this_arg.ty, 5758 other_arg.val, 5759 other_arg.ty, 5760 ctx.module, 5761 null, 5762 ) catch unreachable; 5763 if (!is_eql) { 5764 return false; 5765 } 5766 } 5767 } 5768 return true; 5769 } 5770 5771 /// The implementation of the hash is in semantic analysis of function calls, so 5772 /// that any errors when computing the hash can be properly reported. 5773 pub fn hash(ctx: @This(), adapted_key: void) u64 { 5774 _ = adapted_key; 5775 return ctx.precomputed_hash; 5776 } 5777 }; 5778 5779 fn addComptimeReturnTypeNote( 5780 sema: *Sema, 5781 block: *Block, 5782 func: Air.Inst.Ref, 5783 func_src: LazySrcLoc, 5784 return_ty: Type, 5785 parent: *Module.ErrorMsg, 5786 requires_comptime: bool, 5787 ) !void { 5788 if (!requires_comptime) return; 5789 5790 const src_loc = if (try sema.funcDeclSrc(block, func_src, func)) |capture| blk: { 5791 var src_loc = capture; 5792 src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 }; 5793 break :blk src_loc; 5794 } else blk: { 5795 const src_decl = sema.mod.declPtr(block.src_decl); 5796 break :blk func_src.toSrcLoc(src_decl); 5797 }; 5798 if (return_ty.tag() == .generic_poison) { 5799 return sema.mod.errNoteNonLazy(src_loc, parent, "generic function is instantiated with a comptime only return type", .{}); 5800 } 5801 try sema.mod.errNoteNonLazy( 5802 src_loc, 5803 parent, 5804 "function is being called at comptime because it returns a comptime only type '{}'", 5805 .{return_ty.fmt(sema.mod)}, 5806 ); 5807 try sema.explainWhyTypeIsComptime(block, func_src, parent, src_loc, return_ty); 5808 } 5809 5810 fn analyzeCall( 5811 sema: *Sema, 5812 block: *Block, 5813 func: Air.Inst.Ref, 5814 func_src: LazySrcLoc, 5815 call_src: LazySrcLoc, 5816 modifier: std.builtin.CallOptions.Modifier, 5817 ensure_result_used: bool, 5818 uncasted_args: []const Air.Inst.Ref, 5819 bound_arg_src: ?LazySrcLoc, 5820 ) CompileError!Air.Inst.Ref { 5821 const mod = sema.mod; 5822 5823 const callee_ty = sema.typeOf(func); 5824 const func_ty = func_ty: { 5825 switch (callee_ty.zigTypeTag()) { 5826 .Fn => break :func_ty callee_ty, 5827 .Pointer => { 5828 const ptr_info = callee_ty.ptrInfo().data; 5829 if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) { 5830 break :func_ty ptr_info.pointee_type; 5831 } 5832 }, 5833 else => {}, 5834 } 5835 return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)}); 5836 }; 5837 5838 const func_ty_info = func_ty.fnInfo(); 5839 const cc = func_ty_info.cc; 5840 if (cc == .Naked) { 5841 const decl_src = try sema.funcDeclSrc(block, func_src, func); 5842 const msg = msg: { 5843 const msg = try sema.errMsg( 5844 block, 5845 func_src, 5846 "unable to call function with naked calling convention", 5847 .{}, 5848 ); 5849 errdefer msg.destroy(sema.gpa); 5850 5851 if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{}); 5852 break :msg msg; 5853 }; 5854 return sema.failWithOwnedErrorMsg(msg); 5855 } 5856 const fn_params_len = func_ty_info.param_types.len; 5857 if (func_ty_info.is_var_args) { 5858 assert(cc == .C); 5859 if (uncasted_args.len < fn_params_len) { 5860 // TODO add error note: declared here 5861 return sema.fail( 5862 block, 5863 func_src, 5864 "expected at least {d} argument(s), found {d}", 5865 .{ fn_params_len, uncasted_args.len }, 5866 ); 5867 } 5868 } else if (fn_params_len != uncasted_args.len) { 5869 // TODO add error note: declared here 5870 return sema.fail( 5871 block, 5872 call_src, 5873 "expected {d} argument(s), found {d}", 5874 .{ fn_params_len, uncasted_args.len }, 5875 ); 5876 } 5877 5878 const call_tag: Air.Inst.Tag = switch (modifier) { 5879 .auto, 5880 .always_inline, 5881 .compile_time, 5882 .no_async, 5883 => Air.Inst.Tag.call, 5884 5885 .never_tail => Air.Inst.Tag.call_never_tail, 5886 .never_inline => Air.Inst.Tag.call_never_inline, 5887 .always_tail => Air.Inst.Tag.call_always_tail, 5888 5889 .async_kw => return sema.failWithUseOfAsync(block, call_src), 5890 }; 5891 5892 if (modifier == .never_inline and func_ty_info.cc == .Inline) { 5893 return sema.fail(block, call_src, "no-inline call of inline function", .{}); 5894 } 5895 5896 const gpa = sema.gpa; 5897 5898 var is_generic_call = func_ty_info.is_generic; 5899 var is_comptime_call = block.is_comptime or modifier == .compile_time; 5900 var comptime_only_ret_ty = false; 5901 if (!is_comptime_call) { 5902 if (sema.typeRequiresComptime(func_ty_info.return_type)) |ct| { 5903 is_comptime_call = ct; 5904 comptime_only_ret_ty = ct; 5905 } else |err| switch (err) { 5906 error.GenericPoison => is_generic_call = true, 5907 else => |e| return e, 5908 } 5909 } 5910 var is_inline_call = is_comptime_call or modifier == .always_inline or 5911 func_ty_info.cc == .Inline; 5912 5913 if (!is_inline_call and is_generic_call) { 5914 if (sema.instantiateGenericCall( 5915 block, 5916 func, 5917 func_src, 5918 call_src, 5919 func_ty_info, 5920 ensure_result_used, 5921 uncasted_args, 5922 call_tag, 5923 bound_arg_src, 5924 )) |some| { 5925 return some; 5926 } else |err| switch (err) { 5927 error.GenericPoison => { 5928 is_inline_call = true; 5929 }, 5930 error.ComptimeReturn => { 5931 is_inline_call = true; 5932 is_comptime_call = true; 5933 comptime_only_ret_ty = true; 5934 }, 5935 else => |e| return e, 5936 } 5937 } 5938 5939 if (is_comptime_call and modifier == .never_inline) { 5940 return sema.fail(block, call_src, "unable to perform 'never_inline' call at compile-time", .{}); 5941 } 5942 5943 const result: Air.Inst.Ref = if (is_inline_call) res: { 5944 const func_val = sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime known") catch |err| { 5945 if (err == error.AnalysisFail and sema.err != null) { 5946 try sema.addComptimeReturnTypeNote(block, func, func_src, func_ty_info.return_type, sema.err.?, comptime_only_ret_ty); 5947 } 5948 return err; 5949 }; 5950 const module_fn = switch (func_val.tag()) { 5951 .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data, 5952 .function => func_val.castTag(.function).?.data, 5953 .extern_fn => return sema.fail(block, call_src, "{s} call of extern function", .{ 5954 @as([]const u8, if (is_comptime_call) "comptime" else "inline"), 5955 }), 5956 else => unreachable, 5957 }; 5958 5959 // Analyze the ZIR. The same ZIR gets analyzed into a runtime function 5960 // or an inlined call depending on what union tag the `label` field is 5961 // set to in the `Block`. 5962 // This block instruction will be used to capture the return value from the 5963 // inlined function. 5964 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 5965 try sema.air_instructions.append(gpa, .{ 5966 .tag = .block, 5967 .data = undefined, 5968 }); 5969 // This one is shared among sub-blocks within the same callee, but not 5970 // shared among the entire inline/comptime call stack. 5971 var inlining: Block.Inlining = .{ 5972 .comptime_result = undefined, 5973 .merges = .{ 5974 .results = .{}, 5975 .br_list = .{}, 5976 .block_inst = block_inst, 5977 }, 5978 }; 5979 // In order to save a bit of stack space, directly modify Sema rather 5980 // than create a child one. 5981 const parent_zir = sema.code; 5982 const fn_owner_decl = mod.declPtr(module_fn.owner_decl); 5983 sema.code = fn_owner_decl.getFileScope().zir; 5984 defer sema.code = parent_zir; 5985 5986 const parent_inst_map = sema.inst_map; 5987 sema.inst_map = .{}; 5988 defer { 5989 sema.inst_map.deinit(gpa); 5990 sema.inst_map = parent_inst_map; 5991 } 5992 5993 const parent_func = sema.func; 5994 sema.func = module_fn; 5995 defer sema.func = parent_func; 5996 5997 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, fn_owner_decl.src_scope); 5998 defer wip_captures.deinit(); 5999 6000 var child_block: Block = .{ 6001 .parent = null, 6002 .sema = sema, 6003 .src_decl = module_fn.owner_decl, 6004 .namespace = fn_owner_decl.src_namespace, 6005 .wip_capture_scope = wip_captures.scope, 6006 .instructions = .{}, 6007 .label = null, 6008 .inlining = &inlining, 6009 .is_comptime = is_comptime_call, 6010 }; 6011 6012 const merges = &child_block.inlining.?.merges; 6013 6014 defer child_block.instructions.deinit(gpa); 6015 defer merges.results.deinit(gpa); 6016 defer merges.br_list.deinit(gpa); 6017 6018 // If it's a comptime function call, we need to memoize it as long as no external 6019 // comptime memory is mutated. 6020 var memoized_call_key: Module.MemoizedCall.Key = undefined; 6021 var delete_memoized_call_key = false; 6022 defer if (delete_memoized_call_key) gpa.free(memoized_call_key.args); 6023 if (is_comptime_call) { 6024 memoized_call_key = .{ 6025 .func = module_fn, 6026 .args = try gpa.alloc(TypedValue, func_ty_info.param_types.len), 6027 }; 6028 delete_memoized_call_key = true; 6029 } 6030 6031 try sema.emitBackwardBranch(block, call_src); 6032 6033 // Whether this call should be memoized, set to false if the call can mutate 6034 // comptime state. 6035 var should_memoize = true; 6036 6037 var new_fn_info = fn_owner_decl.ty.fnInfo(); 6038 new_fn_info.param_types = try sema.arena.alloc(Type, new_fn_info.param_types.len); 6039 new_fn_info.comptime_params = (try sema.arena.alloc(bool, new_fn_info.param_types.len)).ptr; 6040 6041 // This will have return instructions analyzed as break instructions to 6042 // the block_inst above. Here we are performing "comptime/inline semantic analysis" 6043 // for a function body, which means we must map the parameter ZIR instructions to 6044 // the AIR instructions of the callsite. The callee could be a generic function 6045 // which means its parameter type expressions must be resolved in order and used 6046 // to successively coerce the arguments. 6047 const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst); 6048 var arg_i: usize = 0; 6049 for (fn_info.param_body) |inst| { 6050 sema.analyzeInlineCallArg( 6051 block, 6052 &child_block, 6053 .unneeded, 6054 inst, 6055 new_fn_info, 6056 &arg_i, 6057 uncasted_args, 6058 is_comptime_call, 6059 &should_memoize, 6060 memoized_call_key, 6061 // last 4 arguments are only used when reporting errors 6062 undefined, 6063 undefined, 6064 undefined, 6065 undefined, 6066 ) catch |err| switch (err) { 6067 error.NeededSourceLocation => { 6068 _ = sema.inst_map.remove(inst); 6069 const decl = sema.mod.declPtr(block.src_decl); 6070 try sema.analyzeInlineCallArg( 6071 block, 6072 &child_block, 6073 Module.argSrc(call_src.node_offset.x, sema.gpa, decl, arg_i, bound_arg_src), 6074 inst, 6075 new_fn_info, 6076 &arg_i, 6077 uncasted_args, 6078 is_comptime_call, 6079 &should_memoize, 6080 memoized_call_key, 6081 func, 6082 func_src, 6083 func_ty_info.return_type, 6084 comptime_only_ret_ty, 6085 ); 6086 return error.AnalysisFail; 6087 }, 6088 else => |e| return e, 6089 }; 6090 } 6091 6092 // In case it is a generic function with an expression for the return type that depends 6093 // on parameters, we must now do the same for the return type as we just did with 6094 // each of the parameters, resolving the return type and providing it to the child 6095 // `Sema` so that it can be used for the `ret_ptr` instruction. 6096 const ret_ty_inst = if (fn_info.ret_ty_body.len != 0) 6097 try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst) 6098 else 6099 try sema.resolveInst(fn_info.ret_ty_ref); 6100 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; 6101 const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst); 6102 // Create a fresh inferred error set type for inline/comptime calls. 6103 const fn_ret_ty = blk: { 6104 if (module_fn.hasInferredErrorSet(mod)) { 6105 const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode); 6106 node.data = .{ .func = module_fn }; 6107 if (parent_func) |some| { 6108 some.inferred_error_sets.prepend(node); 6109 } 6110 6111 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data); 6112 break :blk try Type.Tag.error_union.create(sema.arena, .{ 6113 .error_set = error_set_ty, 6114 .payload = bare_return_type, 6115 }); 6116 } 6117 break :blk bare_return_type; 6118 }; 6119 new_fn_info.return_type = fn_ret_ty; 6120 const parent_fn_ret_ty = sema.fn_ret_ty; 6121 sema.fn_ret_ty = fn_ret_ty; 6122 defer sema.fn_ret_ty = parent_fn_ret_ty; 6123 6124 // This `res2` is here instead of directly breaking from `res` due to a stage1 6125 // bug generating invalid LLVM IR. 6126 const res2: Air.Inst.Ref = res2: { 6127 if (should_memoize and is_comptime_call) { 6128 if (mod.memoized_calls.getContext(memoized_call_key, .{ .module = mod })) |result| { 6129 const ty_inst = try sema.addType(fn_ret_ty); 6130 try sema.air_values.append(gpa, result.val); 6131 sema.air_instructions.set(block_inst, .{ 6132 .tag = .constant, 6133 .data = .{ .ty_pl = .{ 6134 .ty = ty_inst, 6135 .payload = @intCast(u32, sema.air_values.items.len - 1), 6136 } }, 6137 }); 6138 break :res2 Air.indexToRef(block_inst); 6139 } 6140 } 6141 6142 const new_func_resolved_ty = try Type.Tag.function.create(sema.arena, new_fn_info); 6143 if (!is_comptime_call) { 6144 try sema.emitDbgInline(block, parent_func.?, module_fn, new_func_resolved_ty, .dbg_inline_begin); 6145 6146 const zir_tags = sema.code.instructions.items(.tag); 6147 for (fn_info.param_body) |param| switch (zir_tags[param]) { 6148 .param, .param_comptime => { 6149 const inst_data = sema.code.instructions.items(.data)[param].pl_tok; 6150 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index); 6151 const param_name = sema.code.nullTerminatedString(extra.data.name); 6152 const inst = sema.inst_map.get(param).?; 6153 6154 try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name); 6155 }, 6156 .param_anytype, .param_anytype_comptime => { 6157 const inst_data = sema.code.instructions.items(.data)[param].str_tok; 6158 const param_name = inst_data.get(sema.code); 6159 const inst = sema.inst_map.get(param).?; 6160 6161 try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name); 6162 }, 6163 else => continue, 6164 }; 6165 } 6166 6167 const result = result: { 6168 sema.analyzeBody(&child_block, fn_info.body) catch |err| switch (err) { 6169 error.ComptimeReturn => break :result inlining.comptime_result, 6170 error.AnalysisFail => { 6171 const err_msg = sema.err orelse return err; 6172 try sema.errNote(block, call_src, err_msg, "called from here", .{}); 6173 err_msg.clearTrace(sema.gpa); 6174 return err; 6175 }, 6176 else => |e| return e, 6177 }; 6178 break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges); 6179 }; 6180 6181 if (!is_comptime_call and sema.typeOf(result).zigTypeTag() != .NoReturn) { 6182 try sema.emitDbgInline( 6183 block, 6184 module_fn, 6185 parent_func.?, 6186 mod.declPtr(parent_func.?.owner_decl).ty, 6187 .dbg_inline_end, 6188 ); 6189 } 6190 6191 if (should_memoize and is_comptime_call) { 6192 const result_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, result, undefined); 6193 6194 // TODO: check whether any external comptime memory was mutated by the 6195 // comptime function call. If so, then do not memoize the call here. 6196 // TODO: re-evaluate whether memoized_calls needs its own arena. I think 6197 // it should be fine to use the Decl arena for the function. 6198 { 6199 var arena_allocator = std.heap.ArenaAllocator.init(gpa); 6200 errdefer arena_allocator.deinit(); 6201 const arena = arena_allocator.allocator(); 6202 6203 for (memoized_call_key.args) |*arg| { 6204 arg.* = try arg.*.copy(arena); 6205 } 6206 6207 try mod.memoized_calls.putContext(gpa, memoized_call_key, .{ 6208 .val = try result_val.copy(arena), 6209 .arena = arena_allocator.state, 6210 }, .{ .module = mod }); 6211 delete_memoized_call_key = false; 6212 } 6213 } 6214 6215 break :res2 result; 6216 }; 6217 6218 try wip_captures.finalize(); 6219 6220 break :res res2; 6221 } else res: { 6222 assert(!func_ty_info.is_generic); 6223 try sema.requireFunctionBlock(block, call_src); 6224 6225 const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len); 6226 for (uncasted_args) |uncasted_arg, i| { 6227 if (i < fn_params_len) { 6228 const param_ty = func_ty.fnParamType(i); 6229 args[i] = sema.analyzeCallArg( 6230 block, 6231 .unneeded, 6232 param_ty, 6233 uncasted_arg, 6234 ) catch |err| switch (err) { 6235 error.NeededSourceLocation => { 6236 const decl = sema.mod.declPtr(block.src_decl); 6237 _ = try sema.analyzeCallArg( 6238 block, 6239 Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src), 6240 param_ty, 6241 uncasted_arg, 6242 ); 6243 return error.AnalysisFail; 6244 }, 6245 else => |e| return e, 6246 }; 6247 } else { 6248 args[i] = sema.coerceVarArgParam(block, uncasted_arg, .unneeded) catch |err| switch (err) { 6249 error.NeededSourceLocation => { 6250 const decl = sema.mod.declPtr(block.src_decl); 6251 _ = try sema.coerceVarArgParam( 6252 block, 6253 uncasted_arg, 6254 Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src), 6255 ); 6256 return error.AnalysisFail; 6257 }, 6258 else => |e| return e, 6259 }; 6260 } 6261 } 6262 6263 try sema.queueFullTypeResolution(func_ty_info.return_type); 6264 if (sema.owner_func != null and func_ty_info.return_type.isError()) { 6265 sema.owner_func.?.calls_or_awaits_errorable_fn = true; 6266 } 6267 6268 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len + 6269 args.len); 6270 const func_inst = try block.addInst(.{ 6271 .tag = call_tag, 6272 .data = .{ .pl_op = .{ 6273 .operand = func, 6274 .payload = sema.addExtraAssumeCapacity(Air.Call{ 6275 .args_len = @intCast(u32, args.len), 6276 }), 6277 } }, 6278 }); 6279 sema.appendRefsAssumeCapacity(args); 6280 break :res func_inst; 6281 }; 6282 6283 if (ensure_result_used) { 6284 try sema.ensureResultUsed(block, result, call_src); 6285 } 6286 if (call_tag == .call_always_tail) { 6287 return sema.handleTailCall(block, call_src, func_ty, result); 6288 } 6289 return result; 6290 } 6291 6292 fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref { 6293 const target = sema.mod.getTarget(); 6294 const backend = sema.mod.comp.getZigBackend(); 6295 if (!target_util.supportsTailCall(target, backend)) { 6296 return sema.fail(block, call_src, "unable to perform tail call: compiler backend '{s}' does not support tail calls on target architecture '{s}' with the selected CPU feature flags", .{ 6297 @tagName(backend), @tagName(target.cpu.arch), 6298 }); 6299 } 6300 const func_decl = sema.mod.declPtr(sema.owner_func.?.owner_decl); 6301 if (!func_ty.eql(func_decl.ty, sema.mod)) { 6302 return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{ 6303 func_ty.fmt(sema.mod), func_decl.ty.fmt(sema.mod), 6304 }); 6305 } 6306 _ = try block.addUnOp(.ret, result); 6307 return Air.Inst.Ref.unreachable_value; 6308 } 6309 6310 fn analyzeInlineCallArg( 6311 sema: *Sema, 6312 arg_block: *Block, 6313 param_block: *Block, 6314 arg_src: LazySrcLoc, 6315 inst: Zir.Inst.Index, 6316 new_fn_info: Type.Payload.Function.Data, 6317 arg_i: *usize, 6318 uncasted_args: []const Air.Inst.Ref, 6319 is_comptime_call: bool, 6320 should_memoize: *bool, 6321 memoized_call_key: Module.MemoizedCall.Key, 6322 func: Air.Inst.Ref, 6323 func_src: LazySrcLoc, 6324 ret_ty: Type, 6325 comptime_only_ret_ty: bool, 6326 ) !void { 6327 const zir_tags = sema.code.instructions.items(.tag); 6328 switch (zir_tags[inst]) { 6329 .param, .param_comptime => { 6330 // Evaluate the parameter type expression now that previous ones have 6331 // been mapped, and coerce the corresponding argument to it. 6332 const pl_tok = sema.code.instructions.items(.data)[inst].pl_tok; 6333 const param_src = pl_tok.src(); 6334 const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index); 6335 const param_body = sema.code.extra[extra.end..][0..extra.data.body_len]; 6336 const param_ty_inst = try sema.resolveBody(param_block, param_body, inst); 6337 const param_ty = try sema.analyzeAsType(param_block, param_src, param_ty_inst); 6338 new_fn_info.param_types[arg_i.*] = param_ty; 6339 const uncasted_arg = uncasted_args[arg_i.*]; 6340 if (try sema.typeRequiresComptime(param_ty)) { 6341 _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime only type must be comptime known") catch |err| { 6342 if (err == error.AnalysisFail and sema.err != null) { 6343 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty); 6344 } 6345 return err; 6346 }; 6347 } 6348 const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src); 6349 try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg); 6350 6351 if (is_comptime_call) { 6352 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known") catch |err| { 6353 if (err == error.AnalysisFail and sema.err != null) { 6354 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty); 6355 } 6356 return err; 6357 }; 6358 switch (arg_val.tag()) { 6359 .generic_poison, .generic_poison_type => { 6360 // This function is currently evaluated as part of an as-of-yet unresolvable 6361 // parameter or return type. 6362 return error.GenericPoison; 6363 }, 6364 else => { 6365 // Needed so that lazy values do not trigger 6366 // assertion due to type not being resolved 6367 // when the hash function is called. 6368 try sema.resolveLazyValue(arg_block, arg_src, arg_val); 6369 }, 6370 } 6371 should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(); 6372 memoized_call_key.args[arg_i.*] = .{ 6373 .ty = param_ty, 6374 .val = arg_val, 6375 }; 6376 } 6377 6378 arg_i.* += 1; 6379 }, 6380 .param_anytype, .param_anytype_comptime => { 6381 // No coercion needed. 6382 const uncasted_arg = uncasted_args[arg_i.*]; 6383 new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg); 6384 try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg); 6385 6386 if (is_comptime_call) { 6387 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known") catch |err| { 6388 if (err == error.AnalysisFail and sema.err != null) { 6389 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty); 6390 } 6391 return err; 6392 }; 6393 switch (arg_val.tag()) { 6394 .generic_poison, .generic_poison_type => { 6395 // This function is currently evaluated as part of an as-of-yet unresolvable 6396 // parameter or return type. 6397 return error.GenericPoison; 6398 }, 6399 else => { 6400 // Needed so that lazy values do not trigger 6401 // assertion due to type not being resolved 6402 // when the hash function is called. 6403 try sema.resolveLazyValue(arg_block, arg_src, arg_val); 6404 }, 6405 } 6406 should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(); 6407 memoized_call_key.args[arg_i.*] = .{ 6408 .ty = sema.typeOf(uncasted_arg), 6409 .val = arg_val, 6410 }; 6411 } 6412 6413 arg_i.* += 1; 6414 }, 6415 else => {}, 6416 } 6417 } 6418 6419 fn analyzeCallArg( 6420 sema: *Sema, 6421 block: *Block, 6422 arg_src: LazySrcLoc, 6423 param_ty: Type, 6424 uncasted_arg: Air.Inst.Ref, 6425 ) !Air.Inst.Ref { 6426 try sema.resolveTypeFully(block, arg_src, param_ty); 6427 return sema.coerce(block, param_ty, uncasted_arg, arg_src); 6428 } 6429 6430 fn analyzeGenericCallArg( 6431 sema: *Sema, 6432 block: *Block, 6433 arg_src: LazySrcLoc, 6434 uncasted_arg: Air.Inst.Ref, 6435 comptime_arg: TypedValue, 6436 runtime_args: []Air.Inst.Ref, 6437 new_fn_info: Type.Payload.Function.Data, 6438 runtime_i: *u32, 6439 ) !void { 6440 const is_runtime = comptime_arg.val.tag() == .generic_poison and 6441 comptime_arg.ty.hasRuntimeBits() and 6442 !(try sema.typeRequiresComptime(comptime_arg.ty)); 6443 if (is_runtime) { 6444 const param_ty = new_fn_info.param_types[runtime_i.*]; 6445 const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src); 6446 try sema.queueFullTypeResolution(param_ty); 6447 runtime_args[runtime_i.*] = casted_arg; 6448 runtime_i.* += 1; 6449 } 6450 } 6451 6452 fn analyzeGenericCallArgVal(sema: *Sema, block: *Block, arg_src: LazySrcLoc, uncasted_arg: Air.Inst.Ref) !Value { 6453 const arg_val = try sema.resolveValue(block, arg_src, uncasted_arg, "parameter is comptime"); 6454 try sema.resolveLazyValue(block, arg_src, arg_val); 6455 return arg_val; 6456 } 6457 6458 fn instantiateGenericCall( 6459 sema: *Sema, 6460 block: *Block, 6461 func: Air.Inst.Ref, 6462 func_src: LazySrcLoc, 6463 call_src: LazySrcLoc, 6464 func_ty_info: Type.Payload.Function.Data, 6465 ensure_result_used: bool, 6466 uncasted_args: []const Air.Inst.Ref, 6467 call_tag: Air.Inst.Tag, 6468 bound_arg_src: ?LazySrcLoc, 6469 ) CompileError!Air.Inst.Ref { 6470 const mod = sema.mod; 6471 const gpa = sema.gpa; 6472 6473 const func_val = try sema.resolveConstValue(block, func_src, func, "generic function being called must be comptime known"); 6474 const module_fn = switch (func_val.tag()) { 6475 .function => func_val.castTag(.function).?.data, 6476 .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data, 6477 else => unreachable, 6478 }; 6479 // Check the Module's generic function map with an adapted context, so that we 6480 // can match against `uncasted_args` rather than doing the work below to create a 6481 // generic Scope only to junk it if it matches an existing instantiation. 6482 const fn_owner_decl = mod.declPtr(module_fn.owner_decl); 6483 const namespace = fn_owner_decl.src_namespace; 6484 const fn_zir = namespace.file_scope.zir; 6485 const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); 6486 const zir_tags = fn_zir.instructions.items(.tag); 6487 6488 // This hash must match `Module.MonomorphedFuncsContext.hash`. 6489 // For parameters explicitly marked comptime and simple parameter type expressions, 6490 // we know whether a parameter is elided from a monomorphed function, and can 6491 // use it in the hash here. However, for parameter type expressions that are not 6492 // explicitly marked comptime and rely on previous parameter comptime values, we 6493 // don't find out until after generating a monomorphed function whether the parameter 6494 // type ended up being a "must-be-comptime-known" type. 6495 var hasher = std.hash.Wyhash.init(0); 6496 std.hash.autoHash(&hasher, @ptrToInt(module_fn)); 6497 6498 const generic_args = try sema.arena.alloc(GenericCallAdapter.Arg, func_ty_info.param_types.len); 6499 { 6500 var i: usize = 0; 6501 for (fn_info.param_body) |inst| { 6502 var is_comptime = false; 6503 var is_anytype = false; 6504 switch (zir_tags[inst]) { 6505 .param => { 6506 is_comptime = func_ty_info.paramIsComptime(i); 6507 }, 6508 .param_comptime => { 6509 is_comptime = true; 6510 }, 6511 .param_anytype => { 6512 is_anytype = true; 6513 is_comptime = func_ty_info.paramIsComptime(i); 6514 }, 6515 .param_anytype_comptime => { 6516 is_anytype = true; 6517 is_comptime = true; 6518 }, 6519 else => continue, 6520 } 6521 6522 const arg_ty = sema.typeOf(uncasted_args[i]); 6523 6524 if (is_comptime) { 6525 const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[i]) catch |err| switch (err) { 6526 error.NeededSourceLocation => { 6527 const decl = sema.mod.declPtr(block.src_decl); 6528 const arg_src = Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src); 6529 _ = try sema.analyzeGenericCallArgVal(block, arg_src, uncasted_args[i]); 6530 return error.AnalysisFail; 6531 }, 6532 else => |e| return e, 6533 }; 6534 arg_val.hash(arg_ty, &hasher, mod); 6535 if (is_anytype) { 6536 arg_ty.hashWithHasher(&hasher, mod); 6537 generic_args[i] = .{ 6538 .ty = arg_ty, 6539 .val = arg_val, 6540 .is_anytype = true, 6541 }; 6542 } else { 6543 generic_args[i] = .{ 6544 .ty = arg_ty, 6545 .val = arg_val, 6546 .is_anytype = false, 6547 }; 6548 } 6549 } else if (is_anytype) { 6550 arg_ty.hashWithHasher(&hasher, mod); 6551 generic_args[i] = .{ 6552 .ty = arg_ty, 6553 .val = Value.initTag(.generic_poison), 6554 .is_anytype = true, 6555 }; 6556 } else { 6557 generic_args[i] = .{ 6558 .ty = arg_ty, 6559 .val = Value.initTag(.generic_poison), 6560 .is_anytype = false, 6561 }; 6562 } 6563 6564 i += 1; 6565 } 6566 } 6567 6568 const precomputed_hash = hasher.final(); 6569 6570 const adapter: GenericCallAdapter = .{ 6571 .generic_fn = module_fn, 6572 .precomputed_hash = precomputed_hash, 6573 .func_ty_info = func_ty_info, 6574 .args = generic_args, 6575 .module = mod, 6576 }; 6577 const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter); 6578 const callee = if (!gop.found_existing) callee: { 6579 const new_module_func = try gpa.create(Module.Fn); 6580 errdefer gpa.destroy(new_module_func); 6581 6582 // This ensures that we can operate on the hash map before the Module.Fn 6583 // struct is fully initialized. 6584 new_module_func.hash = precomputed_hash; 6585 new_module_func.generic_owner_decl = module_fn.owner_decl.toOptional(); 6586 new_module_func.comptime_args = null; 6587 gop.key_ptr.* = new_module_func; 6588 errdefer assert(mod.monomorphed_funcs.remove(new_module_func)); 6589 6590 try namespace.anon_decls.ensureUnusedCapacity(gpa, 1); 6591 6592 // Create a Decl for the new function. 6593 const src_decl_index = namespace.getDeclIndex(); 6594 const src_decl = mod.declPtr(src_decl_index); 6595 const new_decl_index = try mod.allocateNewDecl(namespace, fn_owner_decl.src_node, src_decl.src_scope); 6596 errdefer mod.destroyDecl(new_decl_index); 6597 const new_decl = mod.declPtr(new_decl_index); 6598 // TODO better names for generic function instantiations 6599 const decl_name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{ 6600 fn_owner_decl.name, @enumToInt(new_decl_index), 6601 }); 6602 new_decl.name = decl_name; 6603 new_decl.src_line = fn_owner_decl.src_line; 6604 new_decl.is_pub = fn_owner_decl.is_pub; 6605 new_decl.is_exported = fn_owner_decl.is_exported; 6606 new_decl.has_align = fn_owner_decl.has_align; 6607 new_decl.has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace; 6608 new_decl.@"linksection" = fn_owner_decl.@"linksection"; 6609 new_decl.@"addrspace" = fn_owner_decl.@"addrspace"; 6610 new_decl.zir_decl_index = fn_owner_decl.zir_decl_index; 6611 new_decl.alive = true; // This Decl is called at runtime. 6612 new_decl.analysis = .in_progress; 6613 new_decl.generation = mod.generation; 6614 6615 namespace.anon_decls.putAssumeCapacityNoClobber(new_decl_index, {}); 6616 errdefer assert(namespace.anon_decls.orderedRemove(new_decl_index)); 6617 6618 // The generic function Decl is guaranteed to be the first dependency 6619 // of each of its instantiations. 6620 assert(new_decl.dependencies.keys().len == 0); 6621 try mod.declareDeclDependency(new_decl_index, module_fn.owner_decl); 6622 // Resolving the new function type below will possibly declare more decl dependencies 6623 // and so we remove them all here in case of error. 6624 errdefer { 6625 for (new_decl.dependencies.keys()) |dep_index| { 6626 const dep = mod.declPtr(dep_index); 6627 dep.removeDependant(new_decl_index); 6628 } 6629 } 6630 6631 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); 6632 errdefer new_decl_arena.deinit(); 6633 const new_decl_arena_allocator = new_decl_arena.allocator(); 6634 6635 // Re-run the block that creates the function, with the comptime parameters 6636 // pre-populated inside `inst_map`. This causes `param_comptime` and 6637 // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a 6638 // new, monomorphized function, with the comptime parameters elided. 6639 var child_sema: Sema = .{ 6640 .mod = mod, 6641 .gpa = gpa, 6642 .arena = sema.arena, 6643 .perm_arena = new_decl_arena_allocator, 6644 .code = fn_zir, 6645 .owner_decl = new_decl, 6646 .owner_decl_index = new_decl_index, 6647 .func = null, 6648 .fn_ret_ty = Type.void, 6649 .owner_func = null, 6650 .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len), 6651 .comptime_args_fn_inst = module_fn.zir_body_inst, 6652 .preallocated_new_func = new_module_func, 6653 .is_generic_instantiation = true, 6654 }; 6655 defer child_sema.deinit(); 6656 6657 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope); 6658 defer wip_captures.deinit(); 6659 6660 var child_block: Block = .{ 6661 .parent = null, 6662 .sema = &child_sema, 6663 .src_decl = new_decl_index, 6664 .namespace = namespace, 6665 .wip_capture_scope = wip_captures.scope, 6666 .instructions = .{}, 6667 .inlining = null, 6668 .is_comptime = true, 6669 }; 6670 defer { 6671 child_block.instructions.deinit(gpa); 6672 child_block.params.deinit(gpa); 6673 } 6674 6675 try child_sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, uncasted_args.len)); 6676 var arg_i: usize = 0; 6677 for (fn_info.param_body) |inst| { 6678 var is_comptime = false; 6679 var is_anytype = false; 6680 switch (zir_tags[inst]) { 6681 .param => { 6682 is_comptime = func_ty_info.paramIsComptime(arg_i); 6683 }, 6684 .param_comptime => { 6685 is_comptime = true; 6686 }, 6687 .param_anytype => { 6688 is_anytype = true; 6689 is_comptime = func_ty_info.paramIsComptime(arg_i); 6690 }, 6691 .param_anytype_comptime => { 6692 is_anytype = true; 6693 is_comptime = true; 6694 }, 6695 else => continue, 6696 } 6697 const arg = uncasted_args[arg_i]; 6698 if (is_comptime) { 6699 if (try sema.resolveMaybeUndefVal(block, .unneeded, arg)) |arg_val| { 6700 const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val); 6701 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); 6702 } else { 6703 return sema.failWithNeededComptime(block, .unneeded, undefined); 6704 } 6705 } else if (is_anytype) { 6706 const arg_ty = sema.typeOf(arg); 6707 if (try sema.typeRequiresComptime(arg_ty)) { 6708 const arg_val = try sema.resolveConstValue(block, .unneeded, arg, undefined); 6709 const child_arg = try child_sema.addConstant(arg_ty, arg_val); 6710 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); 6711 } else { 6712 // We insert into the map an instruction which is runtime-known 6713 // but has the type of the argument. 6714 const child_arg = try child_block.addArg(arg_ty); 6715 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); 6716 } 6717 } 6718 arg_i += 1; 6719 } 6720 const new_func_inst = child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst) catch |err| { 6721 // TODO look up the compile error that happened here and attach a note to it 6722 // pointing here, at the generic instantiation callsite. 6723 if (sema.owner_func) |owner_func| { 6724 owner_func.state = .dependency_failure; 6725 } else { 6726 sema.owner_decl.analysis = .dependency_failure; 6727 } 6728 return err; 6729 }; 6730 const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst, undefined) catch unreachable; 6731 const new_func = new_func_val.castTag(.function).?.data; 6732 errdefer new_func.deinit(gpa); 6733 assert(new_func == new_module_func); 6734 6735 arg_i = 0; 6736 for (fn_info.param_body) |inst| { 6737 var is_comptime = false; 6738 switch (zir_tags[inst]) { 6739 .param => { 6740 is_comptime = func_ty_info.paramIsComptime(arg_i); 6741 }, 6742 .param_comptime => { 6743 is_comptime = true; 6744 }, 6745 .param_anytype => { 6746 is_comptime = func_ty_info.paramIsComptime(arg_i); 6747 }, 6748 .param_anytype_comptime => { 6749 is_comptime = true; 6750 }, 6751 else => continue, 6752 } 6753 6754 // We populate the Type here regardless because it is needed by 6755 // `GenericCallAdapter.eql` as well as function body analysis. 6756 // Whether it is anytype is communicated by `isAnytypeParam`. 6757 const arg = child_sema.inst_map.get(inst).?; 6758 const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator); 6759 6760 if (try sema.typeRequiresComptime(copied_arg_ty)) { 6761 is_comptime = true; 6762 } 6763 6764 if (is_comptime) { 6765 const arg_val = (child_sema.resolveMaybeUndefValAllowVariables( 6766 &child_block, 6767 .unneeded, 6768 arg, 6769 ) catch unreachable).?; 6770 child_sema.comptime_args[arg_i] = .{ 6771 .ty = copied_arg_ty, 6772 .val = try arg_val.copy(new_decl_arena_allocator), 6773 }; 6774 } else { 6775 child_sema.comptime_args[arg_i] = .{ 6776 .ty = copied_arg_ty, 6777 .val = Value.initTag(.generic_poison), 6778 }; 6779 } 6780 6781 arg_i += 1; 6782 } 6783 6784 try wip_captures.finalize(); 6785 6786 // Populate the Decl ty/val with the function and its type. 6787 new_decl.ty = try child_sema.typeOf(new_func_inst).copy(new_decl_arena_allocator); 6788 // If the call evaluated to a return type that requires comptime, never mind 6789 // our generic instantiation. Instead we need to perform a comptime call. 6790 const new_fn_info = new_decl.ty.fnInfo(); 6791 if (try sema.typeRequiresComptime(new_fn_info.return_type)) { 6792 return error.ComptimeReturn; 6793 } 6794 // Similarly, if the call evaluated to a generic type we need to instead 6795 // call it inline. 6796 if (new_fn_info.is_generic or new_fn_info.cc == .Inline) { 6797 return error.GenericPoison; 6798 } 6799 6800 new_decl.val = try Value.Tag.function.create(new_decl_arena_allocator, new_func); 6801 new_decl.@"align" = 0; 6802 new_decl.has_tv = true; 6803 new_decl.owns_tv = true; 6804 new_decl.analysis = .complete; 6805 6806 log.debug("generic function '{s}' instantiated with type {}", .{ 6807 new_decl.name, new_decl.ty.fmtDebug(), 6808 }); 6809 6810 // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field 6811 // will be populated, ensuring it will have `analyzeBody` called with the ZIR 6812 // parameters mapped appropriately. 6813 try mod.comp.bin_file.allocateDeclIndexes(new_decl_index); 6814 try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func }); 6815 6816 try new_decl.finalizeNewArena(&new_decl_arena); 6817 break :callee new_func; 6818 } else gop.key_ptr.*; 6819 6820 callee.branch_quota = @maximum(callee.branch_quota, sema.branch_quota); 6821 6822 const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl); 6823 6824 // Make a runtime call to the new function, making sure to omit the comptime args. 6825 try sema.requireFunctionBlock(block, call_src); 6826 6827 const comptime_args = callee.comptime_args.?; 6828 const func_ty = mod.declPtr(callee.owner_decl).ty; 6829 const new_fn_info = func_ty.fnInfo(); 6830 const runtime_args_len = @intCast(u32, new_fn_info.param_types.len); 6831 const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len); 6832 { 6833 var runtime_i: u32 = 0; 6834 var total_i: u32 = 0; 6835 for (fn_info.param_body) |inst| { 6836 switch (zir_tags[inst]) { 6837 .param_comptime, .param_anytype_comptime, .param, .param_anytype => {}, 6838 else => continue, 6839 } 6840 sema.analyzeGenericCallArg( 6841 block, 6842 .unneeded, 6843 uncasted_args[total_i], 6844 comptime_args[total_i], 6845 runtime_args, 6846 new_fn_info, 6847 &runtime_i, 6848 ) catch |err| switch (err) { 6849 error.NeededSourceLocation => { 6850 const decl = sema.mod.declPtr(block.src_decl); 6851 _ = try sema.analyzeGenericCallArg( 6852 block, 6853 Module.argSrc(call_src.node_offset.x, sema.gpa, decl, total_i, bound_arg_src), 6854 uncasted_args[total_i], 6855 comptime_args[total_i], 6856 runtime_args, 6857 new_fn_info, 6858 &runtime_i, 6859 ); 6860 return error.AnalysisFail; 6861 }, 6862 else => |e| return e, 6863 }; 6864 total_i += 1; 6865 } 6866 6867 try sema.queueFullTypeResolution(new_fn_info.return_type); 6868 } 6869 6870 if (sema.owner_func != null and new_fn_info.return_type.isError()) { 6871 sema.owner_func.?.calls_or_awaits_errorable_fn = true; 6872 } 6873 6874 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + 6875 runtime_args_len); 6876 const result = try block.addInst(.{ 6877 .tag = call_tag, 6878 .data = .{ .pl_op = .{ 6879 .operand = callee_inst, 6880 .payload = sema.addExtraAssumeCapacity(Air.Call{ 6881 .args_len = runtime_args_len, 6882 }), 6883 } }, 6884 }); 6885 sema.appendRefsAssumeCapacity(runtime_args); 6886 6887 if (ensure_result_used) { 6888 try sema.ensureResultUsed(block, result, call_src); 6889 } 6890 if (call_tag == .call_always_tail) { 6891 return sema.handleTailCall(block, call_src, func_ty, result); 6892 } 6893 return result; 6894 } 6895 6896 fn emitDbgInline( 6897 sema: *Sema, 6898 block: *Block, 6899 old_func: *Module.Fn, 6900 new_func: *Module.Fn, 6901 new_func_ty: Type, 6902 tag: Air.Inst.Tag, 6903 ) CompileError!void { 6904 if (sema.mod.comp.bin_file.options.strip) return; 6905 6906 // Recursive inline call; no dbg_inline needed. 6907 if (old_func == new_func) return; 6908 6909 try sema.air_values.append(sema.gpa, try Value.Tag.function.create(sema.arena, new_func)); 6910 _ = try block.addInst(.{ 6911 .tag = tag, 6912 .data = .{ .ty_pl = .{ 6913 .ty = try sema.addType(new_func_ty), 6914 .payload = @intCast(u32, sema.air_values.items.len - 1), 6915 } }, 6916 }); 6917 } 6918 6919 fn zirIntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 6920 _ = block; 6921 const tracy = trace(@src()); 6922 defer tracy.end(); 6923 6924 const int_type = sema.code.instructions.items(.data)[inst].int_type; 6925 const ty = try Module.makeIntType(sema.arena, int_type.signedness, int_type.bit_count); 6926 6927 return sema.addType(ty); 6928 } 6929 6930 fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 6931 const tracy = trace(@src()); 6932 defer tracy.end(); 6933 6934 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 6935 const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; 6936 const child_type = try sema.resolveType(block, operand_src, inst_data.operand); 6937 if (child_type.zigTypeTag() == .Opaque) { 6938 return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(sema.mod)}); 6939 } else if (child_type.zigTypeTag() == .Null) { 6940 return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(sema.mod)}); 6941 } 6942 const opt_type = try Type.optional(sema.arena, child_type); 6943 6944 return sema.addType(opt_type); 6945 } 6946 6947 fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 6948 const bin = sema.code.instructions.items(.data)[inst].bin; 6949 const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs); 6950 assert(indexable_ty.isIndexable()); // validated by a previous instruction 6951 if (indexable_ty.zigTypeTag() == .Struct) { 6952 const elem_type = indexable_ty.tupleFields().types[@enumToInt(bin.rhs)]; 6953 return sema.addType(elem_type); 6954 } else { 6955 const elem_type = indexable_ty.elemType2(); 6956 return sema.addType(elem_type); 6957 } 6958 } 6959 6960 fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 6961 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 6962 const elem_type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 6963 const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 6964 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 6965 const len = try sema.resolveInt(block, len_src, extra.lhs, Type.u32, "vector length must be comptime known"); 6966 const elem_type = try sema.resolveType(block, elem_type_src, extra.rhs); 6967 try sema.checkVectorElemType(block, elem_type_src, elem_type); 6968 const vector_type = try Type.Tag.vector.create(sema.arena, .{ 6969 .len = @intCast(u32, len), 6970 .elem_type = elem_type, 6971 }); 6972 return sema.addType(vector_type); 6973 } 6974 6975 fn zirArrayType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 6976 const tracy = trace(@src()); 6977 defer tracy.end(); 6978 6979 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 6980 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 6981 const len_src: LazySrcLoc = .{ .node_offset_array_type_len = inst_data.src_node }; 6982 const elem_src: LazySrcLoc = .{ .node_offset_array_type_elem = inst_data.src_node }; 6983 const len = try sema.resolveInt(block, len_src, extra.lhs, Type.usize, "array length must be comptime known"); 6984 const elem_type = try sema.resolveType(block, elem_src, extra.rhs); 6985 const array_ty = try Type.array(sema.arena, len, null, elem_type, sema.mod); 6986 6987 return sema.addType(array_ty); 6988 } 6989 6990 fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 6991 const tracy = trace(@src()); 6992 defer tracy.end(); 6993 6994 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 6995 const extra = sema.code.extraData(Zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data; 6996 const len_src: LazySrcLoc = .{ .node_offset_array_type_len = inst_data.src_node }; 6997 const sentinel_src: LazySrcLoc = .{ .node_offset_array_type_sentinel = inst_data.src_node }; 6998 const elem_src: LazySrcLoc = .{ .node_offset_array_type_elem = inst_data.src_node }; 6999 const len = try sema.resolveInt(block, len_src, extra.len, Type.usize, "array length must be comptime known"); 7000 const elem_type = try sema.resolveType(block, elem_src, extra.elem_type); 7001 const uncasted_sentinel = try sema.resolveInst(extra.sentinel); 7002 const sentinel = try sema.coerce(block, elem_type, uncasted_sentinel, sentinel_src); 7003 const sentinel_val = try sema.resolveConstValue(block, sentinel_src, sentinel, "array sentinel value must be comptime known"); 7004 const array_ty = try Type.array(sema.arena, len, sentinel_val, elem_type, sema.mod); 7005 7006 return sema.addType(array_ty); 7007 } 7008 7009 fn zirAnyframeType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7010 const tracy = trace(@src()); 7011 defer tracy.end(); 7012 7013 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 7014 if (true) { 7015 return sema.failWithUseOfAsync(block, inst_data.src()); 7016 } 7017 const operand_src: LazySrcLoc = .{ .node_offset_anyframe_type = inst_data.src_node }; 7018 const return_type = try sema.resolveType(block, operand_src, inst_data.operand); 7019 const anyframe_type = try Type.Tag.anyframe_T.create(sema.arena, return_type); 7020 7021 return sema.addType(anyframe_type); 7022 } 7023 7024 fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7025 const tracy = trace(@src()); 7026 defer tracy.end(); 7027 7028 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 7029 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 7030 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 7031 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 7032 const error_set = try sema.resolveType(block, lhs_src, extra.lhs); 7033 const payload = try sema.resolveType(block, rhs_src, extra.rhs); 7034 7035 if (error_set.zigTypeTag() != .ErrorSet) { 7036 return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{ 7037 error_set.fmt(sema.mod), 7038 }); 7039 } 7040 if (payload.zigTypeTag() == .Opaque) { 7041 return sema.fail(block, rhs_src, "error union with payload of opaque type '{}' not allowed", .{ 7042 payload.fmt(sema.mod), 7043 }); 7044 } else if (payload.zigTypeTag() == .ErrorSet) { 7045 return sema.fail(block, rhs_src, "error union with payload of error set type '{}' not allowed", .{ 7046 payload.fmt(sema.mod), 7047 }); 7048 } 7049 const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod); 7050 return sema.addType(err_union_ty); 7051 } 7052 7053 fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7054 _ = block; 7055 const tracy = trace(@src()); 7056 defer tracy.end(); 7057 7058 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 7059 7060 // Create an anonymous error set type with only this error value, and return the value. 7061 const kv = try sema.mod.getErrorValue(inst_data.get(sema.code)); 7062 const result_type = try Type.Tag.error_set_single.create(sema.arena, kv.key); 7063 return sema.addConstant( 7064 result_type, 7065 try Value.Tag.@"error".create(sema.arena, .{ 7066 .name = kv.key, 7067 }), 7068 ); 7069 } 7070 7071 fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 7072 const tracy = trace(@src()); 7073 defer tracy.end(); 7074 7075 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 7076 const src = LazySrcLoc.nodeOffset(extra.node); 7077 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 7078 const uncasted_operand = try sema.resolveInst(extra.operand); 7079 const operand = try sema.coerce(block, Type.anyerror, uncasted_operand, operand_src); 7080 7081 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| { 7082 if (val.isUndef()) { 7083 return sema.addConstUndef(Type.err_int); 7084 } 7085 switch (val.tag()) { 7086 .@"error" => { 7087 const payload = try sema.arena.create(Value.Payload.U64); 7088 payload.* = .{ 7089 .base = .{ .tag = .int_u64 }, 7090 .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value, 7091 }; 7092 return sema.addConstant(Type.err_int, Value.initPayload(&payload.base)); 7093 }, 7094 7095 // This is not a valid combination with the type `anyerror`. 7096 .the_only_possible_value => unreachable, 7097 7098 // Assume it's already encoded as an integer. 7099 else => return sema.addConstant(Type.err_int, val), 7100 } 7101 } 7102 7103 const op_ty = sema.typeOf(uncasted_operand); 7104 try sema.resolveInferredErrorSetTy(block, src, op_ty); 7105 if (!op_ty.isAnyError()) { 7106 const names = op_ty.errorSetNames(); 7107 switch (names.len) { 7108 0 => return sema.addConstant(Type.err_int, Value.zero), 7109 1 => return sema.addIntUnsigned(Type.err_int, sema.mod.global_error_set.get(names[0]).?), 7110 else => {}, 7111 } 7112 } 7113 7114 try sema.requireRuntimeBlock(block, src, operand_src); 7115 return block.addBitCast(Type.err_int, operand); 7116 } 7117 7118 fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 7119 const tracy = trace(@src()); 7120 defer tracy.end(); 7121 7122 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 7123 const src = LazySrcLoc.nodeOffset(extra.node); 7124 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 7125 const uncasted_operand = try sema.resolveInst(extra.operand); 7126 const operand = try sema.coerce(block, Type.err_int, uncasted_operand, operand_src); 7127 const target = sema.mod.getTarget(); 7128 7129 if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| { 7130 const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(target)); 7131 if (int > sema.mod.global_error_set.count() or int == 0) 7132 return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int}); 7133 const payload = try sema.arena.create(Value.Payload.Error); 7134 payload.* = .{ 7135 .base = .{ .tag = .@"error" }, 7136 .data = .{ .name = sema.mod.error_name_list.items[int] }, 7137 }; 7138 return sema.addConstant(Type.anyerror, Value.initPayload(&payload.base)); 7139 } 7140 try sema.requireRuntimeBlock(block, src, operand_src); 7141 if (block.wantSafety()) { 7142 const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand); 7143 const zero_val = try sema.addConstant(Type.err_int, Value.zero); 7144 const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val); 7145 const ok = try block.addBinOp(.bit_and, is_lt_len, is_non_zero); 7146 try sema.addSafetyCheck(block, ok, .invalid_error_code); 7147 } 7148 return block.addInst(.{ 7149 .tag = .bitcast, 7150 .data = .{ .ty_op = .{ 7151 .ty = Air.Inst.Ref.anyerror_type, 7152 .operand = operand, 7153 } }, 7154 }); 7155 } 7156 7157 fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7158 const tracy = trace(@src()); 7159 defer tracy.end(); 7160 7161 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 7162 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 7163 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 7164 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 7165 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 7166 const lhs = try sema.resolveInst(extra.lhs); 7167 const rhs = try sema.resolveInst(extra.rhs); 7168 if (sema.typeOf(lhs).zigTypeTag() == .Bool and sema.typeOf(rhs).zigTypeTag() == .Bool) { 7169 const msg = msg: { 7170 const msg = try sema.errMsg(block, lhs_src, "expected error set type, found 'bool'", .{}); 7171 errdefer msg.destroy(sema.gpa); 7172 try sema.errNote(block, src, msg, "'||' merges error sets; 'or' performs boolean OR", .{}); 7173 break :msg msg; 7174 }; 7175 return sema.failWithOwnedErrorMsg(msg); 7176 } 7177 const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs); 7178 const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs); 7179 if (lhs_ty.zigTypeTag() != .ErrorSet) 7180 return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{lhs_ty.fmt(sema.mod)}); 7181 if (rhs_ty.zigTypeTag() != .ErrorSet) 7182 return sema.fail(block, rhs_src, "expected error set type, found '{}'", .{rhs_ty.fmt(sema.mod)}); 7183 7184 // Anything merged with anyerror is anyerror. 7185 if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror) { 7186 return Air.Inst.Ref.anyerror_type; 7187 } 7188 7189 if (lhs_ty.castTag(.error_set_inferred)) |payload| { 7190 try sema.resolveInferredErrorSet(block, src, payload.data); 7191 // isAnyError might have changed from a false negative to a true positive after resolution. 7192 if (lhs_ty.isAnyError()) { 7193 return Air.Inst.Ref.anyerror_type; 7194 } 7195 } 7196 if (rhs_ty.castTag(.error_set_inferred)) |payload| { 7197 try sema.resolveInferredErrorSet(block, src, payload.data); 7198 // isAnyError might have changed from a false negative to a true positive after resolution. 7199 if (rhs_ty.isAnyError()) { 7200 return Air.Inst.Ref.anyerror_type; 7201 } 7202 } 7203 7204 const err_set_ty = try lhs_ty.errorSetMerge(sema.arena, rhs_ty); 7205 return sema.addType(err_set_ty); 7206 } 7207 7208 fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7209 _ = block; 7210 const tracy = trace(@src()); 7211 defer tracy.end(); 7212 7213 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 7214 const duped_name = try sema.arena.dupe(u8, inst_data.get(sema.code)); 7215 return sema.addConstant( 7216 Type.initTag(.enum_literal), 7217 try Value.Tag.enum_literal.create(sema.arena, duped_name), 7218 ); 7219 } 7220 7221 fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7222 const arena = sema.arena; 7223 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 7224 const src = inst_data.src(); 7225 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 7226 const operand = try sema.resolveInst(inst_data.operand); 7227 const operand_ty = sema.typeOf(operand); 7228 7229 const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag()) { 7230 .Enum => operand, 7231 .Union => blk: { 7232 const tag_ty = operand_ty.unionTagType() orelse { 7233 return sema.fail( 7234 block, 7235 operand_src, 7236 "untagged union '{}' cannot be converted to integer", 7237 .{src}, 7238 ); 7239 }; 7240 break :blk try sema.unionToTag(block, tag_ty, operand, operand_src); 7241 }, 7242 else => { 7243 return sema.fail(block, operand_src, "expected enum or tagged union, found '{}'", .{ 7244 operand_ty.fmt(sema.mod), 7245 }); 7246 }, 7247 }; 7248 const enum_tag_ty = sema.typeOf(enum_tag); 7249 7250 var int_tag_type_buffer: Type.Payload.Bits = undefined; 7251 const int_tag_ty = try enum_tag_ty.intTagType(&int_tag_type_buffer).copy(arena); 7252 7253 if (try sema.typeHasOnePossibleValue(block, src, enum_tag_ty)) |opv| { 7254 return sema.addConstant(int_tag_ty, opv); 7255 } 7256 7257 if (try sema.resolveMaybeUndefVal(block, operand_src, enum_tag)) |enum_tag_val| { 7258 var buffer: Value.Payload.U64 = undefined; 7259 const val = enum_tag_val.enumToInt(enum_tag_ty, &buffer); 7260 return sema.addConstant(int_tag_ty, try val.copy(sema.arena)); 7261 } 7262 7263 try sema.requireRuntimeBlock(block, src, operand_src); 7264 return block.addBitCast(int_tag_ty, enum_tag); 7265 } 7266 7267 fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7268 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 7269 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 7270 const src = inst_data.src(); 7271 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 7272 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 7273 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); 7274 const operand = try sema.resolveInst(extra.rhs); 7275 7276 if (dest_ty.zigTypeTag() != .Enum) { 7277 return sema.fail(block, dest_ty_src, "expected enum, found '{}'", .{dest_ty.fmt(sema.mod)}); 7278 } 7279 _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand)); 7280 7281 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |int_val| { 7282 if (dest_ty.isNonexhaustiveEnum()) { 7283 return sema.addConstant(dest_ty, int_val); 7284 } 7285 if (int_val.isUndef()) { 7286 return sema.failWithUseOfUndef(block, operand_src); 7287 } 7288 if (!(try sema.enumHasInt(block, src, dest_ty, int_val))) { 7289 const msg = msg: { 7290 const msg = try sema.errMsg( 7291 block, 7292 src, 7293 "enum '{}' has no tag with value '{}'", 7294 .{ dest_ty.fmt(sema.mod), int_val.fmtValue(sema.typeOf(operand), sema.mod) }, 7295 ); 7296 errdefer msg.destroy(sema.gpa); 7297 try sema.addDeclaredHereNote(msg, dest_ty); 7298 break :msg msg; 7299 }; 7300 return sema.failWithOwnedErrorMsg(msg); 7301 } 7302 return sema.addConstant(dest_ty, int_val); 7303 } 7304 7305 try sema.requireRuntimeBlock(block, src, operand_src); 7306 const result = try block.addTyOp(.intcast, dest_ty, operand); 7307 if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum() and sema.mod.comp.bin_file.options.use_llvm) { 7308 const ok = try block.addUnOp(.is_named_enum_value, result); 7309 try sema.addSafetyCheck(block, ok, .invalid_enum_value); 7310 } 7311 return result; 7312 } 7313 7314 /// Pointer in, pointer out. 7315 fn zirOptionalPayloadPtr( 7316 sema: *Sema, 7317 block: *Block, 7318 inst: Zir.Inst.Index, 7319 safety_check: bool, 7320 ) CompileError!Air.Inst.Ref { 7321 const tracy = trace(@src()); 7322 defer tracy.end(); 7323 7324 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 7325 const optional_ptr = try sema.resolveInst(inst_data.operand); 7326 const src = inst_data.src(); 7327 7328 return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false); 7329 } 7330 7331 fn analyzeOptionalPayloadPtr( 7332 sema: *Sema, 7333 block: *Block, 7334 src: LazySrcLoc, 7335 optional_ptr: Air.Inst.Ref, 7336 safety_check: bool, 7337 initializing: bool, 7338 ) CompileError!Air.Inst.Ref { 7339 const optional_ptr_ty = sema.typeOf(optional_ptr); 7340 assert(optional_ptr_ty.zigTypeTag() == .Pointer); 7341 7342 const opt_type = optional_ptr_ty.elemType(); 7343 if (opt_type.zigTypeTag() != .Optional) { 7344 return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(sema.mod)}); 7345 } 7346 7347 const child_type = try opt_type.optionalChildAlloc(sema.arena); 7348 const child_pointer = try Type.ptr(sema.arena, sema.mod, .{ 7349 .pointee_type = child_type, 7350 .mutable = !optional_ptr_ty.isConstPtr(), 7351 .@"addrspace" = optional_ptr_ty.ptrAddressSpace(), 7352 }); 7353 7354 if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| { 7355 if (initializing) { 7356 if (!ptr_val.isComptimeMutablePtr()) { 7357 // If the pointer resulting from this function was stored at comptime, 7358 // the optional non-null bit would be set that way. But in this case, 7359 // we need to emit a runtime instruction to do it. 7360 try sema.requireFunctionBlock(block, src); 7361 _ = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr); 7362 } 7363 return sema.addConstant( 7364 child_pointer, 7365 try Value.Tag.opt_payload_ptr.create(sema.arena, .{ 7366 .container_ptr = ptr_val, 7367 .container_ty = optional_ptr_ty.childType(), 7368 }), 7369 ); 7370 } 7371 if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| { 7372 if (val.isNull()) { 7373 return sema.fail(block, src, "unable to unwrap null", .{}); 7374 } 7375 // The same Value represents the pointer to the optional and the payload. 7376 return sema.addConstant( 7377 child_pointer, 7378 try Value.Tag.opt_payload_ptr.create(sema.arena, .{ 7379 .container_ptr = ptr_val, 7380 .container_ty = optional_ptr_ty.childType(), 7381 }), 7382 ); 7383 } 7384 } 7385 7386 try sema.requireRuntimeBlock(block, src, null); 7387 if (safety_check and block.wantSafety()) { 7388 const is_non_null = try block.addUnOp(.is_non_null_ptr, optional_ptr); 7389 try sema.addSafetyCheck(block, is_non_null, .unwrap_null); 7390 } 7391 const air_tag: Air.Inst.Tag = if (initializing) 7392 .optional_payload_ptr_set 7393 else 7394 .optional_payload_ptr; 7395 return block.addTyOp(air_tag, child_pointer, optional_ptr); 7396 } 7397 7398 /// Value in, value out. 7399 fn zirOptionalPayload( 7400 sema: *Sema, 7401 block: *Block, 7402 inst: Zir.Inst.Index, 7403 safety_check: bool, 7404 ) CompileError!Air.Inst.Ref { 7405 const tracy = trace(@src()); 7406 defer tracy.end(); 7407 7408 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 7409 const src = inst_data.src(); 7410 const operand = try sema.resolveInst(inst_data.operand); 7411 const operand_ty = sema.typeOf(operand); 7412 const result_ty = switch (operand_ty.zigTypeTag()) { 7413 .Optional => try operand_ty.optionalChildAlloc(sema.arena), 7414 .Pointer => t: { 7415 if (operand_ty.ptrSize() != .C) { 7416 return sema.failWithExpectedOptionalType(block, src, operand_ty); 7417 } 7418 // TODO https://github.com/ziglang/zig/issues/6597 7419 if (true) break :t operand_ty; 7420 const ptr_info = operand_ty.ptrInfo().data; 7421 break :t try Type.ptr(sema.arena, sema.mod, .{ 7422 .pointee_type = try ptr_info.pointee_type.copy(sema.arena), 7423 .@"align" = ptr_info.@"align", 7424 .@"addrspace" = ptr_info.@"addrspace", 7425 .mutable = ptr_info.mutable, 7426 .@"allowzero" = ptr_info.@"allowzero", 7427 .@"volatile" = ptr_info.@"volatile", 7428 .size = .One, 7429 }); 7430 }, 7431 else => return sema.failWithExpectedOptionalType(block, src, operand_ty), 7432 }; 7433 7434 if (try sema.resolveDefinedValue(block, src, operand)) |val| { 7435 if (val.isNull()) { 7436 return sema.fail(block, src, "unable to unwrap null", .{}); 7437 } 7438 if (val.castTag(.opt_payload)) |payload| { 7439 return sema.addConstant(result_ty, payload.data); 7440 } 7441 return sema.addConstant(result_ty, val); 7442 } 7443 7444 try sema.requireRuntimeBlock(block, src, null); 7445 if (safety_check and block.wantSafety()) { 7446 const is_non_null = try block.addUnOp(.is_non_null, operand); 7447 try sema.addSafetyCheck(block, is_non_null, .unwrap_null); 7448 } 7449 return block.addTyOp(.optional_payload, result_ty, operand); 7450 } 7451 7452 /// Value in, value out 7453 fn zirErrUnionPayload( 7454 sema: *Sema, 7455 block: *Block, 7456 inst: Zir.Inst.Index, 7457 ) CompileError!Air.Inst.Ref { 7458 const tracy = trace(@src()); 7459 defer tracy.end(); 7460 7461 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 7462 const src = inst_data.src(); 7463 const operand = try sema.resolveInst(inst_data.operand); 7464 const operand_src = src; 7465 const err_union_ty = sema.typeOf(operand); 7466 if (err_union_ty.zigTypeTag() != .ErrorUnion) { 7467 return sema.fail(block, operand_src, "expected error union type, found '{}'", .{ 7468 err_union_ty.fmt(sema.mod), 7469 }); 7470 } 7471 return sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false); 7472 } 7473 7474 fn analyzeErrUnionPayload( 7475 sema: *Sema, 7476 block: *Block, 7477 src: LazySrcLoc, 7478 err_union_ty: Type, 7479 operand: Zir.Inst.Ref, 7480 operand_src: LazySrcLoc, 7481 safety_check: bool, 7482 ) CompileError!Air.Inst.Ref { 7483 const payload_ty = err_union_ty.errorUnionPayload(); 7484 if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { 7485 if (val.getError()) |name| { 7486 return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); 7487 } 7488 const data = val.castTag(.eu_payload).?.data; 7489 return sema.addConstant(payload_ty, data); 7490 } 7491 7492 try sema.requireRuntimeBlock(block, src, null); 7493 7494 // If the error set has no fields then no safety check is needed. 7495 if (safety_check and block.wantSafety() and 7496 !err_union_ty.errorUnionSet().errorSetIsEmpty()) 7497 { 7498 try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err); 7499 } 7500 7501 return block.addTyOp(.unwrap_errunion_payload, payload_ty, operand); 7502 } 7503 7504 /// Pointer in, pointer out. 7505 fn zirErrUnionPayloadPtr( 7506 sema: *Sema, 7507 block: *Block, 7508 inst: Zir.Inst.Index, 7509 ) CompileError!Air.Inst.Ref { 7510 const tracy = trace(@src()); 7511 defer tracy.end(); 7512 7513 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 7514 const operand = try sema.resolveInst(inst_data.operand); 7515 const src = inst_data.src(); 7516 7517 return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false); 7518 } 7519 7520 fn analyzeErrUnionPayloadPtr( 7521 sema: *Sema, 7522 block: *Block, 7523 src: LazySrcLoc, 7524 operand: Air.Inst.Ref, 7525 safety_check: bool, 7526 initializing: bool, 7527 ) CompileError!Air.Inst.Ref { 7528 const operand_ty = sema.typeOf(operand); 7529 assert(operand_ty.zigTypeTag() == .Pointer); 7530 7531 if (operand_ty.elemType().zigTypeTag() != .ErrorUnion) { 7532 return sema.fail(block, src, "expected error union type, found '{}'", .{ 7533 operand_ty.elemType().fmt(sema.mod), 7534 }); 7535 } 7536 7537 const err_union_ty = operand_ty.elemType(); 7538 const payload_ty = err_union_ty.errorUnionPayload(); 7539 const operand_pointer_ty = try Type.ptr(sema.arena, sema.mod, .{ 7540 .pointee_type = payload_ty, 7541 .mutable = !operand_ty.isConstPtr(), 7542 .@"addrspace" = operand_ty.ptrAddressSpace(), 7543 }); 7544 7545 if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| { 7546 if (initializing) { 7547 if (!ptr_val.isComptimeMutablePtr()) { 7548 // If the pointer resulting from this function was stored at comptime, 7549 // the error union error code would be set that way. But in this case, 7550 // we need to emit a runtime instruction to do it. 7551 try sema.requireRuntimeBlock(block, src, null); 7552 _ = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand); 7553 } 7554 return sema.addConstant( 7555 operand_pointer_ty, 7556 try Value.Tag.eu_payload_ptr.create(sema.arena, .{ 7557 .container_ptr = ptr_val, 7558 .container_ty = operand_ty.elemType(), 7559 }), 7560 ); 7561 } 7562 if (try sema.pointerDeref(block, src, ptr_val, operand_ty)) |val| { 7563 if (val.getError()) |name| { 7564 return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); 7565 } 7566 7567 return sema.addConstant( 7568 operand_pointer_ty, 7569 try Value.Tag.eu_payload_ptr.create(sema.arena, .{ 7570 .container_ptr = ptr_val, 7571 .container_ty = operand_ty.elemType(), 7572 }), 7573 ); 7574 } 7575 } 7576 7577 try sema.requireRuntimeBlock(block, src, null); 7578 7579 // If the error set has no fields then no safety check is needed. 7580 if (safety_check and block.wantSafety() and 7581 !err_union_ty.errorUnionSet().errorSetIsEmpty()) 7582 { 7583 try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr); 7584 } 7585 7586 const air_tag: Air.Inst.Tag = if (initializing) 7587 .errunion_payload_ptr_set 7588 else 7589 .unwrap_errunion_payload_ptr; 7590 return block.addTyOp(air_tag, operand_pointer_ty, operand); 7591 } 7592 7593 /// Value in, value out 7594 fn zirErrUnionCode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7595 const tracy = trace(@src()); 7596 defer tracy.end(); 7597 7598 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 7599 const src = inst_data.src(); 7600 const operand = try sema.resolveInst(inst_data.operand); 7601 const operand_ty = sema.typeOf(operand); 7602 if (operand_ty.zigTypeTag() != .ErrorUnion) { 7603 return sema.fail(block, src, "expected error union type, found '{}'", .{ 7604 operand_ty.fmt(sema.mod), 7605 }); 7606 } 7607 7608 const result_ty = operand_ty.errorUnionSet(); 7609 7610 if (try sema.resolveDefinedValue(block, src, operand)) |val| { 7611 assert(val.getError() != null); 7612 return sema.addConstant(result_ty, val); 7613 } 7614 7615 try sema.requireRuntimeBlock(block, src, null); 7616 return block.addTyOp(.unwrap_errunion_err, result_ty, operand); 7617 } 7618 7619 /// Pointer in, value out 7620 fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7621 const tracy = trace(@src()); 7622 defer tracy.end(); 7623 7624 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 7625 const src = inst_data.src(); 7626 const operand = try sema.resolveInst(inst_data.operand); 7627 const operand_ty = sema.typeOf(operand); 7628 assert(operand_ty.zigTypeTag() == .Pointer); 7629 7630 if (operand_ty.elemType().zigTypeTag() != .ErrorUnion) { 7631 return sema.fail(block, src, "expected error union type, found '{}'", .{ 7632 operand_ty.elemType().fmt(sema.mod), 7633 }); 7634 } 7635 7636 const result_ty = operand_ty.elemType().errorUnionSet(); 7637 7638 if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| { 7639 if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| { 7640 assert(val.getError() != null); 7641 return sema.addConstant(result_ty, val); 7642 } 7643 } 7644 7645 try sema.requireRuntimeBlock(block, src, null); 7646 return block.addTyOp(.unwrap_errunion_err_ptr, result_ty, operand); 7647 } 7648 7649 fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 7650 const tracy = trace(@src()); 7651 defer tracy.end(); 7652 7653 const inst_data = sema.code.instructions.items(.data)[inst].un_tok; 7654 const src = inst_data.src(); 7655 const operand = try sema.resolveInst(inst_data.operand); 7656 const operand_ty = sema.typeOf(operand); 7657 if (operand_ty.zigTypeTag() != .ErrorUnion) { 7658 return sema.fail(block, src, "expected error union type, found '{}'", .{ 7659 operand_ty.fmt(sema.mod), 7660 }); 7661 } 7662 if (operand_ty.errorUnionPayload().zigTypeTag() != .Void) { 7663 return sema.fail(block, src, "expression value is ignored", .{}); 7664 } 7665 } 7666 7667 fn zirFunc( 7668 sema: *Sema, 7669 block: *Block, 7670 inst: Zir.Inst.Index, 7671 inferred_error_set: bool, 7672 ) CompileError!Air.Inst.Ref { 7673 const tracy = trace(@src()); 7674 defer tracy.end(); 7675 7676 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 7677 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index); 7678 const target = sema.mod.getTarget(); 7679 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = inst_data.src_node }; 7680 7681 var extra_index = extra.end; 7682 7683 const ret_ty: Type = switch (extra.data.ret_body_len) { 7684 0 => Type.void, 7685 1 => blk: { 7686 const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 7687 extra_index += 1; 7688 if (sema.resolveType(block, ret_ty_src, ret_ty_ref)) |ret_ty| { 7689 break :blk ret_ty; 7690 } else |err| switch (err) { 7691 error.GenericPoison => { 7692 break :blk Type.initTag(.generic_poison); 7693 }, 7694 else => |e| return e, 7695 } 7696 }, 7697 else => blk: { 7698 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len]; 7699 extra_index += ret_ty_body.len; 7700 7701 const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type, "return type must be comptime known"); 7702 var buffer: Value.ToTypeBuffer = undefined; 7703 break :blk try ret_ty_val.toType(&buffer).copy(sema.arena); 7704 }, 7705 }; 7706 7707 var src_locs: Zir.Inst.Func.SrcLocs = undefined; 7708 const has_body = extra.data.body_len != 0; 7709 if (has_body) { 7710 extra_index += extra.data.body_len; 7711 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; 7712 } 7713 7714 // If this instruction has a body it means it's the type of the `owner_decl` 7715 // otherwise it's a function type without a `callconv` attribute and should 7716 // never be `.C`. 7717 // NOTE: revisit when doing #1717 7718 const cc: std.builtin.CallingConvention = if (sema.owner_decl.is_exported and has_body) 7719 .C 7720 else 7721 .Unspecified; 7722 7723 return sema.funcCommon( 7724 block, 7725 inst_data.src_node, 7726 inst, 7727 0, 7728 target_util.defaultAddressSpace(target, .function), 7729 FuncLinkSection.default, 7730 cc, 7731 ret_ty, 7732 false, 7733 inferred_error_set, 7734 false, 7735 has_body, 7736 src_locs, 7737 null, 7738 0, 7739 false, 7740 ); 7741 } 7742 7743 fn resolveGenericBody( 7744 sema: *Sema, 7745 block: *Block, 7746 src: LazySrcLoc, 7747 body: []const Zir.Inst.Index, 7748 func_inst: Zir.Inst.Index, 7749 dest_ty: Type, 7750 reason: []const u8, 7751 ) !Value { 7752 assert(body.len != 0); 7753 7754 const err = err: { 7755 // Make sure any nested param instructions don't clobber our work. 7756 const prev_params = block.params; 7757 block.params = .{}; 7758 defer { 7759 block.params.deinit(sema.gpa); 7760 block.params = prev_params; 7761 } 7762 const uncasted = sema.resolveBody(block, body, func_inst) catch |err| break :err err; 7763 const result = sema.coerce(block, dest_ty, uncasted, src) catch |err| break :err err; 7764 const val = sema.resolveConstValue(block, src, result, reason) catch |err| break :err err; 7765 return val; 7766 }; 7767 switch (err) { 7768 error.GenericPoison => { 7769 if (dest_ty.tag() == .type) { 7770 return Value.initTag(.generic_poison_type); 7771 } else { 7772 return Value.initTag(.generic_poison); 7773 } 7774 }, 7775 else => |e| return e, 7776 } 7777 } 7778 7779 /// Given a library name, examines if the library name should end up in 7780 /// `link.File.Options.system_libs` table (for example, libc is always 7781 /// specified via dedicated flag `link.File.Options.link_libc` instead), 7782 /// and puts it there if it doesn't exist. 7783 /// It also dupes the library name which can then be saved as part of the 7784 /// respective `Decl` (either `ExternFn` or `Var`). 7785 /// The liveness of the duped library name is tied to liveness of `Module`. 7786 /// To deallocate, call `deinit` on the respective `Decl` (`ExternFn` or `Var`). 7787 fn handleExternLibName( 7788 sema: *Sema, 7789 block: *Block, 7790 src_loc: LazySrcLoc, 7791 lib_name: []const u8, 7792 ) CompileError![:0]u8 { 7793 blk: { 7794 const mod = sema.mod; 7795 const comp = mod.comp; 7796 const target = mod.getTarget(); 7797 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name}); 7798 if (target_util.is_libc_lib_name(target, lib_name)) { 7799 if (!comp.bin_file.options.link_libc and !comp.bin_file.options.parent_compilation_link_libc) { 7800 return sema.fail( 7801 block, 7802 src_loc, 7803 "dependency on libc must be explicitly specified in the build command", 7804 .{}, 7805 ); 7806 } 7807 comp.bin_file.options.link_libc = true; 7808 break :blk; 7809 } 7810 if (target_util.is_libcpp_lib_name(target, lib_name)) { 7811 if (!comp.bin_file.options.link_libcpp) { 7812 return sema.fail( 7813 block, 7814 src_loc, 7815 "dependency on libc++ must be explicitly specified in the build command", 7816 .{}, 7817 ); 7818 } 7819 comp.bin_file.options.link_libcpp = true; 7820 break :blk; 7821 } 7822 if (mem.eql(u8, lib_name, "unwind")) { 7823 comp.bin_file.options.link_libunwind = true; 7824 break :blk; 7825 } 7826 if (!target.isWasm() and !comp.bin_file.options.pic) { 7827 return sema.fail( 7828 block, 7829 src_loc, 7830 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.", 7831 .{ lib_name, lib_name }, 7832 ); 7833 } 7834 comp.stage1AddLinkLib(lib_name) catch |err| { 7835 return sema.fail(block, src_loc, "unable to add link lib '{s}': {s}", .{ 7836 lib_name, @errorName(err), 7837 }); 7838 }; 7839 } 7840 return sema.gpa.dupeZ(u8, lib_name); 7841 } 7842 7843 const FuncLinkSection = union(enum) { 7844 generic, 7845 default, 7846 explicit: [*:0]const u8, 7847 }; 7848 7849 fn funcCommon( 7850 sema: *Sema, 7851 block: *Block, 7852 src_node_offset: i32, 7853 func_inst: Zir.Inst.Index, 7854 /// null means generic poison 7855 alignment: ?u32, 7856 /// null means generic poison 7857 address_space: ?std.builtin.AddressSpace, 7858 /// outer null means generic poison; inner null means default link section 7859 section: FuncLinkSection, 7860 /// null means generic poison 7861 cc: ?std.builtin.CallingConvention, 7862 /// this might be Type.generic_poison 7863 bare_return_type: Type, 7864 var_args: bool, 7865 inferred_error_set: bool, 7866 is_extern: bool, 7867 has_body: bool, 7868 src_locs: Zir.Inst.Func.SrcLocs, 7869 opt_lib_name: ?[]const u8, 7870 noalias_bits: u32, 7871 is_noinline: bool, 7872 ) CompileError!Air.Inst.Ref { 7873 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset }; 7874 const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset }; 7875 7876 var is_generic = bare_return_type.tag() == .generic_poison or 7877 alignment == null or 7878 address_space == null or 7879 section == .generic or 7880 cc == null; 7881 7882 var destroy_fn_on_error = false; 7883 const new_func: *Module.Fn = new_func: { 7884 if (!has_body) break :new_func undefined; 7885 if (sema.comptime_args_fn_inst == func_inst) { 7886 const new_func = sema.preallocated_new_func.?; 7887 sema.preallocated_new_func = null; // take ownership 7888 break :new_func new_func; 7889 } 7890 destroy_fn_on_error = true; 7891 const new_func = try sema.gpa.create(Module.Fn); 7892 // Set this here so that the inferred return type can be printed correctly if it appears in an error. 7893 new_func.owner_decl = sema.owner_decl_index; 7894 break :new_func new_func; 7895 }; 7896 errdefer if (destroy_fn_on_error) sema.gpa.destroy(new_func); 7897 7898 var maybe_inferred_error_set_node: ?*Module.Fn.InferredErrorSetListNode = null; 7899 errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node); 7900 // Note: no need to errdefer since this will still be in its default state at the end of the function. 7901 7902 const target = sema.mod.getTarget(); 7903 const fn_ty: Type = fn_ty: { 7904 // Hot path for some common function types. 7905 // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated. 7906 if (!is_generic and block.params.items.len == 0 and !var_args and !inferred_error_set and 7907 alignment.? == 0 and 7908 address_space.? == target_util.defaultAddressSpace(target, .function) and 7909 section == .default) 7910 { 7911 if (bare_return_type.zigTypeTag() == .NoReturn and cc.? == .Unspecified) { 7912 break :fn_ty Type.initTag(.fn_noreturn_no_args); 7913 } 7914 7915 if (bare_return_type.zigTypeTag() == .Void and cc.? == .Unspecified) { 7916 break :fn_ty Type.initTag(.fn_void_no_args); 7917 } 7918 7919 if (bare_return_type.zigTypeTag() == .NoReturn and cc.? == .Naked) { 7920 break :fn_ty Type.initTag(.fn_naked_noreturn_no_args); 7921 } 7922 7923 if (bare_return_type.zigTypeTag() == .Void and cc.? == .C) { 7924 break :fn_ty Type.initTag(.fn_ccc_void_no_args); 7925 } 7926 } 7927 7928 // These locals are pulled out from the init expression below to work around 7929 // a stage1 compiler bug. 7930 // In the case of generic calling convention, or generic alignment, we use 7931 // default values which are only meaningful for the generic function, *not* 7932 // the instantiation, which can depend on comptime parameters. 7933 // Related proposal: https://github.com/ziglang/zig/issues/11834 7934 const cc_workaround = cc orelse .Unspecified; 7935 const align_workaround = alignment orelse 0; 7936 7937 const param_types = try sema.arena.alloc(Type, block.params.items.len); 7938 const comptime_params = try sema.arena.alloc(bool, block.params.items.len); 7939 for (block.params.items) |param, i| { 7940 param_types[i] = param.ty; 7941 sema.analyzeParameter( 7942 block, 7943 .unneeded, 7944 param, 7945 comptime_params, 7946 i, 7947 &is_generic, 7948 cc_workaround, 7949 has_body, 7950 ) catch |err| switch (err) { 7951 error.NeededSourceLocation => { 7952 const decl = sema.mod.declPtr(block.src_decl); 7953 try sema.analyzeParameter( 7954 block, 7955 Module.paramSrc(src_node_offset, sema.gpa, decl, i), 7956 param, 7957 comptime_params, 7958 i, 7959 &is_generic, 7960 cc_workaround, 7961 has_body, 7962 ); 7963 return error.AnalysisFail; 7964 }, 7965 else => |e| return e, 7966 }; 7967 } 7968 7969 var ret_ty_requires_comptime = false; 7970 const ret_poison = if (sema.typeRequiresComptime(bare_return_type)) |ret_comptime| rp: { 7971 ret_ty_requires_comptime = ret_comptime; 7972 break :rp bare_return_type.tag() == .generic_poison; 7973 } else |err| switch (err) { 7974 error.GenericPoison => rp: { 7975 is_generic = true; 7976 break :rp true; 7977 }, 7978 else => |e| return e, 7979 }; 7980 7981 const return_type = if (!inferred_error_set or ret_poison) 7982 bare_return_type 7983 else blk: { 7984 const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode); 7985 node.data = .{ .func = new_func }; 7986 maybe_inferred_error_set_node = node; 7987 7988 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data); 7989 break :blk try Type.Tag.error_union.create(sema.arena, .{ 7990 .error_set = error_set_ty, 7991 .payload = bare_return_type, 7992 }); 7993 }; 7994 7995 if (!bare_return_type.isValidReturnType()) { 7996 const opaque_str = if (bare_return_type.zigTypeTag() == .Opaque) "opaque " else ""; 7997 const msg = msg: { 7998 const msg = try sema.errMsg(block, ret_ty_src, "{s}return type '{}' not allowed", .{ 7999 opaque_str, bare_return_type.fmt(sema.mod), 8000 }); 8001 errdefer msg.destroy(sema.gpa); 8002 8003 try sema.addDeclaredHereNote(msg, bare_return_type); 8004 break :msg msg; 8005 }; 8006 return sema.failWithOwnedErrorMsg(msg); 8007 } 8008 if (!Type.fnCallingConventionAllowsZigTypes(cc_workaround) and !try sema.validateExternType(block, ret_ty_src, return_type, .ret_ty)) { 8009 const msg = msg: { 8010 const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{ 8011 return_type.fmt(sema.mod), @tagName(cc_workaround), 8012 }); 8013 errdefer msg.destroy(sema.gpa); 8014 8015 const src_decl = sema.mod.declPtr(block.src_decl); 8016 try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl), return_type, .ret_ty); 8017 8018 try sema.addDeclaredHereNote(msg, return_type); 8019 break :msg msg; 8020 }; 8021 return sema.failWithOwnedErrorMsg(msg); 8022 } 8023 8024 // If the return type is comptime only but not dependent on parameters then all parameter types also need to be comptime 8025 if (!sema.is_generic_instantiation and has_body and ret_ty_requires_comptime) comptime_check: { 8026 for (block.params.items) |param| { 8027 if (!param.is_comptime) break; 8028 } else break :comptime_check; 8029 8030 const msg = try sema.errMsg( 8031 block, 8032 ret_ty_src, 8033 "function with comptime only return type '{}' requires all parameters to be comptime", 8034 .{return_type.fmt(sema.mod)}, 8035 ); 8036 try sema.explainWhyTypeIsComptime(block, ret_ty_src, msg, ret_ty_src.toSrcLoc(sema.owner_decl), return_type); 8037 8038 const tags = sema.code.instructions.items(.tag); 8039 const data = sema.code.instructions.items(.data); 8040 const param_body = sema.code.getParamBody(func_inst); 8041 for (block.params.items) |param, i| { 8042 if (!param.is_comptime) { 8043 const param_index = param_body[i]; 8044 const param_src = switch (tags[param_index]) { 8045 .param => data[param_index].pl_tok.src(), 8046 .param_anytype => data[param_index].str_tok.src(), 8047 else => unreachable, 8048 }; 8049 if (param.name.len != 0) { 8050 try sema.errNote(block, param_src, msg, "param '{s}' is required to be comptime", .{param.name}); 8051 } else { 8052 try sema.errNote(block, param_src, msg, "param is required to be comptime", .{}); 8053 } 8054 } 8055 } 8056 return sema.failWithOwnedErrorMsg(msg); 8057 } 8058 8059 const arch = sema.mod.getTarget().cpu.arch; 8060 if (switch (cc_workaround) { 8061 .Unspecified, .C, .Naked, .Async, .Inline => null, 8062 .Interrupt => switch (arch) { 8063 .i386, .x86_64, .avr, .msp430 => null, 8064 else => @as([]const u8, "i386, x86_64, AVR, and MSP430"), 8065 }, 8066 .Signal => switch (arch) { 8067 .avr => null, 8068 else => @as([]const u8, "AVR"), 8069 }, 8070 .Stdcall, .Fastcall, .Thiscall => switch (arch) { 8071 .i386 => null, 8072 else => @as([]const u8, "i386"), 8073 }, 8074 .Vectorcall => switch (arch) { 8075 .i386, .aarch64, .aarch64_be, .aarch64_32 => null, 8076 else => @as([]const u8, "i386 and AArch64"), 8077 }, 8078 .APCS, .AAPCS, .AAPCSVFP => switch (arch) { 8079 .arm, .armeb, .aarch64, .aarch64_be, .aarch64_32, .thumb, .thumbeb => null, 8080 else => @as([]const u8, "ARM"), 8081 }, 8082 .SysV, .Win64 => switch (arch) { 8083 .x86_64 => null, 8084 else => @as([]const u8, "x86_64"), 8085 }, 8086 .PtxKernel => switch (arch) { 8087 .nvptx, .nvptx64 => null, 8088 else => @as([]const u8, "nvptx and nvptx64"), 8089 }, 8090 }) |allowed_platform| { 8091 return sema.fail(block, cc_src, "callconv '{s}' is only available on {s}, not {s}", .{ 8092 @tagName(cc_workaround), 8093 allowed_platform, 8094 @tagName(arch), 8095 }); 8096 } 8097 8098 if (cc_workaround == .Inline and is_noinline) { 8099 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{}); 8100 } 8101 if (is_generic and sema.no_partial_func_ty) return error.GenericPoison; 8102 for (comptime_params) |ct| is_generic = is_generic or ct; 8103 is_generic = is_generic or ret_ty_requires_comptime; 8104 8105 break :fn_ty try Type.Tag.function.create(sema.arena, .{ 8106 .param_types = param_types, 8107 .comptime_params = comptime_params.ptr, 8108 .return_type = return_type, 8109 .cc = cc_workaround, 8110 .cc_is_generic = cc == null, 8111 .alignment = align_workaround, 8112 .align_is_generic = alignment == null, 8113 .section_is_generic = section == .generic, 8114 .addrspace_is_generic = address_space == null, 8115 .is_var_args = var_args, 8116 .is_generic = is_generic, 8117 .noalias_bits = noalias_bits, 8118 }); 8119 }; 8120 8121 if (sema.owner_decl.owns_tv) { 8122 switch (section) { 8123 .generic => sema.owner_decl.@"linksection" = undefined, 8124 .default => sema.owner_decl.@"linksection" = null, 8125 .explicit => |s| sema.owner_decl.@"linksection" = s, 8126 } 8127 if (alignment) |a| sema.owner_decl.@"align" = a; 8128 if (address_space) |a| sema.owner_decl.@"addrspace" = a; 8129 } 8130 8131 if (is_extern) { 8132 const new_extern_fn = try sema.gpa.create(Module.ExternFn); 8133 errdefer sema.gpa.destroy(new_extern_fn); 8134 8135 new_extern_fn.* = Module.ExternFn{ 8136 .owner_decl = sema.owner_decl_index, 8137 .lib_name = null, 8138 }; 8139 8140 if (opt_lib_name) |lib_name| { 8141 new_extern_fn.lib_name = try sema.handleExternLibName(block, .{ 8142 .node_offset_lib_name = src_node_offset, 8143 }, lib_name); 8144 } 8145 8146 const extern_fn_payload = try sema.arena.create(Value.Payload.ExternFn); 8147 extern_fn_payload.* = .{ 8148 .base = .{ .tag = .extern_fn }, 8149 .data = new_extern_fn, 8150 }; 8151 return sema.addConstant(fn_ty, Value.initPayload(&extern_fn_payload.base)); 8152 } 8153 8154 if (!has_body) { 8155 return sema.addType(fn_ty); 8156 } 8157 8158 const is_inline = fn_ty.fnCallingConvention() == .Inline; 8159 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued; 8160 8161 const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == func_inst) blk: { 8162 break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr; 8163 } else null; 8164 8165 const hash = new_func.hash; 8166 const generic_owner_decl = if (comptime_args == null) .none else new_func.generic_owner_decl; 8167 const fn_payload = try sema.arena.create(Value.Payload.Function); 8168 new_func.* = .{ 8169 .state = anal_state, 8170 .zir_body_inst = func_inst, 8171 .owner_decl = sema.owner_decl_index, 8172 .generic_owner_decl = generic_owner_decl, 8173 .comptime_args = comptime_args, 8174 .hash = hash, 8175 .lbrace_line = src_locs.lbrace_line, 8176 .rbrace_line = src_locs.rbrace_line, 8177 .lbrace_column = @truncate(u16, src_locs.columns), 8178 .rbrace_column = @truncate(u16, src_locs.columns >> 16), 8179 .branch_quota = default_branch_quota, 8180 .is_noinline = is_noinline, 8181 }; 8182 if (maybe_inferred_error_set_node) |node| { 8183 new_func.inferred_error_sets.prepend(node); 8184 } 8185 maybe_inferred_error_set_node = null; 8186 fn_payload.* = .{ 8187 .base = .{ .tag = .function }, 8188 .data = new_func, 8189 }; 8190 return sema.addConstant(fn_ty, Value.initPayload(&fn_payload.base)); 8191 } 8192 8193 fn analyzeParameter( 8194 sema: *Sema, 8195 block: *Block, 8196 param_src: LazySrcLoc, 8197 param: Block.Param, 8198 comptime_params: []bool, 8199 i: usize, 8200 is_generic: *bool, 8201 cc: std.builtin.CallingConvention, 8202 has_body: bool, 8203 ) !void { 8204 const requires_comptime = try sema.typeRequiresComptime(param.ty); 8205 comptime_params[i] = param.is_comptime or requires_comptime; 8206 const this_generic = param.ty.tag() == .generic_poison; 8207 is_generic.* = is_generic.* or this_generic; 8208 if (param.is_comptime and !Type.fnCallingConventionAllowsZigTypes(cc)) { 8209 return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); 8210 } 8211 if (this_generic and !sema.no_partial_func_ty and !Type.fnCallingConventionAllowsZigTypes(cc)) { 8212 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); 8213 } 8214 if (!param.ty.isValidParamType()) { 8215 const opaque_str = if (param.ty.zigTypeTag() == .Opaque) "opaque " else ""; 8216 const msg = msg: { 8217 const msg = try sema.errMsg(block, param_src, "parameter of {s}type '{}' not allowed", .{ 8218 opaque_str, param.ty.fmt(sema.mod), 8219 }); 8220 errdefer msg.destroy(sema.gpa); 8221 8222 try sema.addDeclaredHereNote(msg, param.ty); 8223 break :msg msg; 8224 }; 8225 return sema.failWithOwnedErrorMsg(msg); 8226 } 8227 if (!this_generic and !Type.fnCallingConventionAllowsZigTypes(cc) and !try sema.validateExternType(block, param_src, param.ty, .param_ty)) { 8228 const msg = msg: { 8229 const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{ 8230 param.ty.fmt(sema.mod), @tagName(cc), 8231 }); 8232 errdefer msg.destroy(sema.gpa); 8233 8234 const src_decl = sema.mod.declPtr(block.src_decl); 8235 try sema.explainWhyTypeIsNotExtern(msg, param_src.toSrcLoc(src_decl), param.ty, .param_ty); 8236 8237 try sema.addDeclaredHereNote(msg, param.ty); 8238 break :msg msg; 8239 }; 8240 return sema.failWithOwnedErrorMsg(msg); 8241 } 8242 if (!sema.is_generic_instantiation and requires_comptime and !param.is_comptime and has_body) { 8243 const msg = msg: { 8244 const msg = try sema.errMsg(block, param_src, "parameter of type '{}' must be declared comptime", .{ 8245 param.ty.fmt(sema.mod), 8246 }); 8247 errdefer msg.destroy(sema.gpa); 8248 8249 try sema.addDeclaredHereNote(msg, param.ty); 8250 break :msg msg; 8251 }; 8252 return sema.failWithOwnedErrorMsg(msg); 8253 } 8254 } 8255 8256 fn zirParam( 8257 sema: *Sema, 8258 block: *Block, 8259 inst: Zir.Inst.Index, 8260 comptime_syntax: bool, 8261 ) CompileError!void { 8262 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok; 8263 const src = inst_data.src(); 8264 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index); 8265 const param_name = sema.code.nullTerminatedString(extra.data.name); 8266 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 8267 8268 // We could be in a generic function instantiation, or we could be evaluating a generic 8269 // function without any comptime args provided. 8270 const param_ty = param_ty: { 8271 const err = err: { 8272 // Make sure any nested param instructions don't clobber our work. 8273 const prev_params = block.params; 8274 const prev_preallocated_new_func = sema.preallocated_new_func; 8275 const prev_no_partial_func_type = sema.no_partial_func_ty; 8276 block.params = .{}; 8277 sema.preallocated_new_func = null; 8278 sema.no_partial_func_ty = true; 8279 defer { 8280 block.params.deinit(sema.gpa); 8281 block.params = prev_params; 8282 sema.preallocated_new_func = prev_preallocated_new_func; 8283 sema.no_partial_func_ty = prev_no_partial_func_type; 8284 } 8285 8286 if (sema.resolveBody(block, body, inst)) |param_ty_inst| { 8287 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| { 8288 break :param_ty param_ty; 8289 } else |err| break :err err; 8290 } else |err| break :err err; 8291 }; 8292 switch (err) { 8293 error.GenericPoison => { 8294 // The type is not available until the generic instantiation. 8295 // We result the param instruction with a poison value and 8296 // insert an anytype parameter. 8297 try block.params.append(sema.gpa, .{ 8298 .ty = Type.initTag(.generic_poison), 8299 .is_comptime = comptime_syntax, 8300 .name = param_name, 8301 }); 8302 try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison); 8303 return; 8304 }, 8305 else => |e| return e, 8306 } 8307 }; 8308 const is_comptime = sema.typeRequiresComptime(param_ty) catch |err| switch (err) { 8309 error.GenericPoison => { 8310 // The type is not available until the generic instantiation. 8311 // We result the param instruction with a poison value and 8312 // insert an anytype parameter. 8313 try block.params.append(sema.gpa, .{ 8314 .ty = Type.initTag(.generic_poison), 8315 .is_comptime = comptime_syntax, 8316 .name = param_name, 8317 }); 8318 try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison); 8319 return; 8320 }, 8321 else => |e| return e, 8322 } or comptime_syntax; 8323 if (sema.inst_map.get(inst)) |arg| { 8324 if (is_comptime) { 8325 // We have a comptime value for this parameter so it should be elided from the 8326 // function type of the function instruction in this block. 8327 const coerced_arg = try sema.coerce(block, param_ty, arg, src); 8328 sema.inst_map.putAssumeCapacity(inst, coerced_arg); 8329 return; 8330 } 8331 // Even though a comptime argument is provided, the generic function wants to treat 8332 // this as a runtime parameter. 8333 assert(sema.inst_map.remove(inst)); 8334 } 8335 8336 if (sema.preallocated_new_func != null) { 8337 if (try sema.typeHasOnePossibleValue(block, src, param_ty)) |opv| { 8338 // In this case we are instantiating a generic function call with a non-comptime 8339 // non-anytype parameter that ended up being a one-possible-type. 8340 // We don't want the parameter to be part of the instantiated function type. 8341 const result = try sema.addConstant(param_ty, opv); 8342 try sema.inst_map.put(sema.gpa, inst, result); 8343 return; 8344 } 8345 } 8346 8347 try block.params.append(sema.gpa, .{ 8348 .ty = param_ty, 8349 .is_comptime = comptime_syntax, 8350 .name = param_name, 8351 }); 8352 8353 if (is_comptime) { 8354 // If this is a comptime parameter we can add a constant generic_poison 8355 // since this is also a generic parameter. 8356 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison)); 8357 try sema.inst_map.putNoClobber(sema.gpa, inst, result); 8358 } else { 8359 // Otherwise we need a dummy runtime instruction. 8360 const result_index = @intCast(Air.Inst.Index, sema.air_instructions.len); 8361 try sema.air_instructions.append(sema.gpa, .{ 8362 .tag = .alloc, 8363 .data = .{ .ty = param_ty }, 8364 }); 8365 const result = Air.indexToRef(result_index); 8366 try sema.inst_map.putNoClobber(sema.gpa, inst, result); 8367 } 8368 } 8369 8370 fn zirParamAnytype( 8371 sema: *Sema, 8372 block: *Block, 8373 inst: Zir.Inst.Index, 8374 comptime_syntax: bool, 8375 ) CompileError!void { 8376 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 8377 const src = inst_data.src(); 8378 const param_name = inst_data.get(sema.code); 8379 8380 if (sema.inst_map.get(inst)) |air_ref| { 8381 const param_ty = sema.typeOf(air_ref); 8382 if (comptime_syntax or try sema.typeRequiresComptime(param_ty)) { 8383 // We have a comptime value for this parameter so it should be elided from the 8384 // function type of the function instruction in this block. 8385 return; 8386 } 8387 if (null != try sema.typeHasOnePossibleValue(block, src, param_ty)) { 8388 return; 8389 } 8390 // The map is already populated but we do need to add a runtime parameter. 8391 try block.params.append(sema.gpa, .{ 8392 .ty = param_ty, 8393 .is_comptime = false, 8394 .name = param_name, 8395 }); 8396 return; 8397 } 8398 8399 // We are evaluating a generic function without any comptime args provided. 8400 8401 try block.params.append(sema.gpa, .{ 8402 .ty = Type.initTag(.generic_poison), 8403 .is_comptime = comptime_syntax, 8404 .name = param_name, 8405 }); 8406 try sema.inst_map.put(sema.gpa, inst, .generic_poison); 8407 } 8408 8409 fn zirAs(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8410 const tracy = trace(@src()); 8411 defer tracy.end(); 8412 8413 const bin_inst = sema.code.instructions.items(.data)[inst].bin; 8414 return sema.analyzeAs(block, sema.src, bin_inst.lhs, bin_inst.rhs, false); 8415 } 8416 8417 fn zirAsNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8418 const tracy = trace(@src()); 8419 defer tracy.end(); 8420 8421 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8422 const src = inst_data.src(); 8423 const extra = sema.code.extraData(Zir.Inst.As, inst_data.payload_index).data; 8424 sema.src = src; 8425 return sema.analyzeAs(block, src, extra.dest_type, extra.operand, false); 8426 } 8427 8428 fn zirAsShiftOperand(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8429 const tracy = trace(@src()); 8430 defer tracy.end(); 8431 8432 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8433 const src = inst_data.src(); 8434 const extra = sema.code.extraData(Zir.Inst.As, inst_data.payload_index).data; 8435 return sema.analyzeAs(block, src, extra.dest_type, extra.operand, true); 8436 } 8437 8438 fn analyzeAs( 8439 sema: *Sema, 8440 block: *Block, 8441 src: LazySrcLoc, 8442 zir_dest_type: Zir.Inst.Ref, 8443 zir_operand: Zir.Inst.Ref, 8444 no_cast_to_comptime_int: bool, 8445 ) CompileError!Air.Inst.Ref { 8446 const is_ret = if (Zir.refToIndex(zir_dest_type)) |ptr_index| 8447 sema.code.instructions.items(.tag)[ptr_index] == .ret_type 8448 else 8449 false; 8450 const dest_ty = try sema.resolveType(block, src, zir_dest_type); 8451 const operand = try sema.resolveInst(zir_operand); 8452 if (dest_ty.tag() == .var_args_param) return operand; 8453 if (dest_ty.zigTypeTag() == .NoReturn) { 8454 return sema.fail(block, src, "cannot cast to noreturn", .{}); 8455 } 8456 return sema.coerceExtra(block, dest_ty, operand, src, .{ .is_ret = is_ret, .no_cast_to_comptime_int = no_cast_to_comptime_int }) catch |err| switch (err) { 8457 error.NotCoercible => unreachable, 8458 else => |e| return e, 8459 }; 8460 } 8461 8462 fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8463 const tracy = trace(@src()); 8464 defer tracy.end(); 8465 8466 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 8467 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 8468 const ptr = try sema.resolveInst(inst_data.operand); 8469 const ptr_ty = sema.typeOf(ptr); 8470 if (!ptr_ty.isPtrAtRuntime()) { 8471 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}); 8472 } 8473 if (try sema.resolveMaybeUndefValIntable(block, ptr_src, ptr)) |ptr_val| { 8474 return sema.addConstant(Type.usize, ptr_val); 8475 } 8476 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); 8477 return block.addUnOp(.ptrtoint, ptr); 8478 } 8479 8480 fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8481 const tracy = trace(@src()); 8482 defer tracy.end(); 8483 8484 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8485 const src = inst_data.src(); 8486 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; 8487 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; 8488 const field_name = sema.code.nullTerminatedString(extra.field_name_start); 8489 const object = try sema.resolveInst(extra.lhs); 8490 return sema.fieldVal(block, src, object, field_name, field_name_src); 8491 } 8492 8493 fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: bool) CompileError!Air.Inst.Ref { 8494 const tracy = trace(@src()); 8495 defer tracy.end(); 8496 8497 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8498 const src = inst_data.src(); 8499 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; 8500 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; 8501 const field_name = sema.code.nullTerminatedString(extra.field_name_start); 8502 const object_ptr = try sema.resolveInst(extra.lhs); 8503 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing); 8504 } 8505 8506 fn zirFieldCallBind(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8507 const tracy = trace(@src()); 8508 defer tracy.end(); 8509 8510 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8511 const src = inst_data.src(); 8512 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; 8513 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; 8514 const field_name = sema.code.nullTerminatedString(extra.field_name_start); 8515 const object_ptr = try sema.resolveInst(extra.lhs); 8516 return sema.fieldCallBind(block, src, object_ptr, field_name, field_name_src); 8517 } 8518 8519 fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8520 const tracy = trace(@src()); 8521 defer tracy.end(); 8522 8523 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8524 const src = inst_data.src(); 8525 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 8526 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; 8527 const object = try sema.resolveInst(extra.lhs); 8528 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime known"); 8529 return sema.fieldVal(block, src, object, field_name, field_name_src); 8530 } 8531 8532 fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8533 const tracy = trace(@src()); 8534 defer tracy.end(); 8535 8536 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8537 const src = inst_data.src(); 8538 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 8539 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; 8540 const object_ptr = try sema.resolveInst(extra.lhs); 8541 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime known"); 8542 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false); 8543 } 8544 8545 fn zirFieldCallBindNamed(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 8546 const tracy = trace(@src()); 8547 defer tracy.end(); 8548 8549 const extra = sema.code.extraData(Zir.Inst.FieldNamedNode, extended.operand).data; 8550 const src = LazySrcLoc.nodeOffset(extra.node); 8551 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 8552 const object_ptr = try sema.resolveInst(extra.lhs); 8553 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime known"); 8554 return sema.fieldCallBind(block, src, object_ptr, field_name, field_name_src); 8555 } 8556 8557 fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8558 const tracy = trace(@src()); 8559 defer tracy.end(); 8560 8561 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8562 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 8563 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 8564 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 8565 8566 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); 8567 const operand = try sema.resolveInst(extra.rhs); 8568 8569 return sema.intCast(block, inst_data.src(), dest_ty, dest_ty_src, operand, operand_src, true); 8570 } 8571 8572 fn intCast( 8573 sema: *Sema, 8574 block: *Block, 8575 src: LazySrcLoc, 8576 dest_ty: Type, 8577 dest_ty_src: LazySrcLoc, 8578 operand: Air.Inst.Ref, 8579 operand_src: LazySrcLoc, 8580 runtime_safety: bool, 8581 ) CompileError!Air.Inst.Ref { 8582 const operand_ty = sema.typeOf(operand); 8583 const dest_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, dest_ty, dest_ty_src); 8584 const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); 8585 8586 if (try sema.isComptimeKnown(block, operand_src, operand)) { 8587 return sema.coerce(block, dest_ty, operand, operand_src); 8588 } else if (dest_scalar_ty.zigTypeTag() == .ComptimeInt) { 8589 return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{}); 8590 } 8591 8592 try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, dest_ty_src, operand_src); 8593 const is_vector = dest_ty.zigTypeTag() == .Vector; 8594 8595 if ((try sema.typeHasOnePossibleValue(block, dest_ty_src, dest_ty))) |opv| { 8596 // requirement: intCast(u0, input) iff input == 0 8597 if (runtime_safety and block.wantSafety()) { 8598 try sema.requireRuntimeBlock(block, src, operand_src); 8599 const target = sema.mod.getTarget(); 8600 const wanted_info = dest_scalar_ty.intInfo(target); 8601 const wanted_bits = wanted_info.bits; 8602 8603 if (wanted_bits == 0) { 8604 const zero_inst = try sema.addConstant(sema.typeOf(operand), Value.zero); 8605 const is_in_range = try block.addBinOp(.cmp_eq, operand, zero_inst); 8606 try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data); 8607 } 8608 } 8609 8610 return sema.addConstant(dest_ty, opv); 8611 } 8612 8613 try sema.requireRuntimeBlock(block, src, operand_src); 8614 if (runtime_safety and block.wantSafety()) { 8615 const target = sema.mod.getTarget(); 8616 const actual_info = operand_scalar_ty.intInfo(target); 8617 const wanted_info = dest_scalar_ty.intInfo(target); 8618 const actual_bits = actual_info.bits; 8619 const wanted_bits = wanted_info.bits; 8620 const actual_value_bits = actual_bits - @boolToInt(actual_info.signedness == .signed); 8621 const wanted_value_bits = wanted_bits - @boolToInt(wanted_info.signedness == .signed); 8622 8623 // range shrinkage 8624 // requirement: int value fits into target type 8625 if (wanted_value_bits < actual_value_bits) { 8626 const dest_max_val_scalar = try dest_scalar_ty.maxInt(sema.arena, target); 8627 const dest_max_val = if (is_vector) 8628 try Value.Tag.repeated.create(sema.arena, dest_max_val_scalar) 8629 else 8630 dest_max_val_scalar; 8631 const dest_max = try sema.addConstant(operand_ty, dest_max_val); 8632 const diff = try block.addBinOp(.subwrap, dest_max, operand); 8633 8634 if (actual_info.signedness == .signed) { 8635 // Reinterpret the sign-bit as part of the value. This will make 8636 // negative differences (`operand` > `dest_max`) appear too big. 8637 const unsigned_operand_ty = try Type.Tag.int_unsigned.create(sema.arena, actual_bits); 8638 const diff_unsigned = try block.addBitCast(unsigned_operand_ty, diff); 8639 8640 // If the destination type is signed, then we need to double its 8641 // range to account for negative values. 8642 const dest_range_val = if (wanted_info.signedness == .signed) range_val: { 8643 const range_minus_one = try dest_max_val.shl(Value.one, unsigned_operand_ty, sema.arena, target); 8644 break :range_val try sema.intAdd(block, operand_src, range_minus_one, Value.one, unsigned_operand_ty); 8645 } else dest_max_val; 8646 const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val); 8647 8648 const ok = if (is_vector) ok: { 8649 const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte, try sema.addType(operand_ty)); 8650 const all_in_range = try block.addInst(.{ 8651 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, 8652 .data = .{ .reduce = .{ 8653 .operand = is_in_range, 8654 .operation = .And, 8655 } }, 8656 }); 8657 break :ok all_in_range; 8658 } else ok: { 8659 const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range); 8660 break :ok is_in_range; 8661 }; 8662 // TODO negative_to_unsigned? 8663 try sema.addSafetyCheck(block, ok, .cast_truncated_data); 8664 } else { 8665 const ok = if (is_vector) ok: { 8666 const is_in_range = try block.addCmpVector(diff, dest_max, .lte, try sema.addType(operand_ty)); 8667 const all_in_range = try block.addInst(.{ 8668 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, 8669 .data = .{ .reduce = .{ 8670 .operand = is_in_range, 8671 .operation = .And, 8672 } }, 8673 }); 8674 break :ok all_in_range; 8675 } else ok: { 8676 const is_in_range = try block.addBinOp(.cmp_lte, diff, dest_max); 8677 break :ok is_in_range; 8678 }; 8679 try sema.addSafetyCheck(block, ok, .cast_truncated_data); 8680 } 8681 } else if (actual_info.signedness == .signed and wanted_info.signedness == .unsigned) { 8682 // no shrinkage, yes sign loss 8683 // requirement: signed to unsigned >= 0 8684 const ok = if (is_vector) ok: { 8685 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); 8686 const zero_inst = try sema.addConstant(operand_ty, zero_val); 8687 const is_in_range = try block.addCmpVector(operand, zero_inst, .gte, try sema.addType(operand_ty)); 8688 const all_in_range = try block.addInst(.{ 8689 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, 8690 .data = .{ .reduce = .{ 8691 .operand = is_in_range, 8692 .operation = .And, 8693 } }, 8694 }); 8695 break :ok all_in_range; 8696 } else ok: { 8697 const zero_inst = try sema.addConstant(operand_ty, Value.zero); 8698 const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst); 8699 break :ok is_in_range; 8700 }; 8701 try sema.addSafetyCheck(block, ok, .negative_to_unsigned); 8702 } 8703 } 8704 return block.addTyOp(.intcast, dest_ty, operand); 8705 } 8706 8707 fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8708 const tracy = trace(@src()); 8709 defer tracy.end(); 8710 8711 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8712 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 8713 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 8714 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 8715 8716 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); 8717 const operand = try sema.resolveInst(extra.rhs); 8718 const operand_ty = sema.typeOf(operand); 8719 switch (dest_ty.zigTypeTag()) { 8720 .AnyFrame, 8721 .ComptimeFloat, 8722 .ComptimeInt, 8723 .EnumLiteral, 8724 .ErrorSet, 8725 .ErrorUnion, 8726 .Fn, 8727 .Frame, 8728 .NoReturn, 8729 .Null, 8730 .Opaque, 8731 .Optional, 8732 .Type, 8733 .Undefined, 8734 .Void, 8735 => return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)}), 8736 8737 .Enum => { 8738 const msg = msg: { 8739 const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)}); 8740 errdefer msg.destroy(sema.gpa); 8741 switch (operand_ty.zigTypeTag()) { 8742 .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToEnum to cast from '{}'", .{operand_ty.fmt(sema.mod)}), 8743 else => {}, 8744 } 8745 8746 break :msg msg; 8747 }; 8748 return sema.failWithOwnedErrorMsg(msg); 8749 }, 8750 8751 .Pointer => { 8752 const msg = msg: { 8753 const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)}); 8754 errdefer msg.destroy(sema.gpa); 8755 switch (operand_ty.zigTypeTag()) { 8756 .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToPtr to cast from '{}'", .{operand_ty.fmt(sema.mod)}), 8757 .Pointer => try sema.errNote(block, dest_ty_src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(sema.mod)}), 8758 else => {}, 8759 } 8760 8761 break :msg msg; 8762 }; 8763 return sema.failWithOwnedErrorMsg(msg); 8764 }, 8765 .Struct, .Union => if (dest_ty.containerLayout() == .Auto) { 8766 const container = switch (dest_ty.zigTypeTag()) { 8767 .Struct => "struct", 8768 .Union => "union", 8769 else => unreachable, 8770 }; 8771 return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}', {s} does not have a guaranteed in-memory layout", .{ 8772 dest_ty.fmt(sema.mod), container, 8773 }); 8774 }, 8775 .BoundFn => @panic("TODO remove this type from the language and compiler"), 8776 8777 .Array, 8778 .Bool, 8779 .Float, 8780 .Int, 8781 .Vector, 8782 => {}, 8783 } 8784 switch (operand_ty.zigTypeTag()) { 8785 .AnyFrame, 8786 .ComptimeFloat, 8787 .ComptimeInt, 8788 .EnumLiteral, 8789 .ErrorSet, 8790 .ErrorUnion, 8791 .Fn, 8792 .Frame, 8793 .NoReturn, 8794 .Null, 8795 .Opaque, 8796 .Optional, 8797 .Type, 8798 .Undefined, 8799 .Void, 8800 => return sema.fail(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)}), 8801 8802 .Enum => { 8803 const msg = msg: { 8804 const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)}); 8805 errdefer msg.destroy(sema.gpa); 8806 switch (dest_ty.zigTypeTag()) { 8807 .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @enumToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}), 8808 else => {}, 8809 } 8810 8811 break :msg msg; 8812 }; 8813 return sema.failWithOwnedErrorMsg(msg); 8814 }, 8815 .Pointer => { 8816 const msg = msg: { 8817 const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)}); 8818 errdefer msg.destroy(sema.gpa); 8819 switch (dest_ty.zigTypeTag()) { 8820 .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @ptrToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}), 8821 .Pointer => try sema.errNote(block, operand_src, msg, "use @ptrCast to cast to '{}'", .{dest_ty.fmt(sema.mod)}), 8822 else => {}, 8823 } 8824 8825 break :msg msg; 8826 }; 8827 return sema.failWithOwnedErrorMsg(msg); 8828 }, 8829 .Struct, .Union => if (operand_ty.containerLayout() == .Auto) { 8830 const container = switch (operand_ty.zigTypeTag()) { 8831 .Struct => "struct", 8832 .Union => "union", 8833 else => unreachable, 8834 }; 8835 return sema.fail(block, operand_src, "cannot @bitCast from '{}', {s} does not have a guaranteed in-memory layout", .{ 8836 operand_ty.fmt(sema.mod), container, 8837 }); 8838 }, 8839 .BoundFn => @panic("TODO remove this type from the language and compiler"), 8840 8841 .Array, 8842 .Bool, 8843 .Float, 8844 .Int, 8845 .Vector, 8846 => {}, 8847 } 8848 return sema.bitCast(block, dest_ty, operand, operand_src); 8849 } 8850 8851 fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8852 const tracy = trace(@src()); 8853 defer tracy.end(); 8854 8855 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8856 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 8857 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 8858 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 8859 8860 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); 8861 const operand = try sema.resolveInst(extra.rhs); 8862 8863 const target = sema.mod.getTarget(); 8864 const dest_is_comptime_float = switch (dest_ty.zigTypeTag()) { 8865 .ComptimeFloat => true, 8866 .Float => false, 8867 else => return sema.fail( 8868 block, 8869 dest_ty_src, 8870 "expected float type, found '{}'", 8871 .{dest_ty.fmt(sema.mod)}, 8872 ), 8873 }; 8874 8875 const operand_ty = sema.typeOf(operand); 8876 switch (operand_ty.zigTypeTag()) { 8877 .ComptimeFloat, .Float, .ComptimeInt => {}, 8878 else => return sema.fail( 8879 block, 8880 operand_src, 8881 "expected float type, found '{}'", 8882 .{operand_ty.fmt(sema.mod)}, 8883 ), 8884 } 8885 8886 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| { 8887 return sema.addConstant(dest_ty, try operand_val.floatCast(sema.arena, dest_ty, target)); 8888 } 8889 if (dest_is_comptime_float) { 8890 return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_float'", .{}); 8891 } 8892 const src_bits = operand_ty.floatBits(target); 8893 const dst_bits = dest_ty.floatBits(target); 8894 if (dst_bits >= src_bits) { 8895 return sema.coerce(block, dest_ty, operand, operand_src); 8896 } 8897 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); 8898 return block.addTyOp(.fptrunc, dest_ty, operand); 8899 } 8900 8901 fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8902 const tracy = trace(@src()); 8903 defer tracy.end(); 8904 8905 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8906 const src = inst_data.src(); 8907 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 8908 const array = try sema.resolveInst(extra.lhs); 8909 const elem_index = try sema.resolveInst(extra.rhs); 8910 return sema.elemVal(block, src, array, elem_index, src); 8911 } 8912 8913 fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8914 const tracy = trace(@src()); 8915 defer tracy.end(); 8916 8917 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8918 const src = inst_data.src(); 8919 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node }; 8920 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 8921 const array = try sema.resolveInst(extra.lhs); 8922 const elem_index = try sema.resolveInst(extra.rhs); 8923 return sema.elemVal(block, src, array, elem_index, elem_index_src); 8924 } 8925 8926 fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8927 const tracy = trace(@src()); 8928 defer tracy.end(); 8929 8930 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8931 const src = inst_data.src(); 8932 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 8933 const array_ptr = try sema.resolveInst(extra.lhs); 8934 const elem_index = try sema.resolveInst(extra.rhs); 8935 return sema.elemPtr(block, src, array_ptr, elem_index, src, false); 8936 } 8937 8938 fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8939 const tracy = trace(@src()); 8940 defer tracy.end(); 8941 8942 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8943 const src = inst_data.src(); 8944 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node }; 8945 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 8946 const array_ptr = try sema.resolveInst(extra.lhs); 8947 const elem_index = try sema.resolveInst(extra.rhs); 8948 return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false); 8949 } 8950 8951 fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8952 const tracy = trace(@src()); 8953 defer tracy.end(); 8954 8955 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8956 const src = inst_data.src(); 8957 const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data; 8958 const array_ptr = try sema.resolveInst(extra.ptr); 8959 const elem_index = try sema.addIntUnsigned(Type.usize, extra.index); 8960 return sema.elemPtr(block, src, array_ptr, elem_index, src, true); 8961 } 8962 8963 fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8964 const tracy = trace(@src()); 8965 defer tracy.end(); 8966 8967 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8968 const src = inst_data.src(); 8969 const extra = sema.code.extraData(Zir.Inst.SliceStart, inst_data.payload_index).data; 8970 const array_ptr = try sema.resolveInst(extra.lhs); 8971 const start = try sema.resolveInst(extra.start); 8972 8973 return sema.analyzeSlice(block, src, array_ptr, start, .none, .none, .unneeded); 8974 } 8975 8976 fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8977 const tracy = trace(@src()); 8978 defer tracy.end(); 8979 8980 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8981 const src = inst_data.src(); 8982 const extra = sema.code.extraData(Zir.Inst.SliceEnd, inst_data.payload_index).data; 8983 const array_ptr = try sema.resolveInst(extra.lhs); 8984 const start = try sema.resolveInst(extra.start); 8985 const end = try sema.resolveInst(extra.end); 8986 8987 return sema.analyzeSlice(block, src, array_ptr, start, end, .none, .unneeded); 8988 } 8989 8990 fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 8991 const tracy = trace(@src()); 8992 defer tracy.end(); 8993 8994 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 8995 const src = inst_data.src(); 8996 const sentinel_src: LazySrcLoc = .{ .node_offset_slice_sentinel = inst_data.src_node }; 8997 const extra = sema.code.extraData(Zir.Inst.SliceSentinel, inst_data.payload_index).data; 8998 const array_ptr = try sema.resolveInst(extra.lhs); 8999 const start = try sema.resolveInst(extra.start); 9000 const end = try sema.resolveInst(extra.end); 9001 const sentinel = try sema.resolveInst(extra.sentinel); 9002 9003 return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src); 9004 } 9005 9006 fn zirSwitchCapture( 9007 sema: *Sema, 9008 block: *Block, 9009 inst: Zir.Inst.Index, 9010 is_multi: bool, 9011 is_ref: bool, 9012 ) CompileError!Air.Inst.Ref { 9013 const tracy = trace(@src()); 9014 defer tracy.end(); 9015 9016 const zir_datas = sema.code.instructions.items(.data); 9017 const capture_info = zir_datas[inst].switch_capture; 9018 const switch_info = zir_datas[capture_info.switch_inst].pl_node; 9019 const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index); 9020 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_info.src_node }; 9021 const operand_is_ref = switch_extra.data.bits.is_ref; 9022 const cond_inst = Zir.refToIndex(switch_extra.data.operand).?; 9023 const cond_info = sema.code.instructions.items(.data)[cond_inst].un_node; 9024 const operand_ptr = try sema.resolveInst(cond_info.operand); 9025 const operand_ptr_ty = sema.typeOf(operand_ptr); 9026 const operand_ty = if (operand_is_ref) operand_ptr_ty.childType() else operand_ptr_ty; 9027 9028 const operand = if (operand_is_ref) 9029 try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src) 9030 else 9031 operand_ptr; 9032 9033 if (capture_info.prong_index == std.math.maxInt(@TypeOf(capture_info.prong_index))) { 9034 // It is the else/`_` prong. 9035 if (is_ref) { 9036 assert(operand_is_ref); 9037 return operand_ptr; 9038 } 9039 9040 switch (operand_ty.zigTypeTag()) { 9041 .ErrorSet => if (block.switch_else_err_ty) |some| { 9042 return sema.bitCast(block, some, operand, operand_src); 9043 } else { 9044 try block.addUnreachable(operand_src, false); 9045 return Air.Inst.Ref.unreachable_value; 9046 }, 9047 else => return operand, 9048 } 9049 } 9050 9051 const items = if (is_multi) 9052 switch_extra.data.getMultiProng(sema.code, switch_extra.end, capture_info.prong_index).items 9053 else 9054 &[_]Zir.Inst.Ref{ 9055 switch_extra.data.getScalarProng(sema.code, switch_extra.end, capture_info.prong_index).item, 9056 }; 9057 9058 switch (operand_ty.zigTypeTag()) { 9059 .Union => { 9060 const union_obj = operand_ty.cast(Type.Payload.Union).?.data; 9061 const first_item = try sema.resolveInst(items[0]); 9062 // Previous switch validation ensured this will succeed 9063 const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, undefined) catch unreachable; 9064 9065 const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, sema.mod).?); 9066 const first_field = union_obj.fields.values()[first_field_index]; 9067 9068 for (items[1..]) |item, i| { 9069 const item_ref = try sema.resolveInst(item); 9070 // Previous switch validation ensured this will succeed 9071 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, undefined) catch unreachable; 9072 9073 const field_index = operand_ty.unionTagFieldIndex(item_val, sema.mod).?; 9074 const field = union_obj.fields.values()[field_index]; 9075 if (!field.ty.eql(first_field.ty, sema.mod)) { 9076 const msg = msg: { 9077 const raw_capture_src = Module.SwitchProngSrc{ .multi_capture = capture_info.prong_index }; 9078 const capture_src = raw_capture_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first); 9079 9080 const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{}); 9081 errdefer msg.destroy(sema.gpa); 9082 9083 const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 0 } }; 9084 const first_item_src = raw_first_item_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first); 9085 const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 1 + @intCast(u32, i) } }; 9086 const item_src = raw_item_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first); 9087 try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(sema.mod)}); 9088 try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(sema.mod)}); 9089 break :msg msg; 9090 }; 9091 return sema.failWithOwnedErrorMsg(msg); 9092 } 9093 } 9094 9095 if (is_ref) { 9096 assert(operand_is_ref); 9097 9098 const field_ty_ptr = try Type.ptr(sema.arena, sema.mod, .{ 9099 .pointee_type = first_field.ty, 9100 .@"addrspace" = .generic, 9101 .mutable = operand_ptr_ty.ptrIsMutable(), 9102 }); 9103 9104 if (try sema.resolveDefinedValue(block, operand_src, operand_ptr)) |op_ptr_val| { 9105 return sema.addConstant( 9106 field_ty_ptr, 9107 try Value.Tag.field_ptr.create(sema.arena, .{ 9108 .container_ptr = op_ptr_val, 9109 .container_ty = operand_ty, 9110 .field_index = first_field_index, 9111 }), 9112 ); 9113 } 9114 try sema.requireRuntimeBlock(block, operand_src, null); 9115 return block.addStructFieldPtr(operand_ptr, first_field_index, field_ty_ptr); 9116 } 9117 9118 if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| { 9119 return sema.addConstant( 9120 first_field.ty, 9121 operand_val.castTag(.@"union").?.data.val, 9122 ); 9123 } 9124 try sema.requireRuntimeBlock(block, operand_src, null); 9125 return block.addStructFieldVal(operand, first_field_index, first_field.ty); 9126 }, 9127 .ErrorSet => { 9128 if (is_multi) { 9129 var names: Module.ErrorSet.NameMap = .{}; 9130 try names.ensureUnusedCapacity(sema.arena, items.len); 9131 for (items) |item| { 9132 const item_ref = try sema.resolveInst(item); 9133 // Previous switch validation ensured this will succeed 9134 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, undefined) catch unreachable; 9135 names.putAssumeCapacityNoClobber( 9136 item_val.getError().?, 9137 {}, 9138 ); 9139 } 9140 // names must be sorted 9141 Module.ErrorSet.sortNames(&names); 9142 const else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names); 9143 9144 return sema.bitCast(block, else_error_ty, operand, operand_src); 9145 } else { 9146 const item_ref = try sema.resolveInst(items[0]); 9147 // Previous switch validation ensured this will succeed 9148 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, undefined) catch unreachable; 9149 9150 const item_ty = try Type.Tag.error_set_single.create(sema.arena, item_val.getError().?); 9151 return sema.bitCast(block, item_ty, operand, operand_src); 9152 } 9153 }, 9154 else => { 9155 // In this case the capture value is just the passed-through value of the 9156 // switch condition. 9157 if (is_ref) { 9158 assert(operand_is_ref); 9159 return operand_ptr; 9160 } else { 9161 return operand; 9162 } 9163 }, 9164 } 9165 } 9166 9167 fn zirSwitchCond( 9168 sema: *Sema, 9169 block: *Block, 9170 inst: Zir.Inst.Index, 9171 is_ref: bool, 9172 ) CompileError!Air.Inst.Ref { 9173 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 9174 const src = inst_data.src(); 9175 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node }; 9176 const operand_ptr = try sema.resolveInst(inst_data.operand); 9177 const operand = if (is_ref) 9178 try sema.analyzeLoad(block, src, operand_ptr, operand_src) 9179 else 9180 operand_ptr; 9181 const operand_ty = sema.typeOf(operand); 9182 9183 switch (operand_ty.zigTypeTag()) { 9184 .Type, 9185 .Void, 9186 .Bool, 9187 .Int, 9188 .Float, 9189 .ComptimeFloat, 9190 .ComptimeInt, 9191 .EnumLiteral, 9192 .Pointer, 9193 .Fn, 9194 .ErrorSet, 9195 .Enum, 9196 => { 9197 if (operand_ty.isSlice()) { 9198 return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)}); 9199 } 9200 if ((try sema.typeHasOnePossibleValue(block, operand_src, operand_ty))) |opv| { 9201 return sema.addConstant(operand_ty, opv); 9202 } 9203 return operand; 9204 }, 9205 9206 .Union => { 9207 const union_ty = try sema.resolveTypeFields(block, operand_src, operand_ty); 9208 const enum_ty = union_ty.unionTagType() orelse { 9209 const msg = msg: { 9210 const msg = try sema.errMsg(block, src, "switch on union with no attached enum", .{}); 9211 errdefer msg.destroy(sema.gpa); 9212 if (union_ty.declSrcLocOrNull(sema.mod)) |union_src| { 9213 try sema.mod.errNoteNonLazy(union_src, msg, "consider 'union(enum)' here", .{}); 9214 } 9215 break :msg msg; 9216 }; 9217 return sema.failWithOwnedErrorMsg(msg); 9218 }; 9219 return sema.unionToTag(block, enum_ty, operand, src); 9220 }, 9221 9222 .ErrorUnion, 9223 .NoReturn, 9224 .Array, 9225 .Struct, 9226 .Undefined, 9227 .Null, 9228 .Optional, 9229 .BoundFn, 9230 .Opaque, 9231 .Vector, 9232 .Frame, 9233 .AnyFrame, 9234 => return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)}), 9235 } 9236 } 9237 9238 const SwitchErrorSet = std.StringHashMap(Module.SwitchProngSrc); 9239 9240 fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 9241 const tracy = trace(@src()); 9242 defer tracy.end(); 9243 9244 const gpa = sema.gpa; 9245 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 9246 const src = inst_data.src(); 9247 const src_node_offset = inst_data.src_node; 9248 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset }; 9249 const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset }; 9250 const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); 9251 9252 const operand = try sema.resolveInst(extra.data.operand); 9253 9254 var header_extra_index: usize = extra.end; 9255 9256 const scalar_cases_len = extra.data.bits.scalar_cases_len; 9257 const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: { 9258 const multi_cases_len = sema.code.extra[header_extra_index]; 9259 header_extra_index += 1; 9260 break :blk multi_cases_len; 9261 } else 0; 9262 9263 const special_prong = extra.data.bits.specialProng(); 9264 const special: struct { body: []const Zir.Inst.Index, end: usize } = switch (special_prong) { 9265 .none => .{ .body = &.{}, .end = header_extra_index }, 9266 .under, .@"else" => blk: { 9267 const body_len = sema.code.extra[header_extra_index]; 9268 const extra_body_start = header_extra_index + 1; 9269 break :blk .{ 9270 .body = sema.code.extra[extra_body_start..][0..body_len], 9271 .end = extra_body_start + body_len, 9272 }; 9273 }, 9274 }; 9275 9276 const maybe_union_ty = blk: { 9277 const zir_data = sema.code.instructions.items(.data); 9278 const cond_index = Zir.refToIndex(extra.data.operand).?; 9279 const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable; 9280 break :blk sema.typeOf(raw_operand); 9281 }; 9282 const union_originally = maybe_union_ty.zigTypeTag() == .Union; 9283 var seen_union_fields: []?Module.SwitchProngSrc = &.{}; 9284 defer gpa.free(seen_union_fields); 9285 9286 var empty_enum = false; 9287 9288 const operand_ty = sema.typeOf(operand); 9289 const err_set = operand_ty.zigTypeTag() == .ErrorSet; 9290 9291 var else_error_ty: ?Type = null; 9292 9293 // Validate usage of '_' prongs. 9294 if (special_prong == .under and (!operand_ty.isNonexhaustiveEnum() or union_originally)) { 9295 const msg = msg: { 9296 const msg = try sema.errMsg( 9297 block, 9298 src, 9299 "'_' prong only allowed when switching on non-exhaustive enums", 9300 .{}, 9301 ); 9302 errdefer msg.destroy(gpa); 9303 try sema.errNote( 9304 block, 9305 special_prong_src, 9306 msg, 9307 "'_' prong here", 9308 .{}, 9309 ); 9310 break :msg msg; 9311 }; 9312 return sema.failWithOwnedErrorMsg(msg); 9313 } 9314 9315 const target = sema.mod.getTarget(); 9316 9317 // Validate for duplicate items, missing else prong, and invalid range. 9318 switch (operand_ty.zigTypeTag()) { 9319 .Union => unreachable, // handled in zirSwitchCond 9320 .Enum => { 9321 var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount()); 9322 empty_enum = seen_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(); 9323 defer if (!union_originally) gpa.free(seen_fields); 9324 if (union_originally) seen_union_fields = seen_fields; 9325 mem.set(?Module.SwitchProngSrc, seen_fields, null); 9326 9327 // This is used for non-exhaustive enum values that do not correspond to any tags. 9328 var range_set = RangeSet.init(gpa, sema.mod); 9329 defer range_set.deinit(); 9330 9331 var extra_index: usize = special.end; 9332 { 9333 var scalar_i: u32 = 0; 9334 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 9335 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 9336 extra_index += 1; 9337 const body_len = sema.code.extra[extra_index]; 9338 extra_index += 1; 9339 extra_index += body_len; 9340 9341 try sema.validateSwitchItemEnum( 9342 block, 9343 seen_fields, 9344 &range_set, 9345 item_ref, 9346 src_node_offset, 9347 .{ .scalar = scalar_i }, 9348 ); 9349 } 9350 } 9351 { 9352 var multi_i: u32 = 0; 9353 while (multi_i < multi_cases_len) : (multi_i += 1) { 9354 const items_len = sema.code.extra[extra_index]; 9355 extra_index += 1; 9356 const ranges_len = sema.code.extra[extra_index]; 9357 extra_index += 1; 9358 const body_len = sema.code.extra[extra_index]; 9359 extra_index += 1; 9360 const items = sema.code.refSlice(extra_index, items_len); 9361 extra_index += items_len + body_len; 9362 9363 for (items) |item_ref, item_i| { 9364 try sema.validateSwitchItemEnum( 9365 block, 9366 seen_fields, 9367 &range_set, 9368 item_ref, 9369 src_node_offset, 9370 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, 9371 ); 9372 } 9373 9374 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); 9375 } 9376 } 9377 const all_tags_handled = for (seen_fields) |seen_src| { 9378 if (seen_src == null) break false; 9379 } else true; 9380 9381 if (special_prong == .@"else") { 9382 if (all_tags_handled and !operand_ty.isNonexhaustiveEnum()) return sema.fail( 9383 block, 9384 special_prong_src, 9385 "unreachable else prong; all cases already handled", 9386 .{}, 9387 ); 9388 } else if (!all_tags_handled) { 9389 const msg = msg: { 9390 const msg = try sema.errMsg( 9391 block, 9392 src, 9393 "switch must handle all possibilities", 9394 .{}, 9395 ); 9396 errdefer msg.destroy(sema.gpa); 9397 for (seen_fields) |seen_src, i| { 9398 if (seen_src != null) continue; 9399 9400 const field_name = operand_ty.enumFieldName(i); 9401 try sema.addFieldErrNote( 9402 operand_ty, 9403 i, 9404 msg, 9405 "unhandled enumeration value: '{s}'", 9406 .{field_name}, 9407 ); 9408 } 9409 try sema.mod.errNoteNonLazy( 9410 operand_ty.declSrcLoc(sema.mod), 9411 msg, 9412 "enum '{}' declared here", 9413 .{operand_ty.fmt(sema.mod)}, 9414 ); 9415 break :msg msg; 9416 }; 9417 return sema.failWithOwnedErrorMsg(msg); 9418 } else if (special_prong == .none and operand_ty.isNonexhaustiveEnum() and !union_originally) { 9419 return sema.fail( 9420 block, 9421 src, 9422 "switch on non-exhaustive enum must include 'else' or '_' prong", 9423 .{}, 9424 ); 9425 } 9426 }, 9427 .ErrorSet => { 9428 var seen_errors = SwitchErrorSet.init(gpa); 9429 defer seen_errors.deinit(); 9430 9431 var extra_index: usize = special.end; 9432 { 9433 var scalar_i: u32 = 0; 9434 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 9435 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 9436 extra_index += 1; 9437 const body_len = sema.code.extra[extra_index]; 9438 extra_index += 1; 9439 extra_index += body_len; 9440 9441 try sema.validateSwitchItemError( 9442 block, 9443 &seen_errors, 9444 item_ref, 9445 src_node_offset, 9446 .{ .scalar = scalar_i }, 9447 ); 9448 } 9449 } 9450 { 9451 var multi_i: u32 = 0; 9452 while (multi_i < multi_cases_len) : (multi_i += 1) { 9453 const items_len = sema.code.extra[extra_index]; 9454 extra_index += 1; 9455 const ranges_len = sema.code.extra[extra_index]; 9456 extra_index += 1; 9457 const body_len = sema.code.extra[extra_index]; 9458 extra_index += 1; 9459 const items = sema.code.refSlice(extra_index, items_len); 9460 extra_index += items_len + body_len; 9461 9462 for (items) |item_ref, item_i| { 9463 try sema.validateSwitchItemError( 9464 block, 9465 &seen_errors, 9466 item_ref, 9467 src_node_offset, 9468 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, 9469 ); 9470 } 9471 9472 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); 9473 } 9474 } 9475 9476 try sema.resolveInferredErrorSetTy(block, src, operand_ty); 9477 9478 if (operand_ty.isAnyError()) { 9479 if (special_prong != .@"else") { 9480 return sema.fail( 9481 block, 9482 src, 9483 "else prong required when switching on type 'anyerror'", 9484 .{}, 9485 ); 9486 } 9487 else_error_ty = Type.@"anyerror"; 9488 } else else_validation: { 9489 var maybe_msg: ?*Module.ErrorMsg = null; 9490 errdefer if (maybe_msg) |msg| msg.destroy(sema.gpa); 9491 9492 for (operand_ty.errorSetNames()) |error_name| { 9493 if (!seen_errors.contains(error_name) and special_prong != .@"else") { 9494 const msg = maybe_msg orelse blk: { 9495 maybe_msg = try sema.errMsg( 9496 block, 9497 src, 9498 "switch must handle all possibilities", 9499 .{}, 9500 ); 9501 break :blk maybe_msg.?; 9502 }; 9503 9504 try sema.errNote( 9505 block, 9506 src, 9507 msg, 9508 "unhandled error value: 'error.{s}'", 9509 .{error_name}, 9510 ); 9511 } 9512 } 9513 9514 if (maybe_msg) |msg| { 9515 maybe_msg = null; 9516 try sema.addDeclaredHereNote(msg, operand_ty); 9517 return sema.failWithOwnedErrorMsg(msg); 9518 } 9519 9520 if (special_prong == .@"else" and seen_errors.count() == operand_ty.errorSetNames().len) { 9521 // In order to enable common patterns for generic code allow simple else bodies 9522 // else => unreachable, 9523 // else => return, 9524 // else => |e| return e, 9525 // even if all the possible errors were already handled. 9526 const tags = sema.code.instructions.items(.tag); 9527 for (special.body) |else_inst| switch (tags[else_inst]) { 9528 .dbg_block_begin, 9529 .dbg_block_end, 9530 .dbg_stmt, 9531 .dbg_var_val, 9532 .switch_capture, 9533 .ret_type, 9534 .as_node, 9535 .ret_node, 9536 .@"unreachable", 9537 .@"defer", 9538 .defer_err_code, 9539 .err_union_code, 9540 .ret_err_value_code, 9541 .is_non_err, 9542 .condbr, 9543 => {}, 9544 else => break, 9545 } else break :else_validation; 9546 9547 return sema.fail( 9548 block, 9549 special_prong_src, 9550 "unreachable else prong; all cases already handled", 9551 .{}, 9552 ); 9553 } 9554 9555 const error_names = operand_ty.errorSetNames(); 9556 var names: Module.ErrorSet.NameMap = .{}; 9557 try names.ensureUnusedCapacity(sema.arena, error_names.len); 9558 for (error_names) |error_name| { 9559 if (seen_errors.contains(error_name)) continue; 9560 9561 names.putAssumeCapacityNoClobber(error_name, {}); 9562 } 9563 9564 // names must be sorted 9565 Module.ErrorSet.sortNames(&names); 9566 else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names); 9567 } 9568 }, 9569 .Int, .ComptimeInt => { 9570 var range_set = RangeSet.init(gpa, sema.mod); 9571 defer range_set.deinit(); 9572 9573 var extra_index: usize = special.end; 9574 { 9575 var scalar_i: u32 = 0; 9576 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 9577 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 9578 extra_index += 1; 9579 const body_len = sema.code.extra[extra_index]; 9580 extra_index += 1; 9581 extra_index += body_len; 9582 9583 try sema.validateSwitchItem( 9584 block, 9585 &range_set, 9586 item_ref, 9587 operand_ty, 9588 src_node_offset, 9589 .{ .scalar = scalar_i }, 9590 ); 9591 } 9592 } 9593 { 9594 var multi_i: u32 = 0; 9595 while (multi_i < multi_cases_len) : (multi_i += 1) { 9596 const items_len = sema.code.extra[extra_index]; 9597 extra_index += 1; 9598 const ranges_len = sema.code.extra[extra_index]; 9599 extra_index += 1; 9600 const body_len = sema.code.extra[extra_index]; 9601 extra_index += 1; 9602 const items = sema.code.refSlice(extra_index, items_len); 9603 extra_index += items_len; 9604 9605 for (items) |item_ref, item_i| { 9606 try sema.validateSwitchItem( 9607 block, 9608 &range_set, 9609 item_ref, 9610 operand_ty, 9611 src_node_offset, 9612 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, 9613 ); 9614 } 9615 9616 var range_i: u32 = 0; 9617 while (range_i < ranges_len) : (range_i += 1) { 9618 const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 9619 extra_index += 1; 9620 const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 9621 extra_index += 1; 9622 9623 try sema.validateSwitchRange( 9624 block, 9625 &range_set, 9626 item_first, 9627 item_last, 9628 operand_ty, 9629 src_node_offset, 9630 .{ .range = .{ .prong = multi_i, .item = range_i } }, 9631 ); 9632 } 9633 9634 extra_index += body_len; 9635 } 9636 } 9637 9638 check_range: { 9639 if (operand_ty.zigTypeTag() == .Int) { 9640 var arena = std.heap.ArenaAllocator.init(gpa); 9641 defer arena.deinit(); 9642 9643 const min_int = try operand_ty.minInt(arena.allocator(), target); 9644 const max_int = try operand_ty.maxInt(arena.allocator(), target); 9645 if (try range_set.spans(min_int, max_int, operand_ty)) { 9646 if (special_prong == .@"else") { 9647 return sema.fail( 9648 block, 9649 special_prong_src, 9650 "unreachable else prong; all cases already handled", 9651 .{}, 9652 ); 9653 } 9654 break :check_range; 9655 } 9656 } 9657 if (special_prong != .@"else") { 9658 return sema.fail( 9659 block, 9660 src, 9661 "switch must handle all possibilities", 9662 .{}, 9663 ); 9664 } 9665 } 9666 }, 9667 .Bool => { 9668 var true_count: u8 = 0; 9669 var false_count: u8 = 0; 9670 9671 var extra_index: usize = special.end; 9672 { 9673 var scalar_i: u32 = 0; 9674 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 9675 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 9676 extra_index += 1; 9677 const body_len = sema.code.extra[extra_index]; 9678 extra_index += 1; 9679 extra_index += body_len; 9680 9681 try sema.validateSwitchItemBool( 9682 block, 9683 &true_count, 9684 &false_count, 9685 item_ref, 9686 src_node_offset, 9687 .{ .scalar = scalar_i }, 9688 ); 9689 } 9690 } 9691 { 9692 var multi_i: u32 = 0; 9693 while (multi_i < multi_cases_len) : (multi_i += 1) { 9694 const items_len = sema.code.extra[extra_index]; 9695 extra_index += 1; 9696 const ranges_len = sema.code.extra[extra_index]; 9697 extra_index += 1; 9698 const body_len = sema.code.extra[extra_index]; 9699 extra_index += 1; 9700 const items = sema.code.refSlice(extra_index, items_len); 9701 extra_index += items_len + body_len; 9702 9703 for (items) |item_ref, item_i| { 9704 try sema.validateSwitchItemBool( 9705 block, 9706 &true_count, 9707 &false_count, 9708 item_ref, 9709 src_node_offset, 9710 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, 9711 ); 9712 } 9713 9714 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); 9715 } 9716 } 9717 switch (special_prong) { 9718 .@"else" => { 9719 if (true_count + false_count == 2) { 9720 return sema.fail( 9721 block, 9722 special_prong_src, 9723 "unreachable else prong; all cases already handled", 9724 .{}, 9725 ); 9726 } 9727 }, 9728 .under, .none => { 9729 if (true_count + false_count < 2) { 9730 return sema.fail( 9731 block, 9732 src, 9733 "switch must handle all possibilities", 9734 .{}, 9735 ); 9736 } 9737 }, 9738 } 9739 }, 9740 .EnumLiteral, .Void, .Fn, .Pointer, .Type => { 9741 if (special_prong != .@"else") { 9742 return sema.fail( 9743 block, 9744 src, 9745 "else prong required when switching on type '{}'", 9746 .{operand_ty.fmt(sema.mod)}, 9747 ); 9748 } 9749 9750 var seen_values = ValueSrcMap.initContext(gpa, .{ 9751 .ty = operand_ty, 9752 .mod = sema.mod, 9753 }); 9754 defer seen_values.deinit(); 9755 9756 var extra_index: usize = special.end; 9757 { 9758 var scalar_i: u32 = 0; 9759 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 9760 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 9761 extra_index += 1; 9762 const body_len = sema.code.extra[extra_index]; 9763 extra_index += 1; 9764 extra_index += body_len; 9765 9766 try sema.validateSwitchItemSparse( 9767 block, 9768 &seen_values, 9769 item_ref, 9770 src_node_offset, 9771 .{ .scalar = scalar_i }, 9772 ); 9773 } 9774 } 9775 { 9776 var multi_i: u32 = 0; 9777 while (multi_i < multi_cases_len) : (multi_i += 1) { 9778 const items_len = sema.code.extra[extra_index]; 9779 extra_index += 1; 9780 const ranges_len = sema.code.extra[extra_index]; 9781 extra_index += 1; 9782 const body_len = sema.code.extra[extra_index]; 9783 extra_index += 1; 9784 const items = sema.code.refSlice(extra_index, items_len); 9785 extra_index += items_len + body_len; 9786 9787 for (items) |item_ref, item_i| { 9788 try sema.validateSwitchItemSparse( 9789 block, 9790 &seen_values, 9791 item_ref, 9792 src_node_offset, 9793 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, 9794 ); 9795 } 9796 9797 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); 9798 } 9799 } 9800 }, 9801 9802 .ErrorUnion, 9803 .NoReturn, 9804 .Array, 9805 .Struct, 9806 .Undefined, 9807 .Null, 9808 .Optional, 9809 .BoundFn, 9810 .Opaque, 9811 .Vector, 9812 .Frame, 9813 .AnyFrame, 9814 .ComptimeFloat, 9815 .Float, 9816 => return sema.fail(block, operand_src, "invalid switch operand type '{}'", .{ 9817 operand_ty.fmt(sema.mod), 9818 }), 9819 } 9820 9821 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 9822 try sema.air_instructions.append(gpa, .{ 9823 .tag = .block, 9824 .data = undefined, 9825 }); 9826 var label: Block.Label = .{ 9827 .zir_block = inst, 9828 .merges = .{ 9829 .results = .{}, 9830 .br_list = .{}, 9831 .block_inst = block_inst, 9832 }, 9833 }; 9834 9835 var child_block: Block = .{ 9836 .parent = block, 9837 .sema = sema, 9838 .src_decl = block.src_decl, 9839 .namespace = block.namespace, 9840 .wip_capture_scope = block.wip_capture_scope, 9841 .instructions = .{}, 9842 .label = &label, 9843 .inlining = block.inlining, 9844 .is_comptime = block.is_comptime, 9845 .switch_else_err_ty = else_error_ty, 9846 .runtime_cond = block.runtime_cond, 9847 .runtime_loop = block.runtime_loop, 9848 .runtime_index = block.runtime_index, 9849 }; 9850 const merges = &child_block.label.?.merges; 9851 defer child_block.instructions.deinit(gpa); 9852 defer merges.results.deinit(gpa); 9853 defer merges.br_list.deinit(gpa); 9854 9855 if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| { 9856 var extra_index: usize = special.end; 9857 { 9858 var scalar_i: usize = 0; 9859 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 9860 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 9861 extra_index += 1; 9862 const body_len = sema.code.extra[extra_index]; 9863 extra_index += 1; 9864 const body = sema.code.extra[extra_index..][0..body_len]; 9865 extra_index += body_len; 9866 9867 const item = try sema.resolveInst(item_ref); 9868 // Validation above ensured these will succeed. 9869 const item_val = sema.resolveConstValue(&child_block, .unneeded, item, undefined) catch unreachable; 9870 if (operand_val.eql(item_val, operand_ty, sema.mod)) { 9871 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); 9872 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); 9873 } 9874 } 9875 } 9876 { 9877 var multi_i: usize = 0; 9878 while (multi_i < multi_cases_len) : (multi_i += 1) { 9879 const items_len = sema.code.extra[extra_index]; 9880 extra_index += 1; 9881 const ranges_len = sema.code.extra[extra_index]; 9882 extra_index += 1; 9883 const body_len = sema.code.extra[extra_index]; 9884 extra_index += 1; 9885 const items = sema.code.refSlice(extra_index, items_len); 9886 extra_index += items_len; 9887 const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..body_len]; 9888 9889 for (items) |item_ref| { 9890 const item = try sema.resolveInst(item_ref); 9891 // Validation above ensured these will succeed. 9892 const item_val = sema.resolveConstValue(&child_block, .unneeded, item, undefined) catch unreachable; 9893 if (operand_val.eql(item_val, operand_ty, sema.mod)) { 9894 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); 9895 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); 9896 } 9897 } 9898 9899 var range_i: usize = 0; 9900 while (range_i < ranges_len) : (range_i += 1) { 9901 const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 9902 extra_index += 1; 9903 const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 9904 extra_index += 1; 9905 9906 // Validation above ensured these will succeed. 9907 const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, undefined) catch unreachable; 9908 const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, undefined) catch unreachable; 9909 if ((try sema.compare(block, src, operand_val, .gte, first_tv.val, operand_ty)) and 9910 (try sema.compare(block, src, operand_val, .lte, last_tv.val, operand_ty))) 9911 { 9912 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); 9913 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); 9914 } 9915 } 9916 9917 extra_index += body_len; 9918 } 9919 } 9920 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand); 9921 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges); 9922 } 9923 9924 if (scalar_cases_len + multi_cases_len == 0) { 9925 if (empty_enum) { 9926 return Air.Inst.Ref.void_value; 9927 } 9928 if (special_prong == .none) { 9929 return sema.fail(block, src, "switch must handle all possibilities", .{}); 9930 } 9931 if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) { 9932 return Air.Inst.Ref.unreachable_value; 9933 } 9934 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges); 9935 } 9936 9937 try sema.requireRuntimeBlock(block, src, operand_src); 9938 9939 const estimated_cases_extra = (scalar_cases_len + multi_cases_len) * 9940 @typeInfo(Air.SwitchBr.Case).Struct.fields.len + 2; 9941 var cases_extra = try std.ArrayListUnmanaged(u32).initCapacity(gpa, estimated_cases_extra); 9942 defer cases_extra.deinit(gpa); 9943 9944 var case_block = child_block.makeSubBlock(); 9945 case_block.runtime_loop = null; 9946 case_block.runtime_cond = operand_src; 9947 case_block.runtime_index.increment(); 9948 defer case_block.instructions.deinit(gpa); 9949 9950 var extra_index: usize = special.end; 9951 9952 var scalar_i: usize = 0; 9953 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 9954 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 9955 extra_index += 1; 9956 const body_len = sema.code.extra[extra_index]; 9957 extra_index += 1; 9958 const body = sema.code.extra[extra_index..][0..body_len]; 9959 extra_index += body_len; 9960 9961 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope); 9962 defer wip_captures.deinit(); 9963 9964 case_block.instructions.shrinkRetainingCapacity(0); 9965 case_block.wip_capture_scope = wip_captures.scope; 9966 9967 const item = try sema.resolveInst(item_ref); 9968 // `item` is already guaranteed to be constant known. 9969 9970 const analyze_body = if (union_originally) blk: { 9971 const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable; 9972 const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); 9973 break :blk field_ty.zigTypeTag() != .NoReturn; 9974 } else true; 9975 9976 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { 9977 // nothing to do here 9978 } else if (analyze_body) { 9979 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) { 9980 error.ComptimeBreak => { 9981 const zir_datas = sema.code.instructions.items(.data); 9982 const break_data = zir_datas[sema.comptime_break_inst].@"break"; 9983 try sema.addRuntimeBreak(&case_block, .{ 9984 .block_inst = break_data.block_inst, 9985 .operand = break_data.operand, 9986 .inst = sema.comptime_break_inst, 9987 }); 9988 }, 9989 else => |e| return e, 9990 }; 9991 } else { 9992 _ = try case_block.addNoOp(.unreach); 9993 } 9994 9995 try wip_captures.finalize(); 9996 9997 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); 9998 cases_extra.appendAssumeCapacity(1); // items_len 9999 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); 10000 cases_extra.appendAssumeCapacity(@enumToInt(item)); 10001 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); 10002 } 10003 10004 var is_first = true; 10005 var prev_cond_br: Air.Inst.Index = undefined; 10006 var first_else_body: []const Air.Inst.Index = &.{}; 10007 defer gpa.free(first_else_body); 10008 var prev_then_body: []const Air.Inst.Index = &.{}; 10009 defer gpa.free(prev_then_body); 10010 10011 var cases_len = scalar_cases_len; 10012 var multi_i: usize = 0; 10013 while (multi_i < multi_cases_len) : (multi_i += 1) { 10014 const items_len = sema.code.extra[extra_index]; 10015 extra_index += 1; 10016 const ranges_len = sema.code.extra[extra_index]; 10017 extra_index += 1; 10018 const body_len = sema.code.extra[extra_index]; 10019 extra_index += 1; 10020 const items = sema.code.refSlice(extra_index, items_len); 10021 extra_index += items_len; 10022 10023 case_block.instructions.shrinkRetainingCapacity(0); 10024 case_block.wip_capture_scope = child_block.wip_capture_scope; 10025 10026 var any_ok: Air.Inst.Ref = .none; 10027 10028 // If there are any ranges, we have to put all the items into the 10029 // else prong. Otherwise, we can take advantage of multiple items 10030 // mapping to the same body. 10031 if (ranges_len == 0) { 10032 cases_len += 1; 10033 10034 const analyze_body = if (union_originally) 10035 for (items) |item_ref| { 10036 const item = try sema.resolveInst(item_ref); 10037 const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable; 10038 const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); 10039 if (field_ty.zigTypeTag() != .NoReturn) break true; 10040 } else false 10041 else 10042 true; 10043 10044 const body = sema.code.extra[extra_index..][0..body_len]; 10045 extra_index += body_len; 10046 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { 10047 // nothing to do here 10048 } else if (analyze_body) { 10049 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) { 10050 error.ComptimeBreak => { 10051 const zir_datas = sema.code.instructions.items(.data); 10052 const break_data = zir_datas[sema.comptime_break_inst].@"break"; 10053 try sema.addRuntimeBreak(&case_block, .{ 10054 .block_inst = break_data.block_inst, 10055 .operand = break_data.operand, 10056 .inst = sema.comptime_break_inst, 10057 }); 10058 }, 10059 else => |e| return e, 10060 }; 10061 } else { 10062 _ = try case_block.addNoOp(.unreach); 10063 } 10064 10065 try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len + 10066 case_block.instructions.items.len); 10067 10068 cases_extra.appendAssumeCapacity(@intCast(u32, items.len)); 10069 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); 10070 10071 for (items) |item_ref| { 10072 const item = try sema.resolveInst(item_ref); 10073 cases_extra.appendAssumeCapacity(@enumToInt(item)); 10074 } 10075 10076 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); 10077 } else { 10078 for (items) |item_ref| { 10079 const item = try sema.resolveInst(item_ref); 10080 const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item); 10081 if (any_ok != .none) { 10082 any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok); 10083 } else { 10084 any_ok = cmp_ok; 10085 } 10086 } 10087 10088 var range_i: usize = 0; 10089 while (range_i < ranges_len) : (range_i += 1) { 10090 const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 10091 extra_index += 1; 10092 const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 10093 extra_index += 1; 10094 10095 const item_first = try sema.resolveInst(first_ref); 10096 const item_last = try sema.resolveInst(last_ref); 10097 10098 // operand >= first and operand <= last 10099 const range_first_ok = try case_block.addBinOp( 10100 if (case_block.float_mode == .Optimized) .cmp_gte_optimized else .cmp_gte, 10101 operand, 10102 item_first, 10103 ); 10104 const range_last_ok = try case_block.addBinOp( 10105 if (case_block.float_mode == .Optimized) .cmp_lte_optimized else .cmp_lte, 10106 operand, 10107 item_last, 10108 ); 10109 const range_ok = try case_block.addBinOp( 10110 .bool_and, 10111 range_first_ok, 10112 range_last_ok, 10113 ); 10114 if (any_ok != .none) { 10115 any_ok = try case_block.addBinOp(.bool_or, any_ok, range_ok); 10116 } else { 10117 any_ok = range_ok; 10118 } 10119 } 10120 10121 const new_cond_br = try case_block.addInstAsIndex(.{ .tag = .cond_br, .data = .{ 10122 .pl_op = .{ 10123 .operand = any_ok, 10124 .payload = undefined, 10125 }, 10126 } }); 10127 var cond_body = case_block.instructions.toOwnedSlice(gpa); 10128 defer gpa.free(cond_body); 10129 10130 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope); 10131 defer wip_captures.deinit(); 10132 10133 case_block.instructions.shrinkRetainingCapacity(0); 10134 case_block.wip_capture_scope = wip_captures.scope; 10135 10136 const body = sema.code.extra[extra_index..][0..body_len]; 10137 extra_index += body_len; 10138 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { 10139 // nothing to do here 10140 } else { 10141 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) { 10142 error.ComptimeBreak => { 10143 const zir_datas = sema.code.instructions.items(.data); 10144 const break_data = zir_datas[sema.comptime_break_inst].@"break"; 10145 try sema.addRuntimeBreak(&case_block, .{ 10146 .block_inst = break_data.block_inst, 10147 .operand = break_data.operand, 10148 .inst = sema.comptime_break_inst, 10149 }); 10150 }, 10151 else => |e| return e, 10152 }; 10153 } 10154 10155 try wip_captures.finalize(); 10156 10157 if (is_first) { 10158 is_first = false; 10159 first_else_body = cond_body; 10160 cond_body = &.{}; 10161 } else { 10162 try sema.air_extra.ensureUnusedCapacity( 10163 gpa, 10164 @typeInfo(Air.CondBr).Struct.fields.len + prev_then_body.len + cond_body.len, 10165 ); 10166 10167 sema.air_instructions.items(.data)[prev_cond_br].pl_op.payload = 10168 sema.addExtraAssumeCapacity(Air.CondBr{ 10169 .then_body_len = @intCast(u32, prev_then_body.len), 10170 .else_body_len = @intCast(u32, cond_body.len), 10171 }); 10172 sema.air_extra.appendSliceAssumeCapacity(prev_then_body); 10173 sema.air_extra.appendSliceAssumeCapacity(cond_body); 10174 } 10175 gpa.free(prev_then_body); 10176 prev_then_body = case_block.instructions.toOwnedSlice(gpa); 10177 prev_cond_br = new_cond_br; 10178 } 10179 } 10180 10181 var final_else_body: []const Air.Inst.Index = &.{}; 10182 if (special.body.len != 0 or !is_first or case_block.wantSafety()) { 10183 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope); 10184 defer wip_captures.deinit(); 10185 10186 case_block.instructions.shrinkRetainingCapacity(0); 10187 case_block.wip_capture_scope = wip_captures.scope; 10188 10189 const analyze_body = if (union_originally) 10190 for (seen_union_fields) |seen_field, index| { 10191 if (seen_field != null) continue; 10192 const union_obj = maybe_union_ty.cast(Type.Payload.Union).?.data; 10193 const field_ty = union_obj.fields.values()[index].ty; 10194 if (field_ty.zigTypeTag() != .NoReturn) break true; 10195 } else false 10196 else 10197 true; 10198 if (special.body.len != 0 and err_set and 10199 try sema.maybeErrorUnwrap(&case_block, special.body, operand)) 10200 { 10201 // nothing to do here 10202 } else if (special.body.len != 0 and analyze_body) { 10203 _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) { 10204 error.ComptimeBreak => { 10205 const zir_datas = sema.code.instructions.items(.data); 10206 const break_data = zir_datas[sema.comptime_break_inst].@"break"; 10207 try sema.addRuntimeBreak(&case_block, .{ 10208 .block_inst = break_data.block_inst, 10209 .operand = break_data.operand, 10210 .inst = sema.comptime_break_inst, 10211 }); 10212 }, 10213 else => |e| return e, 10214 }; 10215 } else { 10216 // We still need a terminator in this block, but we have proven 10217 // that it is unreachable. 10218 if (case_block.wantSafety()) { 10219 _ = try sema.safetyPanic(&case_block, src, .corrupt_switch); 10220 } else { 10221 _ = try case_block.addNoOp(.unreach); 10222 } 10223 } 10224 10225 try wip_captures.finalize(); 10226 10227 if (is_first) { 10228 final_else_body = case_block.instructions.items; 10229 } else { 10230 try sema.air_extra.ensureUnusedCapacity(gpa, prev_then_body.len + 10231 @typeInfo(Air.CondBr).Struct.fields.len + case_block.instructions.items.len); 10232 10233 sema.air_instructions.items(.data)[prev_cond_br].pl_op.payload = 10234 sema.addExtraAssumeCapacity(Air.CondBr{ 10235 .then_body_len = @intCast(u32, prev_then_body.len), 10236 .else_body_len = @intCast(u32, case_block.instructions.items.len), 10237 }); 10238 sema.air_extra.appendSliceAssumeCapacity(prev_then_body); 10239 sema.air_extra.appendSliceAssumeCapacity(case_block.instructions.items); 10240 final_else_body = first_else_body; 10241 } 10242 } 10243 10244 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr).Struct.fields.len + 10245 cases_extra.items.len + final_else_body.len); 10246 10247 _ = try child_block.addInst(.{ .tag = .switch_br, .data = .{ .pl_op = .{ 10248 .operand = operand, 10249 .payload = sema.addExtraAssumeCapacity(Air.SwitchBr{ 10250 .cases_len = @intCast(u32, cases_len), 10251 .else_body_len = @intCast(u32, final_else_body.len), 10252 }), 10253 } } }); 10254 sema.air_extra.appendSliceAssumeCapacity(cases_extra.items); 10255 sema.air_extra.appendSliceAssumeCapacity(final_else_body); 10256 10257 return sema.analyzeBlockBody(block, src, &child_block, merges); 10258 } 10259 10260 fn resolveSwitchItemVal( 10261 sema: *Sema, 10262 block: *Block, 10263 item_ref: Zir.Inst.Ref, 10264 switch_node_offset: i32, 10265 switch_prong_src: Module.SwitchProngSrc, 10266 range_expand: Module.SwitchProngSrc.RangeExpand, 10267 ) CompileError!TypedValue { 10268 const item = try sema.resolveInst(item_ref); 10269 const item_ty = sema.typeOf(item); 10270 // Constructing a LazySrcLoc is costly because we only have the switch AST node. 10271 // Only if we know for sure we need to report a compile error do we resolve the 10272 // full source locations. 10273 if (sema.resolveConstValue(block, .unneeded, item, undefined)) |val| { 10274 return TypedValue{ .ty = item_ty, .val = val }; 10275 } else |err| switch (err) { 10276 error.NeededSourceLocation => { 10277 const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_node_offset, range_expand); 10278 return TypedValue{ 10279 .ty = item_ty, 10280 .val = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime known"), 10281 }; 10282 }, 10283 else => |e| return e, 10284 } 10285 } 10286 10287 fn validateSwitchRange( 10288 sema: *Sema, 10289 block: *Block, 10290 range_set: *RangeSet, 10291 first_ref: Zir.Inst.Ref, 10292 last_ref: Zir.Inst.Ref, 10293 operand_ty: Type, 10294 src_node_offset: i32, 10295 switch_prong_src: Module.SwitchProngSrc, 10296 ) CompileError!void { 10297 const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val; 10298 const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val; 10299 if (first_val.compare(.gt, last_val, operand_ty, sema.mod)) { 10300 const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), src_node_offset, .first); 10301 return sema.fail(block, src, "range start value is greater than the end value", .{}); 10302 } 10303 const maybe_prev_src = try range_set.add(first_val, last_val, operand_ty, switch_prong_src); 10304 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); 10305 } 10306 10307 fn validateSwitchItem( 10308 sema: *Sema, 10309 block: *Block, 10310 range_set: *RangeSet, 10311 item_ref: Zir.Inst.Ref, 10312 operand_ty: Type, 10313 src_node_offset: i32, 10314 switch_prong_src: Module.SwitchProngSrc, 10315 ) CompileError!void { 10316 const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; 10317 const maybe_prev_src = try range_set.add(item_val, item_val, operand_ty, switch_prong_src); 10318 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); 10319 } 10320 10321 fn validateSwitchItemEnum( 10322 sema: *Sema, 10323 block: *Block, 10324 seen_fields: []?Module.SwitchProngSrc, 10325 range_set: *RangeSet, 10326 item_ref: Zir.Inst.Ref, 10327 src_node_offset: i32, 10328 switch_prong_src: Module.SwitchProngSrc, 10329 ) CompileError!void { 10330 const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); 10331 const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val, sema.mod) orelse { 10332 const maybe_prev_src = try range_set.add(item_tv.val, item_tv.val, item_tv.ty, switch_prong_src); 10333 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); 10334 }; 10335 const maybe_prev_src = seen_fields[field_index]; 10336 seen_fields[field_index] = switch_prong_src; 10337 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); 10338 } 10339 10340 fn validateSwitchItemError( 10341 sema: *Sema, 10342 block: *Block, 10343 seen_errors: *SwitchErrorSet, 10344 item_ref: Zir.Inst.Ref, 10345 src_node_offset: i32, 10346 switch_prong_src: Module.SwitchProngSrc, 10347 ) CompileError!void { 10348 const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); 10349 // TODO: Do i need to typecheck here? 10350 const error_name = item_tv.val.castTag(.@"error").?.data.name; 10351 const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev| 10352 prev.value 10353 else 10354 null; 10355 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); 10356 } 10357 10358 fn validateSwitchDupe( 10359 sema: *Sema, 10360 block: *Block, 10361 maybe_prev_src: ?Module.SwitchProngSrc, 10362 switch_prong_src: Module.SwitchProngSrc, 10363 src_node_offset: i32, 10364 ) CompileError!void { 10365 const prev_prong_src = maybe_prev_src orelse return; 10366 const gpa = sema.gpa; 10367 const block_src_decl = sema.mod.declPtr(block.src_decl); 10368 const src = switch_prong_src.resolve(gpa, block_src_decl, src_node_offset, .none); 10369 const prev_src = prev_prong_src.resolve(gpa, block_src_decl, src_node_offset, .none); 10370 const msg = msg: { 10371 const msg = try sema.errMsg( 10372 block, 10373 src, 10374 "duplicate switch value", 10375 .{}, 10376 ); 10377 errdefer msg.destroy(sema.gpa); 10378 try sema.errNote( 10379 block, 10380 prev_src, 10381 msg, 10382 "previous value here", 10383 .{}, 10384 ); 10385 break :msg msg; 10386 }; 10387 return sema.failWithOwnedErrorMsg(msg); 10388 } 10389 10390 fn validateSwitchItemBool( 10391 sema: *Sema, 10392 block: *Block, 10393 true_count: *u8, 10394 false_count: *u8, 10395 item_ref: Zir.Inst.Ref, 10396 src_node_offset: i32, 10397 switch_prong_src: Module.SwitchProngSrc, 10398 ) CompileError!void { 10399 const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; 10400 if (item_val.toBool()) { 10401 true_count.* += 1; 10402 } else { 10403 false_count.* += 1; 10404 } 10405 if (true_count.* + false_count.* > 2) { 10406 const block_src_decl = sema.mod.declPtr(block.src_decl); 10407 const src = switch_prong_src.resolve(sema.gpa, block_src_decl, src_node_offset, .none); 10408 return sema.fail(block, src, "duplicate switch value", .{}); 10409 } 10410 } 10411 10412 const ValueSrcMap = std.HashMap(Value, Module.SwitchProngSrc, Value.HashContext, std.hash_map.default_max_load_percentage); 10413 10414 fn validateSwitchItemSparse( 10415 sema: *Sema, 10416 block: *Block, 10417 seen_values: *ValueSrcMap, 10418 item_ref: Zir.Inst.Ref, 10419 src_node_offset: i32, 10420 switch_prong_src: Module.SwitchProngSrc, 10421 ) CompileError!void { 10422 const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; 10423 const kv = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return; 10424 return sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset); 10425 } 10426 10427 fn validateSwitchNoRange( 10428 sema: *Sema, 10429 block: *Block, 10430 ranges_len: u32, 10431 operand_ty: Type, 10432 src_node_offset: i32, 10433 ) CompileError!void { 10434 if (ranges_len == 0) 10435 return; 10436 10437 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset }; 10438 const range_src: LazySrcLoc = .{ .node_offset_switch_range = src_node_offset }; 10439 10440 const msg = msg: { 10441 const msg = try sema.errMsg( 10442 block, 10443 operand_src, 10444 "ranges not allowed when switching on type '{}'", 10445 .{operand_ty.fmt(sema.mod)}, 10446 ); 10447 errdefer msg.destroy(sema.gpa); 10448 try sema.errNote( 10449 block, 10450 range_src, 10451 msg, 10452 "range here", 10453 .{}, 10454 ); 10455 break :msg msg; 10456 }; 10457 return sema.failWithOwnedErrorMsg(msg); 10458 } 10459 10460 fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !bool { 10461 const this_feature_is_implemented_in_the_backend = 10462 sema.mod.comp.bin_file.options.use_llvm; 10463 10464 if (!this_feature_is_implemented_in_the_backend) return false; 10465 10466 const tags = sema.code.instructions.items(.tag); 10467 for (body) |inst| { 10468 switch (tags[inst]) { 10469 .dbg_block_begin, 10470 .dbg_block_end, 10471 .dbg_stmt, 10472 .@"unreachable", 10473 .str, 10474 .as_node, 10475 .panic, 10476 .field_val, 10477 => {}, 10478 else => return false, 10479 } 10480 } 10481 10482 for (body) |inst| { 10483 const air_inst = switch (tags[inst]) { 10484 .dbg_block_begin, 10485 .dbg_block_end, 10486 => continue, 10487 .dbg_stmt => { 10488 try sema.zirDbgStmt(block, inst); 10489 continue; 10490 }, 10491 .str => try sema.zirStr(block, inst), 10492 .as_node => try sema.zirAsNode(block, inst), 10493 .field_val => try sema.zirFieldVal(block, inst), 10494 .@"unreachable" => { 10495 const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable"; 10496 const src = inst_data.src(); 10497 10498 const panic_fn = try sema.getBuiltin(block, src, "panicUnwrapError"); 10499 const err_return_trace = try sema.getErrorReturnTrace(block, src); 10500 const args: [2]Air.Inst.Ref = .{ err_return_trace, operand }; 10501 _ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, &args, null); 10502 return true; 10503 }, 10504 .panic => { 10505 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 10506 const src = inst_data.src(); 10507 const msg_inst = try sema.resolveInst(inst_data.operand); 10508 10509 const panic_fn = try sema.getBuiltin(block, src, "panic"); 10510 const err_return_trace = try sema.getErrorReturnTrace(block, src); 10511 const args: [3]Air.Inst.Ref = .{ msg_inst, err_return_trace, .null_value }; 10512 _ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, &args, null); 10513 return true; 10514 }, 10515 else => unreachable, 10516 }; 10517 if (sema.typeOf(air_inst).isNoReturn()) 10518 return true; 10519 try sema.inst_map.put(sema.gpa, inst, air_inst); 10520 } 10521 unreachable; 10522 } 10523 10524 fn maybeErrorUnwrapCondbr(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, cond: Zir.Inst.Ref, cond_src: LazySrcLoc) !void { 10525 const index = Zir.refToIndex(cond) orelse return; 10526 if (sema.code.instructions.items(.tag)[index] != .is_non_err) return; 10527 10528 const err_inst_data = sema.code.instructions.items(.data)[index].un_node; 10529 const err_operand = try sema.resolveInst(err_inst_data.operand); 10530 const operand_ty = sema.typeOf(err_operand); 10531 if (operand_ty.zigTypeTag() == .ErrorSet) { 10532 try sema.maybeErrorUnwrapComptime(block, body, err_operand); 10533 return; 10534 } 10535 if (try sema.resolveDefinedValue(block, cond_src, err_operand)) |val| { 10536 if (val.getError() == null) return; 10537 try sema.maybeErrorUnwrapComptime(block, body, err_operand); 10538 } 10539 } 10540 10541 fn maybeErrorUnwrapComptime(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !void { 10542 const tags = sema.code.instructions.items(.tag); 10543 const inst = for (body) |inst| { 10544 switch (tags[inst]) { 10545 .dbg_block_begin, 10546 .dbg_block_end, 10547 .dbg_stmt, 10548 => {}, 10549 .@"unreachable" => break inst, 10550 else => return, 10551 } 10552 } else return; 10553 const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable"; 10554 const src = inst_data.src(); 10555 10556 if (try sema.resolveDefinedValue(block, src, operand)) |val| { 10557 if (val.getError()) |name| { 10558 return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); 10559 } 10560 } 10561 } 10562 10563 fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 10564 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 10565 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 10566 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 10567 const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 10568 const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs); 10569 const field_name = try sema.resolveConstString(block, name_src, extra.rhs, "field name must be comptime known"); 10570 const ty = try sema.resolveTypeFields(block, ty_src, unresolved_ty); 10571 10572 const has_field = hf: { 10573 if (ty.isSlice()) { 10574 if (mem.eql(u8, field_name, "ptr")) break :hf true; 10575 if (mem.eql(u8, field_name, "len")) break :hf true; 10576 break :hf false; 10577 } 10578 if (ty.castTag(.anon_struct)) |pl| { 10579 break :hf for (pl.data.names) |name| { 10580 if (mem.eql(u8, name, field_name)) break true; 10581 } else false; 10582 } 10583 if (ty.isTuple()) { 10584 const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch break :hf false; 10585 break :hf field_index < ty.structFieldCount(); 10586 } 10587 break :hf switch (ty.zigTypeTag()) { 10588 .Struct => ty.structFields().contains(field_name), 10589 .Union => ty.unionFields().contains(field_name), 10590 .Enum => ty.enumFields().contains(field_name), 10591 .Array => mem.eql(u8, field_name, "len"), 10592 else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{ 10593 ty.fmt(sema.mod), 10594 }), 10595 }; 10596 }; 10597 if (has_field) { 10598 return Air.Inst.Ref.bool_true; 10599 } else { 10600 return Air.Inst.Ref.bool_false; 10601 } 10602 } 10603 10604 fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 10605 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 10606 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 10607 const src = inst_data.src(); 10608 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 10609 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 10610 const container_type = try sema.resolveType(block, lhs_src, extra.lhs); 10611 const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "decl name must be comptime known"); 10612 10613 try checkNamespaceType(sema, block, lhs_src, container_type); 10614 10615 const namespace = container_type.getNamespace() orelse return Air.Inst.Ref.bool_false; 10616 if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| { 10617 const decl = sema.mod.declPtr(decl_index); 10618 if (decl.is_pub or decl.getFileScope() == block.getFileScope()) { 10619 return Air.Inst.Ref.bool_true; 10620 } 10621 } 10622 return Air.Inst.Ref.bool_false; 10623 } 10624 10625 fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 10626 const tracy = trace(@src()); 10627 defer tracy.end(); 10628 10629 const mod = sema.mod; 10630 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 10631 const operand_src = inst_data.src(); 10632 const operand = inst_data.get(sema.code); 10633 10634 const result = mod.importFile(block.getFileScope(), operand) catch |err| switch (err) { 10635 error.ImportOutsidePkgPath => { 10636 return sema.fail(block, operand_src, "import of file outside package path: '{s}'", .{operand}); 10637 }, 10638 error.PackageNotFound => { 10639 const cur_pkg = block.getFileScope().pkg; 10640 const parent = if (cur_pkg == sema.mod.main_pkg or cur_pkg == sema.mod.root_pkg) 10641 "root" 10642 else if (cur_pkg.parent) |parent| blk: { 10643 var it = parent.table.iterator(); 10644 while (it.next()) |pkg| { 10645 if (pkg.value_ptr.* == cur_pkg) { 10646 break :blk pkg.key_ptr.*; 10647 } 10648 } 10649 unreachable; 10650 } else { 10651 return sema.fail(block, operand_src, "no package named '{s}' available", .{operand}); 10652 }; 10653 return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, parent }); 10654 }, 10655 else => { 10656 // TODO: these errors are file system errors; make sure an update() will 10657 // retry this and not cache the file system error, which may be transient. 10658 return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) }); 10659 }, 10660 }; 10661 try mod.semaFile(result.file); 10662 const file_root_decl_index = result.file.root_decl.unwrap().?; 10663 const file_root_decl = mod.declPtr(file_root_decl_index); 10664 try mod.declareDeclDependency(sema.owner_decl_index, file_root_decl_index); 10665 return sema.addConstant(file_root_decl.ty, file_root_decl.val); 10666 } 10667 10668 fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 10669 const tracy = trace(@src()); 10670 defer tracy.end(); 10671 10672 const mod = sema.mod; 10673 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 10674 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 10675 const name = try sema.resolveConstString(block, operand_src, inst_data.operand, "file path name must be comptime known"); 10676 10677 const embed_file = mod.embedFile(block.getFileScope(), name) catch |err| switch (err) { 10678 error.ImportOutsidePkgPath => { 10679 return sema.fail(block, operand_src, "embed of file outside package path: '{s}'", .{name}); 10680 }, 10681 else => { 10682 // TODO: these errors are file system errors; make sure an update() will 10683 // retry this and not cache the file system error, which may be transient. 10684 return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ name, @errorName(err) }); 10685 }, 10686 }; 10687 10688 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded); 10689 defer anon_decl.deinit(); 10690 10691 const bytes_including_null = embed_file.bytes[0 .. embed_file.bytes.len + 1]; 10692 10693 // TODO instead of using `Value.Tag.bytes`, create a new value tag for pointing at 10694 // a `*Module.EmbedFile`. The purpose of this would be: 10695 // - If only the length is read and the bytes are not inspected by comptime code, 10696 // there can be an optimization where the codegen backend does a copy_file_range 10697 // into the final binary, and never loads the data into memory. 10698 // - When a Decl is destroyed, it can free the `*Module.EmbedFile`. 10699 embed_file.owner_decl = try anon_decl.finish( 10700 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), embed_file.bytes.len), 10701 try Value.Tag.bytes.create(anon_decl.arena(), bytes_including_null), 10702 0, // default alignment 10703 ); 10704 10705 return sema.analyzeDeclRef(embed_file.owner_decl); 10706 } 10707 10708 fn zirRetErrValueCode(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 10709 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 10710 const err_name = inst_data.get(sema.code); 10711 10712 // Return the error code from the function. 10713 const kv = try sema.mod.getErrorValue(err_name); 10714 const result_inst = try sema.addConstant( 10715 try Type.Tag.error_set_single.create(sema.arena, kv.key), 10716 try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }), 10717 ); 10718 return result_inst; 10719 } 10720 10721 fn zirShl( 10722 sema: *Sema, 10723 block: *Block, 10724 inst: Zir.Inst.Index, 10725 air_tag: Air.Inst.Tag, 10726 ) CompileError!Air.Inst.Ref { 10727 const tracy = trace(@src()); 10728 defer tracy.end(); 10729 10730 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 10731 const src = inst_data.src(); 10732 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 10733 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 10734 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 10735 const lhs = try sema.resolveInst(extra.lhs); 10736 const rhs = try sema.resolveInst(extra.rhs); 10737 const lhs_ty = sema.typeOf(lhs); 10738 const rhs_ty = sema.typeOf(rhs); 10739 const target = sema.mod.getTarget(); 10740 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 10741 10742 const scalar_ty = lhs_ty.scalarType(); 10743 const scalar_rhs_ty = rhs_ty.scalarType(); 10744 10745 // TODO coerce rhs if air_tag is not shl_sat 10746 const rhs_is_comptime_int = try sema.checkIntType(block, rhs_src, scalar_rhs_ty); 10747 10748 const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs); 10749 const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs); 10750 10751 if (maybe_rhs_val) |rhs_val| { 10752 if (rhs_val.isUndef()) { 10753 return sema.addConstUndef(sema.typeOf(lhs)); 10754 } 10755 // If rhs is 0, return lhs without doing any calculations. 10756 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 10757 return lhs; 10758 } 10759 if (scalar_ty.zigTypeTag() != .ComptimeInt and air_tag != .shl_sat) { 10760 var bits_payload = Value.Payload.U64{ 10761 .base = .{ .tag = .int_u64 }, 10762 .data = scalar_ty.intInfo(target).bits, 10763 }; 10764 const bit_value = Value.initPayload(&bits_payload.base); 10765 if (rhs_ty.zigTypeTag() == .Vector) { 10766 var i: usize = 0; 10767 while (i < rhs_ty.vectorLen()) : (i += 1) { 10768 if (rhs_val.indexVectorlike(i).compareHetero(.gte, bit_value, target)) { 10769 return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ 10770 rhs_val.indexVectorlike(i).fmtValue(scalar_ty, sema.mod), 10771 i, 10772 scalar_ty.fmt(sema.mod), 10773 }); 10774 } 10775 } 10776 } else if (rhs_val.compareHetero(.gte, bit_value, target)) { 10777 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ 10778 rhs_val.fmtValue(scalar_ty, sema.mod), 10779 scalar_ty.fmt(sema.mod), 10780 }); 10781 } 10782 } 10783 } 10784 10785 const runtime_src = if (maybe_lhs_val) |lhs_val| rs: { 10786 if (lhs_val.isUndef()) return sema.addConstUndef(lhs_ty); 10787 const rhs_val = maybe_rhs_val orelse { 10788 if (scalar_ty.zigTypeTag() == .ComptimeInt) { 10789 return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be a comptime known", .{}); 10790 } 10791 break :rs rhs_src; 10792 }; 10793 10794 const val = switch (air_tag) { 10795 .shl_exact => val: { 10796 const shifted = try lhs_val.shlWithOverflow(rhs_val, lhs_ty, sema.arena, target); 10797 if (scalar_ty.zigTypeTag() == .ComptimeInt) { 10798 break :val shifted.wrapped_result; 10799 } 10800 if (shifted.overflowed.compareWithZero(.eq)) { 10801 break :val shifted.wrapped_result; 10802 } 10803 return sema.fail(block, src, "operation caused overflow", .{}); 10804 }, 10805 10806 .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt) 10807 try lhs_val.shl(rhs_val, lhs_ty, sema.arena, target) 10808 else 10809 try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, target), 10810 10811 .shl => if (scalar_ty.zigTypeTag() == .ComptimeInt) 10812 try lhs_val.shl(rhs_val, lhs_ty, sema.arena, target) 10813 else 10814 try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, target), 10815 10816 else => unreachable, 10817 }; 10818 10819 return sema.addConstant(lhs_ty, val); 10820 } else lhs_src; 10821 10822 const new_rhs = if (air_tag == .shl_sat) rhs: { 10823 // Limit the RHS type for saturating shl to be an integer as small as the LHS. 10824 if (rhs_is_comptime_int or 10825 scalar_rhs_ty.intInfo(target).bits > scalar_ty.intInfo(target).bits) 10826 { 10827 const max_int = try sema.addConstant( 10828 lhs_ty, 10829 try lhs_ty.maxInt(sema.arena, target), 10830 ); 10831 const rhs_limited = try sema.analyzeMinMax(block, rhs_src, rhs, max_int, .min, rhs_src, rhs_src); 10832 break :rhs try sema.intCast(block, src, lhs_ty, rhs_src, rhs_limited, rhs_src, false); 10833 } else { 10834 break :rhs rhs; 10835 } 10836 } else rhs; 10837 10838 try sema.requireRuntimeBlock(block, src, runtime_src); 10839 if (block.wantSafety()) { 10840 const bit_count = scalar_ty.intInfo(target).bits; 10841 if (!std.math.isPowerOfTwo(bit_count)) { 10842 const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count); 10843 10844 const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { 10845 const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val)); 10846 const lt = try block.addCmpVector(rhs, bit_count_inst, .lt, try sema.addType(rhs_ty)); 10847 break :ok try block.addInst(.{ 10848 .tag = .reduce, 10849 .data = .{ .reduce = .{ 10850 .operand = lt, 10851 .operation = .And, 10852 } }, 10853 }); 10854 } else ok: { 10855 const bit_count_inst = try sema.addConstant(rhs_ty, bit_count_val); 10856 break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst); 10857 }; 10858 try sema.addSafetyCheck(block, ok, .shift_rhs_too_big); 10859 } 10860 10861 if (air_tag == .shl_exact) { 10862 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty); 10863 const op_ov = try block.addInst(.{ 10864 .tag = .shl_with_overflow, 10865 .data = .{ .ty_pl = .{ 10866 .ty = try sema.addType(op_ov_tuple_ty), 10867 .payload = try sema.addExtra(Air.Bin{ 10868 .lhs = lhs, 10869 .rhs = rhs, 10870 }), 10871 } }, 10872 }); 10873 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); 10874 const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector) 10875 try block.addInst(.{ 10876 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, 10877 .data = .{ .reduce = .{ 10878 .operand = ov_bit, 10879 .operation = .Or, 10880 } }, 10881 }) 10882 else 10883 ov_bit; 10884 const zero_ov = try sema.addConstant(Type.@"u1", Value.zero); 10885 const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); 10886 10887 try sema.addSafetyCheck(block, no_ov, .shl_overflow); 10888 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); 10889 } 10890 } 10891 return block.addBinOp(air_tag, lhs, new_rhs); 10892 } 10893 10894 fn zirShr( 10895 sema: *Sema, 10896 block: *Block, 10897 inst: Zir.Inst.Index, 10898 air_tag: Air.Inst.Tag, 10899 ) CompileError!Air.Inst.Ref { 10900 const tracy = trace(@src()); 10901 defer tracy.end(); 10902 10903 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 10904 const src = inst_data.src(); 10905 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 10906 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 10907 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 10908 const lhs = try sema.resolveInst(extra.lhs); 10909 const rhs = try sema.resolveInst(extra.rhs); 10910 const lhs_ty = sema.typeOf(lhs); 10911 const rhs_ty = sema.typeOf(rhs); 10912 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 10913 const target = sema.mod.getTarget(); 10914 const scalar_ty = lhs_ty.scalarType(); 10915 10916 const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs); 10917 const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs); 10918 10919 const runtime_src = if (maybe_rhs_val) |rhs_val| rs: { 10920 if (rhs_val.isUndef()) { 10921 return sema.addConstUndef(lhs_ty); 10922 } 10923 // If rhs is 0, return lhs without doing any calculations. 10924 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 10925 return lhs; 10926 } 10927 if (scalar_ty.zigTypeTag() != .ComptimeInt) { 10928 var bits_payload = Value.Payload.U64{ 10929 .base = .{ .tag = .int_u64 }, 10930 .data = scalar_ty.intInfo(target).bits, 10931 }; 10932 const bit_value = Value.initPayload(&bits_payload.base); 10933 if (rhs_ty.zigTypeTag() == .Vector) { 10934 var i: usize = 0; 10935 while (i < rhs_ty.vectorLen()) : (i += 1) { 10936 if (rhs_val.indexVectorlike(i).compareHetero(.gte, bit_value, target)) { 10937 return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ 10938 rhs_val.indexVectorlike(i).fmtValue(scalar_ty, sema.mod), 10939 i, 10940 scalar_ty.fmt(sema.mod), 10941 }); 10942 } 10943 } 10944 } else if (rhs_val.compareHetero(.gte, bit_value, target)) { 10945 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ 10946 rhs_val.fmtValue(scalar_ty, sema.mod), 10947 scalar_ty.fmt(sema.mod), 10948 }); 10949 } 10950 } 10951 if (maybe_lhs_val) |lhs_val| { 10952 if (lhs_val.isUndef()) { 10953 return sema.addConstUndef(lhs_ty); 10954 } 10955 if (air_tag == .shr_exact) { 10956 // Detect if any ones would be shifted out. 10957 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, target); 10958 if (!(try truncated.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { 10959 return sema.fail(block, src, "exact shift shifted out 1 bits", .{}); 10960 } 10961 } 10962 const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, target); 10963 return sema.addConstant(lhs_ty, val); 10964 } else { 10965 break :rs lhs_src; 10966 } 10967 } else rhs_src; 10968 10969 if (maybe_rhs_val == null and scalar_ty.zigTypeTag() == .ComptimeInt) { 10970 return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be a comptime known", .{}); 10971 } 10972 10973 try sema.requireRuntimeBlock(block, src, runtime_src); 10974 const result = try block.addBinOp(air_tag, lhs, rhs); 10975 if (block.wantSafety()) { 10976 const bit_count = scalar_ty.intInfo(target).bits; 10977 if (!std.math.isPowerOfTwo(bit_count)) { 10978 const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count); 10979 10980 const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { 10981 const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val)); 10982 const lt = try block.addCmpVector(rhs, bit_count_inst, .lt, try sema.addType(rhs_ty)); 10983 break :ok try block.addInst(.{ 10984 .tag = .reduce, 10985 .data = .{ .reduce = .{ 10986 .operand = lt, 10987 .operation = .And, 10988 } }, 10989 }); 10990 } else ok: { 10991 const bit_count_inst = try sema.addConstant(rhs_ty, bit_count_val); 10992 break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst); 10993 }; 10994 try sema.addSafetyCheck(block, ok, .shift_rhs_too_big); 10995 } 10996 10997 if (air_tag == .shr_exact) { 10998 const back = try block.addBinOp(.shl, result, rhs); 10999 11000 const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { 11001 const eql = try block.addCmpVector(lhs, back, .eq, try sema.addType(rhs_ty)); 11002 break :ok try block.addInst(.{ 11003 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, 11004 .data = .{ .reduce = .{ 11005 .operand = eql, 11006 .operation = .And, 11007 } }, 11008 }); 11009 } else try block.addBinOp(.cmp_eq, lhs, back); 11010 try sema.addSafetyCheck(block, ok, .shr_overflow); 11011 } 11012 } 11013 return result; 11014 } 11015 11016 fn zirBitwise( 11017 sema: *Sema, 11018 block: *Block, 11019 inst: Zir.Inst.Index, 11020 air_tag: Air.Inst.Tag, 11021 ) CompileError!Air.Inst.Ref { 11022 const tracy = trace(@src()); 11023 defer tracy.end(); 11024 11025 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 11026 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 11027 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 11028 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 11029 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 11030 const lhs = try sema.resolveInst(extra.lhs); 11031 const rhs = try sema.resolveInst(extra.rhs); 11032 const lhs_ty = sema.typeOf(lhs); 11033 const rhs_ty = sema.typeOf(rhs); 11034 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 11035 11036 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 11037 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } }); 11038 const scalar_type = resolved_type.scalarType(); 11039 const scalar_tag = scalar_type.zigTypeTag(); 11040 11041 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 11042 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 11043 11044 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 11045 const target = sema.mod.getTarget(); 11046 11047 if (!is_int) { 11048 return sema.fail(block, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) }); 11049 } 11050 11051 const runtime_src = runtime: { 11052 // TODO: ask the linker what kind of relocations are available, and 11053 // in some cases emit a Value that means "this decl's address AND'd with this operand". 11054 if (try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs)) |lhs_val| { 11055 if (try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs)) |rhs_val| { 11056 const result_val = switch (air_tag) { 11057 .bit_and => try lhs_val.bitwiseAnd(rhs_val, resolved_type, sema.arena, target), 11058 .bit_or => try lhs_val.bitwiseOr(rhs_val, resolved_type, sema.arena, target), 11059 .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena, target), 11060 else => unreachable, 11061 }; 11062 return sema.addConstant(resolved_type, result_val); 11063 } else { 11064 break :runtime rhs_src; 11065 } 11066 } else { 11067 break :runtime lhs_src; 11068 } 11069 }; 11070 11071 try sema.requireRuntimeBlock(block, src, runtime_src); 11072 return block.addBinOp(air_tag, casted_lhs, casted_rhs); 11073 } 11074 11075 fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 11076 const tracy = trace(@src()); 11077 defer tracy.end(); 11078 11079 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 11080 const src = inst_data.src(); 11081 const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; 11082 11083 const operand = try sema.resolveInst(inst_data.operand); 11084 const operand_type = sema.typeOf(operand); 11085 const scalar_type = operand_type.scalarType(); 11086 const target = sema.mod.getTarget(); 11087 11088 if (scalar_type.zigTypeTag() != .Int) { 11089 return sema.fail(block, src, "unable to perform binary not operation on type '{}'", .{ 11090 operand_type.fmt(sema.mod), 11091 }); 11092 } 11093 11094 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { 11095 if (val.isUndef()) { 11096 return sema.addConstUndef(operand_type); 11097 } else if (operand_type.zigTypeTag() == .Vector) { 11098 const vec_len = try sema.usizeCast(block, operand_src, operand_type.vectorLen()); 11099 var elem_val_buf: Value.ElemValueBuffer = undefined; 11100 const elems = try sema.arena.alloc(Value, vec_len); 11101 for (elems) |*elem, i| { 11102 const elem_val = val.elemValueBuffer(sema.mod, i, &elem_val_buf); 11103 elem.* = try elem_val.bitwiseNot(scalar_type, sema.arena, target); 11104 } 11105 return sema.addConstant( 11106 operand_type, 11107 try Value.Tag.aggregate.create(sema.arena, elems), 11108 ); 11109 } else { 11110 const result_val = try val.bitwiseNot(operand_type, sema.arena, target); 11111 return sema.addConstant(operand_type, result_val); 11112 } 11113 } 11114 11115 try sema.requireRuntimeBlock(block, src, null); 11116 return block.addTyOp(.not, operand_type, operand); 11117 } 11118 11119 fn analyzeTupleCat( 11120 sema: *Sema, 11121 block: *Block, 11122 src_node: i32, 11123 lhs: Air.Inst.Ref, 11124 rhs: Air.Inst.Ref, 11125 ) CompileError!Air.Inst.Ref { 11126 const lhs_ty = sema.typeOf(lhs); 11127 const rhs_ty = sema.typeOf(rhs); 11128 const src = LazySrcLoc.nodeOffset(src_node); 11129 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node }; 11130 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; 11131 11132 const lhs_tuple = lhs_ty.tupleFields(); 11133 const rhs_tuple = rhs_ty.tupleFields(); 11134 const dest_fields = lhs_tuple.types.len + rhs_tuple.types.len; 11135 11136 if (dest_fields == 0) { 11137 return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value)); 11138 } 11139 const final_len = try sema.usizeCast(block, rhs_src, dest_fields); 11140 11141 const types = try sema.arena.alloc(Type, final_len); 11142 const values = try sema.arena.alloc(Value, final_len); 11143 11144 const opt_runtime_src = rs: { 11145 var runtime_src: ?LazySrcLoc = null; 11146 for (lhs_tuple.types) |ty, i| { 11147 types[i] = ty; 11148 values[i] = lhs_tuple.values[i]; 11149 const operand_src = lhs_src; // TODO better source location 11150 if (values[i].tag() == .unreachable_value) { 11151 runtime_src = operand_src; 11152 } 11153 } 11154 const offset = lhs_tuple.types.len; 11155 for (rhs_tuple.types) |ty, i| { 11156 types[i + offset] = ty; 11157 values[i + offset] = rhs_tuple.values[i]; 11158 const operand_src = rhs_src; // TODO better source location 11159 if (rhs_tuple.values[i].tag() == .unreachable_value) { 11160 runtime_src = operand_src; 11161 } 11162 } 11163 break :rs runtime_src; 11164 }; 11165 11166 const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ 11167 .types = types, 11168 .values = values, 11169 }); 11170 11171 const runtime_src = opt_runtime_src orelse { 11172 const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); 11173 return sema.addConstant(tuple_ty, tuple_val); 11174 }; 11175 11176 try sema.requireRuntimeBlock(block, src, runtime_src); 11177 11178 const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len); 11179 for (lhs_tuple.types) |_, i| { 11180 const operand_src = lhs_src; // TODO better source location 11181 element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, lhs, @intCast(u32, i), lhs_ty); 11182 } 11183 const offset = lhs_tuple.types.len; 11184 for (rhs_tuple.types) |_, i| { 11185 const operand_src = rhs_src; // TODO better source location 11186 element_refs[i + offset] = 11187 try sema.tupleFieldValByIndex(block, operand_src, rhs, @intCast(u32, i), rhs_ty); 11188 } 11189 11190 return block.addAggregateInit(tuple_ty, element_refs); 11191 } 11192 11193 fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 11194 const tracy = trace(@src()); 11195 defer tracy.end(); 11196 11197 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 11198 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 11199 const lhs = try sema.resolveInst(extra.lhs); 11200 const rhs = try sema.resolveInst(extra.rhs); 11201 const lhs_ty = sema.typeOf(lhs); 11202 const rhs_ty = sema.typeOf(rhs); 11203 const src = inst_data.src(); 11204 11205 if (lhs_ty.isTuple() and rhs_ty.isTuple()) { 11206 return sema.analyzeTupleCat(block, inst_data.src_node, lhs, rhs); 11207 } 11208 11209 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 11210 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 11211 11212 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs); 11213 const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs); 11214 11215 const resolved_elem_ty = t: { 11216 var trash_block = block.makeSubBlock(); 11217 trash_block.is_comptime = false; 11218 defer trash_block.instructions.deinit(sema.gpa); 11219 11220 const instructions = [_]Air.Inst.Ref{ 11221 try trash_block.addBitCast(lhs_info.elem_type, .void_value), 11222 try trash_block.addBitCast(rhs_info.elem_type, .void_value), 11223 }; 11224 break :t try sema.resolvePeerTypes(block, src, &instructions, .{ 11225 .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, 11226 }); 11227 }; 11228 11229 // When there is a sentinel mismatch, no sentinel on the result. 11230 // Otherwise, use the sentinel value provided by either operand, 11231 // coercing it to the peer-resolved element type. 11232 const res_sent_val: ?Value = s: { 11233 if (lhs_info.sentinel) |lhs_sent_val| { 11234 const lhs_sent = try sema.addConstant(lhs_info.elem_type, lhs_sent_val); 11235 if (rhs_info.sentinel) |rhs_sent_val| { 11236 const rhs_sent = try sema.addConstant(rhs_info.elem_type, rhs_sent_val); 11237 const lhs_sent_casted = try sema.coerce(block, resolved_elem_ty, lhs_sent, lhs_src); 11238 const rhs_sent_casted = try sema.coerce(block, resolved_elem_ty, rhs_sent, rhs_src); 11239 const lhs_sent_casted_val = try sema.resolveConstValue(block, lhs_src, lhs_sent_casted, "array sentinel value must be comptime known"); 11240 const rhs_sent_casted_val = try sema.resolveConstValue(block, rhs_src, rhs_sent_casted, "array sentinel value must be comptime known"); 11241 if (try sema.valuesEqual(block, src, lhs_sent_casted_val, rhs_sent_casted_val, resolved_elem_ty)) { 11242 break :s lhs_sent_casted_val; 11243 } else { 11244 break :s null; 11245 } 11246 } else { 11247 const lhs_sent_casted = try sema.coerce(block, resolved_elem_ty, lhs_sent, lhs_src); 11248 const lhs_sent_casted_val = try sema.resolveConstValue(block, lhs_src, lhs_sent_casted, "array sentinel value must be comptime known"); 11249 break :s lhs_sent_casted_val; 11250 } 11251 } else { 11252 if (rhs_info.sentinel) |rhs_sent_val| { 11253 const rhs_sent = try sema.addConstant(rhs_info.elem_type, rhs_sent_val); 11254 const rhs_sent_casted = try sema.coerce(block, resolved_elem_ty, rhs_sent, rhs_src); 11255 const rhs_sent_casted_val = try sema.resolveConstValue(block, rhs_src, rhs_sent_casted, "array sentinel value must be comptime known"); 11256 break :s rhs_sent_casted_val; 11257 } else { 11258 break :s null; 11259 } 11260 } 11261 }; 11262 11263 const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len); 11264 const rhs_len = try sema.usizeCast(block, lhs_src, rhs_info.len); 11265 const result_len = std.math.add(usize, lhs_len, rhs_len) catch |err| switch (err) { 11266 error.Overflow => return sema.fail( 11267 block, 11268 src, 11269 "concatenating arrays of length {d} and {d} produces an array too large for this compiler implementation to handle", 11270 .{ lhs_len, rhs_len }, 11271 ), 11272 }; 11273 11274 const result_ty = try Type.array(sema.arena, result_len, res_sent_val, resolved_elem_ty, sema.mod); 11275 const ptr_addrspace = p: { 11276 if (lhs_ty.zigTypeTag() == .Pointer) break :p lhs_ty.ptrAddressSpace(); 11277 if (rhs_ty.zigTypeTag() == .Pointer) break :p rhs_ty.ptrAddressSpace(); 11278 break :p null; 11279 }; 11280 11281 const runtime_src = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| rs: { 11282 if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| { 11283 const lhs_sub_val = if (lhs_ty.isSinglePointer()) 11284 (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? 11285 else 11286 lhs_val; 11287 11288 const rhs_sub_val = if (rhs_ty.isSinglePointer()) 11289 (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? 11290 else 11291 rhs_val; 11292 11293 const final_len_including_sent = result_len + @boolToInt(res_sent_val != null); 11294 const element_vals = try sema.arena.alloc(Value, final_len_including_sent); 11295 var elem_i: usize = 0; 11296 while (elem_i < lhs_len) : (elem_i += 1) { 11297 element_vals[elem_i] = try lhs_sub_val.elemValue(sema.mod, sema.arena, elem_i); 11298 } 11299 while (elem_i < result_len) : (elem_i += 1) { 11300 element_vals[elem_i] = try rhs_sub_val.elemValue(sema.mod, sema.arena, elem_i - lhs_len); 11301 } 11302 if (res_sent_val) |sent_val| { 11303 element_vals[result_len] = sent_val; 11304 } 11305 const val = try Value.Tag.aggregate.create(sema.arena, element_vals); 11306 return sema.addConstantMaybeRef(block, src, result_ty, val, ptr_addrspace != null); 11307 } else break :rs rhs_src; 11308 } else lhs_src; 11309 11310 try sema.requireRuntimeBlock(block, src, runtime_src); 11311 11312 if (ptr_addrspace) |ptr_as| { 11313 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ 11314 .pointee_type = result_ty, 11315 .@"addrspace" = ptr_as, 11316 }); 11317 const alloc = try block.addTy(.alloc, alloc_ty); 11318 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 11319 .pointee_type = resolved_elem_ty, 11320 .@"addrspace" = ptr_as, 11321 }); 11322 11323 var elem_i: usize = 0; 11324 while (elem_i < lhs_len) : (elem_i += 1) { 11325 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i); 11326 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); 11327 const init = try sema.elemVal(block, lhs_src, lhs, elem_index, src); 11328 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); 11329 } 11330 while (elem_i < result_len) : (elem_i += 1) { 11331 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i); 11332 const rhs_index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len); 11333 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); 11334 const init = try sema.elemVal(block, rhs_src, rhs, rhs_index, src); 11335 try sema.storePtr2(block, src, elem_ptr, src, init, rhs_src, .store); 11336 } 11337 if (res_sent_val) |sent_val| { 11338 const elem_index = try sema.addIntUnsigned(Type.usize, result_len); 11339 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); 11340 const init = try sema.addConstant(lhs_info.elem_type, sent_val); 11341 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); 11342 } 11343 11344 return alloc; 11345 } 11346 11347 const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len); 11348 { 11349 var elem_i: usize = 0; 11350 while (elem_i < lhs_len) : (elem_i += 1) { 11351 const index = try sema.addIntUnsigned(Type.usize, elem_i); 11352 const init = try sema.elemVal(block, lhs_src, lhs, index, src); 11353 element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, lhs_src); 11354 } 11355 while (elem_i < result_len) : (elem_i += 1) { 11356 const index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len); 11357 const init = try sema.elemVal(block, rhs_src, rhs, index, src); 11358 element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, rhs_src); 11359 } 11360 } 11361 11362 return block.addAggregateInit(result_ty, element_refs); 11363 } 11364 11365 fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref) !Type.ArrayInfo { 11366 const operand_ty = sema.typeOf(operand); 11367 switch (operand_ty.zigTypeTag()) { 11368 .Array => return operand_ty.arrayInfo(), 11369 .Pointer => { 11370 const ptr_info = operand_ty.ptrInfo().data; 11371 switch (ptr_info.size) { 11372 // TODO: in the Many case here this should only work if the type 11373 // has a sentinel, and this code should compute the length based 11374 // on the sentinel value. 11375 .Slice, .Many => { 11376 const val = try sema.resolveConstValue(block, src, operand, "slice value being concatenated must be comptime known"); 11377 return Type.ArrayInfo{ 11378 .elem_type = ptr_info.pointee_type, 11379 .sentinel = ptr_info.sentinel, 11380 .len = val.sliceLen(sema.mod), 11381 }; 11382 }, 11383 .One => { 11384 if (ptr_info.pointee_type.zigTypeTag() == .Array) { 11385 return ptr_info.pointee_type.arrayInfo(); 11386 } 11387 }, 11388 .C => {}, 11389 } 11390 }, 11391 else => {}, 11392 } 11393 return sema.fail(block, src, "expected indexable; found '{}'", .{operand_ty.fmt(sema.mod)}); 11394 } 11395 11396 fn analyzeTupleMul( 11397 sema: *Sema, 11398 block: *Block, 11399 src_node: i32, 11400 operand: Air.Inst.Ref, 11401 factor: u64, 11402 ) CompileError!Air.Inst.Ref { 11403 const operand_ty = sema.typeOf(operand); 11404 const operand_tuple = operand_ty.tupleFields(); 11405 const src = LazySrcLoc.nodeOffset(src_node); 11406 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node }; 11407 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; 11408 11409 const tuple_len = operand_tuple.types.len; 11410 const final_len_u64 = std.math.mul(u64, tuple_len, factor) catch 11411 return sema.fail(block, rhs_src, "operation results in overflow", .{}); 11412 11413 if (final_len_u64 == 0) { 11414 return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value)); 11415 } 11416 const final_len = try sema.usizeCast(block, rhs_src, final_len_u64); 11417 11418 const types = try sema.arena.alloc(Type, final_len); 11419 const values = try sema.arena.alloc(Value, final_len); 11420 11421 const opt_runtime_src = rs: { 11422 var runtime_src: ?LazySrcLoc = null; 11423 for (operand_tuple.types) |ty, i| { 11424 types[i] = ty; 11425 values[i] = operand_tuple.values[i]; 11426 const operand_src = lhs_src; // TODO better source location 11427 if (values[i].tag() == .unreachable_value) { 11428 runtime_src = operand_src; 11429 } 11430 } 11431 var i: usize = 1; 11432 while (i < factor) : (i += 1) { 11433 mem.copy(Type, types[tuple_len * i ..], operand_tuple.types); 11434 mem.copy(Value, values[tuple_len * i ..], operand_tuple.values); 11435 } 11436 break :rs runtime_src; 11437 }; 11438 11439 const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ 11440 .types = types, 11441 .values = values, 11442 }); 11443 11444 const runtime_src = opt_runtime_src orelse { 11445 const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); 11446 return sema.addConstant(tuple_ty, tuple_val); 11447 }; 11448 11449 try sema.requireRuntimeBlock(block, src, runtime_src); 11450 11451 const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len); 11452 for (operand_tuple.types) |_, i| { 11453 const operand_src = lhs_src; // TODO better source location 11454 element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, operand, @intCast(u32, i), operand_ty); 11455 } 11456 var i: usize = 1; 11457 while (i < factor) : (i += 1) { 11458 mem.copy(Air.Inst.Ref, element_refs[tuple_len * i ..], element_refs[0..tuple_len]); 11459 } 11460 11461 return block.addAggregateInit(tuple_ty, element_refs); 11462 } 11463 11464 fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 11465 const tracy = trace(@src()); 11466 defer tracy.end(); 11467 11468 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 11469 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 11470 const lhs = try sema.resolveInst(extra.lhs); 11471 const lhs_ty = sema.typeOf(lhs); 11472 const src: LazySrcLoc = inst_data.src(); 11473 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 11474 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 11475 11476 // In `**` rhs must be comptime-known, but lhs can be runtime-known 11477 const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, "array multiplication factor must be comptime known"); 11478 11479 if (lhs_ty.isTuple()) { 11480 return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor); 11481 } 11482 11483 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs); 11484 11485 const result_len_u64 = std.math.mul(u64, lhs_info.len, factor) catch 11486 return sema.fail(block, rhs_src, "operation results in overflow", .{}); 11487 const result_len = try sema.usizeCast(block, src, result_len_u64); 11488 11489 const result_ty = try Type.array(sema.arena, result_len, lhs_info.sentinel, lhs_info.elem_type, sema.mod); 11490 11491 const ptr_addrspace = if (lhs_ty.zigTypeTag() == .Pointer) lhs_ty.ptrAddressSpace() else null; 11492 const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len); 11493 11494 if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| { 11495 const final_len_including_sent = result_len + @boolToInt(lhs_info.sentinel != null); 11496 11497 const lhs_sub_val = if (lhs_ty.isSinglePointer()) 11498 (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? 11499 else 11500 lhs_val; 11501 11502 const val = v: { 11503 // Optimization for the common pattern of a single element repeated N times, such 11504 // as zero-filling a byte array. 11505 if (lhs_len == 1) { 11506 const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, 0); 11507 break :v try Value.Tag.repeated.create(sema.arena, elem_val); 11508 } 11509 11510 const element_vals = try sema.arena.alloc(Value, final_len_including_sent); 11511 var elem_i: usize = 0; 11512 while (elem_i < result_len) { 11513 var lhs_i: usize = 0; 11514 while (lhs_i < lhs_len) : (lhs_i += 1) { 11515 const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, lhs_i); 11516 element_vals[elem_i] = elem_val; 11517 elem_i += 1; 11518 } 11519 } 11520 if (lhs_info.sentinel) |sent_val| { 11521 element_vals[result_len] = sent_val; 11522 } 11523 break :v try Value.Tag.aggregate.create(sema.arena, element_vals); 11524 }; 11525 return sema.addConstantMaybeRef(block, src, result_ty, val, ptr_addrspace != null); 11526 } 11527 11528 try sema.requireRuntimeBlock(block, src, lhs_src); 11529 11530 if (ptr_addrspace) |ptr_as| { 11531 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ 11532 .pointee_type = result_ty, 11533 .@"addrspace" = ptr_as, 11534 }); 11535 const alloc = try block.addTy(.alloc, alloc_ty); 11536 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 11537 .pointee_type = lhs_info.elem_type, 11538 .@"addrspace" = ptr_as, 11539 }); 11540 11541 var elem_i: usize = 0; 11542 while (elem_i < result_len) { 11543 var lhs_i: usize = 0; 11544 while (lhs_i < lhs_len) : (lhs_i += 1) { 11545 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i); 11546 elem_i += 1; 11547 const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i); 11548 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); 11549 const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src); 11550 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); 11551 } 11552 } 11553 if (lhs_info.sentinel) |sent_val| { 11554 const elem_index = try sema.addIntUnsigned(Type.usize, result_len); 11555 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); 11556 const init = try sema.addConstant(lhs_info.elem_type, sent_val); 11557 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); 11558 } 11559 11560 return alloc; 11561 } 11562 11563 const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len); 11564 var elem_i: usize = 0; 11565 while (elem_i < result_len) { 11566 var lhs_i: usize = 0; 11567 while (lhs_i < lhs_len) : (lhs_i += 1) { 11568 const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i); 11569 const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src); 11570 element_refs[elem_i] = init; 11571 elem_i += 1; 11572 } 11573 } 11574 11575 return block.addAggregateInit(result_ty, element_refs); 11576 } 11577 11578 fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 11579 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 11580 const src = inst_data.src(); 11581 const lhs_src = src; 11582 const rhs_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; 11583 11584 const rhs = try sema.resolveInst(inst_data.operand); 11585 const rhs_ty = sema.typeOf(rhs); 11586 const rhs_scalar_ty = rhs_ty.scalarType(); 11587 11588 if (rhs_scalar_ty.isUnsignedInt() or switch (rhs_scalar_ty.zigTypeTag()) { 11589 .Int, .ComptimeInt, .Float, .ComptimeFloat => false, 11590 else => true, 11591 }) { 11592 return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)}); 11593 } 11594 11595 if (rhs_scalar_ty.isAnyFloat()) { 11596 // We handle float negation here to ensure negative zero is represented in the bits. 11597 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| { 11598 if (rhs_val.isUndef()) return sema.addConstUndef(rhs_ty); 11599 const target = sema.mod.getTarget(); 11600 return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, target)); 11601 } 11602 try sema.requireRuntimeBlock(block, src, null); 11603 return block.addUnOp(if (block.float_mode == .Optimized) .neg_optimized else .neg, rhs); 11604 } 11605 11606 const lhs = if (rhs_ty.zigTypeTag() == .Vector) 11607 try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero)) 11608 else 11609 try sema.resolveInst(.zero); 11610 11611 return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src); 11612 } 11613 11614 fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 11615 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 11616 const src = inst_data.src(); 11617 const lhs_src = src; 11618 const rhs_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; 11619 11620 const rhs = try sema.resolveInst(inst_data.operand); 11621 const rhs_ty = sema.typeOf(rhs); 11622 const rhs_scalar_ty = rhs_ty.scalarType(); 11623 11624 switch (rhs_scalar_ty.zigTypeTag()) { 11625 .Int, .ComptimeInt, .Float, .ComptimeFloat => {}, 11626 else => return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)}), 11627 } 11628 11629 const lhs = if (rhs_ty.zigTypeTag() == .Vector) 11630 try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero)) 11631 else 11632 try sema.resolveInst(.zero); 11633 11634 return sema.analyzeArithmetic(block, .subwrap, lhs, rhs, src, lhs_src, rhs_src); 11635 } 11636 11637 fn zirArithmetic( 11638 sema: *Sema, 11639 block: *Block, 11640 inst: Zir.Inst.Index, 11641 zir_tag: Zir.Inst.Tag, 11642 ) CompileError!Air.Inst.Ref { 11643 const tracy = trace(@src()); 11644 defer tracy.end(); 11645 11646 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 11647 sema.src = .{ .node_offset_bin_op = inst_data.src_node }; 11648 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 11649 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 11650 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 11651 const lhs = try sema.resolveInst(extra.lhs); 11652 const rhs = try sema.resolveInst(extra.rhs); 11653 11654 return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src); 11655 } 11656 11657 fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 11658 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 11659 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 11660 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 11661 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 11662 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 11663 const lhs = try sema.resolveInst(extra.lhs); 11664 const rhs = try sema.resolveInst(extra.rhs); 11665 const lhs_ty = sema.typeOf(lhs); 11666 const rhs_ty = sema.typeOf(rhs); 11667 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); 11668 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); 11669 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 11670 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .div); 11671 11672 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 11673 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 11674 .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, 11675 }); 11676 11677 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 11678 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 11679 11680 const lhs_scalar_ty = lhs_ty.scalarType(); 11681 const rhs_scalar_ty = rhs_ty.scalarType(); 11682 const scalar_tag = resolved_type.scalarType().zigTypeTag(); 11683 11684 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 11685 11686 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div); 11687 11688 const mod = sema.mod; 11689 const target = mod.getTarget(); 11690 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); 11691 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); 11692 11693 if ((lhs_ty.zigTypeTag() == .ComptimeFloat and rhs_ty.zigTypeTag() == .ComptimeInt) or 11694 (lhs_ty.zigTypeTag() == .ComptimeInt and rhs_ty.zigTypeTag() == .ComptimeFloat)) 11695 { 11696 // If it makes a difference whether we coerce to ints or floats before doing the division, error. 11697 // If lhs % rhs is 0, it doesn't matter. 11698 const lhs_val = maybe_lhs_val orelse unreachable; 11699 const rhs_val = maybe_rhs_val orelse unreachable; 11700 const rem = lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target) catch unreachable; 11701 if (rem.compareWithZero(.neq)) { 11702 return sema.fail(block, src, "ambiguous coercion of division operands '{s}' and '{s}'; non-zero remainder '{}'", .{ 11703 @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()), rem.fmtValue(resolved_type, sema.mod), 11704 }); 11705 } 11706 } 11707 11708 // TODO: emit compile error when .div is used on integers and there would be an 11709 // ambiguous result between div_floor and div_trunc. 11710 11711 // For integers: 11712 // If the lhs is zero, then zero is returned regardless of rhs. 11713 // If the rhs is zero, compile error for division by zero. 11714 // If the rhs is undefined, compile error because there is a possible 11715 // value (zero) for which the division would be illegal behavior. 11716 // If the lhs is undefined: 11717 // * if lhs type is signed: 11718 // * if rhs is comptime-known and not -1, result is undefined 11719 // * if rhs is -1 or runtime-known, compile error because there is a 11720 // possible value (-min_int / -1) for which division would be 11721 // illegal behavior. 11722 // * if lhs type is unsigned, undef is returned regardless of rhs. 11723 // 11724 // For floats: 11725 // If the rhs is zero: 11726 // * comptime_float: compile error for division by zero. 11727 // * other float type: 11728 // * if the lhs is zero: QNaN 11729 // * otherwise: +Inf or -Inf depending on lhs sign 11730 // If the rhs is undefined: 11731 // * comptime_float: compile error because there is a possible 11732 // value (zero) for which the division would be illegal behavior. 11733 // * other float type: result is undefined 11734 // If the lhs is undefined, result is undefined. 11735 switch (scalar_tag) { 11736 .Int, .ComptimeInt, .ComptimeFloat => { 11737 if (maybe_lhs_val) |lhs_val| { 11738 if (!lhs_val.isUndef()) { 11739 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 11740 return sema.addConstant(resolved_type, Value.zero); 11741 } 11742 } 11743 } 11744 if (maybe_rhs_val) |rhs_val| { 11745 if (rhs_val.isUndef()) { 11746 return sema.failWithUseOfUndef(block, rhs_src); 11747 } 11748 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 11749 return sema.failWithDivideByZero(block, rhs_src); 11750 } 11751 // TODO: if the RHS is one, return the LHS directly 11752 } 11753 }, 11754 else => {}, 11755 } 11756 11757 const runtime_src = rs: { 11758 if (maybe_lhs_val) |lhs_val| { 11759 if (lhs_val.isUndef()) { 11760 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { 11761 if (maybe_rhs_val) |rhs_val| { 11762 if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) { 11763 return sema.addConstUndef(resolved_type); 11764 } 11765 } 11766 return sema.failWithUseOfUndef(block, rhs_src); 11767 } 11768 return sema.addConstUndef(resolved_type); 11769 } 11770 11771 if (maybe_rhs_val) |rhs_val| { 11772 if (is_int) { 11773 return sema.addConstant( 11774 resolved_type, 11775 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), 11776 ); 11777 } else { 11778 return sema.addConstant( 11779 resolved_type, 11780 try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target), 11781 ); 11782 } 11783 } else { 11784 break :rs rhs_src; 11785 } 11786 } else { 11787 break :rs lhs_src; 11788 } 11789 }; 11790 11791 try sema.requireRuntimeBlock(block, src, runtime_src); 11792 11793 if (block.wantSafety()) { 11794 try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int); 11795 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); 11796 } 11797 11798 const air_tag = if (is_int) blk: { 11799 if (lhs_ty.isSignedInt() or rhs_ty.isSignedInt()) { 11800 return sema.fail(block, src, "division with '{s}' and '{s}': signed integers must use @divTrunc, @divFloor, or @divExact", .{ @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()) }); 11801 } 11802 break :blk Air.Inst.Tag.div_trunc; 11803 } else switch (block.float_mode) { 11804 .Optimized => Air.Inst.Tag.div_float_optimized, 11805 .Strict => Air.Inst.Tag.div_float, 11806 }; 11807 return block.addBinOp(air_tag, casted_lhs, casted_rhs); 11808 } 11809 11810 fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 11811 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 11812 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 11813 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 11814 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 11815 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 11816 const lhs = try sema.resolveInst(extra.lhs); 11817 const rhs = try sema.resolveInst(extra.rhs); 11818 const lhs_ty = sema.typeOf(lhs); 11819 const rhs_ty = sema.typeOf(rhs); 11820 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); 11821 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); 11822 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 11823 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .div_exact); 11824 11825 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 11826 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 11827 .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, 11828 }); 11829 11830 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 11831 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 11832 11833 const lhs_scalar_ty = lhs_ty.scalarType(); 11834 const scalar_tag = resolved_type.scalarType().zigTypeTag(); 11835 11836 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 11837 11838 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_exact); 11839 11840 const mod = sema.mod; 11841 const target = mod.getTarget(); 11842 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); 11843 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); 11844 11845 const runtime_src = rs: { 11846 // For integers: 11847 // If the lhs is zero, then zero is returned regardless of rhs. 11848 // If the rhs is zero, compile error for division by zero. 11849 // If the rhs is undefined, compile error because there is a possible 11850 // value (zero) for which the division would be illegal behavior. 11851 // If the lhs is undefined, compile error because there is a possible 11852 // value for which the division would result in a remainder. 11853 // TODO: emit runtime safety for if there is a remainder 11854 // TODO: emit runtime safety for division by zero 11855 // 11856 // For floats: 11857 // If the rhs is zero, compile error for division by zero. 11858 // If the rhs is undefined, compile error because there is a possible 11859 // value (zero) for which the division would be illegal behavior. 11860 // If the lhs is undefined, compile error because there is a possible 11861 // value for which the division would result in a remainder. 11862 if (maybe_lhs_val) |lhs_val| { 11863 if (lhs_val.isUndef()) { 11864 return sema.failWithUseOfUndef(block, rhs_src); 11865 } else { 11866 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 11867 return sema.addConstant(resolved_type, Value.zero); 11868 } 11869 } 11870 } 11871 if (maybe_rhs_val) |rhs_val| { 11872 if (rhs_val.isUndef()) { 11873 return sema.failWithUseOfUndef(block, rhs_src); 11874 } 11875 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 11876 return sema.failWithDivideByZero(block, rhs_src); 11877 } 11878 // TODO: if the RHS is one, return the LHS directly 11879 } 11880 if (maybe_lhs_val) |lhs_val| { 11881 if (maybe_rhs_val) |rhs_val| { 11882 if (is_int) { 11883 const modulus_val = try lhs_val.intMod(rhs_val, resolved_type, sema.arena, target); 11884 if (modulus_val.compareWithZero(.neq)) { 11885 return sema.fail(block, src, "exact division produced remainder", .{}); 11886 } 11887 return sema.addConstant( 11888 resolved_type, 11889 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), 11890 ); 11891 } else { 11892 const modulus_val = try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target); 11893 if (modulus_val.compareWithZero(.neq)) { 11894 return sema.fail(block, src, "exact division produced remainder", .{}); 11895 } 11896 return sema.addConstant( 11897 resolved_type, 11898 try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target), 11899 ); 11900 } 11901 } else break :rs rhs_src; 11902 } else break :rs lhs_src; 11903 }; 11904 11905 try sema.requireRuntimeBlock(block, src, runtime_src); 11906 11907 // Depending on whether safety is enabled, we will have a slightly different strategy 11908 // here. The `div_exact` AIR instruction causes undefined behavior if a remainder 11909 // is produced, so in the safety check case, it cannot be used. Instead we do a 11910 // div_trunc and check for remainder. 11911 11912 if (block.wantSafety()) { 11913 try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int); 11914 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); 11915 11916 const result = try block.addBinOp(.div_trunc, casted_lhs, casted_rhs); 11917 const ok = if (!is_int) ok: { 11918 const floored = try block.addUnOp(.floor, result); 11919 11920 if (resolved_type.zigTypeTag() == .Vector) { 11921 const eql = try block.addCmpVector(result, floored, .eq, try sema.addType(resolved_type)); 11922 break :ok try block.addInst(.{ 11923 .tag = switch (block.float_mode) { 11924 .Strict => .reduce, 11925 .Optimized => .reduce_optimized, 11926 }, 11927 .data = .{ .reduce = .{ 11928 .operand = eql, 11929 .operation = .And, 11930 } }, 11931 }); 11932 } else { 11933 const is_in_range = try block.addBinOp(switch (block.float_mode) { 11934 .Strict => .cmp_eq, 11935 .Optimized => .cmp_eq_optimized, 11936 }, result, floored); 11937 break :ok is_in_range; 11938 } 11939 } else ok: { 11940 const remainder = try block.addBinOp(.rem, casted_lhs, casted_rhs); 11941 11942 if (resolved_type.zigTypeTag() == .Vector) { 11943 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); 11944 const zero = try sema.addConstant(resolved_type, zero_val); 11945 const eql = try block.addCmpVector(remainder, zero, .eq, try sema.addType(resolved_type)); 11946 break :ok try block.addInst(.{ 11947 .tag = .reduce, 11948 .data = .{ .reduce = .{ 11949 .operand = eql, 11950 .operation = .And, 11951 } }, 11952 }); 11953 } else { 11954 const zero = try sema.addConstant(resolved_type, Value.zero); 11955 const is_in_range = try block.addBinOp(.cmp_eq, remainder, zero); 11956 break :ok is_in_range; 11957 } 11958 }; 11959 try sema.addSafetyCheck(block, ok, .exact_division_remainder); 11960 return result; 11961 } 11962 11963 return block.addBinOp(airTag(block, is_int, .div_exact, .div_exact_optimized), casted_lhs, casted_rhs); 11964 } 11965 11966 fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 11967 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 11968 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 11969 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 11970 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 11971 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 11972 const lhs = try sema.resolveInst(extra.lhs); 11973 const rhs = try sema.resolveInst(extra.rhs); 11974 const lhs_ty = sema.typeOf(lhs); 11975 const rhs_ty = sema.typeOf(rhs); 11976 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); 11977 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); 11978 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 11979 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .div_floor); 11980 11981 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 11982 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 11983 .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, 11984 }); 11985 11986 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 11987 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 11988 11989 const lhs_scalar_ty = lhs_ty.scalarType(); 11990 const rhs_scalar_ty = rhs_ty.scalarType(); 11991 const scalar_tag = resolved_type.scalarType().zigTypeTag(); 11992 11993 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 11994 11995 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_floor); 11996 11997 const mod = sema.mod; 11998 const target = mod.getTarget(); 11999 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); 12000 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); 12001 12002 const runtime_src = rs: { 12003 // For integers: 12004 // If the lhs is zero, then zero is returned regardless of rhs. 12005 // If the rhs is zero, compile error for division by zero. 12006 // If the rhs is undefined, compile error because there is a possible 12007 // value (zero) for which the division would be illegal behavior. 12008 // If the lhs is undefined: 12009 // * if lhs type is signed: 12010 // * if rhs is comptime-known and not -1, result is undefined 12011 // * if rhs is -1 or runtime-known, compile error because there is a 12012 // possible value (-min_int / -1) for which division would be 12013 // illegal behavior. 12014 // * if lhs type is unsigned, undef is returned regardless of rhs. 12015 // TODO: emit runtime safety for division by zero 12016 // 12017 // For floats: 12018 // If the rhs is zero, compile error for division by zero. 12019 // If the rhs is undefined, compile error because there is a possible 12020 // value (zero) for which the division would be illegal behavior. 12021 // If the lhs is undefined, result is undefined. 12022 if (maybe_lhs_val) |lhs_val| { 12023 if (!lhs_val.isUndef()) { 12024 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12025 return sema.addConstant(resolved_type, Value.zero); 12026 } 12027 } 12028 } 12029 if (maybe_rhs_val) |rhs_val| { 12030 if (rhs_val.isUndef()) { 12031 return sema.failWithUseOfUndef(block, rhs_src); 12032 } 12033 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12034 return sema.failWithDivideByZero(block, rhs_src); 12035 } 12036 // TODO: if the RHS is one, return the LHS directly 12037 } 12038 if (maybe_lhs_val) |lhs_val| { 12039 if (lhs_val.isUndef()) { 12040 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { 12041 if (maybe_rhs_val) |rhs_val| { 12042 if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) { 12043 return sema.addConstUndef(resolved_type); 12044 } 12045 } 12046 return sema.failWithUseOfUndef(block, rhs_src); 12047 } 12048 return sema.addConstUndef(resolved_type); 12049 } 12050 12051 if (maybe_rhs_val) |rhs_val| { 12052 if (is_int) { 12053 return sema.addConstant( 12054 resolved_type, 12055 try lhs_val.intDivFloor(rhs_val, resolved_type, sema.arena, target), 12056 ); 12057 } else { 12058 return sema.addConstant( 12059 resolved_type, 12060 try lhs_val.floatDivFloor(rhs_val, resolved_type, sema.arena, target), 12061 ); 12062 } 12063 } else break :rs rhs_src; 12064 } else break :rs lhs_src; 12065 }; 12066 12067 try sema.requireRuntimeBlock(block, src, runtime_src); 12068 12069 if (block.wantSafety()) { 12070 try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int); 12071 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); 12072 } 12073 12074 return block.addBinOp(airTag(block, is_int, .div_floor, .div_floor_optimized), casted_lhs, casted_rhs); 12075 } 12076 12077 fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 12078 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 12079 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 12080 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 12081 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 12082 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 12083 const lhs = try sema.resolveInst(extra.lhs); 12084 const rhs = try sema.resolveInst(extra.rhs); 12085 const lhs_ty = sema.typeOf(lhs); 12086 const rhs_ty = sema.typeOf(rhs); 12087 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); 12088 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); 12089 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 12090 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .div_trunc); 12091 12092 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 12093 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 12094 .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, 12095 }); 12096 12097 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 12098 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 12099 12100 const lhs_scalar_ty = lhs_ty.scalarType(); 12101 const rhs_scalar_ty = rhs_ty.scalarType(); 12102 const scalar_tag = resolved_type.scalarType().zigTypeTag(); 12103 12104 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 12105 12106 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_trunc); 12107 12108 const mod = sema.mod; 12109 const target = mod.getTarget(); 12110 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); 12111 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); 12112 12113 const runtime_src = rs: { 12114 // For integers: 12115 // If the lhs is zero, then zero is returned regardless of rhs. 12116 // If the rhs is zero, compile error for division by zero. 12117 // If the rhs is undefined, compile error because there is a possible 12118 // value (zero) for which the division would be illegal behavior. 12119 // If the lhs is undefined: 12120 // * if lhs type is signed: 12121 // * if rhs is comptime-known and not -1, result is undefined 12122 // * if rhs is -1 or runtime-known, compile error because there is a 12123 // possible value (-min_int / -1) for which division would be 12124 // illegal behavior. 12125 // * if lhs type is unsigned, undef is returned regardless of rhs. 12126 // TODO: emit runtime safety for division by zero 12127 // 12128 // For floats: 12129 // If the rhs is zero, compile error for division by zero. 12130 // If the rhs is undefined, compile error because there is a possible 12131 // value (zero) for which the division would be illegal behavior. 12132 // If the lhs is undefined, result is undefined. 12133 if (maybe_lhs_val) |lhs_val| { 12134 if (!lhs_val.isUndef()) { 12135 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12136 return sema.addConstant(resolved_type, Value.zero); 12137 } 12138 } 12139 } 12140 if (maybe_rhs_val) |rhs_val| { 12141 if (rhs_val.isUndef()) { 12142 return sema.failWithUseOfUndef(block, rhs_src); 12143 } 12144 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12145 return sema.failWithDivideByZero(block, rhs_src); 12146 } 12147 } 12148 if (maybe_lhs_val) |lhs_val| { 12149 if (lhs_val.isUndef()) { 12150 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { 12151 if (maybe_rhs_val) |rhs_val| { 12152 if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) { 12153 return sema.addConstUndef(resolved_type); 12154 } 12155 } 12156 return sema.failWithUseOfUndef(block, rhs_src); 12157 } 12158 return sema.addConstUndef(resolved_type); 12159 } 12160 12161 if (maybe_rhs_val) |rhs_val| { 12162 if (is_int) { 12163 return sema.addConstant( 12164 resolved_type, 12165 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), 12166 ); 12167 } else { 12168 return sema.addConstant( 12169 resolved_type, 12170 try lhs_val.floatDivTrunc(rhs_val, resolved_type, sema.arena, target), 12171 ); 12172 } 12173 } else break :rs rhs_src; 12174 } else break :rs lhs_src; 12175 }; 12176 12177 try sema.requireRuntimeBlock(block, src, runtime_src); 12178 12179 if (block.wantSafety()) { 12180 try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int); 12181 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); 12182 } 12183 12184 return block.addBinOp(airTag(block, is_int, .div_trunc, .div_trunc_optimized), casted_lhs, casted_rhs); 12185 } 12186 12187 fn addDivIntOverflowSafety( 12188 sema: *Sema, 12189 block: *Block, 12190 resolved_type: Type, 12191 lhs_scalar_ty: Type, 12192 maybe_lhs_val: ?Value, 12193 maybe_rhs_val: ?Value, 12194 casted_lhs: Air.Inst.Ref, 12195 casted_rhs: Air.Inst.Ref, 12196 is_int: bool, 12197 ) CompileError!void { 12198 if (!is_int) return; 12199 12200 // If the LHS is unsigned, it cannot cause overflow. 12201 if (!lhs_scalar_ty.isSignedInt()) return; 12202 12203 const mod = sema.mod; 12204 const target = mod.getTarget(); 12205 12206 // If the LHS is widened to a larger integer type, no overflow is possible. 12207 if (lhs_scalar_ty.intInfo(target).bits < resolved_type.intInfo(target).bits) { 12208 return; 12209 } 12210 12211 const min_int = try resolved_type.minInt(sema.arena, target); 12212 const neg_one_scalar = try Value.Tag.int_i64.create(sema.arena, -1); 12213 const neg_one = if (resolved_type.zigTypeTag() == .Vector) 12214 try Value.Tag.repeated.create(sema.arena, neg_one_scalar) 12215 else 12216 neg_one_scalar; 12217 12218 // If the LHS is comptime-known to be not equal to the min int, 12219 // no overflow is possible. 12220 if (maybe_lhs_val) |lhs_val| { 12221 if (!lhs_val.compare(.eq, min_int, resolved_type, mod)) return; 12222 } 12223 12224 // If the RHS is comptime-known to not be equal to -1, no overflow is possible. 12225 if (maybe_rhs_val) |rhs_val| { 12226 if (!rhs_val.compare(.eq, neg_one, resolved_type, mod)) return; 12227 } 12228 12229 var ok: Air.Inst.Ref = .none; 12230 if (resolved_type.zigTypeTag() == .Vector) { 12231 const vector_ty_ref = try sema.addType(resolved_type); 12232 if (maybe_lhs_val == null) { 12233 const min_int_ref = try sema.addConstant(resolved_type, min_int); 12234 ok = try block.addCmpVector(casted_lhs, min_int_ref, .neq, vector_ty_ref); 12235 } 12236 if (maybe_rhs_val == null) { 12237 const neg_one_ref = try sema.addConstant(resolved_type, neg_one); 12238 const rhs_ok = try block.addCmpVector(casted_rhs, neg_one_ref, .neq, vector_ty_ref); 12239 if (ok == .none) { 12240 ok = rhs_ok; 12241 } else { 12242 ok = try block.addBinOp(.bool_or, ok, rhs_ok); 12243 } 12244 } 12245 assert(ok != .none); 12246 ok = try block.addInst(.{ 12247 .tag = .reduce, 12248 .data = .{ .reduce = .{ 12249 .operand = ok, 12250 .operation = .And, 12251 } }, 12252 }); 12253 } else { 12254 if (maybe_lhs_val == null) { 12255 const min_int_ref = try sema.addConstant(resolved_type, min_int); 12256 ok = try block.addBinOp(.cmp_neq, casted_lhs, min_int_ref); 12257 } 12258 if (maybe_rhs_val == null) { 12259 const neg_one_ref = try sema.addConstant(resolved_type, neg_one); 12260 const rhs_ok = try block.addBinOp(.cmp_neq, casted_rhs, neg_one_ref); 12261 if (ok == .none) { 12262 ok = rhs_ok; 12263 } else { 12264 ok = try block.addBinOp(.bool_or, ok, rhs_ok); 12265 } 12266 } 12267 assert(ok != .none); 12268 } 12269 try sema.addSafetyCheck(block, ok, .integer_overflow); 12270 } 12271 12272 fn addDivByZeroSafety( 12273 sema: *Sema, 12274 block: *Block, 12275 resolved_type: Type, 12276 maybe_rhs_val: ?Value, 12277 casted_rhs: Air.Inst.Ref, 12278 is_int: bool, 12279 ) CompileError!void { 12280 // Strict IEEE floats have well-defined division by zero. 12281 if (!is_int and block.float_mode == .Strict) return; 12282 12283 // If rhs was comptime-known to be zero a compile error would have been 12284 // emitted above. 12285 if (maybe_rhs_val != null) return; 12286 12287 const ok = if (resolved_type.zigTypeTag() == .Vector) ok: { 12288 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); 12289 const zero = try sema.addConstant(resolved_type, zero_val); 12290 const ok = try block.addCmpVector(casted_rhs, zero, .neq, try sema.addType(resolved_type)); 12291 break :ok try block.addInst(.{ 12292 .tag = if (is_int) .reduce else .reduce_optimized, 12293 .data = .{ .reduce = .{ 12294 .operand = ok, 12295 .operation = .And, 12296 } }, 12297 }); 12298 } else ok: { 12299 const zero = try sema.addConstant(resolved_type, Value.zero); 12300 break :ok try block.addBinOp(if (is_int) .cmp_neq else .cmp_neq_optimized, casted_rhs, zero); 12301 }; 12302 try sema.addSafetyCheck(block, ok, .divide_by_zero); 12303 } 12304 12305 fn airTag(block: *Block, is_int: bool, normal: Air.Inst.Tag, optimized: Air.Inst.Tag) Air.Inst.Tag { 12306 if (is_int) return normal; 12307 return switch (block.float_mode) { 12308 .Strict => normal, 12309 .Optimized => optimized, 12310 }; 12311 } 12312 12313 fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 12314 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 12315 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 12316 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 12317 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 12318 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 12319 const lhs = try sema.resolveInst(extra.lhs); 12320 const rhs = try sema.resolveInst(extra.rhs); 12321 const lhs_ty = sema.typeOf(lhs); 12322 const rhs_ty = sema.typeOf(rhs); 12323 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); 12324 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); 12325 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 12326 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .mod_rem); 12327 12328 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 12329 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 12330 .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, 12331 }); 12332 12333 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 12334 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 12335 12336 const lhs_scalar_ty = lhs_ty.scalarType(); 12337 const rhs_scalar_ty = rhs_ty.scalarType(); 12338 const scalar_tag = resolved_type.scalarType().zigTypeTag(); 12339 12340 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 12341 12342 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod_rem); 12343 12344 const mod = sema.mod; 12345 const target = mod.getTarget(); 12346 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); 12347 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); 12348 12349 const runtime_src = rs: { 12350 // For integers: 12351 // Either operand being undef is a compile error because there exists 12352 // a possible value (TODO what is it?) that would invoke illegal behavior. 12353 // TODO: can lhs undef be handled better? 12354 // 12355 // For floats: 12356 // If the rhs is zero, compile error for division by zero. 12357 // If the rhs is undefined, compile error because there is a possible 12358 // value (zero) for which the division would be illegal behavior. 12359 // If the lhs is undefined, result is undefined. 12360 // 12361 // For either one: if the result would be different between @mod and @rem, 12362 // then emit a compile error saying you have to pick one. 12363 if (is_int) { 12364 if (maybe_lhs_val) |lhs_val| { 12365 if (lhs_val.isUndef()) { 12366 return sema.failWithUseOfUndef(block, lhs_src); 12367 } 12368 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12369 return sema.addConstant(resolved_type, Value.zero); 12370 } 12371 } else if (lhs_scalar_ty.isSignedInt()) { 12372 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); 12373 } 12374 if (maybe_rhs_val) |rhs_val| { 12375 if (rhs_val.isUndef()) { 12376 return sema.failWithUseOfUndef(block, rhs_src); 12377 } 12378 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12379 return sema.failWithDivideByZero(block, rhs_src); 12380 } 12381 if (maybe_lhs_val) |lhs_val| { 12382 const rem_result = try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src); 12383 // If this answer could possibly be different by doing `intMod`, 12384 // we must emit a compile error. Otherwise, it's OK. 12385 if ((try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) != (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) and 12386 !(try rem_result.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) 12387 { 12388 const bad_src = if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) 12389 lhs_src 12390 else 12391 rhs_src; 12392 return sema.failWithModRemNegative(block, bad_src, lhs_ty, rhs_ty); 12393 } 12394 if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) { 12395 // Negative 12396 return sema.addConstant(resolved_type, Value.zero); 12397 } 12398 return sema.addConstant(resolved_type, rem_result); 12399 } 12400 break :rs lhs_src; 12401 } else if (rhs_scalar_ty.isSignedInt()) { 12402 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); 12403 } else { 12404 break :rs rhs_src; 12405 } 12406 } 12407 // float operands 12408 if (maybe_rhs_val) |rhs_val| { 12409 if (rhs_val.isUndef()) { 12410 return sema.failWithUseOfUndef(block, rhs_src); 12411 } 12412 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12413 return sema.failWithDivideByZero(block, rhs_src); 12414 } 12415 if (try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) { 12416 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); 12417 } 12418 if (maybe_lhs_val) |lhs_val| { 12419 if (lhs_val.isUndef() or (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))) { 12420 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); 12421 } 12422 return sema.addConstant( 12423 resolved_type, 12424 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target), 12425 ); 12426 } else { 12427 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); 12428 } 12429 } else { 12430 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); 12431 } 12432 }; 12433 12434 try sema.requireRuntimeBlock(block, src, runtime_src); 12435 12436 if (block.wantSafety()) { 12437 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); 12438 } 12439 12440 const air_tag = airTag(block, is_int, .rem, .rem_optimized); 12441 return block.addBinOp(air_tag, casted_lhs, casted_rhs); 12442 } 12443 12444 fn intRem( 12445 sema: *Sema, 12446 block: *Block, 12447 ty: Type, 12448 lhs: Value, 12449 lhs_src: LazySrcLoc, 12450 rhs: Value, 12451 rhs_src: LazySrcLoc, 12452 ) CompileError!Value { 12453 if (ty.zigTypeTag() == .Vector) { 12454 const result_data = try sema.arena.alloc(Value, ty.vectorLen()); 12455 for (result_data) |*scalar, i| { 12456 scalar.* = try sema.intRemScalar(block, lhs.indexVectorlike(i), lhs_src, rhs.indexVectorlike(i), rhs_src); 12457 } 12458 return Value.Tag.aggregate.create(sema.arena, result_data); 12459 } 12460 return sema.intRemScalar(block, lhs, lhs_src, rhs, rhs_src); 12461 } 12462 12463 fn intRemScalar( 12464 sema: *Sema, 12465 block: *Block, 12466 lhs: Value, 12467 lhs_src: LazySrcLoc, 12468 rhs: Value, 12469 rhs_src: LazySrcLoc, 12470 ) CompileError!Value { 12471 const target = sema.mod.getTarget(); 12472 // TODO is this a performance issue? maybe we should try the operation without 12473 // resorting to BigInt first. 12474 var lhs_space: Value.BigIntSpace = undefined; 12475 var rhs_space: Value.BigIntSpace = undefined; 12476 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, lhs_src)); 12477 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, rhs_src)); 12478 const limbs_q = try sema.arena.alloc( 12479 math.big.Limb, 12480 lhs_bigint.limbs.len, 12481 ); 12482 const limbs_r = try sema.arena.alloc( 12483 math.big.Limb, 12484 // TODO: consider reworking Sema to re-use Values rather than 12485 // always producing new Value objects. 12486 rhs_bigint.limbs.len, 12487 ); 12488 const limbs_buffer = try sema.arena.alloc( 12489 math.big.Limb, 12490 math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len), 12491 ); 12492 var result_q = math.big.int.Mutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; 12493 var result_r = math.big.int.Mutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; 12494 result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer); 12495 return Value.fromBigInt(sema.arena, result_r.toConst()); 12496 } 12497 12498 fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 12499 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 12500 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 12501 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 12502 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 12503 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 12504 const lhs = try sema.resolveInst(extra.lhs); 12505 const rhs = try sema.resolveInst(extra.rhs); 12506 const lhs_ty = sema.typeOf(lhs); 12507 const rhs_ty = sema.typeOf(rhs); 12508 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); 12509 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); 12510 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 12511 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .mod); 12512 12513 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 12514 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 12515 .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, 12516 }); 12517 12518 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 12519 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 12520 12521 const scalar_tag = resolved_type.scalarType().zigTypeTag(); 12522 12523 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 12524 12525 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod); 12526 12527 const mod = sema.mod; 12528 const target = mod.getTarget(); 12529 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); 12530 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); 12531 12532 const runtime_src = rs: { 12533 // For integers: 12534 // Either operand being undef is a compile error because there exists 12535 // a possible value (TODO what is it?) that would invoke illegal behavior. 12536 // TODO: can lhs zero be handled better? 12537 // TODO: can lhs undef be handled better? 12538 // 12539 // For floats: 12540 // If the rhs is zero, compile error for division by zero. 12541 // If the rhs is undefined, compile error because there is a possible 12542 // value (zero) for which the division would be illegal behavior. 12543 // If the lhs is undefined, result is undefined. 12544 if (is_int) { 12545 if (maybe_lhs_val) |lhs_val| { 12546 if (lhs_val.isUndef()) { 12547 return sema.failWithUseOfUndef(block, lhs_src); 12548 } 12549 } 12550 if (maybe_rhs_val) |rhs_val| { 12551 if (rhs_val.isUndef()) { 12552 return sema.failWithUseOfUndef(block, rhs_src); 12553 } 12554 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12555 return sema.failWithDivideByZero(block, rhs_src); 12556 } 12557 if (maybe_lhs_val) |lhs_val| { 12558 return sema.addConstant( 12559 resolved_type, 12560 try lhs_val.intMod(rhs_val, resolved_type, sema.arena, target), 12561 ); 12562 } 12563 break :rs lhs_src; 12564 } else { 12565 break :rs rhs_src; 12566 } 12567 } 12568 // float operands 12569 if (maybe_rhs_val) |rhs_val| { 12570 if (rhs_val.isUndef()) { 12571 return sema.failWithUseOfUndef(block, rhs_src); 12572 } 12573 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12574 return sema.failWithDivideByZero(block, rhs_src); 12575 } 12576 } 12577 if (maybe_lhs_val) |lhs_val| { 12578 if (lhs_val.isUndef()) { 12579 return sema.addConstUndef(resolved_type); 12580 } 12581 if (maybe_rhs_val) |rhs_val| { 12582 return sema.addConstant( 12583 resolved_type, 12584 try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target), 12585 ); 12586 } else break :rs rhs_src; 12587 } else break :rs lhs_src; 12588 }; 12589 12590 try sema.requireRuntimeBlock(block, src, runtime_src); 12591 12592 if (block.wantSafety()) { 12593 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); 12594 } 12595 12596 const air_tag = airTag(block, is_int, .mod, .mod_optimized); 12597 return block.addBinOp(air_tag, casted_lhs, casted_rhs); 12598 } 12599 12600 fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 12601 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 12602 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 12603 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 12604 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 12605 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 12606 const lhs = try sema.resolveInst(extra.lhs); 12607 const rhs = try sema.resolveInst(extra.rhs); 12608 const lhs_ty = sema.typeOf(lhs); 12609 const rhs_ty = sema.typeOf(rhs); 12610 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); 12611 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); 12612 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 12613 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .rem); 12614 12615 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 12616 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 12617 .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, 12618 }); 12619 12620 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 12621 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 12622 12623 const scalar_tag = resolved_type.scalarType().zigTypeTag(); 12624 12625 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 12626 12627 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .rem); 12628 12629 const mod = sema.mod; 12630 const target = mod.getTarget(); 12631 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); 12632 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); 12633 12634 const runtime_src = rs: { 12635 // For integers: 12636 // Either operand being undef is a compile error because there exists 12637 // a possible value (TODO what is it?) that would invoke illegal behavior. 12638 // TODO: can lhs zero be handled better? 12639 // TODO: can lhs undef be handled better? 12640 // 12641 // For floats: 12642 // If the rhs is zero, compile error for division by zero. 12643 // If the rhs is undefined, compile error because there is a possible 12644 // value (zero) for which the division would be illegal behavior. 12645 // If the lhs is undefined, result is undefined. 12646 if (is_int) { 12647 if (maybe_lhs_val) |lhs_val| { 12648 if (lhs_val.isUndef()) { 12649 return sema.failWithUseOfUndef(block, lhs_src); 12650 } 12651 } 12652 if (maybe_rhs_val) |rhs_val| { 12653 if (rhs_val.isUndef()) { 12654 return sema.failWithUseOfUndef(block, rhs_src); 12655 } 12656 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12657 return sema.failWithDivideByZero(block, rhs_src); 12658 } 12659 if (maybe_lhs_val) |lhs_val| { 12660 return sema.addConstant( 12661 resolved_type, 12662 try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src), 12663 ); 12664 } 12665 break :rs lhs_src; 12666 } else { 12667 break :rs rhs_src; 12668 } 12669 } 12670 // float operands 12671 if (maybe_rhs_val) |rhs_val| { 12672 if (rhs_val.isUndef()) { 12673 return sema.failWithUseOfUndef(block, rhs_src); 12674 } 12675 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12676 return sema.failWithDivideByZero(block, rhs_src); 12677 } 12678 } 12679 if (maybe_lhs_val) |lhs_val| { 12680 if (lhs_val.isUndef()) { 12681 return sema.addConstUndef(resolved_type); 12682 } 12683 if (maybe_rhs_val) |rhs_val| { 12684 return sema.addConstant( 12685 resolved_type, 12686 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target), 12687 ); 12688 } else break :rs rhs_src; 12689 } else break :rs lhs_src; 12690 }; 12691 12692 try sema.requireRuntimeBlock(block, src, runtime_src); 12693 12694 if (block.wantSafety()) { 12695 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); 12696 } 12697 12698 const air_tag = airTag(block, is_int, .rem, .rem_optimized); 12699 return block.addBinOp(air_tag, casted_lhs, casted_rhs); 12700 } 12701 12702 fn zirOverflowArithmetic( 12703 sema: *Sema, 12704 block: *Block, 12705 extended: Zir.Inst.Extended.InstData, 12706 zir_tag: Zir.Inst.Extended, 12707 ) CompileError!Air.Inst.Ref { 12708 const tracy = trace(@src()); 12709 defer tracy.end(); 12710 12711 const extra = sema.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data; 12712 const src = LazySrcLoc.nodeOffset(extra.node); 12713 12714 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 12715 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 12716 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node }; 12717 12718 const lhs = try sema.resolveInst(extra.lhs); 12719 const rhs = try sema.resolveInst(extra.rhs); 12720 const ptr = try sema.resolveInst(extra.ptr); 12721 12722 const lhs_ty = sema.typeOf(lhs); 12723 const rhs_ty = sema.typeOf(rhs); 12724 const mod = sema.mod; 12725 const target = mod.getTarget(); 12726 12727 // Note, the types of lhs/rhs (also for shifting)/ptr are already correct as ensured by astgen. 12728 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 12729 const dest_ty = lhs_ty; 12730 if (dest_ty.scalarType().zigTypeTag() != .Int) { 12731 return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(mod)}); 12732 } 12733 12734 const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs); 12735 const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs); 12736 12737 const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty); 12738 const ov_ty = tuple_ty.tupleFields().types[1]; 12739 // TODO: Remove and use `ov_ty` instead. 12740 // This is a temporary type used until overflow arithmetic properly returns `u1` instead of `bool`. 12741 const overflowed_ty = if (dest_ty.zigTypeTag() == .Vector) try Type.vector(sema.arena, dest_ty.vectorLen(), Type.@"bool") else Type.@"bool"; 12742 12743 const result: struct { 12744 /// TODO: Rename to `overflow_bit` and make of type `u1`. 12745 overflowed: Air.Inst.Ref, 12746 wrapped: Air.Inst.Ref, 12747 } = result: { 12748 switch (zir_tag) { 12749 .add_with_overflow => { 12750 // If either of the arguments is zero, `false` is returned and the other is stored 12751 // to the result, even if it is undefined.. 12752 // Otherwise, if either of the argument is undefined, undefined is returned. 12753 if (maybe_lhs_val) |lhs_val| { 12754 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { 12755 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs }; 12756 } 12757 } 12758 if (maybe_rhs_val) |rhs_val| { 12759 if (!rhs_val.isUndef() and (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { 12760 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; 12761 } 12762 } 12763 if (maybe_lhs_val) |lhs_val| { 12764 if (maybe_rhs_val) |rhs_val| { 12765 if (lhs_val.isUndef() or rhs_val.isUndef()) { 12766 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; 12767 } 12768 12769 const result = try sema.intAddWithOverflow(block, src, lhs_val, rhs_val, dest_ty); 12770 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); 12771 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); 12772 break :result .{ .overflowed = overflowed, .wrapped = wrapped }; 12773 } 12774 } 12775 }, 12776 .sub_with_overflow => { 12777 // If the rhs is zero, then the result is lhs and no overflow occured. 12778 // Otherwise, if either result is undefined, both results are undefined. 12779 if (maybe_rhs_val) |rhs_val| { 12780 if (rhs_val.isUndef()) { 12781 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; 12782 } else if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12783 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; 12784 } else if (maybe_lhs_val) |lhs_val| { 12785 if (lhs_val.isUndef()) { 12786 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; 12787 } 12788 12789 const result = try sema.intSubWithOverflow(block, src, lhs_val, rhs_val, dest_ty); 12790 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); 12791 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); 12792 break :result .{ .overflowed = overflowed, .wrapped = wrapped }; 12793 } 12794 } 12795 }, 12796 .mul_with_overflow => { 12797 // If either of the arguments is zero, the result is zero and no overflow occured. 12798 // If either of the arguments is one, the result is the other and no overflow occured. 12799 // Otherwise, if either of the arguments is undefined, both results are undefined. 12800 if (maybe_lhs_val) |lhs_val| { 12801 if (!lhs_val.isUndef()) { 12802 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12803 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; 12804 } else if (try sema.compare(block, src, lhs_val, .eq, Value.one, dest_ty)) { 12805 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs }; 12806 } 12807 } 12808 } 12809 12810 if (maybe_rhs_val) |rhs_val| { 12811 if (!rhs_val.isUndef()) { 12812 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12813 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs }; 12814 } else if (try sema.compare(block, src, rhs_val, .eq, Value.one, dest_ty)) { 12815 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; 12816 } 12817 } 12818 } 12819 12820 if (maybe_lhs_val) |lhs_val| { 12821 if (maybe_rhs_val) |rhs_val| { 12822 if (lhs_val.isUndef() or rhs_val.isUndef()) { 12823 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; 12824 } 12825 12826 const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, target); 12827 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); 12828 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); 12829 break :result .{ .overflowed = overflowed, .wrapped = wrapped }; 12830 } 12831 } 12832 }, 12833 .shl_with_overflow => { 12834 // If lhs is zero, the result is zero and no overflow occurred. 12835 // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred. 12836 // Oterhwise if either of the arguments is undefined, both results are undefined. 12837 if (maybe_lhs_val) |lhs_val| { 12838 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { 12839 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; 12840 } 12841 } 12842 if (maybe_rhs_val) |rhs_val| { 12843 if (!rhs_val.isUndef() and (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { 12844 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; 12845 } 12846 } 12847 if (maybe_lhs_val) |lhs_val| { 12848 if (maybe_rhs_val) |rhs_val| { 12849 if (lhs_val.isUndef() or rhs_val.isUndef()) { 12850 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; 12851 } 12852 12853 const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, target); 12854 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); 12855 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); 12856 break :result .{ .overflowed = overflowed, .wrapped = wrapped }; 12857 } 12858 } 12859 }, 12860 else => unreachable, 12861 } 12862 12863 const air_tag: Air.Inst.Tag = switch (zir_tag) { 12864 .add_with_overflow => .add_with_overflow, 12865 .mul_with_overflow => .mul_with_overflow, 12866 .sub_with_overflow => .sub_with_overflow, 12867 .shl_with_overflow => .shl_with_overflow, 12868 else => unreachable, 12869 }; 12870 12871 const runtime_src = if (maybe_lhs_val == null) lhs_src else rhs_src; 12872 try sema.requireRuntimeBlock(block, src, runtime_src); 12873 12874 const tuple = try block.addInst(.{ 12875 .tag = air_tag, 12876 .data = .{ .ty_pl = .{ 12877 .ty = try block.sema.addType(tuple_ty), 12878 .payload = try block.sema.addExtra(Air.Bin{ 12879 .lhs = lhs, 12880 .rhs = rhs, 12881 }), 12882 } }, 12883 }); 12884 12885 const wrapped = try sema.tupleFieldValByIndex(block, src, tuple, 0, tuple_ty); 12886 try sema.storePtr2(block, src, ptr, ptr_src, wrapped, src, .store); 12887 12888 const overflow_bit = try sema.tupleFieldValByIndex(block, src, tuple, 1, tuple_ty); 12889 const zero_ov_val = if (dest_ty.zigTypeTag() == .Vector) try Value.Tag.repeated.create(sema.arena, Value.zero) else Value.zero; 12890 const zero_ov = try sema.addConstant(ov_ty, zero_ov_val); 12891 12892 const overflowed_inst = if (dest_ty.zigTypeTag() == .Vector) 12893 block.addCmpVector(overflow_bit, .zero, .neq, try sema.addType(ov_ty)) 12894 else 12895 block.addBinOp(.cmp_neq, overflow_bit, zero_ov); 12896 return overflowed_inst; 12897 }; 12898 12899 try sema.storePtr2(block, src, ptr, ptr_src, result.wrapped, src, .store); 12900 return result.overflowed; 12901 } 12902 12903 fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type { 12904 const ov_ty = if (ty.zigTypeTag() == .Vector) try Type.vector(sema.arena, ty.vectorLen(), Type.@"u1") else Type.@"u1"; 12905 12906 const types = try sema.arena.alloc(Type, 2); 12907 const values = try sema.arena.alloc(Value, 2); 12908 const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ 12909 .types = types, 12910 .values = values, 12911 }); 12912 12913 types[0] = ty; 12914 types[1] = ov_ty; 12915 values[0] = Value.initTag(.unreachable_value); 12916 values[1] = Value.initTag(.unreachable_value); 12917 12918 return tuple_ty; 12919 } 12920 12921 fn analyzeArithmetic( 12922 sema: *Sema, 12923 block: *Block, 12924 /// TODO performance investigation: make this comptime? 12925 zir_tag: Zir.Inst.Tag, 12926 lhs: Air.Inst.Ref, 12927 rhs: Air.Inst.Ref, 12928 src: LazySrcLoc, 12929 lhs_src: LazySrcLoc, 12930 rhs_src: LazySrcLoc, 12931 ) CompileError!Air.Inst.Ref { 12932 const lhs_ty = sema.typeOf(lhs); 12933 const rhs_ty = sema.typeOf(rhs); 12934 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); 12935 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); 12936 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 12937 12938 if (lhs_zig_ty_tag == .Pointer) switch (lhs_ty.ptrSize()) { 12939 .One, .Slice => {}, 12940 .Many, .C => { 12941 const air_tag: Air.Inst.Tag = switch (zir_tag) { 12942 .add => .ptr_add, 12943 .sub => .ptr_sub, 12944 else => return sema.fail( 12945 block, 12946 src, 12947 "invalid pointer arithmetic operand: '{s}''", 12948 .{@tagName(zir_tag)}, 12949 ), 12950 }; 12951 return analyzePtrArithmetic(sema, block, src, lhs, rhs, air_tag, lhs_src, rhs_src); 12952 }, 12953 }; 12954 12955 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 12956 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ 12957 .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, 12958 }); 12959 12960 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 12961 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 12962 12963 const scalar_tag = resolved_type.scalarType().zigTypeTag(); 12964 12965 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 12966 12967 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, zir_tag); 12968 12969 const mod = sema.mod; 12970 const target = mod.getTarget(); 12971 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); 12972 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); 12973 const rs: struct { src: LazySrcLoc, air_tag: Air.Inst.Tag } = rs: { 12974 switch (zir_tag) { 12975 .add => { 12976 // For integers: 12977 // If either of the operands are zero, then the other operand is 12978 // returned, even if it is undefined. 12979 // If either of the operands are undefined, it's a compile error 12980 // because there is a possible value for which the addition would 12981 // overflow (max_int), causing illegal behavior. 12982 // For floats: either operand being undef makes the result undef. 12983 if (maybe_lhs_val) |lhs_val| { 12984 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { 12985 return casted_rhs; 12986 } 12987 } 12988 if (maybe_rhs_val) |rhs_val| { 12989 if (rhs_val.isUndef()) { 12990 if (is_int) { 12991 return sema.failWithUseOfUndef(block, rhs_src); 12992 } else { 12993 return sema.addConstUndef(resolved_type); 12994 } 12995 } 12996 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 12997 return casted_lhs; 12998 } 12999 } 13000 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .add_optimized else .add; 13001 if (maybe_lhs_val) |lhs_val| { 13002 if (lhs_val.isUndef()) { 13003 if (is_int) { 13004 return sema.failWithUseOfUndef(block, lhs_src); 13005 } else { 13006 return sema.addConstUndef(resolved_type); 13007 } 13008 } 13009 if (maybe_rhs_val) |rhs_val| { 13010 if (is_int) { 13011 const sum = try sema.intAdd(block, src, lhs_val, rhs_val, resolved_type); 13012 var vector_index: usize = undefined; 13013 if (!(try sema.intFitsInType(block, src, sum, resolved_type, &vector_index))) { 13014 return sema.failWithIntegerOverflow(block, src, resolved_type, sum, vector_index); 13015 } 13016 return sema.addConstant(resolved_type, sum); 13017 } else { 13018 return sema.addConstant( 13019 resolved_type, 13020 try sema.floatAdd(lhs_val, rhs_val, resolved_type), 13021 ); 13022 } 13023 } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; 13024 } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; 13025 }, 13026 .addwrap => { 13027 // Integers only; floats are checked above. 13028 // If either of the operands are zero, the other operand is returned. 13029 // If either of the operands are undefined, the result is undefined. 13030 if (maybe_lhs_val) |lhs_val| { 13031 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { 13032 return casted_rhs; 13033 } 13034 } 13035 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .addwrap_optimized else .addwrap; 13036 if (maybe_rhs_val) |rhs_val| { 13037 if (rhs_val.isUndef()) { 13038 return sema.addConstUndef(resolved_type); 13039 } 13040 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 13041 return casted_lhs; 13042 } 13043 if (maybe_lhs_val) |lhs_val| { 13044 return sema.addConstant( 13045 resolved_type, 13046 try sema.numberAddWrap(block, src, lhs_val, rhs_val, resolved_type), 13047 ); 13048 } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; 13049 } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; 13050 }, 13051 .add_sat => { 13052 // Integers only; floats are checked above. 13053 // If either of the operands are zero, then the other operand is returned. 13054 // If either of the operands are undefined, the result is undefined. 13055 if (maybe_lhs_val) |lhs_val| { 13056 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { 13057 return casted_rhs; 13058 } 13059 } 13060 if (maybe_rhs_val) |rhs_val| { 13061 if (rhs_val.isUndef()) { 13062 return sema.addConstUndef(resolved_type); 13063 } 13064 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 13065 return casted_lhs; 13066 } 13067 if (maybe_lhs_val) |lhs_val| { 13068 const val = if (scalar_tag == .ComptimeInt) 13069 try sema.intAdd(block, src, lhs_val, rhs_val, resolved_type) 13070 else 13071 try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, target); 13072 13073 return sema.addConstant(resolved_type, val); 13074 } else break :rs .{ .src = lhs_src, .air_tag = .add_sat }; 13075 } else break :rs .{ .src = rhs_src, .air_tag = .add_sat }; 13076 }, 13077 .sub => { 13078 // For integers: 13079 // If the rhs is zero, then the other operand is 13080 // returned, even if it is undefined. 13081 // If either of the operands are undefined, it's a compile error 13082 // because there is a possible value for which the subtraction would 13083 // overflow, causing illegal behavior. 13084 // For floats: either operand being undef makes the result undef. 13085 if (maybe_rhs_val) |rhs_val| { 13086 if (rhs_val.isUndef()) { 13087 if (is_int) { 13088 return sema.failWithUseOfUndef(block, rhs_src); 13089 } else { 13090 return sema.addConstUndef(resolved_type); 13091 } 13092 } 13093 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 13094 return casted_lhs; 13095 } 13096 } 13097 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .sub_optimized else .sub; 13098 if (maybe_lhs_val) |lhs_val| { 13099 if (lhs_val.isUndef()) { 13100 if (is_int) { 13101 return sema.failWithUseOfUndef(block, lhs_src); 13102 } else { 13103 return sema.addConstUndef(resolved_type); 13104 } 13105 } 13106 if (maybe_rhs_val) |rhs_val| { 13107 if (is_int) { 13108 const diff = try sema.intSub(block, src, lhs_val, rhs_val, resolved_type); 13109 var vector_index: usize = undefined; 13110 if (!(try sema.intFitsInType(block, src, diff, resolved_type, &vector_index))) { 13111 return sema.failWithIntegerOverflow(block, src, resolved_type, diff, vector_index); 13112 } 13113 return sema.addConstant(resolved_type, diff); 13114 } else { 13115 return sema.addConstant( 13116 resolved_type, 13117 try sema.floatSub(lhs_val, rhs_val, resolved_type), 13118 ); 13119 } 13120 } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; 13121 } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; 13122 }, 13123 .subwrap => { 13124 // Integers only; floats are checked above. 13125 // If the RHS is zero, then the other operand is returned, even if it is undefined. 13126 // If either of the operands are undefined, the result is undefined. 13127 if (maybe_rhs_val) |rhs_val| { 13128 if (rhs_val.isUndef()) { 13129 return sema.addConstUndef(resolved_type); 13130 } 13131 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 13132 return casted_lhs; 13133 } 13134 } 13135 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .subwrap_optimized else .subwrap; 13136 if (maybe_lhs_val) |lhs_val| { 13137 if (lhs_val.isUndef()) { 13138 return sema.addConstUndef(resolved_type); 13139 } 13140 if (maybe_rhs_val) |rhs_val| { 13141 return sema.addConstant( 13142 resolved_type, 13143 try sema.numberSubWrap(block, src, lhs_val, rhs_val, resolved_type), 13144 ); 13145 } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; 13146 } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; 13147 }, 13148 .sub_sat => { 13149 // Integers only; floats are checked above. 13150 // If the RHS is zero, result is LHS. 13151 // If either of the operands are undefined, result is undefined. 13152 if (maybe_rhs_val) |rhs_val| { 13153 if (rhs_val.isUndef()) { 13154 return sema.addConstUndef(resolved_type); 13155 } 13156 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 13157 return casted_lhs; 13158 } 13159 } 13160 if (maybe_lhs_val) |lhs_val| { 13161 if (lhs_val.isUndef()) { 13162 return sema.addConstUndef(resolved_type); 13163 } 13164 if (maybe_rhs_val) |rhs_val| { 13165 const val = if (scalar_tag == .ComptimeInt) 13166 try sema.intSub(block, src, lhs_val, rhs_val, resolved_type) 13167 else 13168 try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, target); 13169 13170 return sema.addConstant(resolved_type, val); 13171 } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat }; 13172 } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat }; 13173 }, 13174 .mul => { 13175 // For integers: 13176 // If either of the operands are zero, the result is zero. 13177 // If either of the operands are one, the result is the other 13178 // operand, even if it is undefined. 13179 // If either of the operands are undefined, it's a compile error 13180 // because there is a possible value for which the addition would 13181 // overflow (max_int), causing illegal behavior. 13182 // For floats: either operand being undef makes the result undef. 13183 if (maybe_lhs_val) |lhs_val| { 13184 if (!lhs_val.isUndef()) { 13185 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 13186 return sema.addConstant(resolved_type, Value.zero); 13187 } 13188 if (try sema.compare(block, src, lhs_val, .eq, Value.one, resolved_type)) { 13189 return casted_rhs; 13190 } 13191 } 13192 } 13193 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mul_optimized else .mul; 13194 if (maybe_rhs_val) |rhs_val| { 13195 if (rhs_val.isUndef()) { 13196 if (is_int) { 13197 return sema.failWithUseOfUndef(block, rhs_src); 13198 } else { 13199 return sema.addConstUndef(resolved_type); 13200 } 13201 } 13202 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 13203 return sema.addConstant(resolved_type, Value.zero); 13204 } 13205 if (try sema.compare(block, src, rhs_val, .eq, Value.one, resolved_type)) { 13206 return casted_lhs; 13207 } 13208 if (maybe_lhs_val) |lhs_val| { 13209 if (lhs_val.isUndef()) { 13210 if (is_int) { 13211 return sema.failWithUseOfUndef(block, lhs_src); 13212 } else { 13213 return sema.addConstUndef(resolved_type); 13214 } 13215 } 13216 if (is_int) { 13217 const product = try lhs_val.intMul(rhs_val, resolved_type, sema.arena, target); 13218 var vector_index: usize = undefined; 13219 if (!(try sema.intFitsInType(block, src, product, resolved_type, &vector_index))) { 13220 return sema.failWithIntegerOverflow(block, src, resolved_type, product, vector_index); 13221 } 13222 return sema.addConstant(resolved_type, product); 13223 } else { 13224 return sema.addConstant( 13225 resolved_type, 13226 try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, target), 13227 ); 13228 } 13229 } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; 13230 } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; 13231 }, 13232 .mulwrap => { 13233 // Integers only; floats are handled above. 13234 // If either of the operands are zero, result is zero. 13235 // If either of the operands are one, result is the other operand. 13236 // If either of the operands are undefined, result is undefined. 13237 if (maybe_lhs_val) |lhs_val| { 13238 if (!lhs_val.isUndef()) { 13239 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 13240 return sema.addConstant(resolved_type, Value.zero); 13241 } 13242 if (try sema.compare(block, src, lhs_val, .eq, Value.one, resolved_type)) { 13243 return casted_rhs; 13244 } 13245 } 13246 } 13247 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mulwrap_optimized else .mulwrap; 13248 if (maybe_rhs_val) |rhs_val| { 13249 if (rhs_val.isUndef()) { 13250 return sema.addConstUndef(resolved_type); 13251 } 13252 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 13253 return sema.addConstant(resolved_type, Value.zero); 13254 } 13255 if (try sema.compare(block, src, rhs_val, .eq, Value.one, resolved_type)) { 13256 return casted_lhs; 13257 } 13258 if (maybe_lhs_val) |lhs_val| { 13259 if (lhs_val.isUndef()) { 13260 return sema.addConstUndef(resolved_type); 13261 } 13262 return sema.addConstant( 13263 resolved_type, 13264 try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, target), 13265 ); 13266 } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; 13267 } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; 13268 }, 13269 .mul_sat => { 13270 // Integers only; floats are checked above. 13271 // If either of the operands are zero, result is zero. 13272 // If either of the operands are one, result is the other operand. 13273 // If either of the operands are undefined, result is undefined. 13274 if (maybe_lhs_val) |lhs_val| { 13275 if (!lhs_val.isUndef()) { 13276 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 13277 return sema.addConstant(resolved_type, Value.zero); 13278 } 13279 if (try sema.compare(block, src, lhs_val, .eq, Value.one, resolved_type)) { 13280 return casted_rhs; 13281 } 13282 } 13283 } 13284 if (maybe_rhs_val) |rhs_val| { 13285 if (rhs_val.isUndef()) { 13286 return sema.addConstUndef(resolved_type); 13287 } 13288 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { 13289 return sema.addConstant(resolved_type, Value.zero); 13290 } 13291 if (try sema.compare(block, src, rhs_val, .eq, Value.one, resolved_type)) { 13292 return casted_lhs; 13293 } 13294 if (maybe_lhs_val) |lhs_val| { 13295 if (lhs_val.isUndef()) { 13296 return sema.addConstUndef(resolved_type); 13297 } 13298 13299 const val = if (scalar_tag == .ComptimeInt) 13300 try lhs_val.intMul(rhs_val, resolved_type, sema.arena, target) 13301 else 13302 try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, target); 13303 13304 return sema.addConstant(resolved_type, val); 13305 } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat }; 13306 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat }; 13307 }, 13308 else => unreachable, 13309 } 13310 }; 13311 13312 try sema.requireRuntimeBlock(block, src, rs.src); 13313 if (block.wantSafety()) { 13314 if (scalar_tag == .Int) { 13315 const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) { 13316 .add => .add_with_overflow, 13317 .sub => .sub_with_overflow, 13318 .mul => .mul_with_overflow, 13319 else => null, 13320 }; 13321 if (maybe_op_ov) |op_ov_tag| { 13322 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(resolved_type); 13323 const op_ov = try block.addInst(.{ 13324 .tag = op_ov_tag, 13325 .data = .{ .ty_pl = .{ 13326 .ty = try sema.addType(op_ov_tuple_ty), 13327 .payload = try sema.addExtra(Air.Bin{ 13328 .lhs = casted_lhs, 13329 .rhs = casted_rhs, 13330 }), 13331 } }, 13332 }); 13333 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); 13334 const any_ov_bit = if (resolved_type.zigTypeTag() == .Vector) 13335 try block.addInst(.{ 13336 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, 13337 .data = .{ .reduce = .{ 13338 .operand = ov_bit, 13339 .operation = .Or, 13340 } }, 13341 }) 13342 else 13343 ov_bit; 13344 const zero_ov = try sema.addConstant(Type.@"u1", Value.zero); 13345 const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); 13346 13347 try sema.addSafetyCheck(block, no_ov, .integer_overflow); 13348 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); 13349 } 13350 } 13351 } 13352 return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs); 13353 } 13354 13355 fn analyzePtrArithmetic( 13356 sema: *Sema, 13357 block: *Block, 13358 op_src: LazySrcLoc, 13359 ptr: Air.Inst.Ref, 13360 uncasted_offset: Air.Inst.Ref, 13361 air_tag: Air.Inst.Tag, 13362 ptr_src: LazySrcLoc, 13363 offset_src: LazySrcLoc, 13364 ) CompileError!Air.Inst.Ref { 13365 // TODO if the operand is comptime-known to be negative, or is a negative int, 13366 // coerce to isize instead of usize. 13367 const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src); 13368 const target = sema.mod.getTarget(); 13369 const opt_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, ptr); 13370 const opt_off_val = try sema.resolveDefinedValue(block, offset_src, offset); 13371 const ptr_ty = sema.typeOf(ptr); 13372 const ptr_info = ptr_ty.ptrInfo().data; 13373 const elem_ty = if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Array) 13374 ptr_info.pointee_type.childType() 13375 else 13376 ptr_info.pointee_type; 13377 13378 const new_ptr_ty = t: { 13379 // Calculate the new pointer alignment. 13380 // This code is duplicated in `elemPtrType`. 13381 if (ptr_info.@"align" == 0) { 13382 // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness. 13383 break :t ptr_ty; 13384 } 13385 // If the addend is not a comptime-known value we can still count on 13386 // it being a multiple of the type size. 13387 const elem_size = elem_ty.abiSize(target); 13388 const addend = if (opt_off_val) |off_val| a: { 13389 const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(target)); 13390 break :a elem_size * off_int; 13391 } else elem_size; 13392 13393 // The resulting pointer is aligned to the lcd between the offset (an 13394 // arbitrary number) and the alignment factor (always a power of two, 13395 // non zero). 13396 const new_align = @as(u32, 1) << @intCast(u5, @ctz(addend | ptr_info.@"align")); 13397 13398 break :t try Type.ptr(sema.arena, sema.mod, .{ 13399 .pointee_type = ptr_info.pointee_type, 13400 .sentinel = ptr_info.sentinel, 13401 .@"align" = new_align, 13402 .@"addrspace" = ptr_info.@"addrspace", 13403 .mutable = ptr_info.mutable, 13404 .@"allowzero" = ptr_info.@"allowzero", 13405 .@"volatile" = ptr_info.@"volatile", 13406 .size = ptr_info.size, 13407 }); 13408 }; 13409 13410 const runtime_src = rs: { 13411 if (opt_ptr_val) |ptr_val| { 13412 if (opt_off_val) |offset_val| { 13413 if (ptr_val.isUndef()) return sema.addConstUndef(new_ptr_ty); 13414 13415 const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(target)); 13416 if (offset_int == 0) return ptr; 13417 if (try ptr_val.getUnsignedIntAdvanced(target, sema.kit(block, ptr_src))) |addr| { 13418 const elem_size = elem_ty.abiSize(target); 13419 const new_addr = switch (air_tag) { 13420 .ptr_add => addr + elem_size * offset_int, 13421 .ptr_sub => addr - elem_size * offset_int, 13422 else => unreachable, 13423 }; 13424 const new_ptr_val = try Value.Tag.int_u64.create(sema.arena, new_addr); 13425 return sema.addConstant(new_ptr_ty, new_ptr_val); 13426 } 13427 if (air_tag == .ptr_sub) { 13428 return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{}); 13429 } 13430 const new_ptr_val = try ptr_val.elemPtr(ptr_ty, sema.arena, offset_int, sema.mod); 13431 return sema.addConstant(new_ptr_ty, new_ptr_val); 13432 } else break :rs offset_src; 13433 } else break :rs ptr_src; 13434 }; 13435 13436 try sema.requireRuntimeBlock(block, op_src, runtime_src); 13437 return block.addInst(.{ 13438 .tag = air_tag, 13439 .data = .{ .ty_pl = .{ 13440 .ty = try sema.addType(new_ptr_ty), 13441 .payload = try sema.addExtra(Air.Bin{ 13442 .lhs = ptr, 13443 .rhs = offset, 13444 }), 13445 } }, 13446 }); 13447 } 13448 13449 fn zirLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 13450 const tracy = trace(@src()); 13451 defer tracy.end(); 13452 13453 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 13454 const src = inst_data.src(); 13455 const ptr_src = src; // TODO better source location 13456 const ptr = try sema.resolveInst(inst_data.operand); 13457 return sema.analyzeLoad(block, src, ptr, ptr_src); 13458 } 13459 13460 fn zirAsm( 13461 sema: *Sema, 13462 block: *Block, 13463 extended: Zir.Inst.Extended.InstData, 13464 ) CompileError!Air.Inst.Ref { 13465 const tracy = trace(@src()); 13466 defer tracy.end(); 13467 13468 const extra = sema.code.extraData(Zir.Inst.Asm, extended.operand); 13469 const src = LazySrcLoc.nodeOffset(extra.data.src_node); 13470 const ret_ty_src: LazySrcLoc = .{ .node_offset_asm_ret_ty = extra.data.src_node }; 13471 const outputs_len = @truncate(u5, extended.small); 13472 const inputs_len = @truncate(u5, extended.small >> 5); 13473 const clobbers_len = @truncate(u5, extended.small >> 10); 13474 const is_volatile = @truncate(u1, extended.small >> 15) != 0; 13475 const is_global_assembly = sema.func == null; 13476 13477 if (extra.data.asm_source == 0) { 13478 // This can move to become an AstGen error after inline assembly improvements land 13479 // and stage1 code matches stage2 code. 13480 return sema.fail(block, src, "assembly code must use string literal syntax", .{}); 13481 } 13482 13483 const asm_source = sema.code.nullTerminatedString(extra.data.asm_source); 13484 13485 if (is_global_assembly) { 13486 if (outputs_len != 0) { 13487 return sema.fail(block, src, "module-level assembly does not support outputs", .{}); 13488 } 13489 if (inputs_len != 0) { 13490 return sema.fail(block, src, "module-level assembly does not support inputs", .{}); 13491 } 13492 if (clobbers_len != 0) { 13493 return sema.fail(block, src, "module-level assembly does not support clobbers", .{}); 13494 } 13495 if (is_volatile) { 13496 return sema.fail(block, src, "volatile keyword is redundant on module-level assembly", .{}); 13497 } 13498 try sema.mod.addGlobalAssembly(sema.owner_decl_index, asm_source); 13499 return Air.Inst.Ref.void_value; 13500 } 13501 13502 if (block.is_comptime) { 13503 try sema.requireRuntimeBlock(block, src, null); 13504 } 13505 13506 var extra_i = extra.end; 13507 var output_type_bits = extra.data.output_type_bits; 13508 var needed_capacity: usize = @typeInfo(Air.Asm).Struct.fields.len + outputs_len + inputs_len; 13509 13510 const ConstraintName = struct { c: []const u8, n: []const u8 }; 13511 const out_args = try sema.arena.alloc(Air.Inst.Ref, outputs_len); 13512 const outputs = try sema.arena.alloc(ConstraintName, outputs_len); 13513 var expr_ty = Air.Inst.Ref.void_type; 13514 13515 for (out_args) |*arg, out_i| { 13516 const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i); 13517 extra_i = output.end; 13518 13519 const is_type = @truncate(u1, output_type_bits) != 0; 13520 output_type_bits >>= 1; 13521 13522 if (is_type) { 13523 // Indicate the output is the asm instruction return value. 13524 arg.* = .none; 13525 const out_ty = try sema.resolveType(block, ret_ty_src, output.data.operand); 13526 try sema.queueFullTypeResolution(out_ty); 13527 expr_ty = try sema.addType(out_ty); 13528 } else { 13529 arg.* = try sema.resolveInst(output.data.operand); 13530 } 13531 13532 const constraint = sema.code.nullTerminatedString(output.data.constraint); 13533 const name = sema.code.nullTerminatedString(output.data.name); 13534 needed_capacity += (constraint.len + name.len + (2 + 3)) / 4; 13535 13536 outputs[out_i] = .{ .c = constraint, .n = name }; 13537 } 13538 13539 const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len); 13540 const inputs = try sema.arena.alloc(ConstraintName, inputs_len); 13541 13542 for (args) |*arg, arg_i| { 13543 const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i); 13544 extra_i = input.end; 13545 13546 const uncasted_arg = try sema.resolveInst(input.data.operand); 13547 const uncasted_arg_ty = sema.typeOf(uncasted_arg); 13548 switch (uncasted_arg_ty.zigTypeTag()) { 13549 .ComptimeInt => arg.* = try sema.coerce(block, Type.initTag(.usize), uncasted_arg, src), 13550 .ComptimeFloat => arg.* = try sema.coerce(block, Type.initTag(.f64), uncasted_arg, src), 13551 else => { 13552 arg.* = uncasted_arg; 13553 try sema.queueFullTypeResolution(uncasted_arg_ty); 13554 }, 13555 } 13556 13557 const constraint = sema.code.nullTerminatedString(input.data.constraint); 13558 const name = sema.code.nullTerminatedString(input.data.name); 13559 needed_capacity += (constraint.len + name.len + (2 + 3)) / 4; 13560 inputs[arg_i] = .{ .c = constraint, .n = name }; 13561 } 13562 13563 const clobbers = try sema.arena.alloc([]const u8, clobbers_len); 13564 for (clobbers) |*name| { 13565 name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]); 13566 extra_i += 1; 13567 13568 needed_capacity += name.*.len / 4 + 1; 13569 } 13570 13571 needed_capacity += (asm_source.len + 3) / 4; 13572 13573 const gpa = sema.gpa; 13574 try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity); 13575 const asm_air = try block.addInst(.{ 13576 .tag = .assembly, 13577 .data = .{ .ty_pl = .{ 13578 .ty = expr_ty, 13579 .payload = sema.addExtraAssumeCapacity(Air.Asm{ 13580 .source_len = @intCast(u32, asm_source.len), 13581 .outputs_len = outputs_len, 13582 .inputs_len = @intCast(u32, args.len), 13583 .flags = (@as(u32, @boolToInt(is_volatile)) << 31) | @intCast(u32, clobbers.len), 13584 }), 13585 } }, 13586 }); 13587 sema.appendRefsAssumeCapacity(out_args); 13588 sema.appendRefsAssumeCapacity(args); 13589 for (outputs) |o| { 13590 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); 13591 mem.copy(u8, buffer, o.c); 13592 buffer[o.c.len] = 0; 13593 mem.copy(u8, buffer[o.c.len + 1 ..], o.n); 13594 buffer[o.c.len + 1 + o.n.len] = 0; 13595 sema.air_extra.items.len += (o.c.len + o.n.len + (2 + 3)) / 4; 13596 } 13597 for (inputs) |input| { 13598 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); 13599 mem.copy(u8, buffer, input.c); 13600 buffer[input.c.len] = 0; 13601 mem.copy(u8, buffer[input.c.len + 1 ..], input.n); 13602 buffer[input.c.len + 1 + input.n.len] = 0; 13603 sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4; 13604 } 13605 for (clobbers) |clobber| { 13606 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); 13607 mem.copy(u8, buffer, clobber); 13608 buffer[clobber.len] = 0; 13609 sema.air_extra.items.len += clobber.len / 4 + 1; 13610 } 13611 { 13612 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); 13613 mem.copy(u8, buffer, asm_source); 13614 sema.air_extra.items.len += (asm_source.len + 3) / 4; 13615 } 13616 return asm_air; 13617 } 13618 13619 /// Only called for equality operators. See also `zirCmp`. 13620 fn zirCmpEq( 13621 sema: *Sema, 13622 block: *Block, 13623 inst: Zir.Inst.Index, 13624 op: std.math.CompareOperator, 13625 air_tag: Air.Inst.Tag, 13626 ) CompileError!Air.Inst.Ref { 13627 const tracy = trace(@src()); 13628 defer tracy.end(); 13629 13630 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 13631 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 13632 const src: LazySrcLoc = inst_data.src(); 13633 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 13634 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 13635 const lhs = try sema.resolveInst(extra.lhs); 13636 const rhs = try sema.resolveInst(extra.rhs); 13637 13638 const lhs_ty = sema.typeOf(lhs); 13639 const rhs_ty = sema.typeOf(rhs); 13640 const lhs_ty_tag = lhs_ty.zigTypeTag(); 13641 const rhs_ty_tag = rhs_ty.zigTypeTag(); 13642 if (lhs_ty_tag == .Null and rhs_ty_tag == .Null) { 13643 // null == null, null != null 13644 if (op == .eq) { 13645 return Air.Inst.Ref.bool_true; 13646 } else { 13647 return Air.Inst.Ref.bool_false; 13648 } 13649 } 13650 13651 // comparing null with optionals 13652 if (lhs_ty_tag == .Null and (rhs_ty_tag == .Optional or rhs_ty.isCPtr())) { 13653 return sema.analyzeIsNull(block, src, rhs, op == .neq); 13654 } 13655 if (rhs_ty_tag == .Null and (lhs_ty_tag == .Optional or lhs_ty.isCPtr())) { 13656 return sema.analyzeIsNull(block, src, lhs, op == .neq); 13657 } 13658 13659 if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) { 13660 const non_null_type = if (lhs_ty_tag == .Null) rhs_ty else lhs_ty; 13661 return sema.fail(block, src, "comparison of '{}' with null", .{non_null_type.fmt(sema.mod)}); 13662 } 13663 13664 if (lhs_ty_tag == .Union and (rhs_ty_tag == .EnumLiteral or rhs_ty_tag == .Enum)) { 13665 return sema.analyzeCmpUnionTag(block, src, lhs, lhs_src, rhs, rhs_src, op); 13666 } 13667 if (rhs_ty_tag == .Union and (lhs_ty_tag == .EnumLiteral or lhs_ty_tag == .Enum)) { 13668 return sema.analyzeCmpUnionTag(block, src, rhs, rhs_src, lhs, lhs_src, op); 13669 } 13670 13671 if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) { 13672 const runtime_src: LazySrcLoc = src: { 13673 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lval| { 13674 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rval| { 13675 if (lval.isUndef() or rval.isUndef()) { 13676 return sema.addConstUndef(Type.bool); 13677 } 13678 // TODO optimisation opportunity: evaluate if mem.eql is faster with the names, 13679 // or calling to Module.getErrorValue to get the values and then compare them is 13680 // faster. 13681 const lhs_name = lval.castTag(.@"error").?.data.name; 13682 const rhs_name = rval.castTag(.@"error").?.data.name; 13683 if (mem.eql(u8, lhs_name, rhs_name) == (op == .eq)) { 13684 return Air.Inst.Ref.bool_true; 13685 } else { 13686 return Air.Inst.Ref.bool_false; 13687 } 13688 } else { 13689 break :src rhs_src; 13690 } 13691 } else { 13692 break :src lhs_src; 13693 } 13694 }; 13695 try sema.requireRuntimeBlock(block, src, runtime_src); 13696 return block.addBinOp(air_tag, lhs, rhs); 13697 } 13698 if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) { 13699 const lhs_as_type = try sema.analyzeAsType(block, lhs_src, lhs); 13700 const rhs_as_type = try sema.analyzeAsType(block, rhs_src, rhs); 13701 if (lhs_as_type.eql(rhs_as_type, sema.mod) == (op == .eq)) { 13702 return Air.Inst.Ref.bool_true; 13703 } else { 13704 return Air.Inst.Ref.bool_false; 13705 } 13706 } 13707 return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, true); 13708 } 13709 13710 fn analyzeCmpUnionTag( 13711 sema: *Sema, 13712 block: *Block, 13713 src: LazySrcLoc, 13714 un: Air.Inst.Ref, 13715 un_src: LazySrcLoc, 13716 tag: Air.Inst.Ref, 13717 tag_src: LazySrcLoc, 13718 op: std.math.CompareOperator, 13719 ) CompileError!Air.Inst.Ref { 13720 const union_ty = try sema.resolveTypeFields(block, un_src, sema.typeOf(un)); 13721 const union_tag_ty = union_ty.unionTagType() orelse { 13722 const msg = msg: { 13723 const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{}); 13724 errdefer msg.destroy(sema.gpa); 13725 try sema.mod.errNoteNonLazy(union_ty.declSrcLoc(sema.mod), msg, "union '{}' is not a tagged union", .{union_ty.fmt(sema.mod)}); 13726 break :msg msg; 13727 }; 13728 return sema.failWithOwnedErrorMsg(msg); 13729 }; 13730 // Coerce both the union and the tag to the union's tag type, and then execute the 13731 // enum comparison codepath. 13732 const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src); 13733 const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src); 13734 13735 if (try sema.resolveMaybeUndefVal(block, tag_src, coerced_tag)) |enum_val| { 13736 if (enum_val.isUndef()) return sema.addConstUndef(Type.bool); 13737 const field_ty = union_ty.unionFieldType(enum_val, sema.mod); 13738 if (field_ty.zigTypeTag() == .NoReturn) { 13739 return Air.Inst.Ref.bool_false; 13740 } 13741 } 13742 13743 return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src); 13744 } 13745 13746 /// Only called for non-equality operators. See also `zirCmpEq`. 13747 fn zirCmp( 13748 sema: *Sema, 13749 block: *Block, 13750 inst: Zir.Inst.Index, 13751 op: std.math.CompareOperator, 13752 ) CompileError!Air.Inst.Ref { 13753 const tracy = trace(@src()); 13754 defer tracy.end(); 13755 13756 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 13757 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 13758 const src: LazySrcLoc = inst_data.src(); 13759 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 13760 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 13761 const lhs = try sema.resolveInst(extra.lhs); 13762 const rhs = try sema.resolveInst(extra.rhs); 13763 return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, false); 13764 } 13765 13766 fn analyzeCmp( 13767 sema: *Sema, 13768 block: *Block, 13769 src: LazySrcLoc, 13770 lhs: Air.Inst.Ref, 13771 rhs: Air.Inst.Ref, 13772 op: std.math.CompareOperator, 13773 lhs_src: LazySrcLoc, 13774 rhs_src: LazySrcLoc, 13775 is_equality_cmp: bool, 13776 ) CompileError!Air.Inst.Ref { 13777 const lhs_ty = sema.typeOf(lhs); 13778 const rhs_ty = sema.typeOf(rhs); 13779 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 13780 13781 if (lhs_ty.zigTypeTag() == .Vector and rhs_ty.zigTypeTag() == .Vector) { 13782 return sema.cmpVector(block, src, lhs, rhs, op, lhs_src, rhs_src); 13783 } 13784 if (lhs_ty.isNumeric() and rhs_ty.isNumeric()) { 13785 // This operation allows any combination of integer and float types, regardless of the 13786 // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for 13787 // numeric types. 13788 return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src); 13789 } 13790 const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; 13791 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } }); 13792 if (!resolved_type.isSelfComparable(is_equality_cmp)) { 13793 return sema.fail(block, src, "operator {s} not allowed for type '{}'", .{ 13794 compareOperatorName(op), resolved_type.fmt(sema.mod), 13795 }); 13796 } 13797 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); 13798 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); 13799 return sema.cmpSelf(block, src, casted_lhs, casted_rhs, op, lhs_src, rhs_src); 13800 } 13801 13802 fn compareOperatorName(comp: std.math.CompareOperator) []const u8 { 13803 return switch (comp) { 13804 .lt => "<", 13805 .lte => "<=", 13806 .eq => "==", 13807 .gte => ">=", 13808 .gt => ">", 13809 .neq => "!=", 13810 }; 13811 } 13812 13813 fn cmpSelf( 13814 sema: *Sema, 13815 block: *Block, 13816 src: LazySrcLoc, 13817 casted_lhs: Air.Inst.Ref, 13818 casted_rhs: Air.Inst.Ref, 13819 op: std.math.CompareOperator, 13820 lhs_src: LazySrcLoc, 13821 rhs_src: LazySrcLoc, 13822 ) CompileError!Air.Inst.Ref { 13823 const resolved_type = sema.typeOf(casted_lhs); 13824 const runtime_src: LazySrcLoc = src: { 13825 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| { 13826 if (lhs_val.isUndef()) return sema.addConstUndef(Type.bool); 13827 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| { 13828 if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool); 13829 13830 if (resolved_type.zigTypeTag() == .Vector) { 13831 const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.@"bool"); 13832 const cmp_val = try sema.compareVector(block, lhs_src, lhs_val, op, rhs_val, resolved_type); 13833 return sema.addConstant(result_ty, cmp_val); 13834 } 13835 13836 if (try sema.compare(block, lhs_src, lhs_val, op, rhs_val, resolved_type)) { 13837 return Air.Inst.Ref.bool_true; 13838 } else { 13839 return Air.Inst.Ref.bool_false; 13840 } 13841 } else { 13842 if (resolved_type.zigTypeTag() == .Bool) { 13843 // We can lower bool eq/neq more efficiently. 13844 return sema.runtimeBoolCmp(block, src, op, casted_rhs, lhs_val.toBool(), rhs_src); 13845 } 13846 break :src rhs_src; 13847 } 13848 } else { 13849 // For bools, we still check the other operand, because we can lower 13850 // bool eq/neq more efficiently. 13851 if (resolved_type.zigTypeTag() == .Bool) { 13852 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| { 13853 if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool); 13854 return sema.runtimeBoolCmp(block, src, op, casted_lhs, rhs_val.toBool(), lhs_src); 13855 } 13856 } 13857 break :src lhs_src; 13858 } 13859 }; 13860 try sema.requireRuntimeBlock(block, src, runtime_src); 13861 if (resolved_type.zigTypeTag() == .Vector) { 13862 const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.@"bool"); 13863 const result_ty_ref = try sema.addType(result_ty); 13864 return block.addCmpVector(casted_lhs, casted_rhs, op, result_ty_ref); 13865 } 13866 const tag = Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized); 13867 return block.addBinOp(tag, casted_lhs, casted_rhs); 13868 } 13869 13870 /// cmp_eq (x, false) => not(x) 13871 /// cmp_eq (x, true ) => x 13872 /// cmp_neq(x, false) => x 13873 /// cmp_neq(x, true ) => not(x) 13874 fn runtimeBoolCmp( 13875 sema: *Sema, 13876 block: *Block, 13877 src: LazySrcLoc, 13878 op: std.math.CompareOperator, 13879 lhs: Air.Inst.Ref, 13880 rhs: bool, 13881 runtime_src: LazySrcLoc, 13882 ) CompileError!Air.Inst.Ref { 13883 if ((op == .neq) == rhs) { 13884 try sema.requireRuntimeBlock(block, src, runtime_src); 13885 return block.addTyOp(.not, Type.bool, lhs); 13886 } else { 13887 return lhs; 13888 } 13889 } 13890 13891 fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 13892 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 13893 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 13894 const ty = try sema.resolveType(block, operand_src, inst_data.operand); 13895 switch (ty.zigTypeTag()) { 13896 .Fn, 13897 .NoReturn, 13898 .Undefined, 13899 .Null, 13900 .BoundFn, 13901 .Opaque, 13902 => return sema.fail(block, operand_src, "no size available for type '{}'", .{ty.fmt(sema.mod)}), 13903 13904 .Type, 13905 .EnumLiteral, 13906 .ComptimeFloat, 13907 .ComptimeInt, 13908 .Void, 13909 => return sema.addIntUnsigned(Type.comptime_int, 0), 13910 13911 .Bool, 13912 .Int, 13913 .Float, 13914 .Pointer, 13915 .Array, 13916 .Struct, 13917 .Optional, 13918 .ErrorUnion, 13919 .ErrorSet, 13920 .Enum, 13921 .Union, 13922 .Vector, 13923 .Frame, 13924 .AnyFrame, 13925 => {}, 13926 } 13927 const target = sema.mod.getTarget(); 13928 const val = try ty.lazyAbiSize(target, sema.arena); 13929 if (val.tag() == .lazy_size) { 13930 try sema.queueFullTypeResolution(ty); 13931 } 13932 return sema.addConstant(Type.comptime_int, val); 13933 } 13934 13935 fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 13936 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 13937 const src = inst_data.src(); 13938 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 13939 const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand); 13940 const target = sema.mod.getTarget(); 13941 const bit_size = try operand_ty.bitSizeAdvanced(target, sema.kit(block, src)); 13942 return sema.addIntUnsigned(Type.comptime_int, bit_size); 13943 } 13944 13945 fn zirThis( 13946 sema: *Sema, 13947 block: *Block, 13948 extended: Zir.Inst.Extended.InstData, 13949 ) CompileError!Air.Inst.Ref { 13950 const this_decl_index = block.namespace.getDeclIndex(); 13951 const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand)); 13952 return sema.analyzeDeclVal(block, src, this_decl_index); 13953 } 13954 13955 fn zirClosureCapture( 13956 sema: *Sema, 13957 block: *Block, 13958 inst: Zir.Inst.Index, 13959 ) CompileError!void { 13960 // TODO: Compile error when closed over values are modified 13961 const inst_data = sema.code.instructions.items(.data)[inst].un_tok; 13962 const src = inst_data.src(); 13963 // Closures are not necessarily constant values. For example, the 13964 // code might do something like this: 13965 // fn foo(x: anytype) void { const S = struct {field: @TypeOf(x)}; } 13966 // ...in which case the closure_capture instruction has access to a runtime 13967 // value only. In such case we preserve the type and use a dummy runtime value. 13968 const operand = try sema.resolveInst(inst_data.operand); 13969 const val = (try sema.resolveMaybeUndefValAllowVariables(block, src, operand)) orelse 13970 Value.initTag(.generic_poison); 13971 13972 try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, .{ 13973 .ty = try sema.typeOf(operand).copy(sema.perm_arena), 13974 .val = try val.copy(sema.perm_arena), 13975 }); 13976 } 13977 13978 fn zirClosureGet( 13979 sema: *Sema, 13980 block: *Block, 13981 inst: Zir.Inst.Index, 13982 ) CompileError!Air.Inst.Ref { 13983 // TODO CLOSURE: Test this with inline functions 13984 const inst_data = sema.code.instructions.items(.data)[inst].inst_node; 13985 var scope: *CaptureScope = sema.mod.declPtr(block.src_decl).src_scope.?; 13986 // Note: The target closure must be in this scope list. 13987 // If it's not here, the zir is invalid, or the list is broken. 13988 const tv = while (true) { 13989 // Note: We don't need to add a dependency here, because 13990 // decls always depend on their lexical parents. 13991 13992 // Fail this decl if a scope it depended on failed. 13993 if (scope.failed()) { 13994 if (sema.owner_func) |owner_func| { 13995 owner_func.state = .dependency_failure; 13996 } else { 13997 sema.owner_decl.analysis = .dependency_failure; 13998 } 13999 return error.AnalysisFail; 14000 } 14001 if (scope.captures.getPtr(inst_data.inst)) |tv| { 14002 break tv; 14003 } 14004 scope = scope.parent.?; 14005 } else unreachable; 14006 14007 if (tv.val.tag() == .generic_poison and !block.is_typeof and !block.is_comptime and sema.func != null) { 14008 const msg = msg: { 14009 const name = name: { 14010 const file = sema.owner_decl.getFileScope(); 14011 const tree = file.getTree(sema.mod.gpa) catch |err| { 14012 // In this case we emit a warning + a less precise source location. 14013 log.warn("unable to load {s}: {s}", .{ 14014 file.sub_file_path, @errorName(err), 14015 }); 14016 break :name null; 14017 }; 14018 const node = sema.owner_decl.relativeToNodeIndex(inst_data.src_node); 14019 const token = tree.nodes.items(.main_token)[node]; 14020 break :name tree.tokenSlice(token); 14021 }; 14022 14023 const msg = if (name) |some| 14024 try sema.errMsg(block, inst_data.src(), "'{s}' not accessible from inner function", .{some}) 14025 else 14026 try sema.errMsg(block, inst_data.src(), "variable not accessible from inner function", .{}); 14027 errdefer msg.destroy(sema.gpa); 14028 14029 try sema.errNote(block, LazySrcLoc.nodeOffset(0), msg, "crossed function definition here", .{}); 14030 14031 // TODO add "declared here" note 14032 break :msg msg; 14033 }; 14034 return sema.failWithOwnedErrorMsg(msg); 14035 } 14036 14037 return sema.addConstant(tv.ty, tv.val); 14038 } 14039 14040 fn zirRetAddr( 14041 sema: *Sema, 14042 block: *Block, 14043 extended: Zir.Inst.Extended.InstData, 14044 ) CompileError!Air.Inst.Ref { 14045 const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand)); 14046 try sema.requireRuntimeBlock(block, src, null); 14047 return try block.addNoOp(.ret_addr); 14048 } 14049 14050 fn zirFrameAddress( 14051 sema: *Sema, 14052 block: *Block, 14053 extended: Zir.Inst.Extended.InstData, 14054 ) CompileError!Air.Inst.Ref { 14055 const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand)); 14056 try sema.requireRuntimeBlock(block, src, null); 14057 return try block.addNoOp(.frame_addr); 14058 } 14059 14060 fn zirBuiltinSrc( 14061 sema: *Sema, 14062 block: *Block, 14063 extended: Zir.Inst.Extended.InstData, 14064 ) CompileError!Air.Inst.Ref { 14065 const tracy = trace(@src()); 14066 defer tracy.end(); 14067 14068 const extra = sema.code.extraData(Zir.Inst.Src, extended.operand).data; 14069 const src = LazySrcLoc.nodeOffset(extra.node); 14070 const func = sema.func orelse return sema.fail(block, src, "@src outside function", .{}); 14071 const fn_owner_decl = sema.mod.declPtr(func.owner_decl); 14072 14073 const func_name_val = blk: { 14074 var anon_decl = try block.startAnonDecl(src); 14075 defer anon_decl.deinit(); 14076 const name = std.mem.span(fn_owner_decl.name); 14077 const bytes = try anon_decl.arena().dupe(u8, name[0 .. name.len + 1]); 14078 const new_decl = try anon_decl.finish( 14079 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len - 1), 14080 try Value.Tag.bytes.create(anon_decl.arena(), bytes), 14081 0, // default alignment 14082 ); 14083 break :blk try Value.Tag.decl_ref.create(sema.arena, new_decl); 14084 }; 14085 14086 const file_name_val = blk: { 14087 var anon_decl = try block.startAnonDecl(src); 14088 defer anon_decl.deinit(); 14089 const relative_path = try fn_owner_decl.getFileScope().fullPath(sema.arena); 14090 const absolute_path = std.fs.realpathAlloc(sema.arena, relative_path) catch |err| { 14091 return sema.fail(block, src, "failed to get absolute path of file '{s}': {s}", .{ relative_path, @errorName(err) }); 14092 }; 14093 const aboslute_duped = try anon_decl.arena().dupeZ(u8, absolute_path); 14094 const new_decl = try anon_decl.finish( 14095 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), aboslute_duped.len), 14096 try Value.Tag.bytes.create(anon_decl.arena(), aboslute_duped[0 .. aboslute_duped.len + 1]), 14097 0, // default alignment 14098 ); 14099 break :blk try Value.Tag.decl_ref.create(sema.arena, new_decl); 14100 }; 14101 14102 const field_values = try sema.arena.alloc(Value, 4); 14103 // file: [:0]const u8, 14104 field_values[0] = file_name_val; 14105 // fn_name: [:0]const u8, 14106 field_values[1] = func_name_val; 14107 // line: u32 14108 field_values[2] = try Value.Tag.runtime_int.create(sema.arena, extra.line + 1); 14109 // column: u32, 14110 field_values[3] = try Value.Tag.int_u64.create(sema.arena, extra.column + 1); 14111 14112 return sema.addConstant( 14113 try sema.getBuiltinType(block, src, "SourceLocation"), 14114 try Value.Tag.aggregate.create(sema.arena, field_values), 14115 ); 14116 } 14117 14118 fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 14119 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 14120 const src = inst_data.src(); 14121 const ty = try sema.resolveType(block, src, inst_data.operand); 14122 const type_info_ty = try sema.getBuiltinType(block, src, "Type"); 14123 const target = sema.mod.getTarget(); 14124 14125 switch (ty.zigTypeTag()) { 14126 .Type => return sema.addConstant( 14127 type_info_ty, 14128 try Value.Tag.@"union".create(sema.arena, .{ 14129 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Type)), 14130 .val = Value.@"void", 14131 }), 14132 ), 14133 .Void => return sema.addConstant( 14134 type_info_ty, 14135 try Value.Tag.@"union".create(sema.arena, .{ 14136 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Void)), 14137 .val = Value.@"void", 14138 }), 14139 ), 14140 .Bool => return sema.addConstant( 14141 type_info_ty, 14142 try Value.Tag.@"union".create(sema.arena, .{ 14143 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Bool)), 14144 .val = Value.@"void", 14145 }), 14146 ), 14147 .NoReturn => return sema.addConstant( 14148 type_info_ty, 14149 try Value.Tag.@"union".create(sema.arena, .{ 14150 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.NoReturn)), 14151 .val = Value.@"void", 14152 }), 14153 ), 14154 .ComptimeFloat => return sema.addConstant( 14155 type_info_ty, 14156 try Value.Tag.@"union".create(sema.arena, .{ 14157 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ComptimeFloat)), 14158 .val = Value.@"void", 14159 }), 14160 ), 14161 .ComptimeInt => return sema.addConstant( 14162 type_info_ty, 14163 try Value.Tag.@"union".create(sema.arena, .{ 14164 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ComptimeInt)), 14165 .val = Value.@"void", 14166 }), 14167 ), 14168 .Undefined => return sema.addConstant( 14169 type_info_ty, 14170 try Value.Tag.@"union".create(sema.arena, .{ 14171 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Undefined)), 14172 .val = Value.@"void", 14173 }), 14174 ), 14175 .Null => return sema.addConstant( 14176 type_info_ty, 14177 try Value.Tag.@"union".create(sema.arena, .{ 14178 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Null)), 14179 .val = Value.@"void", 14180 }), 14181 ), 14182 .EnumLiteral => return sema.addConstant( 14183 type_info_ty, 14184 try Value.Tag.@"union".create(sema.arena, .{ 14185 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.EnumLiteral)), 14186 .val = Value.@"void", 14187 }), 14188 ), 14189 .Fn => { 14190 // TODO: look into memoizing this result. 14191 const info = ty.fnInfo(); 14192 14193 var params_anon_decl = try block.startAnonDecl(src); 14194 defer params_anon_decl.deinit(); 14195 14196 const param_vals = try params_anon_decl.arena().alloc(Value, info.param_types.len); 14197 for (param_vals) |*param_val, i| { 14198 const param_ty = info.param_types[i]; 14199 const is_generic = param_ty.tag() == .generic_poison; 14200 const param_ty_val = if (is_generic) 14201 Value.@"null" 14202 else 14203 try Value.Tag.opt_payload.create( 14204 params_anon_decl.arena(), 14205 try Value.Tag.ty.create(params_anon_decl.arena(), try param_ty.copy(params_anon_decl.arena())), 14206 ); 14207 14208 const param_fields = try params_anon_decl.arena().create([3]Value); 14209 param_fields.* = .{ 14210 // is_generic: bool, 14211 Value.makeBool(is_generic), 14212 // is_noalias: bool, 14213 Value.@"false", // TODO 14214 // arg_type: ?type, 14215 param_ty_val, 14216 }; 14217 param_val.* = try Value.Tag.aggregate.create(params_anon_decl.arena(), param_fields); 14218 } 14219 14220 const args_val = v: { 14221 const fn_info_decl_index = (try sema.namespaceLookup( 14222 block, 14223 src, 14224 type_info_ty.getNamespace().?, 14225 "Fn", 14226 )).?; 14227 try sema.mod.declareDeclDependency(sema.owner_decl_index, fn_info_decl_index); 14228 try sema.ensureDeclAnalyzed(fn_info_decl_index); 14229 const fn_info_decl = sema.mod.declPtr(fn_info_decl_index); 14230 var fn_ty_buffer: Value.ToTypeBuffer = undefined; 14231 const fn_ty = fn_info_decl.val.toType(&fn_ty_buffer); 14232 const param_info_decl_index = (try sema.namespaceLookup( 14233 block, 14234 src, 14235 fn_ty.getNamespace().?, 14236 "Param", 14237 )).?; 14238 try sema.mod.declareDeclDependency(sema.owner_decl_index, param_info_decl_index); 14239 try sema.ensureDeclAnalyzed(param_info_decl_index); 14240 const param_info_decl = sema.mod.declPtr(param_info_decl_index); 14241 var param_buffer: Value.ToTypeBuffer = undefined; 14242 const param_ty = param_info_decl.val.toType(¶m_buffer); 14243 const new_decl = try params_anon_decl.finish( 14244 try Type.Tag.array.create(params_anon_decl.arena(), .{ 14245 .len = param_vals.len, 14246 .elem_type = try param_ty.copy(params_anon_decl.arena()), 14247 }), 14248 try Value.Tag.aggregate.create( 14249 params_anon_decl.arena(), 14250 param_vals, 14251 ), 14252 0, // default alignment 14253 ); 14254 break :v try Value.Tag.slice.create(sema.arena, .{ 14255 .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), 14256 .len = try Value.Tag.int_u64.create(sema.arena, param_vals.len), 14257 }); 14258 }; 14259 14260 const ret_ty_opt = if (info.return_type.tag() != .generic_poison) 14261 try Value.Tag.opt_payload.create( 14262 sema.arena, 14263 try Value.Tag.ty.create(sema.arena, info.return_type), 14264 ) 14265 else 14266 Value.@"null"; 14267 14268 const field_values = try sema.arena.create([6]Value); 14269 field_values.* = .{ 14270 // calling_convention: CallingConvention, 14271 try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.cc)), 14272 // alignment: comptime_int, 14273 try Value.Tag.int_u64.create(sema.arena, ty.abiAlignment(target)), 14274 // is_generic: bool, 14275 Value.makeBool(info.is_generic), 14276 // is_var_args: bool, 14277 Value.makeBool(info.is_var_args), 14278 // return_type: ?type, 14279 ret_ty_opt, 14280 // args: []const Fn.Param, 14281 args_val, 14282 }; 14283 14284 return sema.addConstant( 14285 type_info_ty, 14286 try Value.Tag.@"union".create(sema.arena, .{ 14287 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Fn)), 14288 .val = try Value.Tag.aggregate.create(sema.arena, field_values), 14289 }), 14290 ); 14291 }, 14292 .Int => { 14293 const info = ty.intInfo(target); 14294 const field_values = try sema.arena.alloc(Value, 2); 14295 // signedness: Signedness, 14296 field_values[0] = try Value.Tag.enum_field_index.create( 14297 sema.arena, 14298 @enumToInt(info.signedness), 14299 ); 14300 // bits: comptime_int, 14301 field_values[1] = try Value.Tag.int_u64.create(sema.arena, info.bits); 14302 14303 return sema.addConstant( 14304 type_info_ty, 14305 try Value.Tag.@"union".create(sema.arena, .{ 14306 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Int)), 14307 .val = try Value.Tag.aggregate.create(sema.arena, field_values), 14308 }), 14309 ); 14310 }, 14311 .Float => { 14312 const field_values = try sema.arena.alloc(Value, 1); 14313 // bits: comptime_int, 14314 field_values[0] = try Value.Tag.int_u64.create(sema.arena, ty.bitSize(target)); 14315 14316 return sema.addConstant( 14317 type_info_ty, 14318 try Value.Tag.@"union".create(sema.arena, .{ 14319 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Float)), 14320 .val = try Value.Tag.aggregate.create(sema.arena, field_values), 14321 }), 14322 ); 14323 }, 14324 .Pointer => { 14325 const info = ty.ptrInfo().data; 14326 const alignment = if (info.@"align" != 0) 14327 try Value.Tag.int_u64.create(sema.arena, info.@"align") 14328 else 14329 try info.pointee_type.lazyAbiAlignment(target, sema.arena); 14330 14331 const field_values = try sema.arena.create([8]Value); 14332 field_values.* = .{ 14333 // size: Size, 14334 try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.size)), 14335 // is_const: bool, 14336 Value.makeBool(!info.mutable), 14337 // is_volatile: bool, 14338 Value.makeBool(info.@"volatile"), 14339 // alignment: comptime_int, 14340 alignment, 14341 // address_space: AddressSpace 14342 try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.@"addrspace")), 14343 // child: type, 14344 try Value.Tag.ty.create(sema.arena, info.pointee_type), 14345 // is_allowzero: bool, 14346 Value.makeBool(info.@"allowzero"), 14347 // sentinel: ?*const anyopaque, 14348 try sema.optRefValue(block, src, info.pointee_type, info.sentinel), 14349 }; 14350 14351 return sema.addConstant( 14352 type_info_ty, 14353 try Value.Tag.@"union".create(sema.arena, .{ 14354 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Pointer)), 14355 .val = try Value.Tag.aggregate.create(sema.arena, field_values), 14356 }), 14357 ); 14358 }, 14359 .Array => { 14360 const info = ty.arrayInfo(); 14361 const field_values = try sema.arena.alloc(Value, 3); 14362 // len: comptime_int, 14363 field_values[0] = try Value.Tag.int_u64.create(sema.arena, info.len); 14364 // child: type, 14365 field_values[1] = try Value.Tag.ty.create(sema.arena, info.elem_type); 14366 // sentinel: ?*const anyopaque, 14367 field_values[2] = try sema.optRefValue(block, src, info.elem_type, info.sentinel); 14368 14369 return sema.addConstant( 14370 type_info_ty, 14371 try Value.Tag.@"union".create(sema.arena, .{ 14372 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Array)), 14373 .val = try Value.Tag.aggregate.create(sema.arena, field_values), 14374 }), 14375 ); 14376 }, 14377 .Vector => { 14378 const info = ty.arrayInfo(); 14379 const field_values = try sema.arena.alloc(Value, 2); 14380 // len: comptime_int, 14381 field_values[0] = try Value.Tag.int_u64.create(sema.arena, info.len); 14382 // child: type, 14383 field_values[1] = try Value.Tag.ty.create(sema.arena, info.elem_type); 14384 14385 return sema.addConstant( 14386 type_info_ty, 14387 try Value.Tag.@"union".create(sema.arena, .{ 14388 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Vector)), 14389 .val = try Value.Tag.aggregate.create(sema.arena, field_values), 14390 }), 14391 ); 14392 }, 14393 .Optional => { 14394 const field_values = try sema.arena.alloc(Value, 1); 14395 // child: type, 14396 field_values[0] = try Value.Tag.ty.create(sema.arena, try ty.optionalChildAlloc(sema.arena)); 14397 14398 return sema.addConstant( 14399 type_info_ty, 14400 try Value.Tag.@"union".create(sema.arena, .{ 14401 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Optional)), 14402 .val = try Value.Tag.aggregate.create(sema.arena, field_values), 14403 }), 14404 ); 14405 }, 14406 .ErrorSet => { 14407 var fields_anon_decl = try block.startAnonDecl(src); 14408 defer fields_anon_decl.deinit(); 14409 14410 // Get the Error type 14411 const error_field_ty = t: { 14412 const set_field_ty_decl_index = (try sema.namespaceLookup( 14413 block, 14414 src, 14415 type_info_ty.getNamespace().?, 14416 "Error", 14417 )).?; 14418 try sema.mod.declareDeclDependency(sema.owner_decl_index, set_field_ty_decl_index); 14419 try sema.ensureDeclAnalyzed(set_field_ty_decl_index); 14420 const set_field_ty_decl = sema.mod.declPtr(set_field_ty_decl_index); 14421 var buffer: Value.ToTypeBuffer = undefined; 14422 break :t try set_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena()); 14423 }; 14424 14425 try sema.queueFullTypeResolution(try error_field_ty.copy(sema.arena)); 14426 14427 // If the error set is inferred it must be resolved at this point 14428 try sema.resolveInferredErrorSetTy(block, src, ty); 14429 14430 // Build our list of Error values 14431 // Optional value is only null if anyerror 14432 // Value can be zero-length slice otherwise 14433 const error_field_vals: ?[]Value = if (ty.isAnyError()) null else blk: { 14434 const names = ty.errorSetNames(); 14435 const vals = try fields_anon_decl.arena().alloc(Value, names.len); 14436 for (vals) |*field_val, i| { 14437 const name = names[i]; 14438 const name_val = v: { 14439 var anon_decl = try block.startAnonDecl(src); 14440 defer anon_decl.deinit(); 14441 const bytes = try anon_decl.arena().dupeZ(u8, name); 14442 const new_decl = try anon_decl.finish( 14443 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), 14444 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), 14445 0, // default alignment 14446 ); 14447 break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl); 14448 }; 14449 14450 const error_field_fields = try fields_anon_decl.arena().create([1]Value); 14451 error_field_fields.* = .{ 14452 // name: []const u8, 14453 name_val, 14454 }; 14455 14456 field_val.* = try Value.Tag.aggregate.create( 14457 fields_anon_decl.arena(), 14458 error_field_fields, 14459 ); 14460 } 14461 14462 break :blk vals; 14463 }; 14464 14465 // Build our ?[]const Error value 14466 const errors_val = if (error_field_vals) |vals| v: { 14467 const new_decl = try fields_anon_decl.finish( 14468 try Type.Tag.array.create(fields_anon_decl.arena(), .{ 14469 .len = vals.len, 14470 .elem_type = error_field_ty, 14471 }), 14472 try Value.Tag.aggregate.create( 14473 fields_anon_decl.arena(), 14474 vals, 14475 ), 14476 0, // default alignment 14477 ); 14478 14479 const new_decl_val = try Value.Tag.decl_ref.create(sema.arena, new_decl); 14480 const slice_val = try Value.Tag.slice.create(sema.arena, .{ 14481 .ptr = new_decl_val, 14482 .len = try Value.Tag.int_u64.create(sema.arena, vals.len), 14483 }); 14484 break :v try Value.Tag.opt_payload.create(sema.arena, slice_val); 14485 } else Value.@"null"; 14486 14487 // Construct Type{ .ErrorSet = errors_val } 14488 return sema.addConstant( 14489 type_info_ty, 14490 try Value.Tag.@"union".create(sema.arena, .{ 14491 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ErrorSet)), 14492 .val = errors_val, 14493 }), 14494 ); 14495 }, 14496 .ErrorUnion => { 14497 const field_values = try sema.arena.alloc(Value, 2); 14498 // error_set: type, 14499 field_values[0] = try Value.Tag.ty.create(sema.arena, ty.errorUnionSet()); 14500 // payload: type, 14501 field_values[1] = try Value.Tag.ty.create(sema.arena, ty.errorUnionPayload()); 14502 14503 return sema.addConstant( 14504 type_info_ty, 14505 try Value.Tag.@"union".create(sema.arena, .{ 14506 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ErrorUnion)), 14507 .val = try Value.Tag.aggregate.create(sema.arena, field_values), 14508 }), 14509 ); 14510 }, 14511 .Enum => { 14512 // TODO: look into memoizing this result. 14513 var int_tag_type_buffer: Type.Payload.Bits = undefined; 14514 const int_tag_ty = try ty.intTagType(&int_tag_type_buffer).copy(sema.arena); 14515 14516 const is_exhaustive = Value.makeBool(!ty.isNonexhaustiveEnum()); 14517 14518 var fields_anon_decl = try block.startAnonDecl(src); 14519 defer fields_anon_decl.deinit(); 14520 14521 const enum_field_ty = t: { 14522 const enum_field_ty_decl_index = (try sema.namespaceLookup( 14523 block, 14524 src, 14525 type_info_ty.getNamespace().?, 14526 "EnumField", 14527 )).?; 14528 try sema.mod.declareDeclDependency(sema.owner_decl_index, enum_field_ty_decl_index); 14529 try sema.ensureDeclAnalyzed(enum_field_ty_decl_index); 14530 const enum_field_ty_decl = sema.mod.declPtr(enum_field_ty_decl_index); 14531 var buffer: Value.ToTypeBuffer = undefined; 14532 break :t try enum_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena()); 14533 }; 14534 14535 const enum_fields = ty.enumFields(); 14536 const enum_field_vals = try fields_anon_decl.arena().alloc(Value, enum_fields.count()); 14537 14538 for (enum_field_vals) |*field_val, i| { 14539 var tag_val_payload: Value.Payload.U32 = .{ 14540 .base = .{ .tag = .enum_field_index }, 14541 .data = @intCast(u32, i), 14542 }; 14543 const tag_val = Value.initPayload(&tag_val_payload.base); 14544 14545 var buffer: Value.Payload.U64 = undefined; 14546 const int_val = try tag_val.enumToInt(ty, &buffer).copy(fields_anon_decl.arena()); 14547 14548 const name = enum_fields.keys()[i]; 14549 const name_val = v: { 14550 var anon_decl = try block.startAnonDecl(src); 14551 defer anon_decl.deinit(); 14552 const bytes = try anon_decl.arena().dupeZ(u8, name); 14553 const new_decl = try anon_decl.finish( 14554 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), 14555 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), 14556 0, // default alignment 14557 ); 14558 break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl); 14559 }; 14560 14561 const enum_field_fields = try fields_anon_decl.arena().create([2]Value); 14562 enum_field_fields.* = .{ 14563 // name: []const u8, 14564 name_val, 14565 // value: comptime_int, 14566 int_val, 14567 }; 14568 field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), enum_field_fields); 14569 } 14570 14571 const fields_val = v: { 14572 const new_decl = try fields_anon_decl.finish( 14573 try Type.Tag.array.create(fields_anon_decl.arena(), .{ 14574 .len = enum_field_vals.len, 14575 .elem_type = enum_field_ty, 14576 }), 14577 try Value.Tag.aggregate.create( 14578 fields_anon_decl.arena(), 14579 enum_field_vals, 14580 ), 14581 0, // default alignment 14582 ); 14583 break :v try Value.Tag.decl_ref.create(sema.arena, new_decl); 14584 }; 14585 14586 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespace()); 14587 14588 const field_values = try sema.arena.create([5]Value); 14589 field_values.* = .{ 14590 // layout: ContainerLayout, 14591 try Value.Tag.enum_field_index.create( 14592 sema.arena, 14593 @enumToInt(std.builtin.Type.ContainerLayout.Auto), 14594 ), 14595 14596 // tag_type: type, 14597 try Value.Tag.ty.create(sema.arena, int_tag_ty), 14598 // fields: []const EnumField, 14599 fields_val, 14600 // decls: []const Declaration, 14601 decls_val, 14602 // is_exhaustive: bool, 14603 is_exhaustive, 14604 }; 14605 14606 return sema.addConstant( 14607 type_info_ty, 14608 try Value.Tag.@"union".create(sema.arena, .{ 14609 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Enum)), 14610 .val = try Value.Tag.aggregate.create(sema.arena, field_values), 14611 }), 14612 ); 14613 }, 14614 .Union => { 14615 // TODO: look into memoizing this result. 14616 14617 var fields_anon_decl = try block.startAnonDecl(src); 14618 defer fields_anon_decl.deinit(); 14619 14620 const union_field_ty = t: { 14621 const union_field_ty_decl_index = (try sema.namespaceLookup( 14622 block, 14623 src, 14624 type_info_ty.getNamespace().?, 14625 "UnionField", 14626 )).?; 14627 try sema.mod.declareDeclDependency(sema.owner_decl_index, union_field_ty_decl_index); 14628 try sema.ensureDeclAnalyzed(union_field_ty_decl_index); 14629 const union_field_ty_decl = sema.mod.declPtr(union_field_ty_decl_index); 14630 var buffer: Value.ToTypeBuffer = undefined; 14631 break :t try union_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena()); 14632 }; 14633 14634 const union_ty = try sema.resolveTypeFields(block, src, ty); 14635 try sema.resolveTypeLayout(block, src, ty); // Getting alignment requires type layout 14636 const layout = union_ty.containerLayout(); 14637 14638 const union_fields = union_ty.unionFields(); 14639 const union_field_vals = try fields_anon_decl.arena().alloc(Value, union_fields.count()); 14640 14641 for (union_field_vals) |*field_val, i| { 14642 const field = union_fields.values()[i]; 14643 const name = union_fields.keys()[i]; 14644 const name_val = v: { 14645 var anon_decl = try block.startAnonDecl(src); 14646 defer anon_decl.deinit(); 14647 const bytes = try anon_decl.arena().dupeZ(u8, name); 14648 const new_decl = try anon_decl.finish( 14649 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), 14650 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), 14651 0, // default alignment 14652 ); 14653 break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl); 14654 }; 14655 14656 const union_field_fields = try fields_anon_decl.arena().create([3]Value); 14657 const alignment = switch (layout) { 14658 .Auto, .Extern => try sema.unionFieldAlignment(block, src, field), 14659 .Packed => 0, 14660 }; 14661 14662 union_field_fields.* = .{ 14663 // name: []const u8, 14664 name_val, 14665 // field_type: type, 14666 try Value.Tag.ty.create(fields_anon_decl.arena(), field.ty), 14667 // alignment: comptime_int, 14668 try Value.Tag.int_u64.create(fields_anon_decl.arena(), alignment), 14669 }; 14670 field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), union_field_fields); 14671 } 14672 14673 const fields_val = v: { 14674 const new_decl = try fields_anon_decl.finish( 14675 try Type.Tag.array.create(fields_anon_decl.arena(), .{ 14676 .len = union_field_vals.len, 14677 .elem_type = union_field_ty, 14678 }), 14679 try Value.Tag.aggregate.create( 14680 fields_anon_decl.arena(), 14681 try fields_anon_decl.arena().dupe(Value, union_field_vals), 14682 ), 14683 0, // default alignment 14684 ); 14685 break :v try Value.Tag.slice.create(sema.arena, .{ 14686 .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), 14687 .len = try Value.Tag.int_u64.create(sema.arena, union_field_vals.len), 14688 }); 14689 }; 14690 14691 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespace()); 14692 14693 const enum_tag_ty_val = if (union_ty.unionTagType()) |tag_ty| v: { 14694 const ty_val = try Value.Tag.ty.create(sema.arena, tag_ty); 14695 break :v try Value.Tag.opt_payload.create(sema.arena, ty_val); 14696 } else Value.@"null"; 14697 14698 const field_values = try sema.arena.create([4]Value); 14699 field_values.* = .{ 14700 // layout: ContainerLayout, 14701 try Value.Tag.enum_field_index.create( 14702 sema.arena, 14703 @enumToInt(layout), 14704 ), 14705 14706 // tag_type: ?type, 14707 enum_tag_ty_val, 14708 // fields: []const UnionField, 14709 fields_val, 14710 // decls: []const Declaration, 14711 decls_val, 14712 }; 14713 14714 return sema.addConstant( 14715 type_info_ty, 14716 try Value.Tag.@"union".create(sema.arena, .{ 14717 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Union)), 14718 .val = try Value.Tag.aggregate.create(sema.arena, field_values), 14719 }), 14720 ); 14721 }, 14722 .Struct => { 14723 // TODO: look into memoizing this result. 14724 14725 var fields_anon_decl = try block.startAnonDecl(src); 14726 defer fields_anon_decl.deinit(); 14727 14728 const struct_field_ty = t: { 14729 const struct_field_ty_decl_index = (try sema.namespaceLookup( 14730 block, 14731 src, 14732 type_info_ty.getNamespace().?, 14733 "StructField", 14734 )).?; 14735 try sema.mod.declareDeclDependency(sema.owner_decl_index, struct_field_ty_decl_index); 14736 try sema.ensureDeclAnalyzed(struct_field_ty_decl_index); 14737 const struct_field_ty_decl = sema.mod.declPtr(struct_field_ty_decl_index); 14738 var buffer: Value.ToTypeBuffer = undefined; 14739 break :t try struct_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena()); 14740 }; 14741 const struct_ty = try sema.resolveTypeFields(block, src, ty); 14742 try sema.resolveTypeLayout(block, src, ty); // Getting alignment requires type layout 14743 const layout = struct_ty.containerLayout(); 14744 14745 const struct_field_vals = fv: { 14746 if (struct_ty.isTupleOrAnonStruct()) { 14747 const tuple = struct_ty.tupleFields(); 14748 const field_types = tuple.types; 14749 const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len); 14750 for (struct_field_vals) |*struct_field_val, i| { 14751 const field_ty = field_types[i]; 14752 const name_val = v: { 14753 var anon_decl = try block.startAnonDecl(src); 14754 defer anon_decl.deinit(); 14755 const bytes = if (struct_ty.castTag(.anon_struct)) |payload| 14756 try anon_decl.arena().dupeZ(u8, payload.data.names[i]) 14757 else 14758 try std.fmt.allocPrintZ(anon_decl.arena(), "{d}", .{i}); 14759 const new_decl = try anon_decl.finish( 14760 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), 14761 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), 14762 0, // default alignment 14763 ); 14764 break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{ 14765 .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl), 14766 .len = try Value.Tag.int_u64.create(fields_anon_decl.arena(), bytes.len), 14767 }); 14768 }; 14769 14770 const struct_field_fields = try fields_anon_decl.arena().create([5]Value); 14771 const field_val = tuple.values[i]; 14772 const is_comptime = field_val.tag() != .unreachable_value; 14773 const opt_default_val = if (is_comptime) field_val else null; 14774 const default_val_ptr = try sema.optRefValue(block, src, field_ty, opt_default_val); 14775 struct_field_fields.* = .{ 14776 // name: []const u8, 14777 name_val, 14778 // field_type: type, 14779 try Value.Tag.ty.create(fields_anon_decl.arena(), field_ty), 14780 // default_value: ?*const anyopaque, 14781 try default_val_ptr.copy(fields_anon_decl.arena()), 14782 // is_comptime: bool, 14783 Value.makeBool(is_comptime), 14784 // alignment: comptime_int, 14785 try field_ty.lazyAbiAlignment(target, fields_anon_decl.arena()), 14786 }; 14787 struct_field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), struct_field_fields); 14788 } 14789 break :fv struct_field_vals; 14790 } 14791 const struct_fields = struct_ty.structFields(); 14792 const struct_field_vals = try fields_anon_decl.arena().alloc(Value, struct_fields.count()); 14793 14794 for (struct_field_vals) |*field_val, i| { 14795 const field = struct_fields.values()[i]; 14796 const name = struct_fields.keys()[i]; 14797 const name_val = v: { 14798 var anon_decl = try block.startAnonDecl(src); 14799 defer anon_decl.deinit(); 14800 const bytes = try anon_decl.arena().dupeZ(u8, name); 14801 const new_decl = try anon_decl.finish( 14802 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), 14803 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), 14804 0, // default alignment 14805 ); 14806 break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{ 14807 .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl), 14808 .len = try Value.Tag.int_u64.create(fields_anon_decl.arena(), bytes.len), 14809 }); 14810 }; 14811 14812 const struct_field_fields = try fields_anon_decl.arena().create([5]Value); 14813 const opt_default_val = if (field.default_val.tag() == .unreachable_value) 14814 null 14815 else 14816 field.default_val; 14817 const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val); 14818 const alignment = field.alignment(target, layout); 14819 14820 struct_field_fields.* = .{ 14821 // name: []const u8, 14822 name_val, 14823 // field_type: type, 14824 try Value.Tag.ty.create(fields_anon_decl.arena(), field.ty), 14825 // default_value: ?*const anyopaque, 14826 try default_val_ptr.copy(fields_anon_decl.arena()), 14827 // is_comptime: bool, 14828 Value.makeBool(field.is_comptime), 14829 // alignment: comptime_int, 14830 try Value.Tag.int_u64.create(fields_anon_decl.arena(), alignment), 14831 }; 14832 field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), struct_field_fields); 14833 } 14834 break :fv struct_field_vals; 14835 }; 14836 14837 const fields_val = v: { 14838 const new_decl = try fields_anon_decl.finish( 14839 try Type.Tag.array.create(fields_anon_decl.arena(), .{ 14840 .len = struct_field_vals.len, 14841 .elem_type = struct_field_ty, 14842 }), 14843 try Value.Tag.aggregate.create( 14844 fields_anon_decl.arena(), 14845 try fields_anon_decl.arena().dupe(Value, struct_field_vals), 14846 ), 14847 0, // default alignment 14848 ); 14849 break :v try Value.Tag.slice.create(sema.arena, .{ 14850 .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), 14851 .len = try Value.Tag.int_u64.create(sema.arena, struct_field_vals.len), 14852 }); 14853 }; 14854 14855 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespace()); 14856 14857 const backing_integer_val = blk: { 14858 if (layout == .Packed) { 14859 const struct_obj = struct_ty.castTag(.@"struct").?.data; 14860 assert(struct_obj.haveLayout()); 14861 assert(struct_obj.backing_int_ty.isInt()); 14862 const backing_int_ty_val = try Value.Tag.ty.create(sema.arena, struct_obj.backing_int_ty); 14863 break :blk try Value.Tag.opt_payload.create(sema.arena, backing_int_ty_val); 14864 } else { 14865 break :blk Value.initTag(.null_value); 14866 } 14867 }; 14868 14869 const field_values = try sema.arena.create([5]Value); 14870 field_values.* = .{ 14871 // layout: ContainerLayout, 14872 try Value.Tag.enum_field_index.create( 14873 sema.arena, 14874 @enumToInt(layout), 14875 ), 14876 // backing_integer: ?type, 14877 backing_integer_val, 14878 // fields: []const StructField, 14879 fields_val, 14880 // decls: []const Declaration, 14881 decls_val, 14882 // is_tuple: bool, 14883 Value.makeBool(struct_ty.isTuple()), 14884 }; 14885 14886 return sema.addConstant( 14887 type_info_ty, 14888 try Value.Tag.@"union".create(sema.arena, .{ 14889 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Struct)), 14890 .val = try Value.Tag.aggregate.create(sema.arena, field_values), 14891 }), 14892 ); 14893 }, 14894 .Opaque => { 14895 // TODO: look into memoizing this result. 14896 14897 const opaque_ty = try sema.resolveTypeFields(block, src, ty); 14898 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespace()); 14899 14900 const field_values = try sema.arena.create([1]Value); 14901 field_values.* = .{ 14902 // decls: []const Declaration, 14903 decls_val, 14904 }; 14905 14906 return sema.addConstant( 14907 type_info_ty, 14908 try Value.Tag.@"union".create(sema.arena, .{ 14909 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Opaque)), 14910 .val = try Value.Tag.aggregate.create(sema.arena, field_values), 14911 }), 14912 ); 14913 }, 14914 .BoundFn => @panic("TODO remove this type from the language and compiler"), 14915 .Frame => return sema.failWithUseOfAsync(block, src), 14916 .AnyFrame => return sema.failWithUseOfAsync(block, src), 14917 } 14918 } 14919 14920 fn typeInfoDecls( 14921 sema: *Sema, 14922 block: *Block, 14923 src: LazySrcLoc, 14924 type_info_ty: Type, 14925 opt_namespace: ?*Module.Namespace, 14926 ) CompileError!Value { 14927 var decls_anon_decl = try block.startAnonDecl(src); 14928 defer decls_anon_decl.deinit(); 14929 14930 const declaration_ty = t: { 14931 const declaration_ty_decl_index = (try sema.namespaceLookup( 14932 block, 14933 src, 14934 type_info_ty.getNamespace().?, 14935 "Declaration", 14936 )).?; 14937 try sema.mod.declareDeclDependency(sema.owner_decl_index, declaration_ty_decl_index); 14938 try sema.ensureDeclAnalyzed(declaration_ty_decl_index); 14939 const declaration_ty_decl = sema.mod.declPtr(declaration_ty_decl_index); 14940 var buffer: Value.ToTypeBuffer = undefined; 14941 break :t try declaration_ty_decl.val.toType(&buffer).copy(decls_anon_decl.arena()); 14942 }; 14943 try sema.queueFullTypeResolution(try declaration_ty.copy(sema.arena)); 14944 14945 const decls_len = if (opt_namespace) |ns| ns.decls.count() else 0; 14946 const decls_vals = try decls_anon_decl.arena().alloc(Value, decls_len); 14947 for (decls_vals) |*decls_val, i| { 14948 const decl_index = opt_namespace.?.decls.keys()[i]; 14949 const decl = sema.mod.declPtr(decl_index); 14950 const name_val = v: { 14951 var anon_decl = try block.startAnonDecl(src); 14952 defer anon_decl.deinit(); 14953 const bytes = try anon_decl.arena().dupeZ(u8, mem.sliceTo(decl.name, 0)); 14954 const new_decl = try anon_decl.finish( 14955 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), 14956 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), 14957 0, // default alignment 14958 ); 14959 break :v try Value.Tag.slice.create(decls_anon_decl.arena(), .{ 14960 .ptr = try Value.Tag.decl_ref.create(decls_anon_decl.arena(), new_decl), 14961 .len = try Value.Tag.int_u64.create(decls_anon_decl.arena(), bytes.len), 14962 }); 14963 }; 14964 14965 const fields = try decls_anon_decl.arena().create([2]Value); 14966 fields.* = .{ 14967 //name: []const u8, 14968 name_val, 14969 //is_pub: bool, 14970 Value.makeBool(decl.is_pub), 14971 }; 14972 decls_val.* = try Value.Tag.aggregate.create(decls_anon_decl.arena(), fields); 14973 } 14974 14975 const new_decl = try decls_anon_decl.finish( 14976 try Type.Tag.array.create(decls_anon_decl.arena(), .{ 14977 .len = decls_vals.len, 14978 .elem_type = declaration_ty, 14979 }), 14980 try Value.Tag.aggregate.create( 14981 decls_anon_decl.arena(), 14982 try decls_anon_decl.arena().dupe(Value, decls_vals), 14983 ), 14984 0, // default alignment 14985 ); 14986 return try Value.Tag.slice.create(sema.arena, .{ 14987 .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), 14988 .len = try Value.Tag.int_u64.create(sema.arena, decls_vals.len), 14989 }); 14990 } 14991 14992 fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 14993 _ = block; 14994 const zir_datas = sema.code.instructions.items(.data); 14995 const inst_data = zir_datas[inst].un_node; 14996 const operand = try sema.resolveInst(inst_data.operand); 14997 const operand_ty = sema.typeOf(operand); 14998 return sema.addType(operand_ty); 14999 } 15000 15001 fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 15002 const pl_node = sema.code.instructions.items(.data)[inst].pl_node; 15003 const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index); 15004 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 15005 15006 var child_block: Block = .{ 15007 .parent = block, 15008 .sema = sema, 15009 .src_decl = block.src_decl, 15010 .namespace = block.namespace, 15011 .wip_capture_scope = block.wip_capture_scope, 15012 .instructions = .{}, 15013 .inlining = block.inlining, 15014 .is_comptime = false, 15015 .is_typeof = true, 15016 .want_safety = false, 15017 }; 15018 defer child_block.instructions.deinit(sema.gpa); 15019 15020 const operand = try sema.resolveBody(&child_block, body, inst); 15021 const operand_ty = sema.typeOf(operand); 15022 if (operand_ty.tag() == .generic_poison) return error.GenericPoison; 15023 return sema.addType(operand_ty); 15024 } 15025 15026 fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 15027 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15028 const src = inst_data.src(); 15029 const operand = try sema.resolveInst(inst_data.operand); 15030 const operand_ty = sema.typeOf(operand); 15031 const res_ty = try sema.log2IntType(block, operand_ty, src); 15032 return sema.addType(res_ty); 15033 } 15034 15035 fn zirLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 15036 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15037 const src = inst_data.src(); 15038 const operand = try sema.resolveType(block, src, inst_data.operand); 15039 const res_ty = try sema.log2IntType(block, operand, src); 15040 return sema.addType(res_ty); 15041 } 15042 15043 fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) CompileError!Type { 15044 switch (operand.zigTypeTag()) { 15045 .ComptimeInt => return Type.@"comptime_int", 15046 .Int => { 15047 const bits = operand.bitSize(sema.mod.getTarget()); 15048 const count = if (bits == 0) 15049 0 15050 else blk: { 15051 var count: u16 = 0; 15052 var s = bits - 1; 15053 while (s != 0) : (s >>= 1) { 15054 count += 1; 15055 } 15056 break :blk count; 15057 }; 15058 return Module.makeIntType(sema.arena, .unsigned, count); 15059 }, 15060 .Vector => { 15061 const elem_ty = operand.elemType2(); 15062 const log2_elem_ty = try sema.log2IntType(block, elem_ty, src); 15063 return Type.Tag.vector.create(sema.arena, .{ 15064 .len = operand.vectorLen(), 15065 .elem_type = log2_elem_ty, 15066 }); 15067 }, 15068 else => {}, 15069 } 15070 return sema.fail( 15071 block, 15072 src, 15073 "bit shifting operation expected integer type, found '{}'", 15074 .{operand.fmt(sema.mod)}, 15075 ); 15076 } 15077 15078 fn zirTypeofPeer( 15079 sema: *Sema, 15080 block: *Block, 15081 extended: Zir.Inst.Extended.InstData, 15082 ) CompileError!Air.Inst.Ref { 15083 const tracy = trace(@src()); 15084 defer tracy.end(); 15085 15086 const extra = sema.code.extraData(Zir.Inst.TypeOfPeer, extended.operand); 15087 const src = LazySrcLoc.nodeOffset(extra.data.src_node); 15088 const body = sema.code.extra[extra.data.body_index..][0..extra.data.body_len]; 15089 15090 var child_block: Block = .{ 15091 .parent = block, 15092 .sema = sema, 15093 .src_decl = block.src_decl, 15094 .namespace = block.namespace, 15095 .wip_capture_scope = block.wip_capture_scope, 15096 .instructions = .{}, 15097 .inlining = block.inlining, 15098 .is_comptime = false, 15099 .is_typeof = true, 15100 .runtime_cond = block.runtime_cond, 15101 .runtime_loop = block.runtime_loop, 15102 .runtime_index = block.runtime_index, 15103 }; 15104 defer child_block.instructions.deinit(sema.gpa); 15105 // Ignore the result, we only care about the instructions in `args`. 15106 _ = try sema.analyzeBodyBreak(&child_block, body); 15107 15108 const args = sema.code.refSlice(extra.end, extended.small); 15109 15110 const inst_list = try sema.gpa.alloc(Air.Inst.Ref, args.len); 15111 defer sema.gpa.free(inst_list); 15112 15113 for (args) |arg_ref, i| { 15114 inst_list[i] = try sema.resolveInst(arg_ref); 15115 } 15116 15117 const result_type = try sema.resolvePeerTypes(block, src, inst_list, .{ .typeof_builtin_call_node_offset = extra.data.src_node }); 15118 return sema.addType(result_type); 15119 } 15120 15121 fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 15122 const tracy = trace(@src()); 15123 defer tracy.end(); 15124 15125 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15126 const src = inst_data.src(); 15127 const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; 15128 const uncasted_operand = try sema.resolveInst(inst_data.operand); 15129 15130 const operand = try sema.coerce(block, Type.bool, uncasted_operand, operand_src); 15131 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { 15132 return if (val.isUndef()) 15133 sema.addConstUndef(Type.bool) 15134 else if (val.toBool()) 15135 Air.Inst.Ref.bool_false 15136 else 15137 Air.Inst.Ref.bool_true; 15138 } 15139 try sema.requireRuntimeBlock(block, src, null); 15140 return block.addTyOp(.not, Type.bool, operand); 15141 } 15142 15143 fn zirBoolBr( 15144 sema: *Sema, 15145 parent_block: *Block, 15146 inst: Zir.Inst.Index, 15147 is_bool_or: bool, 15148 ) CompileError!Air.Inst.Ref { 15149 const tracy = trace(@src()); 15150 defer tracy.end(); 15151 15152 const datas = sema.code.instructions.items(.data); 15153 const inst_data = datas[inst].bool_br; 15154 const lhs = try sema.resolveInst(inst_data.lhs); 15155 const lhs_src = sema.src; 15156 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); 15157 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 15158 const gpa = sema.gpa; 15159 15160 if (try sema.resolveDefinedValue(parent_block, lhs_src, lhs)) |lhs_val| { 15161 if (lhs_val.toBool() == is_bool_or) { 15162 if (is_bool_or) { 15163 return Air.Inst.Ref.bool_true; 15164 } else { 15165 return Air.Inst.Ref.bool_false; 15166 } 15167 } 15168 // comptime-known left-hand side. No need for a block here; the result 15169 // is simply the rhs expression. Here we rely on there only being 1 15170 // break instruction (`break_inline`). 15171 return sema.resolveBody(parent_block, body, inst); 15172 } 15173 15174 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 15175 try sema.air_instructions.append(gpa, .{ 15176 .tag = .block, 15177 .data = .{ .ty_pl = .{ 15178 .ty = .bool_type, 15179 .payload = undefined, 15180 } }, 15181 }); 15182 15183 var child_block = parent_block.makeSubBlock(); 15184 child_block.runtime_loop = null; 15185 child_block.runtime_cond = lhs_src; 15186 child_block.runtime_index.increment(); 15187 defer child_block.instructions.deinit(gpa); 15188 15189 var then_block = child_block.makeSubBlock(); 15190 defer then_block.instructions.deinit(gpa); 15191 15192 var else_block = child_block.makeSubBlock(); 15193 defer else_block.instructions.deinit(gpa); 15194 15195 const lhs_block = if (is_bool_or) &then_block else &else_block; 15196 const rhs_block = if (is_bool_or) &else_block else &then_block; 15197 15198 const lhs_result: Air.Inst.Ref = if (is_bool_or) .bool_true else .bool_false; 15199 _ = try lhs_block.addBr(block_inst, lhs_result); 15200 15201 const rhs_result = try sema.resolveBody(rhs_block, body, inst); 15202 _ = try rhs_block.addBr(block_inst, rhs_result); 15203 15204 return finishCondBr(sema, parent_block, &child_block, &then_block, &else_block, lhs, block_inst); 15205 } 15206 15207 fn finishCondBr( 15208 sema: *Sema, 15209 parent_block: *Block, 15210 child_block: *Block, 15211 then_block: *Block, 15212 else_block: *Block, 15213 cond: Air.Inst.Ref, 15214 block_inst: Air.Inst.Index, 15215 ) !Air.Inst.Ref { 15216 const gpa = sema.gpa; 15217 15218 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + 15219 then_block.instructions.items.len + else_block.instructions.items.len + 15220 @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1); 15221 15222 const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{ 15223 .then_body_len = @intCast(u32, then_block.instructions.items.len), 15224 .else_body_len = @intCast(u32, else_block.instructions.items.len), 15225 }); 15226 sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items); 15227 sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items); 15228 15229 _ = try child_block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{ 15230 .operand = cond, 15231 .payload = cond_br_payload, 15232 } } }); 15233 15234 sema.air_instructions.items(.data)[block_inst].ty_pl.payload = sema.addExtraAssumeCapacity( 15235 Air.Block{ .body_len = @intCast(u32, child_block.instructions.items.len) }, 15236 ); 15237 sema.air_extra.appendSliceAssumeCapacity(child_block.instructions.items); 15238 15239 try parent_block.instructions.append(gpa, block_inst); 15240 return Air.indexToRef(block_inst); 15241 } 15242 15243 fn zirIsNonNull( 15244 sema: *Sema, 15245 block: *Block, 15246 inst: Zir.Inst.Index, 15247 ) CompileError!Air.Inst.Ref { 15248 const tracy = trace(@src()); 15249 defer tracy.end(); 15250 15251 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15252 const src = inst_data.src(); 15253 const operand = try sema.resolveInst(inst_data.operand); 15254 return sema.analyzeIsNull(block, src, operand, true); 15255 } 15256 15257 fn zirIsNonNullPtr( 15258 sema: *Sema, 15259 block: *Block, 15260 inst: Zir.Inst.Index, 15261 ) CompileError!Air.Inst.Ref { 15262 const tracy = trace(@src()); 15263 defer tracy.end(); 15264 15265 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15266 const src = inst_data.src(); 15267 const ptr = try sema.resolveInst(inst_data.operand); 15268 if ((try sema.resolveMaybeUndefVal(block, src, ptr)) == null) { 15269 return block.addUnOp(.is_non_null_ptr, ptr); 15270 } 15271 const loaded = try sema.analyzeLoad(block, src, ptr, src); 15272 return sema.analyzeIsNull(block, src, loaded, true); 15273 } 15274 15275 fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 15276 const tracy = trace(@src()); 15277 defer tracy.end(); 15278 15279 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15280 const operand = try sema.resolveInst(inst_data.operand); 15281 return sema.analyzeIsNonErr(block, inst_data.src(), operand); 15282 } 15283 15284 fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 15285 const tracy = trace(@src()); 15286 defer tracy.end(); 15287 15288 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15289 const src = inst_data.src(); 15290 const ptr = try sema.resolveInst(inst_data.operand); 15291 const loaded = try sema.analyzeLoad(block, src, ptr, src); 15292 return sema.analyzeIsNonErr(block, src, loaded); 15293 } 15294 15295 fn zirCondbr( 15296 sema: *Sema, 15297 parent_block: *Block, 15298 inst: Zir.Inst.Index, 15299 ) CompileError!Zir.Inst.Index { 15300 const tracy = trace(@src()); 15301 defer tracy.end(); 15302 15303 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 15304 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; 15305 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); 15306 15307 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len]; 15308 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; 15309 15310 const uncasted_cond = try sema.resolveInst(extra.data.condition); 15311 const cond = try sema.coerce(parent_block, Type.bool, uncasted_cond, cond_src); 15312 15313 if (try sema.resolveDefinedValue(parent_block, cond_src, cond)) |cond_val| { 15314 const body = if (cond_val.toBool()) then_body else else_body; 15315 15316 try sema.maybeErrorUnwrapCondbr(parent_block, body, extra.data.condition, cond_src); 15317 // We use `analyzeBodyInner` since we want to propagate any possible 15318 // `error.ComptimeBreak` to the caller. 15319 return sema.analyzeBodyInner(parent_block, body); 15320 } 15321 15322 const gpa = sema.gpa; 15323 15324 // We'll re-use the sub block to save on memory bandwidth, and yank out the 15325 // instructions array in between using it for the then block and else block. 15326 var sub_block = parent_block.makeSubBlock(); 15327 sub_block.runtime_loop = null; 15328 sub_block.runtime_cond = cond_src; 15329 sub_block.runtime_index.increment(); 15330 defer sub_block.instructions.deinit(gpa); 15331 15332 _ = sema.analyzeBodyInner(&sub_block, then_body) catch |err| switch (err) { 15333 error.ComptimeBreak => { 15334 const zir_datas = sema.code.instructions.items(.data); 15335 const break_data = zir_datas[sema.comptime_break_inst].@"break"; 15336 try sema.addRuntimeBreak(&sub_block, .{ 15337 .block_inst = break_data.block_inst, 15338 .operand = break_data.operand, 15339 .inst = sema.comptime_break_inst, 15340 }); 15341 }, 15342 else => |e| return e, 15343 }; 15344 const true_instructions = sub_block.instructions.toOwnedSlice(gpa); 15345 defer gpa.free(true_instructions); 15346 15347 const err_cond = blk: { 15348 const index = Zir.refToIndex(extra.data.condition) orelse break :blk null; 15349 if (sema.code.instructions.items(.tag)[index] != .is_non_err) break :blk null; 15350 15351 const err_inst_data = sema.code.instructions.items(.data)[index].un_node; 15352 const err_operand = try sema.resolveInst(err_inst_data.operand); 15353 const operand_ty = sema.typeOf(err_operand); 15354 assert(operand_ty.zigTypeTag() == .ErrorUnion); 15355 const result_ty = operand_ty.errorUnionSet(); 15356 break :blk try sub_block.addTyOp(.unwrap_errunion_err, result_ty, err_operand); 15357 }; 15358 15359 if (err_cond != null and try sema.maybeErrorUnwrap(&sub_block, else_body, err_cond.?)) { 15360 // nothing to do 15361 } else { 15362 _ = sema.analyzeBodyInner(&sub_block, else_body) catch |err| switch (err) { 15363 error.ComptimeBreak => { 15364 const zir_datas = sema.code.instructions.items(.data); 15365 const break_data = zir_datas[sema.comptime_break_inst].@"break"; 15366 try sema.addRuntimeBreak(&sub_block, .{ 15367 .block_inst = break_data.block_inst, 15368 .operand = break_data.operand, 15369 .inst = sema.comptime_break_inst, 15370 }); 15371 }, 15372 else => |e| return e, 15373 }; 15374 } 15375 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + 15376 true_instructions.len + sub_block.instructions.items.len); 15377 _ = try parent_block.addInst(.{ 15378 .tag = .cond_br, 15379 .data = .{ .pl_op = .{ 15380 .operand = cond, 15381 .payload = sema.addExtraAssumeCapacity(Air.CondBr{ 15382 .then_body_len = @intCast(u32, true_instructions.len), 15383 .else_body_len = @intCast(u32, sub_block.instructions.items.len), 15384 }), 15385 } }, 15386 }); 15387 sema.air_extra.appendSliceAssumeCapacity(true_instructions); 15388 sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items); 15389 return always_noreturn; 15390 } 15391 15392 fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Ref { 15393 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 15394 const src = inst_data.src(); 15395 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 15396 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index); 15397 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 15398 const err_union = try sema.resolveInst(extra.data.operand); 15399 const err_union_ty = sema.typeOf(err_union); 15400 if (err_union_ty.zigTypeTag() != .ErrorUnion) { 15401 return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{ 15402 err_union_ty.fmt(sema.mod), 15403 }); 15404 } 15405 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union); 15406 if (is_non_err != .none) { 15407 const is_non_err_val = (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)).?; 15408 if (is_non_err_val.toBool()) { 15409 return sema.analyzeErrUnionPayload(parent_block, src, err_union_ty, err_union, operand_src, false); 15410 } 15411 // We can analyze the body directly in the parent block because we know there are 15412 // no breaks from the body possible, and that the body is noreturn. 15413 return sema.resolveBody(parent_block, body, inst); 15414 } 15415 15416 var sub_block = parent_block.makeSubBlock(); 15417 defer sub_block.instructions.deinit(sema.gpa); 15418 15419 // This body is guaranteed to end with noreturn and has no breaks. 15420 _ = try sema.analyzeBodyInner(&sub_block, body); 15421 15422 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Try).Struct.fields.len + 15423 sub_block.instructions.items.len); 15424 const try_inst = try parent_block.addInst(.{ 15425 .tag = .@"try", 15426 .data = .{ .pl_op = .{ 15427 .operand = err_union, 15428 .payload = sema.addExtraAssumeCapacity(Air.Try{ 15429 .body_len = @intCast(u32, sub_block.instructions.items.len), 15430 }), 15431 } }, 15432 }); 15433 sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items); 15434 return try_inst; 15435 } 15436 15437 fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Ref { 15438 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 15439 const src = inst_data.src(); 15440 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 15441 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index); 15442 const body = sema.code.extra[extra.end..][0..extra.data.body_len]; 15443 const operand = try sema.resolveInst(extra.data.operand); 15444 const err_union = try sema.analyzeLoad(parent_block, src, operand, operand_src); 15445 const err_union_ty = sema.typeOf(err_union); 15446 if (err_union_ty.zigTypeTag() != .ErrorUnion) { 15447 return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{ 15448 err_union_ty.fmt(sema.mod), 15449 }); 15450 } 15451 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union); 15452 if (is_non_err != .none) { 15453 const is_non_err_val = (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)).?; 15454 if (is_non_err_val.toBool()) { 15455 return sema.analyzeErrUnionPayloadPtr(parent_block, src, operand, false, false); 15456 } 15457 // We can analyze the body directly in the parent block because we know there are 15458 // no breaks from the body possible, and that the body is noreturn. 15459 return sema.resolveBody(parent_block, body, inst); 15460 } 15461 15462 var sub_block = parent_block.makeSubBlock(); 15463 defer sub_block.instructions.deinit(sema.gpa); 15464 15465 // This body is guaranteed to end with noreturn and has no breaks. 15466 _ = try sema.analyzeBodyInner(&sub_block, body); 15467 15468 const operand_ty = sema.typeOf(operand); 15469 const ptr_info = operand_ty.ptrInfo().data; 15470 const res_ty = try Type.ptr(sema.arena, sema.mod, .{ 15471 .pointee_type = err_union_ty.errorUnionPayload(), 15472 .@"addrspace" = ptr_info.@"addrspace", 15473 .mutable = ptr_info.mutable, 15474 .@"allowzero" = ptr_info.@"allowzero", 15475 .@"volatile" = ptr_info.@"volatile", 15476 }); 15477 const res_ty_ref = try sema.addType(res_ty); 15478 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.TryPtr).Struct.fields.len + 15479 sub_block.instructions.items.len); 15480 const try_inst = try parent_block.addInst(.{ 15481 .tag = .try_ptr, 15482 .data = .{ .ty_pl = .{ 15483 .ty = res_ty_ref, 15484 .payload = sema.addExtraAssumeCapacity(Air.TryPtr{ 15485 .ptr = operand, 15486 .body_len = @intCast(u32, sub_block.instructions.items.len), 15487 }), 15488 } }, 15489 }); 15490 sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items); 15491 return try_inst; 15492 } 15493 15494 // A `break` statement is inside a runtime condition, but trying to 15495 // break from an inline loop. In such case we must convert it to 15496 // a runtime break. 15497 fn addRuntimeBreak(sema: *Sema, child_block: *Block, break_data: BreakData) !void { 15498 const gop = try sema.inst_map.getOrPut(sema.gpa, break_data.block_inst); 15499 const labeled_block = if (!gop.found_existing) blk: { 15500 try sema.post_hoc_blocks.ensureUnusedCapacity(sema.gpa, 1); 15501 15502 const new_block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 15503 gop.value_ptr.* = Air.indexToRef(new_block_inst); 15504 try sema.air_instructions.append(sema.gpa, .{ 15505 .tag = .block, 15506 .data = undefined, 15507 }); 15508 const labeled_block = try sema.gpa.create(LabeledBlock); 15509 labeled_block.* = .{ 15510 .label = .{ 15511 .zir_block = break_data.block_inst, 15512 .merges = .{ 15513 .results = .{}, 15514 .br_list = .{}, 15515 .block_inst = new_block_inst, 15516 }, 15517 }, 15518 .block = .{ 15519 .parent = child_block, 15520 .sema = sema, 15521 .src_decl = child_block.src_decl, 15522 .namespace = child_block.namespace, 15523 .wip_capture_scope = child_block.wip_capture_scope, 15524 .instructions = .{}, 15525 .label = &labeled_block.label, 15526 .inlining = child_block.inlining, 15527 .is_comptime = child_block.is_comptime, 15528 }, 15529 }; 15530 sema.post_hoc_blocks.putAssumeCapacityNoClobber(new_block_inst, labeled_block); 15531 break :blk labeled_block; 15532 } else blk: { 15533 const new_block_inst = Air.refToIndex(gop.value_ptr.*).?; 15534 const labeled_block = sema.post_hoc_blocks.get(new_block_inst).?; 15535 break :blk labeled_block; 15536 }; 15537 15538 const operand = try sema.resolveInst(break_data.operand); 15539 const br_ref = try child_block.addBr(labeled_block.label.merges.block_inst, operand); 15540 try labeled_block.label.merges.results.append(sema.gpa, operand); 15541 try labeled_block.label.merges.br_list.append(sema.gpa, Air.refToIndex(br_ref).?); 15542 labeled_block.block.runtime_index.increment(); 15543 if (labeled_block.block.runtime_cond == null and labeled_block.block.runtime_loop == null) { 15544 labeled_block.block.runtime_cond = child_block.runtime_cond orelse child_block.runtime_loop; 15545 labeled_block.block.runtime_loop = child_block.runtime_loop; 15546 } 15547 } 15548 15549 fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { 15550 const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable"; 15551 const src = inst_data.src(); 15552 15553 if (block.is_comptime or inst_data.force_comptime) { 15554 return sema.fail(block, src, "reached unreachable code", .{}); 15555 } 15556 try sema.requireFunctionBlock(block, src); 15557 // TODO Add compile error for @optimizeFor occurring too late in a scope. 15558 try block.addUnreachable(src, true); 15559 return always_noreturn; 15560 } 15561 15562 fn zirRetErrValue( 15563 sema: *Sema, 15564 block: *Block, 15565 inst: Zir.Inst.Index, 15566 ) CompileError!Zir.Inst.Index { 15567 const inst_data = sema.code.instructions.items(.data)[inst].str_tok; 15568 const err_name = inst_data.get(sema.code); 15569 const src = inst_data.src(); 15570 15571 // Return the error code from the function. 15572 const kv = try sema.mod.getErrorValue(err_name); 15573 const result_inst = try sema.addConstant( 15574 try Type.Tag.error_set_single.create(sema.arena, kv.key), 15575 try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }), 15576 ); 15577 return sema.analyzeRet(block, result_inst, src); 15578 } 15579 15580 fn zirRetTok( 15581 sema: *Sema, 15582 block: *Block, 15583 inst: Zir.Inst.Index, 15584 ) CompileError!Zir.Inst.Index { 15585 const tracy = trace(@src()); 15586 defer tracy.end(); 15587 15588 const inst_data = sema.code.instructions.items(.data)[inst].un_tok; 15589 const operand = try sema.resolveInst(inst_data.operand); 15590 const src = inst_data.src(); 15591 15592 return sema.analyzeRet(block, operand, src); 15593 } 15594 15595 fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { 15596 const tracy = trace(@src()); 15597 defer tracy.end(); 15598 15599 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15600 const operand = try sema.resolveInst(inst_data.operand); 15601 const src = inst_data.src(); 15602 15603 return sema.analyzeRet(block, operand, src); 15604 } 15605 15606 fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { 15607 const tracy = trace(@src()); 15608 defer tracy.end(); 15609 15610 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15611 const src = inst_data.src(); 15612 const ret_ptr = try sema.resolveInst(inst_data.operand); 15613 15614 if (block.is_comptime or block.inlining != null) { 15615 const operand = try sema.analyzeLoad(block, src, ret_ptr, src); 15616 return sema.analyzeRet(block, operand, src); 15617 } 15618 15619 if (sema.wantErrorReturnTracing()) { 15620 const is_non_err = try sema.analyzePtrIsNonErr(block, src, ret_ptr); 15621 return retWithErrTracing(sema, block, src, is_non_err, .ret_load, ret_ptr); 15622 } 15623 15624 _ = try block.addUnOp(.ret_load, ret_ptr); 15625 return always_noreturn; 15626 } 15627 15628 fn retWithErrTracing( 15629 sema: *Sema, 15630 block: *Block, 15631 src: LazySrcLoc, 15632 is_non_err: Air.Inst.Ref, 15633 ret_tag: Air.Inst.Tag, 15634 operand: Air.Inst.Ref, 15635 ) CompileError!Zir.Inst.Index { 15636 const need_check = switch (is_non_err) { 15637 .bool_true => { 15638 _ = try block.addUnOp(ret_tag, operand); 15639 return always_noreturn; 15640 }, 15641 .bool_false => false, 15642 else => true, 15643 }; 15644 const gpa = sema.gpa; 15645 const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); 15646 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); 15647 const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty); 15648 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); 15649 const return_err_fn = try sema.getBuiltin(block, src, "returnError"); 15650 const args: [1]Air.Inst.Ref = .{err_return_trace}; 15651 15652 if (!need_check) { 15653 _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args, null); 15654 _ = try block.addUnOp(ret_tag, operand); 15655 return always_noreturn; 15656 } 15657 15658 var then_block = block.makeSubBlock(); 15659 defer then_block.instructions.deinit(gpa); 15660 _ = try then_block.addUnOp(ret_tag, operand); 15661 15662 var else_block = block.makeSubBlock(); 15663 defer else_block.instructions.deinit(gpa); 15664 _ = try sema.analyzeCall(&else_block, return_err_fn, src, src, .never_inline, false, &args, null); 15665 _ = try else_block.addUnOp(ret_tag, operand); 15666 15667 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + 15668 then_block.instructions.items.len + else_block.instructions.items.len + 15669 @typeInfo(Air.Block).Struct.fields.len + 1); 15670 15671 const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{ 15672 .then_body_len = @intCast(u32, then_block.instructions.items.len), 15673 .else_body_len = @intCast(u32, else_block.instructions.items.len), 15674 }); 15675 sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items); 15676 sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items); 15677 15678 _ = try block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{ 15679 .operand = is_non_err, 15680 .payload = cond_br_payload, 15681 } } }); 15682 15683 return always_noreturn; 15684 } 15685 15686 fn wantErrorReturnTracing(sema: *Sema) bool { 15687 // TODO implement this feature in all the backends and then delete this check. 15688 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm; 15689 15690 return sema.fn_ret_ty.isError() and 15691 sema.mod.comp.bin_file.options.error_return_tracing and 15692 backend_supports_error_return_tracing; 15693 } 15694 15695 fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void { 15696 assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion); 15697 15698 if (sema.fn_ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| { 15699 const op_ty = sema.typeOf(uncasted_operand); 15700 switch (op_ty.zigTypeTag()) { 15701 .ErrorSet => { 15702 try payload.data.addErrorSet(sema.gpa, op_ty); 15703 }, 15704 .ErrorUnion => { 15705 try payload.data.addErrorSet(sema.gpa, op_ty.errorUnionSet()); 15706 }, 15707 else => {}, 15708 } 15709 } 15710 } 15711 15712 fn analyzeRet( 15713 sema: *Sema, 15714 block: *Block, 15715 uncasted_operand: Air.Inst.Ref, 15716 src: LazySrcLoc, 15717 ) CompileError!Zir.Inst.Index { 15718 // Special case for returning an error to an inferred error set; we need to 15719 // add the error tag to the inferred error set of the in-scope function, so 15720 // that the coercion below works correctly. 15721 if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) { 15722 try sema.addToInferredErrorSet(uncasted_operand); 15723 } 15724 const operand = sema.coerceExtra(block, sema.fn_ret_ty, uncasted_operand, src, .{ .is_ret = true }) catch |err| switch (err) { 15725 error.NotCoercible => unreachable, 15726 else => |e| return e, 15727 }; 15728 15729 if (block.inlining) |inlining| { 15730 if (block.is_comptime) { 15731 inlining.comptime_result = operand; 15732 return error.ComptimeReturn; 15733 } 15734 // We are inlining a function call; rewrite the `ret` as a `break`. 15735 try inlining.merges.results.append(sema.gpa, operand); 15736 _ = try block.addBr(inlining.merges.block_inst, operand); 15737 return always_noreturn; 15738 } 15739 15740 try sema.resolveTypeLayout(block, src, sema.fn_ret_ty); 15741 15742 if (sema.wantErrorReturnTracing()) { 15743 // Avoid adding a frame to the error return trace in case the value is comptime-known 15744 // to be not an error. 15745 const is_non_err = try sema.analyzeIsNonErr(block, src, operand); 15746 return retWithErrTracing(sema, block, src, is_non_err, .ret, operand); 15747 } 15748 15749 _ = try block.addUnOp(.ret, operand); 15750 return always_noreturn; 15751 } 15752 15753 fn floatOpAllowed(tag: Zir.Inst.Tag) bool { 15754 // extend this swich as additional operators are implemented 15755 return switch (tag) { 15756 .add, .sub, .mul, .div, .div_exact, .div_trunc, .div_floor, .mod, .rem, .mod_rem => true, 15757 else => false, 15758 }; 15759 } 15760 15761 fn zirOverflowArithmeticPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 15762 const tracy = trace(@src()); 15763 defer tracy.end(); 15764 15765 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15766 const elem_ty_src = inst_data.src(); 15767 const elem_type = try sema.resolveType(block, elem_ty_src, inst_data.operand); 15768 const ty = try Type.ptr(sema.arena, sema.mod, .{ 15769 .pointee_type = elem_type, 15770 .@"addrspace" = .generic, 15771 .mutable = true, 15772 .@"allowzero" = false, 15773 .@"volatile" = false, 15774 .size = .One, 15775 }); 15776 return sema.addType(ty); 15777 } 15778 15779 fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 15780 const tracy = trace(@src()); 15781 defer tracy.end(); 15782 15783 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type; 15784 const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index); 15785 const elem_ty_src: LazySrcLoc = .{ .node_offset_ptr_elem = extra.data.src_node }; 15786 const sentinel_src: LazySrcLoc = .{ .node_offset_ptr_sentinel = extra.data.src_node }; 15787 const align_src: LazySrcLoc = .{ .node_offset_ptr_align = extra.data.src_node }; 15788 const addrspace_src: LazySrcLoc = .{ .node_offset_ptr_addrspace = extra.data.src_node }; 15789 const bitoffset_src: LazySrcLoc = .{ .node_offset_ptr_bitoffset = extra.data.src_node }; 15790 const hostsize_src: LazySrcLoc = .{ .node_offset_ptr_hostsize = extra.data.src_node }; 15791 15792 const unresolved_elem_ty = try sema.resolveType(block, elem_ty_src, extra.data.elem_type); 15793 const target = sema.mod.getTarget(); 15794 15795 var extra_i = extra.end; 15796 15797 const sentinel = if (inst_data.flags.has_sentinel) blk: { 15798 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); 15799 extra_i += 1; 15800 break :blk (try sema.resolveInstConst(block, sentinel_src, ref, "pointer sentinel value must be comptime known")).val; 15801 } else null; 15802 15803 const abi_align: u32 = if (inst_data.flags.has_align) blk: { 15804 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); 15805 extra_i += 1; 15806 const coerced = try sema.coerce(block, Type.u32, try sema.resolveInst(ref), align_src); 15807 const val = try sema.resolveConstValue(block, align_src, coerced, "pointer alignment must be comptime known"); 15808 // Check if this happens to be the lazy alignment of our element type, in 15809 // which case we can make this 0 without resolving it. 15810 if (val.castTag(.lazy_align)) |payload| { 15811 if (payload.data.eql(unresolved_elem_ty, sema.mod)) { 15812 break :blk 0; 15813 } 15814 } 15815 const abi_align = @intCast(u32, (try val.getUnsignedIntAdvanced(target, sema.kit(block, align_src))).?); 15816 try sema.validateAlign(block, align_src, abi_align); 15817 break :blk abi_align; 15818 } else 0; 15819 15820 const address_space = if (inst_data.flags.has_addrspace) blk: { 15821 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); 15822 extra_i += 1; 15823 break :blk try sema.analyzeAddrspace(block, addrspace_src, ref, .pointer); 15824 } else .generic; 15825 15826 const bit_offset = if (inst_data.flags.has_bit_range) blk: { 15827 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); 15828 extra_i += 1; 15829 const bit_offset = try sema.resolveInt(block, bitoffset_src, ref, Type.u16, "pointer bit-offset must be comptime known"); 15830 break :blk @intCast(u16, bit_offset); 15831 } else 0; 15832 15833 const host_size: u16 = if (inst_data.flags.has_bit_range) blk: { 15834 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); 15835 extra_i += 1; 15836 const host_size = try sema.resolveInt(block, hostsize_src, ref, Type.u16, "pointer host size must be comptime known"); 15837 break :blk @intCast(u16, host_size); 15838 } else 0; 15839 15840 if (host_size != 0 and bit_offset >= host_size * 8) { 15841 return sema.fail(block, bitoffset_src, "bit offset starts after end of host integer", .{}); 15842 } 15843 15844 const elem_ty = if (abi_align == 0) 15845 unresolved_elem_ty 15846 else t: { 15847 const elem_ty = try sema.resolveTypeFields(block, elem_ty_src, unresolved_elem_ty); 15848 try sema.resolveTypeLayout(block, elem_ty_src, elem_ty); 15849 break :t elem_ty; 15850 }; 15851 15852 if (elem_ty.zigTypeTag() == .NoReturn) { 15853 return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{}); 15854 } else if (elem_ty.zigTypeTag() == .Fn) { 15855 if (inst_data.size != .One) { 15856 return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{}); 15857 } 15858 const fn_align = elem_ty.fnInfo().alignment; 15859 if (inst_data.flags.has_align and abi_align != 0 and fn_align != 0 and 15860 abi_align != fn_align) 15861 { 15862 return sema.fail(block, align_src, "function pointer alignment disagrees with function alignment", .{}); 15863 } 15864 } else if (inst_data.size == .Many and elem_ty.zigTypeTag() == .Opaque) { 15865 return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{}); 15866 } else if (inst_data.size == .C) { 15867 if (!try sema.validateExternType(block, elem_ty_src, elem_ty, .other)) { 15868 const msg = msg: { 15869 const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); 15870 errdefer msg.destroy(sema.gpa); 15871 15872 const src_decl = sema.mod.declPtr(block.src_decl); 15873 try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src.toSrcLoc(src_decl), elem_ty, .other); 15874 15875 try sema.addDeclaredHereNote(msg, elem_ty); 15876 break :msg msg; 15877 }; 15878 return sema.failWithOwnedErrorMsg(msg); 15879 } 15880 if (elem_ty.zigTypeTag() == .Opaque) { 15881 return sema.fail(block, elem_ty_src, "C pointers cannot point to opaque types", .{}); 15882 } 15883 } 15884 15885 const ty = try Type.ptr(sema.arena, sema.mod, .{ 15886 .pointee_type = elem_ty, 15887 .sentinel = sentinel, 15888 .@"align" = abi_align, 15889 .@"addrspace" = address_space, 15890 .bit_offset = bit_offset, 15891 .host_size = host_size, 15892 .mutable = inst_data.flags.is_mutable, 15893 .@"allowzero" = inst_data.flags.is_allowzero, 15894 .@"volatile" = inst_data.flags.is_volatile, 15895 .size = inst_data.size, 15896 }); 15897 return sema.addType(ty); 15898 } 15899 15900 fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 15901 const tracy = trace(@src()); 15902 defer tracy.end(); 15903 15904 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 15905 const src = inst_data.src(); 15906 const obj_ty = try sema.resolveType(block, src, inst_data.operand); 15907 15908 switch (obj_ty.zigTypeTag()) { 15909 .Struct => return sema.structInitEmpty(block, obj_ty, src, src), 15910 .Array, .Vector => return sema.arrayInitEmpty(block, src, obj_ty), 15911 .Void => return sema.addConstant(obj_ty, Value.void), 15912 .Union => return sema.fail(block, src, "union initializer must initialize one field", .{}), 15913 else => return sema.failWithArrayInitNotSupported(block, src, obj_ty), 15914 } 15915 } 15916 15917 fn structInitEmpty( 15918 sema: *Sema, 15919 block: *Block, 15920 obj_ty: Type, 15921 dest_src: LazySrcLoc, 15922 init_src: LazySrcLoc, 15923 ) CompileError!Air.Inst.Ref { 15924 const gpa = sema.gpa; 15925 // This logic must be synchronized with that in `zirStructInit`. 15926 const struct_ty = try sema.resolveTypeFields(block, dest_src, obj_ty); 15927 15928 // The init values to use for the struct instance. 15929 const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount()); 15930 defer gpa.free(field_inits); 15931 mem.set(Air.Inst.Ref, field_inits, .none); 15932 15933 return sema.finishStructInit(block, init_src, dest_src, field_inits, struct_ty, false); 15934 } 15935 15936 fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) CompileError!Air.Inst.Ref { 15937 const arr_len = obj_ty.arrayLen(); 15938 if (arr_len != 0) { 15939 if (obj_ty.zigTypeTag() == .Array) { 15940 return sema.fail(block, src, "expected {d} array elements; found 0", .{arr_len}); 15941 } else { 15942 return sema.fail(block, src, "expected {d} vector elements; found 0", .{arr_len}); 15943 } 15944 } 15945 if (obj_ty.sentinel()) |sentinel| { 15946 const val = try Value.Tag.empty_array_sentinel.create(sema.arena, sentinel); 15947 return sema.addConstant(obj_ty, val); 15948 } else { 15949 return sema.addConstant(obj_ty, Value.initTag(.empty_array)); 15950 } 15951 } 15952 15953 fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 15954 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 15955 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 15956 const field_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 15957 const init_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 15958 const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data; 15959 const union_ty = try sema.resolveType(block, ty_src, extra.union_type); 15960 const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "name of field being initialized must be comptime known"); 15961 const init = try sema.resolveInst(extra.init); 15962 return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src); 15963 } 15964 15965 fn unionInit( 15966 sema: *Sema, 15967 block: *Block, 15968 uncasted_init: Air.Inst.Ref, 15969 init_src: LazySrcLoc, 15970 union_ty: Type, 15971 union_ty_src: LazySrcLoc, 15972 field_name: []const u8, 15973 field_src: LazySrcLoc, 15974 ) CompileError!Air.Inst.Ref { 15975 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src); 15976 const field = union_ty.unionFields().values()[field_index]; 15977 const init = try sema.coerce(block, field.ty, uncasted_init, init_src); 15978 15979 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| { 15980 const tag_ty = union_ty.unionTagTypeHypothetical(); 15981 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?); 15982 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); 15983 return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{ 15984 .tag = tag_val, 15985 .val = init_val, 15986 })); 15987 } 15988 15989 try sema.requireRuntimeBlock(block, init_src, null); 15990 _ = union_ty_src; 15991 try sema.queueFullTypeResolution(union_ty); 15992 return block.addUnionInit(union_ty, field_index, init); 15993 } 15994 15995 fn zirStructInit( 15996 sema: *Sema, 15997 block: *Block, 15998 inst: Zir.Inst.Index, 15999 is_ref: bool, 16000 ) CompileError!Air.Inst.Ref { 16001 const gpa = sema.gpa; 16002 const zir_datas = sema.code.instructions.items(.data); 16003 const inst_data = zir_datas[inst].pl_node; 16004 const extra = sema.code.extraData(Zir.Inst.StructInit, inst_data.payload_index); 16005 const src = inst_data.src(); 16006 16007 const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data; 16008 const first_field_type_data = zir_datas[first_item.field_type].pl_node; 16009 const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data; 16010 const resolved_ty = try sema.resolveType(block, src, first_field_type_extra.container_type); 16011 try sema.resolveTypeLayout(block, src, resolved_ty); 16012 16013 if (resolved_ty.zigTypeTag() == .Struct) { 16014 // This logic must be synchronized with that in `zirStructInitEmpty`. 16015 16016 // Maps field index to field_type index of where it was already initialized. 16017 // For making sure all fields are accounted for and no fields are duplicated. 16018 const found_fields = try gpa.alloc(Zir.Inst.Index, resolved_ty.structFieldCount()); 16019 defer gpa.free(found_fields); 16020 16021 // The init values to use for the struct instance. 16022 const field_inits = try gpa.alloc(Air.Inst.Ref, resolved_ty.structFieldCount()); 16023 defer gpa.free(field_inits); 16024 mem.set(Air.Inst.Ref, field_inits, .none); 16025 16026 var field_i: u32 = 0; 16027 var extra_index = extra.end; 16028 16029 const is_packed = resolved_ty.containerLayout() == .Packed; 16030 while (field_i < extra.data.fields_len) : (field_i += 1) { 16031 const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index); 16032 extra_index = item.end; 16033 16034 const field_type_data = zir_datas[item.data.field_type].pl_node; 16035 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node }; 16036 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; 16037 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); 16038 const field_index = if (resolved_ty.isTuple()) 16039 try sema.tupleFieldIndex(block, resolved_ty, field_name, field_src) 16040 else 16041 try sema.structFieldIndex(block, resolved_ty, field_name, field_src); 16042 if (field_inits[field_index] != .none) { 16043 const other_field_type = found_fields[field_index]; 16044 const other_field_type_data = zir_datas[other_field_type].pl_node; 16045 const other_field_src: LazySrcLoc = .{ .node_offset_initializer = other_field_type_data.src_node }; 16046 const msg = msg: { 16047 const msg = try sema.errMsg(block, field_src, "duplicate field", .{}); 16048 errdefer msg.destroy(gpa); 16049 try sema.errNote(block, other_field_src, msg, "other field here", .{}); 16050 break :msg msg; 16051 }; 16052 return sema.failWithOwnedErrorMsg(msg); 16053 } 16054 found_fields[field_index] = item.data.field_type; 16055 field_inits[field_index] = try sema.resolveInst(item.data.init); 16056 if (!is_packed) if (resolved_ty.structFieldValueComptime(field_index)) |default_value| { 16057 const init_val = (try sema.resolveMaybeUndefVal(block, field_src, field_inits[field_index])) orelse { 16058 return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime known"); 16059 }; 16060 16061 if (!init_val.eql(default_value, resolved_ty.structFieldType(field_index), sema.mod)) { 16062 return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index); 16063 } 16064 }; 16065 } 16066 16067 return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref); 16068 } else if (resolved_ty.zigTypeTag() == .Union) { 16069 if (extra.data.fields_len != 1) { 16070 return sema.fail(block, src, "union initialization expects exactly one field", .{}); 16071 } 16072 16073 const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end); 16074 16075 const field_type_data = zir_datas[item.data.field_type].pl_node; 16076 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node }; 16077 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; 16078 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); 16079 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src); 16080 const tag_ty = resolved_ty.unionTagTypeHypothetical(); 16081 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?); 16082 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); 16083 16084 const init_inst = try sema.resolveInst(item.data.init); 16085 if (try sema.resolveMaybeUndefVal(block, field_src, init_inst)) |val| { 16086 return sema.addConstantMaybeRef( 16087 block, 16088 src, 16089 resolved_ty, 16090 try Value.Tag.@"union".create(sema.arena, .{ .tag = tag_val, .val = val }), 16091 is_ref, 16092 ); 16093 } 16094 16095 if (is_ref) { 16096 const target = sema.mod.getTarget(); 16097 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ 16098 .pointee_type = resolved_ty, 16099 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 16100 }); 16101 const alloc = try block.addTy(.alloc, alloc_ty); 16102 const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true); 16103 try sema.storePtr(block, src, field_ptr, init_inst); 16104 const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(), tag_val); 16105 _ = try block.addBinOp(.set_union_tag, alloc, new_tag); 16106 return alloc; 16107 } 16108 16109 try sema.requireRuntimeBlock(block, src, null); 16110 try sema.queueFullTypeResolution(resolved_ty); 16111 return block.addUnionInit(resolved_ty, field_index, init_inst); 16112 } else if (resolved_ty.isAnonStruct()) { 16113 return sema.fail(block, src, "TODO anon struct init validation", .{}); 16114 } 16115 unreachable; 16116 } 16117 16118 fn finishStructInit( 16119 sema: *Sema, 16120 block: *Block, 16121 init_src: LazySrcLoc, 16122 dest_src: LazySrcLoc, 16123 field_inits: []Air.Inst.Ref, 16124 struct_ty: Type, 16125 is_ref: bool, 16126 ) CompileError!Air.Inst.Ref { 16127 const gpa = sema.gpa; 16128 16129 var root_msg: ?*Module.ErrorMsg = null; 16130 errdefer if (root_msg) |msg| msg.destroy(sema.gpa); 16131 16132 if (struct_ty.isAnonStruct()) { 16133 const struct_obj = struct_ty.castTag(.anon_struct).?.data; 16134 for (struct_obj.values) |default_val, i| { 16135 if (field_inits[i] != .none) continue; 16136 16137 if (default_val.tag() == .unreachable_value) { 16138 const field_name = struct_obj.names[i]; 16139 const template = "missing struct field: {s}"; 16140 const args = .{field_name}; 16141 if (root_msg) |msg| { 16142 try sema.errNote(block, init_src, msg, template, args); 16143 } else { 16144 root_msg = try sema.errMsg(block, init_src, template, args); 16145 } 16146 } else { 16147 field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val); 16148 } 16149 } 16150 } else if (struct_ty.isTuple()) { 16151 const struct_obj = struct_ty.castTag(.tuple).?.data; 16152 for (struct_obj.values) |default_val, i| { 16153 if (field_inits[i] != .none) continue; 16154 16155 if (default_val.tag() == .unreachable_value) { 16156 const template = "missing tuple field with index {d}"; 16157 if (root_msg) |msg| { 16158 try sema.errNote(block, init_src, msg, template, .{i}); 16159 } else { 16160 root_msg = try sema.errMsg(block, init_src, template, .{i}); 16161 } 16162 } else { 16163 field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val); 16164 } 16165 } 16166 } else { 16167 const struct_obj = struct_ty.castTag(.@"struct").?.data; 16168 for (struct_obj.fields.values()) |field, i| { 16169 if (field_inits[i] != .none) continue; 16170 16171 if (field.default_val.tag() == .unreachable_value) { 16172 const field_name = struct_obj.fields.keys()[i]; 16173 const template = "missing struct field: {s}"; 16174 const args = .{field_name}; 16175 if (root_msg) |msg| { 16176 try sema.errNote(block, init_src, msg, template, args); 16177 } else { 16178 root_msg = try sema.errMsg(block, init_src, template, args); 16179 } 16180 } else { 16181 field_inits[i] = try sema.addConstant(field.ty, field.default_val); 16182 } 16183 } 16184 } 16185 16186 if (root_msg) |msg| { 16187 root_msg = null; 16188 if (struct_ty.castTag(.@"struct")) |struct_obj| { 16189 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod); 16190 defer gpa.free(fqn); 16191 try sema.mod.errNoteNonLazy( 16192 struct_obj.data.srcLoc(sema.mod), 16193 msg, 16194 "struct '{s}' declared here", 16195 .{fqn}, 16196 ); 16197 } 16198 return sema.failWithOwnedErrorMsg(msg); 16199 } 16200 16201 const is_comptime = for (field_inits) |field_init| { 16202 if (!(try sema.isComptimeKnown(block, dest_src, field_init))) { 16203 break false; 16204 } 16205 } else true; 16206 16207 if (is_comptime) { 16208 const values = try sema.arena.alloc(Value, field_inits.len); 16209 for (field_inits) |field_init, i| { 16210 values[i] = (sema.resolveMaybeUndefVal(block, dest_src, field_init) catch unreachable).?; 16211 } 16212 const struct_val = try Value.Tag.aggregate.create(sema.arena, values); 16213 return sema.addConstantMaybeRef(block, dest_src, struct_ty, struct_val, is_ref); 16214 } 16215 16216 if (is_ref) { 16217 try sema.resolveStructLayout(block, dest_src, struct_ty); 16218 const target = sema.mod.getTarget(); 16219 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ 16220 .pointee_type = struct_ty, 16221 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 16222 }); 16223 const alloc = try block.addTy(.alloc, alloc_ty); 16224 for (field_inits) |field_init, i_usize| { 16225 const i = @intCast(u32, i_usize); 16226 const field_src = dest_src; 16227 const field_ptr = try sema.structFieldPtrByIndex(block, dest_src, alloc, i, field_src, struct_ty, true); 16228 try sema.storePtr(block, dest_src, field_ptr, field_init); 16229 } 16230 16231 return alloc; 16232 } 16233 16234 try sema.requireRuntimeBlock(block, dest_src, null); 16235 try sema.queueFullTypeResolution(struct_ty); 16236 return block.addAggregateInit(struct_ty, field_inits); 16237 } 16238 16239 fn zirStructInitAnon( 16240 sema: *Sema, 16241 block: *Block, 16242 inst: Zir.Inst.Index, 16243 is_ref: bool, 16244 ) CompileError!Air.Inst.Ref { 16245 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 16246 const src = inst_data.src(); 16247 const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index); 16248 const types = try sema.arena.alloc(Type, extra.data.fields_len); 16249 const values = try sema.arena.alloc(Value, types.len); 16250 var fields = std.StringArrayHashMapUnmanaged(u32){}; 16251 defer fields.deinit(sema.gpa); 16252 try fields.ensureUnusedCapacity(sema.gpa, types.len); 16253 16254 const opt_runtime_index = rs: { 16255 var runtime_index: ?usize = null; 16256 var extra_index = extra.end; 16257 for (types) |*field_ty, i| { 16258 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); 16259 extra_index = item.end; 16260 16261 const name = sema.code.nullTerminatedString(item.data.field_name); 16262 const gop = fields.getOrPutAssumeCapacity(name); 16263 if (gop.found_existing) { 16264 const msg = msg: { 16265 const decl = sema.mod.declPtr(block.src_decl); 16266 const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i); 16267 const msg = try sema.errMsg(block, field_src, "duplicate field", .{}); 16268 errdefer msg.destroy(sema.gpa); 16269 16270 const prev_source = Module.initSrc(src.node_offset.x, sema.gpa, decl, gop.value_ptr.*); 16271 try sema.errNote(block, prev_source, msg, "other field here", .{}); 16272 break :msg msg; 16273 }; 16274 return sema.failWithOwnedErrorMsg(msg); 16275 } 16276 gop.value_ptr.* = @intCast(u32, i); 16277 16278 const init = try sema.resolveInst(item.data.init); 16279 field_ty.* = sema.typeOf(init); 16280 if (types[i].zigTypeTag() == .Opaque) { 16281 const msg = msg: { 16282 const decl = sema.mod.declPtr(block.src_decl); 16283 const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i); 16284 const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); 16285 errdefer msg.destroy(sema.gpa); 16286 16287 try sema.addDeclaredHereNote(msg, types[i]); 16288 break :msg msg; 16289 }; 16290 return sema.failWithOwnedErrorMsg(msg); 16291 } 16292 const init_src = src; // TODO better source location 16293 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| { 16294 values[i] = init_val; 16295 } else { 16296 values[i] = Value.initTag(.unreachable_value); 16297 runtime_index = i; 16298 } 16299 } 16300 break :rs runtime_index; 16301 }; 16302 16303 const tuple_ty = try Type.Tag.anon_struct.create(sema.arena, .{ 16304 .names = try sema.arena.dupe([]const u8, fields.keys()), 16305 .types = types, 16306 .values = values, 16307 }); 16308 16309 const runtime_index = opt_runtime_index orelse { 16310 const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); 16311 return sema.addConstantMaybeRef(block, src, tuple_ty, tuple_val, is_ref); 16312 }; 16313 16314 sema.requireRuntimeBlock(block, src, .unneeded) catch |err| switch (err) { 16315 error.NeededSourceLocation => { 16316 const decl = sema.mod.declPtr(block.src_decl); 16317 const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, runtime_index); 16318 try sema.requireRuntimeBlock(block, src, field_src); 16319 return error.AnalysisFail; 16320 }, 16321 else => |e| return e, 16322 }; 16323 16324 if (is_ref) { 16325 const target = sema.mod.getTarget(); 16326 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ 16327 .pointee_type = tuple_ty, 16328 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 16329 }); 16330 const alloc = try block.addTy(.alloc, alloc_ty); 16331 var extra_index = extra.end; 16332 for (types) |field_ty, i_usize| { 16333 const i = @intCast(u32, i_usize); 16334 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); 16335 extra_index = item.end; 16336 16337 const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 16338 .mutable = true, 16339 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 16340 .pointee_type = field_ty, 16341 }); 16342 if (values[i].tag() == .unreachable_value) { 16343 const init = try sema.resolveInst(item.data.init); 16344 const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); 16345 _ = try block.addBinOp(.store, field_ptr, init); 16346 } 16347 } 16348 16349 return alloc; 16350 } 16351 16352 const element_refs = try sema.arena.alloc(Air.Inst.Ref, types.len); 16353 var extra_index = extra.end; 16354 for (types) |_, i| { 16355 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); 16356 extra_index = item.end; 16357 element_refs[i] = try sema.resolveInst(item.data.init); 16358 } 16359 16360 return block.addAggregateInit(tuple_ty, element_refs); 16361 } 16362 16363 fn zirArrayInit( 16364 sema: *Sema, 16365 block: *Block, 16366 inst: Zir.Inst.Index, 16367 is_ref: bool, 16368 ) CompileError!Air.Inst.Ref { 16369 const gpa = sema.gpa; 16370 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 16371 const src = inst_data.src(); 16372 16373 const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); 16374 const args = sema.code.refSlice(extra.end, extra.data.operands_len); 16375 assert(args.len >= 2); // array_ty + at least one element 16376 16377 const array_ty = try sema.resolveType(block, src, args[0]); 16378 const sentinel_val = array_ty.sentinel(); 16379 16380 const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @boolToInt(sentinel_val != null)); 16381 defer gpa.free(resolved_args); 16382 for (args[1..]) |arg, i| { 16383 const resolved_arg = try sema.resolveInst(arg); 16384 const arg_src = src; // TODO better source location 16385 const elem_ty = if (array_ty.zigTypeTag() == .Struct) 16386 array_ty.tupleFields().types[i] 16387 else 16388 array_ty.elemType2(); 16389 resolved_args[i] = try sema.coerce(block, elem_ty, resolved_arg, arg_src); 16390 } 16391 16392 if (sentinel_val) |some| { 16393 resolved_args[resolved_args.len - 1] = try sema.addConstant(array_ty.elemType2(), some); 16394 } 16395 16396 const opt_runtime_src: ?LazySrcLoc = for (resolved_args) |arg| { 16397 const arg_src = src; // TODO better source location 16398 const comptime_known = try sema.isComptimeKnown(block, arg_src, arg); 16399 if (!comptime_known) break arg_src; 16400 } else null; 16401 16402 const runtime_src = opt_runtime_src orelse { 16403 const elem_vals = try sema.arena.alloc(Value, resolved_args.len); 16404 16405 for (resolved_args) |arg, i| { 16406 // We checked that all args are comptime above. 16407 elem_vals[i] = (sema.resolveMaybeUndefVal(block, src, arg) catch unreachable).?; 16408 } 16409 16410 const array_val = try Value.Tag.aggregate.create(sema.arena, elem_vals); 16411 return sema.addConstantMaybeRef(block, src, array_ty, array_val, is_ref); 16412 }; 16413 16414 try sema.requireRuntimeBlock(block, src, runtime_src); 16415 try sema.queueFullTypeResolution(array_ty); 16416 16417 if (is_ref) { 16418 const target = sema.mod.getTarget(); 16419 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ 16420 .pointee_type = array_ty, 16421 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 16422 }); 16423 const alloc = try block.addTy(.alloc, alloc_ty); 16424 16425 if (array_ty.isTuple()) { 16426 const types = array_ty.tupleFields().types; 16427 for (resolved_args) |arg, i| { 16428 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 16429 .mutable = true, 16430 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 16431 .pointee_type = types[i], 16432 }); 16433 const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty); 16434 16435 const index = try sema.addIntUnsigned(Type.usize, i); 16436 const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref); 16437 _ = try block.addBinOp(.store, elem_ptr, arg); 16438 } 16439 return alloc; 16440 } 16441 16442 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 16443 .mutable = true, 16444 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 16445 .pointee_type = array_ty.elemType2(), 16446 }); 16447 const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty); 16448 16449 for (resolved_args) |arg, i| { 16450 const index = try sema.addIntUnsigned(Type.usize, i); 16451 const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref); 16452 _ = try block.addBinOp(.store, elem_ptr, arg); 16453 } 16454 return alloc; 16455 } 16456 16457 return block.addAggregateInit(array_ty, resolved_args); 16458 } 16459 16460 fn zirArrayInitAnon( 16461 sema: *Sema, 16462 block: *Block, 16463 inst: Zir.Inst.Index, 16464 is_ref: bool, 16465 ) CompileError!Air.Inst.Ref { 16466 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 16467 const src = inst_data.src(); 16468 const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); 16469 const operands = sema.code.refSlice(extra.end, extra.data.operands_len); 16470 16471 const types = try sema.arena.alloc(Type, operands.len); 16472 const values = try sema.arena.alloc(Value, operands.len); 16473 16474 const opt_runtime_src = rs: { 16475 var runtime_src: ?LazySrcLoc = null; 16476 for (operands) |operand, i| { 16477 const operand_src = src; // TODO better source location 16478 const elem = try sema.resolveInst(operand); 16479 types[i] = sema.typeOf(elem); 16480 if (types[i].zigTypeTag() == .Opaque) { 16481 const msg = msg: { 16482 const msg = try sema.errMsg(block, operand_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); 16483 errdefer msg.destroy(sema.gpa); 16484 16485 try sema.addDeclaredHereNote(msg, types[i]); 16486 break :msg msg; 16487 }; 16488 return sema.failWithOwnedErrorMsg(msg); 16489 } 16490 if (try sema.resolveMaybeUndefVal(block, operand_src, elem)) |val| { 16491 values[i] = val; 16492 } else { 16493 values[i] = Value.initTag(.unreachable_value); 16494 runtime_src = operand_src; 16495 } 16496 } 16497 break :rs runtime_src; 16498 }; 16499 16500 const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ 16501 .types = types, 16502 .values = values, 16503 }); 16504 16505 const runtime_src = opt_runtime_src orelse { 16506 const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); 16507 return sema.addConstantMaybeRef(block, src, tuple_ty, tuple_val, is_ref); 16508 }; 16509 16510 try sema.requireRuntimeBlock(block, src, runtime_src); 16511 16512 if (is_ref) { 16513 const target = sema.mod.getTarget(); 16514 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ 16515 .pointee_type = tuple_ty, 16516 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 16517 }); 16518 const alloc = try block.addTy(.alloc, alloc_ty); 16519 for (operands) |operand, i_usize| { 16520 const i = @intCast(u32, i_usize); 16521 const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ 16522 .mutable = true, 16523 .@"addrspace" = target_util.defaultAddressSpace(target, .local), 16524 .pointee_type = types[i], 16525 }); 16526 if (values[i].tag() == .unreachable_value) { 16527 const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); 16528 _ = try block.addBinOp(.store, field_ptr, try sema.resolveInst(operand)); 16529 } 16530 } 16531 16532 return alloc; 16533 } 16534 16535 const element_refs = try sema.arena.alloc(Air.Inst.Ref, operands.len); 16536 for (operands) |operand, i| { 16537 element_refs[i] = try sema.resolveInst(operand); 16538 } 16539 16540 return block.addAggregateInit(tuple_ty, element_refs); 16541 } 16542 16543 fn addConstantMaybeRef( 16544 sema: *Sema, 16545 block: *Block, 16546 src: LazySrcLoc, 16547 ty: Type, 16548 val: Value, 16549 is_ref: bool, 16550 ) !Air.Inst.Ref { 16551 if (!is_ref) return sema.addConstant(ty, val); 16552 16553 var anon_decl = try block.startAnonDecl(src); 16554 defer anon_decl.deinit(); 16555 const decl = try anon_decl.finish( 16556 try ty.copy(anon_decl.arena()), 16557 try val.copy(anon_decl.arena()), 16558 0, // default alignment 16559 ); 16560 return sema.analyzeDeclRef(decl); 16561 } 16562 16563 fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 16564 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 16565 const extra = sema.code.extraData(Zir.Inst.FieldTypeRef, inst_data.payload_index).data; 16566 const ty_src = inst_data.src(); 16567 const field_src = inst_data.src(); 16568 const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type); 16569 const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "field name must be comptime known"); 16570 return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src); 16571 } 16572 16573 fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 16574 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 16575 const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data; 16576 const ty_src = inst_data.src(); 16577 const field_src = inst_data.src(); 16578 const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type); 16579 if (aggregate_ty.tag() == .var_args_param) return sema.addType(aggregate_ty); 16580 const field_name = sema.code.nullTerminatedString(extra.name_start); 16581 return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src); 16582 } 16583 16584 fn fieldType( 16585 sema: *Sema, 16586 block: *Block, 16587 aggregate_ty: Type, 16588 field_name: []const u8, 16589 field_src: LazySrcLoc, 16590 ty_src: LazySrcLoc, 16591 ) CompileError!Air.Inst.Ref { 16592 var cur_ty = aggregate_ty; 16593 while (true) { 16594 const resolved_ty = try sema.resolveTypeFields(block, ty_src, cur_ty); 16595 cur_ty = resolved_ty; 16596 switch (cur_ty.zigTypeTag()) { 16597 .Struct => { 16598 if (cur_ty.isAnonStruct()) { 16599 const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src); 16600 return sema.addType(cur_ty.tupleFields().types[field_index]); 16601 } 16602 const struct_obj = cur_ty.castTag(.@"struct").?.data; 16603 const field = struct_obj.fields.get(field_name) orelse 16604 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); 16605 return sema.addType(field.ty); 16606 }, 16607 .Union => { 16608 const union_obj = cur_ty.cast(Type.Payload.Union).?.data; 16609 const field = union_obj.fields.get(field_name) orelse 16610 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); 16611 return sema.addType(field.ty); 16612 }, 16613 .Optional => { 16614 if (cur_ty.castTag(.optional)) |some| { 16615 // Struct/array init through optional requires the child type to not be a pointer. 16616 // If the child of .optional is a pointer it'll error on the next loop. 16617 cur_ty = some.data; 16618 continue; 16619 } 16620 }, 16621 .ErrorUnion => { 16622 cur_ty = cur_ty.errorUnionPayload(); 16623 continue; 16624 }, 16625 else => {}, 16626 } 16627 return sema.fail(block, ty_src, "expected struct or union; found '{}'", .{ 16628 resolved_ty.fmt(sema.mod), 16629 }); 16630 } 16631 } 16632 16633 fn zirErrorReturnTrace( 16634 sema: *Sema, 16635 block: *Block, 16636 extended: Zir.Inst.Extended.InstData, 16637 ) CompileError!Air.Inst.Ref { 16638 const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand)); 16639 return sema.getErrorReturnTrace(block, src); 16640 } 16641 16642 fn getErrorReturnTrace(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError!Air.Inst.Ref { 16643 const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); 16644 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); 16645 const opt_ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty); 16646 16647 // TODO implement this feature in all the backends and then delete this check. 16648 const backend_supports_error_return_tracing = 16649 sema.mod.comp.bin_file.options.use_llvm; 16650 16651 if (sema.owner_func != null and 16652 sema.owner_func.?.calls_or_awaits_errorable_fn and 16653 sema.mod.comp.bin_file.options.error_return_tracing and 16654 backend_supports_error_return_tracing) 16655 { 16656 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); 16657 } 16658 return sema.addConstant(opt_ptr_stack_trace_ty, Value.@"null"); 16659 } 16660 16661 fn zirFrame( 16662 sema: *Sema, 16663 block: *Block, 16664 extended: Zir.Inst.Extended.InstData, 16665 ) CompileError!Air.Inst.Ref { 16666 const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand)); 16667 return sema.failWithUseOfAsync(block, src); 16668 } 16669 16670 fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 16671 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 16672 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 16673 const ty = try sema.resolveType(block, operand_src, inst_data.operand); 16674 if (ty.isNoReturn()) { 16675 return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.mod)}); 16676 } 16677 const target = sema.mod.getTarget(); 16678 const val = try ty.lazyAbiAlignment(target, sema.arena); 16679 if (val.tag() == .lazy_align) { 16680 try sema.queueFullTypeResolution(ty); 16681 } 16682 return sema.addConstant(Type.comptime_int, val); 16683 } 16684 16685 fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 16686 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 16687 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 16688 const operand = try sema.resolveInst(inst_data.operand); 16689 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { 16690 if (val.isUndef()) return sema.addConstUndef(Type.initTag(.u1)); 16691 const bool_ints = [2]Air.Inst.Ref{ .zero, .one }; 16692 return bool_ints[@boolToInt(val.toBool())]; 16693 } 16694 return block.addUnOp(.bool_to_int, operand); 16695 } 16696 16697 fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 16698 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 16699 const src = inst_data.src(); 16700 _ = src; 16701 const operand = try sema.resolveInst(inst_data.operand); 16702 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 16703 16704 if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { 16705 const bytes = val.castTag(.@"error").?.data.name; 16706 return sema.addStrLit(block, bytes); 16707 } 16708 16709 // Similar to zirTagName, we have special AIR instruction for the error name in case an optimimzation pass 16710 // might be able to resolve the result at compile time. 16711 return block.addUnOp(.error_name, operand); 16712 } 16713 16714 fn zirUnaryMath( 16715 sema: *Sema, 16716 block: *Block, 16717 inst: Zir.Inst.Index, 16718 air_tag: Air.Inst.Tag, 16719 comptime eval: fn (Value, Type, Allocator, std.Target) Allocator.Error!Value, 16720 ) CompileError!Air.Inst.Ref { 16721 const tracy = trace(@src()); 16722 defer tracy.end(); 16723 16724 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 16725 const operand = try sema.resolveInst(inst_data.operand); 16726 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 16727 const operand_ty = sema.typeOf(operand); 16728 const target = sema.mod.getTarget(); 16729 16730 switch (operand_ty.zigTypeTag()) { 16731 .ComptimeFloat, .Float => {}, 16732 .Vector => { 16733 const scalar_ty = operand_ty.scalarType(); 16734 switch (scalar_ty.zigTypeTag()) { 16735 .ComptimeFloat, .Float => {}, 16736 else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{scalar_ty.fmt(sema.mod)}), 16737 } 16738 }, 16739 else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{operand_ty.fmt(sema.mod)}), 16740 } 16741 16742 switch (operand_ty.zigTypeTag()) { 16743 .Vector => { 16744 const scalar_ty = operand_ty.scalarType(); 16745 const vec_len = operand_ty.vectorLen(); 16746 const result_ty = try Type.vector(sema.arena, vec_len, scalar_ty); 16747 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { 16748 if (val.isUndef()) 16749 return sema.addConstUndef(result_ty); 16750 16751 var elem_buf: Value.ElemValueBuffer = undefined; 16752 const elems = try sema.arena.alloc(Value, vec_len); 16753 for (elems) |*elem, i| { 16754 const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); 16755 elem.* = try eval(elem_val, scalar_ty, sema.arena, target); 16756 } 16757 return sema.addConstant( 16758 result_ty, 16759 try Value.Tag.aggregate.create(sema.arena, elems), 16760 ); 16761 } 16762 16763 try sema.requireRuntimeBlock(block, operand_src, null); 16764 return block.addUnOp(air_tag, operand); 16765 }, 16766 .ComptimeFloat, .Float => { 16767 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| { 16768 if (operand_val.isUndef()) 16769 return sema.addConstUndef(operand_ty); 16770 const result_val = try eval(operand_val, operand_ty, sema.arena, target); 16771 return sema.addConstant(operand_ty, result_val); 16772 } 16773 16774 try sema.requireRuntimeBlock(block, operand_src, null); 16775 return block.addUnOp(air_tag, operand); 16776 }, 16777 else => unreachable, 16778 } 16779 } 16780 16781 fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 16782 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 16783 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 16784 const src = inst_data.src(); 16785 const operand = try sema.resolveInst(inst_data.operand); 16786 const operand_ty = sema.typeOf(operand); 16787 const mod = sema.mod; 16788 16789 try sema.resolveTypeLayout(block, operand_src, operand_ty); 16790 const enum_ty = switch (operand_ty.zigTypeTag()) { 16791 .EnumLiteral => { 16792 const val = try sema.resolveConstValue(block, .unneeded, operand, undefined); 16793 const bytes = val.castTag(.enum_literal).?.data; 16794 return sema.addStrLit(block, bytes); 16795 }, 16796 .Enum => operand_ty, 16797 .Union => operand_ty.unionTagType() orelse { 16798 const msg = msg: { 16799 const msg = try sema.errMsg(block, src, "union '{}' is untagged", .{ 16800 operand_ty.fmt(sema.mod), 16801 }); 16802 errdefer msg.destroy(sema.gpa); 16803 try sema.addDeclaredHereNote(msg, operand_ty); 16804 break :msg msg; 16805 }; 16806 return sema.failWithOwnedErrorMsg(msg); 16807 }, 16808 else => return sema.fail(block, operand_src, "expected enum or union; found '{}'", .{ 16809 operand_ty.fmt(mod), 16810 }), 16811 }; 16812 const enum_decl_index = enum_ty.getOwnerDecl(); 16813 const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src); 16814 if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| { 16815 const field_index = enum_ty.enumTagFieldIndex(val, mod) orelse { 16816 const enum_decl = mod.declPtr(enum_decl_index); 16817 const msg = msg: { 16818 const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{s}'", .{ 16819 val.fmtValue(enum_ty, sema.mod), enum_decl.name, 16820 }); 16821 errdefer msg.destroy(sema.gpa); 16822 try mod.errNoteNonLazy(enum_decl.srcLoc(), msg, "declared here", .{}); 16823 break :msg msg; 16824 }; 16825 return sema.failWithOwnedErrorMsg(msg); 16826 }; 16827 const field_name = enum_ty.enumFieldName(field_index); 16828 return sema.addStrLit(block, field_name); 16829 } 16830 try sema.requireRuntimeBlock(block, src, operand_src); 16831 if (block.wantSafety() and sema.mod.comp.bin_file.options.use_llvm) { 16832 const ok = try block.addUnOp(.is_named_enum_value, casted_operand); 16833 try sema.addSafetyCheck(block, ok, .invalid_enum_value); 16834 } 16835 // In case the value is runtime-known, we have an AIR instruction for this instead 16836 // of trying to lower it in Sema because an optimization pass may result in the operand 16837 // being comptime-known, which would let us elide the `tag_name` AIR instruction. 16838 return block.addUnOp(.tag_name, casted_operand); 16839 } 16840 16841 fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 16842 const mod = sema.mod; 16843 const name_strategy = @intToEnum(Zir.Inst.NameStrategy, extended.small); 16844 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 16845 const src = LazySrcLoc.nodeOffset(extra.node); 16846 const type_info_ty = try sema.resolveBuiltinTypeFields(block, src, "Type"); 16847 const uncasted_operand = try sema.resolveInst(extra.operand); 16848 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 16849 const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src); 16850 const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime known"); 16851 const union_val = val.cast(Value.Payload.Union).?.data; 16852 const target = mod.getTarget(); 16853 const tag_index = type_info_ty.unionTagFieldIndex(union_val.tag, mod).?; 16854 if (union_val.val.anyUndef()) return sema.failWithUseOfUndef(block, src); 16855 switch (@intToEnum(std.builtin.TypeId, tag_index)) { 16856 .Type => return Air.Inst.Ref.type_type, 16857 .Void => return Air.Inst.Ref.void_type, 16858 .Bool => return Air.Inst.Ref.bool_type, 16859 .NoReturn => return Air.Inst.Ref.noreturn_type, 16860 .ComptimeFloat => return Air.Inst.Ref.comptime_float_type, 16861 .ComptimeInt => return Air.Inst.Ref.comptime_int_type, 16862 .Undefined => return Air.Inst.Ref.undefined_type, 16863 .Null => return Air.Inst.Ref.null_type, 16864 .AnyFrame => return sema.failWithUseOfAsync(block, src), 16865 .EnumLiteral => return Air.Inst.Ref.enum_literal_type, 16866 .Int => { 16867 const struct_val = union_val.val.castTag(.aggregate).?.data; 16868 // TODO use reflection instead of magic numbers here 16869 const signedness_val = struct_val[0]; 16870 const bits_val = struct_val[1]; 16871 16872 const signedness = signedness_val.toEnum(std.builtin.Signedness); 16873 const bits = @intCast(u16, bits_val.toUnsignedInt(target)); 16874 const ty = switch (signedness) { 16875 .signed => try Type.Tag.int_signed.create(sema.arena, bits), 16876 .unsigned => try Type.Tag.int_unsigned.create(sema.arena, bits), 16877 }; 16878 return sema.addType(ty); 16879 }, 16880 .Vector => { 16881 const struct_val = union_val.val.castTag(.aggregate).?.data; 16882 // TODO use reflection instead of magic numbers here 16883 const len_val = struct_val[0]; 16884 const child_val = struct_val[1]; 16885 16886 const len = len_val.toUnsignedInt(target); 16887 var buffer: Value.ToTypeBuffer = undefined; 16888 const child_ty = child_val.toType(&buffer); 16889 16890 try sema.checkVectorElemType(block, src, child_ty); 16891 16892 const ty = try Type.vector(sema.arena, len, try child_ty.copy(sema.arena)); 16893 return sema.addType(ty); 16894 }, 16895 .Float => { 16896 const struct_val = union_val.val.castTag(.aggregate).?.data; 16897 // TODO use reflection instead of magic numbers here 16898 // bits: comptime_int, 16899 const bits_val = struct_val[0]; 16900 16901 const bits = @intCast(u16, bits_val.toUnsignedInt(target)); 16902 const ty = switch (bits) { 16903 16 => Type.@"f16", 16904 32 => Type.@"f32", 16905 64 => Type.@"f64", 16906 80 => Type.@"f80", 16907 128 => Type.@"f128", 16908 else => return sema.fail(block, src, "{}-bit float unsupported", .{bits}), 16909 }; 16910 return sema.addType(ty); 16911 }, 16912 .Pointer => { 16913 const struct_val = union_val.val.castTag(.aggregate).?.data; 16914 // TODO use reflection instead of magic numbers here 16915 const size_val = struct_val[0]; 16916 const is_const_val = struct_val[1]; 16917 const is_volatile_val = struct_val[2]; 16918 const alignment_val = struct_val[3]; 16919 const address_space_val = struct_val[4]; 16920 const child_val = struct_val[5]; 16921 const is_allowzero_val = struct_val[6]; 16922 const sentinel_val = struct_val[7]; 16923 16924 if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) { 16925 return sema.fail(block, src, "alignment must fit in 'u32'", .{}); 16926 } 16927 const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?); 16928 16929 var buffer: Value.ToTypeBuffer = undefined; 16930 const unresolved_elem_ty = child_val.toType(&buffer); 16931 const elem_ty = if (abi_align == 0) 16932 unresolved_elem_ty 16933 else t: { 16934 const elem_ty = try sema.resolveTypeFields(block, src, unresolved_elem_ty); 16935 try sema.resolveTypeLayout(block, src, elem_ty); 16936 break :t elem_ty; 16937 }; 16938 16939 const ptr_size = size_val.toEnum(std.builtin.Type.Pointer.Size); 16940 16941 var actual_sentinel: ?Value = null; 16942 if (!sentinel_val.isNull()) { 16943 if (ptr_size == .One or ptr_size == .C) { 16944 return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{}); 16945 } 16946 const sentinel_ptr_val = sentinel_val.castTag(.opt_payload).?.data; 16947 const ptr_ty = try Type.ptr(sema.arena, mod, .{ 16948 .@"addrspace" = .generic, 16949 .pointee_type = try elem_ty.copy(sema.arena), 16950 }); 16951 actual_sentinel = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?; 16952 } 16953 16954 if (elem_ty.zigTypeTag() == .NoReturn) { 16955 return sema.fail(block, src, "pointer to noreturn not allowed", .{}); 16956 } else if (elem_ty.zigTypeTag() == .Fn) { 16957 if (ptr_size != .One) { 16958 return sema.fail(block, src, "function pointers must be single pointers", .{}); 16959 } 16960 const fn_align = elem_ty.fnInfo().alignment; 16961 if (abi_align != 0 and fn_align != 0 and 16962 abi_align != fn_align) 16963 { 16964 return sema.fail(block, src, "function pointer alignment disagrees with function alignment", .{}); 16965 } 16966 } else if (ptr_size == .Many and elem_ty.zigTypeTag() == .Opaque) { 16967 return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); 16968 } else if (ptr_size == .C) { 16969 if (!try sema.validateExternType(block, src, elem_ty, .other)) { 16970 const msg = msg: { 16971 const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); 16972 errdefer msg.destroy(sema.gpa); 16973 16974 const src_decl = sema.mod.declPtr(block.src_decl); 16975 try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), elem_ty, .other); 16976 16977 try sema.addDeclaredHereNote(msg, elem_ty); 16978 break :msg msg; 16979 }; 16980 return sema.failWithOwnedErrorMsg(msg); 16981 } 16982 if (elem_ty.zigTypeTag() == .Opaque) { 16983 return sema.fail(block, src, "C pointers cannot point to opaque types", .{}); 16984 } 16985 } 16986 16987 const ty = try Type.ptr(sema.arena, mod, .{ 16988 .size = ptr_size, 16989 .mutable = !is_const_val.toBool(), 16990 .@"volatile" = is_volatile_val.toBool(), 16991 .@"align" = abi_align, 16992 .@"addrspace" = address_space_val.toEnum(std.builtin.AddressSpace), 16993 .pointee_type = try elem_ty.copy(sema.arena), 16994 .@"allowzero" = is_allowzero_val.toBool(), 16995 .sentinel = actual_sentinel, 16996 }); 16997 return sema.addType(ty); 16998 }, 16999 .Array => { 17000 const struct_val = union_val.val.castTag(.aggregate).?.data; 17001 // TODO use reflection instead of magic numbers here 17002 // len: comptime_int, 17003 const len_val = struct_val[0]; 17004 // child: type, 17005 const child_val = struct_val[1]; 17006 // sentinel: ?*const anyopaque, 17007 const sentinel_val = struct_val[2]; 17008 17009 const len = len_val.toUnsignedInt(target); 17010 var buffer: Value.ToTypeBuffer = undefined; 17011 const child_ty = try child_val.toType(&buffer).copy(sema.arena); 17012 const sentinel = if (sentinel_val.castTag(.opt_payload)) |p| blk: { 17013 const ptr_ty = try Type.ptr(sema.arena, mod, .{ 17014 .@"addrspace" = .generic, 17015 .pointee_type = child_ty, 17016 }); 17017 break :blk (try sema.pointerDeref(block, src, p.data, ptr_ty)).?; 17018 } else null; 17019 17020 const ty = try Type.array(sema.arena, len, sentinel, child_ty, sema.mod); 17021 return sema.addType(ty); 17022 }, 17023 .Optional => { 17024 const struct_val = union_val.val.castTag(.aggregate).?.data; 17025 // TODO use reflection instead of magic numbers here 17026 // child: type, 17027 const child_val = struct_val[0]; 17028 17029 var buffer: Value.ToTypeBuffer = undefined; 17030 const child_ty = try child_val.toType(&buffer).copy(sema.arena); 17031 17032 const ty = try Type.optional(sema.arena, child_ty); 17033 return sema.addType(ty); 17034 }, 17035 .ErrorUnion => { 17036 const struct_val = union_val.val.castTag(.aggregate).?.data; 17037 // TODO use reflection instead of magic numbers here 17038 // error_set: type, 17039 const error_set_val = struct_val[0]; 17040 // payload: type, 17041 const payload_val = struct_val[1]; 17042 17043 var buffer: Value.ToTypeBuffer = undefined; 17044 const error_set_ty = try error_set_val.toType(&buffer).copy(sema.arena); 17045 const payload_ty = try payload_val.toType(&buffer).copy(sema.arena); 17046 17047 if (error_set_ty.zigTypeTag() != .ErrorSet) { 17048 return sema.fail(block, src, "Type.ErrorUnion.error_set must be an error set type", .{}); 17049 } 17050 17051 const ty = try Type.Tag.error_union.create(sema.arena, .{ 17052 .error_set = error_set_ty, 17053 .payload = payload_ty, 17054 }); 17055 return sema.addType(ty); 17056 }, 17057 .ErrorSet => { 17058 const payload_val = union_val.val.optionalValue() orelse 17059 return sema.addType(Type.initTag(.anyerror)); 17060 const slice_val = payload_val.castTag(.slice).?.data; 17061 17062 const len = try sema.usizeCast(block, src, slice_val.len.toUnsignedInt(mod.getTarget())); 17063 var names: Module.ErrorSet.NameMap = .{}; 17064 try names.ensureUnusedCapacity(sema.arena, len); 17065 var i: usize = 0; 17066 while (i < len) : (i += 1) { 17067 var buf: Value.ElemValueBuffer = undefined; 17068 const elem_val = slice_val.ptr.elemValueBuffer(mod, i, &buf); 17069 const struct_val = elem_val.castTag(.aggregate).?.data; 17070 // TODO use reflection instead of magic numbers here 17071 // error_set: type, 17072 const name_val = struct_val[0]; 17073 const name_str = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, sema.mod); 17074 17075 const kv = try mod.getErrorValue(name_str); 17076 const gop = names.getOrPutAssumeCapacity(kv.key); 17077 if (gop.found_existing) { 17078 return sema.fail(block, src, "duplicate error '{s}'", .{name_str}); 17079 } 17080 } 17081 17082 // names must be sorted 17083 Module.ErrorSet.sortNames(&names); 17084 const ty = try Type.Tag.error_set_merged.create(sema.arena, names); 17085 return sema.addType(ty); 17086 }, 17087 .Struct => { 17088 // TODO use reflection instead of magic numbers here 17089 const struct_val = union_val.val.castTag(.aggregate).?.data; 17090 // layout: containerlayout, 17091 const layout_val = struct_val[0]; 17092 // backing_int: ?type, 17093 const backing_int_val = struct_val[1]; 17094 // fields: []const enumfield, 17095 const fields_val = struct_val[2]; 17096 // decls: []const declaration, 17097 const decls_val = struct_val[3]; 17098 // is_tuple: bool, 17099 const is_tuple_val = struct_val[4]; 17100 assert(struct_val.len == 5); 17101 17102 const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout); 17103 17104 // Decls 17105 if (decls_val.sliceLen(mod) > 0) { 17106 return sema.fail(block, src, "reified structs must have no decls", .{}); 17107 } 17108 17109 if (layout != .Packed and !backing_int_val.isNull()) { 17110 return sema.fail(block, src, "non-packed struct does not support backing integer type", .{}); 17111 } 17112 17113 return if (is_tuple_val.toBool()) 17114 try sema.reifyTuple(block, src, fields_val) 17115 else 17116 try sema.reifyStruct(block, inst, src, layout, backing_int_val, fields_val, name_strategy); 17117 }, 17118 .Enum => { 17119 const struct_val: []const Value = union_val.val.castTag(.aggregate).?.data; 17120 // TODO use reflection instead of magic numbers here 17121 // layout: ContainerLayout, 17122 const layout_val = struct_val[0]; 17123 // tag_type: type, 17124 const tag_type_val = struct_val[1]; 17125 // fields: []const EnumField, 17126 const fields_val = struct_val[2]; 17127 // decls: []const Declaration, 17128 const decls_val = struct_val[3]; 17129 // is_exhaustive: bool, 17130 const is_exhaustive_val = struct_val[4]; 17131 17132 // enum layout is always auto 17133 const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout); 17134 if (layout != .Auto) { 17135 return sema.fail(block, src, "reified enums must have a layout .Auto", .{}); 17136 } 17137 17138 // Decls 17139 if (decls_val.sliceLen(mod) > 0) { 17140 return sema.fail(block, src, "reified enums must have no decls", .{}); 17141 } 17142 17143 const gpa = sema.gpa; 17144 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 17145 errdefer new_decl_arena.deinit(); 17146 const new_decl_arena_allocator = new_decl_arena.allocator(); 17147 17148 // Define our empty enum decl 17149 const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull); 17150 const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumFull); 17151 enum_ty_payload.* = .{ 17152 .base = .{ 17153 .tag = if (!is_exhaustive_val.toBool()) 17154 .enum_nonexhaustive 17155 else 17156 .enum_full, 17157 }, 17158 .data = enum_obj, 17159 }; 17160 const enum_ty = Type.initPayload(&enum_ty_payload.base); 17161 const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); 17162 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 17163 .ty = Type.type, 17164 .val = enum_val, 17165 }, name_strategy, "enum", inst); 17166 const new_decl = mod.declPtr(new_decl_index); 17167 new_decl.owns_tv = true; 17168 errdefer mod.abortAnonDecl(new_decl_index); 17169 17170 enum_obj.* = .{ 17171 .owner_decl = new_decl_index, 17172 .tag_ty = Type.@"null", 17173 .tag_ty_inferred = false, 17174 .fields = .{}, 17175 .values = .{}, 17176 .namespace = .{ 17177 .parent = block.namespace, 17178 .ty = enum_ty, 17179 .file_scope = block.getFileScope(), 17180 }, 17181 }; 17182 17183 // Enum tag type 17184 var buffer: Value.ToTypeBuffer = undefined; 17185 const int_tag_ty = try tag_type_val.toType(&buffer).copy(new_decl_arena_allocator); 17186 17187 if (int_tag_ty.zigTypeTag() != .Int) { 17188 return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{}); 17189 } 17190 enum_obj.tag_ty = int_tag_ty; 17191 17192 // Fields 17193 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); 17194 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); 17195 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{ 17196 .ty = enum_obj.tag_ty, 17197 .mod = mod, 17198 }); 17199 17200 var i: usize = 0; 17201 while (i < fields_len) : (i += 1) { 17202 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); 17203 const field_struct_val: []const Value = elem_val.castTag(.aggregate).?.data; 17204 // TODO use reflection instead of magic numbers here 17205 // name: []const u8 17206 const name_val = field_struct_val[0]; 17207 // value: comptime_int 17208 const value_val = field_struct_val[1]; 17209 17210 const field_name = try name_val.toAllocatedBytes( 17211 Type.initTag(.const_slice_u8), 17212 new_decl_arena_allocator, 17213 sema.mod, 17214 ); 17215 17216 if (!try sema.intFitsInType(block, src, value_val, enum_obj.tag_ty, null)) { 17217 // TODO: better source location 17218 return sema.fail(block, src, "field '{s}' with enumeration value '{}' is too large for backing int type '{}'", .{ 17219 field_name, 17220 value_val.fmtValue(Type.@"comptime_int", mod), 17221 enum_obj.tag_ty.fmt(mod), 17222 }); 17223 } 17224 17225 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name); 17226 if (gop.found_existing) { 17227 // TODO: better source location 17228 return sema.fail(block, src, "duplicate enum tag {s}", .{field_name}); 17229 } 17230 17231 const copied_tag_val = try value_val.copy(new_decl_arena_allocator); 17232 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{ 17233 .ty = enum_obj.tag_ty, 17234 .mod = mod, 17235 }); 17236 } 17237 17238 try new_decl.finalizeNewArena(&new_decl_arena); 17239 return sema.analyzeDeclVal(block, src, new_decl_index); 17240 }, 17241 .Opaque => { 17242 const struct_val = union_val.val.castTag(.aggregate).?.data; 17243 // decls: []const Declaration, 17244 const decls_val = struct_val[0]; 17245 17246 // Decls 17247 if (decls_val.sliceLen(mod) > 0) { 17248 return sema.fail(block, src, "reified opaque must have no decls", .{}); 17249 } 17250 17251 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); 17252 errdefer new_decl_arena.deinit(); 17253 const new_decl_arena_allocator = new_decl_arena.allocator(); 17254 17255 const opaque_obj = try new_decl_arena_allocator.create(Module.Opaque); 17256 const opaque_ty_payload = try new_decl_arena_allocator.create(Type.Payload.Opaque); 17257 opaque_ty_payload.* = .{ 17258 .base = .{ .tag = .@"opaque" }, 17259 .data = opaque_obj, 17260 }; 17261 const opaque_ty = Type.initPayload(&opaque_ty_payload.base); 17262 const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty); 17263 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 17264 .ty = Type.type, 17265 .val = opaque_val, 17266 }, name_strategy, "opaque", inst); 17267 const new_decl = mod.declPtr(new_decl_index); 17268 new_decl.owns_tv = true; 17269 errdefer mod.abortAnonDecl(new_decl_index); 17270 17271 opaque_obj.* = .{ 17272 .owner_decl = new_decl_index, 17273 .namespace = .{ 17274 .parent = block.namespace, 17275 .ty = opaque_ty, 17276 .file_scope = block.getFileScope(), 17277 }, 17278 }; 17279 17280 try new_decl.finalizeNewArena(&new_decl_arena); 17281 return sema.analyzeDeclVal(block, src, new_decl_index); 17282 }, 17283 .Union => { 17284 // TODO use reflection instead of magic numbers here 17285 const struct_val = union_val.val.castTag(.aggregate).?.data; 17286 // layout: containerlayout, 17287 const layout_val = struct_val[0]; 17288 // tag_type: ?type, 17289 const tag_type_val = struct_val[1]; 17290 // fields: []const enumfield, 17291 const fields_val = struct_val[2]; 17292 // decls: []const declaration, 17293 const decls_val = struct_val[3]; 17294 17295 // Decls 17296 if (decls_val.sliceLen(mod) > 0) { 17297 return sema.fail(block, src, "reified unions must have no decls", .{}); 17298 } 17299 const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout); 17300 17301 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); 17302 errdefer new_decl_arena.deinit(); 17303 const new_decl_arena_allocator = new_decl_arena.allocator(); 17304 17305 const union_obj = try new_decl_arena_allocator.create(Module.Union); 17306 const type_tag = if (!tag_type_val.isNull()) 17307 Type.Tag.union_tagged 17308 else if (layout != .Auto) 17309 Type.Tag.@"union" 17310 else switch (block.sema.mod.optimizeMode()) { 17311 .Debug, .ReleaseSafe => Type.Tag.union_safety_tagged, 17312 .ReleaseFast, .ReleaseSmall => Type.Tag.@"union", 17313 }; 17314 const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union); 17315 union_payload.* = .{ 17316 .base = .{ .tag = type_tag }, 17317 .data = union_obj, 17318 }; 17319 const union_ty = Type.initPayload(&union_payload.base); 17320 const new_union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty); 17321 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 17322 .ty = Type.type, 17323 .val = new_union_val, 17324 }, name_strategy, "union", inst); 17325 const new_decl = mod.declPtr(new_decl_index); 17326 new_decl.owns_tv = true; 17327 errdefer mod.abortAnonDecl(new_decl_index); 17328 union_obj.* = .{ 17329 .owner_decl = new_decl_index, 17330 .tag_ty = Type.initTag(.@"null"), 17331 .fields = .{}, 17332 .zir_index = inst, 17333 .layout = layout, 17334 .status = .have_field_types, 17335 .namespace = .{ 17336 .parent = block.namespace, 17337 .ty = union_ty, 17338 .file_scope = block.getFileScope(), 17339 }, 17340 }; 17341 17342 // Tag type 17343 var tag_ty_field_names: ?Module.EnumFull.NameMap = null; 17344 var enum_field_names: ?*Module.EnumNumbered.NameMap = null; 17345 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); 17346 if (tag_type_val.optionalValue()) |payload_val| { 17347 var buffer: Value.ToTypeBuffer = undefined; 17348 union_obj.tag_ty = try payload_val.toType(&buffer).copy(new_decl_arena_allocator); 17349 17350 if (union_obj.tag_ty.zigTypeTag() != .Enum) { 17351 return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}); 17352 } 17353 tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena); 17354 } else { 17355 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, fields_len, null); 17356 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields; 17357 } 17358 17359 // Fields 17360 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); 17361 17362 var i: usize = 0; 17363 while (i < fields_len) : (i += 1) { 17364 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); 17365 const field_struct_val = elem_val.castTag(.aggregate).?.data; 17366 // TODO use reflection instead of magic numbers here 17367 // name: []const u8 17368 const name_val = field_struct_val[0]; 17369 // field_type: type, 17370 const field_type_val = field_struct_val[1]; 17371 // alignment: comptime_int, 17372 const alignment_val = field_struct_val[2]; 17373 17374 const field_name = try name_val.toAllocatedBytes( 17375 Type.initTag(.const_slice_u8), 17376 new_decl_arena_allocator, 17377 sema.mod, 17378 ); 17379 17380 if (enum_field_names) |set| { 17381 set.putAssumeCapacity(field_name, {}); 17382 } 17383 17384 if (tag_ty_field_names) |*names| { 17385 const enum_has_field = names.orderedRemove(field_name); 17386 if (!enum_has_field) { 17387 const msg = msg: { 17388 const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) }); 17389 errdefer msg.destroy(sema.gpa); 17390 try sema.addDeclaredHereNote(msg, union_obj.tag_ty); 17391 break :msg msg; 17392 }; 17393 return sema.failWithOwnedErrorMsg(msg); 17394 } 17395 } 17396 17397 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); 17398 if (gop.found_existing) { 17399 // TODO: better source location 17400 return sema.fail(block, src, "duplicate union field {s}", .{field_name}); 17401 } 17402 17403 var buffer: Value.ToTypeBuffer = undefined; 17404 gop.value_ptr.* = .{ 17405 .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator), 17406 .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)), 17407 }; 17408 } 17409 17410 if (tag_ty_field_names) |names| { 17411 if (names.count() > 0) { 17412 const msg = msg: { 17413 const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{}); 17414 errdefer msg.destroy(sema.gpa); 17415 17416 const enum_ty = union_obj.tag_ty; 17417 for (names.keys()) |field_name| { 17418 const field_index = enum_ty.enumFieldIndex(field_name).?; 17419 try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name}); 17420 } 17421 try sema.addDeclaredHereNote(msg, union_obj.tag_ty); 17422 break :msg msg; 17423 }; 17424 return sema.failWithOwnedErrorMsg(msg); 17425 } 17426 } 17427 17428 try new_decl.finalizeNewArena(&new_decl_arena); 17429 return sema.analyzeDeclVal(block, src, new_decl_index); 17430 }, 17431 .Fn => { 17432 const struct_val = union_val.val.castTag(.aggregate).?.data; 17433 // TODO use reflection instead of magic numbers here 17434 // calling_convention: CallingConvention, 17435 const cc = struct_val[0].toEnum(std.builtin.CallingConvention); 17436 // alignment: comptime_int, 17437 const alignment_val = struct_val[1]; 17438 // is_generic: bool, 17439 const is_generic = struct_val[2].toBool(); 17440 // is_var_args: bool, 17441 const is_var_args = struct_val[3].toBool(); 17442 // return_type: ?type, 17443 const return_type_val = struct_val[4]; 17444 // args: []const Param, 17445 const args_val = struct_val[5]; 17446 17447 if (is_generic) { 17448 return sema.fail(block, src, "Type.Fn.is_generic must be false for @Type", .{}); 17449 } 17450 17451 if (is_var_args and cc != .C) { 17452 return sema.fail(block, src, "varargs functions must have C calling convention", .{}); 17453 } 17454 17455 const alignment = alignment: { 17456 if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) { 17457 return sema.fail(block, src, "alignment must fit in 'u32'", .{}); 17458 } 17459 const alignment = @intCast(u29, alignment_val.toUnsignedInt(target)); 17460 if (alignment == target_util.defaultFunctionAlignment(target)) { 17461 break :alignment 0; 17462 } else { 17463 break :alignment alignment; 17464 } 17465 }; 17466 var buf: Value.ToTypeBuffer = undefined; 17467 17468 const args_slice_val = args_val.castTag(.slice).?.data; 17469 const args_len = try sema.usizeCast(block, src, args_slice_val.len.toUnsignedInt(mod.getTarget())); 17470 var param_types = try sema.arena.alloc(Type, args_len); 17471 var comptime_params = try sema.arena.alloc(bool, args_len); 17472 var noalias_bits: u32 = 0; 17473 var i: usize = 0; 17474 while (i < args_len) : (i += 1) { 17475 var arg_buf: Value.ElemValueBuffer = undefined; 17476 const arg = args_slice_val.ptr.elemValueBuffer(mod, i, &arg_buf); 17477 const arg_val = arg.castTag(.aggregate).?.data; 17478 // TODO use reflection instead of magic numbers here 17479 // is_generic: bool, 17480 const arg_is_generic = arg_val[0].toBool(); 17481 // is_noalias: bool, 17482 const arg_is_noalias = arg_val[1].toBool(); 17483 // arg_type: ?type, 17484 const param_type_val = arg_val[2]; 17485 17486 if (arg_is_generic) { 17487 return sema.fail(block, src, "Type.Fn.Param.is_generic must be false for @Type", .{}); 17488 } 17489 17490 if (arg_is_noalias) { 17491 noalias_bits = @as(u32, 1) << (std.math.cast(u5, i) orelse 17492 return sema.fail(block, src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{})); 17493 } 17494 17495 const param_type = param_type_val.optionalValue() orelse 17496 return sema.fail(block, src, "Type.Fn.Param.arg_type must be non-null for @Type", .{}); 17497 17498 param_types[i] = try param_type.toType(&buf).copy(sema.arena); 17499 } 17500 17501 const return_type = return_type_val.optionalValue() orelse 17502 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); 17503 17504 var fn_info = Type.Payload.Function.Data{ 17505 .param_types = param_types, 17506 .comptime_params = comptime_params.ptr, 17507 .noalias_bits = noalias_bits, 17508 .return_type = try return_type.toType(&buf).copy(sema.arena), 17509 .alignment = alignment, 17510 .cc = cc, 17511 .is_var_args = is_var_args, 17512 .is_generic = false, 17513 .align_is_generic = false, 17514 .cc_is_generic = false, 17515 .section_is_generic = false, 17516 .addrspace_is_generic = false, 17517 }; 17518 17519 const ty = try Type.Tag.function.create(sema.arena, fn_info); 17520 return sema.addType(ty); 17521 }, 17522 .BoundFn => @panic("TODO delete BoundFn from the language"), 17523 .Frame => return sema.failWithUseOfAsync(block, src), 17524 } 17525 } 17526 17527 fn reifyTuple( 17528 sema: *Sema, 17529 block: *Block, 17530 src: LazySrcLoc, 17531 fields_val: Value, 17532 ) CompileError!Air.Inst.Ref { 17533 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(sema.mod)); 17534 if (fields_len == 0) return sema.addType(Type.initTag(.empty_struct_literal)); 17535 17536 const types = try sema.arena.alloc(Type, fields_len); 17537 const values = try sema.arena.alloc(Value, fields_len); 17538 17539 var used_fields: std.AutoArrayHashMapUnmanaged(u32, void) = .{}; 17540 defer used_fields.deinit(sema.gpa); 17541 try used_fields.ensureTotalCapacity(sema.gpa, fields_len); 17542 17543 var i: usize = 0; 17544 while (i < fields_len) : (i += 1) { 17545 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); 17546 const field_struct_val = elem_val.castTag(.aggregate).?.data; 17547 // TODO use reflection instead of magic numbers here 17548 // name: []const u8 17549 const name_val = field_struct_val[0]; 17550 // field_type: type, 17551 const field_type_val = field_struct_val[1]; 17552 //default_value: ?*const anyopaque, 17553 const default_value_val = field_struct_val[2]; 17554 17555 const field_name = try name_val.toAllocatedBytes( 17556 Type.initTag(.const_slice_u8), 17557 sema.arena, 17558 sema.mod, 17559 ); 17560 17561 const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch |err| { 17562 return sema.fail( 17563 block, 17564 src, 17565 "tuple cannot have non-numeric field '{s}': {}", 17566 .{ field_name, err }, 17567 ); 17568 }; 17569 17570 if (field_index >= fields_len) { 17571 return sema.fail( 17572 block, 17573 src, 17574 "tuple field {} exceeds tuple field count", 17575 .{field_index}, 17576 ); 17577 } 17578 17579 const gop = used_fields.getOrPutAssumeCapacity(field_index); 17580 if (gop.found_existing) { 17581 // TODO: better source location 17582 return sema.fail(block, src, "duplicate tuple field {}", .{field_index}); 17583 } 17584 17585 const default_val = if (default_value_val.optionalValue()) |opt_val| blk: { 17586 const payload_val = if (opt_val.pointerDecl()) |opt_decl| 17587 sema.mod.declPtr(opt_decl).val 17588 else 17589 opt_val; 17590 break :blk try payload_val.copy(sema.arena); 17591 } else Value.initTag(.unreachable_value); 17592 17593 var buffer: Value.ToTypeBuffer = undefined; 17594 types[field_index] = try field_type_val.toType(&buffer).copy(sema.arena); 17595 values[field_index] = default_val; 17596 } 17597 17598 const ty = try Type.Tag.tuple.create(sema.arena, .{ 17599 .types = types, 17600 .values = values, 17601 }); 17602 return sema.addType(ty); 17603 } 17604 17605 fn reifyStruct( 17606 sema: *Sema, 17607 block: *Block, 17608 inst: Zir.Inst.Index, 17609 src: LazySrcLoc, 17610 layout: std.builtin.Type.ContainerLayout, 17611 backing_int_val: Value, 17612 fields_val: Value, 17613 name_strategy: Zir.Inst.NameStrategy, 17614 ) CompileError!Air.Inst.Ref { 17615 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); 17616 errdefer new_decl_arena.deinit(); 17617 const new_decl_arena_allocator = new_decl_arena.allocator(); 17618 17619 const struct_obj = try new_decl_arena_allocator.create(Module.Struct); 17620 const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); 17621 const new_struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); 17622 const mod = sema.mod; 17623 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ 17624 .ty = Type.type, 17625 .val = new_struct_val, 17626 }, name_strategy, "struct", inst); 17627 const new_decl = mod.declPtr(new_decl_index); 17628 new_decl.owns_tv = true; 17629 errdefer mod.abortAnonDecl(new_decl_index); 17630 struct_obj.* = .{ 17631 .owner_decl = new_decl_index, 17632 .fields = .{}, 17633 .zir_index = inst, 17634 .layout = layout, 17635 .status = .have_field_types, 17636 .known_non_opv = false, 17637 .namespace = .{ 17638 .parent = block.namespace, 17639 .ty = struct_ty, 17640 .file_scope = block.getFileScope(), 17641 }, 17642 }; 17643 17644 const target = mod.getTarget(); 17645 17646 // Fields 17647 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); 17648 try struct_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); 17649 var i: usize = 0; 17650 while (i < fields_len) : (i += 1) { 17651 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); 17652 const field_struct_val = elem_val.castTag(.aggregate).?.data; 17653 // TODO use reflection instead of magic numbers here 17654 // name: []const u8 17655 const name_val = field_struct_val[0]; 17656 // field_type: type, 17657 const field_type_val = field_struct_val[1]; 17658 //default_value: ?*const anyopaque, 17659 const default_value_val = field_struct_val[2]; 17660 // is_comptime: bool, 17661 const is_comptime_val = field_struct_val[3]; 17662 // alignment: comptime_int, 17663 const alignment_val = field_struct_val[4]; 17664 17665 if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) { 17666 return sema.fail(block, src, "alignment must fit in 'u32'", .{}); 17667 } 17668 const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?); 17669 17670 const field_name = try name_val.toAllocatedBytes( 17671 Type.initTag(.const_slice_u8), 17672 new_decl_arena_allocator, 17673 mod, 17674 ); 17675 17676 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); 17677 if (gop.found_existing) { 17678 // TODO: better source location 17679 return sema.fail(block, src, "duplicate struct field {s}", .{field_name}); 17680 } 17681 17682 const default_val = if (default_value_val.optionalValue()) |opt_val| blk: { 17683 const payload_val = if (opt_val.pointerDecl()) |opt_decl| 17684 mod.declPtr(opt_decl).val 17685 else 17686 opt_val; 17687 break :blk try payload_val.copy(new_decl_arena_allocator); 17688 } else Value.initTag(.unreachable_value); 17689 17690 var buffer: Value.ToTypeBuffer = undefined; 17691 gop.value_ptr.* = .{ 17692 .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator), 17693 .abi_align = abi_align, 17694 .default_val = default_val, 17695 .is_comptime = is_comptime_val.toBool(), 17696 .offset = undefined, 17697 }; 17698 } 17699 17700 if (layout == .Packed) { 17701 struct_obj.status = .layout_wip; 17702 17703 for (struct_obj.fields.values()) |field, index| { 17704 sema.resolveTypeLayout(block, src, field.ty) catch |err| switch (err) { 17705 error.AnalysisFail => { 17706 const msg = sema.err orelse return err; 17707 try sema.addFieldErrNote(struct_ty, index, msg, "while checking this field", .{}); 17708 return err; 17709 }, 17710 else => return err, 17711 }; 17712 } 17713 17714 var fields_bit_sum: u64 = 0; 17715 for (struct_obj.fields.values()) |field| { 17716 fields_bit_sum += field.ty.bitSize(target); 17717 } 17718 17719 if (backing_int_val.optionalValue()) |payload| { 17720 var buf: Value.ToTypeBuffer = undefined; 17721 const backing_int_ty = payload.toType(&buf); 17722 try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum); 17723 struct_obj.backing_int_ty = try backing_int_ty.copy(new_decl_arena_allocator); 17724 } else { 17725 var buf: Type.Payload.Bits = .{ 17726 .base = .{ .tag = .int_unsigned }, 17727 .data = @intCast(u16, fields_bit_sum), 17728 }; 17729 struct_obj.backing_int_ty = try Type.initPayload(&buf.base).copy(new_decl_arena_allocator); 17730 } 17731 17732 struct_obj.status = .have_layout; 17733 } 17734 17735 try new_decl.finalizeNewArena(&new_decl_arena); 17736 return sema.analyzeDeclVal(block, src, new_decl_index); 17737 } 17738 17739 fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17740 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 17741 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 17742 const ty = try sema.resolveType(block, ty_src, inst_data.operand); 17743 17744 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded); 17745 defer anon_decl.deinit(); 17746 17747 const bytes = try ty.nameAllocArena(anon_decl.arena(), sema.mod); 17748 17749 const new_decl = try anon_decl.finish( 17750 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), 17751 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), 17752 0, // default alignment 17753 ); 17754 17755 return sema.analyzeDeclRef(new_decl); 17756 } 17757 17758 fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17759 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 17760 const src = inst_data.src(); 17761 return sema.failWithUseOfAsync(block, src); 17762 } 17763 17764 fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17765 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 17766 const src = inst_data.src(); 17767 return sema.failWithUseOfAsync(block, src); 17768 } 17769 17770 fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17771 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 17772 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 17773 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 17774 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 17775 const dest_ty = try sema.resolveType(block, ty_src, extra.lhs); 17776 const operand = try sema.resolveInst(extra.rhs); 17777 const operand_ty = sema.typeOf(operand); 17778 17779 _ = try sema.checkIntType(block, ty_src, dest_ty); 17780 try sema.checkFloatType(block, operand_src, operand_ty); 17781 17782 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { 17783 const result_val = try sema.floatToInt(block, operand_src, val, operand_ty, dest_ty); 17784 return sema.addConstant(dest_ty, result_val); 17785 } else if (dest_ty.zigTypeTag() == .ComptimeInt) { 17786 return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_int' must be comptime known"); 17787 } 17788 17789 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); 17790 const result = try block.addTyOp(if (block.float_mode == .Optimized) .float_to_int_optimized else .float_to_int, dest_ty, operand); 17791 if (block.wantSafety()) { 17792 const back = try block.addTyOp(.int_to_float, operand_ty, result); 17793 const diff = try block.addBinOp(.sub, operand, back); 17794 const ok_pos = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_lt_optimized else .cmp_lt, diff, try sema.addConstant(operand_ty, Value.one)); 17795 const ok_neg = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_gt_optimized else .cmp_gt, diff, try sema.addConstant(operand_ty, Value.negative_one)); 17796 const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg); 17797 try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds); 17798 } 17799 return result; 17800 } 17801 17802 fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17803 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 17804 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 17805 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 17806 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 17807 const dest_ty = try sema.resolveType(block, ty_src, extra.lhs); 17808 const operand = try sema.resolveInst(extra.rhs); 17809 const operand_ty = sema.typeOf(operand); 17810 17811 try sema.checkFloatType(block, ty_src, dest_ty); 17812 _ = try sema.checkIntType(block, operand_src, operand_ty); 17813 17814 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { 17815 const target = sema.mod.getTarget(); 17816 const result_val = try val.intToFloatAdvanced(sema.arena, operand_ty, dest_ty, target, sema.kit(block, operand_src)); 17817 return sema.addConstant(dest_ty, result_val); 17818 } else if (dest_ty.zigTypeTag() == .ComptimeFloat) { 17819 return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_float' must be comptime known"); 17820 } 17821 17822 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); 17823 return block.addTyOp(.int_to_float, dest_ty, operand); 17824 } 17825 17826 fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17827 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 17828 const src = inst_data.src(); 17829 17830 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 17831 17832 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 17833 const operand_res = try sema.resolveInst(extra.rhs); 17834 const operand_coerced = try sema.coerce(block, Type.usize, operand_res, operand_src); 17835 17836 const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 17837 const ptr_ty = try sema.resolveType(block, src, extra.lhs); 17838 const elem_ty = ptr_ty.elemType2(); 17839 try sema.checkPtrType(block, type_src, ptr_ty); 17840 const target = sema.mod.getTarget(); 17841 const ptr_align = try ptr_ty.ptrAlignmentAdvanced(target, sema.kit(block, src)); 17842 17843 if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| { 17844 const addr = val.toUnsignedInt(target); 17845 if (!ptr_ty.isAllowzeroPtr() and addr == 0) 17846 return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)}); 17847 if (addr != 0 and addr % ptr_align != 0) 17848 return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)}); 17849 17850 const val_payload = try sema.arena.create(Value.Payload.U64); 17851 val_payload.* = .{ 17852 .base = .{ .tag = .int_u64 }, 17853 .data = addr, 17854 }; 17855 return sema.addConstant(ptr_ty, Value.initPayload(&val_payload.base)); 17856 } 17857 17858 try sema.requireRuntimeBlock(block, src, operand_src); 17859 if (block.wantSafety() and try sema.typeHasRuntimeBits(block, sema.src, elem_ty)) { 17860 if (!ptr_ty.isAllowzeroPtr()) { 17861 const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize); 17862 try sema.addSafetyCheck(block, is_non_zero, .cast_to_null); 17863 } 17864 17865 if (ptr_align > 1) { 17866 const val_payload = try sema.arena.create(Value.Payload.U64); 17867 val_payload.* = .{ 17868 .base = .{ .tag = .int_u64 }, 17869 .data = ptr_align - 1, 17870 }; 17871 const align_minus_1 = try sema.addConstant( 17872 Type.usize, 17873 Value.initPayload(&val_payload.base), 17874 ); 17875 const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1); 17876 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); 17877 try sema.addSafetyCheck(block, is_aligned, .incorrect_alignment); 17878 } 17879 } 17880 return block.addBitCast(ptr_ty, operand_coerced); 17881 } 17882 17883 fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 17884 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; 17885 const src = LazySrcLoc.nodeOffset(extra.node); 17886 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 17887 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 17888 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); 17889 const operand = try sema.resolveInst(extra.rhs); 17890 const operand_ty = sema.typeOf(operand); 17891 try sema.checkErrorSetType(block, dest_ty_src, dest_ty); 17892 try sema.checkErrorSetType(block, operand_src, operand_ty); 17893 17894 // operand must be defined since it can be an invalid error value 17895 const maybe_operand_val = try sema.resolveDefinedValue(block, operand_src, operand); 17896 17897 if (disjoint: { 17898 // Try avoiding resolving inferred error sets if we can 17899 if (!dest_ty.isAnyError() and dest_ty.errorSetNames().len == 0) break :disjoint true; 17900 if (!operand_ty.isAnyError() and operand_ty.errorSetNames().len == 0) break :disjoint true; 17901 if (dest_ty.isAnyError()) break :disjoint false; 17902 if (operand_ty.isAnyError()) break :disjoint false; 17903 for (dest_ty.errorSetNames()) |dest_err_name| 17904 if (operand_ty.errorSetHasField(dest_err_name)) 17905 break :disjoint false; 17906 17907 if (dest_ty.tag() != .error_set_inferred and operand_ty.tag() != .error_set_inferred) 17908 break :disjoint true; 17909 17910 try sema.resolveInferredErrorSetTy(block, dest_ty_src, dest_ty); 17911 try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty); 17912 for (dest_ty.errorSetNames()) |dest_err_name| 17913 if (operand_ty.errorSetHasField(dest_err_name)) 17914 break :disjoint false; 17915 17916 break :disjoint true; 17917 }) { 17918 const msg = msg: { 17919 const msg = try sema.errMsg( 17920 block, 17921 src, 17922 "error sets '{}' and '{}' have no common errors", 17923 .{ operand_ty.fmt(sema.mod), dest_ty.fmt(sema.mod) }, 17924 ); 17925 errdefer msg.destroy(sema.gpa); 17926 try sema.addDeclaredHereNote(msg, operand_ty); 17927 try sema.addDeclaredHereNote(msg, dest_ty); 17928 break :msg msg; 17929 }; 17930 return sema.failWithOwnedErrorMsg(msg); 17931 } 17932 17933 if (maybe_operand_val) |val| { 17934 if (!dest_ty.isAnyError()) { 17935 const error_name = val.castTag(.@"error").?.data.name; 17936 if (!dest_ty.errorSetHasField(error_name)) { 17937 const msg = msg: { 17938 const msg = try sema.errMsg( 17939 block, 17940 src, 17941 "'error.{s}' not a member of error set '{}'", 17942 .{ error_name, dest_ty.fmt(sema.mod) }, 17943 ); 17944 errdefer msg.destroy(sema.gpa); 17945 try sema.addDeclaredHereNote(msg, dest_ty); 17946 break :msg msg; 17947 }; 17948 return sema.failWithOwnedErrorMsg(msg); 17949 } 17950 } 17951 17952 return sema.addConstant(dest_ty, val); 17953 } 17954 17955 try sema.requireRuntimeBlock(block, src, operand_src); 17956 if (block.wantSafety() and !dest_ty.isAnyError() and sema.mod.comp.bin_file.options.use_llvm) { 17957 const err_int_inst = try block.addBitCast(Type.err_int, operand); 17958 const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst); 17959 try sema.addSafetyCheck(block, ok, .invalid_error_code); 17960 } 17961 return block.addBitCast(dest_ty, operand); 17962 } 17963 17964 fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 17965 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 17966 const src = inst_data.src(); 17967 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 17968 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 17969 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 17970 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); 17971 const operand = try sema.resolveInst(extra.rhs); 17972 const operand_ty = sema.typeOf(operand); 17973 const target = sema.mod.getTarget(); 17974 17975 try sema.checkPtrType(block, dest_ty_src, dest_ty); 17976 try sema.checkPtrOperand(block, operand_src, operand_ty); 17977 17978 const operand_info = operand_ty.ptrInfo().data; 17979 const dest_info = dest_ty.ptrInfo().data; 17980 if (!operand_info.mutable and dest_info.mutable) { 17981 return sema.fail(block, src, "cast discards const qualifier", .{}); 17982 } 17983 if (operand_info.@"volatile" and !dest_info.@"volatile") { 17984 return sema.fail(block, src, "cast discards volatile qualifier", .{}); 17985 } 17986 17987 const dest_is_slice = dest_ty.isSlice(); 17988 const operand_is_slice = operand_ty.isSlice(); 17989 if (dest_is_slice and !operand_is_slice) { 17990 return sema.fail(block, dest_ty_src, "illegal pointer cast to slice", .{}); 17991 } 17992 const ptr = if (operand_is_slice and !dest_is_slice) 17993 try sema.analyzeSlicePtr(block, operand_src, operand, operand_ty) 17994 else 17995 operand; 17996 17997 const dest_elem_ty = dest_ty.elemType2(); 17998 try sema.resolveTypeLayout(block, dest_ty_src, dest_elem_ty); 17999 const dest_align = dest_ty.ptrAlignment(target); 18000 18001 const operand_elem_ty = operand_ty.elemType2(); 18002 try sema.resolveTypeLayout(block, operand_src, operand_elem_ty); 18003 const operand_align = operand_ty.ptrAlignment(target); 18004 18005 // If the destination is less aligned than the source, preserve the source alignment 18006 const aligned_dest_ty = if (operand_align <= dest_align) dest_ty else blk: { 18007 // Unwrap the pointer (or pointer-like optional) type, set alignment, and re-wrap into result 18008 if (dest_ty.zigTypeTag() == .Optional) { 18009 var buf: Type.Payload.ElemType = undefined; 18010 var dest_ptr_info = dest_ty.optionalChild(&buf).ptrInfo().data; 18011 dest_ptr_info.@"align" = operand_align; 18012 break :blk try Type.optional(sema.arena, try Type.ptr(sema.arena, sema.mod, dest_ptr_info)); 18013 } else { 18014 var dest_ptr_info = dest_ty.ptrInfo().data; 18015 dest_ptr_info.@"align" = operand_align; 18016 break :blk try Type.ptr(sema.arena, sema.mod, dest_ptr_info); 18017 } 18018 }; 18019 18020 if (dest_is_slice) { 18021 const operand_elem_size = operand_elem_ty.abiSize(target); 18022 const dest_elem_size = dest_elem_ty.abiSize(target); 18023 if (operand_elem_size != dest_elem_size) { 18024 // note that this is not implemented in stage1 so we should probably wait 18025 // until that codebase is replaced before implementing this in stage2. 18026 return sema.fail(block, dest_ty_src, "TODO: implement @ptrCast between slices changing the length", .{}); 18027 } 18028 } 18029 18030 if (dest_align > operand_align) { 18031 const msg = msg: { 18032 const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{}); 18033 errdefer msg.destroy(sema.gpa); 18034 18035 try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{ 18036 operand_ty.fmt(sema.mod), operand_align, 18037 }); 18038 try sema.errNote(block, dest_ty_src, msg, "'{}' has alignment '{d}'", .{ 18039 dest_ty.fmt(sema.mod), dest_align, 18040 }); 18041 break :msg msg; 18042 }; 18043 return sema.failWithOwnedErrorMsg(msg); 18044 } 18045 18046 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| { 18047 if (!dest_ty.ptrAllowsZero() and operand_val.isUndef()) { 18048 return sema.failWithUseOfUndef(block, operand_src); 18049 } 18050 if (!dest_ty.ptrAllowsZero() and operand_val.isNull()) { 18051 return sema.fail(block, operand_src, "null pointer casted to type {}", .{dest_ty.fmt(sema.mod)}); 18052 } 18053 return sema.addConstant(aligned_dest_ty, operand_val); 18054 } 18055 18056 try sema.requireRuntimeBlock(block, src, null); 18057 if (block.wantSafety() and operand_ty.ptrAllowsZero() and !dest_ty.ptrAllowsZero() and 18058 try sema.typeHasRuntimeBits(block, sema.src, dest_ty.elemType2())) 18059 { 18060 const ptr_int = try block.addUnOp(.ptrtoint, ptr); 18061 const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize); 18062 const ok = if (operand_is_slice) ok: { 18063 const len = try sema.analyzeSliceLen(block, operand_src, operand); 18064 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); 18065 break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero); 18066 } else is_non_zero; 18067 try sema.addSafetyCheck(block, ok, .cast_to_null); 18068 } 18069 18070 return block.addBitCast(aligned_dest_ty, ptr); 18071 } 18072 18073 fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 18074 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 18075 const src = inst_data.src(); 18076 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 18077 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 18078 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 18079 const dest_scalar_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); 18080 const operand = try sema.resolveInst(extra.rhs); 18081 const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_scalar_ty); 18082 const operand_ty = sema.typeOf(operand); 18083 const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); 18084 const is_vector = operand_ty.zigTypeTag() == .Vector; 18085 const dest_ty = if (is_vector) 18086 try Type.vector(sema.arena, operand_ty.vectorLen(), dest_scalar_ty) 18087 else 18088 dest_scalar_ty; 18089 18090 if (dest_is_comptime_int) { 18091 return sema.coerce(block, dest_ty, operand, operand_src); 18092 } 18093 18094 const target = sema.mod.getTarget(); 18095 const dest_info = dest_scalar_ty.intInfo(target); 18096 18097 if (try sema.typeHasOnePossibleValue(block, dest_ty_src, dest_ty)) |val| { 18098 return sema.addConstant(dest_ty, val); 18099 } 18100 18101 if (operand_scalar_ty.zigTypeTag() != .ComptimeInt) { 18102 const operand_info = operand_ty.intInfo(target); 18103 if (try sema.typeHasOnePossibleValue(block, operand_src, operand_ty)) |val| { 18104 return sema.addConstant(operand_ty, val); 18105 } 18106 18107 if (operand_info.signedness != dest_info.signedness) { 18108 return sema.fail(block, operand_src, "expected {s} integer type, found '{}'", .{ 18109 @tagName(dest_info.signedness), operand_ty.fmt(sema.mod), 18110 }); 18111 } 18112 if (operand_info.bits < dest_info.bits) { 18113 const msg = msg: { 18114 const msg = try sema.errMsg( 18115 block, 18116 src, 18117 "destination type '{}' has more bits than source type '{}'", 18118 .{ dest_ty.fmt(sema.mod), operand_ty.fmt(sema.mod) }, 18119 ); 18120 errdefer msg.destroy(sema.gpa); 18121 try sema.errNote(block, dest_ty_src, msg, "destination type has {d} bits", .{ 18122 dest_info.bits, 18123 }); 18124 try sema.errNote(block, operand_src, msg, "operand type has {d} bits", .{ 18125 operand_info.bits, 18126 }); 18127 break :msg msg; 18128 }; 18129 return sema.failWithOwnedErrorMsg(msg); 18130 } 18131 } 18132 18133 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { 18134 if (val.isUndef()) return sema.addConstUndef(dest_ty); 18135 if (!is_vector) { 18136 return sema.addConstant( 18137 dest_ty, 18138 try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits, target), 18139 ); 18140 } 18141 var elem_buf: Value.ElemValueBuffer = undefined; 18142 const elems = try sema.arena.alloc(Value, operand_ty.vectorLen()); 18143 for (elems) |*elem, i| { 18144 const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); 18145 elem.* = try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits, target); 18146 } 18147 return sema.addConstant( 18148 dest_ty, 18149 try Value.Tag.aggregate.create(sema.arena, elems), 18150 ); 18151 } 18152 18153 try sema.requireRuntimeBlock(block, src, operand_src); 18154 return block.addTyOp(.trunc, dest_ty, operand); 18155 } 18156 18157 fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 18158 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 18159 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 18160 const align_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 18161 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 18162 const dest_align = try sema.resolveAlign(block, align_src, extra.lhs); 18163 const ptr = try sema.resolveInst(extra.rhs); 18164 const ptr_ty = sema.typeOf(ptr); 18165 18166 try sema.checkPtrOperand(block, ptr_src, ptr_ty); 18167 18168 var ptr_info = ptr_ty.ptrInfo().data; 18169 ptr_info.@"align" = dest_align; 18170 var dest_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); 18171 if (ptr_ty.zigTypeTag() == .Optional) { 18172 dest_ty = try Type.Tag.optional.create(sema.arena, dest_ty); 18173 } 18174 18175 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |val| { 18176 if (try val.getUnsignedIntAdvanced(sema.mod.getTarget(), null)) |addr| { 18177 if (addr % dest_align != 0) { 18178 return sema.fail(block, ptr_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align }); 18179 } 18180 } 18181 return sema.addConstant(dest_ty, val); 18182 } 18183 18184 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); 18185 if (block.wantSafety() and dest_align > 1 and 18186 try sema.typeHasRuntimeBits(block, sema.src, ptr_info.pointee_type)) 18187 { 18188 const val_payload = try sema.arena.create(Value.Payload.U64); 18189 val_payload.* = .{ 18190 .base = .{ .tag = .int_u64 }, 18191 .data = dest_align - 1, 18192 }; 18193 const align_minus_1 = try sema.addConstant( 18194 Type.usize, 18195 Value.initPayload(&val_payload.base), 18196 ); 18197 const actual_ptr = if (ptr_ty.isSlice()) 18198 try sema.analyzeSlicePtr(block, ptr_src, ptr, ptr_ty) 18199 else 18200 ptr; 18201 const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr); 18202 const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1); 18203 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); 18204 const ok = if (ptr_ty.isSlice()) ok: { 18205 const len = try sema.analyzeSliceLen(block, ptr_src, ptr); 18206 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); 18207 break :ok try block.addBinOp(.bit_or, len_zero, is_aligned); 18208 } else is_aligned; 18209 try sema.addSafetyCheck(block, ok, .incorrect_alignment); 18210 } 18211 return sema.bitCast(block, dest_ty, ptr, ptr_src); 18212 } 18213 18214 fn zirBitCount( 18215 sema: *Sema, 18216 block: *Block, 18217 inst: Zir.Inst.Index, 18218 air_tag: Air.Inst.Tag, 18219 comptime comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64, 18220 ) CompileError!Air.Inst.Ref { 18221 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 18222 const src = inst_data.src(); 18223 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 18224 const operand = try sema.resolveInst(inst_data.operand); 18225 const operand_ty = sema.typeOf(operand); 18226 _ = try checkIntOrVector(sema, block, operand, operand_src); 18227 const target = sema.mod.getTarget(); 18228 const bits = operand_ty.intInfo(target).bits; 18229 18230 if (try sema.typeHasOnePossibleValue(block, operand_src, operand_ty)) |val| { 18231 return sema.addConstant(operand_ty, val); 18232 } 18233 18234 const result_scalar_ty = try Type.smallestUnsignedInt(sema.arena, bits); 18235 switch (operand_ty.zigTypeTag()) { 18236 .Vector => { 18237 const vec_len = operand_ty.vectorLen(); 18238 const result_ty = try Type.vector(sema.arena, vec_len, result_scalar_ty); 18239 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { 18240 if (val.isUndef()) return sema.addConstUndef(result_ty); 18241 18242 var elem_buf: Value.ElemValueBuffer = undefined; 18243 const elems = try sema.arena.alloc(Value, vec_len); 18244 const scalar_ty = operand_ty.scalarType(); 18245 for (elems) |*elem, i| { 18246 const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); 18247 const count = comptimeOp(elem_val, scalar_ty, target); 18248 elem.* = try Value.Tag.int_u64.create(sema.arena, count); 18249 } 18250 return sema.addConstant( 18251 result_ty, 18252 try Value.Tag.aggregate.create(sema.arena, elems), 18253 ); 18254 } else { 18255 try sema.requireRuntimeBlock(block, src, operand_src); 18256 return block.addTyOp(air_tag, result_ty, operand); 18257 } 18258 }, 18259 .Int => { 18260 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { 18261 if (val.isUndef()) return sema.addConstUndef(result_scalar_ty); 18262 return sema.addIntUnsigned(result_scalar_ty, comptimeOp(val, operand_ty, target)); 18263 } else { 18264 try sema.requireRuntimeBlock(block, src, operand_src); 18265 return block.addTyOp(air_tag, result_scalar_ty, operand); 18266 } 18267 }, 18268 else => unreachable, 18269 } 18270 } 18271 18272 fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 18273 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 18274 const src = inst_data.src(); 18275 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 18276 const operand = try sema.resolveInst(inst_data.operand); 18277 const operand_ty = sema.typeOf(operand); 18278 const scalar_ty = try sema.checkIntOrVector(block, operand, operand_src); 18279 const target = sema.mod.getTarget(); 18280 const bits = scalar_ty.intInfo(target).bits; 18281 if (bits % 8 != 0) { 18282 return sema.fail( 18283 block, 18284 operand_src, 18285 "@byteSwap requires the number of bits to be evenly divisible by 8, but {} has {} bits", 18286 .{ scalar_ty.fmt(sema.mod), bits }, 18287 ); 18288 } 18289 18290 if (try sema.typeHasOnePossibleValue(block, operand_src, operand_ty)) |val| { 18291 return sema.addConstant(operand_ty, val); 18292 } 18293 18294 switch (operand_ty.zigTypeTag()) { 18295 .Int => { 18296 const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { 18297 if (val.isUndef()) return sema.addConstUndef(operand_ty); 18298 const result_val = try val.byteSwap(operand_ty, target, sema.arena); 18299 return sema.addConstant(operand_ty, result_val); 18300 } else operand_src; 18301 18302 try sema.requireRuntimeBlock(block, src, runtime_src); 18303 return block.addTyOp(.byte_swap, operand_ty, operand); 18304 }, 18305 .Vector => { 18306 const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { 18307 if (val.isUndef()) 18308 return sema.addConstUndef(operand_ty); 18309 18310 const vec_len = operand_ty.vectorLen(); 18311 var elem_buf: Value.ElemValueBuffer = undefined; 18312 const elems = try sema.arena.alloc(Value, vec_len); 18313 for (elems) |*elem, i| { 18314 const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); 18315 elem.* = try elem_val.byteSwap(operand_ty, target, sema.arena); 18316 } 18317 return sema.addConstant( 18318 operand_ty, 18319 try Value.Tag.aggregate.create(sema.arena, elems), 18320 ); 18321 } else operand_src; 18322 18323 try sema.requireRuntimeBlock(block, src, runtime_src); 18324 return block.addTyOp(.byte_swap, operand_ty, operand); 18325 }, 18326 else => unreachable, 18327 } 18328 } 18329 18330 fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 18331 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 18332 const src = inst_data.src(); 18333 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 18334 const operand = try sema.resolveInst(inst_data.operand); 18335 const operand_ty = sema.typeOf(operand); 18336 _ = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); 18337 18338 if (try sema.typeHasOnePossibleValue(block, operand_src, operand_ty)) |val| { 18339 return sema.addConstant(operand_ty, val); 18340 } 18341 18342 const target = sema.mod.getTarget(); 18343 switch (operand_ty.zigTypeTag()) { 18344 .Int, .ComptimeInt => { 18345 const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { 18346 if (val.isUndef()) return sema.addConstUndef(operand_ty); 18347 const result_val = try val.bitReverse(operand_ty, target, sema.arena); 18348 return sema.addConstant(operand_ty, result_val); 18349 } else operand_src; 18350 18351 try sema.requireRuntimeBlock(block, src, runtime_src); 18352 return block.addTyOp(.bit_reverse, operand_ty, operand); 18353 }, 18354 .Vector => { 18355 const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { 18356 if (val.isUndef()) 18357 return sema.addConstUndef(operand_ty); 18358 18359 const vec_len = operand_ty.vectorLen(); 18360 var elem_buf: Value.ElemValueBuffer = undefined; 18361 const elems = try sema.arena.alloc(Value, vec_len); 18362 for (elems) |*elem, i| { 18363 const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); 18364 elem.* = try elem_val.bitReverse(operand_ty, target, sema.arena); 18365 } 18366 return sema.addConstant( 18367 operand_ty, 18368 try Value.Tag.aggregate.create(sema.arena, elems), 18369 ); 18370 } else operand_src; 18371 18372 try sema.requireRuntimeBlock(block, src, runtime_src); 18373 return block.addTyOp(.bit_reverse, operand_ty, operand); 18374 }, 18375 else => unreachable, 18376 } 18377 } 18378 18379 fn zirBitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 18380 const offset = try bitOffsetOf(sema, block, inst); 18381 return sema.addIntUnsigned(Type.comptime_int, offset); 18382 } 18383 18384 fn zirOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 18385 const offset = try bitOffsetOf(sema, block, inst); 18386 // TODO reminder to make this a compile error for packed structs 18387 return sema.addIntUnsigned(Type.comptime_int, offset / 8); 18388 } 18389 18390 fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u64 { 18391 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 18392 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; 18393 sema.src = src; 18394 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 18395 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 18396 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 18397 18398 const ty = try sema.resolveType(block, lhs_src, extra.lhs); 18399 const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "name of field must be comptime known"); 18400 const target = sema.mod.getTarget(); 18401 18402 try sema.resolveTypeLayout(block, lhs_src, ty); 18403 switch (ty.zigTypeTag()) { 18404 .Struct => {}, 18405 else => { 18406 const msg = msg: { 18407 const msg = try sema.errMsg(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(sema.mod)}); 18408 errdefer msg.destroy(sema.gpa); 18409 try sema.addDeclaredHereNote(msg, ty); 18410 break :msg msg; 18411 }; 18412 return sema.failWithOwnedErrorMsg(msg); 18413 }, 18414 } 18415 18416 const field_index = if (ty.isTuple()) blk: { 18417 if (mem.eql(u8, field_name, "len")) { 18418 return sema.fail(block, src, "no offset available for 'len' field of tuple", .{}); 18419 } 18420 break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src); 18421 } else try sema.structFieldIndex(block, ty, field_name, rhs_src); 18422 18423 switch (ty.containerLayout()) { 18424 .Packed => { 18425 var bit_sum: u64 = 0; 18426 const fields = ty.structFields(); 18427 for (fields.values()) |field, i| { 18428 if (i == field_index) { 18429 return bit_sum; 18430 } 18431 bit_sum += field.ty.bitSize(target); 18432 } else unreachable; 18433 }, 18434 else => return ty.structFieldOffset(field_index, target) * 8, 18435 } 18436 } 18437 18438 fn checkNamespaceType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { 18439 switch (ty.zigTypeTag()) { 18440 .Struct, .Enum, .Union, .Opaque => return, 18441 else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{}'", .{ty.fmt(sema.mod)}), 18442 } 18443 } 18444 18445 /// Returns `true` if the type was a comptime_int. 18446 fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { 18447 switch (try ty.zigTypeTagOrPoison()) { 18448 .ComptimeInt => return true, 18449 .Int => return false, 18450 else => return sema.fail(block, src, "expected integer type, found '{}'", .{ty.fmt(sema.mod)}), 18451 } 18452 } 18453 18454 fn checkInvalidPtrArithmetic( 18455 sema: *Sema, 18456 block: *Block, 18457 src: LazySrcLoc, 18458 ty: Type, 18459 zir_tag: Zir.Inst.Tag, 18460 ) CompileError!void { 18461 switch (try ty.zigTypeTagOrPoison()) { 18462 .Pointer => switch (ty.ptrSize()) { 18463 .One, .Slice => return, 18464 .Many, .C => return sema.fail( 18465 block, 18466 src, 18467 "invalid pointer arithmetic operand: '{s}''", 18468 .{@tagName(zir_tag)}, 18469 ), 18470 }, 18471 else => return, 18472 } 18473 } 18474 18475 fn checkArithmeticOp( 18476 sema: *Sema, 18477 block: *Block, 18478 src: LazySrcLoc, 18479 scalar_tag: std.builtin.TypeId, 18480 lhs_zig_ty_tag: std.builtin.TypeId, 18481 rhs_zig_ty_tag: std.builtin.TypeId, 18482 zir_tag: Zir.Inst.Tag, 18483 ) CompileError!void { 18484 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; 18485 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat; 18486 18487 if (!is_int and !(is_float and floatOpAllowed(zir_tag))) { 18488 return sema.fail(block, src, "invalid operands to binary expression: '{s}' and '{s}'", .{ 18489 @tagName(lhs_zig_ty_tag), @tagName(rhs_zig_ty_tag), 18490 }); 18491 } 18492 } 18493 18494 fn checkPtrOperand( 18495 sema: *Sema, 18496 block: *Block, 18497 ty_src: LazySrcLoc, 18498 ty: Type, 18499 ) CompileError!void { 18500 switch (ty.zigTypeTag()) { 18501 .Pointer => return, 18502 .Fn => { 18503 const msg = msg: { 18504 const msg = try sema.errMsg( 18505 block, 18506 ty_src, 18507 "expected pointer, found '{}'", 18508 .{ty.fmt(sema.mod)}, 18509 ); 18510 errdefer msg.destroy(sema.gpa); 18511 18512 try sema.errNote(block, ty_src, msg, "use '&' to obtain a function pointer", .{}); 18513 18514 break :msg msg; 18515 }; 18516 return sema.failWithOwnedErrorMsg(msg); 18517 }, 18518 .Optional => if (ty.isPtrLikeOptional()) return, 18519 else => {}, 18520 } 18521 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(sema.mod)}); 18522 } 18523 18524 fn checkPtrType( 18525 sema: *Sema, 18526 block: *Block, 18527 ty_src: LazySrcLoc, 18528 ty: Type, 18529 ) CompileError!void { 18530 switch (ty.zigTypeTag()) { 18531 .Pointer => return, 18532 .Fn => { 18533 const msg = msg: { 18534 const msg = try sema.errMsg( 18535 block, 18536 ty_src, 18537 "expected pointer type, found '{}'", 18538 .{ty.fmt(sema.mod)}, 18539 ); 18540 errdefer msg.destroy(sema.gpa); 18541 18542 try sema.errNote(block, ty_src, msg, "use '*const ' to make a function pointer type", .{}); 18543 18544 break :msg msg; 18545 }; 18546 return sema.failWithOwnedErrorMsg(msg); 18547 }, 18548 .Optional => if (ty.isPtrLikeOptional()) return, 18549 else => {}, 18550 } 18551 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(sema.mod)}); 18552 } 18553 18554 fn checkVectorElemType( 18555 sema: *Sema, 18556 block: *Block, 18557 ty_src: LazySrcLoc, 18558 ty: Type, 18559 ) CompileError!void { 18560 switch (ty.zigTypeTag()) { 18561 .Int, .Float, .Bool => return, 18562 else => if (ty.isPtrAtRuntime()) return, 18563 } 18564 return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{}'", .{ty.fmt(sema.mod)}); 18565 } 18566 18567 fn checkFloatType( 18568 sema: *Sema, 18569 block: *Block, 18570 ty_src: LazySrcLoc, 18571 ty: Type, 18572 ) CompileError!void { 18573 switch (ty.zigTypeTag()) { 18574 .ComptimeInt, .ComptimeFloat, .Float => {}, 18575 else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty.fmt(sema.mod)}), 18576 } 18577 } 18578 18579 fn checkNumericType( 18580 sema: *Sema, 18581 block: *Block, 18582 ty_src: LazySrcLoc, 18583 ty: Type, 18584 ) CompileError!void { 18585 switch (ty.zigTypeTag()) { 18586 .ComptimeFloat, .Float, .ComptimeInt, .Int => {}, 18587 .Vector => switch (ty.childType().zigTypeTag()) { 18588 .ComptimeFloat, .Float, .ComptimeInt, .Int => {}, 18589 else => |t| return sema.fail(block, ty_src, "expected number, found '{}'", .{t}), 18590 }, 18591 else => return sema.fail(block, ty_src, "expected number, found '{}'", .{ty.fmt(sema.mod)}), 18592 } 18593 } 18594 18595 /// Returns the casted pointer. 18596 fn checkAtomicPtrOperand( 18597 sema: *Sema, 18598 block: *Block, 18599 elem_ty: Type, 18600 elem_ty_src: LazySrcLoc, 18601 ptr: Air.Inst.Ref, 18602 ptr_src: LazySrcLoc, 18603 ptr_const: bool, 18604 ) CompileError!Air.Inst.Ref { 18605 const target = sema.mod.getTarget(); 18606 var diag: target_util.AtomicPtrAlignmentDiagnostics = .{}; 18607 const alignment = target_util.atomicPtrAlignment(target, elem_ty, &diag) catch |err| switch (err) { 18608 error.FloatTooBig => return sema.fail( 18609 block, 18610 elem_ty_src, 18611 "expected {d}-bit float type or smaller; found {d}-bit float type", 18612 .{ diag.max_bits, diag.bits }, 18613 ), 18614 error.IntTooBig => return sema.fail( 18615 block, 18616 elem_ty_src, 18617 "expected {d}-bit integer type or smaller; found {d}-bit integer type", 18618 .{ diag.max_bits, diag.bits }, 18619 ), 18620 error.BadType => return sema.fail( 18621 block, 18622 elem_ty_src, 18623 "expected bool, integer, float, enum, or pointer type; found '{}'", 18624 .{elem_ty.fmt(sema.mod)}, 18625 ), 18626 }; 18627 18628 var wanted_ptr_data: Type.Payload.Pointer.Data = .{ 18629 .pointee_type = elem_ty, 18630 .@"align" = alignment, 18631 .@"addrspace" = .generic, 18632 .mutable = !ptr_const, 18633 }; 18634 18635 const ptr_ty = sema.typeOf(ptr); 18636 const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison()) { 18637 .Pointer => ptr_ty.ptrInfo().data, 18638 else => { 18639 const wanted_ptr_ty = try Type.ptr(sema.arena, sema.mod, wanted_ptr_data); 18640 _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); 18641 unreachable; 18642 }, 18643 }; 18644 18645 wanted_ptr_data.@"addrspace" = ptr_data.@"addrspace"; 18646 wanted_ptr_data.@"allowzero" = ptr_data.@"allowzero"; 18647 wanted_ptr_data.@"volatile" = ptr_data.@"volatile"; 18648 18649 const wanted_ptr_ty = try Type.ptr(sema.arena, sema.mod, wanted_ptr_data); 18650 const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); 18651 18652 return casted_ptr; 18653 } 18654 18655 fn checkPtrIsNotComptimeMutable( 18656 sema: *Sema, 18657 block: *Block, 18658 ptr_val: Value, 18659 ptr_src: LazySrcLoc, 18660 operand_src: LazySrcLoc, 18661 ) CompileError!void { 18662 _ = operand_src; 18663 if (ptr_val.isComptimeMutablePtr()) { 18664 return sema.fail(block, ptr_src, "cannot store runtime value in compile time variable", .{}); 18665 } 18666 } 18667 18668 fn checkComptimeVarStore( 18669 sema: *Sema, 18670 block: *Block, 18671 src: LazySrcLoc, 18672 decl_ref_mut: Value.Payload.DeclRefMut.Data, 18673 ) CompileError!void { 18674 if (@enumToInt(decl_ref_mut.runtime_index) < @enumToInt(block.runtime_index)) { 18675 if (block.runtime_cond) |cond_src| { 18676 const msg = msg: { 18677 const msg = try sema.errMsg(block, src, "store to comptime variable depends on runtime condition", .{}); 18678 errdefer msg.destroy(sema.gpa); 18679 try sema.errNote(block, cond_src, msg, "runtime condition here", .{}); 18680 break :msg msg; 18681 }; 18682 return sema.failWithOwnedErrorMsg(msg); 18683 } 18684 if (block.runtime_loop) |loop_src| { 18685 const msg = msg: { 18686 const msg = try sema.errMsg(block, src, "cannot store to comptime variable in non-inline loop", .{}); 18687 errdefer msg.destroy(sema.gpa); 18688 try sema.errNote(block, loop_src, msg, "non-inline loop here", .{}); 18689 break :msg msg; 18690 }; 18691 return sema.failWithOwnedErrorMsg(msg); 18692 } 18693 unreachable; 18694 } 18695 } 18696 18697 fn checkIntOrVector( 18698 sema: *Sema, 18699 block: *Block, 18700 operand: Air.Inst.Ref, 18701 operand_src: LazySrcLoc, 18702 ) CompileError!Type { 18703 const operand_ty = sema.typeOf(operand); 18704 switch (try operand_ty.zigTypeTagOrPoison()) { 18705 .Int => return operand_ty, 18706 .Vector => { 18707 const elem_ty = operand_ty.childType(); 18708 switch (try elem_ty.zigTypeTagOrPoison()) { 18709 .Int => return elem_ty, 18710 else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ 18711 elem_ty.fmt(sema.mod), 18712 }), 18713 } 18714 }, 18715 else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{ 18716 operand_ty.fmt(sema.mod), 18717 }), 18718 } 18719 } 18720 18721 fn checkIntOrVectorAllowComptime( 18722 sema: *Sema, 18723 block: *Block, 18724 operand_ty: Type, 18725 operand_src: LazySrcLoc, 18726 ) CompileError!Type { 18727 switch (try operand_ty.zigTypeTagOrPoison()) { 18728 .Int, .ComptimeInt => return operand_ty, 18729 .Vector => { 18730 const elem_ty = operand_ty.childType(); 18731 switch (try elem_ty.zigTypeTagOrPoison()) { 18732 .Int, .ComptimeInt => return elem_ty, 18733 else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ 18734 elem_ty.fmt(sema.mod), 18735 }), 18736 } 18737 }, 18738 else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{ 18739 operand_ty.fmt(sema.mod), 18740 }), 18741 } 18742 } 18743 18744 fn checkErrorSetType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { 18745 switch (ty.zigTypeTag()) { 18746 .ErrorSet => return, 18747 else => return sema.fail(block, src, "expected error set type, found '{}'", .{ty.fmt(sema.mod)}), 18748 } 18749 } 18750 18751 const SimdBinOp = struct { 18752 len: ?usize, 18753 /// Coerced to `result_ty`. 18754 lhs: Air.Inst.Ref, 18755 /// Coerced to `result_ty`. 18756 rhs: Air.Inst.Ref, 18757 lhs_val: ?Value, 18758 rhs_val: ?Value, 18759 /// Only different than `scalar_ty` when it is a vector operation. 18760 result_ty: Type, 18761 scalar_ty: Type, 18762 }; 18763 18764 fn checkSimdBinOp( 18765 sema: *Sema, 18766 block: *Block, 18767 src: LazySrcLoc, 18768 uncasted_lhs: Air.Inst.Ref, 18769 uncasted_rhs: Air.Inst.Ref, 18770 lhs_src: LazySrcLoc, 18771 rhs_src: LazySrcLoc, 18772 ) CompileError!SimdBinOp { 18773 const lhs_ty = sema.typeOf(uncasted_lhs); 18774 const rhs_ty = sema.typeOf(uncasted_rhs); 18775 18776 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 18777 var vec_len: ?usize = if (lhs_ty.zigTypeTag() == .Vector) lhs_ty.vectorLen() else null; 18778 const result_ty = try sema.resolvePeerTypes(block, src, &.{ uncasted_lhs, uncasted_rhs }, .{ 18779 .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, 18780 }); 18781 const lhs = try sema.coerce(block, result_ty, uncasted_lhs, lhs_src); 18782 const rhs = try sema.coerce(block, result_ty, uncasted_rhs, rhs_src); 18783 18784 return SimdBinOp{ 18785 .len = vec_len, 18786 .lhs = lhs, 18787 .rhs = rhs, 18788 .lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs), 18789 .rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs), 18790 .result_ty = result_ty, 18791 .scalar_ty = result_ty.scalarType(), 18792 }; 18793 } 18794 18795 fn checkVectorizableBinaryOperands( 18796 sema: *Sema, 18797 block: *Block, 18798 src: LazySrcLoc, 18799 lhs_ty: Type, 18800 rhs_ty: Type, 18801 lhs_src: LazySrcLoc, 18802 rhs_src: LazySrcLoc, 18803 ) CompileError!void { 18804 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); 18805 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); 18806 if (lhs_zig_ty_tag != .Vector and rhs_zig_ty_tag != .Vector) return; 18807 18808 const lhs_is_vector = switch (lhs_zig_ty_tag) { 18809 .Vector, .Array => true, 18810 else => false, 18811 }; 18812 const rhs_is_vector = switch (rhs_zig_ty_tag) { 18813 .Vector, .Array => true, 18814 else => false, 18815 }; 18816 18817 if (lhs_is_vector and rhs_is_vector) { 18818 const lhs_len = lhs_ty.arrayLen(); 18819 const rhs_len = rhs_ty.arrayLen(); 18820 if (lhs_len != rhs_len) { 18821 const msg = msg: { 18822 const msg = try sema.errMsg(block, src, "vector length mismatch", .{}); 18823 errdefer msg.destroy(sema.gpa); 18824 try sema.errNote(block, lhs_src, msg, "length {d} here", .{lhs_len}); 18825 try sema.errNote(block, rhs_src, msg, "length {d} here", .{rhs_len}); 18826 break :msg msg; 18827 }; 18828 return sema.failWithOwnedErrorMsg(msg); 18829 } 18830 } else { 18831 const msg = msg: { 18832 const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: '{}' and '{}'", .{ 18833 lhs_ty.fmt(sema.mod), rhs_ty.fmt(sema.mod), 18834 }); 18835 errdefer msg.destroy(sema.gpa); 18836 if (lhs_is_vector) { 18837 try sema.errNote(block, lhs_src, msg, "vector here", .{}); 18838 try sema.errNote(block, rhs_src, msg, "scalar here", .{}); 18839 } else { 18840 try sema.errNote(block, lhs_src, msg, "scalar here", .{}); 18841 try sema.errNote(block, rhs_src, msg, "vector here", .{}); 18842 } 18843 break :msg msg; 18844 }; 18845 return sema.failWithOwnedErrorMsg(msg); 18846 } 18847 } 18848 18849 fn maybeOptionsSrc(sema: *Sema, block: *Block, base_src: LazySrcLoc, wanted: []const u8) LazySrcLoc { 18850 if (base_src == .unneeded) return .unneeded; 18851 return Module.optionsSrc(sema.gpa, sema.mod.declPtr(block.src_decl), base_src, wanted); 18852 } 18853 18854 fn resolveExportOptions( 18855 sema: *Sema, 18856 block: *Block, 18857 src: LazySrcLoc, 18858 zir_ref: Zir.Inst.Ref, 18859 ) CompileError!std.builtin.ExportOptions { 18860 const export_options_ty = try sema.getBuiltinType(block, src, "ExportOptions"); 18861 const air_ref = try sema.resolveInst(zir_ref); 18862 const options = try sema.coerce(block, export_options_ty, air_ref, src); 18863 18864 const name_src = sema.maybeOptionsSrc(block, src, "name"); 18865 const linkage_src = sema.maybeOptionsSrc(block, src, "linkage"); 18866 const section_src = sema.maybeOptionsSrc(block, src, "section"); 18867 const visibility_src = sema.maybeOptionsSrc(block, src, "visibility"); 18868 18869 const name_operand = try sema.fieldVal(block, src, options, "name", name_src); 18870 const name_val = try sema.resolveConstValue(block, name_src, name_operand, "name of exported value must be comptime known"); 18871 const name_ty = Type.initTag(.const_slice_u8); 18872 const name = try name_val.toAllocatedBytes(name_ty, sema.arena, sema.mod); 18873 18874 const linkage_operand = try sema.fieldVal(block, src, options, "linkage", linkage_src); 18875 const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_operand, "linkage of exported value must be comptime known"); 18876 const linkage = linkage_val.toEnum(std.builtin.GlobalLinkage); 18877 18878 const section = try sema.fieldVal(block, src, options, "section", section_src); 18879 const section_val = try sema.resolveConstValue(block, section_src, section, "linksection of exported value must be comptime known"); 18880 18881 const visibility_operand = try sema.fieldVal(block, src, options, "visibility", visibility_src); 18882 const visibility_val = try sema.resolveConstValue(block, visibility_src, visibility_operand, "visibility of exported value must be comptime known"); 18883 const visibility = visibility_val.toEnum(std.builtin.SymbolVisibility); 18884 18885 if (name.len < 1) { 18886 return sema.fail(block, name_src, "exported symbol name cannot be empty", .{}); 18887 } 18888 18889 if (visibility != .default and linkage == .Internal) { 18890 return sema.fail(block, visibility_src, "symbol '{s}' exported with internal linkage has non-default visibility {s}", .{ 18891 name, @tagName(visibility), 18892 }); 18893 } 18894 18895 if (!section_val.isNull()) { 18896 return sema.fail(block, section_src, "TODO: implement exporting with linksection", .{}); 18897 } 18898 18899 return std.builtin.ExportOptions{ 18900 .name = name, 18901 .linkage = linkage, 18902 .section = null, // TODO 18903 .visibility = visibility, 18904 }; 18905 } 18906 18907 fn resolveBuiltinEnum( 18908 sema: *Sema, 18909 block: *Block, 18910 src: LazySrcLoc, 18911 zir_ref: Zir.Inst.Ref, 18912 comptime name: []const u8, 18913 reason: []const u8, 18914 ) CompileError!@field(std.builtin, name) { 18915 const ty = try sema.getBuiltinType(block, src, name); 18916 const air_ref = try sema.resolveInst(zir_ref); 18917 const coerced = try sema.coerce(block, ty, air_ref, src); 18918 const val = try sema.resolveConstValue(block, src, coerced, reason); 18919 return val.toEnum(@field(std.builtin, name)); 18920 } 18921 18922 fn resolveAtomicOrder( 18923 sema: *Sema, 18924 block: *Block, 18925 src: LazySrcLoc, 18926 zir_ref: Zir.Inst.Ref, 18927 reason: []const u8, 18928 ) CompileError!std.builtin.AtomicOrder { 18929 return resolveBuiltinEnum(sema, block, src, zir_ref, "AtomicOrder", reason); 18930 } 18931 18932 fn resolveAtomicRmwOp( 18933 sema: *Sema, 18934 block: *Block, 18935 src: LazySrcLoc, 18936 zir_ref: Zir.Inst.Ref, 18937 ) CompileError!std.builtin.AtomicRmwOp { 18938 return resolveBuiltinEnum(sema, block, src, zir_ref, "AtomicRmwOp", "@atomicRmW operation must be comptime known"); 18939 } 18940 18941 fn zirCmpxchg( 18942 sema: *Sema, 18943 block: *Block, 18944 extended: Zir.Inst.Extended.InstData, 18945 ) CompileError!Air.Inst.Ref { 18946 const extra = sema.code.extraData(Zir.Inst.Cmpxchg, extended.operand).data; 18947 const air_tag: Air.Inst.Tag = switch (extended.small) { 18948 0 => .cmpxchg_weak, 18949 1 => .cmpxchg_strong, 18950 else => unreachable, 18951 }; 18952 const src = LazySrcLoc.nodeOffset(extra.node); 18953 // zig fmt: off 18954 const elem_ty_src : LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 18955 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 18956 const expected_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node }; 18957 const new_value_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = extra.node }; 18958 const success_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg4 = extra.node }; 18959 const failure_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg5 = extra.node }; 18960 // zig fmt: on 18961 const expected_value = try sema.resolveInst(extra.expected_value); 18962 const elem_ty = sema.typeOf(expected_value); 18963 if (elem_ty.zigTypeTag() == .Float) { 18964 return sema.fail( 18965 block, 18966 elem_ty_src, 18967 "expected bool, integer, enum, or pointer type; found '{}'", 18968 .{elem_ty.fmt(sema.mod)}, 18969 ); 18970 } 18971 const uncasted_ptr = try sema.resolveInst(extra.ptr); 18972 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false); 18973 const new_value = try sema.coerce(block, elem_ty, try sema.resolveInst(extra.new_value), new_value_src); 18974 const success_order = try sema.resolveAtomicOrder(block, success_order_src, extra.success_order, "atomic order of cmpxchg success must be comptime known"); 18975 const failure_order = try sema.resolveAtomicOrder(block, failure_order_src, extra.failure_order, "atomic order of cmpxchg failure must be comptime known"); 18976 18977 if (@enumToInt(success_order) < @enumToInt(std.builtin.AtomicOrder.Monotonic)) { 18978 return sema.fail(block, success_order_src, "success atomic ordering must be Monotonic or stricter", .{}); 18979 } 18980 if (@enumToInt(failure_order) < @enumToInt(std.builtin.AtomicOrder.Monotonic)) { 18981 return sema.fail(block, failure_order_src, "failure atomic ordering must be Monotonic or stricter", .{}); 18982 } 18983 if (@enumToInt(failure_order) > @enumToInt(success_order)) { 18984 return sema.fail(block, failure_order_src, "failure atomic ordering must be no stricter than success", .{}); 18985 } 18986 if (failure_order == .Release or failure_order == .AcqRel) { 18987 return sema.fail(block, failure_order_src, "failure atomic ordering must not be Release or AcqRel", .{}); 18988 } 18989 18990 const result_ty = try Type.optional(sema.arena, elem_ty); 18991 18992 // special case zero bit types 18993 if ((try sema.typeHasOnePossibleValue(block, elem_ty_src, elem_ty)) != null) { 18994 return sema.addConstant(result_ty, Value.@"null"); 18995 } 18996 18997 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { 18998 if (try sema.resolveMaybeUndefVal(block, expected_src, expected_value)) |expected_val| { 18999 if (try sema.resolveMaybeUndefVal(block, new_value_src, new_value)) |new_val| { 19000 if (expected_val.isUndef() or new_val.isUndef()) { 19001 // TODO: this should probably cause the memory stored at the pointer 19002 // to become undef as well 19003 return sema.addConstUndef(result_ty); 19004 } 19005 const ptr_ty = sema.typeOf(ptr); 19006 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; 19007 const result_val = if (stored_val.eql(expected_val, elem_ty, sema.mod)) blk: { 19008 try sema.storePtr(block, src, ptr, new_value); 19009 break :blk Value.@"null"; 19010 } else try Value.Tag.opt_payload.create(sema.arena, stored_val); 19011 19012 return sema.addConstant(result_ty, result_val); 19013 } else break :rs new_value_src; 19014 } else break :rs expected_src; 19015 } else ptr_src; 19016 19017 const flags: u32 = @as(u32, @enumToInt(success_order)) | 19018 (@as(u32, @enumToInt(failure_order)) << 3); 19019 19020 try sema.requireRuntimeBlock(block, src, runtime_src); 19021 return block.addInst(.{ 19022 .tag = air_tag, 19023 .data = .{ .ty_pl = .{ 19024 .ty = try sema.addType(result_ty), 19025 .payload = try sema.addExtra(Air.Cmpxchg{ 19026 .ptr = ptr, 19027 .expected_value = expected_value, 19028 .new_value = new_value, 19029 .flags = flags, 19030 }), 19031 } }, 19032 }); 19033 } 19034 19035 fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 19036 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 19037 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 19038 const len_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; 19039 const scalar_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; 19040 const len = @intCast(u32, try sema.resolveInt(block, len_src, extra.lhs, Type.u32, "vector splat destination length must be comptime known")); 19041 const scalar = try sema.resolveInst(extra.rhs); 19042 const scalar_ty = sema.typeOf(scalar); 19043 try sema.checkVectorElemType(block, scalar_src, scalar_ty); 19044 const vector_ty = try Type.Tag.vector.create(sema.arena, .{ 19045 .len = len, 19046 .elem_type = scalar_ty, 19047 }); 19048 if (try sema.resolveMaybeUndefVal(block, scalar_src, scalar)) |scalar_val| { 19049 if (scalar_val.isUndef()) return sema.addConstUndef(vector_ty); 19050 19051 return sema.addConstant( 19052 vector_ty, 19053 try Value.Tag.repeated.create(sema.arena, scalar_val), 19054 ); 19055 } 19056 19057 try sema.requireRuntimeBlock(block, inst_data.src(), scalar_src); 19058 return block.addTyOp(.splat, vector_ty, scalar); 19059 } 19060 19061 fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 19062 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 19063 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 19064 const op_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 19065 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 19066 const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, "ReduceOp", "@reduce operation must be comptime known"); 19067 const operand = try sema.resolveInst(extra.rhs); 19068 const operand_ty = sema.typeOf(operand); 19069 const target = sema.mod.getTarget(); 19070 19071 if (operand_ty.zigTypeTag() != .Vector) { 19072 return sema.fail(block, operand_src, "expected vector, found '{}'", .{operand_ty.fmt(sema.mod)}); 19073 } 19074 19075 const scalar_ty = operand_ty.childType(); 19076 19077 // Type-check depending on operation. 19078 switch (operation) { 19079 .And, .Or, .Xor => switch (scalar_ty.zigTypeTag()) { 19080 .Int, .Bool => {}, 19081 else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found '{}'", .{ 19082 @tagName(operation), operand_ty.fmt(sema.mod), 19083 }), 19084 }, 19085 .Min, .Max, .Add, .Mul => switch (scalar_ty.zigTypeTag()) { 19086 .Int, .Float => {}, 19087 else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found '{}'", .{ 19088 @tagName(operation), operand_ty.fmt(sema.mod), 19089 }), 19090 }, 19091 } 19092 19093 const vec_len = operand_ty.vectorLen(); 19094 if (vec_len == 0) { 19095 // TODO re-evaluate if we should introduce a "neutral value" for some operations, 19096 // e.g. zero for add and one for mul. 19097 return sema.fail(block, operand_src, "@reduce operation requires a vector with nonzero length", .{}); 19098 } 19099 19100 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| { 19101 if (operand_val.isUndef()) return sema.addConstUndef(scalar_ty); 19102 19103 var accum: Value = try operand_val.elemValue(sema.mod, sema.arena, 0); 19104 var elem_buf: Value.ElemValueBuffer = undefined; 19105 var i: u32 = 1; 19106 while (i < vec_len) : (i += 1) { 19107 const elem_val = operand_val.elemValueBuffer(sema.mod, i, &elem_buf); 19108 switch (operation) { 19109 .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena, target), 19110 .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena, target), 19111 .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena, target), 19112 .Min => accum = accum.numberMin(elem_val, target), 19113 .Max => accum = accum.numberMax(elem_val, target), 19114 .Add => accum = try sema.numberAddWrap(block, operand_src, accum, elem_val, scalar_ty), 19115 .Mul => accum = try accum.numberMulWrap(elem_val, scalar_ty, sema.arena, target), 19116 } 19117 } 19118 return sema.addConstant(scalar_ty, accum); 19119 } 19120 19121 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); 19122 return block.addInst(.{ 19123 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, 19124 .data = .{ .reduce = .{ 19125 .operand = operand, 19126 .operation = operation, 19127 } }, 19128 }); 19129 } 19130 19131 fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 19132 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 19133 const extra = sema.code.extraData(Zir.Inst.Shuffle, inst_data.payload_index).data; 19134 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 19135 const mask_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node }; 19136 19137 const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type); 19138 try sema.checkVectorElemType(block, elem_ty_src, elem_ty); 19139 var a = try sema.resolveInst(extra.a); 19140 var b = try sema.resolveInst(extra.b); 19141 var mask = try sema.resolveInst(extra.mask); 19142 var mask_ty = sema.typeOf(mask); 19143 19144 const mask_len = switch (sema.typeOf(mask).zigTypeTag()) { 19145 .Array, .Vector => sema.typeOf(mask).arrayLen(), 19146 else => return sema.fail(block, mask_src, "expected vector or array, found '{}'", .{sema.typeOf(mask).fmt(sema.mod)}), 19147 }; 19148 mask_ty = try Type.Tag.vector.create(sema.arena, .{ 19149 .len = mask_len, 19150 .elem_type = Type.@"i32", 19151 }); 19152 mask = try sema.coerce(block, mask_ty, mask, mask_src); 19153 const mask_val = try sema.resolveConstMaybeUndefVal(block, mask_src, mask, "shuffle mask must be comptime known"); 19154 return sema.analyzeShuffle(block, inst_data.src_node, elem_ty, a, b, mask_val, @intCast(u32, mask_len)); 19155 } 19156 19157 fn analyzeShuffle( 19158 sema: *Sema, 19159 block: *Block, 19160 src_node: i32, 19161 elem_ty: Type, 19162 a_arg: Air.Inst.Ref, 19163 b_arg: Air.Inst.Ref, 19164 mask: Value, 19165 mask_len: u32, 19166 ) CompileError!Air.Inst.Ref { 19167 const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = src_node }; 19168 const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = src_node }; 19169 const mask_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = src_node }; 19170 var a = a_arg; 19171 var b = b_arg; 19172 19173 const res_ty = try Type.Tag.vector.create(sema.arena, .{ 19174 .len = mask_len, 19175 .elem_type = elem_ty, 19176 }); 19177 19178 var maybe_a_len = switch (sema.typeOf(a).zigTypeTag()) { 19179 .Array, .Vector => sema.typeOf(a).arrayLen(), 19180 .Undefined => null, 19181 else => return sema.fail(block, a_src, "expected vector or array with element type '{}', found '{}'", .{ 19182 elem_ty.fmt(sema.mod), 19183 sema.typeOf(a).fmt(sema.mod), 19184 }), 19185 }; 19186 var maybe_b_len = switch (sema.typeOf(b).zigTypeTag()) { 19187 .Array, .Vector => sema.typeOf(b).arrayLen(), 19188 .Undefined => null, 19189 else => return sema.fail(block, b_src, "expected vector or array with element type '{}', found '{}'", .{ 19190 elem_ty.fmt(sema.mod), 19191 sema.typeOf(b).fmt(sema.mod), 19192 }), 19193 }; 19194 if (maybe_a_len == null and maybe_b_len == null) { 19195 return sema.addConstUndef(res_ty); 19196 } 19197 const a_len = maybe_a_len orelse maybe_b_len.?; 19198 const b_len = maybe_b_len orelse a_len; 19199 19200 const a_ty = try Type.Tag.vector.create(sema.arena, .{ 19201 .len = a_len, 19202 .elem_type = elem_ty, 19203 }); 19204 const b_ty = try Type.Tag.vector.create(sema.arena, .{ 19205 .len = b_len, 19206 .elem_type = elem_ty, 19207 }); 19208 19209 if (maybe_a_len == null) a = try sema.addConstUndef(a_ty); 19210 if (maybe_b_len == null) b = try sema.addConstUndef(b_ty); 19211 19212 const operand_info = [2]std.meta.Tuple(&.{ u64, LazySrcLoc, Type }){ 19213 .{ a_len, a_src, a_ty }, 19214 .{ b_len, b_src, b_ty }, 19215 }; 19216 19217 var i: usize = 0; 19218 while (i < mask_len) : (i += 1) { 19219 var buf: Value.ElemValueBuffer = undefined; 19220 const elem = mask.elemValueBuffer(sema.mod, i, &buf); 19221 if (elem.isUndef()) continue; 19222 const int = elem.toSignedInt(); 19223 var unsigned: u32 = undefined; 19224 var chosen: u32 = undefined; 19225 if (int >= 0) { 19226 unsigned = @intCast(u32, int); 19227 chosen = 0; 19228 } else { 19229 unsigned = @intCast(u32, ~int); 19230 chosen = 1; 19231 } 19232 if (unsigned >= operand_info[chosen][0]) { 19233 const msg = msg: { 19234 const msg = try sema.errMsg(block, mask_src, "mask index '{d}' has out-of-bounds selection", .{i}); 19235 errdefer msg.destroy(sema.gpa); 19236 19237 try sema.errNote(block, operand_info[chosen][1], msg, "selected index '{d}' out of bounds of '{}'", .{ 19238 unsigned, 19239 operand_info[chosen][2].fmt(sema.mod), 19240 }); 19241 19242 if (chosen == 0) { 19243 try sema.errNote(block, b_src, msg, "selections from the second vector are specified with negative numbers", .{}); 19244 } 19245 19246 break :msg msg; 19247 }; 19248 return sema.failWithOwnedErrorMsg(msg); 19249 } 19250 } 19251 19252 if (try sema.resolveMaybeUndefVal(block, a_src, a)) |a_val| { 19253 if (try sema.resolveMaybeUndefVal(block, b_src, b)) |b_val| { 19254 const values = try sema.arena.alloc(Value, mask_len); 19255 19256 i = 0; 19257 while (i < mask_len) : (i += 1) { 19258 var buf: Value.ElemValueBuffer = undefined; 19259 const mask_elem_val = mask.elemValueBuffer(sema.mod, i, &buf); 19260 if (mask_elem_val.isUndef()) { 19261 values[i] = Value.undef; 19262 continue; 19263 } 19264 const int = mask_elem_val.toSignedInt(); 19265 const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int); 19266 if (int >= 0) { 19267 values[i] = try a_val.elemValue(sema.mod, sema.arena, unsigned); 19268 } else { 19269 values[i] = try b_val.elemValue(sema.mod, sema.arena, unsigned); 19270 } 19271 } 19272 const res_val = try Value.Tag.aggregate.create(sema.arena, values); 19273 return sema.addConstant(res_ty, res_val); 19274 } 19275 } 19276 19277 // All static analysis passed, and not comptime. 19278 // For runtime codegen, vectors a and b must be the same length. Here we 19279 // recursively @shuffle the smaller vector to append undefined elements 19280 // to it up to the length of the longer vector. This recursion terminates 19281 // in 1 call because these calls to analyzeShuffle guarantee a_len == b_len. 19282 if (a_len != b_len) { 19283 const min_len = std.math.min(a_len, b_len); 19284 const max_src = if (a_len > b_len) a_src else b_src; 19285 const max_len = try sema.usizeCast(block, max_src, std.math.max(a_len, b_len)); 19286 19287 const expand_mask_values = try sema.arena.alloc(Value, max_len); 19288 i = 0; 19289 while (i < min_len) : (i += 1) { 19290 expand_mask_values[i] = try Value.Tag.int_u64.create(sema.arena, i); 19291 } 19292 while (i < max_len) : (i += 1) { 19293 expand_mask_values[i] = Value.negative_one; 19294 } 19295 const expand_mask = try Value.Tag.aggregate.create(sema.arena, expand_mask_values); 19296 19297 if (a_len < b_len) { 19298 const undef = try sema.addConstUndef(a_ty); 19299 a = try sema.analyzeShuffle(block, src_node, elem_ty, a, undef, expand_mask, @intCast(u32, max_len)); 19300 } else { 19301 const undef = try sema.addConstUndef(b_ty); 19302 b = try sema.analyzeShuffle(block, src_node, elem_ty, b, undef, expand_mask, @intCast(u32, max_len)); 19303 } 19304 } 19305 19306 const mask_index = @intCast(u32, sema.air_values.items.len); 19307 try sema.air_values.append(sema.gpa, mask); 19308 return block.addInst(.{ 19309 .tag = .shuffle, 19310 .data = .{ .ty_pl = .{ 19311 .ty = try sema.addType(res_ty), 19312 .payload = try block.sema.addExtra(Air.Shuffle{ 19313 .a = a, 19314 .b = b, 19315 .mask = mask_index, 19316 .mask_len = mask_len, 19317 }), 19318 } }, 19319 }); 19320 } 19321 19322 fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 19323 const extra = sema.code.extraData(Zir.Inst.Select, extended.operand).data; 19324 19325 const src = LazySrcLoc.nodeOffset(extra.node); 19326 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 19327 const pred_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 19328 const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node }; 19329 const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = extra.node }; 19330 19331 const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type); 19332 try sema.checkVectorElemType(block, elem_ty_src, elem_ty); 19333 const pred_uncoerced = try sema.resolveInst(extra.pred); 19334 const pred_ty = sema.typeOf(pred_uncoerced); 19335 19336 const vec_len_u64 = switch (try pred_ty.zigTypeTagOrPoison()) { 19337 .Vector, .Array => pred_ty.arrayLen(), 19338 else => return sema.fail(block, pred_src, "expected vector or array, found '{}'", .{pred_ty.fmt(sema.mod)}), 19339 }; 19340 const vec_len = try sema.usizeCast(block, pred_src, vec_len_u64); 19341 19342 const bool_vec_ty = try Type.vector(sema.arena, vec_len, Type.bool); 19343 const pred = try sema.coerce(block, bool_vec_ty, pred_uncoerced, pred_src); 19344 19345 const vec_ty = try Type.vector(sema.arena, vec_len, elem_ty); 19346 const a = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.a), a_src); 19347 const b = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.b), b_src); 19348 19349 const maybe_pred = try sema.resolveMaybeUndefVal(block, pred_src, pred); 19350 const maybe_a = try sema.resolveMaybeUndefVal(block, a_src, a); 19351 const maybe_b = try sema.resolveMaybeUndefVal(block, b_src, b); 19352 19353 const runtime_src = if (maybe_pred) |pred_val| rs: { 19354 if (pred_val.isUndef()) return sema.addConstUndef(vec_ty); 19355 19356 if (maybe_a) |a_val| { 19357 if (a_val.isUndef()) return sema.addConstUndef(vec_ty); 19358 19359 if (maybe_b) |b_val| { 19360 if (b_val.isUndef()) return sema.addConstUndef(vec_ty); 19361 19362 var buf: Value.ElemValueBuffer = undefined; 19363 const elems = try sema.gpa.alloc(Value, vec_len); 19364 for (elems) |*elem, i| { 19365 const pred_elem_val = pred_val.elemValueBuffer(sema.mod, i, &buf); 19366 const should_choose_a = pred_elem_val.toBool(); 19367 if (should_choose_a) { 19368 elem.* = a_val.elemValueBuffer(sema.mod, i, &buf); 19369 } else { 19370 elem.* = b_val.elemValueBuffer(sema.mod, i, &buf); 19371 } 19372 } 19373 19374 return sema.addConstant( 19375 vec_ty, 19376 try Value.Tag.aggregate.create(sema.arena, elems), 19377 ); 19378 } else { 19379 break :rs b_src; 19380 } 19381 } else { 19382 if (maybe_b) |b_val| { 19383 if (b_val.isUndef()) return sema.addConstUndef(vec_ty); 19384 } 19385 break :rs a_src; 19386 } 19387 } else rs: { 19388 if (maybe_a) |a_val| { 19389 if (a_val.isUndef()) return sema.addConstUndef(vec_ty); 19390 } 19391 if (maybe_b) |b_val| { 19392 if (b_val.isUndef()) return sema.addConstUndef(vec_ty); 19393 } 19394 break :rs pred_src; 19395 }; 19396 19397 try sema.requireRuntimeBlock(block, src, runtime_src); 19398 return block.addInst(.{ 19399 .tag = .select, 19400 .data = .{ .pl_op = .{ 19401 .operand = pred, 19402 .payload = try block.sema.addExtra(Air.Bin{ 19403 .lhs = a, 19404 .rhs = b, 19405 }), 19406 } }, 19407 }); 19408 } 19409 19410 fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 19411 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 19412 const extra = sema.code.extraData(Zir.Inst.AtomicLoad, inst_data.payload_index).data; 19413 // zig fmt: off 19414 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 19415 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 19416 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 19417 // zig fmt: on 19418 const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type); 19419 const uncasted_ptr = try sema.resolveInst(extra.ptr); 19420 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true); 19421 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicLoad must be comptime known"); 19422 19423 switch (order) { 19424 .Release, .AcqRel => { 19425 return sema.fail( 19426 block, 19427 order_src, 19428 "@atomicLoad atomic ordering must not be Release or AcqRel", 19429 .{}, 19430 ); 19431 }, 19432 else => {}, 19433 } 19434 19435 if (try sema.typeHasOnePossibleValue(block, elem_ty_src, elem_ty)) |val| { 19436 return sema.addConstant(elem_ty, val); 19437 } 19438 19439 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { 19440 if (try sema.pointerDeref(block, ptr_src, ptr_val, sema.typeOf(ptr))) |elem_val| { 19441 return sema.addConstant(elem_ty, elem_val); 19442 } 19443 } 19444 19445 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); 19446 return block.addInst(.{ 19447 .tag = .atomic_load, 19448 .data = .{ .atomic_load = .{ 19449 .ptr = ptr, 19450 .order = order, 19451 } }, 19452 }); 19453 } 19454 19455 fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 19456 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 19457 const extra = sema.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data; 19458 const src = inst_data.src(); 19459 // zig fmt: off 19460 const elem_ty_src : LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 19461 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 19462 const op_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 19463 const operand_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node }; 19464 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg4 = inst_data.src_node }; 19465 // zig fmt: on 19466 const operand = try sema.resolveInst(extra.operand); 19467 const elem_ty = sema.typeOf(operand); 19468 const uncasted_ptr = try sema.resolveInst(extra.ptr); 19469 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false); 19470 const op = try sema.resolveAtomicRmwOp(block, op_src, extra.operation); 19471 19472 switch (elem_ty.zigTypeTag()) { 19473 .Enum => if (op != .Xchg) { 19474 return sema.fail(block, op_src, "@atomicRmw with enum only allowed with .Xchg", .{}); 19475 }, 19476 .Bool => if (op != .Xchg) { 19477 return sema.fail(block, op_src, "@atomicRmw with bool only allowed with .Xchg", .{}); 19478 }, 19479 .Float => switch (op) { 19480 .Xchg, .Add, .Sub => {}, 19481 else => return sema.fail(block, op_src, "@atomicRmw with float only allowed with .Xchg, .Add, and .Sub", .{}), 19482 }, 19483 else => {}, 19484 } 19485 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicRmW must be comptime known"); 19486 19487 if (order == .Unordered) { 19488 return sema.fail(block, order_src, "@atomicRmw atomic ordering must not be Unordered", .{}); 19489 } 19490 19491 // special case zero bit types 19492 if (try sema.typeHasOnePossibleValue(block, elem_ty_src, elem_ty)) |val| { 19493 return sema.addConstant(elem_ty, val); 19494 } 19495 19496 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { 19497 const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand); 19498 const operand_val = maybe_operand_val orelse { 19499 try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); 19500 break :rs operand_src; 19501 }; 19502 if (ptr_val.isComptimeMutablePtr()) { 19503 const target = sema.mod.getTarget(); 19504 const ptr_ty = sema.typeOf(ptr); 19505 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; 19506 const new_val = switch (op) { 19507 // zig fmt: off 19508 .Xchg => operand_val, 19509 .Add => try sema.numberAddWrap(block, src, stored_val, operand_val, elem_ty), 19510 .Sub => try sema.numberSubWrap(block, src, stored_val, operand_val, elem_ty), 19511 .And => try stored_val.bitwiseAnd (operand_val, elem_ty, sema.arena, target), 19512 .Nand => try stored_val.bitwiseNand (operand_val, elem_ty, sema.arena, target), 19513 .Or => try stored_val.bitwiseOr (operand_val, elem_ty, sema.arena, target), 19514 .Xor => try stored_val.bitwiseXor (operand_val, elem_ty, sema.arena, target), 19515 .Max => stored_val.numberMax (operand_val, target), 19516 .Min => stored_val.numberMin (operand_val, target), 19517 // zig fmt: on 19518 }; 19519 try sema.storePtrVal(block, src, ptr_val, new_val, elem_ty); 19520 return sema.addConstant(elem_ty, stored_val); 19521 } else break :rs ptr_src; 19522 } else ptr_src; 19523 19524 const flags: u32 = @as(u32, @enumToInt(order)) | (@as(u32, @enumToInt(op)) << 3); 19525 19526 try sema.requireRuntimeBlock(block, src, runtime_src); 19527 return block.addInst(.{ 19528 .tag = .atomic_rmw, 19529 .data = .{ .pl_op = .{ 19530 .operand = ptr, 19531 .payload = try sema.addExtra(Air.AtomicRmw{ 19532 .operand = operand, 19533 .flags = flags, 19534 }), 19535 } }, 19536 }); 19537 } 19538 19539 fn zirAtomicStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 19540 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 19541 const extra = sema.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data; 19542 const src = inst_data.src(); 19543 // zig fmt: off 19544 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 19545 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 19546 const operand_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 19547 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node }; 19548 // zig fmt: on 19549 const operand = try sema.resolveInst(extra.operand); 19550 const elem_ty = sema.typeOf(operand); 19551 const uncasted_ptr = try sema.resolveInst(extra.ptr); 19552 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false); 19553 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicStore must be comptime known"); 19554 19555 const air_tag: Air.Inst.Tag = switch (order) { 19556 .Acquire, .AcqRel => { 19557 return sema.fail( 19558 block, 19559 order_src, 19560 "@atomicStore atomic ordering must not be Acquire or AcqRel", 19561 .{}, 19562 ); 19563 }, 19564 .Unordered => .atomic_store_unordered, 19565 .Monotonic => .atomic_store_monotonic, 19566 .Release => .atomic_store_release, 19567 .SeqCst => .atomic_store_seq_cst, 19568 }; 19569 19570 return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag); 19571 } 19572 19573 fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 19574 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 19575 const extra = sema.code.extraData(Zir.Inst.MulAdd, inst_data.payload_index).data; 19576 const src = inst_data.src(); 19577 19578 const mulend1_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 19579 const mulend2_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 19580 const addend_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node }; 19581 19582 const addend = try sema.resolveInst(extra.addend); 19583 const ty = sema.typeOf(addend); 19584 const mulend1 = try sema.coerce(block, ty, try sema.resolveInst(extra.mulend1), mulend1_src); 19585 const mulend2 = try sema.coerce(block, ty, try sema.resolveInst(extra.mulend2), mulend2_src); 19586 19587 const target = sema.mod.getTarget(); 19588 19589 const maybe_mulend1 = try sema.resolveMaybeUndefVal(block, mulend1_src, mulend1); 19590 const maybe_mulend2 = try sema.resolveMaybeUndefVal(block, mulend2_src, mulend2); 19591 const maybe_addend = try sema.resolveMaybeUndefVal(block, addend_src, addend); 19592 19593 switch (ty.zigTypeTag()) { 19594 .ComptimeFloat, .Float, .Vector => {}, 19595 else => return sema.fail(block, src, "expected vector of floats or float type, found '{}'", .{ty.fmt(sema.mod)}), 19596 } 19597 19598 const runtime_src = if (maybe_mulend1) |mulend1_val| rs: { 19599 if (maybe_mulend2) |mulend2_val| { 19600 if (mulend2_val.isUndef()) return sema.addConstUndef(ty); 19601 19602 if (maybe_addend) |addend_val| { 19603 if (addend_val.isUndef()) return sema.addConstUndef(ty); 19604 const result_val = try Value.mulAdd(ty, mulend1_val, mulend2_val, addend_val, sema.arena, target); 19605 return sema.addConstant(ty, result_val); 19606 } else { 19607 break :rs addend_src; 19608 } 19609 } else { 19610 if (maybe_addend) |addend_val| { 19611 if (addend_val.isUndef()) return sema.addConstUndef(ty); 19612 } 19613 break :rs mulend2_src; 19614 } 19615 } else rs: { 19616 if (maybe_mulend2) |mulend2_val| { 19617 if (mulend2_val.isUndef()) return sema.addConstUndef(ty); 19618 } 19619 if (maybe_addend) |addend_val| { 19620 if (addend_val.isUndef()) return sema.addConstUndef(ty); 19621 } 19622 break :rs mulend1_src; 19623 }; 19624 19625 try sema.requireRuntimeBlock(block, src, runtime_src); 19626 return block.addInst(.{ 19627 .tag = .mul_add, 19628 .data = .{ .pl_op = .{ 19629 .operand = addend, 19630 .payload = try sema.addExtra(Air.Bin{ 19631 .lhs = mulend1, 19632 .rhs = mulend2, 19633 }), 19634 } }, 19635 }); 19636 } 19637 19638 fn resolveCallOptions( 19639 sema: *Sema, 19640 block: *Block, 19641 src: LazySrcLoc, 19642 zir_ref: Zir.Inst.Ref, 19643 is_comptime: bool, 19644 is_nosuspend: bool, 19645 func: Air.Inst.Ref, 19646 func_src: LazySrcLoc, 19647 ) CompileError!std.builtin.CallOptions.Modifier { 19648 const call_options_ty = try sema.getBuiltinType(block, src, "CallOptions"); 19649 const air_ref = try sema.resolveInst(zir_ref); 19650 const options = try sema.coerce(block, call_options_ty, air_ref, src); 19651 19652 const modifier_src = sema.maybeOptionsSrc(block, src, "modifier"); 19653 const stack_src = sema.maybeOptionsSrc(block, src, "stack"); 19654 19655 const modifier = try sema.fieldVal(block, src, options, "modifier", modifier_src); 19656 const modifier_val = try sema.resolveConstValue(block, modifier_src, modifier, "call modifier must be comptime known"); 19657 const wanted_modifier = modifier_val.toEnum(std.builtin.CallOptions.Modifier); 19658 19659 const stack = try sema.fieldVal(block, src, options, "stack", stack_src); 19660 const stack_val = try sema.resolveConstValue(block, stack_src, stack, "call stack value must be comptime known"); 19661 19662 if (!stack_val.isNull()) { 19663 return sema.fail(block, stack_src, "TODO: implement @call with stack", .{}); 19664 } 19665 19666 switch (wanted_modifier) { 19667 // These can be upgraded to comptime or nosuspend calls. 19668 .auto, .never_tail, .no_async => { 19669 if (is_comptime) { 19670 if (wanted_modifier == .never_tail) { 19671 return sema.fail(block, modifier_src, "unable to perform 'never_tail' call at compile-time", .{}); 19672 } 19673 return .compile_time; 19674 } 19675 if (is_nosuspend) { 19676 return .no_async; 19677 } 19678 return wanted_modifier; 19679 }, 19680 // These can be upgraded to comptime. nosuspend bit can be safely ignored. 19681 .always_inline, .compile_time => { 19682 _ = (try sema.resolveDefinedValue(block, func_src, func)) orelse { 19683 return sema.fail(block, func_src, "modifier '{s}' requires a comptime-known function", .{@tagName(wanted_modifier)}); 19684 }; 19685 19686 if (is_comptime) { 19687 return .compile_time; 19688 } 19689 return wanted_modifier; 19690 }, 19691 .always_tail => { 19692 if (is_comptime) { 19693 return .compile_time; 19694 } 19695 return wanted_modifier; 19696 }, 19697 .async_kw => { 19698 if (is_nosuspend) { 19699 return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{}); 19700 } 19701 if (is_comptime) { 19702 return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used in combination with comptime function call", .{}); 19703 } 19704 return wanted_modifier; 19705 }, 19706 .never_inline => { 19707 if (is_comptime) { 19708 return sema.fail(block, modifier_src, "unable to perform 'never_inline' call at compile-time", .{}); 19709 } 19710 return wanted_modifier; 19711 }, 19712 } 19713 } 19714 19715 fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 19716 const tracy = trace(@src()); 19717 defer tracy.end(); 19718 19719 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 19720 const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 19721 const func_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 19722 const args_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 19723 const call_src = inst_data.src(); 19724 19725 const extra = sema.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data; 19726 var func = try sema.resolveInst(extra.callee); 19727 const modifier = sema.resolveCallOptions( 19728 block, 19729 .unneeded, 19730 extra.options, 19731 extra.flags.is_comptime, 19732 extra.flags.is_nosuspend, 19733 func, 19734 func_src, 19735 ) catch |err| switch (err) { 19736 error.NeededSourceLocation => { 19737 _ = try sema.resolveCallOptions( 19738 block, 19739 options_src, 19740 extra.options, 19741 extra.flags.is_comptime, 19742 extra.flags.is_nosuspend, 19743 func, 19744 func_src, 19745 ); 19746 return error.AnalysisFail; 19747 }, 19748 else => |e| return e, 19749 }; 19750 const args = try sema.resolveInst(extra.args); 19751 19752 const args_ty = sema.typeOf(args); 19753 if (!args_ty.isTuple() and args_ty.tag() != .empty_struct_literal) { 19754 return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(sema.mod)}); 19755 } 19756 19757 var resolved_args: []Air.Inst.Ref = undefined; 19758 19759 // Desugar bound functions here 19760 var bound_arg_src: ?LazySrcLoc = null; 19761 if (sema.typeOf(func).tag() == .bound_fn) { 19762 bound_arg_src = func_src; 19763 const bound_func = try sema.resolveValue(block, .unneeded, func, undefined); 19764 const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data; 19765 func = bound_data.func_inst; 19766 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount() + 1); 19767 resolved_args[0] = bound_data.arg0_inst; 19768 for (resolved_args[1..]) |*resolved, i| { 19769 resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty); 19770 } 19771 } else { 19772 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount()); 19773 for (resolved_args) |*resolved, i| { 19774 resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty); 19775 } 19776 } 19777 const ensure_result_used = extra.flags.ensure_result_used; 19778 return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src); 19779 } 19780 19781 fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 19782 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 19783 const extra = sema.code.extraData(Zir.Inst.FieldParentPtr, inst_data.payload_index).data; 19784 const src = inst_data.src(); 19785 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 19786 const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 19787 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 19788 19789 const struct_ty = try sema.resolveType(block, ty_src, extra.parent_type); 19790 const field_name = try sema.resolveConstString(block, name_src, extra.field_name, "field name must be comptime known"); 19791 const field_ptr = try sema.resolveInst(extra.field_ptr); 19792 const field_ptr_ty = sema.typeOf(field_ptr); 19793 19794 if (struct_ty.zigTypeTag() != .Struct) { 19795 return sema.fail(block, ty_src, "expected struct type, found '{}'", .{struct_ty.fmt(sema.mod)}); 19796 } 19797 try sema.resolveTypeLayout(block, ty_src, struct_ty); 19798 19799 const field_index = if (struct_ty.isTuple()) blk: { 19800 if (mem.eql(u8, field_name, "len")) { 19801 return sema.fail(block, src, "cannot get @fieldParentPtr of 'len' field of tuple", .{}); 19802 } 19803 break :blk try sema.tupleFieldIndex(block, struct_ty, field_name, name_src); 19804 } else try sema.structFieldIndex(block, struct_ty, field_name, name_src); 19805 19806 try sema.checkPtrOperand(block, ptr_src, field_ptr_ty); 19807 const field_ptr_ty_info = field_ptr_ty.ptrInfo().data; 19808 19809 var ptr_ty_data: Type.Payload.Pointer.Data = .{ 19810 .pointee_type = struct_ty.structFieldType(field_index), 19811 .mutable = field_ptr_ty_info.mutable, 19812 .@"addrspace" = field_ptr_ty_info.@"addrspace", 19813 }; 19814 19815 if (struct_ty.containerLayout() == .Packed) { 19816 return sema.fail(block, src, "TODO handle packed structs with @fieldParentPtr", .{}); 19817 } else { 19818 ptr_ty_data.@"align" = if (struct_ty.castTag(.@"struct")) |struct_obj| b: { 19819 break :b struct_obj.data.fields.values()[field_index].abi_align; 19820 } else 0; 19821 } 19822 19823 const actual_field_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_ty_data); 19824 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, ptr_src); 19825 19826 ptr_ty_data.pointee_type = struct_ty; 19827 const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data); 19828 19829 if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| { 19830 const payload = field_ptr_val.castTag(.field_ptr) orelse { 19831 return sema.fail(block, ptr_src, "pointer value not based on parent struct", .{}); 19832 }; 19833 if (payload.data.field_index != field_index) { 19834 const msg = msg: { 19835 const msg = try sema.errMsg( 19836 block, 19837 src, 19838 "field '{s}' has index '{d}' but pointer value is index '{d}' of struct '{}'", 19839 .{ 19840 field_name, 19841 field_index, 19842 payload.data.field_index, 19843 struct_ty.fmt(sema.mod), 19844 }, 19845 ); 19846 errdefer msg.destroy(sema.gpa); 19847 try sema.addDeclaredHereNote(msg, struct_ty); 19848 break :msg msg; 19849 }; 19850 return sema.failWithOwnedErrorMsg(msg); 19851 } 19852 return sema.addConstant(result_ptr, payload.data.container_ptr); 19853 } 19854 19855 try sema.requireRuntimeBlock(block, src, ptr_src); 19856 return block.addInst(.{ 19857 .tag = .field_parent_ptr, 19858 .data = .{ .ty_pl = .{ 19859 .ty = try sema.addType(result_ptr), 19860 .payload = try block.sema.addExtra(Air.FieldParentPtr{ 19861 .field_ptr = casted_field_ptr, 19862 .field_index = @intCast(u32, field_index), 19863 }), 19864 } }, 19865 }); 19866 } 19867 19868 fn zirMinMax( 19869 sema: *Sema, 19870 block: *Block, 19871 inst: Zir.Inst.Index, 19872 comptime air_tag: Air.Inst.Tag, 19873 ) CompileError!Air.Inst.Ref { 19874 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 19875 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 19876 const src = inst_data.src(); 19877 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 19878 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 19879 const lhs = try sema.resolveInst(extra.lhs); 19880 const rhs = try sema.resolveInst(extra.rhs); 19881 try sema.checkNumericType(block, lhs_src, sema.typeOf(lhs)); 19882 try sema.checkNumericType(block, rhs_src, sema.typeOf(rhs)); 19883 return sema.analyzeMinMax(block, src, lhs, rhs, air_tag, lhs_src, rhs_src); 19884 } 19885 19886 fn analyzeMinMax( 19887 sema: *Sema, 19888 block: *Block, 19889 src: LazySrcLoc, 19890 lhs: Air.Inst.Ref, 19891 rhs: Air.Inst.Ref, 19892 comptime air_tag: Air.Inst.Tag, 19893 lhs_src: LazySrcLoc, 19894 rhs_src: LazySrcLoc, 19895 ) CompileError!Air.Inst.Ref { 19896 const simd_op = try sema.checkSimdBinOp(block, src, lhs, rhs, lhs_src, rhs_src); 19897 19898 // TODO @maximum(max_int, undefined) should return max_int 19899 19900 const runtime_src = if (simd_op.lhs_val) |lhs_val| rs: { 19901 if (lhs_val.isUndef()) return sema.addConstUndef(simd_op.result_ty); 19902 19903 const rhs_val = simd_op.rhs_val orelse break :rs rhs_src; 19904 19905 if (rhs_val.isUndef()) return sema.addConstUndef(simd_op.result_ty); 19906 19907 const opFunc = switch (air_tag) { 19908 .min => Value.numberMin, 19909 .max => Value.numberMax, 19910 else => unreachable, 19911 }; 19912 const target = sema.mod.getTarget(); 19913 const vec_len = simd_op.len orelse { 19914 const result_val = opFunc(lhs_val, rhs_val, target); 19915 return sema.addConstant(simd_op.result_ty, result_val); 19916 }; 19917 var lhs_buf: Value.ElemValueBuffer = undefined; 19918 var rhs_buf: Value.ElemValueBuffer = undefined; 19919 const elems = try sema.arena.alloc(Value, vec_len); 19920 for (elems) |*elem, i| { 19921 const lhs_elem_val = lhs_val.elemValueBuffer(sema.mod, i, &lhs_buf); 19922 const rhs_elem_val = rhs_val.elemValueBuffer(sema.mod, i, &rhs_buf); 19923 elem.* = opFunc(lhs_elem_val, rhs_elem_val, target); 19924 } 19925 return sema.addConstant( 19926 simd_op.result_ty, 19927 try Value.Tag.aggregate.create(sema.arena, elems), 19928 ); 19929 } else rs: { 19930 if (simd_op.rhs_val) |rhs_val| { 19931 if (rhs_val.isUndef()) return sema.addConstUndef(simd_op.result_ty); 19932 } 19933 break :rs lhs_src; 19934 }; 19935 19936 try sema.requireRuntimeBlock(block, src, runtime_src); 19937 return block.addBinOp(air_tag, simd_op.lhs, simd_op.rhs); 19938 } 19939 19940 fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 19941 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 19942 const extra = sema.code.extraData(Zir.Inst.Memcpy, inst_data.payload_index).data; 19943 const src = inst_data.src(); 19944 const dest_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 19945 const src_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 19946 const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 19947 const uncasted_dest_ptr = try sema.resolveInst(extra.dest); 19948 19949 // TODO AstGen's coerced_ty cannot handle volatile here 19950 var dest_ptr_info = Type.initTag(.manyptr_u8).ptrInfo().data; 19951 dest_ptr_info.@"volatile" = sema.typeOf(uncasted_dest_ptr).isVolatilePtr(); 19952 const dest_ptr_ty = try Type.ptr(sema.arena, sema.mod, dest_ptr_info); 19953 const dest_ptr = try sema.coerce(block, dest_ptr_ty, uncasted_dest_ptr, dest_src); 19954 19955 const uncasted_src_ptr = try sema.resolveInst(extra.source); 19956 var src_ptr_info = Type.initTag(.manyptr_const_u8).ptrInfo().data; 19957 src_ptr_info.@"volatile" = sema.typeOf(uncasted_src_ptr).isVolatilePtr(); 19958 const src_ptr_ty = try Type.ptr(sema.arena, sema.mod, src_ptr_info); 19959 const src_ptr = try sema.coerce(block, src_ptr_ty, uncasted_src_ptr, src_src); 19960 const len = try sema.coerce(block, Type.usize, try sema.resolveInst(extra.byte_count), len_src); 19961 19962 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: { 19963 if (!dest_ptr_val.isComptimeMutablePtr()) break :rs dest_src; 19964 if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |src_ptr_val| { 19965 if (!src_ptr_val.isComptimeMutablePtr()) break :rs src_src; 19966 if (try sema.resolveDefinedValue(block, len_src, len)) |len_val| { 19967 _ = len_val; 19968 return sema.fail(block, src, "TODO: Sema.zirMemcpy at comptime", .{}); 19969 } else break :rs len_src; 19970 } else break :rs src_src; 19971 } else dest_src; 19972 19973 try sema.requireRuntimeBlock(block, src, runtime_src); 19974 _ = try block.addInst(.{ 19975 .tag = .memcpy, 19976 .data = .{ .pl_op = .{ 19977 .operand = dest_ptr, 19978 .payload = try sema.addExtra(Air.Bin{ 19979 .lhs = src_ptr, 19980 .rhs = len, 19981 }), 19982 } }, 19983 }); 19984 } 19985 19986 fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 19987 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 19988 const extra = sema.code.extraData(Zir.Inst.Memset, inst_data.payload_index).data; 19989 const src = inst_data.src(); 19990 const dest_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; 19991 const value_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; 19992 const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; 19993 const uncasted_dest_ptr = try sema.resolveInst(extra.dest); 19994 19995 // TODO AstGen's coerced_ty cannot handle volatile here 19996 var ptr_info = Type.initTag(.manyptr_u8).ptrInfo().data; 19997 ptr_info.@"volatile" = sema.typeOf(uncasted_dest_ptr).isVolatilePtr(); 19998 const dest_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); 19999 const dest_ptr = try sema.coerce(block, dest_ptr_ty, uncasted_dest_ptr, dest_src); 20000 20001 const value = try sema.coerce(block, Type.u8, try sema.resolveInst(extra.byte), value_src); 20002 const len = try sema.coerce(block, Type.usize, try sema.resolveInst(extra.byte_count), len_src); 20003 20004 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: { 20005 if (!ptr_val.isComptimeMutablePtr()) break :rs dest_src; 20006 if (try sema.resolveDefinedValue(block, len_src, len)) |len_val| { 20007 if (try sema.resolveMaybeUndefVal(block, value_src, value)) |val| { 20008 _ = len_val; 20009 _ = val; 20010 return sema.fail(block, src, "TODO: Sema.zirMemset at comptime", .{}); 20011 } else break :rs value_src; 20012 } else break :rs len_src; 20013 } else dest_src; 20014 20015 try sema.requireRuntimeBlock(block, src, runtime_src); 20016 _ = try block.addInst(.{ 20017 .tag = .memset, 20018 .data = .{ .pl_op = .{ 20019 .operand = dest_ptr, 20020 .payload = try sema.addExtra(Air.Bin{ 20021 .lhs = value, 20022 .rhs = len, 20023 }), 20024 } }, 20025 }); 20026 } 20027 20028 fn zirBuiltinAsyncCall(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 20029 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 20030 const src = LazySrcLoc.nodeOffset(extra.node); 20031 return sema.failWithUseOfAsync(block, src); 20032 } 20033 20034 fn zirResume(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20035 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 20036 const src = inst_data.src(); 20037 return sema.failWithUseOfAsync(block, src); 20038 } 20039 20040 fn zirAwait( 20041 sema: *Sema, 20042 block: *Block, 20043 inst: Zir.Inst.Index, 20044 ) CompileError!Air.Inst.Ref { 20045 const inst_data = sema.code.instructions.items(.data)[inst].un_node; 20046 const src = inst_data.src(); 20047 20048 return sema.failWithUseOfAsync(block, src); 20049 } 20050 20051 fn zirAwaitNosuspend( 20052 sema: *Sema, 20053 block: *Block, 20054 extended: Zir.Inst.Extended.InstData, 20055 ) CompileError!Air.Inst.Ref { 20056 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 20057 const src = LazySrcLoc.nodeOffset(extra.node); 20058 20059 return sema.failWithUseOfAsync(block, src); 20060 } 20061 20062 fn zirVarExtended( 20063 sema: *Sema, 20064 block: *Block, 20065 extended: Zir.Inst.Extended.InstData, 20066 ) CompileError!Air.Inst.Ref { 20067 const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand); 20068 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 }; 20069 const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 }; 20070 const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small); 20071 20072 var extra_index: usize = extra.end; 20073 20074 const lib_name: ?[]const u8 = if (small.has_lib_name) blk: { 20075 const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]); 20076 extra_index += 1; 20077 break :blk lib_name; 20078 } else null; 20079 20080 // ZIR supports encoding this information but it is not used; the information 20081 // is encoded via the Decl entry. 20082 assert(!small.has_align); 20083 20084 const uncasted_init: Air.Inst.Ref = if (small.has_init) blk: { 20085 const init_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 20086 extra_index += 1; 20087 break :blk try sema.resolveInst(init_ref); 20088 } else .none; 20089 20090 const have_ty = extra.data.var_type != .none; 20091 const var_ty = if (have_ty) 20092 try sema.resolveType(block, ty_src, extra.data.var_type) 20093 else 20094 sema.typeOf(uncasted_init); 20095 20096 const init_val = if (uncasted_init != .none) blk: { 20097 const init = if (have_ty) 20098 try sema.coerce(block, var_ty, uncasted_init, init_src) 20099 else 20100 uncasted_init; 20101 20102 break :blk (try sema.resolveMaybeUndefVal(block, init_src, init)) orelse 20103 return sema.failWithNeededComptime(block, init_src, "container level variable initializers must be comptime known"); 20104 } else Value.initTag(.unreachable_value); 20105 20106 try sema.validateVarType(block, ty_src, var_ty, small.is_extern); 20107 20108 const new_var = try sema.gpa.create(Module.Var); 20109 errdefer sema.gpa.destroy(new_var); 20110 20111 log.debug("created variable {*} owner_decl: {*} ({s})", .{ 20112 new_var, sema.owner_decl, sema.owner_decl.name, 20113 }); 20114 20115 new_var.* = .{ 20116 .owner_decl = sema.owner_decl_index, 20117 .init = init_val, 20118 .is_extern = small.is_extern, 20119 .is_mutable = true, // TODO get rid of this unused field 20120 .is_threadlocal = small.is_threadlocal, 20121 .is_weak_linkage = false, 20122 .lib_name = null, 20123 }; 20124 20125 if (lib_name) |lname| { 20126 new_var.lib_name = try sema.handleExternLibName(block, ty_src, lname); 20127 } 20128 20129 const result = try sema.addConstant( 20130 var_ty, 20131 try Value.Tag.variable.create(sema.arena, new_var), 20132 ); 20133 return result; 20134 } 20135 20136 fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 20137 const tracy = trace(@src()); 20138 defer tracy.end(); 20139 20140 const inst_data = sema.code.instructions.items(.data)[inst].pl_node; 20141 const extra = sema.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index); 20142 const target = sema.mod.getTarget(); 20143 20144 const align_src: LazySrcLoc = .{ .node_offset_fn_type_align = inst_data.src_node }; 20145 const addrspace_src: LazySrcLoc = .{ .node_offset_fn_type_addrspace = inst_data.src_node }; 20146 const section_src: LazySrcLoc = .{ .node_offset_fn_type_section = inst_data.src_node }; 20147 const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node }; 20148 const ret_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = inst_data.src_node }; 20149 const has_body = extra.data.body_len != 0; 20150 20151 var extra_index: usize = extra.end; 20152 20153 const lib_name: ?[]const u8 = if (extra.data.bits.has_lib_name) blk: { 20154 const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]); 20155 extra_index += 1; 20156 break :blk lib_name; 20157 } else null; 20158 20159 if (has_body and 20160 (extra.data.bits.has_align_body or extra.data.bits.has_align_ref) and 20161 !target_util.supportsFunctionAlignment(target)) 20162 { 20163 return sema.fail(block, align_src, "target does not support function alignment", .{}); 20164 } 20165 20166 const @"align": ?u32 = if (extra.data.bits.has_align_body) blk: { 20167 const body_len = sema.code.extra[extra_index]; 20168 extra_index += 1; 20169 const body = sema.code.extra[extra_index..][0..body_len]; 20170 extra_index += body.len; 20171 20172 const val = try sema.resolveGenericBody(block, align_src, body, inst, Type.u29, "alignment must be comptime known"); 20173 if (val.tag() == .generic_poison) { 20174 break :blk null; 20175 } 20176 const alignment = @intCast(u32, val.toUnsignedInt(target)); 20177 try sema.validateAlign(block, align_src, alignment); 20178 if (alignment == target_util.defaultFunctionAlignment(target)) { 20179 break :blk 0; 20180 } else { 20181 break :blk alignment; 20182 } 20183 } else if (extra.data.bits.has_align_ref) blk: { 20184 const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 20185 extra_index += 1; 20186 const align_tv = sema.resolveInstConst(block, align_src, align_ref, "alignment must be comptime known") catch |err| switch (err) { 20187 error.GenericPoison => { 20188 break :blk null; 20189 }, 20190 else => |e| return e, 20191 }; 20192 const alignment = @intCast(u32, align_tv.val.toUnsignedInt(target)); 20193 try sema.validateAlign(block, align_src, alignment); 20194 if (alignment == target_util.defaultFunctionAlignment(target)) { 20195 break :blk 0; 20196 } else { 20197 break :blk alignment; 20198 } 20199 } else 0; 20200 20201 const @"addrspace": ?std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: { 20202 const body_len = sema.code.extra[extra_index]; 20203 extra_index += 1; 20204 const body = sema.code.extra[extra_index..][0..body_len]; 20205 extra_index += body.len; 20206 20207 const addrspace_ty = try sema.getBuiltinType(block, addrspace_src, "AddressSpace"); 20208 const val = try sema.resolveGenericBody(block, addrspace_src, body, inst, addrspace_ty, "addrespace must be comptime known"); 20209 if (val.tag() == .generic_poison) { 20210 break :blk null; 20211 } 20212 break :blk val.toEnum(std.builtin.AddressSpace); 20213 } else if (extra.data.bits.has_addrspace_ref) blk: { 20214 const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 20215 extra_index += 1; 20216 const addrspace_tv = sema.resolveInstConst(block, addrspace_src, addrspace_ref, "addrespace must be comptime known") catch |err| switch (err) { 20217 error.GenericPoison => { 20218 break :blk null; 20219 }, 20220 else => |e| return e, 20221 }; 20222 break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace); 20223 } else target_util.defaultAddressSpace(target, .function); 20224 20225 const @"linksection": FuncLinkSection = if (extra.data.bits.has_section_body) blk: { 20226 const body_len = sema.code.extra[extra_index]; 20227 extra_index += 1; 20228 const body = sema.code.extra[extra_index..][0..body_len]; 20229 extra_index += body.len; 20230 20231 const val = try sema.resolveGenericBody(block, section_src, body, inst, Type.initTag(.const_slice_u8), "linksection must be comptime known"); 20232 if (val.tag() == .generic_poison) { 20233 break :blk FuncLinkSection{ .generic = {} }; 20234 } 20235 return sema.fail(block, section_src, "TODO implement linksection on functions", .{}); 20236 } else if (extra.data.bits.has_section_ref) blk: { 20237 const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 20238 extra_index += 1; 20239 const section_tv = sema.resolveInstConst(block, section_src, section_ref, "linksection must be comptime known") catch |err| switch (err) { 20240 error.GenericPoison => { 20241 break :blk FuncLinkSection{ .generic = {} }; 20242 }, 20243 else => |e| return e, 20244 }; 20245 _ = section_tv; 20246 return sema.fail(block, section_src, "TODO implement linksection on functions", .{}); 20247 } else FuncLinkSection{ .default = {} }; 20248 20249 const cc: ?std.builtin.CallingConvention = if (extra.data.bits.has_cc_body) blk: { 20250 const body_len = sema.code.extra[extra_index]; 20251 extra_index += 1; 20252 const body = sema.code.extra[extra_index..][0..body_len]; 20253 extra_index += body.len; 20254 20255 const cc_ty = try sema.getBuiltinType(block, addrspace_src, "CallingConvention"); 20256 const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty, "calling convention must be comptime known"); 20257 if (val.tag() == .generic_poison) { 20258 break :blk null; 20259 } 20260 break :blk val.toEnum(std.builtin.CallingConvention); 20261 } else if (extra.data.bits.has_cc_ref) blk: { 20262 const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 20263 extra_index += 1; 20264 const cc_tv = sema.resolveInstConst(block, cc_src, cc_ref, "calling convention must be comptime known") catch |err| switch (err) { 20265 error.GenericPoison => { 20266 break :blk null; 20267 }, 20268 else => |e| return e, 20269 }; 20270 break :blk cc_tv.val.toEnum(std.builtin.CallingConvention); 20271 } else std.builtin.CallingConvention.Unspecified; 20272 20273 const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: { 20274 const body_len = sema.code.extra[extra_index]; 20275 extra_index += 1; 20276 const body = sema.code.extra[extra_index..][0..body_len]; 20277 extra_index += body.len; 20278 20279 const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type, "return type must be comptime known"); 20280 var buffer: Value.ToTypeBuffer = undefined; 20281 const ty = try val.toType(&buffer).copy(sema.arena); 20282 break :blk ty; 20283 } else if (extra.data.bits.has_ret_ty_ref) blk: { 20284 const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); 20285 extra_index += 1; 20286 const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref, "return type must be comptime known") catch |err| switch (err) { 20287 error.GenericPoison => { 20288 break :blk Type.initTag(.generic_poison); 20289 }, 20290 else => |e| return e, 20291 }; 20292 var buffer: Value.ToTypeBuffer = undefined; 20293 const ty = try ret_ty_tv.val.toType(&buffer).copy(sema.arena); 20294 break :blk ty; 20295 } else Type.void; 20296 20297 const noalias_bits: u32 = if (extra.data.bits.has_any_noalias) blk: { 20298 const x = sema.code.extra[extra_index]; 20299 extra_index += 1; 20300 break :blk x; 20301 } else 0; 20302 20303 var src_locs: Zir.Inst.Func.SrcLocs = undefined; 20304 if (has_body) { 20305 extra_index += extra.data.body_len; 20306 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; 20307 } 20308 20309 const is_var_args = extra.data.bits.is_var_args; 20310 const is_inferred_error = extra.data.bits.is_inferred_error; 20311 const is_extern = extra.data.bits.is_extern; 20312 const is_noinline = extra.data.bits.is_noinline; 20313 20314 return sema.funcCommon( 20315 block, 20316 inst_data.src_node, 20317 inst, 20318 @"align", 20319 @"addrspace", 20320 @"linksection", 20321 cc, 20322 ret_ty, 20323 is_var_args, 20324 is_inferred_error, 20325 is_extern, 20326 has_body, 20327 src_locs, 20328 lib_name, 20329 noalias_bits, 20330 is_noinline, 20331 ); 20332 } 20333 20334 fn zirCUndef( 20335 sema: *Sema, 20336 block: *Block, 20337 extended: Zir.Inst.Extended.InstData, 20338 ) CompileError!Air.Inst.Ref { 20339 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 20340 const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 20341 20342 const name = try sema.resolveConstString(block, src, extra.operand, "name of macro being undefined must be comptime known"); 20343 try block.c_import_buf.?.writer().print("#undefine {s}\n", .{name}); 20344 return Air.Inst.Ref.void_value; 20345 } 20346 20347 fn zirCInclude( 20348 sema: *Sema, 20349 block: *Block, 20350 extended: Zir.Inst.Extended.InstData, 20351 ) CompileError!Air.Inst.Ref { 20352 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 20353 const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 20354 20355 const name = try sema.resolveConstString(block, src, extra.operand, "path being included must be comptime known"); 20356 try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name}); 20357 return Air.Inst.Ref.void_value; 20358 } 20359 20360 fn zirCDefine( 20361 sema: *Sema, 20362 block: *Block, 20363 extended: Zir.Inst.Extended.InstData, 20364 ) CompileError!Air.Inst.Ref { 20365 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; 20366 const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 20367 const val_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 20368 20369 const name = try sema.resolveConstString(block, name_src, extra.lhs, "name of macro being undefined must be comptime known"); 20370 const rhs = try sema.resolveInst(extra.rhs); 20371 if (sema.typeOf(rhs).zigTypeTag() != .Void) { 20372 const value = try sema.resolveConstString(block, val_src, extra.rhs, "value of macro being undefined must be comptime known"); 20373 try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value }); 20374 } else { 20375 try block.c_import_buf.?.writer().print("#define {s}\n", .{name}); 20376 } 20377 return Air.Inst.Ref.void_value; 20378 } 20379 20380 fn zirWasmMemorySize( 20381 sema: *Sema, 20382 block: *Block, 20383 extended: Zir.Inst.Extended.InstData, 20384 ) CompileError!Air.Inst.Ref { 20385 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 20386 const index_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 20387 const builtin_src = LazySrcLoc.nodeOffset(extra.node); 20388 const target = sema.mod.getTarget(); 20389 if (!target.isWasm()) { 20390 return sema.fail(block, builtin_src, "builtin @wasmMemorySize is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)}); 20391 } 20392 20393 const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.operand, Type.u32, "wasm memory size index must be comptime known")); 20394 try sema.requireRuntimeBlock(block, builtin_src, null); 20395 return block.addInst(.{ 20396 .tag = .wasm_memory_size, 20397 .data = .{ .pl_op = .{ 20398 .operand = .none, 20399 .payload = index, 20400 } }, 20401 }); 20402 } 20403 20404 fn zirWasmMemoryGrow( 20405 sema: *Sema, 20406 block: *Block, 20407 extended: Zir.Inst.Extended.InstData, 20408 ) CompileError!Air.Inst.Ref { 20409 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; 20410 const builtin_src = LazySrcLoc.nodeOffset(extra.node); 20411 const index_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 20412 const delta_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 20413 const target = sema.mod.getTarget(); 20414 if (!target.isWasm()) { 20415 return sema.fail(block, builtin_src, "builtin @wasmMemoryGrow is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)}); 20416 } 20417 20418 const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.lhs, Type.u32, "wasm memory size index must be comptime known")); 20419 const delta = try sema.coerce(block, Type.u32, try sema.resolveInst(extra.rhs), delta_src); 20420 20421 try sema.requireRuntimeBlock(block, builtin_src, null); 20422 return block.addInst(.{ 20423 .tag = .wasm_memory_grow, 20424 .data = .{ .pl_op = .{ 20425 .operand = delta, 20426 .payload = index, 20427 } }, 20428 }); 20429 } 20430 20431 fn resolvePrefetchOptions( 20432 sema: *Sema, 20433 block: *Block, 20434 src: LazySrcLoc, 20435 zir_ref: Zir.Inst.Ref, 20436 ) CompileError!std.builtin.PrefetchOptions { 20437 const options_ty = try sema.getBuiltinType(block, src, "PrefetchOptions"); 20438 const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src); 20439 const target = sema.mod.getTarget(); 20440 20441 const rw_src = sema.maybeOptionsSrc(block, src, "rw"); 20442 const locality_src = sema.maybeOptionsSrc(block, src, "locality"); 20443 const cache_src = sema.maybeOptionsSrc(block, src, "cache"); 20444 20445 const rw = try sema.fieldVal(block, src, options, "rw", rw_src); 20446 const rw_val = try sema.resolveConstValue(block, rw_src, rw, "prefetch read/write must be comptime known"); 20447 20448 const locality = try sema.fieldVal(block, src, options, "locality", locality_src); 20449 const locality_val = try sema.resolveConstValue(block, locality_src, locality, "prefetch locality must be comptime known"); 20450 20451 const cache = try sema.fieldVal(block, src, options, "cache", cache_src); 20452 const cache_val = try sema.resolveConstValue(block, cache_src, cache, "prefetch cache must be comptime known"); 20453 20454 return std.builtin.PrefetchOptions{ 20455 .rw = rw_val.toEnum(std.builtin.PrefetchOptions.Rw), 20456 .locality = @intCast(u2, locality_val.toUnsignedInt(target)), 20457 .cache = cache_val.toEnum(std.builtin.PrefetchOptions.Cache), 20458 }; 20459 } 20460 20461 fn zirPrefetch( 20462 sema: *Sema, 20463 block: *Block, 20464 extended: Zir.Inst.Extended.InstData, 20465 ) CompileError!Air.Inst.Ref { 20466 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; 20467 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 20468 const opts_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 20469 const ptr = try sema.resolveInst(extra.lhs); 20470 try sema.checkPtrOperand(block, ptr_src, sema.typeOf(ptr)); 20471 20472 const options = sema.resolvePrefetchOptions(block, .unneeded, extra.rhs) catch |err| switch (err) { 20473 error.NeededSourceLocation => { 20474 _ = try sema.resolvePrefetchOptions(block, opts_src, extra.rhs); 20475 return error.AnalysisFail; 20476 }, 20477 else => |e| return e, 20478 }; 20479 20480 if (!block.is_comptime) { 20481 _ = try block.addInst(.{ 20482 .tag = .prefetch, 20483 .data = .{ .prefetch = .{ 20484 .ptr = ptr, 20485 .rw = options.rw, 20486 .locality = options.locality, 20487 .cache = options.cache, 20488 } }, 20489 }); 20490 } 20491 20492 return Air.Inst.Ref.void_value; 20493 } 20494 20495 fn resolveExternOptions( 20496 sema: *Sema, 20497 block: *Block, 20498 src: LazySrcLoc, 20499 zir_ref: Zir.Inst.Ref, 20500 ) CompileError!std.builtin.ExternOptions { 20501 const options_inst = try sema.resolveInst(zir_ref); 20502 const extern_options_ty = try sema.getBuiltinType(block, src, "ExternOptions"); 20503 const options = try sema.coerce(block, extern_options_ty, options_inst, src); 20504 const mod = sema.mod; 20505 20506 const name_src = sema.maybeOptionsSrc(block, src, "name"); 20507 const library_src = sema.maybeOptionsSrc(block, src, "library"); 20508 const linkage_src = sema.maybeOptionsSrc(block, src, "linkage"); 20509 const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local"); 20510 20511 const name_ref = try sema.fieldVal(block, src, options, "name", name_src); 20512 const name_val = try sema.resolveConstValue(block, name_src, name_ref, "name of the extern symbol must be comptime known"); 20513 const name = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, mod); 20514 20515 const library_name_inst = try sema.fieldVal(block, src, options, "library_name", library_src); 20516 const library_name_val = try sema.resolveConstValue(block, library_src, library_name_inst, "library in which extern symbol is must be comptime known"); 20517 20518 const linkage_ref = try sema.fieldVal(block, src, options, "linkage", linkage_src); 20519 const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_ref, "linkage of the extern symbol must be comptime known"); 20520 const linkage = linkage_val.toEnum(std.builtin.GlobalLinkage); 20521 20522 const is_thread_local = try sema.fieldVal(block, src, options, "is_thread_local", thread_local_src); 20523 const is_thread_local_val = try sema.resolveConstValue(block, thread_local_src, is_thread_local, "threadlocality of the extern symbol must be comptime known"); 20524 20525 const library_name = if (!library_name_val.isNull()) blk: { 20526 const payload = library_name_val.castTag(.opt_payload).?.data; 20527 const library_name = try payload.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, mod); 20528 if (library_name.len == 0) { 20529 return sema.fail(block, library_src, "library name name cannot be empty", .{}); 20530 } 20531 break :blk try sema.handleExternLibName(block, library_src, library_name); 20532 } else null; 20533 20534 if (name.len == 0) { 20535 return sema.fail(block, name_src, "extern symbol name cannot be empty", .{}); 20536 } 20537 20538 if (linkage != .Weak and linkage != .Strong) { 20539 return sema.fail(block, linkage_src, "extern symbol must use strong or weak linkage", .{}); 20540 } 20541 20542 return std.builtin.ExternOptions{ 20543 .name = name, 20544 .library_name = library_name, 20545 .linkage = linkage, 20546 .is_thread_local = is_thread_local_val.toBool(), 20547 }; 20548 } 20549 20550 fn zirBuiltinExtern( 20551 sema: *Sema, 20552 block: *Block, 20553 extended: Zir.Inst.Extended.InstData, 20554 ) CompileError!Air.Inst.Ref { 20555 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; 20556 const src = LazySrcLoc.nodeOffset(extra.node); 20557 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; 20558 const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; 20559 20560 var ty = try sema.resolveType(block, ty_src, extra.lhs); 20561 if (!ty.isPtrAtRuntime()) { 20562 return sema.fail(block, ty_src, "expected (optional) pointer", .{}); 20563 } 20564 20565 const options = sema.resolveExternOptions(block, .unneeded, extra.rhs) catch |err| switch (err) { 20566 error.NeededSourceLocation => { 20567 _ = try sema.resolveExternOptions(block, options_src, extra.rhs); 20568 return error.AnalysisFail; 20569 }, 20570 else => |e| return e, 20571 }; 20572 20573 if (options.linkage == .Weak and !ty.ptrAllowsZero()) { 20574 ty = try Type.optional(sema.arena, ty); 20575 } 20576 20577 // TODO check duplicate extern 20578 20579 const new_decl_index = try sema.mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, null); 20580 errdefer sema.mod.destroyDecl(new_decl_index); 20581 const new_decl = sema.mod.declPtr(new_decl_index); 20582 new_decl.name = try sema.gpa.dupeZ(u8, options.name); 20583 20584 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); 20585 errdefer new_decl_arena.deinit(); 20586 const new_decl_arena_allocator = new_decl_arena.allocator(); 20587 20588 const new_var = try new_decl_arena_allocator.create(Module.Var); 20589 errdefer new_decl_arena_allocator.destroy(new_var); 20590 20591 new_var.* = .{ 20592 .owner_decl = sema.owner_decl_index, 20593 .init = Value.initTag(.unreachable_value), 20594 .is_extern = true, 20595 .is_mutable = false, // TODO get rid of this unused field 20596 .is_threadlocal = options.is_thread_local, 20597 .is_weak_linkage = options.linkage == .Weak, 20598 .lib_name = null, 20599 }; 20600 20601 new_decl.src_line = sema.owner_decl.src_line; 20602 new_decl.ty = try ty.copy(new_decl_arena_allocator); 20603 new_decl.val = try Value.Tag.variable.create(new_decl_arena_allocator, new_var); 20604 new_decl.@"align" = 0; 20605 new_decl.@"linksection" = null; 20606 new_decl.has_tv = true; 20607 new_decl.analysis = .complete; 20608 new_decl.generation = sema.mod.generation; 20609 20610 const arena_state = try new_decl_arena_allocator.create(std.heap.ArenaAllocator.State); 20611 arena_state.* = new_decl_arena.state; 20612 new_decl.value_arena = arena_state; 20613 20614 const ref = try sema.analyzeDeclRef(new_decl_index); 20615 try sema.requireRuntimeBlock(block, src, null); 20616 return block.addBitCast(ty, ref); 20617 } 20618 20619 /// Asserts that the block is not comptime. 20620 fn requireFunctionBlock(sema: *Sema, block: *Block, src: LazySrcLoc) !void { 20621 assert(!block.is_comptime); 20622 if (sema.func == null and !block.is_typeof and !block.is_coerce_result_ptr) { 20623 return sema.fail(block, src, "instruction illegal outside function body", .{}); 20624 } 20625 } 20626 20627 fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: ?LazySrcLoc) !void { 20628 if (block.is_comptime) { 20629 const msg = msg: { 20630 const msg = try sema.errMsg(block, src, "unable to evaluate comptime expression", .{}); 20631 errdefer msg.destroy(sema.gpa); 20632 20633 if (runtime_src) |some| { 20634 try sema.errNote(block, some, msg, "operation is runtime due to this operand", .{}); 20635 } 20636 break :msg msg; 20637 }; 20638 return sema.failWithOwnedErrorMsg(msg); 20639 } 20640 try sema.requireFunctionBlock(block, src); 20641 } 20642 20643 /// Emit a compile error if type cannot be used for a runtime variable. 20644 fn validateVarType( 20645 sema: *Sema, 20646 block: *Block, 20647 src: LazySrcLoc, 20648 var_ty: Type, 20649 is_extern: bool, 20650 ) CompileError!void { 20651 if (try sema.validateRunTimeType(block, src, var_ty, is_extern)) return; 20652 20653 const mod = sema.mod; 20654 20655 const msg = msg: { 20656 const msg = try sema.errMsg(block, src, "variable of type '{}' must be const or comptime", .{var_ty.fmt(mod)}); 20657 errdefer msg.destroy(sema.gpa); 20658 20659 const src_decl = mod.declPtr(block.src_decl); 20660 try sema.explainWhyTypeIsComptime(block, src, msg, src.toSrcLoc(src_decl), var_ty); 20661 if (var_ty.zigTypeTag() == .ComptimeInt or var_ty.zigTypeTag() == .ComptimeFloat) { 20662 try sema.errNote(block, src, msg, "to modify this variable at runtime, it must be given an explicit fixed-size number type", .{}); 20663 } 20664 20665 break :msg msg; 20666 }; 20667 return sema.failWithOwnedErrorMsg(msg); 20668 } 20669 20670 fn validateRunTimeType( 20671 sema: *Sema, 20672 block: *Block, 20673 src: LazySrcLoc, 20674 var_ty: Type, 20675 is_extern: bool, 20676 ) CompileError!bool { 20677 var ty = var_ty; 20678 while (true) switch (ty.zigTypeTag()) { 20679 .Bool, 20680 .Int, 20681 .Float, 20682 .ErrorSet, 20683 .Frame, 20684 .AnyFrame, 20685 .Void, 20686 => return true, 20687 20688 .Enum => return !(try sema.typeRequiresComptime(ty)), 20689 20690 .BoundFn, 20691 .ComptimeFloat, 20692 .ComptimeInt, 20693 .EnumLiteral, 20694 .NoReturn, 20695 .Type, 20696 .Undefined, 20697 .Null, 20698 .Fn, 20699 => return false, 20700 20701 .Pointer => { 20702 const elem_ty = ty.childType(); 20703 switch (elem_ty.zigTypeTag()) { 20704 .Opaque => return true, 20705 .Fn => return elem_ty.isFnOrHasRuntimeBits(), 20706 else => ty = elem_ty, 20707 } 20708 }, 20709 .Opaque => return is_extern, 20710 20711 .Optional => { 20712 var buf: Type.Payload.ElemType = undefined; 20713 const child_ty = ty.optionalChild(&buf); 20714 return validateRunTimeType(sema, block, src, child_ty, is_extern); 20715 }, 20716 .Array, .Vector => ty = ty.elemType(), 20717 20718 .ErrorUnion => ty = ty.errorUnionPayload(), 20719 20720 .Struct, .Union => { 20721 const resolved_ty = try sema.resolveTypeFields(block, src, ty); 20722 const needs_comptime = try sema.typeRequiresComptime(resolved_ty); 20723 return !needs_comptime; 20724 }, 20725 }; 20726 } 20727 20728 const TypeSet = std.HashMapUnmanaged(Type, void, Type.HashContext64, std.hash_map.default_max_load_percentage); 20729 20730 fn explainWhyTypeIsComptime( 20731 sema: *Sema, 20732 block: *Block, 20733 src: LazySrcLoc, 20734 msg: *Module.ErrorMsg, 20735 src_loc: Module.SrcLoc, 20736 ty: Type, 20737 ) CompileError!void { 20738 var type_set = TypeSet{}; 20739 defer type_set.deinit(sema.gpa); 20740 20741 try sema.resolveTypeFully(block, src, ty); 20742 return sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty, &type_set); 20743 } 20744 20745 fn explainWhyTypeIsComptimeInner( 20746 sema: *Sema, 20747 block: *Block, 20748 src: LazySrcLoc, 20749 msg: *Module.ErrorMsg, 20750 src_loc: Module.SrcLoc, 20751 ty: Type, 20752 type_set: *TypeSet, 20753 ) CompileError!void { 20754 const mod = sema.mod; 20755 switch (ty.zigTypeTag()) { 20756 .Bool, 20757 .Int, 20758 .Float, 20759 .ErrorSet, 20760 .Enum, 20761 .Frame, 20762 .AnyFrame, 20763 .Void, 20764 => return, 20765 20766 .Fn => { 20767 try mod.errNoteNonLazy(src_loc, msg, "use '*const {}' for a function pointer type", .{ 20768 ty.fmt(sema.mod), 20769 }); 20770 }, 20771 20772 .Type => { 20773 try mod.errNoteNonLazy(src_loc, msg, "types are not available at runtime", .{}); 20774 }, 20775 20776 .BoundFn, 20777 .ComptimeFloat, 20778 .ComptimeInt, 20779 .EnumLiteral, 20780 .NoReturn, 20781 .Undefined, 20782 .Null, 20783 => return, 20784 20785 .Opaque => { 20786 try mod.errNoteNonLazy(src_loc, msg, "opaque type '{}' has undefined size", .{ty.fmt(sema.mod)}); 20787 }, 20788 20789 .Array, .Vector => { 20790 try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.elemType(), type_set); 20791 }, 20792 .Pointer => { 20793 const elem_ty = ty.elemType2(); 20794 if (elem_ty.zigTypeTag() == .Fn) { 20795 const fn_info = elem_ty.fnInfo(); 20796 if (fn_info.is_generic) { 20797 try mod.errNoteNonLazy(src_loc, msg, "function is generic", .{}); 20798 } 20799 switch (fn_info.cc) { 20800 .Inline => try mod.errNoteNonLazy(src_loc, msg, "function has inline calling convention", .{}), 20801 else => {}, 20802 } 20803 if (fn_info.return_type.comptimeOnly()) { 20804 try mod.errNoteNonLazy(src_loc, msg, "function has a comptime-only return type", .{}); 20805 } 20806 return; 20807 } 20808 try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.elemType(), type_set); 20809 }, 20810 20811 .Optional => { 20812 var buf: Type.Payload.ElemType = undefined; 20813 try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.optionalChild(&buf), type_set); 20814 }, 20815 .ErrorUnion => { 20816 try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.errorUnionPayload(), type_set); 20817 }, 20818 20819 .Struct => { 20820 if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return; 20821 20822 if (ty.castTag(.@"struct")) |payload| { 20823 const struct_obj = payload.data; 20824 for (struct_obj.fields.values()) |field, i| { 20825 const field_src_loc = struct_obj.fieldSrcLoc(sema.mod, .{ 20826 .index = i, 20827 .range = .type, 20828 }); 20829 20830 if (try sema.typeRequiresComptime(field.ty)) { 20831 try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{}); 20832 try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set); 20833 } 20834 } 20835 } 20836 // TODO tuples 20837 }, 20838 20839 .Union => { 20840 if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return; 20841 20842 if (ty.cast(Type.Payload.Union)) |payload| { 20843 const union_obj = payload.data; 20844 for (union_obj.fields.values()) |field, i| { 20845 const field_src_loc = union_obj.fieldSrcLoc(sema.mod, .{ 20846 .index = i, 20847 .range = .type, 20848 }); 20849 20850 if (try sema.typeRequiresComptime(field.ty)) { 20851 try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{}); 20852 try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set); 20853 } 20854 } 20855 } 20856 }, 20857 } 20858 } 20859 20860 const ExternPosition = enum { 20861 ret_ty, 20862 param_ty, 20863 union_field, 20864 other, 20865 }; 20866 20867 /// Returns true if `ty` is allowed in extern types. 20868 /// Does *NOT* require `ty` to be resolved in any way. 20869 /// Calls `resolveTypeLayout` for packed containers. 20870 fn validateExternType( 20871 sema: *Sema, 20872 block: *Block, 20873 src: LazySrcLoc, 20874 ty: Type, 20875 position: ExternPosition, 20876 ) !bool { 20877 switch (ty.zigTypeTag()) { 20878 .Type, 20879 .ComptimeFloat, 20880 .ComptimeInt, 20881 .EnumLiteral, 20882 .Undefined, 20883 .Null, 20884 .ErrorUnion, 20885 .ErrorSet, 20886 .BoundFn, 20887 .Frame, 20888 => return false, 20889 .Void => return position == .union_field or position == .ret_ty, 20890 .NoReturn => return position == .ret_ty, 20891 .Opaque, 20892 .Bool, 20893 .Float, 20894 .AnyFrame, 20895 => return true, 20896 .Pointer => return !ty.isSlice(), 20897 .Int => switch (ty.intInfo(sema.mod.getTarget()).bits) { 20898 8, 16, 32, 64, 128 => return true, 20899 else => return false, 20900 }, 20901 .Fn => return !Type.fnCallingConventionAllowsZigTypes(ty.fnCallingConvention()), 20902 .Enum => { 20903 var buf: Type.Payload.Bits = undefined; 20904 return sema.validateExternType(block, src, ty.intTagType(&buf), position); 20905 }, 20906 .Struct, .Union => switch (ty.containerLayout()) { 20907 .Extern => return true, 20908 .Packed => { 20909 const target = sema.mod.getTarget(); 20910 const bit_size = try ty.bitSizeAdvanced(target, sema.kit(block, src)); 20911 switch (bit_size) { 20912 8, 16, 32, 64, 128 => return true, 20913 else => return false, 20914 } 20915 }, 20916 .Auto => return false, 20917 }, 20918 .Array => { 20919 if (position == .ret_ty or position == .param_ty) return false; 20920 return sema.validateExternType(block, src, ty.elemType2(), .other); 20921 }, 20922 .Vector => return sema.validateExternType(block, src, ty.elemType2(), .other), 20923 .Optional => return ty.isPtrLikeOptional(), 20924 } 20925 } 20926 20927 fn explainWhyTypeIsNotExtern( 20928 sema: *Sema, 20929 msg: *Module.ErrorMsg, 20930 src_loc: Module.SrcLoc, 20931 ty: Type, 20932 position: ExternPosition, 20933 ) CompileError!void { 20934 const mod = sema.mod; 20935 switch (ty.zigTypeTag()) { 20936 .Opaque, 20937 .Bool, 20938 .Float, 20939 .AnyFrame, 20940 => return, 20941 20942 .Type, 20943 .ComptimeFloat, 20944 .ComptimeInt, 20945 .EnumLiteral, 20946 .Undefined, 20947 .Null, 20948 .ErrorUnion, 20949 .ErrorSet, 20950 .BoundFn, 20951 .Frame, 20952 => return, 20953 20954 .Pointer => try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{}), 20955 .Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}), 20956 .NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}), 20957 .Int => if (ty.intInfo(sema.mod.getTarget()).bits > 128) { 20958 try mod.errNoteNonLazy(src_loc, msg, "only integers with less than 128 bits are extern compatible", .{}); 20959 } else { 20960 try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{}); 20961 }, 20962 .Fn => switch (ty.fnCallingConvention()) { 20963 .Unspecified => try mod.errNoteNonLazy(src_loc, msg, "extern function must specify calling convention", .{}), 20964 .Async => try mod.errNoteNonLazy(src_loc, msg, "async function cannot be extern", .{}), 20965 .Inline => try mod.errNoteNonLazy(src_loc, msg, "inline function cannot be extern", .{}), 20966 else => return, 20967 }, 20968 .Enum => { 20969 var buf: Type.Payload.Bits = undefined; 20970 const tag_ty = ty.intTagType(&buf); 20971 try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)}); 20972 try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); 20973 }, 20974 .Struct => try mod.errNoteNonLazy(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}), 20975 .Union => try mod.errNoteNonLazy(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}), 20976 .Array => { 20977 if (position == .ret_ty) { 20978 return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a return type", .{}); 20979 } else if (position == .param_ty) { 20980 return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a parameter type", .{}); 20981 } 20982 try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(), position); 20983 }, 20984 .Vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(), position), 20985 .Optional => try mod.errNoteNonLazy(src_loc, msg, "only pointer like optionals are extern compatible", .{}), 20986 } 20987 } 20988 20989 /// Returns true if `ty` is allowed in packed types. 20990 /// Does *NOT* require `ty` to be resolved in any way. 20991 fn validatePackedType(ty: Type) bool { 20992 switch (ty.zigTypeTag()) { 20993 .Type, 20994 .ComptimeFloat, 20995 .ComptimeInt, 20996 .EnumLiteral, 20997 .Undefined, 20998 .Null, 20999 .ErrorUnion, 21000 .ErrorSet, 21001 .BoundFn, 21002 .Frame, 21003 .NoReturn, 21004 .Opaque, 21005 .AnyFrame, 21006 .Fn, 21007 .Array, 21008 => return false, 21009 .Optional => return ty.isPtrLikeOptional(), 21010 .Void, 21011 .Bool, 21012 .Float, 21013 .Int, 21014 .Vector, 21015 .Enum, 21016 => return true, 21017 .Pointer => return !ty.isSlice(), 21018 .Struct, .Union => return ty.containerLayout() == .Packed, 21019 } 21020 } 21021 21022 fn explainWhyTypeIsNotPacked( 21023 sema: *Sema, 21024 msg: *Module.ErrorMsg, 21025 src_loc: Module.SrcLoc, 21026 ty: Type, 21027 ) CompileError!void { 21028 const mod = sema.mod; 21029 switch (ty.zigTypeTag()) { 21030 .Void, 21031 .Bool, 21032 .Float, 21033 .Int, 21034 .Vector, 21035 .Enum, 21036 => return, 21037 .Type, 21038 .ComptimeFloat, 21039 .ComptimeInt, 21040 .EnumLiteral, 21041 .Undefined, 21042 .Null, 21043 .BoundFn, 21044 .Frame, 21045 .NoReturn, 21046 .Opaque, 21047 .ErrorUnion, 21048 .ErrorSet, 21049 .AnyFrame, 21050 .Optional, 21051 .Array, 21052 => try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{}), 21053 .Pointer => try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{}), 21054 .Fn => { 21055 try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{}); 21056 try mod.errNoteNonLazy(src_loc, msg, "use '*const ' to make a function pointer type", .{}); 21057 }, 21058 .Struct => try mod.errNoteNonLazy(src_loc, msg, "only packed structs layout are allowed in packed types", .{}), 21059 .Union => try mod.errNoteNonLazy(src_loc, msg, "only packed unions layout are allowed in packed types", .{}), 21060 } 21061 } 21062 21063 pub const PanicId = enum { 21064 unreach, 21065 unwrap_null, 21066 cast_to_null, 21067 incorrect_alignment, 21068 invalid_error_code, 21069 cast_truncated_data, 21070 negative_to_unsigned, 21071 integer_overflow, 21072 shl_overflow, 21073 shr_overflow, 21074 divide_by_zero, 21075 exact_division_remainder, 21076 /// TODO make this call `std.builtin.panicInactiveUnionField`. 21077 inactive_union_field, 21078 integer_part_out_of_bounds, 21079 corrupt_switch, 21080 shift_rhs_too_big, 21081 invalid_enum_value, 21082 }; 21083 21084 fn addSafetyCheck( 21085 sema: *Sema, 21086 parent_block: *Block, 21087 ok: Air.Inst.Ref, 21088 panic_id: PanicId, 21089 ) !void { 21090 const gpa = sema.gpa; 21091 21092 var fail_block: Block = .{ 21093 .parent = parent_block, 21094 .sema = sema, 21095 .src_decl = parent_block.src_decl, 21096 .namespace = parent_block.namespace, 21097 .wip_capture_scope = parent_block.wip_capture_scope, 21098 .instructions = .{}, 21099 .inlining = parent_block.inlining, 21100 .is_comptime = parent_block.is_comptime, 21101 }; 21102 21103 defer fail_block.instructions.deinit(gpa); 21104 21105 // This function doesn't actually need a src location but if 21106 // the panic function interface ever changes passing `.unneeded` here 21107 // will cause confusing panics. 21108 const src = sema.src; 21109 _ = try sema.safetyPanic(&fail_block, src, panic_id); 21110 21111 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); 21112 } 21113 21114 fn addSafetyCheckExtra( 21115 sema: *Sema, 21116 parent_block: *Block, 21117 ok: Air.Inst.Ref, 21118 fail_block: *Block, 21119 ) !void { 21120 const gpa = sema.gpa; 21121 21122 try parent_block.instructions.ensureUnusedCapacity(gpa, 1); 21123 21124 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + 21125 1 + // The main block only needs space for the cond_br. 21126 @typeInfo(Air.CondBr).Struct.fields.len + 21127 1 + // The ok branch of the cond_br only needs space for the br. 21128 fail_block.instructions.items.len); 21129 21130 try sema.air_instructions.ensureUnusedCapacity(gpa, 3); 21131 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); 21132 const cond_br_inst = block_inst + 1; 21133 const br_inst = cond_br_inst + 1; 21134 sema.air_instructions.appendAssumeCapacity(.{ 21135 .tag = .block, 21136 .data = .{ .ty_pl = .{ 21137 .ty = .void_type, 21138 .payload = sema.addExtraAssumeCapacity(Air.Block{ 21139 .body_len = 1, 21140 }), 21141 } }, 21142 }); 21143 sema.air_extra.appendAssumeCapacity(cond_br_inst); 21144 21145 sema.air_instructions.appendAssumeCapacity(.{ 21146 .tag = .cond_br, 21147 .data = .{ .pl_op = .{ 21148 .operand = ok, 21149 .payload = sema.addExtraAssumeCapacity(Air.CondBr{ 21150 .then_body_len = 1, 21151 .else_body_len = @intCast(u32, fail_block.instructions.items.len), 21152 }), 21153 } }, 21154 }); 21155 sema.air_extra.appendAssumeCapacity(br_inst); 21156 sema.air_extra.appendSliceAssumeCapacity(fail_block.instructions.items); 21157 21158 sema.air_instructions.appendAssumeCapacity(.{ 21159 .tag = .br, 21160 .data = .{ .br = .{ 21161 .block_inst = block_inst, 21162 .operand = .void_value, 21163 } }, 21164 }); 21165 21166 parent_block.instructions.appendAssumeCapacity(block_inst); 21167 } 21168 21169 fn panicWithMsg( 21170 sema: *Sema, 21171 block: *Block, 21172 src: LazySrcLoc, 21173 msg_inst: Air.Inst.Ref, 21174 ) !Zir.Inst.Index { 21175 const mod = sema.mod; 21176 const arena = sema.arena; 21177 21178 const this_feature_is_implemented_in_the_backend = 21179 mod.comp.bin_file.options.target.ofmt == .c or 21180 mod.comp.bin_file.options.use_llvm; 21181 if (!this_feature_is_implemented_in_the_backend) { 21182 // TODO implement this feature in all the backends and then delete this branch 21183 _ = try block.addNoOp(.breakpoint); 21184 _ = try block.addNoOp(.unreach); 21185 return always_noreturn; 21186 } 21187 const panic_fn = try sema.getBuiltin(block, src, "panic"); 21188 const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); 21189 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); 21190 const target = mod.getTarget(); 21191 const ptr_stack_trace_ty = try Type.ptr(arena, mod, .{ 21192 .pointee_type = stack_trace_ty, 21193 .@"addrspace" = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic 21194 }); 21195 const null_stack_trace = try sema.addConstant( 21196 try Type.optional(arena, ptr_stack_trace_ty), 21197 Value.@"null", 21198 ); 21199 const args: [3]Air.Inst.Ref = .{ msg_inst, null_stack_trace, .null_value }; 21200 _ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, &args, null); 21201 return always_noreturn; 21202 } 21203 21204 fn panicUnwrapError( 21205 sema: *Sema, 21206 parent_block: *Block, 21207 src: LazySrcLoc, 21208 operand: Air.Inst.Ref, 21209 unwrap_err_tag: Air.Inst.Tag, 21210 is_non_err_tag: Air.Inst.Tag, 21211 ) !void { 21212 const ok = try parent_block.addUnOp(is_non_err_tag, operand); 21213 const gpa = sema.gpa; 21214 21215 var fail_block: Block = .{ 21216 .parent = parent_block, 21217 .sema = sema, 21218 .src_decl = parent_block.src_decl, 21219 .namespace = parent_block.namespace, 21220 .wip_capture_scope = parent_block.wip_capture_scope, 21221 .instructions = .{}, 21222 .inlining = parent_block.inlining, 21223 .is_comptime = parent_block.is_comptime, 21224 }; 21225 21226 defer fail_block.instructions.deinit(gpa); 21227 21228 { 21229 const this_feature_is_implemented_in_the_backend = 21230 sema.mod.comp.bin_file.options.use_llvm; 21231 21232 if (!this_feature_is_implemented_in_the_backend) { 21233 // TODO implement this feature in all the backends and then delete this branch 21234 _ = try fail_block.addNoOp(.breakpoint); 21235 _ = try fail_block.addNoOp(.unreach); 21236 } else { 21237 const panic_fn = try sema.getBuiltin(&fail_block, src, "panicUnwrapError"); 21238 const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand); 21239 const err_return_trace = try sema.getErrorReturnTrace(&fail_block, src); 21240 const args: [2]Air.Inst.Ref = .{ err_return_trace, err }; 21241 _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args, null); 21242 } 21243 } 21244 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); 21245 } 21246 21247 fn panicIndexOutOfBounds( 21248 sema: *Sema, 21249 parent_block: *Block, 21250 src: LazySrcLoc, 21251 index: Air.Inst.Ref, 21252 len: Air.Inst.Ref, 21253 cmp_op: Air.Inst.Tag, 21254 ) !void { 21255 const ok = try parent_block.addBinOp(cmp_op, index, len); 21256 const gpa = sema.gpa; 21257 21258 var fail_block: Block = .{ 21259 .parent = parent_block, 21260 .sema = sema, 21261 .src_decl = parent_block.src_decl, 21262 .namespace = parent_block.namespace, 21263 .wip_capture_scope = parent_block.wip_capture_scope, 21264 .instructions = .{}, 21265 .inlining = parent_block.inlining, 21266 .is_comptime = parent_block.is_comptime, 21267 }; 21268 21269 defer fail_block.instructions.deinit(gpa); 21270 21271 { 21272 const this_feature_is_implemented_in_the_backend = 21273 sema.mod.comp.bin_file.options.use_llvm; 21274 21275 if (!this_feature_is_implemented_in_the_backend) { 21276 // TODO implement this feature in all the backends and then delete this branch 21277 _ = try fail_block.addNoOp(.breakpoint); 21278 _ = try fail_block.addNoOp(.unreach); 21279 } else { 21280 const panic_fn = try sema.getBuiltin(&fail_block, src, "panicOutOfBounds"); 21281 const args: [2]Air.Inst.Ref = .{ index, len }; 21282 _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args, null); 21283 } 21284 } 21285 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); 21286 } 21287 21288 fn panicSentinelMismatch( 21289 sema: *Sema, 21290 parent_block: *Block, 21291 src: LazySrcLoc, 21292 maybe_sentinel: ?Value, 21293 sentinel_ty: Type, 21294 ptr: Air.Inst.Ref, 21295 sentinel_index: Air.Inst.Ref, 21296 ) !void { 21297 const expected_sentinel_val = maybe_sentinel orelse return; 21298 const expected_sentinel = try sema.addConstant(sentinel_ty, expected_sentinel_val); 21299 21300 const ptr_ty = sema.typeOf(ptr); 21301 const actual_sentinel = if (ptr_ty.isSlice()) 21302 try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index) 21303 else blk: { 21304 const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null); 21305 const sentinel_ptr = try parent_block.addPtrElemPtr(ptr, sentinel_index, elem_ptr_ty); 21306 break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr); 21307 }; 21308 21309 const ok = if (sentinel_ty.zigTypeTag() == .Vector) ok: { 21310 const eql = 21311 try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq, try sema.addType(sentinel_ty)); 21312 break :ok try parent_block.addInst(.{ 21313 .tag = .reduce, 21314 .data = .{ .reduce = .{ 21315 .operand = eql, 21316 .operation = .And, 21317 } }, 21318 }); 21319 } else if (sentinel_ty.isSelfComparable(true)) 21320 try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel) 21321 else { 21322 const panic_fn = try sema.getBuiltin(parent_block, src, "checkNonScalarSentinel"); 21323 const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel }; 21324 _ = try sema.analyzeCall(parent_block, panic_fn, src, src, .auto, false, &args, null); 21325 return; 21326 }; 21327 const gpa = sema.gpa; 21328 21329 var fail_block: Block = .{ 21330 .parent = parent_block, 21331 .sema = sema, 21332 .src_decl = parent_block.src_decl, 21333 .namespace = parent_block.namespace, 21334 .wip_capture_scope = parent_block.wip_capture_scope, 21335 .instructions = .{}, 21336 .inlining = parent_block.inlining, 21337 .is_comptime = parent_block.is_comptime, 21338 }; 21339 21340 defer fail_block.instructions.deinit(gpa); 21341 21342 { 21343 const this_feature_is_implemented_in_the_backend = 21344 sema.mod.comp.bin_file.options.use_llvm; 21345 21346 if (!this_feature_is_implemented_in_the_backend) { 21347 // TODO implement this feature in all the backends and then delete this branch 21348 _ = try fail_block.addNoOp(.breakpoint); 21349 _ = try fail_block.addNoOp(.unreach); 21350 } else { 21351 const panic_fn = try sema.getBuiltin(&fail_block, src, "panicSentinelMismatch"); 21352 const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel }; 21353 _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args, null); 21354 } 21355 } 21356 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); 21357 } 21358 21359 fn safetyPanic( 21360 sema: *Sema, 21361 block: *Block, 21362 src: LazySrcLoc, 21363 panic_id: PanicId, 21364 ) CompileError!Zir.Inst.Index { 21365 const msg = switch (panic_id) { 21366 .unreach => "reached unreachable code", 21367 .unwrap_null => "attempt to use null value", 21368 .cast_to_null => "cast causes pointer to be null", 21369 .incorrect_alignment => "incorrect alignment", 21370 .invalid_error_code => "invalid error code", 21371 .cast_truncated_data => "integer cast truncated bits", 21372 .negative_to_unsigned => "attempt to cast negative value to unsigned integer", 21373 .integer_overflow => "integer overflow", 21374 .shl_overflow => "left shift overflowed bits", 21375 .shr_overflow => "right shift overflowed bits", 21376 .divide_by_zero => "division by zero", 21377 .exact_division_remainder => "exact division produced remainder", 21378 .inactive_union_field => "access of inactive union field", 21379 .integer_part_out_of_bounds => "integer part of floating point value out of bounds", 21380 .corrupt_switch => "switch on corrupt value", 21381 .shift_rhs_too_big => "shift amount is greater than the type size", 21382 .invalid_enum_value => "invalid enum value", 21383 }; 21384 21385 const msg_inst = msg_inst: { 21386 // TODO instead of making a new decl for every panic in the entire compilation, 21387 // introduce the concept of a reference-counted decl for these 21388 var anon_decl = try block.startAnonDecl(src); 21389 defer anon_decl.deinit(); 21390 break :msg_inst try sema.analyzeDeclRef(try anon_decl.finish( 21391 try Type.Tag.array_u8.create(anon_decl.arena(), msg.len), 21392 try Value.Tag.bytes.create(anon_decl.arena(), msg), 21393 0, // default alignment 21394 )); 21395 }; 21396 21397 const casted_msg_inst = try sema.coerce(block, Type.initTag(.const_slice_u8), msg_inst, src); 21398 return sema.panicWithMsg(block, src, casted_msg_inst); 21399 } 21400 21401 fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void { 21402 sema.branch_count += 1; 21403 if (sema.branch_count > sema.branch_quota) { 21404 const msg = try sema.errMsg( 21405 block, 21406 src, 21407 "evaluation exceeded {d} backwards branches", 21408 .{sema.branch_quota}, 21409 ); 21410 try sema.errNote( 21411 block, 21412 src, 21413 msg, 21414 "use @setEvalBranchQuota() to raise the branch limit from {d}", 21415 .{sema.branch_quota}, 21416 ); 21417 return sema.failWithOwnedErrorMsg(msg); 21418 } 21419 } 21420 21421 fn fieldVal( 21422 sema: *Sema, 21423 block: *Block, 21424 src: LazySrcLoc, 21425 object: Air.Inst.Ref, 21426 field_name: []const u8, 21427 field_name_src: LazySrcLoc, 21428 ) CompileError!Air.Inst.Ref { 21429 // When editing this function, note that there is corresponding logic to be edited 21430 // in `fieldPtr`. This function takes a value and returns a value. 21431 21432 const arena = sema.arena; 21433 const object_src = src; // TODO better source location 21434 const object_ty = sema.typeOf(object); 21435 21436 // Zig allows dereferencing a single pointer during field lookup. Note that 21437 // we don't actually need to generate the dereference some field lookups, like the 21438 // length of arrays and other comptime operations. 21439 const is_pointer_to = object_ty.isSinglePointer(); 21440 21441 const inner_ty = if (is_pointer_to) 21442 object_ty.childType() 21443 else 21444 object_ty; 21445 21446 switch (inner_ty.zigTypeTag()) { 21447 .Array => { 21448 if (mem.eql(u8, field_name, "len")) { 21449 return sema.addConstant( 21450 Type.usize, 21451 try Value.Tag.int_u64.create(arena, inner_ty.arrayLen()), 21452 ); 21453 } else { 21454 return sema.fail( 21455 block, 21456 field_name_src, 21457 "no member named '{s}' in '{}'", 21458 .{ field_name, object_ty.fmt(sema.mod) }, 21459 ); 21460 } 21461 }, 21462 .Pointer => { 21463 const ptr_info = inner_ty.ptrInfo().data; 21464 if (ptr_info.size == .Slice) { 21465 if (mem.eql(u8, field_name, "ptr")) { 21466 const slice = if (is_pointer_to) 21467 try sema.analyzeLoad(block, src, object, object_src) 21468 else 21469 object; 21470 return sema.analyzeSlicePtr(block, object_src, slice, inner_ty); 21471 } else if (mem.eql(u8, field_name, "len")) { 21472 const slice = if (is_pointer_to) 21473 try sema.analyzeLoad(block, src, object, object_src) 21474 else 21475 object; 21476 return sema.analyzeSliceLen(block, src, slice); 21477 } else { 21478 return sema.fail( 21479 block, 21480 field_name_src, 21481 "no member named '{s}' in '{}'", 21482 .{ field_name, object_ty.fmt(sema.mod) }, 21483 ); 21484 } 21485 } else if (ptr_info.pointee_type.zigTypeTag() == .Array) { 21486 if (mem.eql(u8, field_name, "len")) { 21487 return sema.addConstant( 21488 Type.usize, 21489 try Value.Tag.int_u64.create(arena, ptr_info.pointee_type.arrayLen()), 21490 ); 21491 } else { 21492 return sema.fail( 21493 block, 21494 field_name_src, 21495 "no member named '{s}' in '{}'", 21496 .{ field_name, ptr_info.pointee_type.fmt(sema.mod) }, 21497 ); 21498 } 21499 } 21500 }, 21501 .Type => { 21502 const dereffed_type = if (is_pointer_to) 21503 try sema.analyzeLoad(block, src, object, object_src) 21504 else 21505 object; 21506 21507 const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?; 21508 var to_type_buffer: Value.ToTypeBuffer = undefined; 21509 const child_type = val.toType(&to_type_buffer); 21510 21511 switch (try child_type.zigTypeTagOrPoison()) { 21512 .ErrorSet => { 21513 const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: { 21514 if (payload.data.names.getEntry(field_name)) |entry| { 21515 break :blk entry.key_ptr.*; 21516 } 21517 const msg = msg: { 21518 const msg = try sema.errMsg(block, src, "no error named '{s}' in '{}'", .{ 21519 field_name, child_type.fmt(sema.mod), 21520 }); 21521 errdefer msg.destroy(sema.gpa); 21522 try sema.addDeclaredHereNote(msg, child_type); 21523 break :msg msg; 21524 }; 21525 return sema.failWithOwnedErrorMsg(msg); 21526 } else (try sema.mod.getErrorValue(field_name)).key; 21527 21528 return sema.addConstant( 21529 try child_type.copy(arena), 21530 try Value.Tag.@"error".create(arena, .{ .name = name }), 21531 ); 21532 }, 21533 .Union => { 21534 const union_ty = try sema.resolveTypeFields(block, src, child_type); 21535 21536 if (union_ty.getNamespace()) |namespace| { 21537 if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { 21538 return inst; 21539 } 21540 } 21541 if (union_ty.unionTagType()) |enum_ty| { 21542 if (enum_ty.enumFieldIndex(field_name)) |field_index_usize| { 21543 const field_index = @intCast(u32, field_index_usize); 21544 return sema.addConstant( 21545 enum_ty, 21546 try Value.Tag.enum_field_index.create(sema.arena, field_index), 21547 ); 21548 } 21549 } 21550 return sema.failWithBadMemberAccess(block, union_ty, field_name_src, field_name); 21551 }, 21552 .Enum => { 21553 if (child_type.getNamespace()) |namespace| { 21554 if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { 21555 return inst; 21556 } 21557 } 21558 const field_index_usize = child_type.enumFieldIndex(field_name) orelse 21559 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); 21560 const field_index = @intCast(u32, field_index_usize); 21561 const enum_val = try Value.Tag.enum_field_index.create(arena, field_index); 21562 return sema.addConstant(try child_type.copy(arena), enum_val); 21563 }, 21564 .Struct, .Opaque => { 21565 if (child_type.getNamespace()) |namespace| { 21566 if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { 21567 return inst; 21568 } 21569 } 21570 return sema.failWithBadMemberAccess(block, child_type, src, field_name); 21571 }, 21572 else => { 21573 const msg = msg: { 21574 const msg = try sema.errMsg(block, src, "type '{}' has no members", .{child_type.fmt(sema.mod)}); 21575 errdefer msg.destroy(sema.gpa); 21576 if (child_type.isSlice()) try sema.errNote(block, src, msg, "slice values have 'len' and 'ptr' members", .{}); 21577 if (child_type.zigTypeTag() == .Array) try sema.errNote(block, src, msg, "array values have 'len' member", .{}); 21578 break :msg msg; 21579 }; 21580 return sema.failWithOwnedErrorMsg(msg); 21581 }, 21582 } 21583 }, 21584 .Struct => if (is_pointer_to) { 21585 // Avoid loading the entire struct by fetching a pointer and loading that 21586 const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false); 21587 return sema.analyzeLoad(block, src, field_ptr, object_src); 21588 } else { 21589 return sema.structFieldVal(block, src, object, field_name, field_name_src, inner_ty); 21590 }, 21591 .Union => if (is_pointer_to) { 21592 // Avoid loading the entire union by fetching a pointer and loading that 21593 const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false); 21594 return sema.analyzeLoad(block, src, field_ptr, object_src); 21595 } else { 21596 return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty); 21597 }, 21598 else => {}, 21599 } 21600 return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); 21601 } 21602 21603 fn fieldPtr( 21604 sema: *Sema, 21605 block: *Block, 21606 src: LazySrcLoc, 21607 object_ptr: Air.Inst.Ref, 21608 field_name: []const u8, 21609 field_name_src: LazySrcLoc, 21610 initializing: bool, 21611 ) CompileError!Air.Inst.Ref { 21612 // When editing this function, note that there is corresponding logic to be edited 21613 // in `fieldVal`. This function takes a pointer and returns a pointer. 21614 21615 const object_ptr_src = src; // TODO better source location 21616 const object_ptr_ty = sema.typeOf(object_ptr); 21617 const object_ty = switch (object_ptr_ty.zigTypeTag()) { 21618 .Pointer => object_ptr_ty.elemType(), 21619 else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty.fmt(sema.mod)}), 21620 }; 21621 21622 // Zig allows dereferencing a single pointer during field lookup. Note that 21623 // we don't actually need to generate the dereference some field lookups, like the 21624 // length of arrays and other comptime operations. 21625 const is_pointer_to = object_ty.isSinglePointer(); 21626 21627 const inner_ty = if (is_pointer_to) 21628 object_ty.childType() 21629 else 21630 object_ty; 21631 21632 switch (inner_ty.zigTypeTag()) { 21633 .Array => { 21634 if (mem.eql(u8, field_name, "len")) { 21635 var anon_decl = try block.startAnonDecl(src); 21636 defer anon_decl.deinit(); 21637 return sema.analyzeDeclRef(try anon_decl.finish( 21638 Type.usize, 21639 try Value.Tag.int_u64.create(anon_decl.arena(), inner_ty.arrayLen()), 21640 0, // default alignment 21641 )); 21642 } else { 21643 return sema.fail( 21644 block, 21645 field_name_src, 21646 "no member named '{s}' in '{}'", 21647 .{ field_name, object_ty.fmt(sema.mod) }, 21648 ); 21649 } 21650 }, 21651 .Pointer => if (inner_ty.isSlice()) { 21652 const inner_ptr = if (is_pointer_to) 21653 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) 21654 else 21655 object_ptr; 21656 21657 if (mem.eql(u8, field_name, "ptr")) { 21658 const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer); 21659 const slice_ptr_ty = inner_ty.slicePtrFieldType(buf); 21660 21661 const result_ty = try Type.ptr(sema.arena, sema.mod, .{ 21662 .pointee_type = slice_ptr_ty, 21663 .mutable = object_ptr_ty.ptrIsMutable(), 21664 .@"addrspace" = object_ptr_ty.ptrAddressSpace(), 21665 }); 21666 21667 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { 21668 return sema.addConstant( 21669 result_ty, 21670 try Value.Tag.field_ptr.create(sema.arena, .{ 21671 .container_ptr = val, 21672 .container_ty = inner_ty, 21673 .field_index = Value.Payload.Slice.ptr_index, 21674 }), 21675 ); 21676 } 21677 try sema.requireRuntimeBlock(block, src, null); 21678 21679 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr); 21680 } else if (mem.eql(u8, field_name, "len")) { 21681 const result_ty = try Type.ptr(sema.arena, sema.mod, .{ 21682 .pointee_type = Type.usize, 21683 .mutable = object_ptr_ty.ptrIsMutable(), 21684 .@"addrspace" = object_ptr_ty.ptrAddressSpace(), 21685 }); 21686 21687 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { 21688 return sema.addConstant( 21689 result_ty, 21690 try Value.Tag.field_ptr.create(sema.arena, .{ 21691 .container_ptr = val, 21692 .container_ty = inner_ty, 21693 .field_index = Value.Payload.Slice.len_index, 21694 }), 21695 ); 21696 } 21697 try sema.requireRuntimeBlock(block, src, null); 21698 21699 return block.addTyOp(.ptr_slice_len_ptr, result_ty, inner_ptr); 21700 } else { 21701 return sema.fail( 21702 block, 21703 field_name_src, 21704 "no member named '{s}' in '{}'", 21705 .{ field_name, object_ty.fmt(sema.mod) }, 21706 ); 21707 } 21708 }, 21709 .Type => { 21710 _ = try sema.resolveConstValue(block, .unneeded, object_ptr, undefined); 21711 const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src); 21712 const inner = if (is_pointer_to) 21713 try sema.analyzeLoad(block, src, result, object_ptr_src) 21714 else 21715 result; 21716 21717 const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?; 21718 var to_type_buffer: Value.ToTypeBuffer = undefined; 21719 const child_type = val.toType(&to_type_buffer); 21720 21721 switch (child_type.zigTypeTag()) { 21722 .ErrorSet => { 21723 // TODO resolve inferred error sets 21724 const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: { 21725 if (payload.data.names.getEntry(field_name)) |entry| { 21726 break :blk entry.key_ptr.*; 21727 } 21728 return sema.fail(block, src, "no error named '{s}' in '{}'", .{ 21729 field_name, child_type.fmt(sema.mod), 21730 }); 21731 } else (try sema.mod.getErrorValue(field_name)).key; 21732 21733 var anon_decl = try block.startAnonDecl(src); 21734 defer anon_decl.deinit(); 21735 return sema.analyzeDeclRef(try anon_decl.finish( 21736 try child_type.copy(anon_decl.arena()), 21737 try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }), 21738 0, // default alignment 21739 )); 21740 }, 21741 .Union => { 21742 if (child_type.getNamespace()) |namespace| { 21743 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { 21744 return inst; 21745 } 21746 } 21747 if (child_type.unionTagType()) |enum_ty| { 21748 if (enum_ty.enumFieldIndex(field_name)) |field_index| { 21749 const field_index_u32 = @intCast(u32, field_index); 21750 var anon_decl = try block.startAnonDecl(src); 21751 defer anon_decl.deinit(); 21752 return sema.analyzeDeclRef(try anon_decl.finish( 21753 try enum_ty.copy(anon_decl.arena()), 21754 try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32), 21755 0, // default alignment 21756 )); 21757 } 21758 } 21759 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); 21760 }, 21761 .Enum => { 21762 if (child_type.getNamespace()) |namespace| { 21763 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { 21764 return inst; 21765 } 21766 } 21767 const field_index = child_type.enumFieldIndex(field_name) orelse { 21768 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); 21769 }; 21770 const field_index_u32 = @intCast(u32, field_index); 21771 var anon_decl = try block.startAnonDecl(src); 21772 defer anon_decl.deinit(); 21773 return sema.analyzeDeclRef(try anon_decl.finish( 21774 try child_type.copy(anon_decl.arena()), 21775 try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32), 21776 0, // default alignment 21777 )); 21778 }, 21779 .Struct, .Opaque => { 21780 if (child_type.getNamespace()) |namespace| { 21781 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { 21782 return inst; 21783 } 21784 } 21785 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); 21786 }, 21787 else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(sema.mod)}), 21788 } 21789 }, 21790 .Struct => { 21791 const inner_ptr = if (is_pointer_to) 21792 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) 21793 else 21794 object_ptr; 21795 return sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing); 21796 }, 21797 .Union => { 21798 const inner_ptr = if (is_pointer_to) 21799 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) 21800 else 21801 object_ptr; 21802 return sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing); 21803 }, 21804 else => {}, 21805 } 21806 return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); 21807 } 21808 21809 fn fieldCallBind( 21810 sema: *Sema, 21811 block: *Block, 21812 src: LazySrcLoc, 21813 raw_ptr: Air.Inst.Ref, 21814 field_name: []const u8, 21815 field_name_src: LazySrcLoc, 21816 ) CompileError!Air.Inst.Ref { 21817 // When editing this function, note that there is corresponding logic to be edited 21818 // in `fieldVal`. This function takes a pointer and returns a pointer. 21819 21820 const raw_ptr_src = src; // TODO better source location 21821 const raw_ptr_ty = sema.typeOf(raw_ptr); 21822 const inner_ty = if (raw_ptr_ty.zigTypeTag() == .Pointer and (raw_ptr_ty.ptrSize() == .One or raw_ptr_ty.ptrSize() == .C)) 21823 raw_ptr_ty.childType() 21824 else 21825 return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(sema.mod)}); 21826 21827 // Optionally dereference a second pointer to get the concrete type. 21828 const is_double_ptr = inner_ty.zigTypeTag() == .Pointer and inner_ty.ptrSize() == .One; 21829 const concrete_ty = if (is_double_ptr) inner_ty.childType() else inner_ty; 21830 const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty; 21831 const object_ptr = if (is_double_ptr) 21832 try sema.analyzeLoad(block, src, raw_ptr, src) 21833 else 21834 raw_ptr; 21835 21836 const arena = sema.arena; 21837 find_field: { 21838 switch (concrete_ty.zigTypeTag()) { 21839 .Struct => { 21840 const struct_ty = try sema.resolveTypeFields(block, src, concrete_ty); 21841 if (struct_ty.castTag(.@"struct")) |struct_obj| { 21842 const field_index_usize = struct_obj.data.fields.getIndex(field_name) orelse 21843 break :find_field; 21844 const field_index = @intCast(u32, field_index_usize); 21845 const field = struct_obj.data.fields.values()[field_index]; 21846 21847 return finishFieldCallBind(sema, block, src, ptr_ty, field.ty, field_index, object_ptr); 21848 } else if (struct_ty.isTuple()) { 21849 if (mem.eql(u8, field_name, "len")) { 21850 return sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount()); 21851 } 21852 if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| { 21853 if (field_index >= struct_ty.structFieldCount()) break :find_field; 21854 return finishFieldCallBind(sema, block, src, ptr_ty, struct_ty.structFieldType(field_index), field_index, object_ptr); 21855 } else |_| {} 21856 } else { 21857 const max = struct_ty.structFieldCount(); 21858 var i: u32 = 0; 21859 while (i < max) : (i += 1) { 21860 if (mem.eql(u8, struct_ty.structFieldName(i), field_name)) { 21861 return finishFieldCallBind(sema, block, src, ptr_ty, struct_ty.structFieldType(i), i, object_ptr); 21862 } 21863 } 21864 } 21865 }, 21866 .Union => { 21867 const union_ty = try sema.resolveTypeFields(block, src, concrete_ty); 21868 const fields = union_ty.unionFields(); 21869 const field_index_usize = fields.getIndex(field_name) orelse break :find_field; 21870 const field_index = @intCast(u32, field_index_usize); 21871 const field = fields.values()[field_index]; 21872 21873 return finishFieldCallBind(sema, block, src, ptr_ty, field.ty, field_index, object_ptr); 21874 }, 21875 .Type => { 21876 const namespace = try sema.analyzeLoad(block, src, object_ptr, src); 21877 return sema.fieldVal(block, src, namespace, field_name, field_name_src); 21878 }, 21879 else => {}, 21880 } 21881 } 21882 21883 // If we get here, we need to look for a decl in the struct type instead. 21884 switch (concrete_ty.zigTypeTag()) { 21885 .Struct, .Opaque, .Union, .Enum => { 21886 if (concrete_ty.getNamespace()) |namespace| { 21887 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { 21888 const decl_val = try sema.analyzeLoad(block, src, inst, src); 21889 const decl_type = sema.typeOf(decl_val); 21890 if (decl_type.zigTypeTag() == .Fn and 21891 decl_type.fnParamLen() >= 1) 21892 { 21893 const first_param_type = decl_type.fnParamType(0); 21894 const first_param_tag = first_param_type.tag(); 21895 // zig fmt: off 21896 if (first_param_tag == .var_args_param or 21897 first_param_tag == .generic_poison or ( 21898 first_param_type.zigTypeTag() == .Pointer and 21899 (first_param_type.ptrSize() == .One or 21900 first_param_type.ptrSize() == .C) and 21901 first_param_type.childType().eql(concrete_ty, sema.mod))) 21902 { 21903 // zig fmt: on 21904 // TODO: bound fn calls on rvalues should probably 21905 // generate a by-value argument somehow. 21906 const ty = Type.Tag.bound_fn.init(); 21907 const value = try Value.Tag.bound_fn.create(arena, .{ 21908 .func_inst = decl_val, 21909 .arg0_inst = object_ptr, 21910 }); 21911 return sema.addConstant(ty, value); 21912 } else if (first_param_type.eql(concrete_ty, sema.mod)) { 21913 var deref = try sema.analyzeLoad(block, src, object_ptr, src); 21914 const ty = Type.Tag.bound_fn.init(); 21915 const value = try Value.Tag.bound_fn.create(arena, .{ 21916 .func_inst = decl_val, 21917 .arg0_inst = deref, 21918 }); 21919 return sema.addConstant(ty, value); 21920 } 21921 } 21922 } 21923 } 21924 }, 21925 else => {}, 21926 } 21927 21928 const msg = msg: { 21929 const msg = try sema.errMsg(block, src, "no field or member function named '{s}' in '{}'", .{ field_name, concrete_ty.fmt(sema.mod) }); 21930 errdefer msg.destroy(sema.gpa); 21931 try sema.addDeclaredHereNote(msg, concrete_ty); 21932 break :msg msg; 21933 }; 21934 return sema.failWithOwnedErrorMsg(msg); 21935 } 21936 21937 fn finishFieldCallBind( 21938 sema: *Sema, 21939 block: *Block, 21940 src: LazySrcLoc, 21941 ptr_ty: Type, 21942 field_ty: Type, 21943 field_index: u32, 21944 object_ptr: Air.Inst.Ref, 21945 ) CompileError!Air.Inst.Ref { 21946 const arena = sema.arena; 21947 const ptr_field_ty = try Type.ptr(arena, sema.mod, .{ 21948 .pointee_type = field_ty, 21949 .mutable = ptr_ty.ptrIsMutable(), 21950 .@"addrspace" = ptr_ty.ptrAddressSpace(), 21951 }); 21952 21953 const container_ty = ptr_ty.childType(); 21954 if (container_ty.zigTypeTag() == .Struct) { 21955 if (container_ty.structFieldValueComptime(field_index)) |default_val| { 21956 return sema.addConstant(field_ty, default_val); 21957 } 21958 } 21959 21960 if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| { 21961 const pointer = try sema.addConstant( 21962 ptr_field_ty, 21963 try Value.Tag.field_ptr.create(arena, .{ 21964 .container_ptr = struct_ptr_val, 21965 .container_ty = container_ty, 21966 .field_index = field_index, 21967 }), 21968 ); 21969 return sema.analyzeLoad(block, src, pointer, src); 21970 } 21971 21972 try sema.requireRuntimeBlock(block, src, null); 21973 const ptr_inst = try block.addStructFieldPtr(object_ptr, field_index, ptr_field_ty); 21974 return sema.analyzeLoad(block, src, ptr_inst, src); 21975 } 21976 21977 fn namespaceLookup( 21978 sema: *Sema, 21979 block: *Block, 21980 src: LazySrcLoc, 21981 namespace: *Namespace, 21982 decl_name: []const u8, 21983 ) CompileError!?Decl.Index { 21984 const gpa = sema.gpa; 21985 if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| { 21986 const decl = sema.mod.declPtr(decl_index); 21987 if (!decl.is_pub and decl.getFileScope() != block.getFileScope()) { 21988 const msg = msg: { 21989 const msg = try sema.errMsg(block, src, "'{s}' is not marked 'pub'", .{ 21990 decl_name, 21991 }); 21992 errdefer msg.destroy(gpa); 21993 try sema.mod.errNoteNonLazy(decl.srcLoc(), msg, "declared here", .{}); 21994 break :msg msg; 21995 }; 21996 return sema.failWithOwnedErrorMsg(msg); 21997 } 21998 return decl_index; 21999 } 22000 return null; 22001 } 22002 22003 fn namespaceLookupRef( 22004 sema: *Sema, 22005 block: *Block, 22006 src: LazySrcLoc, 22007 namespace: *Namespace, 22008 decl_name: []const u8, 22009 ) CompileError!?Air.Inst.Ref { 22010 const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; 22011 try sema.addReferencedBy(block, src, decl); 22012 return try sema.analyzeDeclRef(decl); 22013 } 22014 22015 fn namespaceLookupVal( 22016 sema: *Sema, 22017 block: *Block, 22018 src: LazySrcLoc, 22019 namespace: *Namespace, 22020 decl_name: []const u8, 22021 ) CompileError!?Air.Inst.Ref { 22022 const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; 22023 return try sema.analyzeDeclVal(block, src, decl); 22024 } 22025 22026 fn structFieldPtr( 22027 sema: *Sema, 22028 block: *Block, 22029 src: LazySrcLoc, 22030 struct_ptr: Air.Inst.Ref, 22031 field_name: []const u8, 22032 field_name_src: LazySrcLoc, 22033 unresolved_struct_ty: Type, 22034 initializing: bool, 22035 ) CompileError!Air.Inst.Ref { 22036 assert(unresolved_struct_ty.zigTypeTag() == .Struct); 22037 22038 const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty); 22039 try sema.resolveStructLayout(block, src, struct_ty); 22040 22041 if (struct_ty.isTuple()) { 22042 if (mem.eql(u8, field_name, "len")) { 22043 const len_inst = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount()); 22044 return sema.analyzeRef(block, src, len_inst); 22045 } 22046 const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src); 22047 return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); 22048 } else if (struct_ty.isAnonStruct()) { 22049 const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); 22050 return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); 22051 } 22052 22053 const struct_obj = struct_ty.castTag(.@"struct").?.data; 22054 22055 const field_index_big = struct_obj.fields.getIndex(field_name) orelse 22056 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); 22057 const field_index = @intCast(u32, field_index_big); 22058 22059 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, field_name_src, struct_ty, initializing); 22060 } 22061 22062 fn structFieldPtrByIndex( 22063 sema: *Sema, 22064 block: *Block, 22065 src: LazySrcLoc, 22066 struct_ptr: Air.Inst.Ref, 22067 field_index: u32, 22068 field_src: LazySrcLoc, 22069 struct_ty: Type, 22070 initializing: bool, 22071 ) CompileError!Air.Inst.Ref { 22072 if (struct_ty.isAnonStruct()) { 22073 return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing); 22074 } 22075 22076 const struct_obj = struct_ty.castTag(.@"struct").?.data; 22077 const field = struct_obj.fields.values()[field_index]; 22078 const struct_ptr_ty = sema.typeOf(struct_ptr); 22079 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo().data; 22080 22081 var ptr_ty_data: Type.Payload.Pointer.Data = .{ 22082 .pointee_type = field.ty, 22083 .mutable = struct_ptr_ty_info.mutable, 22084 .@"volatile" = struct_ptr_ty_info.@"volatile", 22085 .@"addrspace" = struct_ptr_ty_info.@"addrspace", 22086 }; 22087 22088 const target = sema.mod.getTarget(); 22089 22090 if (struct_obj.layout == .Packed) { 22091 comptime assert(Type.packed_struct_layout_version == 2); 22092 22093 var running_bits: u16 = 0; 22094 for (struct_obj.fields.values()) |f, i| { 22095 if (!(try sema.typeHasRuntimeBits(block, field_src, f.ty))) continue; 22096 22097 if (i == field_index) { 22098 ptr_ty_data.bit_offset = running_bits; 22099 } 22100 running_bits += @intCast(u16, f.ty.bitSize(target)); 22101 } 22102 ptr_ty_data.host_size = (running_bits + 7) / 8; 22103 22104 // If this is a packed struct embedded in another one, we need to offset 22105 // the bits against each other. 22106 if (struct_ptr_ty_info.host_size != 0) { 22107 ptr_ty_data.host_size = struct_ptr_ty_info.host_size; 22108 ptr_ty_data.bit_offset += struct_ptr_ty_info.bit_offset; 22109 } 22110 22111 const parent_align = if (struct_ptr_ty_info.@"align" != 0) 22112 struct_ptr_ty_info.@"align" 22113 else 22114 struct_ptr_ty_info.pointee_type.abiAlignment(target); 22115 ptr_ty_data.@"align" = parent_align; 22116 22117 // If the field happens to be byte-aligned, simplify the pointer type. 22118 // The pointee type bit size must match its ABI byte size so that loads and stores 22119 // do not interfere with the surrounding packed bits. 22120 // We do not attempt this with big-endian targets yet because of nested 22121 // structs and floats. I need to double-check the desired behavior for big endian 22122 // targets before adding the necessary complications to this code. This will not 22123 // cause miscompilations; it only means the field pointer uses bit masking when it 22124 // might not be strictly necessary. 22125 if (parent_align != 0 and ptr_ty_data.bit_offset % 8 == 0 and 22126 target.cpu.arch.endian() == .Little) 22127 { 22128 const elem_size_bytes = ptr_ty_data.pointee_type.abiSize(target); 22129 const elem_size_bits = ptr_ty_data.pointee_type.bitSize(target); 22130 if (elem_size_bytes * 8 == elem_size_bits) { 22131 const byte_offset = ptr_ty_data.bit_offset / 8; 22132 const new_align = @as(u32, 1) << @intCast(u5, @ctz(byte_offset | parent_align)); 22133 ptr_ty_data.bit_offset = 0; 22134 ptr_ty_data.host_size = 0; 22135 ptr_ty_data.@"align" = new_align; 22136 } 22137 } 22138 } else { 22139 ptr_ty_data.@"align" = field.abi_align; 22140 } 22141 22142 const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, ptr_ty_data); 22143 22144 if (field.is_comptime) { 22145 const val = try Value.Tag.comptime_field_ptr.create(sema.arena, .{ 22146 .field_ty = try field.ty.copy(sema.arena), 22147 .field_val = try field.default_val.copy(sema.arena), 22148 }); 22149 return sema.addConstant(ptr_field_ty, val); 22150 } 22151 22152 if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| { 22153 return sema.addConstant( 22154 ptr_field_ty, 22155 try Value.Tag.field_ptr.create(sema.arena, .{ 22156 .container_ptr = struct_ptr_val, 22157 .container_ty = struct_ptr_ty.childType(), 22158 .field_index = field_index, 22159 }), 22160 ); 22161 } 22162 22163 try sema.requireRuntimeBlock(block, src, null); 22164 return block.addStructFieldPtr(struct_ptr, field_index, ptr_field_ty); 22165 } 22166 22167 fn structFieldVal( 22168 sema: *Sema, 22169 block: *Block, 22170 src: LazySrcLoc, 22171 struct_byval: Air.Inst.Ref, 22172 field_name: []const u8, 22173 field_name_src: LazySrcLoc, 22174 unresolved_struct_ty: Type, 22175 ) CompileError!Air.Inst.Ref { 22176 assert(unresolved_struct_ty.zigTypeTag() == .Struct); 22177 22178 const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty); 22179 switch (struct_ty.tag()) { 22180 .tuple, .empty_struct_literal => return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty), 22181 .anon_struct => { 22182 const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); 22183 return tupleFieldValByIndex(sema, block, src, struct_byval, field_index, struct_ty); 22184 }, 22185 .@"struct" => { 22186 const struct_obj = struct_ty.castTag(.@"struct").?.data; 22187 22188 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse 22189 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); 22190 const field_index = @intCast(u32, field_index_usize); 22191 const field = struct_obj.fields.values()[field_index]; 22192 22193 if (field.is_comptime) { 22194 return sema.addConstant(field.ty, field.default_val); 22195 } 22196 22197 if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| { 22198 if (struct_val.isUndef()) return sema.addConstUndef(field.ty); 22199 if ((try sema.typeHasOnePossibleValue(block, src, field.ty))) |opv| { 22200 return sema.addConstant(field.ty, opv); 22201 } 22202 22203 const field_values = struct_val.castTag(.aggregate).?.data; 22204 return sema.addConstant(field.ty, field_values[field_index]); 22205 } 22206 22207 try sema.requireRuntimeBlock(block, src, null); 22208 return block.addStructFieldVal(struct_byval, field_index, field.ty); 22209 }, 22210 else => unreachable, 22211 } 22212 } 22213 22214 fn tupleFieldVal( 22215 sema: *Sema, 22216 block: *Block, 22217 src: LazySrcLoc, 22218 tuple_byval: Air.Inst.Ref, 22219 field_name: []const u8, 22220 field_name_src: LazySrcLoc, 22221 tuple_ty: Type, 22222 ) CompileError!Air.Inst.Ref { 22223 if (mem.eql(u8, field_name, "len")) { 22224 return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount()); 22225 } 22226 const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_name_src); 22227 return tupleFieldValByIndex(sema, block, src, tuple_byval, field_index, tuple_ty); 22228 } 22229 22230 /// Asserts that `field_name` is not "len". 22231 fn tupleFieldIndex( 22232 sema: *Sema, 22233 block: *Block, 22234 tuple_ty: Type, 22235 field_name: []const u8, 22236 field_name_src: LazySrcLoc, 22237 ) CompileError!u32 { 22238 assert(!std.mem.eql(u8, field_name, "len")); 22239 if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| { 22240 if (field_index < tuple_ty.structFieldCount()) return field_index; 22241 return sema.fail(block, field_name_src, "index '{s}' out of bounds of tuple '{}'", .{ 22242 field_name, tuple_ty.fmt(sema.mod), 22243 }); 22244 } else |_| {} 22245 22246 return sema.fail(block, field_name_src, "no field named '{s}' in tuple '{}'", .{ 22247 field_name, tuple_ty.fmt(sema.mod), 22248 }); 22249 } 22250 22251 fn tupleFieldValByIndex( 22252 sema: *Sema, 22253 block: *Block, 22254 src: LazySrcLoc, 22255 tuple_byval: Air.Inst.Ref, 22256 field_index: u32, 22257 tuple_ty: Type, 22258 ) CompileError!Air.Inst.Ref { 22259 const tuple = tuple_ty.tupleFields(); 22260 const field_ty = tuple.types[field_index]; 22261 22262 if (tuple.values[field_index].tag() != .unreachable_value) { 22263 return sema.addConstant(field_ty, tuple.values[field_index]); 22264 } 22265 22266 if (try sema.resolveMaybeUndefVal(block, src, tuple_byval)) |tuple_val| { 22267 if (tuple_val.isUndef()) return sema.addConstUndef(field_ty); 22268 if ((try sema.typeHasOnePossibleValue(block, src, field_ty))) |opv| { 22269 return sema.addConstant(field_ty, opv); 22270 } 22271 const field_values = tuple_val.castTag(.aggregate).?.data; 22272 return sema.addConstant(field_ty, field_values[field_index]); 22273 } 22274 22275 if (tuple_ty.structFieldValueComptime(field_index)) |default_val| { 22276 return sema.addConstant(field_ty, default_val); 22277 } 22278 22279 try sema.requireRuntimeBlock(block, src, null); 22280 return block.addStructFieldVal(tuple_byval, field_index, field_ty); 22281 } 22282 22283 fn unionFieldPtr( 22284 sema: *Sema, 22285 block: *Block, 22286 src: LazySrcLoc, 22287 union_ptr: Air.Inst.Ref, 22288 field_name: []const u8, 22289 field_name_src: LazySrcLoc, 22290 unresolved_union_ty: Type, 22291 initializing: bool, 22292 ) CompileError!Air.Inst.Ref { 22293 const arena = sema.arena; 22294 assert(unresolved_union_ty.zigTypeTag() == .Union); 22295 22296 const union_ptr_ty = sema.typeOf(union_ptr); 22297 const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty); 22298 const union_obj = union_ty.cast(Type.Payload.Union).?.data; 22299 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); 22300 const field = union_obj.fields.values()[field_index]; 22301 const ptr_field_ty = try Type.ptr(arena, sema.mod, .{ 22302 .pointee_type = field.ty, 22303 .mutable = union_ptr_ty.ptrIsMutable(), 22304 .@"volatile" = union_ptr_ty.isVolatilePtr(), 22305 .@"addrspace" = union_ptr_ty.ptrAddressSpace(), 22306 }); 22307 const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?); 22308 22309 if (initializing and field.ty.zigTypeTag() == .NoReturn) { 22310 const msg = msg: { 22311 const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{}); 22312 errdefer msg.destroy(sema.gpa); 22313 22314 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); 22315 try sema.addDeclaredHereNote(msg, union_ty); 22316 break :msg msg; 22317 }; 22318 return sema.failWithOwnedErrorMsg(msg); 22319 } 22320 22321 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: { 22322 switch (union_obj.layout) { 22323 .Auto => if (!initializing) { 22324 const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse 22325 break :ct; 22326 if (union_val.isUndef()) { 22327 return sema.failWithUseOfUndef(block, src); 22328 } 22329 const tag_and_val = union_val.castTag(.@"union").?.data; 22330 var field_tag_buf: Value.Payload.U32 = .{ 22331 .base = .{ .tag = .enum_field_index }, 22332 .data = enum_field_index, 22333 }; 22334 const field_tag = Value.initPayload(&field_tag_buf.base); 22335 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); 22336 if (!tag_matches) { 22337 const msg = msg: { 22338 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data; 22339 const active_field_name = union_obj.tag_ty.enumFieldName(active_index); 22340 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); 22341 errdefer msg.destroy(sema.gpa); 22342 try sema.addDeclaredHereNote(msg, union_ty); 22343 break :msg msg; 22344 }; 22345 return sema.failWithOwnedErrorMsg(msg); 22346 } 22347 }, 22348 .Packed, .Extern => {}, 22349 } 22350 return sema.addConstant( 22351 ptr_field_ty, 22352 try Value.Tag.field_ptr.create(arena, .{ 22353 .container_ptr = union_ptr_val, 22354 .container_ty = union_ty, 22355 .field_index = field_index, 22356 }), 22357 ); 22358 } 22359 22360 try sema.requireRuntimeBlock(block, src, null); 22361 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and 22362 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1) 22363 { 22364 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); 22365 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); 22366 // TODO would it be better if get_union_tag supported pointers to unions? 22367 const union_val = try block.addTyOp(.load, union_ty, union_ptr); 22368 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val); 22369 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); 22370 try sema.addSafetyCheck(block, ok, .inactive_union_field); 22371 } 22372 if (field.ty.zigTypeTag() == .NoReturn) { 22373 _ = try block.addNoOp(.unreach); 22374 return Air.Inst.Ref.unreachable_value; 22375 } 22376 return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty); 22377 } 22378 22379 fn unionFieldVal( 22380 sema: *Sema, 22381 block: *Block, 22382 src: LazySrcLoc, 22383 union_byval: Air.Inst.Ref, 22384 field_name: []const u8, 22385 field_name_src: LazySrcLoc, 22386 unresolved_union_ty: Type, 22387 ) CompileError!Air.Inst.Ref { 22388 assert(unresolved_union_ty.zigTypeTag() == .Union); 22389 22390 const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty); 22391 const union_obj = union_ty.cast(Type.Payload.Union).?.data; 22392 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); 22393 const field = union_obj.fields.values()[field_index]; 22394 const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?); 22395 22396 if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| { 22397 if (union_val.isUndef()) return sema.addConstUndef(field.ty); 22398 22399 const tag_and_val = union_val.castTag(.@"union").?.data; 22400 var field_tag_buf: Value.Payload.U32 = .{ 22401 .base = .{ .tag = .enum_field_index }, 22402 .data = enum_field_index, 22403 }; 22404 const field_tag = Value.initPayload(&field_tag_buf.base); 22405 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); 22406 switch (union_obj.layout) { 22407 .Auto => { 22408 if (tag_matches) { 22409 return sema.addConstant(field.ty, tag_and_val.val); 22410 } else { 22411 const msg = msg: { 22412 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data; 22413 const active_field_name = union_obj.tag_ty.enumFieldName(active_index); 22414 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); 22415 errdefer msg.destroy(sema.gpa); 22416 try sema.addDeclaredHereNote(msg, union_ty); 22417 break :msg msg; 22418 }; 22419 return sema.failWithOwnedErrorMsg(msg); 22420 } 22421 }, 22422 .Packed, .Extern => { 22423 if (tag_matches) { 22424 return sema.addConstant(field.ty, tag_and_val.val); 22425 } else { 22426 const old_ty = union_ty.unionFieldType(tag_and_val.tag, sema.mod); 22427 const new_val = try sema.bitCastVal(block, src, tag_and_val.val, old_ty, field.ty, 0); 22428 return sema.addConstant(field.ty, new_val); 22429 } 22430 }, 22431 } 22432 } 22433 22434 try sema.requireRuntimeBlock(block, src, null); 22435 if (union_obj.layout == .Auto and block.wantSafety() and 22436 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1) 22437 { 22438 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); 22439 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); 22440 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval); 22441 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); 22442 try sema.addSafetyCheck(block, ok, .inactive_union_field); 22443 } 22444 if (field.ty.zigTypeTag() == .NoReturn) { 22445 _ = try block.addNoOp(.unreach); 22446 return Air.Inst.Ref.unreachable_value; 22447 } 22448 return block.addStructFieldVal(union_byval, field_index, field.ty); 22449 } 22450 22451 fn elemPtr( 22452 sema: *Sema, 22453 block: *Block, 22454 src: LazySrcLoc, 22455 indexable_ptr: Air.Inst.Ref, 22456 elem_index: Air.Inst.Ref, 22457 elem_index_src: LazySrcLoc, 22458 init: bool, 22459 ) CompileError!Air.Inst.Ref { 22460 const indexable_ptr_src = src; // TODO better source location 22461 const indexable_ptr_ty = sema.typeOf(indexable_ptr); 22462 const target = sema.mod.getTarget(); 22463 const indexable_ty = switch (indexable_ptr_ty.zigTypeTag()) { 22464 .Pointer => indexable_ptr_ty.elemType(), 22465 else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(sema.mod)}), 22466 }; 22467 if (!indexable_ty.isIndexable()) { 22468 return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty.fmt(sema.mod)}); 22469 } 22470 22471 switch (indexable_ty.zigTypeTag()) { 22472 .Pointer => { 22473 // In all below cases, we have to deref the ptr operand to get the actual indexable pointer. 22474 const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); 22475 switch (indexable_ty.ptrSize()) { 22476 .Slice => return sema.elemPtrSlice(block, src, indexable_ptr_src, indexable, elem_index_src, elem_index), 22477 .Many, .C => { 22478 const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_ptr_src, indexable); 22479 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); 22480 const runtime_src = rs: { 22481 const ptr_val = maybe_ptr_val orelse break :rs indexable_ptr_src; 22482 const index_val = maybe_index_val orelse break :rs elem_index_src; 22483 const index = @intCast(usize, index_val.toUnsignedInt(target)); 22484 const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, sema.mod); 22485 const result_ty = try sema.elemPtrType(indexable_ty, index); 22486 return sema.addConstant(result_ty, elem_ptr); 22487 }; 22488 const result_ty = try sema.elemPtrType(indexable_ty, null); 22489 22490 try sema.requireRuntimeBlock(block, src, runtime_src); 22491 return block.addPtrElemPtr(indexable, elem_index, result_ty); 22492 }, 22493 .One => { 22494 assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable 22495 return sema.elemPtrArray(block, src, indexable_ptr_src, indexable, elem_index_src, elem_index, init); 22496 }, 22497 } 22498 }, 22499 .Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init), 22500 .Struct => { 22501 // Tuple field access. 22502 const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime known"); 22503 const index = @intCast(u32, index_val.toUnsignedInt(target)); 22504 return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init); 22505 }, 22506 else => unreachable, 22507 } 22508 } 22509 22510 fn elemVal( 22511 sema: *Sema, 22512 block: *Block, 22513 src: LazySrcLoc, 22514 indexable: Air.Inst.Ref, 22515 elem_index_uncasted: Air.Inst.Ref, 22516 elem_index_src: LazySrcLoc, 22517 ) CompileError!Air.Inst.Ref { 22518 const indexable_src = src; // TODO better source location 22519 const indexable_ty = sema.typeOf(indexable); 22520 const target = sema.mod.getTarget(); 22521 22522 if (!indexable_ty.isIndexable()) { 22523 return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty.fmt(sema.mod)}); 22524 } 22525 22526 // TODO in case of a vector of pointers, we need to detect whether the element 22527 // index is a scalar or vector instead of unconditionally casting to usize. 22528 const elem_index = try sema.coerce(block, Type.usize, elem_index_uncasted, elem_index_src); 22529 22530 switch (indexable_ty.zigTypeTag()) { 22531 .Pointer => switch (indexable_ty.ptrSize()) { 22532 .Slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index), 22533 .Many, .C => { 22534 const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable); 22535 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); 22536 22537 const runtime_src = rs: { 22538 const indexable_val = maybe_indexable_val orelse break :rs indexable_src; 22539 const index_val = maybe_index_val orelse break :rs elem_index_src; 22540 const index = @intCast(usize, index_val.toUnsignedInt(target)); 22541 const elem_ptr_val = try indexable_val.elemPtr(indexable_ty, sema.arena, index, sema.mod); 22542 if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, indexable_ty)) |elem_val| { 22543 return sema.addConstant(indexable_ty.elemType2(), elem_val); 22544 } 22545 break :rs indexable_src; 22546 }; 22547 22548 try sema.requireRuntimeBlock(block, src, runtime_src); 22549 return block.addBinOp(.ptr_elem_val, indexable, elem_index); 22550 }, 22551 .One => { 22552 assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable 22553 const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false); 22554 return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src); 22555 }, 22556 }, 22557 .Array => return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index), 22558 .Vector => { 22559 // TODO: If the index is a vector, the result should be a vector. 22560 return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index); 22561 }, 22562 .Struct => { 22563 // Tuple field access. 22564 const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime known"); 22565 const index = @intCast(u32, index_val.toUnsignedInt(target)); 22566 return tupleField(sema, block, indexable_src, indexable, elem_index_src, index); 22567 }, 22568 else => unreachable, 22569 } 22570 } 22571 22572 fn validateRuntimeElemAccess( 22573 sema: *Sema, 22574 block: *Block, 22575 elem_index_src: LazySrcLoc, 22576 elem_ty: Type, 22577 parent_ty: Type, 22578 parent_src: LazySrcLoc, 22579 ) CompileError!void { 22580 const valid_rt = try sema.validateRunTimeType(block, elem_index_src, elem_ty, false); 22581 if (!valid_rt) { 22582 const msg = msg: { 22583 const msg = try sema.errMsg( 22584 block, 22585 elem_index_src, 22586 "values of type '{}' must be comptime known, but index value is runtime known", 22587 .{parent_ty.fmt(sema.mod)}, 22588 ); 22589 errdefer msg.destroy(sema.gpa); 22590 22591 const src_decl = sema.mod.declPtr(block.src_decl); 22592 try sema.explainWhyTypeIsComptime(block, elem_index_src, msg, parent_src.toSrcLoc(src_decl), parent_ty); 22593 22594 break :msg msg; 22595 }; 22596 return sema.failWithOwnedErrorMsg(msg); 22597 } 22598 } 22599 22600 fn tupleFieldPtr( 22601 sema: *Sema, 22602 block: *Block, 22603 tuple_ptr_src: LazySrcLoc, 22604 tuple_ptr: Air.Inst.Ref, 22605 field_index_src: LazySrcLoc, 22606 field_index: u32, 22607 init: bool, 22608 ) CompileError!Air.Inst.Ref { 22609 const tuple_ptr_ty = sema.typeOf(tuple_ptr); 22610 const tuple_ty = tuple_ptr_ty.childType(); 22611 const tuple_fields = tuple_ty.tupleFields(); 22612 22613 if (tuple_fields.types.len == 0) { 22614 return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{}); 22615 } 22616 22617 if (field_index >= tuple_fields.types.len) { 22618 return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ 22619 field_index, tuple_fields.types.len, 22620 }); 22621 } 22622 22623 const field_ty = tuple_fields.types[field_index]; 22624 const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{ 22625 .pointee_type = field_ty, 22626 .mutable = tuple_ptr_ty.ptrIsMutable(), 22627 .@"volatile" = tuple_ptr_ty.isVolatilePtr(), 22628 .@"addrspace" = tuple_ptr_ty.ptrAddressSpace(), 22629 }); 22630 22631 if (tuple_ty.structFieldValueComptime(field_index)) |default_val| { 22632 const val = try Value.Tag.comptime_field_ptr.create(sema.arena, .{ 22633 .field_ty = field_ty, 22634 .field_val = default_val, 22635 }); 22636 return sema.addConstant(ptr_field_ty, val); 22637 } 22638 22639 if (try sema.resolveMaybeUndefVal(block, tuple_ptr_src, tuple_ptr)) |tuple_ptr_val| { 22640 return sema.addConstant( 22641 ptr_field_ty, 22642 try Value.Tag.field_ptr.create(sema.arena, .{ 22643 .container_ptr = tuple_ptr_val, 22644 .container_ty = tuple_ty, 22645 .field_index = field_index, 22646 }), 22647 ); 22648 } 22649 22650 if (!init) { 22651 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_ptr_src); 22652 } 22653 22654 try sema.requireRuntimeBlock(block, tuple_ptr_src, null); 22655 return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty); 22656 } 22657 22658 fn tupleField( 22659 sema: *Sema, 22660 block: *Block, 22661 tuple_src: LazySrcLoc, 22662 tuple: Air.Inst.Ref, 22663 field_index_src: LazySrcLoc, 22664 field_index: u32, 22665 ) CompileError!Air.Inst.Ref { 22666 const tuple_ty = sema.typeOf(tuple); 22667 const tuple_fields = tuple_ty.tupleFields(); 22668 22669 if (tuple_fields.types.len == 0) { 22670 return sema.fail(block, tuple_src, "indexing into empty tuple is not allowed", .{}); 22671 } 22672 22673 if (field_index >= tuple_fields.types.len) { 22674 return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ 22675 field_index, tuple_fields.types.len, 22676 }); 22677 } 22678 22679 const field_ty = tuple_fields.types[field_index]; 22680 const field_val = tuple_fields.values[field_index]; 22681 22682 if (field_val.tag() != .unreachable_value) { 22683 return sema.addConstant(field_ty, field_val); // comptime field 22684 } 22685 22686 if (try sema.resolveMaybeUndefVal(block, tuple_src, tuple)) |tuple_val| { 22687 if (tuple_val.isUndef()) return sema.addConstUndef(field_ty); 22688 return sema.addConstant(field_ty, tuple_val.fieldValue(tuple_ty, field_index)); 22689 } 22690 22691 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src); 22692 22693 try sema.requireRuntimeBlock(block, tuple_src, null); 22694 return block.addStructFieldVal(tuple, field_index, field_ty); 22695 } 22696 22697 fn elemValArray( 22698 sema: *Sema, 22699 block: *Block, 22700 src: LazySrcLoc, 22701 array_src: LazySrcLoc, 22702 array: Air.Inst.Ref, 22703 elem_index_src: LazySrcLoc, 22704 elem_index: Air.Inst.Ref, 22705 ) CompileError!Air.Inst.Ref { 22706 const array_ty = sema.typeOf(array); 22707 const array_sent = array_ty.sentinel(); 22708 const array_len = array_ty.arrayLen(); 22709 const array_len_s = array_len + @boolToInt(array_sent != null); 22710 const elem_ty = array_ty.childType(); 22711 22712 if (array_len_s == 0) { 22713 return sema.fail(block, array_src, "indexing into empty array is not allowed", .{}); 22714 } 22715 22716 const maybe_undef_array_val = try sema.resolveMaybeUndefVal(block, array_src, array); 22717 // index must be defined since it can access out of bounds 22718 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); 22719 const target = sema.mod.getTarget(); 22720 22721 if (maybe_index_val) |index_val| { 22722 const index = @intCast(usize, index_val.toUnsignedInt(target)); 22723 if (array_sent) |s| { 22724 if (index == array_len) { 22725 return sema.addConstant(elem_ty, s); 22726 } 22727 } 22728 if (index >= array_len_s) { 22729 const sentinel_label: []const u8 = if (array_sent != null) " +1 (sentinel)" else ""; 22730 return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); 22731 } 22732 } 22733 if (maybe_undef_array_val) |array_val| { 22734 if (array_val.isUndef()) { 22735 return sema.addConstUndef(elem_ty); 22736 } 22737 if (maybe_index_val) |index_val| { 22738 const index = @intCast(usize, index_val.toUnsignedInt(target)); 22739 const elem_val = try array_val.elemValue(sema.mod, sema.arena, index); 22740 return sema.addConstant(elem_ty, elem_val); 22741 } 22742 } 22743 22744 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src); 22745 22746 const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src; 22747 try sema.requireRuntimeBlock(block, src, runtime_src); 22748 if (block.wantSafety()) { 22749 // Runtime check is only needed if unable to comptime check 22750 if (maybe_index_val == null) { 22751 const len_inst = try sema.addIntUnsigned(Type.usize, array_len); 22752 const cmp_op: Air.Inst.Tag = if (array_sent != null) .cmp_lte else .cmp_lt; 22753 try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op); 22754 } 22755 } 22756 return block.addBinOp(.array_elem_val, array, elem_index); 22757 } 22758 22759 fn elemPtrArray( 22760 sema: *Sema, 22761 block: *Block, 22762 src: LazySrcLoc, 22763 array_ptr_src: LazySrcLoc, 22764 array_ptr: Air.Inst.Ref, 22765 elem_index_src: LazySrcLoc, 22766 elem_index: Air.Inst.Ref, 22767 init: bool, 22768 ) CompileError!Air.Inst.Ref { 22769 const target = sema.mod.getTarget(); 22770 const array_ptr_ty = sema.typeOf(array_ptr); 22771 const array_ty = array_ptr_ty.childType(); 22772 const array_sent = array_ty.sentinel() != null; 22773 const array_len = array_ty.arrayLen(); 22774 const array_len_s = array_len + @boolToInt(array_sent); 22775 22776 if (array_len_s == 0) { 22777 return sema.fail(block, array_ptr_src, "indexing into empty array is not allowed", .{}); 22778 } 22779 22780 const maybe_undef_array_ptr_val = try sema.resolveMaybeUndefVal(block, array_ptr_src, array_ptr); 22781 // The index must not be undefined since it can be out of bounds. 22782 const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { 22783 const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(target)); 22784 if (index >= array_len_s) { 22785 const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; 22786 return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); 22787 } 22788 break :o index; 22789 } else null; 22790 22791 const elem_ptr_ty = try sema.elemPtrType(array_ptr_ty, offset); 22792 22793 if (maybe_undef_array_ptr_val) |array_ptr_val| { 22794 if (array_ptr_val.isUndef()) { 22795 return sema.addConstUndef(elem_ptr_ty); 22796 } 22797 if (offset) |index| { 22798 const elem_ptr = try array_ptr_val.elemPtr(array_ptr_ty, sema.arena, index, sema.mod); 22799 return sema.addConstant(elem_ptr_ty, elem_ptr); 22800 } 22801 } 22802 22803 if (!init) { 22804 try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(), array_ty, array_ptr_src); 22805 } 22806 22807 const runtime_src = if (maybe_undef_array_ptr_val != null) elem_index_src else array_ptr_src; 22808 try sema.requireRuntimeBlock(block, src, runtime_src); 22809 22810 // Runtime check is only needed if unable to comptime check. 22811 if (block.wantSafety() and offset == null) { 22812 const len_inst = try sema.addIntUnsigned(Type.usize, array_len); 22813 const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt; 22814 try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op); 22815 } 22816 22817 return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty); 22818 } 22819 22820 fn elemValSlice( 22821 sema: *Sema, 22822 block: *Block, 22823 src: LazySrcLoc, 22824 slice_src: LazySrcLoc, 22825 slice: Air.Inst.Ref, 22826 elem_index_src: LazySrcLoc, 22827 elem_index: Air.Inst.Ref, 22828 ) CompileError!Air.Inst.Ref { 22829 const slice_ty = sema.typeOf(slice); 22830 const slice_sent = slice_ty.sentinel() != null; 22831 const elem_ty = slice_ty.elemType2(); 22832 var runtime_src = slice_src; 22833 22834 // slice must be defined since it can dereferenced as null 22835 const maybe_slice_val = try sema.resolveDefinedValue(block, slice_src, slice); 22836 // index must be defined since it can index out of bounds 22837 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); 22838 const target = sema.mod.getTarget(); 22839 22840 if (maybe_slice_val) |slice_val| { 22841 runtime_src = elem_index_src; 22842 const slice_len = slice_val.sliceLen(sema.mod); 22843 const slice_len_s = slice_len + @boolToInt(slice_sent); 22844 if (slice_len_s == 0) { 22845 return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); 22846 } 22847 if (maybe_index_val) |index_val| { 22848 const index = @intCast(usize, index_val.toUnsignedInt(target)); 22849 if (index >= slice_len_s) { 22850 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; 22851 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); 22852 } 22853 const elem_ptr_val = try slice_val.elemPtr(slice_ty, sema.arena, index, sema.mod); 22854 if (try sema.pointerDeref(block, slice_src, elem_ptr_val, slice_ty)) |elem_val| { 22855 return sema.addConstant(elem_ty, elem_val); 22856 } 22857 runtime_src = slice_src; 22858 } 22859 } 22860 22861 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src); 22862 22863 try sema.requireRuntimeBlock(block, src, runtime_src); 22864 if (block.wantSafety()) { 22865 const len_inst = if (maybe_slice_val) |slice_val| 22866 try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod)) 22867 else 22868 try block.addTyOp(.slice_len, Type.usize, slice); 22869 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; 22870 try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op); 22871 } 22872 try sema.queueFullTypeResolution(sema.typeOf(slice)); 22873 return block.addBinOp(.slice_elem_val, slice, elem_index); 22874 } 22875 22876 fn elemPtrSlice( 22877 sema: *Sema, 22878 block: *Block, 22879 src: LazySrcLoc, 22880 slice_src: LazySrcLoc, 22881 slice: Air.Inst.Ref, 22882 elem_index_src: LazySrcLoc, 22883 elem_index: Air.Inst.Ref, 22884 ) CompileError!Air.Inst.Ref { 22885 const target = sema.mod.getTarget(); 22886 const slice_ty = sema.typeOf(slice); 22887 const slice_sent = slice_ty.sentinel() != null; 22888 22889 const maybe_undef_slice_val = try sema.resolveMaybeUndefVal(block, slice_src, slice); 22890 // The index must not be undefined since it can be out of bounds. 22891 const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { 22892 const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(target)); 22893 break :o index; 22894 } else null; 22895 22896 const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset); 22897 22898 if (maybe_undef_slice_val) |slice_val| { 22899 if (slice_val.isUndef()) { 22900 return sema.addConstUndef(elem_ptr_ty); 22901 } 22902 const slice_len = slice_val.sliceLen(sema.mod); 22903 const slice_len_s = slice_len + @boolToInt(slice_sent); 22904 if (slice_len_s == 0) { 22905 return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); 22906 } 22907 if (offset) |index| { 22908 if (index >= slice_len_s) { 22909 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; 22910 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); 22911 } 22912 const elem_ptr_val = try slice_val.elemPtr(slice_ty, sema.arena, index, sema.mod); 22913 return sema.addConstant(elem_ptr_ty, elem_ptr_val); 22914 } 22915 } 22916 22917 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ptr_ty, slice_ty, slice_src); 22918 22919 const runtime_src = if (maybe_undef_slice_val != null) elem_index_src else slice_src; 22920 try sema.requireRuntimeBlock(block, src, runtime_src); 22921 if (block.wantSafety()) { 22922 const len_inst = len: { 22923 if (maybe_undef_slice_val) |slice_val| 22924 if (!slice_val.isUndef()) 22925 break :len try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod)); 22926 break :len try block.addTyOp(.slice_len, Type.usize, slice); 22927 }; 22928 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; 22929 try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op); 22930 } 22931 return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty); 22932 } 22933 22934 fn coerce( 22935 sema: *Sema, 22936 block: *Block, 22937 dest_ty_unresolved: Type, 22938 inst: Air.Inst.Ref, 22939 inst_src: LazySrcLoc, 22940 ) CompileError!Air.Inst.Ref { 22941 return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, .{}) catch |err| switch (err) { 22942 error.NotCoercible => unreachable, 22943 else => |e| return e, 22944 }; 22945 } 22946 22947 const CoersionError = CompileError || error{ 22948 /// When coerce is called recursively, this error should be returned instead of using `fail` 22949 /// to ensure correct types in compile errors. 22950 NotCoercible, 22951 }; 22952 22953 const CoerceOpts = struct { 22954 /// Should coerceExtra emit error messages. 22955 report_err: bool = true, 22956 /// Ignored if `report_err == false`. 22957 is_ret: bool = false, 22958 /// Should coercion to comptime_int ermit an error message. 22959 no_cast_to_comptime_int: bool = false, 22960 }; 22961 22962 fn coerceExtra( 22963 sema: *Sema, 22964 block: *Block, 22965 dest_ty_unresolved: Type, 22966 inst: Air.Inst.Ref, 22967 inst_src: LazySrcLoc, 22968 opts: CoerceOpts, 22969 ) CoersionError!Air.Inst.Ref { 22970 switch (dest_ty_unresolved.tag()) { 22971 .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src), 22972 .generic_poison => return inst, 22973 else => {}, 22974 } 22975 const dest_ty_src = inst_src; // TODO better source location 22976 const dest_ty = try sema.resolveTypeFields(block, dest_ty_src, dest_ty_unresolved); 22977 const inst_ty = try sema.resolveTypeFields(block, inst_src, sema.typeOf(inst)); 22978 const target = sema.mod.getTarget(); 22979 // If the types are the same, we can return the operand. 22980 if (dest_ty.eql(inst_ty, sema.mod)) 22981 return inst; 22982 22983 const arena = sema.arena; 22984 const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst); 22985 22986 var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src); 22987 if (in_memory_result == .ok) { 22988 if (maybe_inst_val) |val| { 22989 // Keep the comptime Value representation; take the new type. 22990 return sema.addConstant(dest_ty, val); 22991 } 22992 try sema.requireRuntimeBlock(block, inst_src, null); 22993 return block.addBitCast(dest_ty, inst); 22994 } 22995 22996 const is_undef = if (maybe_inst_val) |val| val.isUndef() else false; 22997 22998 switch (dest_ty.zigTypeTag()) { 22999 .Optional => optional: { 23000 // undefined sets the optional bit also to undefined. 23001 if (is_undef) { 23002 return sema.addConstUndef(dest_ty); 23003 } 23004 23005 // null to ?T 23006 if (inst_ty.zigTypeTag() == .Null) { 23007 return sema.addConstant(dest_ty, Value.@"null"); 23008 } 23009 23010 // cast from ?*T and ?[*]T to ?*anyopaque 23011 // but don't do it if the source type is a double pointer 23012 if (dest_ty.isPtrLikeOptional() and dest_ty.elemType2().tag() == .anyopaque and 23013 inst_ty.isPtrLikeOptional() and inst_ty.elemType2().zigTypeTag() != .Pointer) 23014 { 23015 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional; 23016 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); 23017 } 23018 23019 // T to ?T 23020 const child_type = try dest_ty.optionalChildAlloc(sema.arena); 23021 const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) { 23022 error.NotCoercible => { 23023 if (in_memory_result == .no_match) { 23024 // Try to give more useful notes 23025 in_memory_result = try sema.coerceInMemoryAllowed(block, child_type, inst_ty, false, target, dest_ty_src, inst_src); 23026 } 23027 break :optional; 23028 }, 23029 else => |e| return e, 23030 }; 23031 return try sema.wrapOptional(block, dest_ty, intermediate, inst_src); 23032 }, 23033 .Pointer => pointer: { 23034 const dest_info = dest_ty.ptrInfo().data; 23035 23036 // Function body to function pointer. 23037 if (inst_ty.zigTypeTag() == .Fn) { 23038 const fn_val = try sema.resolveConstValue(block, .unneeded, inst, undefined); 23039 const fn_decl = fn_val.pointerDecl().?; 23040 const inst_as_ptr = try sema.analyzeDeclRef(fn_decl); 23041 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src); 23042 } 23043 23044 // *T to *[1]T 23045 single_item: { 23046 if (dest_info.size != .One) break :single_item; 23047 if (!inst_ty.isSinglePointer()) break :single_item; 23048 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; 23049 const ptr_elem_ty = inst_ty.childType(); 23050 const array_ty = dest_info.pointee_type; 23051 if (array_ty.zigTypeTag() != .Array) break :single_item; 23052 const array_elem_ty = array_ty.childType(); 23053 const dest_is_mut = dest_info.mutable; 23054 switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { 23055 .ok => {}, 23056 else => break :single_item, 23057 } 23058 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); 23059 } 23060 23061 // Coercions where the source is a single pointer to an array. 23062 src_array_ptr: { 23063 if (!inst_ty.isSinglePointer()) break :src_array_ptr; 23064 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; 23065 const array_ty = inst_ty.childType(); 23066 if (array_ty.zigTypeTag() != .Array) break :src_array_ptr; 23067 const array_elem_type = array_ty.childType(); 23068 const dest_is_mut = dest_info.mutable; 23069 23070 const dst_elem_type = dest_info.pointee_type; 23071 const elem_res = try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src); 23072 switch (elem_res) { 23073 .ok => {}, 23074 else => { 23075 in_memory_result = .{ .ptr_child = .{ 23076 .child = try elem_res.dupe(sema.arena), 23077 .actual = array_elem_type, 23078 .wanted = dst_elem_type, 23079 } }; 23080 break :src_array_ptr; 23081 }, 23082 } 23083 23084 if (dest_info.sentinel) |dest_sent| { 23085 if (array_ty.sentinel()) |inst_sent| { 23086 if (!dest_sent.eql(inst_sent, dst_elem_type, sema.mod)) { 23087 in_memory_result = .{ .ptr_sentinel = .{ 23088 .actual = inst_sent, 23089 .wanted = dest_sent, 23090 .ty = dst_elem_type, 23091 } }; 23092 break :src_array_ptr; 23093 } 23094 } else { 23095 in_memory_result = .{ .ptr_sentinel = .{ 23096 .actual = Value.initTag(.unreachable_value), 23097 .wanted = dest_sent, 23098 .ty = dst_elem_type, 23099 } }; 23100 break :src_array_ptr; 23101 } 23102 } 23103 23104 switch (dest_info.size) { 23105 .Slice => { 23106 // *[N]T to []T 23107 return sema.coerceArrayPtrToSlice(block, dest_ty, inst, inst_src); 23108 }, 23109 .C => { 23110 // *[N]T to [*c]T 23111 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); 23112 }, 23113 .Many => { 23114 // *[N]T to [*]T 23115 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); 23116 }, 23117 .One => {}, 23118 } 23119 } 23120 23121 // coercion from C pointer 23122 if (inst_ty.isCPtr()) src_c_ptr: { 23123 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :src_c_ptr; 23124 // In this case we must add a safety check because the C pointer 23125 // could be null. 23126 const src_elem_ty = inst_ty.childType(); 23127 const dest_is_mut = dest_info.mutable; 23128 const dst_elem_type = dest_info.pointee_type; 23129 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { 23130 .ok => {}, 23131 else => break :src_c_ptr, 23132 } 23133 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); 23134 } 23135 23136 // cast from *T and [*]T to *anyopaque 23137 // but don't do it if the source type is a double pointer 23138 if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer and 23139 inst_ty.childType().zigTypeTag() != .Pointer and sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) 23140 { 23141 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); 23142 } 23143 23144 switch (dest_info.size) { 23145 // coercion to C pointer 23146 .C => switch (inst_ty.zigTypeTag()) { 23147 .Null => { 23148 return sema.addConstant(dest_ty, Value.@"null"); 23149 }, 23150 .ComptimeInt => { 23151 const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) { 23152 error.NotCoercible => break :pointer, 23153 else => |e| return e, 23154 }; 23155 return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); 23156 }, 23157 .Int => { 23158 const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) { 23159 .signed => Type.isize, 23160 .unsigned => Type.usize, 23161 }; 23162 const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) { 23163 error.NotCoercible => { 23164 // Try to give more useful notes 23165 in_memory_result = try sema.coerceInMemoryAllowed(block, ptr_size_ty, inst_ty, false, target, dest_ty_src, inst_src); 23166 break :pointer; 23167 }, 23168 else => |e| return e, 23169 }; 23170 return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); 23171 }, 23172 .Pointer => p: { 23173 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p; 23174 const inst_info = inst_ty.ptrInfo().data; 23175 switch (try sema.coerceInMemoryAllowed( 23176 block, 23177 dest_info.pointee_type, 23178 inst_info.pointee_type, 23179 dest_info.mutable, 23180 target, 23181 dest_ty_src, 23182 inst_src, 23183 )) { 23184 .ok => {}, 23185 else => break :p, 23186 } 23187 if (inst_info.size == .Slice) { 23188 if (dest_info.sentinel == null or inst_info.sentinel == null or 23189 !dest_info.sentinel.?.eql(inst_info.sentinel.?, dest_info.pointee_type, sema.mod)) 23190 break :p; 23191 23192 const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); 23193 return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src); 23194 } 23195 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); 23196 }, 23197 else => {}, 23198 }, 23199 .One => switch (dest_info.pointee_type.zigTypeTag()) { 23200 .Union => { 23201 // pointer to anonymous struct to pointer to union 23202 if (inst_ty.isSinglePointer() and 23203 inst_ty.childType().isAnonStruct() and 23204 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) 23205 { 23206 return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src); 23207 } 23208 }, 23209 .Struct => { 23210 // pointer to anonymous struct to pointer to struct 23211 if (inst_ty.isSinglePointer() and 23212 inst_ty.childType().isAnonStruct() and 23213 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) 23214 { 23215 return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src); 23216 } 23217 }, 23218 .Array => { 23219 // pointer to tuple to pointer to array 23220 if (inst_ty.isSinglePointer() and 23221 inst_ty.childType().isTuple() and 23222 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) 23223 { 23224 return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src); 23225 } 23226 }, 23227 else => {}, 23228 }, 23229 .Slice => { 23230 // pointer to tuple to slice 23231 if (inst_ty.isSinglePointer() and inst_ty.childType().isTuple() and dest_info.size == .Slice and 23232 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) 23233 { 23234 return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src); 23235 } 23236 23237 // empty tuple to zero-length slice 23238 // note that this allows coercing to a mutable slice. 23239 if (inst_ty.isSinglePointer() and 23240 inst_ty.childType().tag() == .empty_struct_literal and 23241 dest_info.size == .Slice) 23242 { 23243 const slice_val = try Value.Tag.slice.create(sema.arena, .{ 23244 .ptr = Value.undef, 23245 .len = Value.zero, 23246 }); 23247 return sema.addConstant(dest_ty, slice_val); 23248 } 23249 23250 if (inst_ty.zigTypeTag() == .Array) { 23251 return sema.fail( 23252 block, 23253 inst_src, 23254 "array literal requires address-of operator (&) to coerce to slice type '{}'", 23255 .{dest_ty.fmt(sema.mod)}, 23256 ); 23257 } 23258 }, 23259 .Many => p: { 23260 if (!inst_ty.isSlice()) break :p; 23261 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p; 23262 const inst_info = inst_ty.ptrInfo().data; 23263 23264 switch (try sema.coerceInMemoryAllowed( 23265 block, 23266 dest_info.pointee_type, 23267 inst_info.pointee_type, 23268 dest_info.mutable, 23269 target, 23270 dest_ty_src, 23271 inst_src, 23272 )) { 23273 .ok => {}, 23274 else => break :p, 23275 } 23276 23277 if (dest_info.sentinel == null or inst_info.sentinel == null or 23278 !dest_info.sentinel.?.eql(inst_info.sentinel.?, dest_info.pointee_type, sema.mod)) 23279 break :p; 23280 23281 const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); 23282 return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src); 23283 }, 23284 } 23285 }, 23286 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) { 23287 .Float, .ComptimeFloat => float: { 23288 const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse { 23289 if (dest_ty.zigTypeTag() == .ComptimeInt) { 23290 if (!opts.report_err) return error.NotCoercible; 23291 return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime known"); 23292 } 23293 break :float; 23294 }; 23295 23296 if (val.floatHasFraction()) { 23297 return sema.fail( 23298 block, 23299 inst_src, 23300 "fractional component prevents float value '{}' from coercion to type '{}'", 23301 .{ val.fmtValue(inst_ty, sema.mod), dest_ty.fmt(sema.mod) }, 23302 ); 23303 } 23304 const result_val = try sema.floatToInt(block, inst_src, val, inst_ty, dest_ty); 23305 return try sema.addConstant(dest_ty, result_val); 23306 }, 23307 .Int, .ComptimeInt => { 23308 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| { 23309 // comptime known integer to other number 23310 if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) { 23311 if (!opts.report_err) return error.NotCoercible; 23312 return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) }); 23313 } 23314 return try sema.addConstant(dest_ty, val); 23315 } 23316 if (dest_ty.zigTypeTag() == .ComptimeInt) { 23317 if (!opts.report_err) return error.NotCoercible; 23318 if (opts.no_cast_to_comptime_int) return inst; 23319 return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime known"); 23320 } 23321 23322 // integer widening 23323 const dst_info = dest_ty.intInfo(target); 23324 const src_info = inst_ty.intInfo(target); 23325 if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or 23326 // small enough unsigned ints can get casted to large enough signed ints 23327 (dst_info.signedness == .signed and dst_info.bits > src_info.bits)) 23328 { 23329 try sema.requireRuntimeBlock(block, inst_src, null); 23330 return block.addTyOp(.intcast, dest_ty, inst); 23331 } 23332 }, 23333 .Undefined => { 23334 return sema.addConstUndef(dest_ty); 23335 }, 23336 else => {}, 23337 }, 23338 .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag()) { 23339 .ComptimeFloat => { 23340 const val = try sema.resolveConstValue(block, .unneeded, inst, undefined); 23341 const result_val = try val.floatCast(sema.arena, dest_ty, target); 23342 return try sema.addConstant(dest_ty, result_val); 23343 }, 23344 .Float => { 23345 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| { 23346 const result_val = try val.floatCast(sema.arena, dest_ty, target); 23347 if (!val.eql(result_val, dest_ty, sema.mod)) { 23348 return sema.fail( 23349 block, 23350 inst_src, 23351 "type '{}' cannot represent float value '{}'", 23352 .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) }, 23353 ); 23354 } 23355 return try sema.addConstant(dest_ty, result_val); 23356 } else if (dest_ty.zigTypeTag() == .ComptimeFloat) { 23357 if (!opts.report_err) return error.NotCoercible; 23358 return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime known"); 23359 } 23360 23361 // float widening 23362 const src_bits = inst_ty.floatBits(target); 23363 const dst_bits = dest_ty.floatBits(target); 23364 if (dst_bits >= src_bits) { 23365 try sema.requireRuntimeBlock(block, inst_src, null); 23366 return block.addTyOp(.fpext, dest_ty, inst); 23367 } 23368 }, 23369 .Int, .ComptimeInt => int: { 23370 const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse { 23371 if (dest_ty.zigTypeTag() == .ComptimeFloat) { 23372 if (!opts.report_err) return error.NotCoercible; 23373 return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime known"); 23374 } 23375 break :int; 23376 }; 23377 const result_val = try val.intToFloatAdvanced(sema.arena, inst_ty, dest_ty, target, sema.kit(block, inst_src)); 23378 // TODO implement this compile error 23379 //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty); 23380 //if (!int_again_val.eql(val, inst_ty, mod)) { 23381 // return sema.fail( 23382 // block, 23383 // inst_src, 23384 // "type '{}' cannot represent integer value '{}'", 23385 // .{ dest_ty.fmt(sema.mod), val }, 23386 // ); 23387 //} 23388 return try sema.addConstant(dest_ty, result_val); 23389 }, 23390 .Undefined => { 23391 return sema.addConstUndef(dest_ty); 23392 }, 23393 else => {}, 23394 }, 23395 .Enum => switch (inst_ty.zigTypeTag()) { 23396 .EnumLiteral => { 23397 // enum literal to enum 23398 const val = try sema.resolveConstValue(block, .unneeded, inst, undefined); 23399 const bytes = val.castTag(.enum_literal).?.data; 23400 const field_index = dest_ty.enumFieldIndex(bytes) orelse { 23401 const msg = msg: { 23402 const msg = try sema.errMsg( 23403 block, 23404 inst_src, 23405 "no field named '{s}' in enum '{}'", 23406 .{ bytes, dest_ty.fmt(sema.mod) }, 23407 ); 23408 errdefer msg.destroy(sema.gpa); 23409 try sema.addDeclaredHereNote(msg, dest_ty); 23410 break :msg msg; 23411 }; 23412 return sema.failWithOwnedErrorMsg(msg); 23413 }; 23414 return sema.addConstant( 23415 dest_ty, 23416 try Value.Tag.enum_field_index.create(arena, @intCast(u32, field_index)), 23417 ); 23418 }, 23419 .Union => blk: { 23420 // union to its own tag type 23421 const union_tag_ty = inst_ty.unionTagType() orelse break :blk; 23422 if (union_tag_ty.eql(dest_ty, sema.mod)) { 23423 return sema.unionToTag(block, dest_ty, inst, inst_src); 23424 } 23425 }, 23426 .Undefined => { 23427 return sema.addConstUndef(dest_ty); 23428 }, 23429 else => {}, 23430 }, 23431 .ErrorUnion => switch (inst_ty.zigTypeTag()) { 23432 .ErrorUnion => eu: { 23433 if (maybe_inst_val) |inst_val| { 23434 switch (inst_val.tag()) { 23435 .undef => return sema.addConstUndef(dest_ty), 23436 .eu_payload => { 23437 const payload = try sema.addConstant( 23438 inst_ty.errorUnionPayload(), 23439 inst_val.castTag(.eu_payload).?.data, 23440 ); 23441 return sema.wrapErrorUnionPayload(block, dest_ty, payload, inst_src) catch |err| switch (err) { 23442 error.NotCoercible => break :eu, 23443 else => |e| return e, 23444 }; 23445 }, 23446 else => { 23447 const error_set = try sema.addConstant( 23448 inst_ty.errorUnionSet(), 23449 inst_val, 23450 ); 23451 return sema.wrapErrorUnionSet(block, dest_ty, error_set, inst_src); 23452 }, 23453 } 23454 } 23455 }, 23456 .ErrorSet => { 23457 // E to E!T 23458 return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src); 23459 }, 23460 .Undefined => { 23461 return sema.addConstUndef(dest_ty); 23462 }, 23463 else => eu: { 23464 // T to E!T 23465 return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src) catch |err| switch (err) { 23466 error.NotCoercible => break :eu, 23467 else => |e| return e, 23468 }; 23469 }, 23470 }, 23471 .Union => switch (inst_ty.zigTypeTag()) { 23472 .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src), 23473 .Struct => { 23474 if (inst_ty.isAnonStruct()) { 23475 return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src); 23476 } 23477 }, 23478 .Undefined => { 23479 return sema.addConstUndef(dest_ty); 23480 }, 23481 else => {}, 23482 }, 23483 .Array => switch (inst_ty.zigTypeTag()) { 23484 .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src), 23485 .Struct => { 23486 if (inst == .empty_struct) { 23487 return sema.arrayInitEmpty(block, inst_src, dest_ty); 23488 } 23489 if (inst_ty.isTuple()) { 23490 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src); 23491 } 23492 }, 23493 .Undefined => { 23494 return sema.addConstUndef(dest_ty); 23495 }, 23496 else => {}, 23497 }, 23498 .Vector => switch (inst_ty.zigTypeTag()) { 23499 .Array, .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src), 23500 .Struct => { 23501 if (inst_ty.isTuple()) { 23502 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src); 23503 } 23504 }, 23505 .Undefined => { 23506 return sema.addConstUndef(dest_ty); 23507 }, 23508 else => {}, 23509 }, 23510 .Struct => { 23511 if (inst == .empty_struct) { 23512 return sema.structInitEmpty(block, dest_ty, dest_ty_src, inst_src); 23513 } 23514 if (inst_ty.isTupleOrAnonStruct()) { 23515 return sema.coerceTupleToStruct(block, dest_ty, dest_ty_src, inst, inst_src); 23516 } 23517 }, 23518 else => {}, 23519 } 23520 23521 // undefined to anything. We do this after the big switch above so that 23522 // special logic has a chance to run first, such as `*[N]T` to `[]T` which 23523 // should initialize the length field of the slice. 23524 if (is_undef) { 23525 return sema.addConstUndef(dest_ty); 23526 } 23527 23528 if (!opts.report_err) return error.NotCoercible; 23529 23530 if (opts.is_ret and dest_ty.zigTypeTag() == .NoReturn) { 23531 const msg = msg: { 23532 const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{}); 23533 errdefer msg.destroy(sema.gpa); 23534 23535 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; 23536 const src_decl = sema.mod.declPtr(sema.func.?.owner_decl); 23537 try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "'noreturn' declared here", .{}); 23538 break :msg msg; 23539 }; 23540 return sema.failWithOwnedErrorMsg(msg); 23541 } 23542 23543 const msg = msg: { 23544 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) }); 23545 errdefer msg.destroy(sema.gpa); 23546 23547 // E!T to T 23548 if (inst_ty.zigTypeTag() == .ErrorUnion and 23549 (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) 23550 { 23551 try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{}); 23552 try sema.errNote(block, inst_src, msg, "consider using `try`, `catch`, or `if`", .{}); 23553 } 23554 23555 // ?T to T 23556 var buf: Type.Payload.ElemType = undefined; 23557 if (inst_ty.zigTypeTag() == .Optional and 23558 (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(&buf), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) 23559 { 23560 try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{}); 23561 try sema.errNote(block, inst_src, msg, "consider using `.?`, `orelse`, or `if`", .{}); 23562 } 23563 23564 try in_memory_result.report(sema, block, inst_src, msg); 23565 23566 // Add notes about function return type 23567 if (opts.is_ret and sema.mod.test_functions.get(sema.func.?.owner_decl) == null) { 23568 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; 23569 const src_decl = sema.mod.declPtr(sema.func.?.owner_decl); 23570 if (inst_ty.isError() and !dest_ty.isError()) { 23571 try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function cannot return an error", .{}); 23572 } else { 23573 try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function return type declared here", .{}); 23574 } 23575 } 23576 23577 // TODO maybe add "cannot store an error in type '{}'" note 23578 23579 break :msg msg; 23580 }; 23581 return sema.failWithOwnedErrorMsg(msg); 23582 } 23583 23584 const InMemoryCoercionResult = union(enum) { 23585 ok, 23586 no_match: Pair, 23587 int_not_coercible: Int, 23588 error_union_payload: PairAndChild, 23589 array_len: IntPair, 23590 array_sentinel: Sentinel, 23591 array_elem: PairAndChild, 23592 vector_len: IntPair, 23593 vector_elem: PairAndChild, 23594 optional_shape: Pair, 23595 optional_child: PairAndChild, 23596 from_anyerror, 23597 missing_error: []const []const u8, 23598 /// true if wanted is var args 23599 fn_var_args: bool, 23600 /// true if wanted is generic 23601 fn_generic: bool, 23602 fn_param_count: IntPair, 23603 fn_param_noalias: IntPair, 23604 fn_param_comptime: ComptimeParam, 23605 fn_param: Param, 23606 fn_cc: CC, 23607 fn_return_type: PairAndChild, 23608 ptr_child: PairAndChild, 23609 ptr_addrspace: AddressSpace, 23610 ptr_sentinel: Sentinel, 23611 ptr_size: Size, 23612 ptr_qualifiers: Qualifiers, 23613 ptr_allowzero: Pair, 23614 ptr_bit_range: BitRange, 23615 ptr_alignment: IntPair, 23616 23617 const Pair = struct { 23618 actual: Type, 23619 wanted: Type, 23620 }; 23621 23622 const PairAndChild = struct { 23623 child: *InMemoryCoercionResult, 23624 actual: Type, 23625 wanted: Type, 23626 }; 23627 23628 const Param = struct { 23629 child: *InMemoryCoercionResult, 23630 actual: Type, 23631 wanted: Type, 23632 index: u64, 23633 }; 23634 23635 const ComptimeParam = struct { 23636 index: u64, 23637 wanted: bool, 23638 }; 23639 23640 const Sentinel = struct { 23641 // unreachable_value indicates no sentinel 23642 actual: Value, 23643 wanted: Value, 23644 ty: Type, 23645 }; 23646 23647 const Int = struct { 23648 actual_signedness: std.builtin.Signedness, 23649 wanted_signedness: std.builtin.Signedness, 23650 actual_bits: u16, 23651 wanted_bits: u16, 23652 }; 23653 23654 const IntPair = struct { 23655 actual: u64, 23656 wanted: u64, 23657 }; 23658 23659 const Size = struct { 23660 actual: std.builtin.Type.Pointer.Size, 23661 wanted: std.builtin.Type.Pointer.Size, 23662 }; 23663 23664 const Qualifiers = struct { 23665 actual_const: bool, 23666 wanted_const: bool, 23667 actual_volatile: bool, 23668 wanted_volatile: bool, 23669 }; 23670 23671 const AddressSpace = struct { 23672 actual: std.builtin.AddressSpace, 23673 wanted: std.builtin.AddressSpace, 23674 }; 23675 23676 const CC = struct { 23677 actual: std.builtin.CallingConvention, 23678 wanted: std.builtin.CallingConvention, 23679 }; 23680 23681 const BitRange = struct { 23682 actual_host: u16, 23683 wanted_host: u16, 23684 actual_offset: u16, 23685 wanted_offset: u16, 23686 }; 23687 23688 fn dupe(child: *const InMemoryCoercionResult, arena: Allocator) !*InMemoryCoercionResult { 23689 const res = try arena.create(InMemoryCoercionResult); 23690 res.* = child.*; 23691 return res; 23692 } 23693 23694 fn report(res: *const InMemoryCoercionResult, sema: *Sema, block: *Block, src: LazySrcLoc, msg: *Module.ErrorMsg) !void { 23695 var cur = res; 23696 while (true) switch (cur.*) { 23697 .ok => unreachable, 23698 .no_match => |types| { 23699 try sema.addDeclaredHereNote(msg, types.wanted); 23700 try sema.addDeclaredHereNote(msg, types.actual); 23701 break; 23702 }, 23703 .int_not_coercible => |int| { 23704 try sema.errNote(block, src, msg, "{s} {d}-bit int cannot represent all possible {s} {d}-bit values", .{ 23705 @tagName(int.wanted_signedness), int.wanted_bits, @tagName(int.actual_signedness), int.actual_bits, 23706 }); 23707 break; 23708 }, 23709 .error_union_payload => |pair| { 23710 try sema.errNote(block, src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{ 23711 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), 23712 }); 23713 cur = pair.child; 23714 }, 23715 .array_len => |lens| { 23716 try sema.errNote(block, src, msg, "array of length {d} cannot cast into an array of length {d}", .{ 23717 lens.actual, lens.wanted, 23718 }); 23719 break; 23720 }, 23721 .array_sentinel => |sentinel| { 23722 if (sentinel.actual.tag() != .unreachable_value) { 23723 try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{ 23724 sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod), 23725 }); 23726 } else { 23727 try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{ 23728 sentinel.wanted.fmtValue(sentinel.ty, sema.mod), 23729 }); 23730 } 23731 break; 23732 }, 23733 .array_elem => |pair| { 23734 try sema.errNote(block, src, msg, "array element type '{}' cannot cast into array element type '{}'", .{ 23735 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), 23736 }); 23737 cur = pair.child; 23738 }, 23739 .vector_len => |lens| { 23740 try sema.errNote(block, src, msg, "vector of length {d} cannot cast into a vector of length {d}", .{ 23741 lens.actual, lens.wanted, 23742 }); 23743 break; 23744 }, 23745 .vector_elem => |pair| { 23746 try sema.errNote(block, src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{ 23747 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), 23748 }); 23749 cur = pair.child; 23750 }, 23751 .optional_shape => |pair| { 23752 var buf_actual: Type.Payload.ElemType = undefined; 23753 var buf_wanted: Type.Payload.ElemType = undefined; 23754 try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ 23755 pair.actual.optionalChild(&buf_actual).fmt(sema.mod), pair.wanted.optionalChild(&buf_wanted).fmt(sema.mod), 23756 }); 23757 break; 23758 }, 23759 .optional_child => |pair| { 23760 try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ 23761 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), 23762 }); 23763 cur = pair.child; 23764 }, 23765 .from_anyerror => { 23766 try sema.errNote(block, src, msg, "global error set cannot cast into a smaller set", .{}); 23767 break; 23768 }, 23769 .missing_error => |missing_errors| { 23770 for (missing_errors) |err| { 23771 try sema.errNote(block, src, msg, "'error.{s}' not a member of destination error set", .{err}); 23772 } 23773 break; 23774 }, 23775 .fn_var_args => |wanted_var_args| { 23776 if (wanted_var_args) { 23777 try sema.errNote(block, src, msg, "non-variadic function cannot cast into a variadic function", .{}); 23778 } else { 23779 try sema.errNote(block, src, msg, "variadic function cannot cast into a non-variadic function", .{}); 23780 } 23781 break; 23782 }, 23783 .fn_generic => |wanted_generic| { 23784 if (wanted_generic) { 23785 try sema.errNote(block, src, msg, "non-generic function cannot cast into a generic function", .{}); 23786 } else { 23787 try sema.errNote(block, src, msg, "generic function cannot cast into a non-generic function", .{}); 23788 } 23789 break; 23790 }, 23791 .fn_param_count => |lens| { 23792 try sema.errNote(block, src, msg, "function with {d} parameters cannot cast into a function with {d} parameters", .{ 23793 lens.actual, lens.wanted, 23794 }); 23795 break; 23796 }, 23797 .fn_param_noalias => |param| { 23798 var index: u6 = 0; 23799 var actual_noalias = false; 23800 while (true) : (index += 1) { 23801 const actual = @truncate(u1, param.actual >> index); 23802 const wanted = @truncate(u1, param.wanted >> index); 23803 if (actual != wanted) { 23804 actual_noalias = actual == 1; 23805 break; 23806 } 23807 } 23808 if (!actual_noalias) { 23809 try sema.errNote(block, src, msg, "regular parameter {d} cannot cast into a noalias parameter", .{index}); 23810 } else { 23811 try sema.errNote(block, src, msg, "noalias parameter {d} cannot cast into a regular parameter", .{index}); 23812 } 23813 break; 23814 }, 23815 .fn_param_comptime => |param| { 23816 if (param.wanted) { 23817 try sema.errNote(block, src, msg, "non-comptime parameter {d} cannot cast into a comptime parameter", .{param.index}); 23818 } else { 23819 try sema.errNote(block, src, msg, "comptime parameter {d} cannot cast into a non-comptime parameter", .{param.index}); 23820 } 23821 break; 23822 }, 23823 .fn_param => |param| { 23824 try sema.errNote(block, src, msg, "parameter {d} '{}' cannot cast into '{}'", .{ 23825 param.index, param.actual.fmt(sema.mod), param.wanted.fmt(sema.mod), 23826 }); 23827 cur = param.child; 23828 }, 23829 .fn_cc => |cc| { 23830 try sema.errNote(block, src, msg, "calling convention {s} cannot cast into calling convention {s}", .{ @tagName(cc.actual), @tagName(cc.wanted) }); 23831 break; 23832 }, 23833 .fn_return_type => |pair| { 23834 try sema.errNote(block, src, msg, "return type '{}' cannot cast into return type '{}'", .{ 23835 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), 23836 }); 23837 cur = pair.child; 23838 }, 23839 .ptr_child => |pair| { 23840 try sema.errNote(block, src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{ 23841 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), 23842 }); 23843 cur = pair.child; 23844 }, 23845 .ptr_addrspace => |@"addrspace"| { 23846 try sema.errNote(block, src, msg, "address space '{s}' cannot cast into address space '{s}'", .{ @tagName(@"addrspace".actual), @tagName(@"addrspace".wanted) }); 23847 break; 23848 }, 23849 .ptr_sentinel => |sentinel| { 23850 if (sentinel.actual.tag() != .unreachable_value) { 23851 try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{ 23852 sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod), 23853 }); 23854 } else { 23855 try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{ 23856 sentinel.wanted.fmtValue(sentinel.ty, sema.mod), 23857 }); 23858 } 23859 break; 23860 }, 23861 .ptr_size => |size| { 23862 try sema.errNote(block, src, msg, "a {s} pointer cannot cast into a {s} pointer", .{ pointerSizeString(size.actual), pointerSizeString(size.wanted) }); 23863 break; 23864 }, 23865 .ptr_qualifiers => |qualifiers| { 23866 const ok_const = !qualifiers.actual_const or qualifiers.wanted_const; 23867 const ok_volatile = !qualifiers.actual_volatile or qualifiers.wanted_volatile; 23868 if (!ok_const) { 23869 try sema.errNote(block, src, msg, "cast discards const qualifier", .{}); 23870 } else if (!ok_volatile) { 23871 try sema.errNote(block, src, msg, "cast discards volatile qualifier", .{}); 23872 } 23873 break; 23874 }, 23875 .ptr_allowzero => |pair| { 23876 const wanted_allow_zero = pair.wanted.ptrAllowsZero(); 23877 const actual_allow_zero = pair.actual.ptrAllowsZero(); 23878 if (actual_allow_zero and !wanted_allow_zero) { 23879 try sema.errNote(block, src, msg, "'{}' could have null values which are illegal in type '{}'", .{ 23880 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), 23881 }); 23882 } else { 23883 try sema.errNote(block, src, msg, "mutable '{}' allows illegal null values stored to type '{}'", .{ 23884 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), 23885 }); 23886 } 23887 break; 23888 }, 23889 .ptr_bit_range => |bit_range| { 23890 if (bit_range.actual_host != bit_range.wanted_host) { 23891 try sema.errNote(block, src, msg, "pointer host size '{}' cannot cast into pointer host size '{}'", .{ 23892 bit_range.actual_host, bit_range.wanted_host, 23893 }); 23894 } 23895 if (bit_range.actual_offset != bit_range.wanted_offset) { 23896 try sema.errNote(block, src, msg, "pointer bit offset '{}' cannot cast into pointer bit offset '{}'", .{ 23897 bit_range.actual_offset, bit_range.wanted_offset, 23898 }); 23899 } 23900 break; 23901 }, 23902 .ptr_alignment => |pair| { 23903 try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{ 23904 pair.actual, pair.wanted, 23905 }); 23906 break; 23907 }, 23908 }; 23909 } 23910 }; 23911 23912 fn pointerSizeString(size: std.builtin.Type.Pointer.Size) []const u8 { 23913 return switch (size) { 23914 .One => "single", 23915 .Many => "many", 23916 .C => "C", 23917 .Slice => unreachable, 23918 }; 23919 } 23920 23921 /// If pointers have the same representation in runtime memory, a bitcast AIR instruction 23922 /// may be used for the coercion. 23923 /// * `const` attribute can be gained 23924 /// * `volatile` attribute can be gained 23925 /// * `allowzero` attribute can be gained (whether from explicit attribute, C pointer, or optional pointer) but only if !dest_is_mut 23926 /// * alignment can be decreased 23927 /// * bit offset attributes must match exactly 23928 /// * `*`/`[*]` must match exactly, but `[*c]` matches either one 23929 /// * sentinel-terminated pointers can coerce into `[*]` 23930 fn coerceInMemoryAllowed( 23931 sema: *Sema, 23932 block: *Block, 23933 dest_ty: Type, 23934 src_ty: Type, 23935 dest_is_mut: bool, 23936 target: std.Target, 23937 dest_src: LazySrcLoc, 23938 src_src: LazySrcLoc, 23939 ) CompileError!InMemoryCoercionResult { 23940 if (dest_ty.eql(src_ty, sema.mod)) 23941 return .ok; 23942 23943 // Differently-named integers with the same number of bits. 23944 if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) { 23945 const dest_info = dest_ty.intInfo(target); 23946 const src_info = src_ty.intInfo(target); 23947 23948 if (dest_info.signedness == src_info.signedness and 23949 dest_info.bits == src_info.bits) 23950 { 23951 return .ok; 23952 } 23953 23954 if ((src_info.signedness == dest_info.signedness and dest_info.bits < src_info.bits) or 23955 // small enough unsigned ints can get casted to large enough signed ints 23956 (dest_info.signedness == .signed and (src_info.signedness == .unsigned or dest_info.bits <= src_info.bits)) or 23957 (dest_info.signedness == .unsigned and src_info.signedness == .signed)) 23958 { 23959 return InMemoryCoercionResult{ .int_not_coercible = .{ 23960 .actual_signedness = src_info.signedness, 23961 .wanted_signedness = dest_info.signedness, 23962 .actual_bits = src_info.bits, 23963 .wanted_bits = dest_info.bits, 23964 } }; 23965 } 23966 } 23967 23968 // Differently-named floats with the same number of bits. 23969 if (dest_ty.zigTypeTag() == .Float and src_ty.zigTypeTag() == .Float) { 23970 const dest_bits = dest_ty.floatBits(target); 23971 const src_bits = src_ty.floatBits(target); 23972 if (dest_bits == src_bits) { 23973 return .ok; 23974 } 23975 } 23976 23977 // Pointers / Pointer-like Optionals 23978 var dest_buf: Type.Payload.ElemType = undefined; 23979 var src_buf: Type.Payload.ElemType = undefined; 23980 const maybe_dest_ptr_ty = try sema.typePtrOrOptionalPtrTy(block, dest_ty, &dest_buf, dest_src); 23981 const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(block, src_ty, &src_buf, src_src); 23982 if (maybe_dest_ptr_ty) |dest_ptr_ty| { 23983 if (maybe_src_ptr_ty) |src_ptr_ty| { 23984 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target, dest_src, src_src); 23985 } 23986 } 23987 23988 // Slices 23989 if (dest_ty.isSlice() and src_ty.isSlice()) { 23990 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src); 23991 } 23992 23993 const dest_tag = dest_ty.zigTypeTag(); 23994 const src_tag = src_ty.zigTypeTag(); 23995 23996 // Functions 23997 if (dest_tag == .Fn and src_tag == .Fn) { 23998 return try sema.coerceInMemoryAllowedFns(block, dest_ty, src_ty, target, dest_src, src_src); 23999 } 24000 24001 // Error Unions 24002 if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) { 24003 const dest_payload = dest_ty.errorUnionPayload(); 24004 const src_payload = src_ty.errorUnionPayload(); 24005 const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src); 24006 if (child != .ok) { 24007 return InMemoryCoercionResult{ .error_union_payload = .{ 24008 .child = try child.dupe(sema.arena), 24009 .actual = src_payload, 24010 .wanted = dest_payload, 24011 } }; 24012 } 24013 return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target, dest_src, src_src); 24014 } 24015 24016 // Error Sets 24017 if (dest_tag == .ErrorSet and src_tag == .ErrorSet) { 24018 return try sema.coerceInMemoryAllowedErrorSets(block, dest_ty, src_ty, dest_src, src_src); 24019 } 24020 24021 // Arrays 24022 if (dest_tag == .Array and src_tag == .Array) { 24023 const dest_info = dest_ty.arrayInfo(); 24024 const src_info = src_ty.arrayInfo(); 24025 if (dest_info.len != src_info.len) { 24026 return InMemoryCoercionResult{ .array_len = .{ 24027 .actual = src_info.len, 24028 .wanted = dest_info.len, 24029 } }; 24030 } 24031 24032 const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src); 24033 if (child != .ok) { 24034 return InMemoryCoercionResult{ .array_elem = .{ 24035 .child = try child.dupe(sema.arena), 24036 .actual = src_info.elem_type, 24037 .wanted = dest_info.elem_type, 24038 } }; 24039 } 24040 const ok_sent = dest_info.sentinel == null or 24041 (src_info.sentinel != null and 24042 dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, sema.mod)); 24043 if (!ok_sent) { 24044 return InMemoryCoercionResult{ .array_sentinel = .{ 24045 .actual = src_info.sentinel orelse Value.initTag(.unreachable_value), 24046 .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value), 24047 .ty = dest_info.elem_type, 24048 } }; 24049 } 24050 return .ok; 24051 } 24052 24053 // Vectors 24054 if (dest_tag == .Vector and src_tag == .Vector) { 24055 const dest_len = dest_ty.vectorLen(); 24056 const src_len = src_ty.vectorLen(); 24057 if (dest_len != src_len) { 24058 return InMemoryCoercionResult{ .vector_len = .{ 24059 .actual = src_len, 24060 .wanted = dest_len, 24061 } }; 24062 } 24063 24064 const dest_elem_ty = dest_ty.scalarType(); 24065 const src_elem_ty = src_ty.scalarType(); 24066 const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src); 24067 if (child != .ok) { 24068 return InMemoryCoercionResult{ .vector_elem = .{ 24069 .child = try child.dupe(sema.arena), 24070 .actual = src_elem_ty, 24071 .wanted = dest_elem_ty, 24072 } }; 24073 } 24074 24075 return .ok; 24076 } 24077 24078 // Optionals 24079 if (dest_tag == .Optional and src_tag == .Optional) { 24080 if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) { 24081 return InMemoryCoercionResult{ .optional_shape = .{ 24082 .actual = src_ty, 24083 .wanted = dest_ty, 24084 } }; 24085 } 24086 const dest_child_type = dest_ty.optionalChild(&dest_buf); 24087 const src_child_type = src_ty.optionalChild(&src_buf); 24088 24089 const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src); 24090 if (child != .ok) { 24091 return InMemoryCoercionResult{ .optional_child = .{ 24092 .child = try child.dupe(sema.arena), 24093 .actual = try src_child_type.copy(sema.arena), 24094 .wanted = try dest_child_type.copy(sema.arena), 24095 } }; 24096 } 24097 24098 return .ok; 24099 } 24100 24101 return InMemoryCoercionResult{ .no_match = .{ 24102 .actual = dest_ty, 24103 .wanted = src_ty, 24104 } }; 24105 } 24106 24107 fn coerceInMemoryAllowedErrorSets( 24108 sema: *Sema, 24109 block: *Block, 24110 dest_ty: Type, 24111 src_ty: Type, 24112 dest_src: LazySrcLoc, 24113 src_src: LazySrcLoc, 24114 ) !InMemoryCoercionResult { 24115 // Coercion to `anyerror`. Note that this check can return false negatives 24116 // in case the error sets did not get resolved. 24117 if (dest_ty.isAnyError()) { 24118 return .ok; 24119 } 24120 24121 if (dest_ty.castTag(.error_set_inferred)) |dst_payload| { 24122 const dst_ies = dst_payload.data; 24123 // We will make an effort to return `ok` without resolving either error set, to 24124 // avoid unnecessary "unable to resolve error set" dependency loop errors. 24125 switch (src_ty.tag()) { 24126 .error_set_inferred => { 24127 // If both are inferred error sets of functions, and 24128 // the dest includes the source function, the coercion is OK. 24129 // This check is important because it works without forcing a full resolution 24130 // of inferred error sets. 24131 const src_ies = src_ty.castTag(.error_set_inferred).?.data; 24132 24133 if (dst_ies.inferred_error_sets.contains(src_ies)) { 24134 return .ok; 24135 } 24136 }, 24137 .error_set_single => { 24138 const name = src_ty.castTag(.error_set_single).?.data; 24139 if (dst_ies.errors.contains(name)) return .ok; 24140 }, 24141 .error_set_merged => { 24142 const names = src_ty.castTag(.error_set_merged).?.data.keys(); 24143 for (names) |name| { 24144 if (!dst_ies.errors.contains(name)) break; 24145 } else return .ok; 24146 }, 24147 .error_set => { 24148 const names = src_ty.castTag(.error_set).?.data.names.keys(); 24149 for (names) |name| { 24150 if (!dst_ies.errors.contains(name)) break; 24151 } else return .ok; 24152 }, 24153 .anyerror => {}, 24154 else => unreachable, 24155 } 24156 24157 if (dst_ies.func == sema.owner_func) { 24158 // We are trying to coerce an error set to the current function's 24159 // inferred error set. 24160 try dst_ies.addErrorSet(sema.gpa, src_ty); 24161 return .ok; 24162 } 24163 24164 try sema.resolveInferredErrorSet(block, dest_src, dst_payload.data); 24165 // isAnyError might have changed from a false negative to a true positive after resolution. 24166 if (dest_ty.isAnyError()) { 24167 return .ok; 24168 } 24169 } 24170 24171 var missing_error_buf = std.ArrayList([]const u8).init(sema.gpa); 24172 defer missing_error_buf.deinit(); 24173 24174 switch (src_ty.tag()) { 24175 .error_set_inferred => { 24176 const src_data = src_ty.castTag(.error_set_inferred).?.data; 24177 24178 try sema.resolveInferredErrorSet(block, src_src, src_data); 24179 // src anyerror status might have changed after the resolution. 24180 if (src_ty.isAnyError()) { 24181 // dest_ty.isAnyError() == true is already checked for at this point. 24182 return .from_anyerror; 24183 } 24184 24185 for (src_data.errors.keys()) |key| { 24186 if (!dest_ty.errorSetHasField(key)) { 24187 try missing_error_buf.append(key); 24188 } 24189 } 24190 24191 if (missing_error_buf.items.len != 0) { 24192 return InMemoryCoercionResult{ 24193 .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), 24194 }; 24195 } 24196 24197 return .ok; 24198 }, 24199 .error_set_single => { 24200 const name = src_ty.castTag(.error_set_single).?.data; 24201 if (dest_ty.errorSetHasField(name)) { 24202 return .ok; 24203 } 24204 const list = try sema.arena.alloc([]const u8, 1); 24205 list[0] = name; 24206 return InMemoryCoercionResult{ .missing_error = list }; 24207 }, 24208 .error_set_merged => { 24209 const names = src_ty.castTag(.error_set_merged).?.data.keys(); 24210 for (names) |name| { 24211 if (!dest_ty.errorSetHasField(name)) { 24212 try missing_error_buf.append(name); 24213 } 24214 } 24215 24216 if (missing_error_buf.items.len != 0) { 24217 return InMemoryCoercionResult{ 24218 .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), 24219 }; 24220 } 24221 24222 return .ok; 24223 }, 24224 .error_set => { 24225 const names = src_ty.castTag(.error_set).?.data.names.keys(); 24226 for (names) |name| { 24227 if (!dest_ty.errorSetHasField(name)) { 24228 try missing_error_buf.append(name); 24229 } 24230 } 24231 24232 if (missing_error_buf.items.len != 0) { 24233 return InMemoryCoercionResult{ 24234 .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), 24235 }; 24236 } 24237 24238 return .ok; 24239 }, 24240 .anyerror => switch (dest_ty.tag()) { 24241 .error_set_inferred => unreachable, // Caught by dest_ty.isAnyError() above. 24242 .error_set_single, .error_set_merged, .error_set => return .from_anyerror, 24243 .anyerror => unreachable, // Filtered out above. 24244 else => unreachable, 24245 }, 24246 else => unreachable, 24247 } 24248 24249 unreachable; 24250 } 24251 24252 fn coerceInMemoryAllowedFns( 24253 sema: *Sema, 24254 block: *Block, 24255 dest_ty: Type, 24256 src_ty: Type, 24257 target: std.Target, 24258 dest_src: LazySrcLoc, 24259 src_src: LazySrcLoc, 24260 ) !InMemoryCoercionResult { 24261 const dest_info = dest_ty.fnInfo(); 24262 const src_info = src_ty.fnInfo(); 24263 24264 if (dest_info.is_var_args != src_info.is_var_args) { 24265 return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args }; 24266 } 24267 24268 if (dest_info.is_generic != src_info.is_generic) { 24269 return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic }; 24270 } 24271 24272 if (dest_info.cc != src_info.cc) { 24273 return InMemoryCoercionResult{ .fn_cc = .{ 24274 .actual = src_info.cc, 24275 .wanted = dest_info.cc, 24276 } }; 24277 } 24278 24279 if (!src_info.return_type.isNoReturn()) { 24280 const rt = try sema.coerceInMemoryAllowed(block, dest_info.return_type, src_info.return_type, false, target, dest_src, src_src); 24281 if (rt != .ok) { 24282 return InMemoryCoercionResult{ .fn_return_type = .{ 24283 .child = try rt.dupe(sema.arena), 24284 .actual = src_info.return_type, 24285 .wanted = dest_info.return_type, 24286 } }; 24287 } 24288 } 24289 24290 if (dest_info.param_types.len != src_info.param_types.len) { 24291 return InMemoryCoercionResult{ .fn_param_count = .{ 24292 .actual = dest_info.param_types.len, 24293 .wanted = dest_info.param_types.len, 24294 } }; 24295 } 24296 24297 if (dest_info.noalias_bits != src_info.noalias_bits) { 24298 return InMemoryCoercionResult{ .fn_param_noalias = .{ 24299 .actual = src_info.noalias_bits, 24300 .wanted = dest_info.noalias_bits, 24301 } }; 24302 } 24303 24304 for (dest_info.param_types) |dest_param_ty, i| { 24305 const src_param_ty = src_info.param_types[i]; 24306 24307 if (dest_info.comptime_params[i] != src_info.comptime_params[i]) { 24308 return InMemoryCoercionResult{ .fn_param_comptime = .{ 24309 .index = i, 24310 .wanted = dest_info.comptime_params[i], 24311 } }; 24312 } 24313 24314 // Note: Cast direction is reversed here. 24315 const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src); 24316 if (param != .ok) { 24317 return InMemoryCoercionResult{ .fn_param = .{ 24318 .child = try param.dupe(sema.arena), 24319 .actual = src_param_ty, 24320 .wanted = dest_param_ty, 24321 .index = i, 24322 } }; 24323 } 24324 } 24325 24326 return .ok; 24327 } 24328 24329 fn coerceInMemoryAllowedPtrs( 24330 sema: *Sema, 24331 block: *Block, 24332 dest_ty: Type, 24333 src_ty: Type, 24334 dest_ptr_ty: Type, 24335 src_ptr_ty: Type, 24336 dest_is_mut: bool, 24337 target: std.Target, 24338 dest_src: LazySrcLoc, 24339 src_src: LazySrcLoc, 24340 ) !InMemoryCoercionResult { 24341 const dest_info = dest_ptr_ty.ptrInfo().data; 24342 const src_info = src_ptr_ty.ptrInfo().data; 24343 24344 const ok_ptr_size = src_info.size == dest_info.size or 24345 src_info.size == .C or dest_info.size == .C; 24346 if (!ok_ptr_size) { 24347 return InMemoryCoercionResult{ .ptr_size = .{ 24348 .actual = src_info.size, 24349 .wanted = dest_info.size, 24350 } }; 24351 } 24352 24353 const ok_cv_qualifiers = 24354 (src_info.mutable or !dest_info.mutable) and 24355 (!src_info.@"volatile" or dest_info.@"volatile"); 24356 24357 if (!ok_cv_qualifiers) { 24358 return InMemoryCoercionResult{ .ptr_qualifiers = .{ 24359 .actual_const = !src_info.mutable, 24360 .wanted_const = !dest_info.mutable, 24361 .actual_volatile = src_info.@"volatile", 24362 .wanted_volatile = dest_info.@"volatile", 24363 } }; 24364 } 24365 24366 if (dest_info.@"addrspace" != src_info.@"addrspace") { 24367 return InMemoryCoercionResult{ .ptr_addrspace = .{ 24368 .actual = src_info.@"addrspace", 24369 .wanted = dest_info.@"addrspace", 24370 } }; 24371 } 24372 24373 const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src); 24374 if (child != .ok) { 24375 return InMemoryCoercionResult{ .ptr_child = .{ 24376 .child = try child.dupe(sema.arena), 24377 .actual = src_info.pointee_type, 24378 .wanted = dest_info.pointee_type, 24379 } }; 24380 } 24381 24382 const dest_allow_zero = dest_ty.ptrAllowsZero(); 24383 const src_allow_zero = src_ty.ptrAllowsZero(); 24384 24385 const ok_allows_zero = (dest_allow_zero and 24386 (src_allow_zero or !dest_is_mut)) or 24387 (!dest_allow_zero and !src_allow_zero); 24388 if (!ok_allows_zero) { 24389 return InMemoryCoercionResult{ .ptr_allowzero = .{ 24390 .actual = src_ty, 24391 .wanted = dest_ty, 24392 } }; 24393 } 24394 24395 if (src_info.host_size != dest_info.host_size or 24396 src_info.bit_offset != dest_info.bit_offset) 24397 { 24398 return InMemoryCoercionResult{ .ptr_bit_range = .{ 24399 .actual_host = src_info.host_size, 24400 .wanted_host = dest_info.host_size, 24401 .actual_offset = src_info.bit_offset, 24402 .wanted_offset = dest_info.bit_offset, 24403 } }; 24404 } 24405 24406 const ok_sent = dest_info.sentinel == null or src_info.size == .C or 24407 (src_info.sentinel != null and 24408 dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod)); 24409 if (!ok_sent) { 24410 return InMemoryCoercionResult{ .ptr_sentinel = .{ 24411 .actual = src_info.sentinel orelse Value.initTag(.unreachable_value), 24412 .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value), 24413 .ty = dest_info.pointee_type, 24414 } }; 24415 } 24416 24417 // If both pointers have alignment 0, it means they both want ABI alignment. 24418 // In this case, if they share the same child type, no need to resolve 24419 // pointee type alignment. Otherwise both pointee types must have their alignment 24420 // resolved and we compare the alignment numerically. 24421 alignment: { 24422 if (src_info.@"align" == 0 and dest_info.@"align" == 0 and 24423 dest_info.pointee_type.eql(src_info.pointee_type, sema.mod)) 24424 { 24425 break :alignment; 24426 } 24427 24428 const src_align = if (src_info.@"align" != 0) 24429 src_info.@"align" 24430 else 24431 src_info.pointee_type.abiAlignment(target); 24432 24433 const dest_align = if (dest_info.@"align" != 0) 24434 dest_info.@"align" 24435 else 24436 dest_info.pointee_type.abiAlignment(target); 24437 24438 if (dest_align > src_align) { 24439 return InMemoryCoercionResult{ .ptr_alignment = .{ 24440 .actual = src_align, 24441 .wanted = dest_align, 24442 } }; 24443 } 24444 24445 break :alignment; 24446 } 24447 24448 return .ok; 24449 } 24450 24451 fn coerceVarArgParam( 24452 sema: *Sema, 24453 block: *Block, 24454 inst: Air.Inst.Ref, 24455 inst_src: LazySrcLoc, 24456 ) !Air.Inst.Ref { 24457 if (block.is_typeof) return inst; 24458 24459 const coerced = switch (sema.typeOf(inst).zigTypeTag()) { 24460 // TODO consider casting to c_int/f64 if they fit 24461 .ComptimeInt, .ComptimeFloat => return sema.fail( 24462 block, 24463 inst_src, 24464 "integer and float literals passed variadic function must be casted to a fixed-size number type", 24465 .{}, 24466 ), 24467 .Fn => blk: { 24468 const fn_val = try sema.resolveConstValue(block, .unneeded, inst, undefined); 24469 const fn_decl = fn_val.pointerDecl().?; 24470 break :blk try sema.analyzeDeclRef(fn_decl); 24471 }, 24472 .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), 24473 else => inst, 24474 }; 24475 24476 const coerced_ty = sema.typeOf(coerced); 24477 if (!try sema.validateExternType(block, inst_src, coerced_ty, .other)) { 24478 const msg = msg: { 24479 const msg = try sema.errMsg(block, inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(sema.mod)}); 24480 errdefer msg.destroy(sema.gpa); 24481 24482 const src_decl = sema.mod.declPtr(block.src_decl); 24483 try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl), coerced_ty, .other); 24484 24485 try sema.addDeclaredHereNote(msg, coerced_ty); 24486 break :msg msg; 24487 }; 24488 return sema.failWithOwnedErrorMsg(msg); 24489 } 24490 return coerced; 24491 } 24492 24493 // TODO migrate callsites to use storePtr2 instead. 24494 fn storePtr( 24495 sema: *Sema, 24496 block: *Block, 24497 src: LazySrcLoc, 24498 ptr: Air.Inst.Ref, 24499 uncasted_operand: Air.Inst.Ref, 24500 ) CompileError!void { 24501 return sema.storePtr2(block, src, ptr, src, uncasted_operand, src, .store); 24502 } 24503 24504 fn storePtr2( 24505 sema: *Sema, 24506 block: *Block, 24507 src: LazySrcLoc, 24508 ptr: Air.Inst.Ref, 24509 ptr_src: LazySrcLoc, 24510 uncasted_operand: Air.Inst.Ref, 24511 operand_src: LazySrcLoc, 24512 air_tag: Air.Inst.Tag, 24513 ) CompileError!void { 24514 const ptr_ty = sema.typeOf(ptr); 24515 if (ptr_ty.isConstPtr()) 24516 return sema.fail(block, ptr_src, "cannot assign to constant", .{}); 24517 24518 const elem_ty = ptr_ty.childType(); 24519 24520 // To generate better code for tuples, we detect a tuple operand here, and 24521 // analyze field loads and stores directly. This avoids an extra allocation + memcpy 24522 // which would occur if we used `coerce`. 24523 // However, we avoid this mechanism if the destination element type is a tuple, 24524 // because the regular store will be better for this case. 24525 // If the destination type is a struct we don't want this mechanism to trigger, because 24526 // this code does not handle tuple-to-struct coercion which requires dealing with missing 24527 // fields. 24528 const operand_ty = sema.typeOf(uncasted_operand); 24529 if (operand_ty.isTuple() and elem_ty.zigTypeTag() == .Array) { 24530 const tuple = operand_ty.tupleFields(); 24531 for (tuple.types) |_, i_usize| { 24532 const i = @intCast(u32, i_usize); 24533 const elem_src = operand_src; // TODO better source location 24534 const elem = try tupleField(sema, block, operand_src, uncasted_operand, elem_src, i); 24535 const elem_index = try sema.addIntUnsigned(Type.usize, i); 24536 const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src, false); 24537 try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store); 24538 } 24539 return; 24540 } 24541 24542 // TODO do the same thing for anon structs as for tuples above. 24543 // However, beware of the need to handle missing/extra fields. 24544 24545 const is_ret = air_tag == .ret_ptr; 24546 24547 // Detect if we are storing an array operand to a bitcasted vector pointer. 24548 // If so, we instead reach through the bitcasted pointer to the vector pointer, 24549 // bitcast the array operand to a vector, and then lower this as a store of 24550 // a vector value to a vector pointer. This generally results in better code, 24551 // as well as working around an LLVM bug: 24552 // https://github.com/ziglang/zig/issues/11154 24553 if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| { 24554 const vector_ty = sema.typeOf(vector_ptr).childType(); 24555 const vector = sema.coerceExtra(block, vector_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) { 24556 error.NotCoercible => unreachable, 24557 else => |e| return e, 24558 }; 24559 try sema.storePtr2(block, src, vector_ptr, ptr_src, vector, operand_src, .store); 24560 return; 24561 } 24562 24563 const operand = sema.coerceExtra(block, elem_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) { 24564 error.NotCoercible => unreachable, 24565 else => |e| return e, 24566 }; 24567 const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand); 24568 24569 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { 24570 const operand_val = maybe_operand_val orelse { 24571 try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); 24572 break :rs operand_src; 24573 }; 24574 if (ptr_val.isComptimeMutablePtr()) { 24575 try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty); 24576 return; 24577 } else break :rs ptr_src; 24578 } else ptr_src; 24579 24580 // We do this after the possible comptime store above, for the case of field_ptr stores 24581 // to unions because we want the comptime tag to be set, even if the field type is void. 24582 if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null) 24583 return; 24584 24585 if (air_tag == .bitcast) { 24586 // `air_tag == .bitcast` is used as a special case for `zirCoerceResultPtr` 24587 // to avoid calling `requireRuntimeBlock` for the dummy block. 24588 _ = try block.addBinOp(.store, ptr, operand); 24589 return; 24590 } 24591 24592 if (block.is_comptime) { 24593 // TODO ideally this would tell why the block is comptime 24594 return sema.fail(block, ptr_src, "cannot store to runtime value in comptime block", .{}); 24595 } 24596 24597 try sema.requireRuntimeBlock(block, src, runtime_src); 24598 try sema.queueFullTypeResolution(elem_ty); 24599 if (is_ret) { 24600 _ = try block.addBinOp(.store, ptr, operand); 24601 } else { 24602 _ = try block.addBinOp(air_tag, ptr, operand); 24603 } 24604 } 24605 24606 /// Traverse an arbitrary number of bitcasted pointers and return the underyling vector 24607 /// pointer. Only if the final element type matches the vector element type, and the 24608 /// lengths match. 24609 fn obtainBitCastedVectorPtr(sema: *Sema, ptr: Air.Inst.Ref) ?Air.Inst.Ref { 24610 const array_ty = sema.typeOf(ptr).childType(); 24611 if (array_ty.zigTypeTag() != .Array) return null; 24612 var ptr_inst = Air.refToIndex(ptr) orelse return null; 24613 const air_datas = sema.air_instructions.items(.data); 24614 const air_tags = sema.air_instructions.items(.tag); 24615 const prev_ptr = while (air_tags[ptr_inst] == .bitcast) { 24616 const prev_ptr = air_datas[ptr_inst].ty_op.operand; 24617 const prev_ptr_ty = sema.typeOf(prev_ptr); 24618 const prev_ptr_child_ty = switch (prev_ptr_ty.tag()) { 24619 .single_mut_pointer => prev_ptr_ty.castTag(.single_mut_pointer).?.data, 24620 .pointer => prev_ptr_ty.castTag(.pointer).?.data.pointee_type, 24621 else => return null, 24622 }; 24623 if (prev_ptr_child_ty.zigTypeTag() == .Vector) break prev_ptr; 24624 ptr_inst = Air.refToIndex(prev_ptr) orelse return null; 24625 } else return null; 24626 24627 // We have a pointer-to-array and a pointer-to-vector. If the elements and 24628 // lengths match, return the result. 24629 const vector_ty = sema.typeOf(prev_ptr).childType(); 24630 if (array_ty.childType().eql(vector_ty.childType(), sema.mod) and 24631 array_ty.arrayLen() == vector_ty.vectorLen()) 24632 { 24633 return prev_ptr; 24634 } else { 24635 return null; 24636 } 24637 } 24638 24639 /// Call when you have Value objects rather than Air instructions, and you want to 24640 /// assert the store must be done at comptime. 24641 fn storePtrVal( 24642 sema: *Sema, 24643 block: *Block, 24644 src: LazySrcLoc, 24645 ptr_val: Value, 24646 operand_val: Value, 24647 operand_ty: Type, 24648 ) !void { 24649 var mut_kit = try beginComptimePtrMutation(sema, block, src, ptr_val, operand_ty); 24650 try sema.checkComptimeVarStore(block, src, mut_kit.decl_ref_mut); 24651 24652 switch (mut_kit.pointee) { 24653 .direct => |val_ptr| { 24654 if (mut_kit.decl_ref_mut.runtime_index == .comptime_field_ptr) { 24655 if (!operand_val.eql(val_ptr.*, operand_ty, sema.mod)) { 24656 // TODO use failWithInvalidComptimeFieldStore 24657 return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{}); 24658 } 24659 return; 24660 } 24661 const arena = mut_kit.beginArena(sema.mod); 24662 defer mut_kit.finishArena(sema.mod); 24663 24664 val_ptr.* = try operand_val.copy(arena); 24665 }, 24666 .reinterpret => |reinterpret| { 24667 const target = sema.mod.getTarget(); 24668 const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(target)); 24669 const buffer = try sema.gpa.alloc(u8, abi_size); 24670 defer sema.gpa.free(buffer); 24671 reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, sema.mod, buffer); 24672 operand_val.writeToMemory(operand_ty, sema.mod, buffer[reinterpret.byte_offset..]); 24673 24674 const arena = mut_kit.beginArena(sema.mod); 24675 defer mut_kit.finishArena(sema.mod); 24676 24677 reinterpret.val_ptr.* = try Value.readFromMemory(mut_kit.ty, sema.mod, buffer, arena); 24678 }, 24679 .bad_decl_ty, .bad_ptr_ty => { 24680 // TODO show the decl declaration site in a note and explain whether the decl 24681 // or the pointer is the problematic type 24682 return sema.fail(block, src, "comptime mutation of a reinterpreted pointer requires type '{}' to have a well-defined memory layout", .{mut_kit.ty.fmt(sema.mod)}); 24683 }, 24684 } 24685 } 24686 24687 const ComptimePtrMutationKit = struct { 24688 decl_ref_mut: Value.Payload.DeclRefMut.Data, 24689 pointee: union(enum) { 24690 /// The pointer type matches the actual comptime Value so a direct 24691 /// modification is possible. 24692 direct: *Value, 24693 /// The largest parent Value containing pointee and having a well-defined memory layout. 24694 /// This is used for bitcasting, if direct dereferencing failed. 24695 reinterpret: struct { 24696 val_ptr: *Value, 24697 byte_offset: usize, 24698 }, 24699 /// If the root decl could not be used as parent, this means `ty` is the type that 24700 /// caused that by not having a well-defined layout. 24701 /// This one means the Decl that owns the value trying to be modified does not 24702 /// have a well defined memory layout. 24703 bad_decl_ty, 24704 /// If the root decl could not be used as parent, this means `ty` is the type that 24705 /// caused that by not having a well-defined layout. 24706 /// This one means the pointer type that is being stored through does not 24707 /// have a well defined memory layout. 24708 bad_ptr_ty, 24709 }, 24710 ty: Type, 24711 decl_arena: std.heap.ArenaAllocator = undefined, 24712 24713 fn beginArena(self: *ComptimePtrMutationKit, mod: *Module) Allocator { 24714 const decl = mod.declPtr(self.decl_ref_mut.decl_index); 24715 self.decl_arena = decl.value_arena.?.promote(mod.gpa); 24716 return self.decl_arena.allocator(); 24717 } 24718 24719 fn finishArena(self: *ComptimePtrMutationKit, mod: *Module) void { 24720 const decl = mod.declPtr(self.decl_ref_mut.decl_index); 24721 decl.value_arena.?.* = self.decl_arena.state; 24722 self.decl_arena = undefined; 24723 } 24724 }; 24725 24726 fn beginComptimePtrMutation( 24727 sema: *Sema, 24728 block: *Block, 24729 src: LazySrcLoc, 24730 ptr_val: Value, 24731 ptr_elem_ty: Type, 24732 ) CompileError!ComptimePtrMutationKit { 24733 const target = sema.mod.getTarget(); 24734 switch (ptr_val.tag()) { 24735 .decl_ref_mut => { 24736 const decl_ref_mut = ptr_val.castTag(.decl_ref_mut).?.data; 24737 const decl = sema.mod.declPtr(decl_ref_mut.decl_index); 24738 return beginComptimePtrMutationInner(sema, block, src, decl.ty, &decl.val, ptr_elem_ty, decl_ref_mut); 24739 }, 24740 .comptime_field_ptr => { 24741 const payload = ptr_val.castTag(.comptime_field_ptr).?.data; 24742 const duped = try sema.arena.create(Value); 24743 duped.* = payload.field_val; 24744 return beginComptimePtrMutationInner(sema, block, src, payload.field_ty, duped, ptr_elem_ty, .{ 24745 .decl_index = @intToEnum(Module.Decl.Index, 0), 24746 .runtime_index = .comptime_field_ptr, 24747 }); 24748 }, 24749 .elem_ptr => { 24750 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; 24751 var parent = try beginComptimePtrMutation(sema, block, src, elem_ptr.array_ptr, elem_ptr.elem_ty); 24752 switch (parent.pointee) { 24753 .direct => |val_ptr| switch (parent.ty.zigTypeTag()) { 24754 .Array, .Vector => { 24755 const check_len = parent.ty.arrayLenIncludingSentinel(); 24756 if (elem_ptr.index >= check_len) { 24757 // TODO have the parent include the decl so we can say "declared here" 24758 return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{ 24759 elem_ptr.index, check_len, 24760 }); 24761 } 24762 const elem_ty = parent.ty.childType(); 24763 switch (val_ptr.tag()) { 24764 .undef => { 24765 // An array has been initialized to undefined at comptime and now we 24766 // are for the first time setting an element. We must change the representation 24767 // of the array from `undef` to `array`. 24768 const arena = parent.beginArena(sema.mod); 24769 defer parent.finishArena(sema.mod); 24770 24771 const array_len_including_sentinel = 24772 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel()); 24773 const elems = try arena.alloc(Value, array_len_including_sentinel); 24774 mem.set(Value, elems, Value.undef); 24775 24776 val_ptr.* = try Value.Tag.aggregate.create(arena, elems); 24777 24778 return beginComptimePtrMutationInner( 24779 sema, 24780 block, 24781 src, 24782 elem_ty, 24783 &elems[elem_ptr.index], 24784 ptr_elem_ty, 24785 parent.decl_ref_mut, 24786 ); 24787 }, 24788 .bytes => { 24789 // An array is memory-optimized to store a slice of bytes, but we are about 24790 // to modify an individual field and the representation has to change. 24791 // If we wanted to avoid this, there would need to be special detection 24792 // elsewhere to identify when writing a value to an array element that is stored 24793 // using the `bytes` tag, and handle it without making a call to this function. 24794 const arena = parent.beginArena(sema.mod); 24795 defer parent.finishArena(sema.mod); 24796 24797 const bytes = val_ptr.castTag(.bytes).?.data; 24798 const dest_len = parent.ty.arrayLenIncludingSentinel(); 24799 // bytes.len may be one greater than dest_len because of the case when 24800 // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. 24801 assert(bytes.len >= dest_len); 24802 const elems = try arena.alloc(Value, @intCast(usize, dest_len)); 24803 for (elems) |*elem, i| { 24804 elem.* = try Value.Tag.int_u64.create(arena, bytes[i]); 24805 } 24806 24807 val_ptr.* = try Value.Tag.aggregate.create(arena, elems); 24808 24809 return beginComptimePtrMutationInner( 24810 sema, 24811 block, 24812 src, 24813 elem_ty, 24814 &elems[elem_ptr.index], 24815 ptr_elem_ty, 24816 parent.decl_ref_mut, 24817 ); 24818 }, 24819 .str_lit => { 24820 // An array is memory-optimized to store a slice of bytes, but we are about 24821 // to modify an individual field and the representation has to change. 24822 // If we wanted to avoid this, there would need to be special detection 24823 // elsewhere to identify when writing a value to an array element that is stored 24824 // using the `str_lit` tag, and handle it without making a call to this function. 24825 const arena = parent.beginArena(sema.mod); 24826 defer parent.finishArena(sema.mod); 24827 24828 const str_lit = val_ptr.castTag(.str_lit).?.data; 24829 const dest_len = parent.ty.arrayLenIncludingSentinel(); 24830 const bytes = sema.mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; 24831 const elems = try arena.alloc(Value, @intCast(usize, dest_len)); 24832 for (bytes) |byte, i| { 24833 elems[i] = try Value.Tag.int_u64.create(arena, byte); 24834 } 24835 if (parent.ty.sentinel()) |sent_val| { 24836 assert(elems.len == bytes.len + 1); 24837 elems[bytes.len] = sent_val; 24838 } 24839 24840 val_ptr.* = try Value.Tag.aggregate.create(arena, elems); 24841 24842 return beginComptimePtrMutationInner( 24843 sema, 24844 block, 24845 src, 24846 elem_ty, 24847 &elems[elem_ptr.index], 24848 ptr_elem_ty, 24849 parent.decl_ref_mut, 24850 ); 24851 }, 24852 .repeated => { 24853 // An array is memory-optimized to store only a single element value, and 24854 // that value is understood to be the same for the entire length of the array. 24855 // However, now we want to modify an individual field and so the 24856 // representation has to change. If we wanted to avoid this, there would 24857 // need to be special detection elsewhere to identify when writing a value to an 24858 // array element that is stored using the `repeated` tag, and handle it 24859 // without making a call to this function. 24860 const arena = parent.beginArena(sema.mod); 24861 defer parent.finishArena(sema.mod); 24862 24863 const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena); 24864 const array_len_including_sentinel = 24865 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel()); 24866 const elems = try arena.alloc(Value, array_len_including_sentinel); 24867 if (elems.len > 0) elems[0] = repeated_val; 24868 for (elems[1..]) |*elem| { 24869 elem.* = try repeated_val.copy(arena); 24870 } 24871 24872 val_ptr.* = try Value.Tag.aggregate.create(arena, elems); 24873 24874 return beginComptimePtrMutationInner( 24875 sema, 24876 block, 24877 src, 24878 elem_ty, 24879 &elems[elem_ptr.index], 24880 ptr_elem_ty, 24881 parent.decl_ref_mut, 24882 ); 24883 }, 24884 24885 .aggregate => return beginComptimePtrMutationInner( 24886 sema, 24887 block, 24888 src, 24889 elem_ty, 24890 &val_ptr.castTag(.aggregate).?.data[elem_ptr.index], 24891 ptr_elem_ty, 24892 parent.decl_ref_mut, 24893 ), 24894 24895 .the_only_possible_value => { 24896 const duped = try sema.arena.create(Value); 24897 duped.* = Value.initTag(.the_only_possible_value); 24898 return beginComptimePtrMutationInner( 24899 sema, 24900 block, 24901 src, 24902 elem_ty, 24903 duped, 24904 ptr_elem_ty, 24905 parent.decl_ref_mut, 24906 ); 24907 }, 24908 24909 else => unreachable, 24910 } 24911 }, 24912 else => { 24913 if (elem_ptr.index != 0) { 24914 // TODO include a "declared here" note for the decl 24915 return sema.fail(block, src, "out of bounds comptime store of index {d}", .{ 24916 elem_ptr.index, 24917 }); 24918 } 24919 return beginComptimePtrMutationInner( 24920 sema, 24921 block, 24922 src, 24923 parent.ty, 24924 val_ptr, 24925 ptr_elem_ty, 24926 parent.decl_ref_mut, 24927 ); 24928 }, 24929 }, 24930 .reinterpret => |reinterpret| { 24931 if (!elem_ptr.elem_ty.hasWellDefinedLayout()) { 24932 // Even though the parent value type has well-defined memory layout, our 24933 // pointer type does not. 24934 return ComptimePtrMutationKit{ 24935 .decl_ref_mut = parent.decl_ref_mut, 24936 .pointee = .bad_ptr_ty, 24937 .ty = elem_ptr.elem_ty, 24938 }; 24939 } 24940 24941 const elem_abi_size_u64 = try sema.typeAbiSize(block, src, elem_ptr.elem_ty); 24942 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); 24943 return ComptimePtrMutationKit{ 24944 .decl_ref_mut = parent.decl_ref_mut, 24945 .pointee = .{ .reinterpret = .{ 24946 .val_ptr = reinterpret.val_ptr, 24947 .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_ptr.index, 24948 } }, 24949 .ty = parent.ty, 24950 }; 24951 }, 24952 .bad_decl_ty, .bad_ptr_ty => return parent, 24953 } 24954 }, 24955 .field_ptr => { 24956 const field_ptr = ptr_val.castTag(.field_ptr).?.data; 24957 const field_index = @intCast(u32, field_ptr.field_index); 24958 24959 var parent = try beginComptimePtrMutation(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty); 24960 switch (parent.pointee) { 24961 .direct => |val_ptr| switch (val_ptr.tag()) { 24962 .undef => { 24963 // A struct or union has been initialized to undefined at comptime and now we 24964 // are for the first time setting a field. We must change the representation 24965 // of the struct/union from `undef` to `struct`/`union`. 24966 const arena = parent.beginArena(sema.mod); 24967 defer parent.finishArena(sema.mod); 24968 24969 switch (parent.ty.zigTypeTag()) { 24970 .Struct => { 24971 const fields = try arena.alloc(Value, parent.ty.structFieldCount()); 24972 mem.set(Value, fields, Value.undef); 24973 24974 val_ptr.* = try Value.Tag.aggregate.create(arena, fields); 24975 24976 return beginComptimePtrMutationInner( 24977 sema, 24978 block, 24979 src, 24980 parent.ty.structFieldType(field_index), 24981 &fields[field_index], 24982 ptr_elem_ty, 24983 parent.decl_ref_mut, 24984 ); 24985 }, 24986 .Union => { 24987 const payload = try arena.create(Value.Payload.Union); 24988 payload.* = .{ .data = .{ 24989 .tag = try Value.Tag.enum_field_index.create(arena, field_index), 24990 .val = Value.undef, 24991 } }; 24992 24993 val_ptr.* = Value.initPayload(&payload.base); 24994 24995 return beginComptimePtrMutationInner( 24996 sema, 24997 block, 24998 src, 24999 parent.ty.structFieldType(field_index), 25000 &payload.data.val, 25001 ptr_elem_ty, 25002 parent.decl_ref_mut, 25003 ); 25004 }, 25005 .Pointer => { 25006 assert(parent.ty.isSlice()); 25007 val_ptr.* = try Value.Tag.slice.create(arena, .{ 25008 .ptr = Value.undef, 25009 .len = Value.undef, 25010 }); 25011 25012 switch (field_index) { 25013 Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner( 25014 sema, 25015 block, 25016 src, 25017 parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), 25018 &val_ptr.castTag(.slice).?.data.ptr, 25019 ptr_elem_ty, 25020 parent.decl_ref_mut, 25021 ), 25022 Value.Payload.Slice.len_index => return beginComptimePtrMutationInner( 25023 sema, 25024 block, 25025 src, 25026 Type.usize, 25027 &val_ptr.castTag(.slice).?.data.len, 25028 ptr_elem_ty, 25029 parent.decl_ref_mut, 25030 ), 25031 25032 else => unreachable, 25033 } 25034 }, 25035 else => unreachable, 25036 } 25037 }, 25038 .aggregate => return beginComptimePtrMutationInner( 25039 sema, 25040 block, 25041 src, 25042 parent.ty.structFieldType(field_index), 25043 &val_ptr.castTag(.aggregate).?.data[field_index], 25044 ptr_elem_ty, 25045 parent.decl_ref_mut, 25046 ), 25047 25048 .@"union" => { 25049 // We need to set the active field of the union. 25050 const arena = parent.beginArena(sema.mod); 25051 defer parent.finishArena(sema.mod); 25052 25053 const payload = &val_ptr.castTag(.@"union").?.data; 25054 payload.tag = try Value.Tag.enum_field_index.create(arena, field_index); 25055 25056 return beginComptimePtrMutationInner( 25057 sema, 25058 block, 25059 src, 25060 parent.ty.structFieldType(field_index), 25061 &payload.val, 25062 ptr_elem_ty, 25063 parent.decl_ref_mut, 25064 ); 25065 }, 25066 .slice => switch (field_index) { 25067 Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner( 25068 sema, 25069 block, 25070 src, 25071 parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), 25072 &val_ptr.castTag(.slice).?.data.ptr, 25073 ptr_elem_ty, 25074 parent.decl_ref_mut, 25075 ), 25076 25077 Value.Payload.Slice.len_index => return beginComptimePtrMutationInner( 25078 sema, 25079 block, 25080 src, 25081 Type.usize, 25082 &val_ptr.castTag(.slice).?.data.len, 25083 ptr_elem_ty, 25084 parent.decl_ref_mut, 25085 ), 25086 25087 else => unreachable, 25088 }, 25089 25090 .empty_struct_value => { 25091 const duped = try sema.arena.create(Value); 25092 duped.* = Value.initTag(.the_only_possible_value); 25093 return beginComptimePtrMutationInner( 25094 sema, 25095 block, 25096 src, 25097 parent.ty.structFieldType(field_index), 25098 duped, 25099 ptr_elem_ty, 25100 parent.decl_ref_mut, 25101 ); 25102 }, 25103 25104 else => unreachable, 25105 }, 25106 .reinterpret => |reinterpret| { 25107 const field_offset_u64 = field_ptr.container_ty.structFieldOffset(field_index, target); 25108 const field_offset = try sema.usizeCast(block, src, field_offset_u64); 25109 return ComptimePtrMutationKit{ 25110 .decl_ref_mut = parent.decl_ref_mut, 25111 .pointee = .{ .reinterpret = .{ 25112 .val_ptr = reinterpret.val_ptr, 25113 .byte_offset = reinterpret.byte_offset + field_offset, 25114 } }, 25115 .ty = parent.ty, 25116 }; 25117 }, 25118 .bad_decl_ty, .bad_ptr_ty => return parent, 25119 } 25120 }, 25121 .eu_payload_ptr => { 25122 const eu_ptr = ptr_val.castTag(.eu_payload_ptr).?.data; 25123 var parent = try beginComptimePtrMutation(sema, block, src, eu_ptr.container_ptr, eu_ptr.container_ty); 25124 switch (parent.pointee) { 25125 .direct => |val_ptr| { 25126 const payload_ty = parent.ty.errorUnionPayload(); 25127 switch (val_ptr.tag()) { 25128 else => { 25129 // An error union has been initialized to undefined at comptime and now we 25130 // are for the first time setting the payload. We must change the 25131 // representation of the error union from `undef` to `opt_payload`. 25132 const arena = parent.beginArena(sema.mod); 25133 defer parent.finishArena(sema.mod); 25134 25135 const payload = try arena.create(Value.Payload.SubValue); 25136 payload.* = .{ 25137 .base = .{ .tag = .eu_payload }, 25138 .data = Value.undef, 25139 }; 25140 25141 val_ptr.* = Value.initPayload(&payload.base); 25142 25143 return ComptimePtrMutationKit{ 25144 .decl_ref_mut = parent.decl_ref_mut, 25145 .pointee = .{ .direct = &payload.data }, 25146 .ty = payload_ty, 25147 }; 25148 }, 25149 .eu_payload => return ComptimePtrMutationKit{ 25150 .decl_ref_mut = parent.decl_ref_mut, 25151 .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data }, 25152 .ty = payload_ty, 25153 }, 25154 } 25155 }, 25156 .bad_decl_ty, .bad_ptr_ty => return parent, 25157 // Even though the parent value type has well-defined memory layout, our 25158 // pointer type does not. 25159 .reinterpret => return ComptimePtrMutationKit{ 25160 .decl_ref_mut = parent.decl_ref_mut, 25161 .pointee = .bad_ptr_ty, 25162 .ty = eu_ptr.container_ty, 25163 }, 25164 } 25165 }, 25166 .opt_payload_ptr => { 25167 const opt_ptr = if (ptr_val.castTag(.opt_payload_ptr)) |some| some.data else { 25168 return sema.beginComptimePtrMutation(block, src, ptr_val, try ptr_elem_ty.optionalChildAlloc(sema.arena)); 25169 }; 25170 var parent = try beginComptimePtrMutation(sema, block, src, opt_ptr.container_ptr, opt_ptr.container_ty); 25171 switch (parent.pointee) { 25172 .direct => |val_ptr| { 25173 const payload_ty = try parent.ty.optionalChildAlloc(sema.arena); 25174 switch (val_ptr.tag()) { 25175 .undef, .null_value => { 25176 // An optional has been initialized to undefined at comptime and now we 25177 // are for the first time setting the payload. We must change the 25178 // representation of the optional from `undef` to `opt_payload`. 25179 const arena = parent.beginArena(sema.mod); 25180 defer parent.finishArena(sema.mod); 25181 25182 const payload = try arena.create(Value.Payload.SubValue); 25183 payload.* = .{ 25184 .base = .{ .tag = .opt_payload }, 25185 .data = Value.undef, 25186 }; 25187 25188 val_ptr.* = Value.initPayload(&payload.base); 25189 25190 return ComptimePtrMutationKit{ 25191 .decl_ref_mut = parent.decl_ref_mut, 25192 .pointee = .{ .direct = &payload.data }, 25193 .ty = payload_ty, 25194 }; 25195 }, 25196 .opt_payload => return ComptimePtrMutationKit{ 25197 .decl_ref_mut = parent.decl_ref_mut, 25198 .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data }, 25199 .ty = payload_ty, 25200 }, 25201 25202 else => return ComptimePtrMutationKit{ 25203 .decl_ref_mut = parent.decl_ref_mut, 25204 .pointee = .{ .direct = val_ptr }, 25205 .ty = payload_ty, 25206 }, 25207 } 25208 }, 25209 .bad_decl_ty, .bad_ptr_ty => return parent, 25210 // Even though the parent value type has well-defined memory layout, our 25211 // pointer type does not. 25212 .reinterpret => return ComptimePtrMutationKit{ 25213 .decl_ref_mut = parent.decl_ref_mut, 25214 .pointee = .bad_ptr_ty, 25215 .ty = opt_ptr.container_ty, 25216 }, 25217 } 25218 }, 25219 .decl_ref => unreachable, // isComptimeMutablePtr() has been checked already 25220 else => unreachable, 25221 } 25222 } 25223 25224 fn beginComptimePtrMutationInner( 25225 sema: *Sema, 25226 block: *Block, 25227 src: LazySrcLoc, 25228 decl_ty: Type, 25229 decl_val: *Value, 25230 ptr_elem_ty: Type, 25231 decl_ref_mut: Value.Payload.DeclRefMut.Data, 25232 ) CompileError!ComptimePtrMutationKit { 25233 const target = sema.mod.getTarget(); 25234 const coerce_ok = (try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_ty, true, target, src, src)) == .ok; 25235 if (coerce_ok) { 25236 return ComptimePtrMutationKit{ 25237 .decl_ref_mut = decl_ref_mut, 25238 .pointee = .{ .direct = decl_val }, 25239 .ty = decl_ty, 25240 }; 25241 } 25242 25243 // Handle the case that the decl is an array and we're actually trying to point to an element. 25244 if (decl_ty.isArrayOrVector()) { 25245 const decl_elem_ty = decl_ty.childType(); 25246 if ((try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_elem_ty, true, target, src, src)) == .ok) { 25247 return ComptimePtrMutationKit{ 25248 .decl_ref_mut = decl_ref_mut, 25249 .pointee = .{ .direct = decl_val }, 25250 .ty = decl_ty, 25251 }; 25252 } 25253 } 25254 25255 if (!decl_ty.hasWellDefinedLayout()) { 25256 return ComptimePtrMutationKit{ 25257 .decl_ref_mut = decl_ref_mut, 25258 .pointee = .{ .bad_decl_ty = {} }, 25259 .ty = decl_ty, 25260 }; 25261 } 25262 if (!ptr_elem_ty.hasWellDefinedLayout()) { 25263 return ComptimePtrMutationKit{ 25264 .decl_ref_mut = decl_ref_mut, 25265 .pointee = .{ .bad_ptr_ty = {} }, 25266 .ty = ptr_elem_ty, 25267 }; 25268 } 25269 return ComptimePtrMutationKit{ 25270 .decl_ref_mut = decl_ref_mut, 25271 .pointee = .{ .reinterpret = .{ 25272 .val_ptr = decl_val, 25273 .byte_offset = 0, 25274 } }, 25275 .ty = decl_ty, 25276 }; 25277 } 25278 25279 const TypedValueAndOffset = struct { 25280 tv: TypedValue, 25281 byte_offset: usize, 25282 }; 25283 25284 const ComptimePtrLoadKit = struct { 25285 /// The Value and Type corresponding to the pointee of the provided pointer. 25286 /// If a direct dereference is not possible, this is null. 25287 pointee: ?TypedValue, 25288 /// The largest parent Value containing `pointee` and having a well-defined memory layout. 25289 /// This is used for bitcasting, if direct dereferencing failed (i.e. `pointee` is null). 25290 parent: ?TypedValueAndOffset, 25291 /// Whether the `pointee` could be mutated by further 25292 /// semantic analysis and a copy must be performed. 25293 is_mutable: bool, 25294 /// If the root decl could not be used as `parent`, this is the type that 25295 /// caused that by not having a well-defined layout 25296 ty_without_well_defined_layout: ?Type, 25297 }; 25298 25299 const ComptimePtrLoadError = CompileError || error{ 25300 RuntimeLoad, 25301 }; 25302 25303 /// If `maybe_array_ty` is provided, it will be used to directly dereference an 25304 /// .elem_ptr of type T to a value of [N]T, if necessary. 25305 fn beginComptimePtrLoad( 25306 sema: *Sema, 25307 block: *Block, 25308 src: LazySrcLoc, 25309 ptr_val: Value, 25310 maybe_array_ty: ?Type, 25311 ) ComptimePtrLoadError!ComptimePtrLoadKit { 25312 const target = sema.mod.getTarget(); 25313 var deref: ComptimePtrLoadKit = switch (ptr_val.tag()) { 25314 .decl_ref, 25315 .decl_ref_mut, 25316 => blk: { 25317 const decl_index = switch (ptr_val.tag()) { 25318 .decl_ref => ptr_val.castTag(.decl_ref).?.data, 25319 .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl_index, 25320 else => unreachable, 25321 }; 25322 const is_mutable = ptr_val.tag() == .decl_ref_mut; 25323 const decl = sema.mod.declPtr(decl_index); 25324 const decl_tv = try decl.typedValue(); 25325 if (decl_tv.val.tag() == .variable) return error.RuntimeLoad; 25326 25327 const layout_defined = decl.ty.hasWellDefinedLayout(); 25328 break :blk ComptimePtrLoadKit{ 25329 .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, 25330 .pointee = decl_tv, 25331 .is_mutable = is_mutable, 25332 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, 25333 }; 25334 }, 25335 25336 .elem_ptr => blk: { 25337 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; 25338 const elem_ty = elem_ptr.elem_ty; 25339 var deref = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr, null); 25340 25341 // This code assumes that elem_ptrs have been "flattened" in order for direct dereference 25342 // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that 25343 // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened" 25344 if (elem_ptr.array_ptr.castTag(.elem_ptr)) |parent_elem_ptr| { 25345 assert(!(parent_elem_ptr.data.elem_ty.eql(elem_ty, sema.mod))); 25346 } 25347 25348 if (elem_ptr.index != 0) { 25349 if (elem_ty.hasWellDefinedLayout()) { 25350 if (deref.parent) |*parent| { 25351 // Update the byte offset (in-place) 25352 const elem_size = try sema.typeAbiSize(block, src, elem_ty); 25353 const offset = parent.byte_offset + elem_size * elem_ptr.index; 25354 parent.byte_offset = try sema.usizeCast(block, src, offset); 25355 } 25356 } else { 25357 deref.parent = null; 25358 deref.ty_without_well_defined_layout = elem_ty; 25359 } 25360 } 25361 25362 // If we're loading an elem_ptr that was derived from a different type 25363 // than the true type of the underlying decl, we cannot deref directly 25364 const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector()) x: { 25365 const deref_elem_ty = deref.pointee.?.ty.childType(); 25366 break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or 25367 (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok; 25368 } else false; 25369 if (!ty_matches) { 25370 deref.pointee = null; 25371 break :blk deref; 25372 } 25373 25374 var array_tv = deref.pointee.?; 25375 const check_len = array_tv.ty.arrayLenIncludingSentinel(); 25376 if (maybe_array_ty) |load_ty| { 25377 // It's possible that we're loading a [N]T, in which case we'd like to slice 25378 // the pointee array directly from our parent array. 25379 if (load_ty.isArrayOrVector() and load_ty.childType().eql(elem_ty, sema.mod)) { 25380 const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel()); 25381 deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{ 25382 .ty = try Type.array(sema.arena, N, null, elem_ty, sema.mod), 25383 .val = try array_tv.val.sliceArray(sema.mod, sema.arena, elem_ptr.index, elem_ptr.index + N), 25384 } else null; 25385 break :blk deref; 25386 } 25387 } 25388 25389 if (elem_ptr.index >= check_len) { 25390 deref.pointee = null; 25391 break :blk deref; 25392 } 25393 if (elem_ptr.index == check_len - 1) { 25394 if (array_tv.ty.sentinel()) |sent| { 25395 deref.pointee = TypedValue{ 25396 .ty = elem_ty, 25397 .val = sent, 25398 }; 25399 break :blk deref; 25400 } 25401 } 25402 deref.pointee = TypedValue{ 25403 .ty = elem_ty, 25404 .val = try array_tv.val.elemValue(sema.mod, sema.arena, elem_ptr.index), 25405 }; 25406 break :blk deref; 25407 }, 25408 25409 .slice => blk: { 25410 const slice = ptr_val.castTag(.slice).?.data; 25411 break :blk try beginComptimePtrLoad(sema, block, src, slice.ptr, null); 25412 }, 25413 25414 .field_ptr => blk: { 25415 const field_ptr = ptr_val.castTag(.field_ptr).?.data; 25416 const field_index = @intCast(u32, field_ptr.field_index); 25417 var deref = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty); 25418 25419 if (field_ptr.container_ty.hasWellDefinedLayout()) { 25420 const struct_ty = field_ptr.container_ty.castTag(.@"struct"); 25421 if (struct_ty != null and struct_ty.?.data.layout == .Packed) { 25422 // packed structs are not byte addressable 25423 deref.parent = null; 25424 } else if (deref.parent) |*parent| { 25425 // Update the byte offset (in-place) 25426 try sema.resolveTypeLayout(block, src, field_ptr.container_ty); 25427 const field_offset = field_ptr.container_ty.structFieldOffset(field_index, target); 25428 parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset); 25429 } 25430 } else { 25431 deref.parent = null; 25432 deref.ty_without_well_defined_layout = field_ptr.container_ty; 25433 } 25434 25435 const tv = deref.pointee orelse { 25436 deref.pointee = null; 25437 break :blk deref; 25438 }; 25439 const coerce_in_mem_ok = 25440 (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or 25441 (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok; 25442 if (!coerce_in_mem_ok) { 25443 deref.pointee = null; 25444 break :blk deref; 25445 } 25446 25447 if (field_ptr.container_ty.isSlice()) { 25448 const slice_val = tv.val.castTag(.slice).?.data; 25449 deref.pointee = switch (field_index) { 25450 Value.Payload.Slice.ptr_index => TypedValue{ 25451 .ty = field_ptr.container_ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), 25452 .val = slice_val.ptr, 25453 }, 25454 Value.Payload.Slice.len_index => TypedValue{ 25455 .ty = Type.usize, 25456 .val = slice_val.len, 25457 }, 25458 else => unreachable, 25459 }; 25460 } else { 25461 const field_ty = field_ptr.container_ty.structFieldType(field_index); 25462 deref.pointee = TypedValue{ 25463 .ty = field_ty, 25464 .val = tv.val.fieldValue(tv.ty, field_index), 25465 }; 25466 } 25467 break :blk deref; 25468 }, 25469 25470 .comptime_field_ptr => blk: { 25471 const comptime_field_ptr = ptr_val.castTag(.comptime_field_ptr).?.data; 25472 break :blk ComptimePtrLoadKit{ 25473 .parent = null, 25474 .pointee = .{ .ty = comptime_field_ptr.field_ty, .val = comptime_field_ptr.field_val }, 25475 .is_mutable = false, 25476 .ty_without_well_defined_layout = comptime_field_ptr.field_ty, 25477 }; 25478 }, 25479 25480 .opt_payload_ptr, 25481 .eu_payload_ptr, 25482 => blk: { 25483 const payload_ptr = ptr_val.cast(Value.Payload.PayloadPtr).?.data; 25484 const payload_ty = switch (ptr_val.tag()) { 25485 .eu_payload_ptr => payload_ptr.container_ty.errorUnionPayload(), 25486 .opt_payload_ptr => try payload_ptr.container_ty.optionalChildAlloc(sema.arena), 25487 else => unreachable, 25488 }; 25489 var deref = try beginComptimePtrLoad(sema, block, src, payload_ptr.container_ptr, payload_ptr.container_ty); 25490 25491 // eu_payload_ptr and opt_payload_ptr never have a well-defined layout 25492 if (deref.parent != null) { 25493 deref.parent = null; 25494 deref.ty_without_well_defined_layout = payload_ptr.container_ty; 25495 } 25496 25497 if (deref.pointee) |*tv| { 25498 const coerce_in_mem_ok = 25499 (try sema.coerceInMemoryAllowed(block, payload_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or 25500 (try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok; 25501 if (coerce_in_mem_ok) { 25502 const payload_val = switch (ptr_val.tag()) { 25503 .eu_payload_ptr => if (tv.val.castTag(.eu_payload)) |some| some.data else { 25504 return sema.fail(block, src, "attempt to unwrap error: {s}", .{tv.val.castTag(.@"error").?.data.name}); 25505 }, 25506 .opt_payload_ptr => if (tv.val.castTag(.opt_payload)) |some| some.data else opt: { 25507 if (tv.val.isNull()) return sema.fail(block, src, "attempt to use null value", .{}); 25508 break :opt tv.val; 25509 }, 25510 else => unreachable, 25511 }; 25512 tv.* = TypedValue{ .ty = payload_ty, .val = payload_val }; 25513 break :blk deref; 25514 } 25515 } 25516 deref.pointee = null; 25517 break :blk deref; 25518 }, 25519 .null_value => { 25520 return sema.fail(block, src, "attempt to use null value", .{}); 25521 }, 25522 25523 .zero, 25524 .one, 25525 .int_u64, 25526 .int_i64, 25527 .int_big_positive, 25528 .int_big_negative, 25529 .variable, 25530 .extern_fn, 25531 .function, 25532 => return error.RuntimeLoad, 25533 25534 else => unreachable, 25535 }; 25536 25537 if (deref.pointee) |tv| { 25538 if (deref.parent == null and tv.ty.hasWellDefinedLayout()) { 25539 deref.parent = .{ .tv = tv, .byte_offset = 0 }; 25540 } 25541 } 25542 return deref; 25543 } 25544 25545 fn bitCast( 25546 sema: *Sema, 25547 block: *Block, 25548 dest_ty_unresolved: Type, 25549 inst: Air.Inst.Ref, 25550 inst_src: LazySrcLoc, 25551 ) CompileError!Air.Inst.Ref { 25552 const dest_ty = try sema.resolveTypeFields(block, inst_src, dest_ty_unresolved); 25553 try sema.resolveTypeLayout(block, inst_src, dest_ty); 25554 25555 const old_ty = try sema.resolveTypeFields(block, inst_src, sema.typeOf(inst)); 25556 try sema.resolveTypeLayout(block, inst_src, old_ty); 25557 25558 const target = sema.mod.getTarget(); 25559 const dest_bits = dest_ty.bitSize(target); 25560 const old_bits = old_ty.bitSize(target); 25561 25562 if (old_bits != dest_bits) { 25563 return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{}' has {d} bits but source type '{}' has {d} bits", .{ 25564 dest_ty.fmt(sema.mod), 25565 dest_bits, 25566 old_ty.fmt(sema.mod), 25567 old_bits, 25568 }); 25569 } 25570 25571 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| { 25572 const result_val = try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0); 25573 return sema.addConstant(dest_ty, result_val); 25574 } 25575 try sema.requireRuntimeBlock(block, inst_src, null); 25576 return block.addBitCast(dest_ty, inst); 25577 } 25578 25579 fn bitCastVal( 25580 sema: *Sema, 25581 block: *Block, 25582 src: LazySrcLoc, 25583 val: Value, 25584 old_ty: Type, 25585 new_ty: Type, 25586 buffer_offset: usize, 25587 ) !Value { 25588 const target = sema.mod.getTarget(); 25589 if (old_ty.eql(new_ty, sema.mod)) return val; 25590 25591 // Some conversions have a bitwise definition that ignores in-memory layout, 25592 // such as converting between f80 and u80. 25593 25594 if (old_ty.eql(Type.f80, sema.mod) and new_ty.isAbiInt()) { 25595 const float = val.toFloat(f80); 25596 switch (new_ty.intInfo(target).signedness) { 25597 .signed => { 25598 const int = @bitCast(i80, float); 25599 const limbs = try sema.arena.alloc(std.math.big.Limb, 2); 25600 const big_int = std.math.big.int.Mutable.init(limbs, int); 25601 return Value.fromBigInt(sema.arena, big_int.toConst()); 25602 }, 25603 .unsigned => { 25604 const int = @bitCast(u80, float); 25605 const limbs = try sema.arena.alloc(std.math.big.Limb, 2); 25606 const big_int = std.math.big.int.Mutable.init(limbs, int); 25607 return Value.fromBigInt(sema.arena, big_int.toConst()); 25608 }, 25609 } 25610 } 25611 25612 if (new_ty.eql(Type.f80, sema.mod) and old_ty.isAbiInt()) { 25613 var bigint_space: Value.BigIntSpace = undefined; 25614 var bigint = try val.toBigIntAdvanced(&bigint_space, target, sema.kit(block, src)); 25615 switch (old_ty.intInfo(target).signedness) { 25616 .signed => { 25617 // This conversion cannot fail because we already checked bit size before 25618 // calling bitCastVal. 25619 const int = bigint.to(i80) catch unreachable; 25620 const float = @bitCast(f80, int); 25621 return Value.Tag.float_80.create(sema.arena, float); 25622 }, 25623 .unsigned => { 25624 // This conversion cannot fail because we already checked bit size before 25625 // calling bitCastVal. 25626 const int = bigint.to(u80) catch unreachable; 25627 const float = @bitCast(f80, int); 25628 return Value.Tag.float_80.create(sema.arena, float); 25629 }, 25630 } 25631 } 25632 25633 // For types with well-defined memory layouts, we serialize them a byte buffer, 25634 // then deserialize to the new type. 25635 const abi_size = try sema.usizeCast(block, src, old_ty.abiSize(target)); 25636 const buffer = try sema.gpa.alloc(u8, abi_size); 25637 defer sema.gpa.free(buffer); 25638 val.writeToMemory(old_ty, sema.mod, buffer); 25639 return Value.readFromMemory(new_ty, sema.mod, buffer[buffer_offset..], sema.arena); 25640 } 25641 25642 fn coerceArrayPtrToSlice( 25643 sema: *Sema, 25644 block: *Block, 25645 dest_ty: Type, 25646 inst: Air.Inst.Ref, 25647 inst_src: LazySrcLoc, 25648 ) CompileError!Air.Inst.Ref { 25649 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| { 25650 const ptr_array_ty = sema.typeOf(inst); 25651 const array_ty = ptr_array_ty.childType(); 25652 const slice_val = try Value.Tag.slice.create(sema.arena, .{ 25653 .ptr = val, 25654 .len = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()), 25655 }); 25656 return sema.addConstant(dest_ty, slice_val); 25657 } 25658 try sema.requireRuntimeBlock(block, inst_src, null); 25659 return block.addTyOp(.array_to_slice, dest_ty, inst); 25660 } 25661 25662 fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_result: *InMemoryCoercionResult) bool { 25663 const dest_info = dest_ty.ptrInfo().data; 25664 const inst_info = inst_ty.ptrInfo().data; 25665 const len0 = (inst_info.pointee_type.zigTypeTag() == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel() == 0 or 25666 (inst_info.pointee_type.arrayLen() == 0 and dest_info.sentinel == null and dest_info.size != .C and dest_info.size != .Many))) or 25667 (inst_info.pointee_type.isTuple() and inst_info.pointee_type.tupleFields().types.len == 0); 25668 25669 const ok_cv_qualifiers = 25670 ((inst_info.mutable or !dest_info.mutable) or len0) and 25671 (!inst_info.@"volatile" or dest_info.@"volatile"); 25672 25673 if (!ok_cv_qualifiers) { 25674 in_memory_result.* = .{ .ptr_qualifiers = .{ 25675 .actual_const = !inst_info.mutable, 25676 .wanted_const = !dest_info.mutable, 25677 .actual_volatile = inst_info.@"volatile", 25678 .wanted_volatile = dest_info.@"volatile", 25679 } }; 25680 return false; 25681 } 25682 if (dest_info.@"addrspace" != inst_info.@"addrspace") { 25683 in_memory_result.* = .{ .ptr_addrspace = .{ 25684 .actual = inst_info.@"addrspace", 25685 .wanted = dest_info.@"addrspace", 25686 } }; 25687 return false; 25688 } 25689 if (inst_info.@"align" == 0 and dest_info.@"align" == 0) return true; 25690 if (len0) return true; 25691 const target = sema.mod.getTarget(); 25692 25693 const inst_align = if (inst_info.@"align" != 0) 25694 inst_info.@"align" 25695 else 25696 inst_info.pointee_type.abiAlignment(target); 25697 25698 const dest_align = if (dest_info.@"align" != 0) 25699 dest_info.@"align" 25700 else 25701 dest_info.pointee_type.abiAlignment(target); 25702 25703 if (dest_align > inst_align) { 25704 in_memory_result.* = .{ .ptr_alignment = .{ 25705 .actual = inst_align, 25706 .wanted = dest_align, 25707 } }; 25708 return false; 25709 } 25710 return true; 25711 } 25712 25713 fn coerceCompatiblePtrs( 25714 sema: *Sema, 25715 block: *Block, 25716 dest_ty: Type, 25717 inst: Air.Inst.Ref, 25718 inst_src: LazySrcLoc, 25719 ) !Air.Inst.Ref { 25720 const inst_ty = sema.typeOf(inst); 25721 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| { 25722 // The comptime Value representation is compatible with both types. 25723 return sema.addConstant(dest_ty, val); 25724 } 25725 try sema.requireRuntimeBlock(block, inst_src, null); 25726 const inst_allows_zero = (inst_ty.zigTypeTag() == .Pointer and inst_ty.ptrAllowsZero()) or true; 25727 if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero() and 25728 try sema.typeHasRuntimeBits(block, sema.src, dest_ty.elemType2())) 25729 { 25730 const actual_ptr = if (inst_ty.isSlice()) 25731 try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty) 25732 else 25733 inst; 25734 const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr); 25735 const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize); 25736 const ok = if (inst_ty.isSlice()) ok: { 25737 const len = try sema.analyzeSliceLen(block, inst_src, inst); 25738 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); 25739 break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero); 25740 } else is_non_zero; 25741 try sema.addSafetyCheck(block, ok, .cast_to_null); 25742 } 25743 return sema.bitCast(block, dest_ty, inst, inst_src); 25744 } 25745 25746 fn coerceEnumToUnion( 25747 sema: *Sema, 25748 block: *Block, 25749 union_ty: Type, 25750 union_ty_src: LazySrcLoc, 25751 inst: Air.Inst.Ref, 25752 inst_src: LazySrcLoc, 25753 ) !Air.Inst.Ref { 25754 const inst_ty = sema.typeOf(inst); 25755 25756 const tag_ty = union_ty.unionTagType() orelse { 25757 const msg = msg: { 25758 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ 25759 union_ty.fmt(sema.mod), inst_ty.fmt(sema.mod), 25760 }); 25761 errdefer msg.destroy(sema.gpa); 25762 try sema.errNote(block, union_ty_src, msg, "cannot coerce enum to untagged union", .{}); 25763 try sema.addDeclaredHereNote(msg, union_ty); 25764 break :msg msg; 25765 }; 25766 return sema.failWithOwnedErrorMsg(msg); 25767 }; 25768 25769 const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src); 25770 if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| { 25771 const field_index = union_ty.unionTagFieldIndex(val, sema.mod) orelse { 25772 const msg = msg: { 25773 const msg = try sema.errMsg(block, inst_src, "union '{}' has no tag with value '{}'", .{ 25774 union_ty.fmt(sema.mod), val.fmtValue(tag_ty, sema.mod), 25775 }); 25776 errdefer msg.destroy(sema.gpa); 25777 try sema.addDeclaredHereNote(msg, union_ty); 25778 break :msg msg; 25779 }; 25780 return sema.failWithOwnedErrorMsg(msg); 25781 }; 25782 25783 const union_obj = union_ty.cast(Type.Payload.Union).?.data; 25784 const field = union_obj.fields.values()[field_index]; 25785 const field_ty = try sema.resolveTypeFields(block, inst_src, field.ty); 25786 if (field_ty.zigTypeTag() == .NoReturn) { 25787 const msg = msg: { 25788 const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{}); 25789 errdefer msg.destroy(sema.gpa); 25790 25791 const field_name = union_obj.fields.keys()[field_index]; 25792 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); 25793 try sema.addDeclaredHereNote(msg, union_ty); 25794 break :msg msg; 25795 }; 25796 return sema.failWithOwnedErrorMsg(msg); 25797 } 25798 const opv = (try sema.typeHasOnePossibleValue(block, inst_src, field_ty)) orelse { 25799 const msg = msg: { 25800 const field_name = union_obj.fields.keys()[field_index]; 25801 const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{s}'", .{ 25802 inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod), field_ty.fmt(sema.mod), field_name, 25803 }); 25804 errdefer msg.destroy(sema.gpa); 25805 25806 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); 25807 try sema.addDeclaredHereNote(msg, union_ty); 25808 break :msg msg; 25809 }; 25810 return sema.failWithOwnedErrorMsg(msg); 25811 }; 25812 25813 return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{ 25814 .tag = val, 25815 .val = opv, 25816 })); 25817 } 25818 25819 try sema.requireRuntimeBlock(block, inst_src, null); 25820 25821 if (tag_ty.isNonexhaustiveEnum()) { 25822 const msg = msg: { 25823 const msg = try sema.errMsg(block, inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{ 25824 union_ty.fmt(sema.mod), 25825 }); 25826 errdefer msg.destroy(sema.gpa); 25827 try sema.addDeclaredHereNote(msg, tag_ty); 25828 break :msg msg; 25829 }; 25830 return sema.failWithOwnedErrorMsg(msg); 25831 } 25832 25833 const union_obj = union_ty.cast(Type.Payload.Union).?.data; 25834 { 25835 var msg: ?*Module.ErrorMsg = null; 25836 errdefer if (msg) |some| some.destroy(sema.gpa); 25837 25838 for (union_obj.fields.values()) |field, i| { 25839 if (field.ty.zigTypeTag() == .NoReturn) { 25840 const err_msg = msg orelse try sema.errMsg( 25841 block, 25842 inst_src, 25843 "runtime coercion from enum '{}' to union '{}' which has a 'noreturn' field", 25844 .{ tag_ty.fmt(sema.mod), union_ty.fmt(sema.mod) }, 25845 ); 25846 msg = err_msg; 25847 25848 try sema.addFieldErrNote(union_ty, i, err_msg, "'noreturn' field here", .{}); 25849 } 25850 } 25851 if (msg) |some| { 25852 msg = null; 25853 try sema.addDeclaredHereNote(some, union_ty); 25854 return sema.failWithOwnedErrorMsg(some); 25855 } 25856 } 25857 25858 // If the union has all fields 0 bits, the union value is just the enum value. 25859 if (union_ty.unionHasAllZeroBitFieldTypes()) { 25860 return block.addBitCast(union_ty, enum_tag); 25861 } 25862 25863 const msg = msg: { 25864 const msg = try sema.errMsg( 25865 block, 25866 inst_src, 25867 "runtime coercion from enum '{}' to union '{}' which has non-void fields", 25868 .{ tag_ty.fmt(sema.mod), union_ty.fmt(sema.mod) }, 25869 ); 25870 errdefer msg.destroy(sema.gpa); 25871 25872 var it = union_obj.fields.iterator(); 25873 var field_index: usize = 0; 25874 while (it.next()) |field| : (field_index += 1) { 25875 const field_name = field.key_ptr.*; 25876 const field_ty = field.value_ptr.ty; 25877 if (!field_ty.hasRuntimeBits()) continue; 25878 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) }); 25879 } 25880 try sema.addDeclaredHereNote(msg, union_ty); 25881 break :msg msg; 25882 }; 25883 return sema.failWithOwnedErrorMsg(msg); 25884 } 25885 25886 fn coerceAnonStructToUnion( 25887 sema: *Sema, 25888 block: *Block, 25889 union_ty: Type, 25890 union_ty_src: LazySrcLoc, 25891 inst: Air.Inst.Ref, 25892 inst_src: LazySrcLoc, 25893 ) !Air.Inst.Ref { 25894 const inst_ty = sema.typeOf(inst); 25895 const field_count = inst_ty.structFieldCount(); 25896 if (field_count != 1) { 25897 const msg = msg: { 25898 const msg = if (field_count > 1) try sema.errMsg( 25899 block, 25900 inst_src, 25901 "cannot initialize multiple union fields at once, unions can only have one active field", 25902 .{}, 25903 ) else try sema.errMsg( 25904 block, 25905 inst_src, 25906 "union initializer must initialize one field", 25907 .{}, 25908 ); 25909 errdefer msg.destroy(sema.gpa); 25910 25911 // TODO add notes for where the anon struct was created to point out 25912 // the extra fields. 25913 25914 try sema.addDeclaredHereNote(msg, union_ty); 25915 break :msg msg; 25916 }; 25917 return sema.failWithOwnedErrorMsg(msg); 25918 } 25919 25920 const anon_struct = inst_ty.castTag(.anon_struct).?.data; 25921 const field_name = anon_struct.names[0]; 25922 const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty); 25923 return sema.unionInit(block, init, inst_src, union_ty, union_ty_src, field_name, inst_src); 25924 } 25925 25926 fn coerceAnonStructToUnionPtrs( 25927 sema: *Sema, 25928 block: *Block, 25929 ptr_union_ty: Type, 25930 union_ty_src: LazySrcLoc, 25931 ptr_anon_struct: Air.Inst.Ref, 25932 anon_struct_src: LazySrcLoc, 25933 ) !Air.Inst.Ref { 25934 const union_ty = ptr_union_ty.childType(); 25935 const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src); 25936 const union_inst = try sema.coerceAnonStructToUnion(block, union_ty, union_ty_src, anon_struct, anon_struct_src); 25937 return sema.analyzeRef(block, union_ty_src, union_inst); 25938 } 25939 25940 fn coerceAnonStructToStructPtrs( 25941 sema: *Sema, 25942 block: *Block, 25943 ptr_struct_ty: Type, 25944 struct_ty_src: LazySrcLoc, 25945 ptr_anon_struct: Air.Inst.Ref, 25946 anon_struct_src: LazySrcLoc, 25947 ) !Air.Inst.Ref { 25948 const struct_ty = ptr_struct_ty.childType(); 25949 const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src); 25950 const struct_inst = try sema.coerceTupleToStruct(block, struct_ty, struct_ty_src, anon_struct, anon_struct_src); 25951 return sema.analyzeRef(block, struct_ty_src, struct_inst); 25952 } 25953 25954 /// If the lengths match, coerces element-wise. 25955 fn coerceArrayLike( 25956 sema: *Sema, 25957 block: *Block, 25958 dest_ty: Type, 25959 dest_ty_src: LazySrcLoc, 25960 inst: Air.Inst.Ref, 25961 inst_src: LazySrcLoc, 25962 ) !Air.Inst.Ref { 25963 const inst_ty = sema.typeOf(inst); 25964 const inst_len = inst_ty.arrayLen(); 25965 const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen()); 25966 const target = sema.mod.getTarget(); 25967 25968 if (dest_len != inst_len) { 25969 const msg = msg: { 25970 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ 25971 dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod), 25972 }); 25973 errdefer msg.destroy(sema.gpa); 25974 try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len}); 25975 try sema.errNote(block, inst_src, msg, "source has length {d}", .{inst_len}); 25976 break :msg msg; 25977 }; 25978 return sema.failWithOwnedErrorMsg(msg); 25979 } 25980 25981 const dest_elem_ty = dest_ty.childType(); 25982 const inst_elem_ty = inst_ty.childType(); 25983 const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_elem_ty, inst_elem_ty, false, target, dest_ty_src, inst_src); 25984 if (in_memory_result == .ok) { 25985 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |inst_val| { 25986 // These types share the same comptime value representation. 25987 return sema.addConstant(dest_ty, inst_val); 25988 } 25989 try sema.requireRuntimeBlock(block, inst_src, null); 25990 return block.addBitCast(dest_ty, inst); 25991 } 25992 25993 const element_vals = try sema.arena.alloc(Value, dest_len); 25994 const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_len); 25995 var runtime_src: ?LazySrcLoc = null; 25996 25997 for (element_vals) |*elem, i| { 25998 const index_ref = try sema.addConstant( 25999 Type.usize, 26000 try Value.Tag.int_u64.create(sema.arena, i), 26001 ); 26002 const src = inst_src; // TODO better source location 26003 const elem_src = inst_src; // TODO better source location 26004 const elem_ref = try sema.elemValArray(block, src, inst_src, inst, elem_src, index_ref); 26005 const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); 26006 element_refs[i] = coerced; 26007 if (runtime_src == null) { 26008 if (try sema.resolveMaybeUndefVal(block, elem_src, coerced)) |elem_val| { 26009 elem.* = elem_val; 26010 } else { 26011 runtime_src = elem_src; 26012 } 26013 } 26014 } 26015 26016 if (runtime_src) |rs| { 26017 try sema.requireRuntimeBlock(block, inst_src, rs); 26018 return block.addAggregateInit(dest_ty, element_refs); 26019 } 26020 26021 return sema.addConstant( 26022 dest_ty, 26023 try Value.Tag.aggregate.create(sema.arena, element_vals), 26024 ); 26025 } 26026 26027 /// If the lengths match, coerces element-wise. 26028 fn coerceTupleToArray( 26029 sema: *Sema, 26030 block: *Block, 26031 dest_ty: Type, 26032 dest_ty_src: LazySrcLoc, 26033 inst: Air.Inst.Ref, 26034 inst_src: LazySrcLoc, 26035 ) !Air.Inst.Ref { 26036 const inst_ty = sema.typeOf(inst); 26037 const inst_len = inst_ty.arrayLen(); 26038 const dest_len = dest_ty.arrayLen(); 26039 26040 if (dest_len != inst_len) { 26041 const msg = msg: { 26042 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ 26043 dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod), 26044 }); 26045 errdefer msg.destroy(sema.gpa); 26046 try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len}); 26047 try sema.errNote(block, inst_src, msg, "source has length {d}", .{inst_len}); 26048 break :msg msg; 26049 }; 26050 return sema.failWithOwnedErrorMsg(msg); 26051 } 26052 26053 const dest_elems = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLenIncludingSentinel()); 26054 const element_vals = try sema.arena.alloc(Value, dest_elems); 26055 const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_elems); 26056 const dest_elem_ty = dest_ty.childType(); 26057 26058 var runtime_src: ?LazySrcLoc = null; 26059 for (element_vals) |*elem, i_usize| { 26060 const i = @intCast(u32, i_usize); 26061 if (i_usize == inst_len) { 26062 elem.* = dest_ty.sentinel().?; 26063 element_refs[i] = try sema.addConstant(dest_elem_ty, elem.*); 26064 break; 26065 } 26066 const elem_src = inst_src; // TODO better source location 26067 const elem_ref = try tupleField(sema, block, inst_src, inst, elem_src, i); 26068 const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); 26069 element_refs[i] = coerced; 26070 if (runtime_src == null) { 26071 if (try sema.resolveMaybeUndefVal(block, elem_src, coerced)) |elem_val| { 26072 elem.* = elem_val; 26073 } else { 26074 runtime_src = elem_src; 26075 } 26076 } 26077 } 26078 26079 if (runtime_src) |rs| { 26080 try sema.requireRuntimeBlock(block, inst_src, rs); 26081 return block.addAggregateInit(dest_ty, element_refs); 26082 } 26083 26084 return sema.addConstant( 26085 dest_ty, 26086 try Value.Tag.aggregate.create(sema.arena, element_vals), 26087 ); 26088 } 26089 26090 /// If the lengths match, coerces element-wise. 26091 fn coerceTupleToSlicePtrs( 26092 sema: *Sema, 26093 block: *Block, 26094 slice_ty: Type, 26095 slice_ty_src: LazySrcLoc, 26096 ptr_tuple: Air.Inst.Ref, 26097 tuple_src: LazySrcLoc, 26098 ) !Air.Inst.Ref { 26099 const tuple_ty = sema.typeOf(ptr_tuple).childType(); 26100 const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src); 26101 const slice_info = slice_ty.ptrInfo().data; 26102 const array_ty = try Type.array(sema.arena, tuple_ty.structFieldCount(), slice_info.sentinel, slice_info.pointee_type, sema.mod); 26103 const array_inst = try sema.coerceTupleToArray(block, array_ty, slice_ty_src, tuple, tuple_src); 26104 if (slice_info.@"align" != 0) { 26105 return sema.fail(block, slice_ty_src, "TODO: override the alignment of the array decl we create here", .{}); 26106 } 26107 const ptr_array = try sema.analyzeRef(block, slice_ty_src, array_inst); 26108 return sema.coerceArrayPtrToSlice(block, slice_ty, ptr_array, slice_ty_src); 26109 } 26110 26111 /// If the lengths match, coerces element-wise. 26112 fn coerceTupleToArrayPtrs( 26113 sema: *Sema, 26114 block: *Block, 26115 ptr_array_ty: Type, 26116 array_ty_src: LazySrcLoc, 26117 ptr_tuple: Air.Inst.Ref, 26118 tuple_src: LazySrcLoc, 26119 ) !Air.Inst.Ref { 26120 const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src); 26121 const ptr_info = ptr_array_ty.ptrInfo().data; 26122 const array_ty = ptr_info.pointee_type; 26123 const array_inst = try sema.coerceTupleToArray(block, array_ty, array_ty_src, tuple, tuple_src); 26124 if (ptr_info.@"align" != 0) { 26125 return sema.fail(block, array_ty_src, "TODO: override the alignment of the array decl we create here", .{}); 26126 } 26127 const ptr_array = try sema.analyzeRef(block, array_ty_src, array_inst); 26128 return ptr_array; 26129 } 26130 26131 /// Handles both tuples and anon struct literals. Coerces field-wise. Reports 26132 /// errors for both extra fields and missing fields. 26133 fn coerceTupleToStruct( 26134 sema: *Sema, 26135 block: *Block, 26136 dest_ty: Type, 26137 dest_ty_src: LazySrcLoc, 26138 inst: Air.Inst.Ref, 26139 inst_src: LazySrcLoc, 26140 ) !Air.Inst.Ref { 26141 const struct_ty = try sema.resolveTypeFields(block, dest_ty_src, dest_ty); 26142 26143 if (struct_ty.isTupleOrAnonStruct()) { 26144 return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src); 26145 } 26146 26147 const fields = struct_ty.structFields(); 26148 const field_vals = try sema.arena.alloc(Value, fields.count()); 26149 const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); 26150 mem.set(Air.Inst.Ref, field_refs, .none); 26151 26152 const inst_ty = sema.typeOf(inst); 26153 const tuple = inst_ty.tupleFields(); 26154 var runtime_src: ?LazySrcLoc = null; 26155 for (tuple.types) |_, i_usize| { 26156 const i = @intCast(u32, i_usize); 26157 const field_src = inst_src; // TODO better source location 26158 const field_name = if (inst_ty.castTag(.anon_struct)) |payload| 26159 payload.data.names[i] 26160 else 26161 try std.fmt.allocPrint(sema.arena, "{d}", .{i}); 26162 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src); 26163 const field = fields.values()[field_index]; 26164 const elem_ref = try tupleField(sema, block, inst_src, inst, field_src, i); 26165 const coerced = try sema.coerce(block, field.ty, elem_ref, field_src); 26166 field_refs[field_index] = coerced; 26167 if (field.is_comptime) { 26168 const init_val = (try sema.resolveMaybeUndefVal(block, field_src, coerced)) orelse { 26169 return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime known"); 26170 }; 26171 26172 if (!init_val.eql(field.default_val, field.ty, sema.mod)) { 26173 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, i); 26174 } 26175 } 26176 if (runtime_src == null) { 26177 if (try sema.resolveMaybeUndefVal(block, field_src, coerced)) |field_val| { 26178 field_vals[field_index] = field_val; 26179 } else { 26180 runtime_src = field_src; 26181 } 26182 } 26183 } 26184 26185 // Populate default field values and report errors for missing fields. 26186 var root_msg: ?*Module.ErrorMsg = null; 26187 errdefer if (root_msg) |msg| msg.destroy(sema.gpa); 26188 26189 for (field_refs) |*field_ref, i| { 26190 if (field_ref.* != .none) continue; 26191 26192 const field_name = fields.keys()[i]; 26193 const field = fields.values()[i]; 26194 const field_src = inst_src; // TODO better source location 26195 if (field.default_val.tag() == .unreachable_value) { 26196 const template = "missing struct field: {s}"; 26197 const args = .{field_name}; 26198 if (root_msg) |msg| { 26199 try sema.errNote(block, field_src, msg, template, args); 26200 } else { 26201 root_msg = try sema.errMsg(block, field_src, template, args); 26202 } 26203 continue; 26204 } 26205 if (runtime_src == null) { 26206 field_vals[i] = field.default_val; 26207 } else { 26208 field_ref.* = try sema.addConstant(field.ty, field.default_val); 26209 } 26210 } 26211 26212 if (root_msg) |msg| { 26213 root_msg = null; 26214 try sema.addDeclaredHereNote(msg, struct_ty); 26215 return sema.failWithOwnedErrorMsg(msg); 26216 } 26217 26218 if (runtime_src) |rs| { 26219 try sema.requireRuntimeBlock(block, inst_src, rs); 26220 return block.addAggregateInit(struct_ty, field_refs); 26221 } 26222 26223 return sema.addConstant( 26224 struct_ty, 26225 try Value.Tag.aggregate.create(sema.arena, field_vals), 26226 ); 26227 } 26228 26229 fn coerceTupleToTuple( 26230 sema: *Sema, 26231 block: *Block, 26232 tuple_ty: Type, 26233 inst: Air.Inst.Ref, 26234 inst_src: LazySrcLoc, 26235 ) !Air.Inst.Ref { 26236 const field_count = tuple_ty.structFieldCount(); 26237 const field_vals = try sema.arena.alloc(Value, field_count); 26238 const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); 26239 mem.set(Air.Inst.Ref, field_refs, .none); 26240 26241 const inst_ty = sema.typeOf(inst); 26242 const tuple = inst_ty.tupleFields(); 26243 var runtime_src: ?LazySrcLoc = null; 26244 for (tuple.types) |_, i_usize| { 26245 const i = @intCast(u32, i_usize); 26246 const field_src = inst_src; // TODO better source location 26247 const field_name = if (inst_ty.castTag(.anon_struct)) |payload| 26248 payload.data.names[i] 26249 else 26250 try std.fmt.allocPrint(sema.arena, "{d}", .{i}); 26251 26252 if (mem.eql(u8, field_name, "len")) { 26253 return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{}); 26254 } 26255 26256 const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src); 26257 26258 const field_ty = tuple_ty.structFieldType(i); 26259 const default_val = tuple_ty.structFieldDefaultValue(i); 26260 const elem_ref = try tupleField(sema, block, inst_src, inst, field_src, i); 26261 const coerced = try sema.coerce(block, field_ty, elem_ref, field_src); 26262 field_refs[field_index] = coerced; 26263 if (default_val.tag() != .unreachable_value) { 26264 const init_val = (try sema.resolveMaybeUndefVal(block, field_src, coerced)) orelse { 26265 return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime known"); 26266 }; 26267 26268 if (!init_val.eql(default_val, field_ty, sema.mod)) { 26269 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, i); 26270 } 26271 } 26272 if (runtime_src == null) { 26273 if (try sema.resolveMaybeUndefVal(block, field_src, coerced)) |field_val| { 26274 field_vals[field_index] = field_val; 26275 } else { 26276 runtime_src = field_src; 26277 } 26278 } 26279 } 26280 26281 // Populate default field values and report errors for missing fields. 26282 var root_msg: ?*Module.ErrorMsg = null; 26283 errdefer if (root_msg) |msg| msg.destroy(sema.gpa); 26284 26285 for (field_refs) |*field_ref, i| { 26286 if (field_ref.* != .none) continue; 26287 26288 const default_val = tuple_ty.structFieldDefaultValue(i); 26289 const field_ty = tuple_ty.structFieldType(i); 26290 26291 const field_src = inst_src; // TODO better source location 26292 if (default_val.tag() == .unreachable_value) { 26293 if (tuple_ty.isTuple()) { 26294 const template = "missing tuple field: {d}"; 26295 if (root_msg) |msg| { 26296 try sema.errNote(block, field_src, msg, template, .{i}); 26297 } else { 26298 root_msg = try sema.errMsg(block, field_src, template, .{i}); 26299 } 26300 continue; 26301 } 26302 const template = "missing struct field: {s}"; 26303 const args = .{tuple_ty.structFieldName(i)}; 26304 if (root_msg) |msg| { 26305 try sema.errNote(block, field_src, msg, template, args); 26306 } else { 26307 root_msg = try sema.errMsg(block, field_src, template, args); 26308 } 26309 continue; 26310 } 26311 if (runtime_src == null) { 26312 field_vals[i] = default_val; 26313 } else { 26314 field_ref.* = try sema.addConstant(field_ty, default_val); 26315 } 26316 } 26317 26318 if (root_msg) |msg| { 26319 root_msg = null; 26320 try sema.addDeclaredHereNote(msg, tuple_ty); 26321 return sema.failWithOwnedErrorMsg(msg); 26322 } 26323 26324 if (runtime_src) |rs| { 26325 try sema.requireRuntimeBlock(block, inst_src, rs); 26326 return block.addAggregateInit(tuple_ty, field_refs); 26327 } 26328 26329 return sema.addConstant( 26330 tuple_ty, 26331 try Value.Tag.aggregate.create(sema.arena, field_vals), 26332 ); 26333 } 26334 26335 fn analyzeDeclVal( 26336 sema: *Sema, 26337 block: *Block, 26338 src: LazySrcLoc, 26339 decl_index: Decl.Index, 26340 ) CompileError!Air.Inst.Ref { 26341 if (sema.decl_val_table.get(decl_index)) |result| { 26342 return result; 26343 } 26344 try sema.addReferencedBy(block, src, decl_index); 26345 const decl_ref = try sema.analyzeDeclRef(decl_index); 26346 const result = try sema.analyzeLoad(block, src, decl_ref, src); 26347 if (Air.refToIndex(result)) |index| { 26348 if (sema.air_instructions.items(.tag)[index] == .constant and !block.is_typeof) { 26349 try sema.decl_val_table.put(sema.gpa, decl_index, result); 26350 } 26351 } 26352 return result; 26353 } 26354 26355 fn addReferencedBy( 26356 sema: *Sema, 26357 block: *Block, 26358 src: LazySrcLoc, 26359 decl_index: Decl.Index, 26360 ) !void { 26361 if (sema.mod.comp.reference_trace == @as(u32, 0)) return; 26362 try sema.mod.reference_table.put(sema.gpa, decl_index, .{ 26363 .referencer = block.src_decl, 26364 .src = src, 26365 }); 26366 } 26367 26368 fn ensureDeclAnalyzed(sema: *Sema, decl_index: Decl.Index) CompileError!void { 26369 const decl = sema.mod.declPtr(decl_index); 26370 if (decl.analysis == .in_progress) { 26371 const msg = try Module.ErrorMsg.create(sema.gpa, decl.srcLoc(), "dependency loop detected", .{}); 26372 return sema.failWithOwnedErrorMsg(msg); 26373 } 26374 26375 sema.mod.ensureDeclAnalyzed(decl_index) catch |err| { 26376 if (sema.owner_func) |owner_func| { 26377 owner_func.state = .dependency_failure; 26378 } else { 26379 sema.owner_decl.analysis = .dependency_failure; 26380 } 26381 return err; 26382 }; 26383 } 26384 26385 fn ensureFuncBodyAnalyzed(sema: *Sema, func: *Module.Fn) CompileError!void { 26386 sema.mod.ensureFuncBodyAnalyzed(func) catch |err| { 26387 if (sema.owner_func) |owner_func| { 26388 owner_func.state = .dependency_failure; 26389 } else { 26390 sema.owner_decl.analysis = .dependency_failure; 26391 } 26392 return err; 26393 }; 26394 } 26395 26396 fn refValue(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, val: Value) !Value { 26397 var anon_decl = try block.startAnonDecl(src); 26398 defer anon_decl.deinit(); 26399 const decl = try anon_decl.finish( 26400 try ty.copy(anon_decl.arena()), 26401 try val.copy(anon_decl.arena()), 26402 0, // default alignment 26403 ); 26404 try sema.mod.declareDeclDependency(sema.owner_decl_index, decl); 26405 return try Value.Tag.decl_ref.create(sema.arena, decl); 26406 } 26407 26408 fn optRefValue(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, opt_val: ?Value) !Value { 26409 const val = opt_val orelse return Value.@"null"; 26410 const ptr_val = try refValue(sema, block, src, ty, val); 26411 const result = try Value.Tag.opt_payload.create(sema.arena, ptr_val); 26412 return result; 26413 } 26414 26415 fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref { 26416 try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index); 26417 try sema.ensureDeclAnalyzed(decl_index); 26418 26419 const decl = sema.mod.declPtr(decl_index); 26420 const decl_tv = try decl.typedValue(); 26421 if (decl_tv.val.castTag(.variable)) |payload| { 26422 const variable = payload.data; 26423 const ty = try Type.ptr(sema.arena, sema.mod, .{ 26424 .pointee_type = decl_tv.ty, 26425 .mutable = variable.is_mutable, 26426 .@"addrspace" = decl.@"addrspace", 26427 .@"align" = decl.@"align", 26428 }); 26429 return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl_index)); 26430 } 26431 return sema.addConstant( 26432 try Type.ptr(sema.arena, sema.mod, .{ 26433 .pointee_type = decl_tv.ty, 26434 .mutable = false, 26435 .@"addrspace" = decl.@"addrspace", 26436 .@"align" = decl.@"align", 26437 }), 26438 try Value.Tag.decl_ref.create(sema.arena, decl_index), 26439 ); 26440 } 26441 26442 fn analyzeRef( 26443 sema: *Sema, 26444 block: *Block, 26445 src: LazySrcLoc, 26446 operand: Air.Inst.Ref, 26447 ) CompileError!Air.Inst.Ref { 26448 const operand_ty = sema.typeOf(operand); 26449 26450 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| { 26451 var anon_decl = try block.startAnonDecl(src); 26452 defer anon_decl.deinit(); 26453 return sema.analyzeDeclRef(try anon_decl.finish( 26454 try operand_ty.copy(anon_decl.arena()), 26455 try val.copy(anon_decl.arena()), 26456 0, // default alignment 26457 )); 26458 } 26459 26460 try sema.requireRuntimeBlock(block, src, null); 26461 const address_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local); 26462 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{ 26463 .pointee_type = operand_ty, 26464 .mutable = false, 26465 .@"addrspace" = address_space, 26466 }); 26467 const mut_ptr_type = try Type.ptr(sema.arena, sema.mod, .{ 26468 .pointee_type = operand_ty, 26469 .@"addrspace" = address_space, 26470 }); 26471 const alloc = try block.addTy(.alloc, mut_ptr_type); 26472 try sema.storePtr(block, src, alloc, operand); 26473 26474 // TODO: Replace with sema.coerce when that supports adding pointer constness. 26475 return sema.bitCast(block, ptr_type, alloc, src); 26476 } 26477 26478 fn analyzeLoad( 26479 sema: *Sema, 26480 block: *Block, 26481 src: LazySrcLoc, 26482 ptr: Air.Inst.Ref, 26483 ptr_src: LazySrcLoc, 26484 ) CompileError!Air.Inst.Ref { 26485 const ptr_ty = sema.typeOf(ptr); 26486 const elem_ty = switch (ptr_ty.zigTypeTag()) { 26487 .Pointer => ptr_ty.childType(), 26488 else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}), 26489 }; 26490 26491 if (try sema.typeHasOnePossibleValue(block, src, elem_ty)) |opv| { 26492 return sema.addConstant(elem_ty, opv); 26493 } 26494 26495 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { 26496 if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| { 26497 return sema.addConstant(elem_ty, elem_val); 26498 } 26499 if (block.is_typeof) { 26500 return sema.addConstUndef(elem_ty); 26501 } 26502 } 26503 26504 if (block.is_comptime) { 26505 // TODO ideally this would tell why the block is comptime 26506 return sema.fail(block, ptr_src, "cannot load runtime value in comptime block", .{}); 26507 } 26508 26509 try sema.requireFunctionBlock(block, src); 26510 return block.addTyOp(.load, elem_ty, ptr); 26511 } 26512 26513 fn analyzeSlicePtr( 26514 sema: *Sema, 26515 block: *Block, 26516 slice_src: LazySrcLoc, 26517 slice: Air.Inst.Ref, 26518 slice_ty: Type, 26519 ) CompileError!Air.Inst.Ref { 26520 const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer); 26521 const result_ty = slice_ty.slicePtrFieldType(buf); 26522 if (try sema.resolveMaybeUndefVal(block, slice_src, slice)) |val| { 26523 if (val.isUndef()) return sema.addConstUndef(result_ty); 26524 return sema.addConstant(result_ty, val.slicePtr()); 26525 } 26526 try sema.requireRuntimeBlock(block, slice_src, null); 26527 return block.addTyOp(.slice_ptr, result_ty, slice); 26528 } 26529 26530 fn analyzeSliceLen( 26531 sema: *Sema, 26532 block: *Block, 26533 src: LazySrcLoc, 26534 slice_inst: Air.Inst.Ref, 26535 ) CompileError!Air.Inst.Ref { 26536 if (try sema.resolveMaybeUndefVal(block, src, slice_inst)) |slice_val| { 26537 if (slice_val.isUndef()) { 26538 return sema.addConstUndef(Type.usize); 26539 } 26540 return sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod)); 26541 } 26542 try sema.requireRuntimeBlock(block, src, null); 26543 return block.addTyOp(.slice_len, Type.usize, slice_inst); 26544 } 26545 26546 fn analyzeIsNull( 26547 sema: *Sema, 26548 block: *Block, 26549 src: LazySrcLoc, 26550 operand: Air.Inst.Ref, 26551 invert_logic: bool, 26552 ) CompileError!Air.Inst.Ref { 26553 const result_ty = Type.bool; 26554 if (try sema.resolveMaybeUndefVal(block, src, operand)) |opt_val| { 26555 if (opt_val.isUndef()) { 26556 return sema.addConstUndef(result_ty); 26557 } 26558 const is_null = opt_val.isNull(); 26559 const bool_value = if (invert_logic) !is_null else is_null; 26560 if (bool_value) { 26561 return Air.Inst.Ref.bool_true; 26562 } else { 26563 return Air.Inst.Ref.bool_false; 26564 } 26565 } 26566 26567 const operand_ty = sema.typeOf(operand); 26568 var buf: Type.Payload.ElemType = undefined; 26569 if (operand_ty.zigTypeTag() == .Optional and operand_ty.optionalChild(&buf).zigTypeTag() == .NoReturn) { 26570 return Air.Inst.Ref.bool_true; 26571 } 26572 try sema.requireRuntimeBlock(block, src, null); 26573 const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null; 26574 return block.addUnOp(air_tag, operand); 26575 } 26576 26577 fn analyzePtrIsNonErrComptimeOnly( 26578 sema: *Sema, 26579 block: *Block, 26580 src: LazySrcLoc, 26581 operand: Air.Inst.Ref, 26582 ) CompileError!Air.Inst.Ref { 26583 const ptr_ty = sema.typeOf(operand); 26584 assert(ptr_ty.zigTypeTag() == .Pointer); 26585 const child_ty = ptr_ty.childType(); 26586 26587 const child_tag = child_ty.zigTypeTag(); 26588 if (child_tag != .ErrorSet and child_tag != .ErrorUnion) return Air.Inst.Ref.bool_true; 26589 if (child_tag == .ErrorSet) return Air.Inst.Ref.bool_false; 26590 assert(child_tag == .ErrorUnion); 26591 26592 _ = block; 26593 _ = src; 26594 26595 return Air.Inst.Ref.none; 26596 } 26597 26598 fn analyzeIsNonErrComptimeOnly( 26599 sema: *Sema, 26600 block: *Block, 26601 src: LazySrcLoc, 26602 operand: Air.Inst.Ref, 26603 ) CompileError!Air.Inst.Ref { 26604 const operand_ty = sema.typeOf(operand); 26605 const ot = operand_ty.zigTypeTag(); 26606 if (ot != .ErrorSet and ot != .ErrorUnion) return Air.Inst.Ref.bool_true; 26607 if (ot == .ErrorSet) return Air.Inst.Ref.bool_false; 26608 assert(ot == .ErrorUnion); 26609 26610 const payload_ty = operand_ty.errorUnionPayload(); 26611 if (payload_ty.zigTypeTag() == .NoReturn) { 26612 return Air.Inst.Ref.bool_false; 26613 } 26614 26615 if (Air.refToIndex(operand)) |operand_inst| { 26616 switch (sema.air_instructions.items(.tag)[operand_inst]) { 26617 .wrap_errunion_payload => return Air.Inst.Ref.bool_true, 26618 .wrap_errunion_err => return Air.Inst.Ref.bool_false, 26619 else => {}, 26620 } 26621 } else if (operand == .undef) { 26622 return sema.addConstUndef(Type.bool); 26623 } else { 26624 // None of the ref tags can be errors. 26625 return Air.Inst.Ref.bool_true; 26626 } 26627 26628 const maybe_operand_val = try sema.resolveMaybeUndefVal(block, src, operand); 26629 26630 // exception if the error union error set is known to be empty, 26631 // we allow the comparison but always make it comptime known. 26632 const set_ty = operand_ty.errorUnionSet(); 26633 switch (set_ty.tag()) { 26634 .anyerror => {}, 26635 .error_set_inferred => blk: { 26636 // If the error set is empty, we must return a comptime true or false. 26637 // However we want to avoid unnecessarily resolving an inferred error set 26638 // in case it is already non-empty. 26639 const ies = set_ty.castTag(.error_set_inferred).?.data; 26640 if (ies.is_anyerror) break :blk; 26641 if (ies.errors.count() != 0) break :blk; 26642 if (maybe_operand_val == null) { 26643 // Try to avoid resolving inferred error set if possible. 26644 if (ies.errors.count() != 0) break :blk; 26645 if (ies.is_anyerror) break :blk; 26646 var it = ies.inferred_error_sets.keyIterator(); 26647 while (it.next()) |other_error_set_ptr| { 26648 const other_ies: *Module.Fn.InferredErrorSet = other_error_set_ptr.*; 26649 if (ies == other_ies) continue; 26650 try sema.resolveInferredErrorSet(block, src, other_ies); 26651 if (other_ies.is_anyerror) { 26652 ies.is_anyerror = true; 26653 ies.is_resolved = true; 26654 break :blk; 26655 } 26656 26657 if (other_ies.errors.count() != 0) break :blk; 26658 } 26659 if (ies.func == sema.owner_func) { 26660 // We're checking the inferred errorset of the current function and none of 26661 // its child inferred error sets contained any errors meaning that any value 26662 // so far with this type can't contain errors either. 26663 return Air.Inst.Ref.bool_true; 26664 } 26665 try sema.resolveInferredErrorSet(block, src, ies); 26666 if (ies.is_anyerror) break :blk; 26667 if (ies.errors.count() == 0) return Air.Inst.Ref.bool_true; 26668 } 26669 }, 26670 else => if (set_ty.errorSetNames().len == 0) return Air.Inst.Ref.bool_true, 26671 } 26672 26673 if (maybe_operand_val) |err_union| { 26674 if (err_union.isUndef()) { 26675 return sema.addConstUndef(Type.bool); 26676 } 26677 if (err_union.getError() == null) { 26678 return Air.Inst.Ref.bool_true; 26679 } else { 26680 return Air.Inst.Ref.bool_false; 26681 } 26682 } 26683 return Air.Inst.Ref.none; 26684 } 26685 26686 fn analyzeIsNonErr( 26687 sema: *Sema, 26688 block: *Block, 26689 src: LazySrcLoc, 26690 operand: Air.Inst.Ref, 26691 ) CompileError!Air.Inst.Ref { 26692 const result = try sema.analyzeIsNonErrComptimeOnly(block, src, operand); 26693 if (result == .none) { 26694 try sema.requireRuntimeBlock(block, src, null); 26695 return block.addUnOp(.is_non_err, operand); 26696 } else { 26697 return result; 26698 } 26699 } 26700 26701 fn analyzePtrIsNonErr( 26702 sema: *Sema, 26703 block: *Block, 26704 src: LazySrcLoc, 26705 operand: Air.Inst.Ref, 26706 ) CompileError!Air.Inst.Ref { 26707 const result = try sema.analyzePtrIsNonErrComptimeOnly(block, src, operand); 26708 if (result == .none) { 26709 try sema.requireRuntimeBlock(block, src, null); 26710 return block.addUnOp(.is_non_err_ptr, operand); 26711 } else { 26712 return result; 26713 } 26714 } 26715 26716 fn analyzeSlice( 26717 sema: *Sema, 26718 block: *Block, 26719 src: LazySrcLoc, 26720 ptr_ptr: Air.Inst.Ref, 26721 uncasted_start: Air.Inst.Ref, 26722 uncasted_end_opt: Air.Inst.Ref, 26723 sentinel_opt: Air.Inst.Ref, 26724 sentinel_src: LazySrcLoc, 26725 ) CompileError!Air.Inst.Ref { 26726 const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = src.node_offset.x }; 26727 const start_src: LazySrcLoc = .{ .node_offset_slice_start = src.node_offset.x }; 26728 const end_src: LazySrcLoc = .{ .node_offset_slice_end = src.node_offset.x }; 26729 // Slice expressions can operate on a variable whose type is an array. This requires 26730 // the slice operand to be a pointer. In the case of a non-array, it will be a double pointer. 26731 const ptr_ptr_ty = sema.typeOf(ptr_ptr); 26732 const target = sema.mod.getTarget(); 26733 const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag()) { 26734 .Pointer => ptr_ptr_ty.elemType(), 26735 else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(sema.mod)}), 26736 }; 26737 const mod = sema.mod; 26738 26739 var array_ty = ptr_ptr_child_ty; 26740 var slice_ty = ptr_ptr_ty; 26741 var ptr_or_slice = ptr_ptr; 26742 var elem_ty: Type = undefined; 26743 var ptr_sentinel: ?Value = null; 26744 switch (ptr_ptr_child_ty.zigTypeTag()) { 26745 .Array => { 26746 ptr_sentinel = ptr_ptr_child_ty.sentinel(); 26747 elem_ty = ptr_ptr_child_ty.childType(); 26748 }, 26749 .Pointer => switch (ptr_ptr_child_ty.ptrSize()) { 26750 .One => { 26751 const double_child_ty = ptr_ptr_child_ty.childType(); 26752 if (double_child_ty.zigTypeTag() == .Array) { 26753 ptr_sentinel = double_child_ty.sentinel(); 26754 ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); 26755 slice_ty = ptr_ptr_child_ty; 26756 array_ty = double_child_ty; 26757 elem_ty = double_child_ty.childType(); 26758 } else { 26759 return sema.fail(block, src, "slice of single-item pointer", .{}); 26760 } 26761 }, 26762 .Many, .C => { 26763 ptr_sentinel = ptr_ptr_child_ty.sentinel(); 26764 ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); 26765 slice_ty = ptr_ptr_child_ty; 26766 array_ty = ptr_ptr_child_ty; 26767 elem_ty = ptr_ptr_child_ty.childType(); 26768 26769 if (ptr_ptr_child_ty.ptrSize() == .C) { 26770 if (try sema.resolveDefinedValue(block, ptr_src, ptr_or_slice)) |ptr_val| { 26771 if (ptr_val.isNull()) { 26772 return sema.fail(block, src, "slice of null pointer", .{}); 26773 } 26774 } 26775 } 26776 }, 26777 .Slice => { 26778 ptr_sentinel = ptr_ptr_child_ty.sentinel(); 26779 ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); 26780 slice_ty = ptr_ptr_child_ty; 26781 array_ty = ptr_ptr_child_ty; 26782 elem_ty = ptr_ptr_child_ty.childType(); 26783 }, 26784 }, 26785 else => return sema.fail(block, src, "slice of non-array type '{}'", .{ptr_ptr_child_ty.fmt(mod)}), 26786 } 26787 26788 const ptr = if (slice_ty.isSlice()) 26789 try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty) 26790 else 26791 ptr_or_slice; 26792 26793 const start = try sema.coerce(block, Type.usize, uncasted_start, start_src); 26794 const new_ptr = try analyzePtrArithmetic(sema, block, src, ptr, start, .ptr_add, ptr_src, start_src); 26795 26796 // true if and only if the end index of the slice, implicitly or explicitly, equals 26797 // the length of the underlying object being sliced. we might learn the length of the 26798 // underlying object because it is an array (which has the length in the type), or 26799 // we might learn of the length because it is a comptime-known slice value. 26800 var end_is_len = uncasted_end_opt == .none; 26801 const end = e: { 26802 if (array_ty.zigTypeTag() == .Array) { 26803 const len_val = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()); 26804 26805 if (!end_is_len) { 26806 const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); 26807 if (try sema.resolveMaybeUndefVal(block, end_src, end)) |end_val| { 26808 const len_s_val = try Value.Tag.int_u64.create( 26809 sema.arena, 26810 array_ty.arrayLenIncludingSentinel(), 26811 ); 26812 if (try sema.compare(block, src, end_val, .gt, len_s_val, Type.usize)) { 26813 const sentinel_label: []const u8 = if (array_ty.sentinel() != null) 26814 " +1 (sentinel)" 26815 else 26816 ""; 26817 26818 return sema.fail( 26819 block, 26820 end_src, 26821 "end index {} out of bounds for array of length {}{s}", 26822 .{ 26823 end_val.fmtValue(Type.usize, mod), 26824 len_val.fmtValue(Type.usize, mod), 26825 sentinel_label, 26826 }, 26827 ); 26828 } 26829 26830 // end_is_len is only true if we are NOT using the sentinel 26831 // length. For sentinel-length, we don't want the type to 26832 // contain the sentinel. 26833 if (end_val.eql(len_val, Type.usize, mod)) { 26834 end_is_len = true; 26835 } 26836 } 26837 break :e end; 26838 } 26839 26840 break :e try sema.addConstant(Type.usize, len_val); 26841 } else if (slice_ty.isSlice()) { 26842 if (!end_is_len) { 26843 const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); 26844 if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { 26845 if (try sema.resolveMaybeUndefVal(block, src, ptr_or_slice)) |slice_val| { 26846 if (slice_val.isUndef()) { 26847 return sema.fail(block, src, "slice of undefined", .{}); 26848 } 26849 const has_sentinel = slice_ty.sentinel() != null; 26850 var int_payload: Value.Payload.U64 = .{ 26851 .base = .{ .tag = .int_u64 }, 26852 .data = slice_val.sliceLen(mod) + @boolToInt(has_sentinel), 26853 }; 26854 const slice_len_val = Value.initPayload(&int_payload.base); 26855 if (try sema.compare(block, src, end_val, .gt, slice_len_val, Type.usize)) { 26856 const sentinel_label: []const u8 = if (has_sentinel) 26857 " +1 (sentinel)" 26858 else 26859 ""; 26860 26861 return sema.fail( 26862 block, 26863 end_src, 26864 "end index {} out of bounds for slice of length {d}{s}", 26865 .{ 26866 end_val.fmtValue(Type.usize, mod), 26867 slice_val.sliceLen(mod), 26868 sentinel_label, 26869 }, 26870 ); 26871 } 26872 26873 // If the slice has a sentinel, we subtract one so that 26874 // end_is_len is only true if it equals the length WITHOUT 26875 // the sentinel, so we don't add a sentinel type. 26876 if (has_sentinel) { 26877 int_payload.data -= 1; 26878 } 26879 26880 if (end_val.eql(slice_len_val, Type.usize, mod)) { 26881 end_is_len = true; 26882 } 26883 } 26884 } 26885 break :e end; 26886 } 26887 break :e try sema.analyzeSliceLen(block, src, ptr_or_slice); 26888 } 26889 if (!end_is_len) { 26890 break :e try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); 26891 } 26892 return sema.fail(block, end_src, "slice of pointer must include end value", .{}); 26893 }; 26894 26895 const sentinel = s: { 26896 if (sentinel_opt != .none) { 26897 const casted = try sema.coerce(block, elem_ty, sentinel_opt, sentinel_src); 26898 break :s try sema.resolveConstValue(block, sentinel_src, casted, "slice sentinel must be comptime known"); 26899 } 26900 // If we are slicing to the end of something that is sentinel-terminated 26901 // then the resulting slice type is also sentinel-terminated. 26902 if (end_is_len) { 26903 if (ptr_sentinel) |sent| { 26904 break :s sent; 26905 } 26906 } 26907 break :s null; 26908 }; 26909 const slice_sentinel = if (sentinel_opt != .none) sentinel else null; 26910 26911 // requirement: start <= end 26912 if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { 26913 if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { 26914 if (try sema.compare(block, src, start_val, .gt, end_val, Type.usize)) { 26915 return sema.fail( 26916 block, 26917 start_src, 26918 "start index {} is larger than end index {}", 26919 .{ 26920 start_val.fmtValue(Type.usize, mod), 26921 end_val.fmtValue(Type.usize, mod), 26922 }, 26923 ); 26924 } 26925 if (try sema.resolveMaybeUndefVal(block, ptr_src, new_ptr)) |ptr_val| sentinel_check: { 26926 const expected_sentinel = sentinel orelse break :sentinel_check; 26927 const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?; 26928 const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?; 26929 const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); 26930 26931 const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod); 26932 const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); 26933 const actual_sentinel = switch (res) { 26934 .runtime_load => break :sentinel_check, 26935 .val => |v| v, 26936 .needed_well_defined => |ty| return sema.fail( 26937 block, 26938 src, 26939 "comptime dereference requires '{}' to have a well-defined layout, but it does not.", 26940 .{ty.fmt(sema.mod)}, 26941 ), 26942 .out_of_bounds => |ty| return sema.fail( 26943 block, 26944 end_src, 26945 "slice end index {d} exceeds bounds of containing decl of type '{}'", 26946 .{ end_int, ty.fmt(sema.mod) }, 26947 ), 26948 }; 26949 26950 if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) { 26951 const msg = msg: { 26952 const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); 26953 errdefer msg.destroy(sema.gpa); 26954 try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ 26955 expected_sentinel.fmtValue(elem_ty, sema.mod), 26956 actual_sentinel.fmtValue(elem_ty, sema.mod), 26957 }); 26958 26959 break :msg msg; 26960 }; 26961 return sema.failWithOwnedErrorMsg(msg); 26962 } 26963 } 26964 } 26965 } 26966 26967 const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src); 26968 const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len); 26969 26970 const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data; 26971 const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize() != .C; 26972 26973 if (opt_new_len_val) |new_len_val| { 26974 const new_len_int = new_len_val.toUnsignedInt(target); 26975 26976 const return_ty = try Type.ptr(sema.arena, mod, .{ 26977 .pointee_type = try Type.array(sema.arena, new_len_int, sentinel, elem_ty, mod), 26978 .sentinel = null, 26979 .@"align" = new_ptr_ty_info.@"align", 26980 .@"addrspace" = new_ptr_ty_info.@"addrspace", 26981 .mutable = new_ptr_ty_info.mutable, 26982 .@"allowzero" = new_allowzero, 26983 .@"volatile" = new_ptr_ty_info.@"volatile", 26984 .size = .One, 26985 }); 26986 26987 const opt_new_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, new_ptr); 26988 const new_ptr_val = opt_new_ptr_val orelse { 26989 const result = try block.addBitCast(return_ty, new_ptr); 26990 if (block.wantSafety()) { 26991 // requirement: slicing C ptr is non-null 26992 if (ptr_ptr_child_ty.isCPtr()) { 26993 const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true); 26994 try sema.addSafetyCheck(block, is_non_null, .unwrap_null); 26995 } 26996 26997 if (slice_ty.isSlice()) { 26998 const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice); 26999 const actual_len = if (slice_ty.sentinel() == null) 27000 slice_len_inst 27001 else 27002 try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src); 27003 27004 const actual_end = if (slice_sentinel != null) 27005 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src) 27006 else 27007 end; 27008 27009 try sema.panicIndexOutOfBounds(block, src, actual_end, actual_len, .cmp_lte); 27010 } 27011 27012 // requirement: result[new_len] == slice_sentinel 27013 try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len); 27014 } 27015 return result; 27016 }; 27017 27018 if (!new_ptr_val.isUndef()) { 27019 return sema.addConstant(return_ty, new_ptr_val); 27020 } 27021 27022 // Special case: @as([]i32, undefined)[x..x] 27023 if (new_len_int == 0) { 27024 return sema.addConstUndef(return_ty); 27025 } 27026 27027 return sema.fail(block, src, "non-zero length slice of undefined pointer", .{}); 27028 } 27029 27030 const return_ty = try Type.ptr(sema.arena, mod, .{ 27031 .pointee_type = elem_ty, 27032 .sentinel = sentinel, 27033 .@"align" = new_ptr_ty_info.@"align", 27034 .@"addrspace" = new_ptr_ty_info.@"addrspace", 27035 .mutable = new_ptr_ty_info.mutable, 27036 .@"allowzero" = new_allowzero, 27037 .@"volatile" = new_ptr_ty_info.@"volatile", 27038 .size = .Slice, 27039 }); 27040 27041 const runtime_src = if ((try sema.resolveMaybeUndefVal(block, ptr_src, ptr_or_slice)) == null) 27042 ptr_src 27043 else if ((try sema.resolveMaybeUndefVal(block, src, start)) == null) 27044 start_src 27045 else 27046 end_src; 27047 27048 try sema.requireRuntimeBlock(block, src, runtime_src); 27049 if (block.wantSafety()) { 27050 // requirement: slicing C ptr is non-null 27051 if (ptr_ptr_child_ty.isCPtr()) { 27052 const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true); 27053 try sema.addSafetyCheck(block, is_non_null, .unwrap_null); 27054 } 27055 27056 // requirement: end <= len 27057 const opt_len_inst = if (array_ty.zigTypeTag() == .Array) 27058 try sema.addIntUnsigned(Type.usize, array_ty.arrayLenIncludingSentinel()) 27059 else if (slice_ty.isSlice()) blk: { 27060 if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { 27061 // we don't need to add one for sentinels because the 27062 // underlying value data includes the sentinel 27063 break :blk try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(mod)); 27064 } 27065 27066 const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice); 27067 if (slice_ty.sentinel() == null) break :blk slice_len_inst; 27068 27069 // we have to add one because slice lengths don't include the sentinel 27070 break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src); 27071 } else null; 27072 if (opt_len_inst) |len_inst| { 27073 const actual_end = if (slice_sentinel != null) 27074 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src) 27075 else 27076 end; 27077 try sema.panicIndexOutOfBounds(block, src, actual_end, len_inst, .cmp_lte); 27078 } 27079 27080 // requirement: start <= end 27081 try sema.panicIndexOutOfBounds(block, src, start, end, .cmp_lte); 27082 } 27083 const result = try block.addInst(.{ 27084 .tag = .slice, 27085 .data = .{ .ty_pl = .{ 27086 .ty = try sema.addType(return_ty), 27087 .payload = try sema.addExtra(Air.Bin{ 27088 .lhs = new_ptr, 27089 .rhs = new_len, 27090 }), 27091 } }, 27092 }); 27093 if (block.wantSafety()) { 27094 // requirement: result[new_len] == slice_sentinel 27095 try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len); 27096 } 27097 return result; 27098 } 27099 27100 /// Asserts that lhs and rhs types are both numeric. 27101 fn cmpNumeric( 27102 sema: *Sema, 27103 block: *Block, 27104 src: LazySrcLoc, 27105 uncasted_lhs: Air.Inst.Ref, 27106 uncasted_rhs: Air.Inst.Ref, 27107 op: std.math.CompareOperator, 27108 lhs_src: LazySrcLoc, 27109 rhs_src: LazySrcLoc, 27110 ) CompileError!Air.Inst.Ref { 27111 const lhs_ty = sema.typeOf(uncasted_lhs); 27112 const rhs_ty = sema.typeOf(uncasted_rhs); 27113 27114 assert(lhs_ty.isNumeric()); 27115 assert(rhs_ty.isNumeric()); 27116 27117 const lhs_ty_tag = lhs_ty.zigTypeTag(); 27118 const rhs_ty_tag = rhs_ty.zigTypeTag(); 27119 const target = sema.mod.getTarget(); 27120 27121 // One exception to heterogeneous comparison: comptime_float needs to 27122 // coerce to fixed-width float. 27123 27124 const lhs = if (lhs_ty_tag == .ComptimeFloat and rhs_ty_tag == .Float) 27125 try sema.coerce(block, rhs_ty, uncasted_lhs, lhs_src) 27126 else 27127 uncasted_lhs; 27128 27129 const rhs = if (lhs_ty_tag == .Float and rhs_ty_tag == .ComptimeFloat) 27130 try sema.coerce(block, lhs_ty, uncasted_rhs, rhs_src) 27131 else 27132 uncasted_rhs; 27133 27134 const runtime_src: LazySrcLoc = src: { 27135 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { 27136 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| { 27137 if (lhs_val.isUndef() or rhs_val.isUndef()) { 27138 return sema.addConstUndef(Type.bool); 27139 } 27140 if (lhs_val.isNan() or rhs_val.isNan()) { 27141 if (op == std.math.CompareOperator.neq) { 27142 return Air.Inst.Ref.bool_true; 27143 } else { 27144 return Air.Inst.Ref.bool_false; 27145 } 27146 } 27147 if (try Value.compareHeteroAdvanced(lhs_val, op, rhs_val, target, sema.kit(block, src))) { 27148 return Air.Inst.Ref.bool_true; 27149 } else { 27150 return Air.Inst.Ref.bool_false; 27151 } 27152 } else { 27153 break :src rhs_src; 27154 } 27155 } else { 27156 break :src lhs_src; 27157 } 27158 }; 27159 27160 // TODO handle comparisons against lazy zero values 27161 // Some values can be compared against zero without being runtime known or without forcing 27162 // a full resolution of their value, for example `@sizeOf(@Frame(function))` is known to 27163 // always be nonzero, and we benefit from not forcing the full evaluation and stack frame layout 27164 // of this function if we don't need to. 27165 try sema.requireRuntimeBlock(block, src, runtime_src); 27166 27167 // For floats, emit a float comparison instruction. 27168 const lhs_is_float = switch (lhs_ty_tag) { 27169 .Float, .ComptimeFloat => true, 27170 else => false, 27171 }; 27172 const rhs_is_float = switch (rhs_ty_tag) { 27173 .Float, .ComptimeFloat => true, 27174 else => false, 27175 }; 27176 27177 if (lhs_is_float and rhs_is_float) { 27178 // Smaller fixed-width floats coerce to larger fixed-width floats. 27179 // comptime_float coerces to fixed-width float. 27180 const dest_ty = x: { 27181 if (lhs_ty_tag == .ComptimeFloat) { 27182 break :x rhs_ty; 27183 } else if (rhs_ty_tag == .ComptimeFloat) { 27184 break :x lhs_ty; 27185 } 27186 if (lhs_ty.floatBits(target) >= rhs_ty.floatBits(target)) { 27187 break :x lhs_ty; 27188 } else { 27189 break :x rhs_ty; 27190 } 27191 }; 27192 const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src); 27193 const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src); 27194 return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs); 27195 } 27196 // For mixed unsigned integer sizes, implicit cast both operands to the larger integer. 27197 // For mixed signed and unsigned integers, implicit cast both operands to a signed 27198 // integer with + 1 bit. 27199 // For mixed floats and integers, extract the integer part from the float, cast that to 27200 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float, 27201 // add/subtract 1. 27202 const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| 27203 (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) 27204 else 27205 (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt()); 27206 const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| 27207 (try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) 27208 else 27209 (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt()); 27210 const dest_int_is_signed = lhs_is_signed or rhs_is_signed; 27211 27212 var dest_float_type: ?Type = null; 27213 27214 var lhs_bits: usize = undefined; 27215 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { 27216 if (lhs_val.isUndef()) 27217 return sema.addConstUndef(Type.bool); 27218 if (!rhs_is_signed) { 27219 switch (lhs_val.orderAgainstZero()) { 27220 .gt => {}, 27221 .eq => switch (op) { // LHS = 0, RHS is unsigned 27222 .lte => return Air.Inst.Ref.bool_true, 27223 .gt => return Air.Inst.Ref.bool_false, 27224 else => {}, 27225 }, 27226 .lt => switch (op) { // LHS < 0, RHS is unsigned 27227 .neq, .lt, .lte => return Air.Inst.Ref.bool_true, 27228 .eq, .gt, .gte => return Air.Inst.Ref.bool_false, 27229 }, 27230 } 27231 } 27232 if (lhs_is_float) { 27233 var bigint_space: Value.BigIntSpace = undefined; 27234 var bigint = try lhs_val.toBigInt(&bigint_space, target).toManaged(sema.gpa); 27235 defer bigint.deinit(); 27236 if (lhs_val.floatHasFraction()) { 27237 switch (op) { 27238 .eq => return Air.Inst.Ref.bool_false, 27239 .neq => return Air.Inst.Ref.bool_true, 27240 else => {}, 27241 } 27242 if (lhs_is_signed) { 27243 try bigint.addScalar(&bigint, -1); 27244 } else { 27245 try bigint.addScalar(&bigint, 1); 27246 } 27247 } 27248 lhs_bits = bigint.toConst().bitCountTwosComp(); 27249 } else { 27250 lhs_bits = lhs_val.intBitCountTwosComp(target); 27251 } 27252 lhs_bits += @boolToInt(!lhs_is_signed and dest_int_is_signed); 27253 } else if (lhs_is_float) { 27254 dest_float_type = lhs_ty; 27255 } else { 27256 const int_info = lhs_ty.intInfo(target); 27257 lhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed); 27258 } 27259 27260 var rhs_bits: usize = undefined; 27261 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| { 27262 if (rhs_val.isUndef()) 27263 return sema.addConstUndef(Type.bool); 27264 if (!lhs_is_signed) { 27265 switch (rhs_val.orderAgainstZero()) { 27266 .gt => {}, 27267 .eq => switch (op) { // RHS = 0, LHS is unsigned 27268 .gte => return Air.Inst.Ref.bool_true, 27269 .lt => return Air.Inst.Ref.bool_false, 27270 else => {}, 27271 }, 27272 .lt => switch (op) { // RHS < 0, LHS is unsigned 27273 .neq, .gt, .gte => return Air.Inst.Ref.bool_true, 27274 .eq, .lt, .lte => return Air.Inst.Ref.bool_false, 27275 }, 27276 } 27277 } 27278 if (rhs_is_float) { 27279 var bigint_space: Value.BigIntSpace = undefined; 27280 var bigint = try rhs_val.toBigInt(&bigint_space, target).toManaged(sema.gpa); 27281 defer bigint.deinit(); 27282 if (rhs_val.floatHasFraction()) { 27283 switch (op) { 27284 .eq => return Air.Inst.Ref.bool_false, 27285 .neq => return Air.Inst.Ref.bool_true, 27286 else => {}, 27287 } 27288 if (rhs_is_signed) { 27289 try bigint.addScalar(&bigint, -1); 27290 } else { 27291 try bigint.addScalar(&bigint, 1); 27292 } 27293 } 27294 rhs_bits = bigint.toConst().bitCountTwosComp(); 27295 } else { 27296 rhs_bits = rhs_val.intBitCountTwosComp(target); 27297 } 27298 rhs_bits += @boolToInt(!rhs_is_signed and dest_int_is_signed); 27299 } else if (rhs_is_float) { 27300 dest_float_type = rhs_ty; 27301 } else { 27302 const int_info = rhs_ty.intInfo(target); 27303 rhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed); 27304 } 27305 27306 const dest_ty = if (dest_float_type) |ft| ft else blk: { 27307 const max_bits = std.math.max(lhs_bits, rhs_bits); 27308 const casted_bits = std.math.cast(u16, max_bits) orelse return sema.fail(block, src, "{d} exceeds maximum integer bit count", .{max_bits}); 27309 const signedness: std.builtin.Signedness = if (dest_int_is_signed) .signed else .unsigned; 27310 break :blk try Module.makeIntType(sema.arena, signedness, casted_bits); 27311 }; 27312 const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src); 27313 const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src); 27314 27315 return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs); 27316 } 27317 27318 /// Asserts that lhs and rhs types are both vectors. 27319 fn cmpVector( 27320 sema: *Sema, 27321 block: *Block, 27322 src: LazySrcLoc, 27323 lhs: Air.Inst.Ref, 27324 rhs: Air.Inst.Ref, 27325 op: std.math.CompareOperator, 27326 lhs_src: LazySrcLoc, 27327 rhs_src: LazySrcLoc, 27328 ) CompileError!Air.Inst.Ref { 27329 const lhs_ty = sema.typeOf(lhs); 27330 const rhs_ty = sema.typeOf(rhs); 27331 assert(lhs_ty.zigTypeTag() == .Vector); 27332 assert(rhs_ty.zigTypeTag() == .Vector); 27333 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); 27334 27335 const result_ty = try Type.vector(sema.arena, lhs_ty.vectorLen(), Type.@"bool"); 27336 27337 const runtime_src: LazySrcLoc = src: { 27338 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { 27339 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| { 27340 if (lhs_val.isUndef() or rhs_val.isUndef()) { 27341 return sema.addConstUndef(result_ty); 27342 } 27343 const cmp_val = try sema.compareVector(block, src, lhs_val, op, rhs_val, lhs_ty); 27344 return sema.addConstant(result_ty, cmp_val); 27345 } else { 27346 break :src rhs_src; 27347 } 27348 } else { 27349 break :src lhs_src; 27350 } 27351 }; 27352 27353 try sema.requireRuntimeBlock(block, src, runtime_src); 27354 const result_ty_inst = try sema.addType(result_ty); 27355 return block.addCmpVector(lhs, rhs, op, result_ty_inst); 27356 } 27357 27358 fn wrapOptional( 27359 sema: *Sema, 27360 block: *Block, 27361 dest_ty: Type, 27362 inst: Air.Inst.Ref, 27363 inst_src: LazySrcLoc, 27364 ) !Air.Inst.Ref { 27365 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| { 27366 return sema.addConstant(dest_ty, try Value.Tag.opt_payload.create(sema.arena, val)); 27367 } 27368 27369 try sema.requireRuntimeBlock(block, inst_src, null); 27370 return block.addTyOp(.wrap_optional, dest_ty, inst); 27371 } 27372 27373 fn wrapErrorUnionPayload( 27374 sema: *Sema, 27375 block: *Block, 27376 dest_ty: Type, 27377 inst: Air.Inst.Ref, 27378 inst_src: LazySrcLoc, 27379 ) !Air.Inst.Ref { 27380 const dest_payload_ty = dest_ty.errorUnionPayload(); 27381 const coerced = try sema.coerceExtra(block, dest_payload_ty, inst, inst_src, .{ .report_err = false }); 27382 if (try sema.resolveMaybeUndefVal(block, inst_src, coerced)) |val| { 27383 return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val)); 27384 } 27385 try sema.requireRuntimeBlock(block, inst_src, null); 27386 try sema.queueFullTypeResolution(dest_payload_ty); 27387 return block.addTyOp(.wrap_errunion_payload, dest_ty, coerced); 27388 } 27389 27390 fn wrapErrorUnionSet( 27391 sema: *Sema, 27392 block: *Block, 27393 dest_ty: Type, 27394 inst: Air.Inst.Ref, 27395 inst_src: LazySrcLoc, 27396 ) !Air.Inst.Ref { 27397 const inst_ty = sema.typeOf(inst); 27398 const dest_err_set_ty = dest_ty.errorUnionSet(); 27399 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| { 27400 switch (dest_err_set_ty.tag()) { 27401 .anyerror => {}, 27402 .error_set_single => ok: { 27403 const expected_name = val.castTag(.@"error").?.data.name; 27404 const n = dest_err_set_ty.castTag(.error_set_single).?.data; 27405 if (mem.eql(u8, expected_name, n)) break :ok; 27406 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); 27407 }, 27408 .error_set => { 27409 const expected_name = val.castTag(.@"error").?.data.name; 27410 const error_set = dest_err_set_ty.castTag(.error_set).?.data; 27411 if (!error_set.names.contains(expected_name)) { 27412 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); 27413 } 27414 }, 27415 .error_set_inferred => ok: { 27416 const expected_name = val.castTag(.@"error").?.data.name; 27417 const ies = dest_err_set_ty.castTag(.error_set_inferred).?.data; 27418 27419 // We carefully do this in an order that avoids unnecessarily 27420 // resolving the destination error set type. 27421 if (ies.is_anyerror) break :ok; 27422 if (ies.errors.contains(expected_name)) break :ok; 27423 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) { 27424 break :ok; 27425 } 27426 27427 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); 27428 }, 27429 .error_set_merged => { 27430 const expected_name = val.castTag(.@"error").?.data.name; 27431 const error_set = dest_err_set_ty.castTag(.error_set_merged).?.data; 27432 if (!error_set.contains(expected_name)) { 27433 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); 27434 } 27435 }, 27436 else => unreachable, 27437 } 27438 return sema.addConstant(dest_ty, val); 27439 } 27440 27441 try sema.requireRuntimeBlock(block, inst_src, null); 27442 const coerced = try sema.coerce(block, dest_err_set_ty, inst, inst_src); 27443 return block.addTyOp(.wrap_errunion_err, dest_ty, coerced); 27444 } 27445 27446 fn unionToTag( 27447 sema: *Sema, 27448 block: *Block, 27449 enum_ty: Type, 27450 un: Air.Inst.Ref, 27451 un_src: LazySrcLoc, 27452 ) !Air.Inst.Ref { 27453 if ((try sema.typeHasOnePossibleValue(block, un_src, enum_ty))) |opv| { 27454 return sema.addConstant(enum_ty, opv); 27455 } 27456 if (try sema.resolveMaybeUndefVal(block, un_src, un)) |un_val| { 27457 return sema.addConstant(enum_ty, un_val.unionTag()); 27458 } 27459 try sema.requireRuntimeBlock(block, un_src, null); 27460 return block.addTyOp(.get_union_tag, enum_ty, un); 27461 } 27462 27463 fn resolvePeerTypes( 27464 sema: *Sema, 27465 block: *Block, 27466 src: LazySrcLoc, 27467 instructions: []const Air.Inst.Ref, 27468 candidate_srcs: Module.PeerTypeCandidateSrc, 27469 ) !Type { 27470 switch (instructions.len) { 27471 0 => return Type.initTag(.noreturn), 27472 1 => return sema.typeOf(instructions[0]), 27473 else => {}, 27474 } 27475 27476 const target = sema.mod.getTarget(); 27477 27478 var chosen = instructions[0]; 27479 // If this is non-null then it does the following thing, depending on the chosen zigTypeTag(). 27480 // * ErrorSet: this is an override 27481 // * ErrorUnion: this is an override of the error set only 27482 // * other: at the end we make an ErrorUnion with the other thing and this 27483 var err_set_ty: ?Type = null; 27484 var any_are_null = false; 27485 var seen_const = false; 27486 var convert_to_slice = false; 27487 var chosen_i: usize = 0; 27488 for (instructions[1..]) |candidate, candidate_i| { 27489 const candidate_ty = sema.typeOf(candidate); 27490 const chosen_ty = sema.typeOf(chosen); 27491 27492 const candidate_ty_tag = try candidate_ty.zigTypeTagOrPoison(); 27493 const chosen_ty_tag = try chosen_ty.zigTypeTagOrPoison(); 27494 27495 if (candidate_ty.eql(chosen_ty, sema.mod)) 27496 continue; 27497 27498 switch (candidate_ty_tag) { 27499 .NoReturn, .Undefined => continue, 27500 27501 .Null => { 27502 any_are_null = true; 27503 continue; 27504 }, 27505 27506 .Int => switch (chosen_ty_tag) { 27507 .ComptimeInt => { 27508 chosen = candidate; 27509 chosen_i = candidate_i + 1; 27510 continue; 27511 }, 27512 .Int => { 27513 const chosen_info = chosen_ty.intInfo(target); 27514 const candidate_info = candidate_ty.intInfo(target); 27515 27516 if (chosen_info.bits < candidate_info.bits) { 27517 chosen = candidate; 27518 chosen_i = candidate_i + 1; 27519 } 27520 continue; 27521 }, 27522 .Pointer => if (chosen_ty.ptrSize() == .C) continue, 27523 else => {}, 27524 }, 27525 .ComptimeInt => switch (chosen_ty_tag) { 27526 .Int, .Float, .ComptimeFloat => continue, 27527 .Pointer => if (chosen_ty.ptrSize() == .C) continue, 27528 else => {}, 27529 }, 27530 .Float => switch (chosen_ty_tag) { 27531 .Float => { 27532 if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) { 27533 chosen = candidate; 27534 chosen_i = candidate_i + 1; 27535 } 27536 continue; 27537 }, 27538 .ComptimeFloat, .ComptimeInt => { 27539 chosen = candidate; 27540 chosen_i = candidate_i + 1; 27541 continue; 27542 }, 27543 else => {}, 27544 }, 27545 .ComptimeFloat => switch (chosen_ty_tag) { 27546 .Float => continue, 27547 .ComptimeInt => { 27548 chosen = candidate; 27549 chosen_i = candidate_i + 1; 27550 continue; 27551 }, 27552 else => {}, 27553 }, 27554 .Enum => switch (chosen_ty_tag) { 27555 .EnumLiteral => { 27556 chosen = candidate; 27557 chosen_i = candidate_i + 1; 27558 continue; 27559 }, 27560 .Union => continue, 27561 else => {}, 27562 }, 27563 .EnumLiteral => switch (chosen_ty_tag) { 27564 .Enum, .Union => continue, 27565 else => {}, 27566 }, 27567 .Union => switch (chosen_ty_tag) { 27568 .Enum, .EnumLiteral => { 27569 chosen = candidate; 27570 chosen_i = candidate_i + 1; 27571 continue; 27572 }, 27573 else => {}, 27574 }, 27575 .ErrorSet => switch (chosen_ty_tag) { 27576 .ErrorSet => { 27577 // If chosen is superset of candidate, keep it. 27578 // If candidate is superset of chosen, switch it. 27579 // If neither is a superset, merge errors. 27580 const chosen_set_ty = err_set_ty orelse chosen_ty; 27581 27582 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) { 27583 continue; 27584 } 27585 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) { 27586 err_set_ty = null; 27587 chosen = candidate; 27588 chosen_i = candidate_i + 1; 27589 continue; 27590 } 27591 27592 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty); 27593 continue; 27594 }, 27595 .ErrorUnion => { 27596 const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(); 27597 27598 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) { 27599 continue; 27600 } 27601 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) { 27602 err_set_ty = candidate_ty; 27603 continue; 27604 } 27605 27606 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty); 27607 continue; 27608 }, 27609 else => { 27610 if (err_set_ty) |chosen_set_ty| { 27611 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) { 27612 continue; 27613 } 27614 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) { 27615 err_set_ty = candidate_ty; 27616 continue; 27617 } 27618 27619 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty); 27620 continue; 27621 } else { 27622 err_set_ty = candidate_ty; 27623 continue; 27624 } 27625 }, 27626 }, 27627 .ErrorUnion => switch (chosen_ty_tag) { 27628 .ErrorSet => { 27629 const chosen_set_ty = err_set_ty orelse chosen_ty; 27630 const candidate_set_ty = candidate_ty.errorUnionSet(); 27631 27632 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { 27633 err_set_ty = chosen_set_ty; 27634 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { 27635 err_set_ty = null; 27636 } else { 27637 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty); 27638 } 27639 chosen = candidate; 27640 chosen_i = candidate_i + 1; 27641 continue; 27642 }, 27643 27644 .ErrorUnion => { 27645 const chosen_payload_ty = chosen_ty.errorUnionPayload(); 27646 const candidate_payload_ty = candidate_ty.errorUnionPayload(); 27647 27648 const coerce_chosen = (try sema.coerceInMemoryAllowed(block, chosen_payload_ty, candidate_payload_ty, false, target, src, src)) == .ok; 27649 const coerce_candidate = (try sema.coerceInMemoryAllowed(block, candidate_payload_ty, chosen_payload_ty, false, target, src, src)) == .ok; 27650 27651 if (coerce_chosen or coerce_candidate) { 27652 // If we can coerce to the candidate, we switch to that 27653 // type. This is the same logic as the bare (non-union) 27654 // coercion check we do at the top of this func. 27655 if (coerce_candidate) { 27656 chosen = candidate; 27657 chosen_i = candidate_i + 1; 27658 } 27659 27660 const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(); 27661 const candidate_set_ty = candidate_ty.errorUnionSet(); 27662 27663 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { 27664 err_set_ty = chosen_set_ty; 27665 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { 27666 err_set_ty = candidate_set_ty; 27667 } else { 27668 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty); 27669 } 27670 continue; 27671 } 27672 }, 27673 27674 else => { 27675 if (err_set_ty) |chosen_set_ty| { 27676 const candidate_set_ty = candidate_ty.errorUnionSet(); 27677 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { 27678 err_set_ty = chosen_set_ty; 27679 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { 27680 err_set_ty = null; 27681 } else { 27682 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty); 27683 } 27684 } 27685 seen_const = seen_const or chosen_ty.isConstPtr(); 27686 chosen = candidate; 27687 chosen_i = candidate_i + 1; 27688 continue; 27689 }, 27690 }, 27691 .Pointer => { 27692 const cand_info = candidate_ty.ptrInfo().data; 27693 switch (chosen_ty_tag) { 27694 .Pointer => { 27695 const chosen_info = chosen_ty.ptrInfo().data; 27696 27697 seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; 27698 27699 // *[N]T to [*]T 27700 // *[N]T to []T 27701 if ((cand_info.size == .Many or cand_info.size == .Slice) and 27702 chosen_info.size == .One and 27703 chosen_info.pointee_type.zigTypeTag() == .Array) 27704 { 27705 // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T` 27706 convert_to_slice = false; 27707 chosen = candidate; 27708 chosen_i = candidate_i + 1; 27709 continue; 27710 } 27711 if (cand_info.size == .One and 27712 cand_info.pointee_type.zigTypeTag() == .Array and 27713 (chosen_info.size == .Many or chosen_info.size == .Slice)) 27714 { 27715 // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T` 27716 convert_to_slice = false; 27717 continue; 27718 } 27719 27720 // *[N]T and *[M]T 27721 // Verify both are single-pointers to arrays. 27722 // Keep the one whose element type can be coerced into. 27723 if (chosen_info.size == .One and 27724 cand_info.size == .One and 27725 chosen_info.pointee_type.zigTypeTag() == .Array and 27726 cand_info.pointee_type.zigTypeTag() == .Array) 27727 { 27728 const chosen_elem_ty = chosen_info.pointee_type.childType(); 27729 const cand_elem_ty = cand_info.pointee_type.childType(); 27730 27731 const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_elem_ty, cand_elem_ty, chosen_info.mutable, target, src, src); 27732 if (chosen_ok) { 27733 convert_to_slice = true; 27734 continue; 27735 } 27736 27737 const cand_ok = .ok == try sema.coerceInMemoryAllowed(block, cand_elem_ty, chosen_elem_ty, cand_info.mutable, target, src, src); 27738 if (cand_ok) { 27739 convert_to_slice = true; 27740 chosen = candidate; 27741 chosen_i = candidate_i + 1; 27742 continue; 27743 } 27744 27745 // They're both bad. Report error. 27746 // In the future we probably want to use the 27747 // coerceInMemoryAllowed error reporting mechanism, 27748 // however, for now we just fall through for the 27749 // "incompatible types" error below. 27750 } 27751 27752 // [*c]T and any other pointer size 27753 // Whichever element type can coerce to the other one, is 27754 // the one we will keep. If they're both OK then we keep the 27755 // C pointer since it matches both single and many pointers. 27756 if (cand_info.size == .C or chosen_info.size == .C) { 27757 const cand_ok = .ok == try sema.coerceInMemoryAllowed(block, cand_info.pointee_type, chosen_info.pointee_type, cand_info.mutable, target, src, src); 27758 const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_info.pointee_type, cand_info.pointee_type, chosen_info.mutable, target, src, src); 27759 27760 if (cand_ok) { 27761 if (chosen_ok) { 27762 if (chosen_info.size == .C) { 27763 continue; 27764 } else { 27765 chosen = candidate; 27766 chosen_i = candidate_i + 1; 27767 continue; 27768 } 27769 } else { 27770 chosen = candidate; 27771 chosen_i = candidate_i + 1; 27772 continue; 27773 } 27774 } else { 27775 if (chosen_ok) { 27776 continue; 27777 } else { 27778 // They're both bad. Report error. 27779 // In the future we probably want to use the 27780 // coerceInMemoryAllowed error reporting mechanism, 27781 // however, for now we just fall through for the 27782 // "incompatible types" error below. 27783 } 27784 } 27785 } 27786 }, 27787 .Int, .ComptimeInt => { 27788 if (cand_info.size == .C) { 27789 chosen = candidate; 27790 chosen_i = candidate_i + 1; 27791 continue; 27792 } 27793 }, 27794 .Optional => { 27795 var opt_child_buf: Type.Payload.ElemType = undefined; 27796 const chosen_ptr_ty = chosen_ty.optionalChild(&opt_child_buf); 27797 if (chosen_ptr_ty.zigTypeTag() == .Pointer) { 27798 const chosen_info = chosen_ptr_ty.ptrInfo().data; 27799 27800 seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; 27801 27802 // *[N]T to ?![*]T 27803 // *[N]T to ?![]T 27804 if (cand_info.size == .One and 27805 cand_info.pointee_type.zigTypeTag() == .Array and 27806 (chosen_info.size == .Many or chosen_info.size == .Slice)) 27807 { 27808 continue; 27809 } 27810 } 27811 }, 27812 .ErrorUnion => { 27813 const chosen_ptr_ty = chosen_ty.errorUnionPayload(); 27814 if (chosen_ptr_ty.zigTypeTag() == .Pointer) { 27815 const chosen_info = chosen_ptr_ty.ptrInfo().data; 27816 27817 seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; 27818 27819 // *[N]T to E![*]T 27820 // *[N]T to E![]T 27821 if (cand_info.size == .One and 27822 cand_info.pointee_type.zigTypeTag() == .Array and 27823 (chosen_info.size == .Many or chosen_info.size == .Slice)) 27824 { 27825 continue; 27826 } 27827 } 27828 }, 27829 else => {}, 27830 } 27831 }, 27832 .Optional => { 27833 var opt_child_buf: Type.Payload.ElemType = undefined; 27834 const opt_child_ty = candidate_ty.optionalChild(&opt_child_buf); 27835 if ((try sema.coerceInMemoryAllowed(block, chosen_ty, opt_child_ty, false, target, src, src)) == .ok) { 27836 seen_const = seen_const or opt_child_ty.isConstPtr(); 27837 any_are_null = true; 27838 continue; 27839 } 27840 27841 seen_const = seen_const or chosen_ty.isConstPtr(); 27842 any_are_null = false; 27843 chosen = candidate; 27844 chosen_i = candidate_i + 1; 27845 continue; 27846 }, 27847 .Vector => switch (chosen_ty_tag) { 27848 .Array => { 27849 chosen = candidate; 27850 chosen_i = candidate_i + 1; 27851 continue; 27852 }, 27853 else => {}, 27854 }, 27855 .Array => switch (chosen_ty_tag) { 27856 .Vector => continue, 27857 else => {}, 27858 }, 27859 else => {}, 27860 } 27861 27862 switch (chosen_ty_tag) { 27863 .NoReturn, .Undefined => { 27864 chosen = candidate; 27865 chosen_i = candidate_i + 1; 27866 continue; 27867 }, 27868 .Null => { 27869 any_are_null = true; 27870 chosen = candidate; 27871 chosen_i = candidate_i + 1; 27872 continue; 27873 }, 27874 .Optional => { 27875 var opt_child_buf: Type.Payload.ElemType = undefined; 27876 const opt_child_ty = chosen_ty.optionalChild(&opt_child_buf); 27877 if ((try sema.coerceInMemoryAllowed(block, opt_child_ty, candidate_ty, false, target, src, src)) == .ok) { 27878 continue; 27879 } 27880 if ((try sema.coerceInMemoryAllowed(block, candidate_ty, opt_child_ty, false, target, src, src)) == .ok) { 27881 any_are_null = true; 27882 chosen = candidate; 27883 chosen_i = candidate_i + 1; 27884 continue; 27885 } 27886 }, 27887 .ErrorUnion => { 27888 const payload_ty = chosen_ty.errorUnionPayload(); 27889 if ((try sema.coerceInMemoryAllowed(block, payload_ty, candidate_ty, false, target, src, src)) == .ok) { 27890 continue; 27891 } 27892 }, 27893 else => {}, 27894 } 27895 27896 // If the candidate can coerce into our chosen type, we're done. 27897 // If the chosen type can coerce into the candidate, use that. 27898 if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) { 27899 continue; 27900 } 27901 if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) { 27902 chosen = candidate; 27903 chosen_i = candidate_i + 1; 27904 continue; 27905 } 27906 27907 // At this point, we hit a compile error. We need to recover 27908 // the source locations. 27909 const chosen_src = candidate_srcs.resolve( 27910 sema.gpa, 27911 sema.mod.declPtr(block.src_decl), 27912 chosen_i, 27913 ); 27914 const candidate_src = candidate_srcs.resolve( 27915 sema.gpa, 27916 sema.mod.declPtr(block.src_decl), 27917 candidate_i + 1, 27918 ); 27919 27920 const msg = msg: { 27921 const msg = try sema.errMsg(block, src, "incompatible types: '{}' and '{}'", .{ 27922 chosen_ty.fmt(sema.mod), 27923 candidate_ty.fmt(sema.mod), 27924 }); 27925 errdefer msg.destroy(sema.gpa); 27926 27927 if (chosen_src) |src_loc| 27928 try sema.errNote(block, src_loc, msg, "type '{}' here", .{chosen_ty.fmt(sema.mod)}); 27929 27930 if (candidate_src) |src_loc| 27931 try sema.errNote(block, src_loc, msg, "type '{}' here", .{candidate_ty.fmt(sema.mod)}); 27932 27933 break :msg msg; 27934 }; 27935 return sema.failWithOwnedErrorMsg(msg); 27936 } 27937 27938 const chosen_ty = sema.typeOf(chosen); 27939 27940 if (convert_to_slice) { 27941 // turn *[N]T => []T 27942 const chosen_child_ty = chosen_ty.childType(); 27943 var info = chosen_ty.ptrInfo(); 27944 info.data.sentinel = chosen_child_ty.sentinel(); 27945 info.data.size = .Slice; 27946 info.data.mutable = !(seen_const or chosen_child_ty.isConstPtr()); 27947 info.data.pointee_type = chosen_child_ty.elemType2(); 27948 27949 const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data); 27950 const opt_ptr_ty = if (any_are_null) 27951 try Type.optional(sema.arena, new_ptr_ty) 27952 else 27953 new_ptr_ty; 27954 const set_ty = err_set_ty orelse return opt_ptr_ty; 27955 return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, sema.mod); 27956 } 27957 27958 if (seen_const) { 27959 // turn []T => []const T 27960 switch (chosen_ty.zigTypeTag()) { 27961 .ErrorUnion => { 27962 const ptr_ty = chosen_ty.errorUnionPayload(); 27963 var info = ptr_ty.ptrInfo(); 27964 info.data.mutable = false; 27965 const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data); 27966 const opt_ptr_ty = if (any_are_null) 27967 try Type.optional(sema.arena, new_ptr_ty) 27968 else 27969 new_ptr_ty; 27970 const set_ty = err_set_ty orelse chosen_ty.errorUnionSet(); 27971 return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, sema.mod); 27972 }, 27973 .Pointer => { 27974 var info = chosen_ty.ptrInfo(); 27975 info.data.mutable = false; 27976 const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data); 27977 const opt_ptr_ty = if (any_are_null) 27978 try Type.optional(sema.arena, new_ptr_ty) 27979 else 27980 new_ptr_ty; 27981 const set_ty = err_set_ty orelse return opt_ptr_ty; 27982 return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, sema.mod); 27983 }, 27984 else => return chosen_ty, 27985 } 27986 } 27987 27988 if (any_are_null) { 27989 const opt_ty = switch (chosen_ty.zigTypeTag()) { 27990 .Null, .Optional => chosen_ty, 27991 else => try Type.optional(sema.arena, chosen_ty), 27992 }; 27993 const set_ty = err_set_ty orelse return opt_ty; 27994 return try Type.errorUnion(sema.arena, set_ty, opt_ty, sema.mod); 27995 } 27996 27997 if (err_set_ty) |ty| switch (chosen_ty.zigTypeTag()) { 27998 .ErrorSet => return ty, 27999 .ErrorUnion => { 28000 const payload_ty = chosen_ty.errorUnionPayload(); 28001 return try Type.errorUnion(sema.arena, ty, payload_ty, sema.mod); 28002 }, 28003 else => return try Type.errorUnion(sema.arena, ty, chosen_ty, sema.mod), 28004 }; 28005 28006 return chosen_ty; 28007 } 28008 28009 pub fn resolveFnTypes( 28010 sema: *Sema, 28011 block: *Block, 28012 src: LazySrcLoc, 28013 fn_info: Type.Payload.Function.Data, 28014 ) CompileError!void { 28015 try sema.resolveTypeFully(block, src, fn_info.return_type); 28016 28017 if (sema.mod.comp.bin_file.options.error_return_tracing and fn_info.return_type.isError()) { 28018 // Ensure the type exists so that backends can assume that. 28019 _ = try sema.getBuiltinType(block, src, "StackTrace"); 28020 } 28021 28022 for (fn_info.param_types) |param_ty| { 28023 try sema.resolveTypeFully(block, src, param_ty); 28024 } 28025 } 28026 28027 /// Make it so that calling hash() and eql() on `val` will not assert due 28028 /// to a type not having its layout resolved. 28029 fn resolveLazyValue( 28030 sema: *Sema, 28031 block: *Block, 28032 src: LazySrcLoc, 28033 val: Value, 28034 ) CompileError!void { 28035 switch (val.tag()) { 28036 .lazy_align => { 28037 const ty = val.castTag(.lazy_align).?.data; 28038 return sema.resolveTypeLayout(block, src, ty); 28039 }, 28040 .lazy_size => { 28041 const ty = val.castTag(.lazy_size).?.data; 28042 return sema.resolveTypeLayout(block, src, ty); 28043 }, 28044 else => return, 28045 } 28046 } 28047 28048 pub fn resolveTypeLayout( 28049 sema: *Sema, 28050 block: *Block, 28051 src: LazySrcLoc, 28052 ty: Type, 28053 ) CompileError!void { 28054 switch (ty.zigTypeTag()) { 28055 .Struct => return sema.resolveStructLayout(block, src, ty), 28056 .Union => return sema.resolveUnionLayout(block, src, ty), 28057 .Array => { 28058 if (ty.arrayLenIncludingSentinel() == 0) return; 28059 const elem_ty = ty.childType(); 28060 return sema.resolveTypeLayout(block, src, elem_ty); 28061 }, 28062 .Optional => { 28063 var buf: Type.Payload.ElemType = undefined; 28064 const payload_ty = ty.optionalChild(&buf); 28065 // In case of querying the ABI alignment of this optional, we will ask 28066 // for hasRuntimeBits() of the payload type, so we need "requires comptime" 28067 // to be known already before this function returns. 28068 _ = try sema.typeRequiresComptime(payload_ty); 28069 return sema.resolveTypeLayout(block, src, payload_ty); 28070 }, 28071 .ErrorUnion => { 28072 const payload_ty = ty.errorUnionPayload(); 28073 return sema.resolveTypeLayout(block, src, payload_ty); 28074 }, 28075 else => {}, 28076 } 28077 } 28078 28079 fn resolveStructLayout( 28080 sema: *Sema, 28081 block: *Block, 28082 src: LazySrcLoc, 28083 ty: Type, 28084 ) CompileError!void { 28085 const resolved_ty = try sema.resolveTypeFields(block, src, ty); 28086 if (resolved_ty.castTag(.@"struct")) |payload| { 28087 const struct_obj = payload.data; 28088 switch (struct_obj.status) { 28089 .none, .have_field_types => {}, 28090 .field_types_wip, .layout_wip => { 28091 const msg = try Module.ErrorMsg.create( 28092 sema.gpa, 28093 struct_obj.srcLoc(sema.mod), 28094 "struct '{}' depends on itself", 28095 .{ty.fmt(sema.mod)}, 28096 ); 28097 return sema.failWithOwnedErrorMsg(msg); 28098 }, 28099 .have_layout, .fully_resolved_wip, .fully_resolved => return, 28100 } 28101 struct_obj.status = .layout_wip; 28102 for (struct_obj.fields.values()) |field, i| { 28103 sema.resolveTypeLayout(block, src, field.ty) catch |err| switch (err) { 28104 error.AnalysisFail => { 28105 const msg = sema.err orelse return err; 28106 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); 28107 return err; 28108 }, 28109 else => return err, 28110 }; 28111 } 28112 28113 if (struct_obj.layout == .Packed) { 28114 try semaBackingIntType(sema.mod, struct_obj); 28115 } 28116 28117 struct_obj.status = .have_layout; 28118 28119 // In case of querying the ABI alignment of this struct, we will ask 28120 // for hasRuntimeBits() of each field, so we need "requires comptime" 28121 // to be known already before this function returns. 28122 for (struct_obj.fields.values()) |field, i| { 28123 _ = sema.typeRequiresComptime(field.ty) catch |err| switch (err) { 28124 error.AnalysisFail => { 28125 const msg = sema.err orelse return err; 28126 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); 28127 return err; 28128 }, 28129 else => return err, 28130 }; 28131 } 28132 } 28133 // otherwise it's a tuple; no need to resolve anything 28134 } 28135 28136 fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void { 28137 const gpa = mod.gpa; 28138 const target = mod.getTarget(); 28139 28140 var fields_bit_sum: u64 = 0; 28141 for (struct_obj.fields.values()) |field| { 28142 fields_bit_sum += field.ty.bitSize(target); 28143 } 28144 28145 const decl_index = struct_obj.owner_decl; 28146 const decl = mod.declPtr(decl_index); 28147 var decl_arena = decl.value_arena.?.promote(gpa); 28148 defer decl.value_arena.?.* = decl_arena.state; 28149 const decl_arena_allocator = decl_arena.allocator(); 28150 28151 const zir = struct_obj.namespace.file_scope.zir; 28152 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; 28153 assert(extended.opcode == .struct_decl); 28154 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); 28155 28156 if (small.has_backing_int) { 28157 var extra_index: usize = extended.operand; 28158 extra_index += @boolToInt(small.has_src_node); 28159 extra_index += @boolToInt(small.has_fields_len); 28160 extra_index += @boolToInt(small.has_decls_len); 28161 28162 const backing_int_body_len = zir.extra[extra_index]; 28163 extra_index += 1; 28164 28165 var analysis_arena = std.heap.ArenaAllocator.init(gpa); 28166 defer analysis_arena.deinit(); 28167 28168 var sema: Sema = .{ 28169 .mod = mod, 28170 .gpa = gpa, 28171 .arena = analysis_arena.allocator(), 28172 .perm_arena = decl_arena_allocator, 28173 .code = zir, 28174 .owner_decl = decl, 28175 .owner_decl_index = decl_index, 28176 .func = null, 28177 .fn_ret_ty = Type.void, 28178 .owner_func = null, 28179 }; 28180 defer sema.deinit(); 28181 28182 var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope); 28183 defer wip_captures.deinit(); 28184 28185 var block: Block = .{ 28186 .parent = null, 28187 .sema = &sema, 28188 .src_decl = decl_index, 28189 .namespace = &struct_obj.namespace, 28190 .wip_capture_scope = wip_captures.scope, 28191 .instructions = .{}, 28192 .inlining = null, 28193 .is_comptime = true, 28194 }; 28195 defer { 28196 assert(block.instructions.items.len == 0); 28197 block.params.deinit(gpa); 28198 } 28199 28200 const backing_int_src: LazySrcLoc = .{ .node_offset_container_tag = 0 }; 28201 const backing_int_ty = blk: { 28202 if (backing_int_body_len == 0) { 28203 const backing_int_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 28204 break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref); 28205 } else { 28206 const body = zir.extra[extra_index..][0..backing_int_body_len]; 28207 const ty_ref = try sema.resolveBody(&block, body, struct_obj.zir_index); 28208 break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref); 28209 } 28210 }; 28211 28212 try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum); 28213 struct_obj.backing_int_ty = try backing_int_ty.copy(decl_arena_allocator); 28214 } else { 28215 var buf: Type.Payload.Bits = .{ 28216 .base = .{ .tag = .int_unsigned }, 28217 .data = @intCast(u16, fields_bit_sum), 28218 }; 28219 struct_obj.backing_int_ty = try Type.initPayload(&buf.base).copy(decl_arena_allocator); 28220 } 28221 } 28222 28223 fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void { 28224 const target = sema.mod.getTarget(); 28225 28226 if (!backing_int_ty.isInt()) { 28227 return sema.fail(block, src, "expected backing integer type, found '{}'", .{backing_int_ty.fmt(sema.mod)}); 28228 } 28229 if (backing_int_ty.bitSize(target) != fields_bit_sum) { 28230 return sema.fail( 28231 block, 28232 src, 28233 "backing integer type '{}' has bit size {} but the struct fields have a total bit size of {}", 28234 .{ backing_int_ty.fmt(sema.mod), backing_int_ty.bitSize(target), fields_bit_sum }, 28235 ); 28236 } 28237 } 28238 28239 fn resolveUnionLayout( 28240 sema: *Sema, 28241 block: *Block, 28242 src: LazySrcLoc, 28243 ty: Type, 28244 ) CompileError!void { 28245 const resolved_ty = try sema.resolveTypeFields(block, src, ty); 28246 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; 28247 switch (union_obj.status) { 28248 .none, .have_field_types => {}, 28249 .field_types_wip, .layout_wip => { 28250 const msg = try Module.ErrorMsg.create( 28251 sema.gpa, 28252 union_obj.srcLoc(sema.mod), 28253 "union '{}' depends on itself", 28254 .{ty.fmt(sema.mod)}, 28255 ); 28256 return sema.failWithOwnedErrorMsg(msg); 28257 }, 28258 .have_layout, .fully_resolved_wip, .fully_resolved => return, 28259 } 28260 union_obj.status = .layout_wip; 28261 for (union_obj.fields.values()) |field, i| { 28262 sema.resolveTypeLayout(block, src, field.ty) catch |err| switch (err) { 28263 error.AnalysisFail => { 28264 const msg = sema.err orelse return err; 28265 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); 28266 return err; 28267 }, 28268 else => return err, 28269 }; 28270 } 28271 union_obj.status = .have_layout; 28272 } 28273 28274 /// Returns `error.AnalysisFail` if any of the types (recursively) failed to 28275 /// be resolved. 28276 pub fn resolveTypeFully( 28277 sema: *Sema, 28278 block: *Block, 28279 src: LazySrcLoc, 28280 ty: Type, 28281 ) CompileError!void { 28282 switch (ty.zigTypeTag()) { 28283 .Pointer => { 28284 const child_ty = try sema.resolveTypeFields(block, src, ty.childType()); 28285 return resolveTypeFully(sema, block, src, child_ty); 28286 }, 28287 .Struct => switch (ty.tag()) { 28288 .@"struct" => return resolveStructFully(sema, block, src, ty), 28289 .tuple, .anon_struct => { 28290 const tuple = ty.tupleFields(); 28291 28292 for (tuple.types) |field_ty| { 28293 try sema.resolveTypeFully(block, src, field_ty); 28294 } 28295 }, 28296 else => {}, 28297 }, 28298 .Union => return resolveUnionFully(sema, block, src, ty), 28299 .Array => return resolveTypeFully(sema, block, src, ty.childType()), 28300 .Optional => { 28301 var buf: Type.Payload.ElemType = undefined; 28302 return resolveTypeFully(sema, block, src, ty.optionalChild(&buf)); 28303 }, 28304 .ErrorUnion => return resolveTypeFully(sema, block, src, ty.errorUnionPayload()), 28305 .Fn => { 28306 const info = ty.fnInfo(); 28307 if (info.is_generic) { 28308 // Resolving of generic function types is defeerred to when 28309 // the function is instantiated. 28310 return; 28311 } 28312 for (info.param_types) |param_ty| { 28313 const param_ty_src = src; // TODO better source location 28314 try sema.resolveTypeFully(block, param_ty_src, param_ty); 28315 } 28316 const return_ty_src = src; // TODO better source location 28317 try sema.resolveTypeFully(block, return_ty_src, info.return_type); 28318 }, 28319 else => {}, 28320 } 28321 } 28322 28323 fn resolveStructFully( 28324 sema: *Sema, 28325 block: *Block, 28326 src: LazySrcLoc, 28327 ty: Type, 28328 ) CompileError!void { 28329 try resolveStructLayout(sema, block, src, ty); 28330 28331 const resolved_ty = try sema.resolveTypeFields(block, src, ty); 28332 const payload = resolved_ty.castTag(.@"struct").?; 28333 const struct_obj = payload.data; 28334 28335 switch (struct_obj.status) { 28336 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, 28337 .fully_resolved_wip, .fully_resolved => return, 28338 } 28339 28340 { 28341 // After we have resolve struct layout we have to go over the fields again to 28342 // make sure pointer fields get their child types resolved as well. 28343 // See also similar code for unions. 28344 const prev_status = struct_obj.status; 28345 errdefer struct_obj.status = prev_status; 28346 28347 struct_obj.status = .fully_resolved_wip; 28348 for (struct_obj.fields.values()) |field| { 28349 try sema.resolveTypeFully(block, src, field.ty); 28350 } 28351 struct_obj.status = .fully_resolved; 28352 } 28353 28354 // And let's not forget comptime-only status. 28355 _ = try sema.typeRequiresComptime(ty); 28356 } 28357 28358 fn resolveUnionFully( 28359 sema: *Sema, 28360 block: *Block, 28361 src: LazySrcLoc, 28362 ty: Type, 28363 ) CompileError!void { 28364 try resolveUnionLayout(sema, block, src, ty); 28365 28366 const resolved_ty = try sema.resolveTypeFields(block, src, ty); 28367 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; 28368 switch (union_obj.status) { 28369 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, 28370 .fully_resolved_wip, .fully_resolved => return, 28371 } 28372 28373 { 28374 // After we have resolve union layout we have to go over the fields again to 28375 // make sure pointer fields get their child types resolved as well. 28376 // See also similar code for structs. 28377 const prev_status = union_obj.status; 28378 errdefer union_obj.status = prev_status; 28379 28380 union_obj.status = .fully_resolved_wip; 28381 for (union_obj.fields.values()) |field| { 28382 try sema.resolveTypeFully(block, src, field.ty); 28383 } 28384 union_obj.status = .fully_resolved; 28385 } 28386 28387 // And let's not forget comptime-only status. 28388 _ = try sema.typeRequiresComptime(ty); 28389 } 28390 28391 pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type { 28392 switch (ty.tag()) { 28393 .@"struct" => { 28394 const struct_obj = ty.castTag(.@"struct").?.data; 28395 try sema.resolveTypeFieldsStruct(ty, struct_obj); 28396 return ty; 28397 }, 28398 .@"union", .union_safety_tagged, .union_tagged => { 28399 const union_obj = ty.cast(Type.Payload.Union).?.data; 28400 try sema.resolveTypeFieldsUnion(ty, union_obj); 28401 return ty; 28402 }, 28403 .type_info => return sema.resolveBuiltinTypeFields(block, src, "Type"), 28404 .extern_options => return sema.resolveBuiltinTypeFields(block, src, "ExternOptions"), 28405 .export_options => return sema.resolveBuiltinTypeFields(block, src, "ExportOptions"), 28406 .atomic_order => return sema.resolveBuiltinTypeFields(block, src, "AtomicOrder"), 28407 .atomic_rmw_op => return sema.resolveBuiltinTypeFields(block, src, "AtomicRmwOp"), 28408 .calling_convention => return sema.resolveBuiltinTypeFields(block, src, "CallingConvention"), 28409 .address_space => return sema.resolveBuiltinTypeFields(block, src, "AddressSpace"), 28410 .float_mode => return sema.resolveBuiltinTypeFields(block, src, "FloatMode"), 28411 .reduce_op => return sema.resolveBuiltinTypeFields(block, src, "ReduceOp"), 28412 .call_options => return sema.resolveBuiltinTypeFields(block, src, "CallOptions"), 28413 .prefetch_options => return sema.resolveBuiltinTypeFields(block, src, "PrefetchOptions"), 28414 28415 else => return ty, 28416 } 28417 } 28418 28419 fn resolveTypeFieldsStruct( 28420 sema: *Sema, 28421 ty: Type, 28422 struct_obj: *Module.Struct, 28423 ) CompileError!void { 28424 switch (struct_obj.status) { 28425 .none => {}, 28426 .field_types_wip => { 28427 const msg = try Module.ErrorMsg.create( 28428 sema.gpa, 28429 struct_obj.srcLoc(sema.mod), 28430 "struct '{}' depends on itself", 28431 .{ty.fmt(sema.mod)}, 28432 ); 28433 return sema.failWithOwnedErrorMsg(msg); 28434 }, 28435 .have_field_types, 28436 .have_layout, 28437 .layout_wip, 28438 .fully_resolved_wip, 28439 .fully_resolved, 28440 => return, 28441 } 28442 28443 struct_obj.status = .field_types_wip; 28444 try semaStructFields(sema.mod, struct_obj); 28445 } 28446 28447 fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_obj: *Module.Union) CompileError!void { 28448 switch (union_obj.status) { 28449 .none => {}, 28450 .field_types_wip => { 28451 const msg = try Module.ErrorMsg.create( 28452 sema.gpa, 28453 union_obj.srcLoc(sema.mod), 28454 "union '{}' depends on itself", 28455 .{ty.fmt(sema.mod)}, 28456 ); 28457 return sema.failWithOwnedErrorMsg(msg); 28458 }, 28459 .have_field_types, 28460 .have_layout, 28461 .layout_wip, 28462 .fully_resolved_wip, 28463 .fully_resolved, 28464 => return, 28465 } 28466 28467 union_obj.status = .field_types_wip; 28468 try semaUnionFields(sema.mod, union_obj); 28469 union_obj.status = .have_field_types; 28470 } 28471 28472 fn resolveBuiltinTypeFields( 28473 sema: *Sema, 28474 block: *Block, 28475 src: LazySrcLoc, 28476 name: []const u8, 28477 ) CompileError!Type { 28478 const resolved_ty = try sema.getBuiltinType(block, src, name); 28479 return sema.resolveTypeFields(block, src, resolved_ty); 28480 } 28481 28482 fn resolveInferredErrorSet( 28483 sema: *Sema, 28484 block: *Block, 28485 src: LazySrcLoc, 28486 ies: *Module.Fn.InferredErrorSet, 28487 ) CompileError!void { 28488 if (ies.is_resolved) return; 28489 28490 if (ies.func.state == .in_progress) { 28491 return sema.fail(block, src, "unable to resolve inferred error set", .{}); 28492 } 28493 28494 // In order to ensure that all dependencies are properly added to the set, we 28495 // need to ensure the function body is analyzed of the inferred error set. 28496 // However, in the case of comptime/inline function calls with inferred error sets, 28497 // each call gets a new InferredErrorSet object, which points to the same 28498 // `*Module.Fn`. Not only is the function not relevant to the inferred error set 28499 // in this case, it may be a generic function which would cause an assertion failure 28500 // if we called `ensureFuncBodyAnalyzed` on it here. 28501 const ies_func_owner_decl = sema.mod.declPtr(ies.func.owner_decl); 28502 const ies_func_info = ies_func_owner_decl.ty.fnInfo(); 28503 // if ies declared by a inline function with generic return type, the return_type should be generic_poison, 28504 // because inline function does not create a new declaration, and the ies has been filled with analyzeCall, 28505 // so here we can simply skip this case. 28506 if (ies_func_info.return_type.tag() == .generic_poison) { 28507 assert(ies_func_info.cc == .Inline); 28508 } else if (ies_func_info.return_type.errorUnionSet().castTag(.error_set_inferred).?.data == ies) { 28509 // In this case we are dealing with the actual InferredErrorSet object that 28510 // corresponds to the function, not one created to track an inline/comptime call. 28511 try sema.ensureFuncBodyAnalyzed(ies.func); 28512 } 28513 28514 ies.is_resolved = true; 28515 28516 var it = ies.inferred_error_sets.keyIterator(); 28517 while (it.next()) |other_error_set_ptr| { 28518 const other_ies: *Module.Fn.InferredErrorSet = other_error_set_ptr.*; 28519 if (ies == other_ies) continue; 28520 try sema.resolveInferredErrorSet(block, src, other_ies); 28521 28522 for (other_ies.errors.keys()) |key| { 28523 try ies.errors.put(sema.gpa, key, {}); 28524 } 28525 if (other_ies.is_anyerror) 28526 ies.is_anyerror = true; 28527 } 28528 } 28529 28530 fn resolveInferredErrorSetTy( 28531 sema: *Sema, 28532 block: *Block, 28533 src: LazySrcLoc, 28534 ty: Type, 28535 ) CompileError!void { 28536 if (ty.castTag(.error_set_inferred)) |inferred| { 28537 try sema.resolveInferredErrorSet(block, src, inferred.data); 28538 } 28539 } 28540 28541 fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void { 28542 const gpa = mod.gpa; 28543 const decl_index = struct_obj.owner_decl; 28544 const file_scope = struct_obj.namespace.file_scope; 28545 if (file_scope.status != .success_zir) return error.AnalysisFail; 28546 const zir = file_scope.zir; 28547 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; 28548 assert(extended.opcode == .struct_decl); 28549 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); 28550 var extra_index: usize = extended.operand; 28551 28552 const src = LazySrcLoc.nodeOffset(0); 28553 extra_index += @boolToInt(small.has_src_node); 28554 28555 const fields_len = if (small.has_fields_len) blk: { 28556 const fields_len = zir.extra[extra_index]; 28557 extra_index += 1; 28558 break :blk fields_len; 28559 } else 0; 28560 28561 const decls_len = if (small.has_decls_len) decls_len: { 28562 const decls_len = zir.extra[extra_index]; 28563 extra_index += 1; 28564 break :decls_len decls_len; 28565 } else 0; 28566 28567 // The backing integer cannot be handled until `resolveStructLayout()`. 28568 if (small.has_backing_int) { 28569 const backing_int_body_len = zir.extra[extra_index]; 28570 extra_index += 1; // backing_int_body_len 28571 if (backing_int_body_len == 0) { 28572 extra_index += 1; // backing_int_ref 28573 } else { 28574 extra_index += backing_int_body_len; // backing_int_body_inst 28575 } 28576 } 28577 28578 // Skip over decls. 28579 var decls_it = zir.declIteratorInner(extra_index, decls_len); 28580 while (decls_it.next()) |_| {} 28581 extra_index = decls_it.extra_index; 28582 28583 if (fields_len == 0) { 28584 if (struct_obj.layout == .Packed) { 28585 try semaBackingIntType(mod, struct_obj); 28586 } 28587 struct_obj.status = .have_layout; 28588 return; 28589 } 28590 28591 const decl = mod.declPtr(decl_index); 28592 var decl_arena = decl.value_arena.?.promote(gpa); 28593 defer decl.value_arena.?.* = decl_arena.state; 28594 const decl_arena_allocator = decl_arena.allocator(); 28595 28596 var analysis_arena = std.heap.ArenaAllocator.init(gpa); 28597 defer analysis_arena.deinit(); 28598 28599 var sema: Sema = .{ 28600 .mod = mod, 28601 .gpa = gpa, 28602 .arena = analysis_arena.allocator(), 28603 .perm_arena = decl_arena_allocator, 28604 .code = zir, 28605 .owner_decl = decl, 28606 .owner_decl_index = decl_index, 28607 .func = null, 28608 .fn_ret_ty = Type.void, 28609 .owner_func = null, 28610 }; 28611 defer sema.deinit(); 28612 28613 var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope); 28614 defer wip_captures.deinit(); 28615 28616 var block_scope: Block = .{ 28617 .parent = null, 28618 .sema = &sema, 28619 .src_decl = decl_index, 28620 .namespace = &struct_obj.namespace, 28621 .wip_capture_scope = wip_captures.scope, 28622 .instructions = .{}, 28623 .inlining = null, 28624 .is_comptime = true, 28625 }; 28626 defer { 28627 assert(block_scope.instructions.items.len == 0); 28628 block_scope.params.deinit(gpa); 28629 } 28630 28631 try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len); 28632 28633 const Field = struct { 28634 type_body_len: u32 = 0, 28635 align_body_len: u32 = 0, 28636 init_body_len: u32 = 0, 28637 type_ref: Air.Inst.Ref = .none, 28638 }; 28639 const fields = try sema.arena.alloc(Field, fields_len); 28640 var any_inits = false; 28641 28642 { 28643 const bits_per_field = 4; 28644 const fields_per_u32 = 32 / bits_per_field; 28645 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; 28646 const flags_index = extra_index; 28647 var bit_bag_index: usize = flags_index; 28648 extra_index += bit_bags_count; 28649 var cur_bit_bag: u32 = undefined; 28650 var field_i: u32 = 0; 28651 while (field_i < fields_len) : (field_i += 1) { 28652 if (field_i % fields_per_u32 == 0) { 28653 cur_bit_bag = zir.extra[bit_bag_index]; 28654 bit_bag_index += 1; 28655 } 28656 const has_align = @truncate(u1, cur_bit_bag) != 0; 28657 cur_bit_bag >>= 1; 28658 const has_init = @truncate(u1, cur_bit_bag) != 0; 28659 cur_bit_bag >>= 1; 28660 const is_comptime = @truncate(u1, cur_bit_bag) != 0; 28661 cur_bit_bag >>= 1; 28662 const has_type_body = @truncate(u1, cur_bit_bag) != 0; 28663 cur_bit_bag >>= 1; 28664 28665 const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]); 28666 extra_index += 1; 28667 extra_index += 1; // doc_comment 28668 28669 fields[field_i] = .{}; 28670 28671 if (has_type_body) { 28672 fields[field_i].type_body_len = zir.extra[extra_index]; 28673 } else { 28674 fields[field_i].type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 28675 } 28676 extra_index += 1; 28677 28678 // This string needs to outlive the ZIR code. 28679 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir); 28680 28681 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); 28682 if (gop.found_existing) { 28683 const msg = msg: { 28684 const tree = try sema.getAstTree(&block_scope); 28685 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); 28686 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name}); 28687 errdefer msg.destroy(gpa); 28688 28689 const prev_field_index = struct_obj.fields.getIndex(field_name).?; 28690 const prev_field_src = enumFieldSrcLoc(decl, tree.*, 0, prev_field_index); 28691 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{}); 28692 try sema.errNote(&block_scope, src, msg, "struct declared here", .{}); 28693 break :msg msg; 28694 }; 28695 return sema.failWithOwnedErrorMsg(msg); 28696 } 28697 gop.value_ptr.* = .{ 28698 .ty = Type.initTag(.noreturn), 28699 .abi_align = 0, 28700 .default_val = Value.initTag(.unreachable_value), 28701 .is_comptime = is_comptime, 28702 .offset = undefined, 28703 }; 28704 28705 if (has_align) { 28706 fields[field_i].align_body_len = zir.extra[extra_index]; 28707 extra_index += 1; 28708 } 28709 if (has_init) { 28710 fields[field_i].init_body_len = zir.extra[extra_index]; 28711 extra_index += 1; 28712 any_inits = true; 28713 } 28714 } 28715 } 28716 28717 // Next we do only types and alignments, saving the inits for a second pass, 28718 // so that init values may depend on type layout. 28719 const bodies_index = extra_index; 28720 28721 for (fields) |zir_field, i| { 28722 // TODO emit compile errors for invalid field types 28723 // such as arrays and pointers inside packed structs. 28724 const field_ty: Type = ty: { 28725 if (zir_field.type_ref != .none) { 28726 // TODO: if we need to report an error here, use a source location 28727 // that points to this type expression rather than the struct. 28728 // But only resolve the source location if we need to emit a compile error. 28729 break :ty try sema.resolveType(&block_scope, src, zir_field.type_ref); 28730 } 28731 assert(zir_field.type_body_len != 0); 28732 const body = zir.extra[extra_index..][0..zir_field.type_body_len]; 28733 extra_index += body.len; 28734 const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); 28735 break :ty try sema.analyzeAsType(&block_scope, src, ty_ref); 28736 }; 28737 if (field_ty.tag() == .generic_poison) { 28738 return error.GenericPoison; 28739 } 28740 28741 const field = &struct_obj.fields.values()[i]; 28742 field.ty = try field_ty.copy(decl_arena_allocator); 28743 28744 if (field_ty.zigTypeTag() == .Opaque) { 28745 const msg = msg: { 28746 const tree = try sema.getAstTree(&block_scope); 28747 const field_src = enumFieldSrcLoc(decl, tree.*, 0, i); 28748 const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); 28749 errdefer msg.destroy(sema.gpa); 28750 28751 try sema.addDeclaredHereNote(msg, field_ty); 28752 break :msg msg; 28753 }; 28754 return sema.failWithOwnedErrorMsg(msg); 28755 } 28756 if (field_ty.zigTypeTag() == .NoReturn) { 28757 const msg = msg: { 28758 const tree = try sema.getAstTree(&block_scope); 28759 const field_src = enumFieldSrcLoc(decl, tree.*, 0, i); 28760 const msg = try sema.errMsg(&block_scope, field_src, "struct fields cannot be 'noreturn'", .{}); 28761 errdefer msg.destroy(sema.gpa); 28762 28763 try sema.addDeclaredHereNote(msg, field_ty); 28764 break :msg msg; 28765 }; 28766 return sema.failWithOwnedErrorMsg(msg); 28767 } 28768 if (struct_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field.ty, .other)) { 28769 const msg = msg: { 28770 const tree = try sema.getAstTree(&block_scope); 28771 const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i); 28772 const msg = try sema.errMsg(&block_scope, fields_src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)}); 28773 errdefer msg.destroy(sema.gpa); 28774 28775 try sema.explainWhyTypeIsNotExtern(msg, fields_src.toSrcLoc(decl), field.ty, .other); 28776 28777 try sema.addDeclaredHereNote(msg, field.ty); 28778 break :msg msg; 28779 }; 28780 return sema.failWithOwnedErrorMsg(msg); 28781 } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty))) { 28782 const msg = msg: { 28783 const tree = try sema.getAstTree(&block_scope); 28784 const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i); 28785 const msg = try sema.errMsg(&block_scope, fields_src, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)}); 28786 errdefer msg.destroy(sema.gpa); 28787 28788 try sema.explainWhyTypeIsNotPacked(msg, fields_src.toSrcLoc(decl), field.ty); 28789 28790 try sema.addDeclaredHereNote(msg, field.ty); 28791 break :msg msg; 28792 }; 28793 return sema.failWithOwnedErrorMsg(msg); 28794 } 28795 28796 if (zir_field.align_body_len > 0) { 28797 const body = zir.extra[extra_index..][0..zir_field.align_body_len]; 28798 extra_index += body.len; 28799 const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); 28800 field.abi_align = try sema.analyzeAsAlign(&block_scope, src, align_ref); 28801 } 28802 28803 extra_index += zir_field.init_body_len; 28804 } 28805 28806 struct_obj.status = .have_field_types; 28807 28808 if (any_inits) { 28809 extra_index = bodies_index; 28810 for (fields) |zir_field, i| { 28811 extra_index += zir_field.type_body_len; 28812 extra_index += zir_field.align_body_len; 28813 if (zir_field.init_body_len > 0) { 28814 const body = zir.extra[extra_index..][0..zir_field.init_body_len]; 28815 extra_index += body.len; 28816 const init = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); 28817 const field = &struct_obj.fields.values()[i]; 28818 const coerced = try sema.coerce(&block_scope, field.ty, init, src); 28819 const default_val = (try sema.resolveMaybeUndefVal(&block_scope, src, coerced)) orelse 28820 return sema.failWithNeededComptime(&block_scope, src, "struct field default value must be comptime known"); 28821 field.default_val = try default_val.copy(decl_arena_allocator); 28822 } 28823 } 28824 } 28825 28826 struct_obj.have_field_inits = true; 28827 } 28828 28829 fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { 28830 const tracy = trace(@src()); 28831 defer tracy.end(); 28832 28833 const gpa = mod.gpa; 28834 const decl_index = union_obj.owner_decl; 28835 const zir = union_obj.namespace.file_scope.zir; 28836 const extended = zir.instructions.items(.data)[union_obj.zir_index].extended; 28837 assert(extended.opcode == .union_decl); 28838 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); 28839 var extra_index: usize = extended.operand; 28840 28841 const src = LazySrcLoc.nodeOffset(0); 28842 extra_index += @boolToInt(small.has_src_node); 28843 28844 const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: { 28845 const ty_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 28846 extra_index += 1; 28847 break :blk ty_ref; 28848 } else .none; 28849 28850 const body_len = if (small.has_body_len) blk: { 28851 const body_len = zir.extra[extra_index]; 28852 extra_index += 1; 28853 break :blk body_len; 28854 } else 0; 28855 28856 const fields_len = if (small.has_fields_len) blk: { 28857 const fields_len = zir.extra[extra_index]; 28858 extra_index += 1; 28859 break :blk fields_len; 28860 } else 0; 28861 28862 const decls_len = if (small.has_decls_len) decls_len: { 28863 const decls_len = zir.extra[extra_index]; 28864 extra_index += 1; 28865 break :decls_len decls_len; 28866 } else 0; 28867 28868 // Skip over decls. 28869 var decls_it = zir.declIteratorInner(extra_index, decls_len); 28870 while (decls_it.next()) |_| {} 28871 extra_index = decls_it.extra_index; 28872 28873 const body = zir.extra[extra_index..][0..body_len]; 28874 extra_index += body.len; 28875 28876 const decl = mod.declPtr(decl_index); 28877 28878 var decl_arena = decl.value_arena.?.promote(gpa); 28879 defer decl.value_arena.?.* = decl_arena.state; 28880 const decl_arena_allocator = decl_arena.allocator(); 28881 28882 var analysis_arena = std.heap.ArenaAllocator.init(gpa); 28883 defer analysis_arena.deinit(); 28884 28885 var sema: Sema = .{ 28886 .mod = mod, 28887 .gpa = gpa, 28888 .arena = analysis_arena.allocator(), 28889 .perm_arena = decl_arena_allocator, 28890 .code = zir, 28891 .owner_decl = decl, 28892 .owner_decl_index = decl_index, 28893 .func = null, 28894 .fn_ret_ty = Type.void, 28895 .owner_func = null, 28896 }; 28897 defer sema.deinit(); 28898 28899 var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope); 28900 defer wip_captures.deinit(); 28901 28902 var block_scope: Block = .{ 28903 .parent = null, 28904 .sema = &sema, 28905 .src_decl = decl_index, 28906 .namespace = &union_obj.namespace, 28907 .wip_capture_scope = wip_captures.scope, 28908 .instructions = .{}, 28909 .inlining = null, 28910 .is_comptime = true, 28911 }; 28912 defer { 28913 assert(block_scope.instructions.items.len == 0); 28914 block_scope.params.deinit(gpa); 28915 } 28916 28917 if (body.len != 0) { 28918 try sema.analyzeBody(&block_scope, body); 28919 } 28920 28921 try wip_captures.finalize(); 28922 28923 try union_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len); 28924 28925 var int_tag_ty: Type = undefined; 28926 var enum_field_names: ?*Module.EnumNumbered.NameMap = null; 28927 var enum_value_map: ?*Module.EnumNumbered.ValueMap = null; 28928 var tag_ty_field_names: ?Module.EnumFull.NameMap = null; 28929 if (tag_type_ref != .none) { 28930 const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x }; 28931 const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref); 28932 if (small.auto_enum_tag) { 28933 // The provided type is an integer type and we must construct the enum tag type here. 28934 int_tag_ty = provided_ty; 28935 if (int_tag_ty.zigTypeTag() != .Int and int_tag_ty.zigTypeTag() != .ComptimeInt) { 28936 return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{}'", .{int_tag_ty.fmt(sema.mod)}); 28937 } 28938 union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, fields_len, provided_ty, union_obj); 28939 const enum_obj = union_obj.tag_ty.castTag(.enum_numbered).?.data; 28940 enum_field_names = &enum_obj.fields; 28941 enum_value_map = &enum_obj.values; 28942 } else { 28943 // The provided type is the enum tag type. 28944 union_obj.tag_ty = try provided_ty.copy(decl_arena_allocator); 28945 if (union_obj.tag_ty.zigTypeTag() != .Enum) { 28946 return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(sema.mod)}); 28947 } 28948 // The fields of the union must match the enum exactly. 28949 // Store a copy of the enum field names so we can check for 28950 // missing or extraneous fields later. 28951 tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena); 28952 } 28953 } else { 28954 // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis 28955 // purposes, we still auto-generate an enum tag type the same way. That the union is 28956 // untagged is represented by the Type tag (union vs union_tagged). 28957 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, fields_len, union_obj); 28958 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields; 28959 } 28960 28961 if (fields_len == 0) { 28962 return; 28963 } 28964 28965 const bits_per_field = 4; 28966 const fields_per_u32 = 32 / bits_per_field; 28967 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; 28968 var bit_bag_index: usize = extra_index; 28969 extra_index += bit_bags_count; 28970 var cur_bit_bag: u32 = undefined; 28971 var field_i: u32 = 0; 28972 var last_tag_val: ?Value = null; 28973 while (field_i < fields_len) : (field_i += 1) { 28974 if (field_i % fields_per_u32 == 0) { 28975 cur_bit_bag = zir.extra[bit_bag_index]; 28976 bit_bag_index += 1; 28977 } 28978 const has_type = @truncate(u1, cur_bit_bag) != 0; 28979 cur_bit_bag >>= 1; 28980 const has_align = @truncate(u1, cur_bit_bag) != 0; 28981 cur_bit_bag >>= 1; 28982 const has_tag = @truncate(u1, cur_bit_bag) != 0; 28983 cur_bit_bag >>= 1; 28984 const unused = @truncate(u1, cur_bit_bag) != 0; 28985 cur_bit_bag >>= 1; 28986 _ = unused; 28987 28988 const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]); 28989 extra_index += 1; 28990 28991 // doc_comment 28992 extra_index += 1; 28993 28994 const field_type_ref: Zir.Inst.Ref = if (has_type) blk: { 28995 const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 28996 extra_index += 1; 28997 break :blk field_type_ref; 28998 } else .none; 28999 29000 const align_ref: Zir.Inst.Ref = if (has_align) blk: { 29001 const align_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 29002 extra_index += 1; 29003 break :blk align_ref; 29004 } else .none; 29005 29006 const tag_ref: Zir.Inst.Ref = if (has_tag) blk: { 29007 const tag_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 29008 extra_index += 1; 29009 break :blk try sema.resolveInst(tag_ref); 29010 } else .none; 29011 29012 if (enum_value_map) |map| { 29013 if (tag_ref != .none) { 29014 const tag_src = src; // TODO better source location 29015 const coerced = try sema.coerce(&block_scope, int_tag_ty, tag_ref, tag_src); 29016 const val = try sema.resolveConstValue(&block_scope, tag_src, coerced, "enum tag value must be comptime known"); 29017 last_tag_val = val; 29018 29019 // This puts the memory into the union arena, not the enum arena, but 29020 // it is OK since they share the same lifetime. 29021 const copied_val = try val.copy(decl_arena_allocator); 29022 map.putAssumeCapacityContext(copied_val, {}, .{ 29023 .ty = int_tag_ty, 29024 .mod = mod, 29025 }); 29026 } else { 29027 const val = if (last_tag_val) |val| 29028 try sema.intAdd(&block_scope, src, val, Value.one, int_tag_ty) 29029 else 29030 Value.zero; 29031 last_tag_val = val; 29032 29033 const copied_val = try val.copy(decl_arena_allocator); 29034 map.putAssumeCapacityContext(copied_val, {}, .{ 29035 .ty = int_tag_ty, 29036 .mod = mod, 29037 }); 29038 } 29039 } 29040 29041 // This string needs to outlive the ZIR code. 29042 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir); 29043 if (enum_field_names) |set| { 29044 set.putAssumeCapacity(field_name, {}); 29045 } 29046 29047 const field_ty: Type = if (!has_type) 29048 Type.void 29049 else if (field_type_ref == .none) 29050 Type.initTag(.noreturn) 29051 else 29052 // TODO: if we need to report an error here, use a source location 29053 // that points to this type expression rather than the union. 29054 // But only resolve the source location if we need to emit a compile error. 29055 try sema.resolveType(&block_scope, src, field_type_ref); 29056 29057 if (field_ty.tag() == .generic_poison) { 29058 return error.GenericPoison; 29059 } 29060 29061 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); 29062 if (gop.found_existing) { 29063 const msg = msg: { 29064 const tree = try sema.getAstTree(&block_scope); 29065 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); 29066 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name}); 29067 errdefer msg.destroy(gpa); 29068 29069 const prev_field_index = union_obj.fields.getIndex(field_name).?; 29070 const prev_field_src = enumFieldSrcLoc(decl, tree.*, 0, prev_field_index); 29071 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{}); 29072 try sema.errNote(&block_scope, src, msg, "union declared here", .{}); 29073 break :msg msg; 29074 }; 29075 return sema.failWithOwnedErrorMsg(msg); 29076 } 29077 29078 if (tag_ty_field_names) |*names| { 29079 const enum_has_field = names.orderedRemove(field_name); 29080 if (!enum_has_field) { 29081 const msg = msg: { 29082 const tree = try sema.getAstTree(&block_scope); 29083 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); 29084 const msg = try sema.errMsg(&block_scope, field_src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) }); 29085 errdefer msg.destroy(sema.gpa); 29086 try sema.addDeclaredHereNote(msg, union_obj.tag_ty); 29087 break :msg msg; 29088 }; 29089 return sema.failWithOwnedErrorMsg(msg); 29090 } 29091 } 29092 29093 if (field_ty.zigTypeTag() == .Opaque) { 29094 const msg = msg: { 29095 const tree = try sema.getAstTree(&block_scope); 29096 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); 29097 const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{}); 29098 errdefer msg.destroy(sema.gpa); 29099 29100 try sema.addDeclaredHereNote(msg, field_ty); 29101 break :msg msg; 29102 }; 29103 return sema.failWithOwnedErrorMsg(msg); 29104 } 29105 if (union_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field_ty, .union_field)) { 29106 const msg = msg: { 29107 const tree = try sema.getAstTree(&block_scope); 29108 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); 29109 const msg = try sema.errMsg(&block_scope, field_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); 29110 errdefer msg.destroy(sema.gpa); 29111 29112 try sema.explainWhyTypeIsNotExtern(msg, field_src.toSrcLoc(decl), field_ty, .union_field); 29113 29114 try sema.addDeclaredHereNote(msg, field_ty); 29115 break :msg msg; 29116 }; 29117 return sema.failWithOwnedErrorMsg(msg); 29118 } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty))) { 29119 const msg = msg: { 29120 const tree = try sema.getAstTree(&block_scope); 29121 const fields_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); 29122 const msg = try sema.errMsg(&block_scope, fields_src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); 29123 errdefer msg.destroy(sema.gpa); 29124 29125 try sema.explainWhyTypeIsNotPacked(msg, fields_src.toSrcLoc(decl), field_ty); 29126 29127 try sema.addDeclaredHereNote(msg, field_ty); 29128 break :msg msg; 29129 }; 29130 return sema.failWithOwnedErrorMsg(msg); 29131 } 29132 29133 gop.value_ptr.* = .{ 29134 .ty = try field_ty.copy(decl_arena_allocator), 29135 .abi_align = 0, 29136 }; 29137 29138 if (align_ref != .none) { 29139 // TODO: if we need to report an error here, use a source location 29140 // that points to this alignment expression rather than the struct. 29141 // But only resolve the source location if we need to emit a compile error. 29142 gop.value_ptr.abi_align = try sema.resolveAlign(&block_scope, src, align_ref); 29143 } else { 29144 gop.value_ptr.abi_align = 0; 29145 } 29146 } 29147 29148 if (tag_ty_field_names) |names| { 29149 if (names.count() > 0) { 29150 const msg = msg: { 29151 const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{}); 29152 errdefer msg.destroy(sema.gpa); 29153 29154 const enum_ty = union_obj.tag_ty; 29155 for (names.keys()) |field_name| { 29156 const field_index = enum_ty.enumFieldIndex(field_name).?; 29157 try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name}); 29158 } 29159 try sema.addDeclaredHereNote(msg, union_obj.tag_ty); 29160 break :msg msg; 29161 }; 29162 return sema.failWithOwnedErrorMsg(msg); 29163 } 29164 } 29165 } 29166 29167 fn generateUnionTagTypeNumbered( 29168 sema: *Sema, 29169 block: *Block, 29170 fields_len: u32, 29171 int_ty: Type, 29172 union_obj: *Module.Union, 29173 ) !Type { 29174 const mod = sema.mod; 29175 29176 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); 29177 errdefer new_decl_arena.deinit(); 29178 const new_decl_arena_allocator = new_decl_arena.allocator(); 29179 29180 const enum_obj = try new_decl_arena_allocator.create(Module.EnumNumbered); 29181 const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumNumbered); 29182 enum_ty_payload.* = .{ 29183 .base = .{ .tag = .enum_numbered }, 29184 .data = enum_obj, 29185 }; 29186 const enum_ty = Type.initPayload(&enum_ty_payload.base); 29187 const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); 29188 29189 const src_decl = mod.declPtr(block.src_decl); 29190 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); 29191 errdefer mod.destroyDecl(new_decl_index); 29192 const name = name: { 29193 const fqn = try union_obj.getFullyQualifiedName(mod); 29194 defer sema.gpa.free(fqn); 29195 break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn}); 29196 }; 29197 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{ 29198 .ty = Type.type, 29199 .val = enum_val, 29200 }, name); 29201 sema.mod.declPtr(new_decl_index).name_fully_qualified = true; 29202 29203 const new_decl = mod.declPtr(new_decl_index); 29204 new_decl.owns_tv = true; 29205 new_decl.name_fully_qualified = true; 29206 errdefer mod.abortAnonDecl(new_decl_index); 29207 29208 enum_obj.* = .{ 29209 .owner_decl = new_decl_index, 29210 .tag_ty = int_ty, 29211 .fields = .{}, 29212 .values = .{}, 29213 }; 29214 // Here we pre-allocate the maps using the decl arena. 29215 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); 29216 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{ 29217 .ty = int_ty, 29218 .mod = mod, 29219 }); 29220 try new_decl.finalizeNewArena(&new_decl_arena); 29221 return enum_ty; 29222 } 29223 29224 fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, maybe_union_obj: ?*Module.Union) !Type { 29225 const mod = sema.mod; 29226 29227 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); 29228 errdefer new_decl_arena.deinit(); 29229 const new_decl_arena_allocator = new_decl_arena.allocator(); 29230 29231 const enum_obj = try new_decl_arena_allocator.create(Module.EnumSimple); 29232 const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumSimple); 29233 enum_ty_payload.* = .{ 29234 .base = .{ .tag = .enum_simple }, 29235 .data = enum_obj, 29236 }; 29237 const enum_ty = Type.initPayload(&enum_ty_payload.base); 29238 const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); 29239 29240 const new_decl_index = new_decl_index: { 29241 const union_obj = maybe_union_obj orelse { 29242 break :new_decl_index try mod.createAnonymousDecl(block, .{ 29243 .ty = Type.type, 29244 .val = enum_val, 29245 }); 29246 }; 29247 const src_decl = mod.declPtr(block.src_decl); 29248 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); 29249 errdefer mod.destroyDecl(new_decl_index); 29250 const name = name: { 29251 const fqn = try union_obj.getFullyQualifiedName(mod); 29252 defer sema.gpa.free(fqn); 29253 break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn}); 29254 }; 29255 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{ 29256 .ty = Type.type, 29257 .val = enum_val, 29258 }, name); 29259 sema.mod.declPtr(new_decl_index).name_fully_qualified = true; 29260 break :new_decl_index new_decl_index; 29261 }; 29262 29263 const new_decl = mod.declPtr(new_decl_index); 29264 new_decl.owns_tv = true; 29265 errdefer mod.abortAnonDecl(new_decl_index); 29266 29267 enum_obj.* = .{ 29268 .owner_decl = new_decl_index, 29269 .fields = .{}, 29270 }; 29271 // Here we pre-allocate the maps using the decl arena. 29272 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); 29273 try new_decl.finalizeNewArena(&new_decl_arena); 29274 return enum_ty; 29275 } 29276 29277 fn getBuiltin( 29278 sema: *Sema, 29279 block: *Block, 29280 src: LazySrcLoc, 29281 name: []const u8, 29282 ) CompileError!Air.Inst.Ref { 29283 const mod = sema.mod; 29284 const std_pkg = mod.main_pkg.table.get("std").?; 29285 const std_file = (mod.importPkg(std_pkg) catch unreachable).file; 29286 const opt_builtin_inst = try sema.namespaceLookupRef( 29287 block, 29288 src, 29289 mod.declPtr(std_file.root_decl.unwrap().?).src_namespace, 29290 "builtin", 29291 ); 29292 const builtin_inst = try sema.analyzeLoad(block, src, opt_builtin_inst.?, src); 29293 const builtin_ty = try sema.analyzeAsType(block, src, builtin_inst); 29294 const opt_ty_decl = try sema.namespaceLookup( 29295 block, 29296 src, 29297 builtin_ty.getNamespace().?, 29298 name, 29299 ); 29300 return sema.analyzeDeclVal(block, src, opt_ty_decl.?); 29301 } 29302 29303 fn getBuiltinType( 29304 sema: *Sema, 29305 block: *Block, 29306 src: LazySrcLoc, 29307 name: []const u8, 29308 ) CompileError!Type { 29309 const ty_inst = try sema.getBuiltin(block, src, name); 29310 const result_ty = try sema.analyzeAsType(block, src, ty_inst); 29311 try sema.resolveTypeFully(block, src, result_ty); // Should not fail 29312 return result_ty; 29313 } 29314 29315 /// There is another implementation of this in `Type.onePossibleValue`. This one 29316 /// in `Sema` is for calling during semantic analysis, and performs field resolution 29317 /// to get the answer. The one in `Type` is for calling during codegen and asserts 29318 /// that the types are already resolved. 29319 /// TODO assert the return value matches `ty.onePossibleValue` 29320 pub fn typeHasOnePossibleValue( 29321 sema: *Sema, 29322 block: *Block, 29323 src: LazySrcLoc, 29324 ty: Type, 29325 ) CompileError!?Value { 29326 switch (ty.tag()) { 29327 .f16, 29328 .f32, 29329 .f64, 29330 .f80, 29331 .f128, 29332 .c_longdouble, 29333 .comptime_int, 29334 .comptime_float, 29335 .u1, 29336 .u8, 29337 .i8, 29338 .u16, 29339 .i16, 29340 .u29, 29341 .u32, 29342 .i32, 29343 .u64, 29344 .i64, 29345 .u128, 29346 .i128, 29347 .usize, 29348 .isize, 29349 .c_short, 29350 .c_ushort, 29351 .c_int, 29352 .c_uint, 29353 .c_long, 29354 .c_ulong, 29355 .c_longlong, 29356 .c_ulonglong, 29357 .bool, 29358 .type, 29359 .anyerror, 29360 .error_set_single, 29361 .error_set, 29362 .error_set_merged, 29363 .error_union, 29364 .fn_noreturn_no_args, 29365 .fn_void_no_args, 29366 .fn_naked_noreturn_no_args, 29367 .fn_ccc_void_no_args, 29368 .function, 29369 .single_const_pointer_to_comptime_int, 29370 .array_sentinel, 29371 .array_u8_sentinel_0, 29372 .const_slice_u8, 29373 .const_slice_u8_sentinel_0, 29374 .const_slice, 29375 .mut_slice, 29376 .anyopaque, 29377 .optional_single_mut_pointer, 29378 .optional_single_const_pointer, 29379 .enum_literal, 29380 .anyerror_void_error_union, 29381 .error_set_inferred, 29382 .@"opaque", 29383 .var_args_param, 29384 .manyptr_u8, 29385 .manyptr_const_u8, 29386 .manyptr_const_u8_sentinel_0, 29387 .atomic_order, 29388 .atomic_rmw_op, 29389 .calling_convention, 29390 .address_space, 29391 .float_mode, 29392 .reduce_op, 29393 .call_options, 29394 .prefetch_options, 29395 .export_options, 29396 .extern_options, 29397 .type_info, 29398 .@"anyframe", 29399 .anyframe_T, 29400 .many_const_pointer, 29401 .many_mut_pointer, 29402 .c_const_pointer, 29403 .c_mut_pointer, 29404 .single_const_pointer, 29405 .single_mut_pointer, 29406 .pointer, 29407 .bound_fn, 29408 => return null, 29409 29410 .optional => { 29411 var buf: Type.Payload.ElemType = undefined; 29412 const child_ty = ty.optionalChild(&buf); 29413 if (child_ty.isNoReturn()) { 29414 return Value.@"null"; 29415 } else { 29416 return null; 29417 } 29418 }, 29419 29420 .@"struct" => { 29421 const resolved_ty = try sema.resolveTypeFields(block, src, ty); 29422 const s = resolved_ty.castTag(.@"struct").?.data; 29423 for (s.fields.values()) |field, i| { 29424 if (field.is_comptime) continue; 29425 if (field.ty.eql(resolved_ty, sema.mod)) { 29426 const msg = try Module.ErrorMsg.create( 29427 sema.gpa, 29428 s.srcLoc(sema.mod), 29429 "struct '{}' depends on itself", 29430 .{ty.fmt(sema.mod)}, 29431 ); 29432 try sema.addFieldErrNote(resolved_ty, i, msg, "while checking this field", .{}); 29433 return sema.failWithOwnedErrorMsg(msg); 29434 } 29435 if ((try sema.typeHasOnePossibleValue(block, src, field.ty)) == null) { 29436 return null; 29437 } 29438 } 29439 return Value.initTag(.empty_struct_value); 29440 }, 29441 29442 .tuple, .anon_struct => { 29443 const tuple = ty.tupleFields(); 29444 for (tuple.values) |val, i| { 29445 const is_comptime = val.tag() != .unreachable_value; 29446 if (is_comptime) continue; 29447 if ((try sema.typeHasOnePossibleValue(block, src, tuple.types[i])) != null) continue; 29448 return null; 29449 } 29450 return Value.initTag(.empty_struct_value); 29451 }, 29452 29453 .enum_numbered => { 29454 const resolved_ty = try sema.resolveTypeFields(block, src, ty); 29455 const enum_obj = resolved_ty.castTag(.enum_numbered).?.data; 29456 // An explicit tag type is always provided for enum_numbered. 29457 if (enum_obj.tag_ty.hasRuntimeBits()) { 29458 return null; 29459 } 29460 if (enum_obj.fields.count() == 1) { 29461 if (enum_obj.values.count() == 0) { 29462 return Value.zero; // auto-numbered 29463 } else { 29464 return enum_obj.values.keys()[0]; 29465 } 29466 } else { 29467 return null; 29468 } 29469 }, 29470 .enum_full => { 29471 const resolved_ty = try sema.resolveTypeFields(block, src, ty); 29472 const enum_obj = resolved_ty.castTag(.enum_full).?.data; 29473 if (enum_obj.tag_ty.hasRuntimeBits()) { 29474 return null; 29475 } 29476 if (enum_obj.fields.count() == 1) { 29477 if (enum_obj.values.count() == 0) { 29478 return Value.zero; // auto-numbered 29479 } else { 29480 return enum_obj.values.keys()[0]; 29481 } 29482 } else { 29483 return null; 29484 } 29485 }, 29486 .enum_simple => { 29487 const resolved_ty = try sema.resolveTypeFields(block, src, ty); 29488 const enum_simple = resolved_ty.castTag(.enum_simple).?.data; 29489 if (enum_simple.fields.count() == 1) { 29490 return Value.zero; 29491 } else { 29492 return null; 29493 } 29494 }, 29495 .enum_nonexhaustive => { 29496 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty; 29497 if (tag_ty.zigTypeTag() != .ComptimeInt and !(try sema.typeHasRuntimeBits(block, src, tag_ty))) { 29498 return Value.zero; 29499 } else { 29500 return null; 29501 } 29502 }, 29503 .@"union", .union_safety_tagged, .union_tagged => { 29504 const resolved_ty = try sema.resolveTypeFields(block, src, ty); 29505 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; 29506 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse 29507 return null; 29508 const fields = union_obj.fields.values(); 29509 if (fields.len == 0) return Value.initTag(.empty_struct_value); 29510 const only_field = fields[0]; 29511 if (only_field.ty.eql(resolved_ty, sema.mod)) { 29512 const msg = try Module.ErrorMsg.create( 29513 sema.gpa, 29514 union_obj.srcLoc(sema.mod), 29515 "union '{}' depends on itself", 29516 .{ty.fmt(sema.mod)}, 29517 ); 29518 try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{}); 29519 return sema.failWithOwnedErrorMsg(msg); 29520 } 29521 const val_val = (try sema.typeHasOnePossibleValue(block, src, only_field.ty)) orelse 29522 return null; 29523 // TODO make this not allocate. The function in `Type.onePossibleValue` 29524 // currently returns `empty_struct_value` and we should do that here too. 29525 return try Value.Tag.@"union".create(sema.arena, .{ 29526 .tag = tag_val, 29527 .val = val_val, 29528 }); 29529 }, 29530 29531 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value), 29532 .void => return Value.void, 29533 .noreturn => return Value.initTag(.unreachable_value), 29534 .@"null" => return Value.@"null", 29535 .@"undefined" => return Value.initTag(.undef), 29536 29537 .int_unsigned, .int_signed => { 29538 if (ty.cast(Type.Payload.Bits).?.data == 0) { 29539 return Value.zero; 29540 } else { 29541 return null; 29542 } 29543 }, 29544 .vector, .array, .array_u8 => { 29545 if (ty.arrayLen() == 0) 29546 return Value.initTag(.empty_array); 29547 if ((try sema.typeHasOnePossibleValue(block, src, ty.elemType())) != null) { 29548 return Value.initTag(.the_only_possible_value); 29549 } 29550 return null; 29551 }, 29552 29553 .inferred_alloc_const => unreachable, 29554 .inferred_alloc_mut => unreachable, 29555 .generic_poison => return error.GenericPoison, 29556 } 29557 } 29558 29559 fn getAstTree(sema: *Sema, block: *Block) CompileError!*const std.zig.Ast { 29560 return block.namespace.file_scope.getTree(sema.gpa) catch |err| { 29561 log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); 29562 return error.AnalysisFail; 29563 }; 29564 } 29565 29566 fn enumFieldSrcLoc( 29567 decl: *Decl, 29568 tree: std.zig.Ast, 29569 node_offset: i32, 29570 field_index: usize, 29571 ) LazySrcLoc { 29572 @setCold(true); 29573 const enum_node = decl.relativeToNodeIndex(node_offset); 29574 const node_tags = tree.nodes.items(.tag); 29575 var buffer: [2]std.zig.Ast.Node.Index = undefined; 29576 const container_decl = switch (node_tags[enum_node]) { 29577 .container_decl, 29578 .container_decl_trailing, 29579 => tree.containerDecl(enum_node), 29580 29581 .container_decl_two, 29582 .container_decl_two_trailing, 29583 => tree.containerDeclTwo(&buffer, enum_node), 29584 29585 .container_decl_arg, 29586 .container_decl_arg_trailing, 29587 => tree.containerDeclArg(enum_node), 29588 29589 .tagged_union, 29590 .tagged_union_trailing, 29591 => tree.taggedUnion(enum_node), 29592 .tagged_union_two, 29593 .tagged_union_two_trailing, 29594 => tree.taggedUnionTwo(&buffer, enum_node), 29595 .tagged_union_enum_tag, 29596 .tagged_union_enum_tag_trailing, 29597 => tree.taggedUnionEnumTag(enum_node), 29598 29599 // Container was constructed with `@Type`. 29600 else => return LazySrcLoc.nodeOffset(0), 29601 }; 29602 var it_index: usize = 0; 29603 for (container_decl.ast.members) |member_node| { 29604 switch (node_tags[member_node]) { 29605 .container_field_init, 29606 .container_field_align, 29607 .container_field, 29608 => { 29609 if (it_index == field_index) { 29610 return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(member_node)); 29611 } 29612 it_index += 1; 29613 }, 29614 29615 else => continue, 29616 } 29617 } else unreachable; 29618 } 29619 29620 /// Returns the type of the AIR instruction. 29621 fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type { 29622 return sema.getTmpAir().typeOf(inst); 29623 } 29624 29625 pub fn getTmpAir(sema: Sema) Air { 29626 return .{ 29627 .instructions = sema.air_instructions.slice(), 29628 .extra = sema.air_extra.items, 29629 .values = sema.air_values.items, 29630 }; 29631 } 29632 29633 pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref { 29634 switch (ty.tag()) { 29635 .u1 => return .u1_type, 29636 .u8 => return .u8_type, 29637 .i8 => return .i8_type, 29638 .u16 => return .u16_type, 29639 .u29 => return .u29_type, 29640 .i16 => return .i16_type, 29641 .u32 => return .u32_type, 29642 .i32 => return .i32_type, 29643 .u64 => return .u64_type, 29644 .i64 => return .i64_type, 29645 .u128 => return .u128_type, 29646 .i128 => return .i128_type, 29647 .usize => return .usize_type, 29648 .isize => return .isize_type, 29649 .c_short => return .c_short_type, 29650 .c_ushort => return .c_ushort_type, 29651 .c_int => return .c_int_type, 29652 .c_uint => return .c_uint_type, 29653 .c_long => return .c_long_type, 29654 .c_ulong => return .c_ulong_type, 29655 .c_longlong => return .c_longlong_type, 29656 .c_ulonglong => return .c_ulonglong_type, 29657 .c_longdouble => return .c_longdouble_type, 29658 .f16 => return .f16_type, 29659 .f32 => return .f32_type, 29660 .f64 => return .f64_type, 29661 .f80 => return .f80_type, 29662 .f128 => return .f128_type, 29663 .anyopaque => return .anyopaque_type, 29664 .bool => return .bool_type, 29665 .void => return .void_type, 29666 .type => return .type_type, 29667 .anyerror => return .anyerror_type, 29668 .comptime_int => return .comptime_int_type, 29669 .comptime_float => return .comptime_float_type, 29670 .noreturn => return .noreturn_type, 29671 .@"anyframe" => return .anyframe_type, 29672 .@"null" => return .null_type, 29673 .@"undefined" => return .undefined_type, 29674 .enum_literal => return .enum_literal_type, 29675 .atomic_order => return .atomic_order_type, 29676 .atomic_rmw_op => return .atomic_rmw_op_type, 29677 .calling_convention => return .calling_convention_type, 29678 .address_space => return .address_space_type, 29679 .float_mode => return .float_mode_type, 29680 .reduce_op => return .reduce_op_type, 29681 .call_options => return .call_options_type, 29682 .prefetch_options => return .prefetch_options_type, 29683 .export_options => return .export_options_type, 29684 .extern_options => return .extern_options_type, 29685 .type_info => return .type_info_type, 29686 .manyptr_u8 => return .manyptr_u8_type, 29687 .manyptr_const_u8 => return .manyptr_const_u8_type, 29688 .fn_noreturn_no_args => return .fn_noreturn_no_args_type, 29689 .fn_void_no_args => return .fn_void_no_args_type, 29690 .fn_naked_noreturn_no_args => return .fn_naked_noreturn_no_args_type, 29691 .fn_ccc_void_no_args => return .fn_ccc_void_no_args_type, 29692 .single_const_pointer_to_comptime_int => return .single_const_pointer_to_comptime_int_type, 29693 .const_slice_u8 => return .const_slice_u8_type, 29694 .anyerror_void_error_union => return .anyerror_void_error_union_type, 29695 .generic_poison => return .generic_poison_type, 29696 else => {}, 29697 } 29698 try sema.air_instructions.append(sema.gpa, .{ 29699 .tag = .const_ty, 29700 .data = .{ .ty = ty }, 29701 }); 29702 return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); 29703 } 29704 29705 fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref { 29706 return sema.addConstant(ty, try Value.Tag.int_u64.create(sema.arena, int)); 29707 } 29708 29709 fn addBool(sema: *Sema, ty: Type, boolean: bool) CompileError!Air.Inst.Ref { 29710 return switch (ty.zigTypeTag()) { 29711 .Vector => sema.addConstant(ty, try Value.Tag.repeated.create(sema.arena, Value.makeBool(boolean))), 29712 .Bool => try sema.resolveInst(if (boolean) .bool_true else .bool_false), 29713 else => unreachable, 29714 }; 29715 } 29716 29717 fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref { 29718 return sema.addConstant(ty, Value.undef); 29719 } 29720 29721 pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref { 29722 const gpa = sema.gpa; 29723 const ty_inst = try sema.addType(ty); 29724 try sema.air_values.append(gpa, val); 29725 try sema.air_instructions.append(gpa, .{ 29726 .tag = .constant, 29727 .data = .{ .ty_pl = .{ 29728 .ty = ty_inst, 29729 .payload = @intCast(u32, sema.air_values.items.len - 1), 29730 } }, 29731 }); 29732 return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); 29733 } 29734 29735 pub fn addExtra(sema: *Sema, extra: anytype) Allocator.Error!u32 { 29736 const fields = std.meta.fields(@TypeOf(extra)); 29737 try sema.air_extra.ensureUnusedCapacity(sema.gpa, fields.len); 29738 return addExtraAssumeCapacity(sema, extra); 29739 } 29740 29741 pub fn addExtraAssumeCapacity(sema: *Sema, extra: anytype) u32 { 29742 const fields = std.meta.fields(@TypeOf(extra)); 29743 const result = @intCast(u32, sema.air_extra.items.len); 29744 inline for (fields) |field| { 29745 sema.air_extra.appendAssumeCapacity(switch (field.field_type) { 29746 u32 => @field(extra, field.name), 29747 Air.Inst.Ref => @enumToInt(@field(extra, field.name)), 29748 i32 => @bitCast(u32, @field(extra, field.name)), 29749 else => @compileError("bad field type"), 29750 }); 29751 } 29752 return result; 29753 } 29754 29755 fn appendRefsAssumeCapacity(sema: *Sema, refs: []const Air.Inst.Ref) void { 29756 const coerced = @ptrCast([]const u32, refs); 29757 sema.air_extra.appendSliceAssumeCapacity(coerced); 29758 } 29759 29760 fn getBreakBlock(sema: *Sema, inst_index: Air.Inst.Index) ?Air.Inst.Index { 29761 const air_datas = sema.air_instructions.items(.data); 29762 const air_tags = sema.air_instructions.items(.tag); 29763 switch (air_tags[inst_index]) { 29764 .br => return air_datas[inst_index].br.block_inst, 29765 else => return null, 29766 } 29767 } 29768 29769 fn isComptimeKnown( 29770 sema: *Sema, 29771 block: *Block, 29772 src: LazySrcLoc, 29773 inst: Air.Inst.Ref, 29774 ) !bool { 29775 return (try sema.resolveMaybeUndefVal(block, src, inst)) != null; 29776 } 29777 29778 fn analyzeComptimeAlloc( 29779 sema: *Sema, 29780 block: *Block, 29781 var_type: Type, 29782 alignment: u32, 29783 src: LazySrcLoc, 29784 ) CompileError!Air.Inst.Ref { 29785 // Needed to make an anon decl with type `var_type` (the `finish()` call below). 29786 _ = try sema.typeHasOnePossibleValue(block, src, var_type); 29787 29788 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{ 29789 .pointee_type = var_type, 29790 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant), 29791 .@"align" = alignment, 29792 }); 29793 29794 var anon_decl = try block.startAnonDecl(src); 29795 defer anon_decl.deinit(); 29796 29797 const decl_index = try anon_decl.finish( 29798 try var_type.copy(anon_decl.arena()), 29799 // There will be stores before the first load, but they may be to sub-elements or 29800 // sub-fields. So we need to initialize with undef to allow the mechanism to expand 29801 // into fields/elements and have those overridden with stored values. 29802 Value.undef, 29803 alignment, 29804 ); 29805 const decl = sema.mod.declPtr(decl_index); 29806 decl.@"align" = alignment; 29807 29808 try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index); 29809 return sema.addConstant(ptr_type, try Value.Tag.decl_ref_mut.create(sema.arena, .{ 29810 .runtime_index = block.runtime_index, 29811 .decl_index = decl_index, 29812 })); 29813 } 29814 29815 /// The places where a user can specify an address space attribute 29816 pub const AddressSpaceContext = enum { 29817 /// A function is specified to be placed in a certain address space. 29818 function, 29819 29820 /// A (global) variable is specified to be placed in a certain address space. 29821 /// In contrast to .constant, these values (and thus the address space they will be 29822 /// placed in) are required to be mutable. 29823 variable, 29824 29825 /// A (global) constant value is specified to be placed in a certain address space. 29826 /// In contrast to .variable, values placed in this address space are not required to be mutable. 29827 constant, 29828 29829 /// A pointer is ascripted to point into a certain address space. 29830 pointer, 29831 }; 29832 29833 pub fn analyzeAddrspace( 29834 sema: *Sema, 29835 block: *Block, 29836 src: LazySrcLoc, 29837 zir_ref: Zir.Inst.Ref, 29838 ctx: AddressSpaceContext, 29839 ) !std.builtin.AddressSpace { 29840 const addrspace_tv = try sema.resolveInstConst(block, src, zir_ref, "addresspace must be comptime known"); 29841 const address_space = addrspace_tv.val.toEnum(std.builtin.AddressSpace); 29842 const target = sema.mod.getTarget(); 29843 const arch = target.cpu.arch; 29844 const is_gpu = arch == .nvptx or arch == .nvptx64; 29845 29846 const supported = switch (address_space) { 29847 .generic => true, 29848 .gs, .fs, .ss => (arch == .i386 or arch == .x86_64) and ctx == .pointer, 29849 // TODO: check that .shared and .local are left uninitialized 29850 .global, .param, .shared, .local => is_gpu, 29851 .constant => is_gpu and (ctx == .constant), 29852 }; 29853 29854 if (!supported) { 29855 // TODO error messages could be made more elaborate here 29856 const entity = switch (ctx) { 29857 .function => "functions", 29858 .variable => "mutable values", 29859 .constant => "constant values", 29860 .pointer => "pointers", 29861 }; 29862 return sema.fail( 29863 block, 29864 src, 29865 "{s} with address space '{s}' are not supported on {s}", 29866 .{ entity, @tagName(address_space), arch.genericName() }, 29867 ); 29868 } 29869 29870 return address_space; 29871 } 29872 29873 /// Asserts the value is a pointer and dereferences it. 29874 /// Returns `null` if the pointer contents cannot be loaded at comptime. 29875 fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value { 29876 const load_ty = ptr_ty.childType(); 29877 const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty, true); 29878 switch (res) { 29879 .runtime_load => return null, 29880 .val => |v| return v, 29881 .needed_well_defined => |ty| return sema.fail( 29882 block, 29883 src, 29884 "comptime dereference requires '{}' to have a well-defined layout, but it does not.", 29885 .{ty.fmt(sema.mod)}, 29886 ), 29887 .out_of_bounds => |ty| return sema.fail( 29888 block, 29889 src, 29890 "dereference of '{}' exceeds bounds of containing decl of type '{}'", 29891 .{ ptr_ty.fmt(sema.mod), ty.fmt(sema.mod) }, 29892 ), 29893 } 29894 } 29895 29896 const DerefResult = union(enum) { 29897 runtime_load, 29898 val: Value, 29899 needed_well_defined: Type, 29900 out_of_bounds: Type, 29901 }; 29902 29903 fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type, want_mutable: bool) CompileError!DerefResult { 29904 const target = sema.mod.getTarget(); 29905 const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) { 29906 error.RuntimeLoad => return DerefResult{ .runtime_load = {} }, 29907 else => |e| return e, 29908 }; 29909 29910 if (deref.pointee) |tv| { 29911 const coerce_in_mem_ok = 29912 (try sema.coerceInMemoryAllowed(block, load_ty, tv.ty, false, target, src, src)) == .ok or 29913 (try sema.coerceInMemoryAllowed(block, tv.ty, load_ty, false, target, src, src)) == .ok; 29914 if (coerce_in_mem_ok) { 29915 // We have a Value that lines up in virtual memory exactly with what we want to load, 29916 // and it is in-memory coercible to load_ty. It may be returned without modifications. 29917 if (deref.is_mutable and want_mutable) { 29918 // The decl whose value we are obtaining here may be overwritten with 29919 // a different value upon further semantic analysis, which would 29920 // invalidate this memory. So we must copy here. 29921 return DerefResult{ .val = try tv.val.copy(sema.arena) }; 29922 } 29923 return DerefResult{ .val = tv.val }; 29924 } 29925 } 29926 29927 // The type is not in-memory coercible or the direct dereference failed, so it must 29928 // be bitcast according to the pointer type we are performing the load through. 29929 if (!load_ty.hasWellDefinedLayout()) { 29930 return DerefResult{ .needed_well_defined = load_ty }; 29931 } 29932 29933 const load_sz = try sema.typeAbiSize(block, src, load_ty); 29934 29935 // Try the smaller bit-cast first, since that's more efficient than using the larger `parent` 29936 if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(block, src, tv.ty)) 29937 return DerefResult{ .val = try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0) }; 29938 29939 // If that fails, try to bit-cast from the largest parent value with a well-defined layout 29940 if (deref.parent) |parent| if (load_sz + parent.byte_offset <= try sema.typeAbiSize(block, src, parent.tv.ty)) 29941 return DerefResult{ .val = try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset) }; 29942 29943 if (deref.ty_without_well_defined_layout) |bad_ty| { 29944 // We got no parent for bit-casting, or the parent we got was too small. Either way, the problem 29945 // is that some type we encountered when de-referencing does not have a well-defined layout. 29946 return DerefResult{ .needed_well_defined = bad_ty }; 29947 } else { 29948 // If all encountered types had well-defined layouts, the parent is the root decl and it just 29949 // wasn't big enough for the load. 29950 return DerefResult{ .out_of_bounds = deref.parent.?.tv.ty }; 29951 } 29952 } 29953 29954 /// Used to convert a u64 value to a usize value, emitting a compile error if the number 29955 /// is too big to fit. 29956 fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError!usize { 29957 if (@bitSizeOf(u64) <= @bitSizeOf(usize)) return int; 29958 return std.math.cast(usize, int) orelse return sema.fail(block, src, "expression produces integer value '{d}' which is too big for this compiler implementation to handle", .{int}); 29959 } 29960 29961 /// For pointer-like optionals, it returns the pointer type. For pointers, 29962 /// the type is returned unmodified. 29963 /// This can return `error.AnalysisFail` because it sometimes requires resolving whether 29964 /// a type has zero bits, which can cause a "foo depends on itself" compile error. 29965 /// This logic must be kept in sync with `Type.isPtrLikeOptional`. 29966 fn typePtrOrOptionalPtrTy( 29967 sema: *Sema, 29968 block: *Block, 29969 ty: Type, 29970 buf: *Type.Payload.ElemType, 29971 src: LazySrcLoc, 29972 ) !?Type { 29973 switch (ty.tag()) { 29974 .optional_single_const_pointer, 29975 .optional_single_mut_pointer, 29976 .c_const_pointer, 29977 .c_mut_pointer, 29978 => return ty.optionalChild(buf), 29979 29980 .single_const_pointer_to_comptime_int, 29981 .single_const_pointer, 29982 .single_mut_pointer, 29983 .many_const_pointer, 29984 .many_mut_pointer, 29985 .manyptr_u8, 29986 .manyptr_const_u8, 29987 .manyptr_const_u8_sentinel_0, 29988 => return ty, 29989 29990 .pointer => switch (ty.ptrSize()) { 29991 .Slice => return null, 29992 .C => return ty.optionalChild(buf), 29993 else => return ty, 29994 }, 29995 29996 .inferred_alloc_const => unreachable, 29997 .inferred_alloc_mut => unreachable, 29998 29999 .optional => { 30000 const child_type = ty.optionalChild(buf); 30001 if (child_type.zigTypeTag() != .Pointer) return null; 30002 30003 const info = child_type.ptrInfo().data; 30004 switch (info.size) { 30005 .Slice, .C => return null, 30006 .Many, .One => { 30007 if (info.@"allowzero") return null; 30008 30009 // optionals of zero sized types behave like bools, not pointers 30010 if ((try sema.typeHasOnePossibleValue(block, src, child_type)) != null) { 30011 return null; 30012 } 30013 30014 return child_type; 30015 }, 30016 } 30017 }, 30018 30019 else => return null, 30020 } 30021 } 30022 30023 /// `generic_poison` will return false. 30024 /// This function returns false negatives when structs and unions are having their 30025 /// field types resolved. 30026 /// TODO assert the return value matches `ty.comptimeOnly` 30027 /// TODO merge these implementations together with the "advanced"/sema_kit pattern seen 30028 /// elsewhere in value.zig 30029 pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { 30030 return switch (ty.tag()) { 30031 .u1, 30032 .u8, 30033 .i8, 30034 .u16, 30035 .i16, 30036 .u29, 30037 .u32, 30038 .i32, 30039 .u64, 30040 .i64, 30041 .u128, 30042 .i128, 30043 .usize, 30044 .isize, 30045 .c_short, 30046 .c_ushort, 30047 .c_int, 30048 .c_uint, 30049 .c_long, 30050 .c_ulong, 30051 .c_longlong, 30052 .c_ulonglong, 30053 .c_longdouble, 30054 .f16, 30055 .f32, 30056 .f64, 30057 .f80, 30058 .f128, 30059 .anyopaque, 30060 .bool, 30061 .void, 30062 .anyerror, 30063 .noreturn, 30064 .@"anyframe", 30065 .@"null", 30066 .@"undefined", 30067 .atomic_order, 30068 .atomic_rmw_op, 30069 .calling_convention, 30070 .address_space, 30071 .float_mode, 30072 .reduce_op, 30073 .call_options, 30074 .prefetch_options, 30075 .export_options, 30076 .extern_options, 30077 .manyptr_u8, 30078 .manyptr_const_u8, 30079 .manyptr_const_u8_sentinel_0, 30080 .const_slice_u8, 30081 .const_slice_u8_sentinel_0, 30082 .anyerror_void_error_union, 30083 .empty_struct_literal, 30084 .empty_struct, 30085 .error_set, 30086 .error_set_single, 30087 .error_set_inferred, 30088 .error_set_merged, 30089 .@"opaque", 30090 .generic_poison, 30091 .array_u8, 30092 .array_u8_sentinel_0, 30093 .int_signed, 30094 .int_unsigned, 30095 .enum_simple, 30096 => false, 30097 30098 .single_const_pointer_to_comptime_int, 30099 .type, 30100 .comptime_int, 30101 .comptime_float, 30102 .enum_literal, 30103 .type_info, 30104 // These are function bodies, not function pointers. 30105 .fn_noreturn_no_args, 30106 .fn_void_no_args, 30107 .fn_naked_noreturn_no_args, 30108 .fn_ccc_void_no_args, 30109 .function, 30110 => true, 30111 30112 .var_args_param => unreachable, 30113 .inferred_alloc_mut => unreachable, 30114 .inferred_alloc_const => unreachable, 30115 .bound_fn => unreachable, 30116 30117 .array, 30118 .array_sentinel, 30119 .vector, 30120 => return sema.typeRequiresComptime(ty.childType()), 30121 30122 .pointer, 30123 .single_const_pointer, 30124 .single_mut_pointer, 30125 .many_const_pointer, 30126 .many_mut_pointer, 30127 .c_const_pointer, 30128 .c_mut_pointer, 30129 .const_slice, 30130 .mut_slice, 30131 => { 30132 const child_ty = ty.childType(); 30133 if (child_ty.zigTypeTag() == .Fn) { 30134 return child_ty.fnInfo().is_generic; 30135 } else { 30136 return sema.typeRequiresComptime(child_ty); 30137 } 30138 }, 30139 30140 .optional, 30141 .optional_single_mut_pointer, 30142 .optional_single_const_pointer, 30143 => { 30144 var buf: Type.Payload.ElemType = undefined; 30145 return sema.typeRequiresComptime(ty.optionalChild(&buf)); 30146 }, 30147 30148 .tuple, .anon_struct => { 30149 const tuple = ty.tupleFields(); 30150 for (tuple.types) |field_ty, i| { 30151 const have_comptime_val = tuple.values[i].tag() != .unreachable_value; 30152 if (!have_comptime_val and try sema.typeRequiresComptime(field_ty)) { 30153 return true; 30154 } 30155 } 30156 return false; 30157 }, 30158 30159 .@"struct" => { 30160 const struct_obj = ty.castTag(.@"struct").?.data; 30161 switch (struct_obj.requires_comptime) { 30162 .no, .wip => return false, 30163 .yes => return true, 30164 .unknown => { 30165 if (struct_obj.status == .field_types_wip) 30166 return false; 30167 30168 try sema.resolveTypeFieldsStruct(ty, struct_obj); 30169 30170 struct_obj.requires_comptime = .wip; 30171 for (struct_obj.fields.values()) |field| { 30172 if (field.is_comptime) continue; 30173 if (try sema.typeRequiresComptime(field.ty)) { 30174 struct_obj.requires_comptime = .yes; 30175 return true; 30176 } 30177 } 30178 struct_obj.requires_comptime = .no; 30179 return false; 30180 }, 30181 } 30182 }, 30183 30184 .@"union", .union_safety_tagged, .union_tagged => { 30185 const union_obj = ty.cast(Type.Payload.Union).?.data; 30186 switch (union_obj.requires_comptime) { 30187 .no, .wip => return false, 30188 .yes => return true, 30189 .unknown => { 30190 if (union_obj.status == .field_types_wip) 30191 return false; 30192 30193 try sema.resolveTypeFieldsUnion(ty, union_obj); 30194 30195 union_obj.requires_comptime = .wip; 30196 for (union_obj.fields.values()) |field| { 30197 if (try sema.typeRequiresComptime(field.ty)) { 30198 union_obj.requires_comptime = .yes; 30199 return true; 30200 } 30201 } 30202 union_obj.requires_comptime = .no; 30203 return false; 30204 }, 30205 } 30206 }, 30207 30208 .error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()), 30209 .anyframe_T => { 30210 const child_ty = ty.castTag(.anyframe_T).?.data; 30211 return sema.typeRequiresComptime(child_ty); 30212 }, 30213 .enum_numbered => { 30214 const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty; 30215 return sema.typeRequiresComptime(tag_ty); 30216 }, 30217 .enum_full, .enum_nonexhaustive => { 30218 const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty; 30219 return sema.typeRequiresComptime(tag_ty); 30220 }, 30221 }; 30222 } 30223 30224 pub fn typeHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { 30225 return ty.hasRuntimeBitsAdvanced(false, sema.kit(block, src)); 30226 } 30227 30228 fn typeAbiSize(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u64 { 30229 try sema.resolveTypeLayout(block, src, ty); 30230 const target = sema.mod.getTarget(); 30231 return ty.abiSize(target); 30232 } 30233 30234 fn typeAbiAlignment(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!u32 { 30235 const target = sema.mod.getTarget(); 30236 return (try ty.abiAlignmentAdvanced(target, .{ .sema_kit = sema.kit(block, src) })).scalar; 30237 } 30238 30239 /// Not valid to call for packed unions. 30240 /// Keep implementation in sync with `Module.Union.Field.normalAlignment`. 30241 fn unionFieldAlignment( 30242 sema: *Sema, 30243 block: *Block, 30244 src: LazySrcLoc, 30245 field: Module.Union.Field, 30246 ) !u32 { 30247 if (field.ty.zigTypeTag() == .NoReturn) { 30248 return @as(u32, 0); 30249 } else if (field.abi_align == 0) { 30250 return sema.typeAbiAlignment(block, src, field.ty); 30251 } else { 30252 return field.abi_align; 30253 } 30254 } 30255 30256 /// Synchronize logic with `Type.isFnOrHasRuntimeBits`. 30257 pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { 30258 const fn_info = ty.fnInfo(); 30259 if (fn_info.is_generic) return false; 30260 if (fn_info.is_var_args) return true; 30261 switch (fn_info.cc) { 30262 // If there was a comptime calling convention, it should also return false here. 30263 .Inline => return false, 30264 else => {}, 30265 } 30266 if (try sema.typeRequiresComptime(fn_info.return_type)) { 30267 return false; 30268 } 30269 return true; 30270 } 30271 30272 fn unionFieldIndex( 30273 sema: *Sema, 30274 block: *Block, 30275 unresolved_union_ty: Type, 30276 field_name: []const u8, 30277 field_src: LazySrcLoc, 30278 ) !u32 { 30279 const union_ty = try sema.resolveTypeFields(block, field_src, unresolved_union_ty); 30280 const union_obj = union_ty.cast(Type.Payload.Union).?.data; 30281 const field_index_usize = union_obj.fields.getIndex(field_name) orelse 30282 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); 30283 return @intCast(u32, field_index_usize); 30284 } 30285 30286 fn structFieldIndex( 30287 sema: *Sema, 30288 block: *Block, 30289 unresolved_struct_ty: Type, 30290 field_name: []const u8, 30291 field_src: LazySrcLoc, 30292 ) !u32 { 30293 const struct_ty = try sema.resolveTypeFields(block, field_src, unresolved_struct_ty); 30294 if (struct_ty.isAnonStruct()) { 30295 return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src); 30296 } else { 30297 const struct_obj = struct_ty.castTag(.@"struct").?.data; 30298 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse 30299 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); 30300 return @intCast(u32, field_index_usize); 30301 } 30302 } 30303 30304 fn anonStructFieldIndex( 30305 sema: *Sema, 30306 block: *Block, 30307 struct_ty: Type, 30308 field_name: []const u8, 30309 field_src: LazySrcLoc, 30310 ) !u32 { 30311 const anon_struct = struct_ty.castTag(.anon_struct).?.data; 30312 for (anon_struct.names) |name, i| { 30313 if (mem.eql(u8, name, field_name)) { 30314 return @intCast(u32, i); 30315 } 30316 } 30317 return sema.fail(block, field_src, "no field named '{s}' in anonymous struct '{}'", .{ 30318 field_name, struct_ty.fmt(sema.mod), 30319 }); 30320 } 30321 30322 fn kit(sema: *Sema, block: *Block, src: LazySrcLoc) Module.WipAnalysis { 30323 return .{ .sema = sema, .block = block, .src = src }; 30324 } 30325 30326 fn queueFullTypeResolution(sema: *Sema, ty: Type) !void { 30327 const inst_ref = try sema.addType(ty); 30328 try sema.types_to_resolve.append(sema.gpa, inst_ref); 30329 } 30330 30331 fn intAdd(sema: *Sema, block: *Block, src: LazySrcLoc, lhs: Value, rhs: Value, ty: Type) !Value { 30332 if (ty.zigTypeTag() == .Vector) { 30333 const result_data = try sema.arena.alloc(Value, ty.vectorLen()); 30334 for (result_data) |*scalar, i| { 30335 scalar.* = try sema.intAddScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i)); 30336 } 30337 return Value.Tag.aggregate.create(sema.arena, result_data); 30338 } 30339 return sema.intAddScalar(block, src, lhs, rhs); 30340 } 30341 30342 fn intAddScalar(sema: *Sema, block: *Block, src: LazySrcLoc, lhs: Value, rhs: Value) !Value { 30343 // TODO is this a performance issue? maybe we should try the operation without 30344 // resorting to BigInt first. 30345 var lhs_space: Value.BigIntSpace = undefined; 30346 var rhs_space: Value.BigIntSpace = undefined; 30347 const target = sema.mod.getTarget(); 30348 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, src)); 30349 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, src)); 30350 const limbs = try sema.arena.alloc( 30351 std.math.big.Limb, 30352 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, 30353 ); 30354 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; 30355 result_bigint.add(lhs_bigint, rhs_bigint); 30356 return Value.fromBigInt(sema.arena, result_bigint.toConst()); 30357 } 30358 30359 /// Supports both (vectors of) floats and ints; handles undefined scalars. 30360 fn numberAddWrap( 30361 sema: *Sema, 30362 block: *Block, 30363 src: LazySrcLoc, 30364 lhs: Value, 30365 rhs: Value, 30366 ty: Type, 30367 ) !Value { 30368 if (ty.zigTypeTag() == .Vector) { 30369 const result_data = try sema.arena.alloc(Value, ty.vectorLen()); 30370 for (result_data) |*scalar, i| { 30371 scalar.* = try sema.numberAddWrapScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType()); 30372 } 30373 return Value.Tag.aggregate.create(sema.arena, result_data); 30374 } 30375 return sema.numberAddWrapScalar(block, src, lhs, rhs, ty); 30376 } 30377 30378 /// Supports both floats and ints; handles undefined. 30379 fn numberAddWrapScalar( 30380 sema: *Sema, 30381 block: *Block, 30382 src: LazySrcLoc, 30383 lhs: Value, 30384 rhs: Value, 30385 ty: Type, 30386 ) !Value { 30387 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); 30388 30389 if (ty.zigTypeTag() == .ComptimeInt) { 30390 return sema.intAdd(block, src, lhs, rhs, ty); 30391 } 30392 30393 if (ty.isAnyFloat()) { 30394 return sema.floatAdd(lhs, rhs, ty); 30395 } 30396 30397 const overflow_result = try sema.intAddWithOverflow(block, src, lhs, rhs, ty); 30398 return overflow_result.wrapped_result; 30399 } 30400 30401 fn intSub( 30402 sema: *Sema, 30403 block: *Block, 30404 src: LazySrcLoc, 30405 lhs: Value, 30406 rhs: Value, 30407 ty: Type, 30408 ) !Value { 30409 if (ty.zigTypeTag() == .Vector) { 30410 const result_data = try sema.arena.alloc(Value, ty.vectorLen()); 30411 for (result_data) |*scalar, i| { 30412 scalar.* = try sema.intSubScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i)); 30413 } 30414 return Value.Tag.aggregate.create(sema.arena, result_data); 30415 } 30416 return sema.intSubScalar(block, src, lhs, rhs); 30417 } 30418 30419 fn intSubScalar(sema: *Sema, block: *Block, src: LazySrcLoc, lhs: Value, rhs: Value) !Value { 30420 // TODO is this a performance issue? maybe we should try the operation without 30421 // resorting to BigInt first. 30422 var lhs_space: Value.BigIntSpace = undefined; 30423 var rhs_space: Value.BigIntSpace = undefined; 30424 const target = sema.mod.getTarget(); 30425 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, src)); 30426 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, src)); 30427 const limbs = try sema.arena.alloc( 30428 std.math.big.Limb, 30429 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, 30430 ); 30431 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; 30432 result_bigint.sub(lhs_bigint, rhs_bigint); 30433 return Value.fromBigInt(sema.arena, result_bigint.toConst()); 30434 } 30435 30436 /// Supports both (vectors of) floats and ints; handles undefined scalars. 30437 fn numberSubWrap( 30438 sema: *Sema, 30439 block: *Block, 30440 src: LazySrcLoc, 30441 lhs: Value, 30442 rhs: Value, 30443 ty: Type, 30444 ) !Value { 30445 if (ty.zigTypeTag() == .Vector) { 30446 const result_data = try sema.arena.alloc(Value, ty.vectorLen()); 30447 for (result_data) |*scalar, i| { 30448 scalar.* = try sema.numberSubWrapScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType()); 30449 } 30450 return Value.Tag.aggregate.create(sema.arena, result_data); 30451 } 30452 return sema.numberSubWrapScalar(block, src, lhs, rhs, ty); 30453 } 30454 30455 /// Supports both floats and ints; handles undefined. 30456 fn numberSubWrapScalar( 30457 sema: *Sema, 30458 block: *Block, 30459 src: LazySrcLoc, 30460 lhs: Value, 30461 rhs: Value, 30462 ty: Type, 30463 ) !Value { 30464 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); 30465 30466 if (ty.zigTypeTag() == .ComptimeInt) { 30467 return sema.intSub(block, src, lhs, rhs, ty); 30468 } 30469 30470 if (ty.isAnyFloat()) { 30471 return sema.floatSub(lhs, rhs, ty); 30472 } 30473 30474 const overflow_result = try sema.intSubWithOverflow(block, src, lhs, rhs, ty); 30475 return overflow_result.wrapped_result; 30476 } 30477 30478 fn floatAdd( 30479 sema: *Sema, 30480 lhs: Value, 30481 rhs: Value, 30482 float_type: Type, 30483 ) !Value { 30484 if (float_type.zigTypeTag() == .Vector) { 30485 const result_data = try sema.arena.alloc(Value, float_type.vectorLen()); 30486 for (result_data) |*scalar, i| { 30487 scalar.* = try sema.floatAddScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType()); 30488 } 30489 return Value.Tag.aggregate.create(sema.arena, result_data); 30490 } 30491 return sema.floatAddScalar(lhs, rhs, float_type); 30492 } 30493 30494 fn floatAddScalar( 30495 sema: *Sema, 30496 lhs: Value, 30497 rhs: Value, 30498 float_type: Type, 30499 ) !Value { 30500 const target = sema.mod.getTarget(); 30501 switch (float_type.floatBits(target)) { 30502 16 => { 30503 const lhs_val = lhs.toFloat(f16); 30504 const rhs_val = rhs.toFloat(f16); 30505 return Value.Tag.float_16.create(sema.arena, lhs_val + rhs_val); 30506 }, 30507 32 => { 30508 const lhs_val = lhs.toFloat(f32); 30509 const rhs_val = rhs.toFloat(f32); 30510 return Value.Tag.float_32.create(sema.arena, lhs_val + rhs_val); 30511 }, 30512 64 => { 30513 const lhs_val = lhs.toFloat(f64); 30514 const rhs_val = rhs.toFloat(f64); 30515 return Value.Tag.float_64.create(sema.arena, lhs_val + rhs_val); 30516 }, 30517 80 => { 30518 const lhs_val = lhs.toFloat(f80); 30519 const rhs_val = rhs.toFloat(f80); 30520 return Value.Tag.float_80.create(sema.arena, lhs_val + rhs_val); 30521 }, 30522 128 => { 30523 const lhs_val = lhs.toFloat(f128); 30524 const rhs_val = rhs.toFloat(f128); 30525 return Value.Tag.float_128.create(sema.arena, lhs_val + rhs_val); 30526 }, 30527 else => unreachable, 30528 } 30529 } 30530 30531 fn floatSub( 30532 sema: *Sema, 30533 lhs: Value, 30534 rhs: Value, 30535 float_type: Type, 30536 ) !Value { 30537 if (float_type.zigTypeTag() == .Vector) { 30538 const result_data = try sema.arena.alloc(Value, float_type.vectorLen()); 30539 for (result_data) |*scalar, i| { 30540 scalar.* = try sema.floatSubScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType()); 30541 } 30542 return Value.Tag.aggregate.create(sema.arena, result_data); 30543 } 30544 return sema.floatSubScalar(lhs, rhs, float_type); 30545 } 30546 30547 fn floatSubScalar( 30548 sema: *Sema, 30549 lhs: Value, 30550 rhs: Value, 30551 float_type: Type, 30552 ) !Value { 30553 const target = sema.mod.getTarget(); 30554 switch (float_type.floatBits(target)) { 30555 16 => { 30556 const lhs_val = lhs.toFloat(f16); 30557 const rhs_val = rhs.toFloat(f16); 30558 return Value.Tag.float_16.create(sema.arena, lhs_val - rhs_val); 30559 }, 30560 32 => { 30561 const lhs_val = lhs.toFloat(f32); 30562 const rhs_val = rhs.toFloat(f32); 30563 return Value.Tag.float_32.create(sema.arena, lhs_val - rhs_val); 30564 }, 30565 64 => { 30566 const lhs_val = lhs.toFloat(f64); 30567 const rhs_val = rhs.toFloat(f64); 30568 return Value.Tag.float_64.create(sema.arena, lhs_val - rhs_val); 30569 }, 30570 80 => { 30571 const lhs_val = lhs.toFloat(f80); 30572 const rhs_val = rhs.toFloat(f80); 30573 return Value.Tag.float_80.create(sema.arena, lhs_val - rhs_val); 30574 }, 30575 128 => { 30576 const lhs_val = lhs.toFloat(f128); 30577 const rhs_val = rhs.toFloat(f128); 30578 return Value.Tag.float_128.create(sema.arena, lhs_val - rhs_val); 30579 }, 30580 else => unreachable, 30581 } 30582 } 30583 30584 fn intSubWithOverflow( 30585 sema: *Sema, 30586 block: *Block, 30587 src: LazySrcLoc, 30588 lhs: Value, 30589 rhs: Value, 30590 ty: Type, 30591 ) !Value.OverflowArithmeticResult { 30592 if (ty.zigTypeTag() == .Vector) { 30593 const overflowed_data = try sema.arena.alloc(Value, ty.vectorLen()); 30594 const result_data = try sema.arena.alloc(Value, ty.vectorLen()); 30595 for (result_data) |*scalar, i| { 30596 const of_math_result = try sema.intSubWithOverflowScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType()); 30597 overflowed_data[i] = of_math_result.overflowed; 30598 scalar.* = of_math_result.wrapped_result; 30599 } 30600 return Value.OverflowArithmeticResult{ 30601 .overflowed = try Value.Tag.aggregate.create(sema.arena, overflowed_data), 30602 .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data), 30603 }; 30604 } 30605 return sema.intSubWithOverflowScalar(block, src, lhs, rhs, ty); 30606 } 30607 30608 fn intSubWithOverflowScalar( 30609 sema: *Sema, 30610 block: *Block, 30611 src: LazySrcLoc, 30612 lhs: Value, 30613 rhs: Value, 30614 ty: Type, 30615 ) !Value.OverflowArithmeticResult { 30616 const target = sema.mod.getTarget(); 30617 const info = ty.intInfo(target); 30618 30619 var lhs_space: Value.BigIntSpace = undefined; 30620 var rhs_space: Value.BigIntSpace = undefined; 30621 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, src)); 30622 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, src)); 30623 const limbs = try sema.arena.alloc( 30624 std.math.big.Limb, 30625 std.math.big.int.calcTwosCompLimbCount(info.bits), 30626 ); 30627 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; 30628 const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); 30629 const wrapped_result = try Value.fromBigInt(sema.arena, result_bigint.toConst()); 30630 return Value.OverflowArithmeticResult{ 30631 .overflowed = Value.makeBool(overflowed), 30632 .wrapped_result = wrapped_result, 30633 }; 30634 } 30635 30636 fn floatToInt( 30637 sema: *Sema, 30638 block: *Block, 30639 src: LazySrcLoc, 30640 val: Value, 30641 float_ty: Type, 30642 int_ty: Type, 30643 ) CompileError!Value { 30644 if (float_ty.zigTypeTag() == .Vector) { 30645 const elem_ty = float_ty.childType(); 30646 const result_data = try sema.arena.alloc(Value, float_ty.vectorLen()); 30647 for (result_data) |*scalar, i| { 30648 scalar.* = try sema.floatToIntScalar(block, src, val.indexVectorlike(i), elem_ty, int_ty.scalarType()); 30649 } 30650 return Value.Tag.aggregate.create(sema.arena, result_data); 30651 } 30652 return sema.floatToIntScalar(block, src, val, float_ty, int_ty); 30653 } 30654 30655 fn floatToIntScalar( 30656 sema: *Sema, 30657 block: *Block, 30658 src: LazySrcLoc, 30659 val: Value, 30660 float_ty: Type, 30661 int_ty: Type, 30662 ) CompileError!Value { 30663 const Limb = std.math.big.Limb; 30664 30665 const float = val.toFloat(f128); 30666 if (std.math.isNan(float)) { 30667 return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{ 30668 int_ty.fmt(sema.mod), 30669 }); 30670 } 30671 if (std.math.isInf(float)) { 30672 return sema.fail(block, src, "float value Inf cannot be stored in integer type '{}'", .{ 30673 int_ty.fmt(sema.mod), 30674 }); 30675 } 30676 30677 const is_negative = std.math.signbit(float); 30678 const floored = @floor(@fabs(float)); 30679 30680 var rational = try std.math.big.Rational.init(sema.arena); 30681 defer rational.deinit(); 30682 rational.setFloat(f128, floored) catch |err| switch (err) { 30683 error.NonFiniteFloat => unreachable, 30684 error.OutOfMemory => return error.OutOfMemory, 30685 }; 30686 30687 // The float is reduced in rational.setFloat, so we assert that denominator is equal to one 30688 const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true }; 30689 assert(rational.q.toConst().eqAbs(big_one)); 30690 30691 const result_limbs = try sema.arena.dupe(Limb, rational.p.toConst().limbs); 30692 const result = if (is_negative) 30693 try Value.Tag.int_big_negative.create(sema.arena, result_limbs) 30694 else 30695 try Value.Tag.int_big_positive.create(sema.arena, result_limbs); 30696 30697 if (!(try sema.intFitsInType(block, src, result, int_ty, null))) { 30698 return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{ 30699 val.fmtValue(float_ty, sema.mod), int_ty.fmt(sema.mod), 30700 }); 30701 } 30702 return result; 30703 } 30704 30705 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int. 30706 /// Vectors are also accepted. Vector results are reduced with AND. 30707 fn intFitsInType( 30708 sema: *Sema, 30709 block: *Block, 30710 src: LazySrcLoc, 30711 val: Value, 30712 ty: Type, 30713 vector_index: ?*usize, 30714 ) CompileError!bool { 30715 const target = sema.mod.getTarget(); 30716 switch (val.tag()) { 30717 .zero, 30718 .undef, 30719 .bool_false, 30720 => return true, 30721 30722 .one, 30723 .bool_true, 30724 => switch (ty.zigTypeTag()) { 30725 .Int => { 30726 const info = ty.intInfo(target); 30727 return switch (info.signedness) { 30728 .signed => info.bits >= 2, 30729 .unsigned => info.bits >= 1, 30730 }; 30731 }, 30732 .ComptimeInt => return true, 30733 else => unreachable, 30734 }, 30735 30736 .lazy_align => switch (ty.zigTypeTag()) { 30737 .Int => { 30738 const info = ty.intInfo(target); 30739 const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed); 30740 // If it is u16 or bigger we know the alignment fits without resolving it. 30741 if (info.bits >= max_needed_bits) return true; 30742 const x = try sema.typeAbiAlignment(block, src, val.castTag(.lazy_align).?.data); 30743 if (x == 0) return true; 30744 const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); 30745 return info.bits >= actual_needed_bits; 30746 }, 30747 .ComptimeInt => return true, 30748 else => unreachable, 30749 }, 30750 .lazy_size => switch (ty.zigTypeTag()) { 30751 .Int => { 30752 const info = ty.intInfo(target); 30753 const max_needed_bits = @as(u16, 64) + @boolToInt(info.signedness == .signed); 30754 // If it is u64 or bigger we know the size fits without resolving it. 30755 if (info.bits >= max_needed_bits) return true; 30756 const x = try sema.typeAbiSize(block, src, val.castTag(.lazy_size).?.data); 30757 if (x == 0) return true; 30758 const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); 30759 return info.bits >= actual_needed_bits; 30760 }, 30761 .ComptimeInt => return true, 30762 else => unreachable, 30763 }, 30764 30765 .int_u64 => switch (ty.zigTypeTag()) { 30766 .Int => { 30767 const x = val.castTag(.int_u64).?.data; 30768 if (x == 0) return true; 30769 const info = ty.intInfo(target); 30770 const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); 30771 return info.bits >= needed_bits; 30772 }, 30773 .ComptimeInt => return true, 30774 else => unreachable, 30775 }, 30776 .int_i64 => switch (ty.zigTypeTag()) { 30777 .Int => { 30778 const x = val.castTag(.int_i64).?.data; 30779 if (x == 0) return true; 30780 const info = ty.intInfo(target); 30781 if (info.signedness == .unsigned and x < 0) 30782 return false; 30783 var buffer: Value.BigIntSpace = undefined; 30784 return (try val.toBigIntAdvanced(&buffer, target, sema.kit(block, src))).fitsInTwosComp(info.signedness, info.bits); 30785 }, 30786 .ComptimeInt => return true, 30787 else => unreachable, 30788 }, 30789 .int_big_positive => switch (ty.zigTypeTag()) { 30790 .Int => { 30791 const info = ty.intInfo(target); 30792 return val.castTag(.int_big_positive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits); 30793 }, 30794 .ComptimeInt => return true, 30795 else => unreachable, 30796 }, 30797 .int_big_negative => switch (ty.zigTypeTag()) { 30798 .Int => { 30799 const info = ty.intInfo(target); 30800 return val.castTag(.int_big_negative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits); 30801 }, 30802 .ComptimeInt => return true, 30803 else => unreachable, 30804 }, 30805 30806 .the_only_possible_value => { 30807 assert(ty.intInfo(target).bits == 0); 30808 return true; 30809 }, 30810 30811 .decl_ref_mut, 30812 .extern_fn, 30813 .decl_ref, 30814 .function, 30815 .variable, 30816 => switch (ty.zigTypeTag()) { 30817 .Int => { 30818 const info = ty.intInfo(target); 30819 const ptr_bits = target.cpu.arch.ptrBitWidth(); 30820 return switch (info.signedness) { 30821 .signed => info.bits > ptr_bits, 30822 .unsigned => info.bits >= ptr_bits, 30823 }; 30824 }, 30825 .ComptimeInt => return true, 30826 else => unreachable, 30827 }, 30828 30829 .aggregate => { 30830 assert(ty.zigTypeTag() == .Vector); 30831 for (val.castTag(.aggregate).?.data) |elem, i| { 30832 if (!(try sema.intFitsInType(block, src, elem, ty.scalarType(), null))) { 30833 if (vector_index) |some| some.* = i; 30834 return false; 30835 } 30836 } 30837 return true; 30838 }, 30839 30840 else => unreachable, 30841 } 30842 } 30843 30844 fn intInRange( 30845 sema: *Sema, 30846 block: *Block, 30847 src: LazySrcLoc, 30848 tag_ty: Type, 30849 int_val: Value, 30850 end: usize, 30851 ) !bool { 30852 if (try int_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) return false; 30853 var end_payload: Value.Payload.U64 = .{ 30854 .base = .{ .tag = .int_u64 }, 30855 .data = end, 30856 }; 30857 const end_val = Value.initPayload(&end_payload.base); 30858 if (try sema.compare(block, src, int_val, .gte, end_val, tag_ty)) return false; 30859 return true; 30860 } 30861 30862 /// Asserts the type is an enum. 30863 fn enumHasInt( 30864 sema: *Sema, 30865 block: *Block, 30866 src: LazySrcLoc, 30867 ty: Type, 30868 int: Value, 30869 ) CompileError!bool { 30870 switch (ty.tag()) { 30871 .enum_nonexhaustive => return sema.intFitsInType(block, src, int, ty, null), 30872 .enum_full => { 30873 const enum_full = ty.castTag(.enum_full).?.data; 30874 const tag_ty = enum_full.tag_ty; 30875 if (enum_full.values.count() == 0) { 30876 return intInRange(sema, block, src, tag_ty, int, enum_full.fields.count()); 30877 } else { 30878 return enum_full.values.containsContext(int, .{ 30879 .ty = tag_ty, 30880 .mod = sema.mod, 30881 }); 30882 } 30883 }, 30884 .enum_numbered => { 30885 const enum_obj = ty.castTag(.enum_numbered).?.data; 30886 const tag_ty = enum_obj.tag_ty; 30887 if (enum_obj.values.count() == 0) { 30888 return intInRange(sema, block, src, tag_ty, int, enum_obj.fields.count()); 30889 } else { 30890 return enum_obj.values.containsContext(int, .{ 30891 .ty = tag_ty, 30892 .mod = sema.mod, 30893 }); 30894 } 30895 }, 30896 .enum_simple => { 30897 const enum_simple = ty.castTag(.enum_simple).?.data; 30898 const fields_len = enum_simple.fields.count(); 30899 const bits = std.math.log2_int_ceil(usize, fields_len); 30900 var buffer: Type.Payload.Bits = .{ 30901 .base = .{ .tag = .int_unsigned }, 30902 .data = bits, 30903 }; 30904 const tag_ty = Type.initPayload(&buffer.base); 30905 return intInRange(sema, block, src, tag_ty, int, fields_len); 30906 }, 30907 .atomic_order, 30908 .atomic_rmw_op, 30909 .calling_convention, 30910 .address_space, 30911 .float_mode, 30912 .reduce_op, 30913 .call_options, 30914 .prefetch_options, 30915 .export_options, 30916 .extern_options, 30917 => unreachable, 30918 30919 else => unreachable, 30920 } 30921 } 30922 30923 fn intAddWithOverflow( 30924 sema: *Sema, 30925 block: *Block, 30926 src: LazySrcLoc, 30927 lhs: Value, 30928 rhs: Value, 30929 ty: Type, 30930 ) !Value.OverflowArithmeticResult { 30931 if (ty.zigTypeTag() == .Vector) { 30932 const overflowed_data = try sema.arena.alloc(Value, ty.vectorLen()); 30933 const result_data = try sema.arena.alloc(Value, ty.vectorLen()); 30934 for (result_data) |*scalar, i| { 30935 const of_math_result = try sema.intAddWithOverflowScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType()); 30936 overflowed_data[i] = of_math_result.overflowed; 30937 scalar.* = of_math_result.wrapped_result; 30938 } 30939 return Value.OverflowArithmeticResult{ 30940 .overflowed = try Value.Tag.aggregate.create(sema.arena, overflowed_data), 30941 .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data), 30942 }; 30943 } 30944 return sema.intAddWithOverflowScalar(block, src, lhs, rhs, ty); 30945 } 30946 30947 fn intAddWithOverflowScalar( 30948 sema: *Sema, 30949 block: *Block, 30950 src: LazySrcLoc, 30951 lhs: Value, 30952 rhs: Value, 30953 ty: Type, 30954 ) !Value.OverflowArithmeticResult { 30955 const target = sema.mod.getTarget(); 30956 const info = ty.intInfo(target); 30957 30958 var lhs_space: Value.BigIntSpace = undefined; 30959 var rhs_space: Value.BigIntSpace = undefined; 30960 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, src)); 30961 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, src)); 30962 const limbs = try sema.arena.alloc( 30963 std.math.big.Limb, 30964 std.math.big.int.calcTwosCompLimbCount(info.bits), 30965 ); 30966 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; 30967 const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); 30968 const result = try Value.fromBigInt(sema.arena, result_bigint.toConst()); 30969 return Value.OverflowArithmeticResult{ 30970 .overflowed = Value.makeBool(overflowed), 30971 .wrapped_result = result, 30972 }; 30973 } 30974 30975 /// Asserts the values are comparable. Both operands have type `ty`. 30976 /// Vector results will be reduced with AND. 30977 fn compare( 30978 sema: *Sema, 30979 block: *Block, 30980 src: LazySrcLoc, 30981 lhs: Value, 30982 op: std.math.CompareOperator, 30983 rhs: Value, 30984 ty: Type, 30985 ) CompileError!bool { 30986 if (ty.zigTypeTag() == .Vector) { 30987 var i: usize = 0; 30988 while (i < ty.vectorLen()) : (i += 1) { 30989 if (!(try sema.compareScalar(block, src, lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType()))) { 30990 return false; 30991 } 30992 } 30993 return true; 30994 } 30995 return sema.compareScalar(block, src, lhs, op, rhs, ty); 30996 } 30997 30998 /// Asserts the values are comparable. Both operands have type `ty`. 30999 fn compareScalar( 31000 sema: *Sema, 31001 block: *Block, 31002 src: LazySrcLoc, 31003 lhs: Value, 31004 op: std.math.CompareOperator, 31005 rhs: Value, 31006 ty: Type, 31007 ) CompileError!bool { 31008 switch (op) { 31009 .eq => return sema.valuesEqual(block, src, lhs, rhs, ty), 31010 .neq => return !(try sema.valuesEqual(block, src, lhs, rhs, ty)), 31011 else => return Value.compareHeteroAdvanced(lhs, op, rhs, sema.mod.getTarget(), sema.kit(block, src)), 31012 } 31013 } 31014 31015 fn valuesEqual( 31016 sema: *Sema, 31017 block: *Block, 31018 src: LazySrcLoc, 31019 lhs: Value, 31020 rhs: Value, 31021 ty: Type, 31022 ) CompileError!bool { 31023 return Value.eqlAdvanced(lhs, ty, rhs, ty, sema.mod, sema.kit(block, src)); 31024 } 31025 31026 /// Asserts the values are comparable vectors of type `ty`. 31027 fn compareVector( 31028 sema: *Sema, 31029 block: *Block, 31030 src: LazySrcLoc, 31031 lhs: Value, 31032 op: std.math.CompareOperator, 31033 rhs: Value, 31034 ty: Type, 31035 ) !Value { 31036 assert(ty.zigTypeTag() == .Vector); 31037 const result_data = try sema.arena.alloc(Value, ty.vectorLen()); 31038 for (result_data) |*scalar, i| { 31039 const res_bool = try sema.compareScalar(block, src, lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType()); 31040 scalar.* = Value.makeBool(res_bool); 31041 } 31042 return Value.Tag.aggregate.create(sema.arena, result_data); 31043 } 31044 31045 /// Returns the type of a pointer to an element. 31046 /// Asserts that the type is a pointer, and that the element type is indexable. 31047 /// For *[N]T, return *T 31048 /// For [*]T, returns *T 31049 /// For []T, returns *T 31050 /// Handles const-ness and address spaces in particular. 31051 /// This code is duplicated in `analyzePtrArithmetic`. 31052 fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { 31053 const ptr_info = ptr_ty.ptrInfo().data; 31054 const elem_ty = ptr_ty.elemType2(); 31055 const allow_zero = ptr_info.@"allowzero" and (offset orelse 0) == 0; 31056 const alignment: u32 = a: { 31057 // Calculate the new pointer alignment. 31058 if (ptr_info.@"align" == 0) { 31059 // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness. 31060 break :a 0; 31061 } 31062 // If the addend is not a comptime-known value we can still count on 31063 // it being a multiple of the type size. 31064 const target = sema.mod.getTarget(); 31065 const elem_size = elem_ty.abiSize(target); 31066 const addend = if (offset) |off| elem_size * off else elem_size; 31067 31068 // The resulting pointer is aligned to the lcd between the offset (an 31069 // arbitrary number) and the alignment factor (always a power of two, 31070 // non zero). 31071 const new_align = @as(u32, 1) << @intCast(u5, @ctz(addend | ptr_info.@"align")); 31072 break :a new_align; 31073 }; 31074 return try Type.ptr(sema.arena, sema.mod, .{ 31075 .pointee_type = elem_ty, 31076 .mutable = ptr_info.mutable, 31077 .@"addrspace" = ptr_info.@"addrspace", 31078 .@"allowzero" = allow_zero, 31079 .@"volatile" = ptr_info.@"volatile", 31080 .@"align" = alignment, 31081 }); 31082 }