zig

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

blob 320627a1 (248069B) - Raw


      1 //! Compilation of all Zig source code is represented by one `Module`.
      2 //! Each `Compilation` has exactly one or zero `Module`, depending on whether
      3 //! there is or is not any zig source code, respectively.
      4 
      5 const std = @import("std");
      6 const builtin = @import("builtin");
      7 const mem = std.mem;
      8 const Allocator = std.mem.Allocator;
      9 const ArrayListUnmanaged = std.ArrayListUnmanaged;
     10 const assert = std.debug.assert;
     11 const log = std.log.scoped(.module);
     12 const BigIntConst = std.math.big.int.Const;
     13 const BigIntMutable = std.math.big.int.Mutable;
     14 const Target = std.Target;
     15 const Ast = std.zig.Ast;
     16 const LazySrcLoc = std.zig.LazySrcLoc;
     17 
     18 /// Deprecated, use `Zcu`.
     19 const Module = Zcu;
     20 const Zcu = @This();
     21 const Compilation = @import("Compilation.zig");
     22 const Cache = std.Build.Cache;
     23 const Value = @import("Value.zig");
     24 const Type = @import("type.zig").Type;
     25 const Package = @import("Package.zig");
     26 const link = @import("link.zig");
     27 const Air = @import("Air.zig");
     28 const Zir = std.zig.Zir;
     29 const trace = @import("tracy.zig").trace;
     30 const AstGen = std.zig.AstGen;
     31 const Sema = @import("Sema.zig");
     32 const target_util = @import("target.zig");
     33 const build_options = @import("build_options");
     34 const Liveness = @import("Liveness.zig");
     35 const isUpDir = @import("introspect.zig").isUpDir;
     36 const clang = @import("clang.zig");
     37 const InternPool = @import("InternPool.zig");
     38 const Alignment = InternPool.Alignment;
     39 const BuiltinFn = std.zig.BuiltinFn;
     40 const LlvmObject = @import("codegen/llvm.zig").Object;
     41 
     42 comptime {
     43     @setEvalBranchQuota(4000);
     44     for (
     45         @typeInfo(Zir.Inst.Ref).Enum.fields,
     46         @typeInfo(Air.Inst.Ref).Enum.fields,
     47         @typeInfo(InternPool.Index).Enum.fields,
     48     ) |zir_field, air_field, ip_field| {
     49         assert(mem.eql(u8, zir_field.name, ip_field.name));
     50         assert(mem.eql(u8, air_field.name, ip_field.name));
     51     }
     52 }
     53 
     54 /// General-purpose allocator. Used for both temporary and long-term storage.
     55 gpa: Allocator,
     56 comp: *Compilation,
     57 /// Usually, the LlvmObject is managed by linker code, however, in the case
     58 /// that -fno-emit-bin is specified, the linker code never executes, so we
     59 /// store the LlvmObject here.
     60 llvm_object: ?*LlvmObject,
     61 
     62 /// Pointer to externally managed resource.
     63 root_mod: *Package.Module,
     64 /// Normally, `main_mod` and `root_mod` are the same. The exception is `zig test`, in which
     65 /// `root_mod` is the test runner, and `main_mod` is the user's source file which has the tests.
     66 main_mod: *Package.Module,
     67 std_mod: *Package.Module,
     68 sema_prog_node: std.Progress.Node = undefined,
     69 
     70 /// Used by AstGen worker to load and store ZIR cache.
     71 global_zir_cache: Compilation.Directory,
     72 /// Used by AstGen worker to load and store ZIR cache.
     73 local_zir_cache: Compilation.Directory,
     74 /// It's rare for a decl to be exported, so we save memory by having a sparse
     75 /// map of Decl indexes to details about them being exported.
     76 /// The Export memory is owned by the `export_owners` table; the slice itself
     77 /// is owned by this table. The slice is guaranteed to not be empty.
     78 decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{},
     79 /// Same as `decl_exports` but for exported constant values.
     80 value_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, ArrayListUnmanaged(*Export)) = .{},
     81 /// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl
     82 /// is modified. Note that the key of this table is not the Decl being exported, but the Decl that
     83 /// is performing the export of another Decl.
     84 /// This table owns the Export memory.
     85 export_owners: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{},
     86 /// The set of all the Zig source files in the Module. We keep track of this in order
     87 /// to iterate over it and check which source files have been modified on the file system when
     88 /// an update is requested, as well as to cache `@import` results.
     89 /// Keys are fully resolved file paths. This table owns the keys and values.
     90 import_table: std.StringArrayHashMapUnmanaged(*File) = .{},
     91 /// The set of all the files which have been loaded with `@embedFile` in the Module.
     92 /// We keep track of this in order to iterate over it and check which files have been
     93 /// modified on the file system when an update is requested, as well as to cache
     94 /// `@embedFile` results.
     95 /// Keys are fully resolved file paths. This table owns the keys and values.
     96 embed_table: std.StringArrayHashMapUnmanaged(*EmbedFile) = .{},
     97 
     98 /// Stores all Type and Value objects.
     99 /// The idea is that this will be periodically garbage-collected, but such logic
    100 /// is not yet implemented.
    101 intern_pool: InternPool = .{},
    102 
    103 /// We optimize memory usage for a compilation with no compile errors by storing the
    104 /// error messages and mapping outside of `Decl`.
    105 /// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.
    106 /// Note that a Decl can succeed but the Fn it represents can fail. In this case,
    107 /// a Decl can have a failed_decls entry but have analysis status of success.
    108 failed_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, *ErrorMsg) = .{},
    109 /// Keep track of one `@compileLog` callsite per owner Decl.
    110 /// The value is the AST node index offset from the Decl.
    111 compile_log_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, i32) = .{},
    112 /// Using a map here for consistency with the other fields here.
    113 /// The ErrorMsg memory is owned by the `File`, using Module's general purpose allocator.
    114 failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .{},
    115 /// The ErrorMsg memory is owned by the `EmbedFile`, using Module's general purpose allocator.
    116 failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .{},
    117 /// Using a map here for consistency with the other fields here.
    118 /// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
    119 failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
    120 /// If a decl failed due to a cimport error, the corresponding Clang errors
    121 /// are stored here.
    122 cimport_errors: std.AutoArrayHashMapUnmanaged(Decl.Index, std.zig.ErrorBundle) = .{},
    123 
    124 /// Key is the error name, index is the error tag value. Index 0 has a length-0 string.
    125 global_error_set: GlobalErrorSet = .{},
    126 
    127 /// Maximum amount of distinct error values, set by --error-limit
    128 error_limit: ErrorInt,
    129 
    130 /// Value is the number of PO or outdated Decls which this Depender depends on.
    131 potentially_outdated: std.AutoArrayHashMapUnmanaged(InternPool.Depender, u32) = .{},
    132 /// Value is the number of PO or outdated Decls which this Depender depends on.
    133 /// Once this value drops to 0, the Depender is a candidate for re-analysis.
    134 outdated: std.AutoArrayHashMapUnmanaged(InternPool.Depender, u32) = .{},
    135 /// This contains all `Depender`s in `outdated` whose PO dependency count is 0.
    136 /// Such `Depender`s are ready for immediate re-analysis.
    137 /// See `findOutdatedToAnalyze` for details.
    138 outdated_ready: std.AutoArrayHashMapUnmanaged(InternPool.Depender, void) = .{},
    139 /// This contains a set of Decls which may not be in `outdated`, but are the
    140 /// root Decls of files which have updated source and thus must be re-analyzed.
    141 /// If such a Decl is only in this set, the struct type index may be preserved
    142 /// (only the namespace might change). If such a Decl is also `outdated`, the
    143 /// struct type index must be recreated.
    144 outdated_file_root: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
    145 /// This contains a list of Dependers whose analysis or codegen failed, but the
    146 /// failure was something like running out of disk space, and trying again may
    147 /// succeed. On the next update, we will flush this list, marking all members of
    148 /// it as outdated.
    149 retryable_failures: std.ArrayListUnmanaged(InternPool.Depender) = .{},
    150 
    151 stage1_flags: packed struct {
    152     have_winmain: bool = false,
    153     have_wwinmain: bool = false,
    154     have_winmain_crt_startup: bool = false,
    155     have_wwinmain_crt_startup: bool = false,
    156     have_dllmain_crt_startup: bool = false,
    157     have_c_main: bool = false,
    158     reserved: u2 = 0,
    159 } = .{},
    160 
    161 compile_log_text: ArrayListUnmanaged(u8) = .{},
    162 
    163 emit_h: ?*GlobalEmitH,
    164 
    165 test_functions: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
    166 
    167 global_assembly: std.AutoArrayHashMapUnmanaged(Decl.Index, []u8) = .{},
    168 
    169 reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct {
    170     referencer: Decl.Index,
    171     src: LazySrcLoc,
    172 }) = .{},
    173 
    174 panic_messages: [PanicId.len]Decl.OptionalIndex = .{.none} ** PanicId.len,
    175 /// The panic function body.
    176 panic_func_index: InternPool.Index = .none,
    177 null_stack_trace: InternPool.Index = .none,
    178 
    179 pub const PanicId = enum {
    180     unreach,
    181     unwrap_null,
    182     cast_to_null,
    183     incorrect_alignment,
    184     invalid_error_code,
    185     cast_truncated_data,
    186     negative_to_unsigned,
    187     integer_overflow,
    188     shl_overflow,
    189     shr_overflow,
    190     divide_by_zero,
    191     exact_division_remainder,
    192     inactive_union_field,
    193     integer_part_out_of_bounds,
    194     corrupt_switch,
    195     shift_rhs_too_big,
    196     invalid_enum_value,
    197     sentinel_mismatch,
    198     unwrap_error,
    199     index_out_of_bounds,
    200     start_index_greater_than_end,
    201     for_len_mismatch,
    202     memcpy_len_mismatch,
    203     memcpy_alias,
    204     noreturn_returned,
    205 
    206     pub const len = @typeInfo(PanicId).Enum.fields.len;
    207 };
    208 
    209 pub const GlobalErrorSet = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void);
    210 
    211 pub const CImportError = struct {
    212     offset: u32,
    213     line: u32,
    214     column: u32,
    215     path: ?[*:0]u8,
    216     source_line: ?[*:0]u8,
    217     msg: [*:0]u8,
    218 
    219     pub fn deinit(err: CImportError, gpa: Allocator) void {
    220         if (err.path) |some| gpa.free(std.mem.span(some));
    221         if (err.source_line) |some| gpa.free(std.mem.span(some));
    222         gpa.free(std.mem.span(err.msg));
    223     }
    224 };
    225 
    226 /// A `Module` has zero or one of these depending on whether `-femit-h` is enabled.
    227 pub const GlobalEmitH = struct {
    228     /// Where to put the output.
    229     loc: Compilation.EmitLoc,
    230     /// When emit_h is non-null, each Decl gets one more compile error slot for
    231     /// emit-h failing for that Decl. This table is also how we tell if a Decl has
    232     /// failed emit-h or succeeded.
    233     failed_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, *ErrorMsg) = .{},
    234     /// Tracks all decls in order to iterate over them and emit .h code for them.
    235     decl_table: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
    236     /// Similar to the allocated_decls field of Module, this is where `EmitH` objects
    237     /// are allocated. There will be exactly one EmitH object per Decl object, with
    238     /// identical indexes.
    239     allocated_emit_h: std.SegmentedList(EmitH, 0) = .{},
    240 
    241     pub fn declPtr(global_emit_h: *GlobalEmitH, decl_index: Decl.Index) *EmitH {
    242         return global_emit_h.allocated_emit_h.at(@intFromEnum(decl_index));
    243     }
    244 };
    245 
    246 pub const ErrorInt = u32;
    247 
    248 pub const Exported = union(enum) {
    249     /// The Decl being exported. Note this is *not* the Decl performing the export.
    250     decl_index: Decl.Index,
    251     /// Constant value being exported.
    252     value: InternPool.Index,
    253 };
    254 
    255 pub const Export = struct {
    256     opts: Options,
    257     src: LazySrcLoc,
    258     /// The Decl that performs the export. Note that this is *not* the Decl being exported.
    259     owner_decl: Decl.Index,
    260     /// The Decl containing the export statement.  Inline function calls
    261     /// may cause this to be different from the owner_decl.
    262     src_decl: Decl.Index,
    263     exported: Exported,
    264     status: enum {
    265         in_progress,
    266         failed,
    267         /// Indicates that the failure was due to a temporary issue, such as an I/O error
    268         /// when writing to the output file. Retrying the export may succeed.
    269         failed_retryable,
    270         complete,
    271     },
    272 
    273     pub const Options = struct {
    274         name: InternPool.NullTerminatedString,
    275         linkage: std.builtin.GlobalLinkage = .strong,
    276         section: InternPool.OptionalNullTerminatedString = .none,
    277         visibility: std.builtin.SymbolVisibility = .default,
    278     };
    279 
    280     pub fn getSrcLoc(exp: Export, mod: *Module) SrcLoc {
    281         const src_decl = mod.declPtr(exp.src_decl);
    282         return .{
    283             .file_scope = src_decl.getFileScope(mod),
    284             .parent_decl_node = src_decl.src_node,
    285             .lazy = exp.src,
    286         };
    287     }
    288 };
    289 
    290 const ValueArena = struct {
    291     state: std.heap.ArenaAllocator.State,
    292     state_acquired: ?*std.heap.ArenaAllocator.State = null,
    293 
    294     /// If this ValueArena replaced an existing one during re-analysis, this is the previous instance
    295     prev: ?*ValueArena = null,
    296 
    297     /// Returns an allocator backed by either promoting `state`, or by the existing ArenaAllocator
    298     /// that has already promoted `state`. `out_arena_allocator` provides storage for the initial promotion,
    299     /// and must live until the matching call to release().
    300     pub fn acquire(self: *ValueArena, child_allocator: Allocator, out_arena_allocator: *std.heap.ArenaAllocator) Allocator {
    301         if (self.state_acquired) |state_acquired| {
    302             return @as(*std.heap.ArenaAllocator, @fieldParentPtr("state", state_acquired)).allocator();
    303         }
    304 
    305         out_arena_allocator.* = self.state.promote(child_allocator);
    306         self.state_acquired = &out_arena_allocator.state;
    307         return out_arena_allocator.allocator();
    308     }
    309 
    310     /// Releases the allocator acquired by `acquire. `arena_allocator` must match the one passed to `acquire`.
    311     pub fn release(self: *ValueArena, arena_allocator: *std.heap.ArenaAllocator) void {
    312         if (@as(*std.heap.ArenaAllocator, @fieldParentPtr("state", self.state_acquired.?)) == arena_allocator) {
    313             self.state = self.state_acquired.?.*;
    314             self.state_acquired = null;
    315         }
    316     }
    317 
    318     pub fn deinit(self: ValueArena, child_allocator: Allocator) void {
    319         assert(self.state_acquired == null);
    320 
    321         const prev = self.prev;
    322         self.state.promote(child_allocator).deinit();
    323 
    324         if (prev) |p| {
    325             p.deinit(child_allocator);
    326         }
    327     }
    328 };
    329 
    330 pub const Decl = struct {
    331     name: InternPool.NullTerminatedString,
    332     /// The most recent Value of the Decl after a successful semantic analysis.
    333     /// Populated when `has_tv`.
    334     val: Value,
    335     /// Populated when `has_tv`.
    336     @"linksection": InternPool.OptionalNullTerminatedString,
    337     /// Populated when `has_tv`.
    338     alignment: Alignment,
    339     /// Populated when `has_tv`.
    340     @"addrspace": std.builtin.AddressSpace,
    341     /// The direct parent namespace of the Decl. In the case of the Decl
    342     /// corresponding to a file, this is the namespace of the struct, since
    343     /// there is no parent.
    344     src_namespace: Namespace.Index,
    345 
    346     /// The AST node index of this declaration.
    347     /// Must be recomputed when the corresponding source file is modified.
    348     src_node: Ast.Node.Index,
    349     /// Line number corresponding to `src_node`. Stored separately so that source files
    350     /// do not need to be loaded into memory in order to compute debug line numbers.
    351     /// This value is absolute.
    352     src_line: u32,
    353     /// Index of the ZIR `declaration` instruction from which this `Decl` was created.
    354     /// For the root `Decl` of a `File` and legacy anonymous decls, this is `.none`.
    355     zir_decl_index: InternPool.TrackedInst.Index.Optional,
    356 
    357     /// Represents the "shallow" analysis status. For example, for decls that are functions,
    358     /// the function type is analyzed with this set to `in_progress`, however, the semantic
    359     /// analysis of the function body is performed with this value set to `success`. Functions
    360     /// have their own analysis status field.
    361     analysis: enum {
    362         /// This Decl corresponds to an AST Node that has not been referenced yet, and therefore
    363         /// because of Zig's lazy declaration analysis, it will remain unanalyzed until referenced.
    364         unreferenced,
    365         /// Semantic analysis for this Decl is running right now.
    366         /// This state detects dependency loops.
    367         in_progress,
    368         /// The file corresponding to this Decl had a parse error or ZIR error.
    369         /// There will be a corresponding ErrorMsg in Zcu.failed_files.
    370         file_failure,
    371         /// This Decl might be OK but it depends on another one which did not
    372         /// successfully complete semantic analysis.
    373         dependency_failure,
    374         /// Semantic analysis failure.
    375         /// There will be a corresponding ErrorMsg in Zcu.failed_decls.
    376         sema_failure,
    377         /// There will be a corresponding ErrorMsg in Zcu.failed_decls.
    378         codegen_failure,
    379         /// Sematic analysis and constant value codegen of this Decl has
    380         /// succeeded. However, the Decl may be outdated due to an in-progress
    381         /// update. Note that for a function, this does not mean codegen of the
    382         /// function body succeded: that state is indicated by the function's
    383         /// `analysis` field.
    384         complete,
    385     },
    386     /// Whether `typed_value`, `align`, `linksection` and `addrspace` are populated.
    387     has_tv: bool,
    388     /// If `true` it means the `Decl` is the resource owner of the type/value associated
    389     /// with it. That means when `Decl` is destroyed, the cleanup code should additionally
    390     /// check if the value owns a `Namespace`, and destroy that too.
    391     owns_tv: bool,
    392     /// Whether the corresponding AST decl has a `pub` keyword.
    393     is_pub: bool,
    394     /// Whether the corresponding AST decl has a `export` keyword.
    395     is_exported: bool,
    396     /// If true `name` is already fully qualified.
    397     name_fully_qualified: bool = false,
    398     /// What kind of a declaration is this.
    399     kind: Kind,
    400 
    401     pub const Kind = enum {
    402         @"usingnamespace",
    403         @"test",
    404         @"comptime",
    405         named,
    406         anon,
    407     };
    408 
    409     const Index = InternPool.DeclIndex;
    410     const OptionalIndex = InternPool.OptionalDeclIndex;
    411 
    412     pub fn zirBodies(decl: Decl, zcu: *Zcu) Zir.Inst.Declaration.Bodies {
    413         const zir = decl.getFileScope(zcu).zir;
    414         const zir_index = decl.zir_decl_index.unwrap().?.resolve(&zcu.intern_pool);
    415         const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
    416         const extra = zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
    417         return extra.data.getBodies(@intCast(extra.end), zir);
    418     }
    419 
    420     pub fn relativeToNodeIndex(decl: Decl, offset: i32) Ast.Node.Index {
    421         return @bitCast(offset + @as(i32, @bitCast(decl.src_node)));
    422     }
    423 
    424     pub fn nodeIndexToRelative(decl: Decl, node_index: Ast.Node.Index) i32 {
    425         return @as(i32, @bitCast(node_index)) - @as(i32, @bitCast(decl.src_node));
    426     }
    427 
    428     pub fn srcLoc(decl: Decl, zcu: *Zcu) SrcLoc {
    429         return decl.nodeOffsetSrcLoc(0, zcu);
    430     }
    431 
    432     pub fn nodeOffsetSrcLoc(decl: Decl, node_offset: i32, zcu: *Zcu) SrcLoc {
    433         return .{
    434             .file_scope = decl.getFileScope(zcu),
    435             .parent_decl_node = decl.src_node,
    436             .lazy = LazySrcLoc.nodeOffset(node_offset),
    437         };
    438     }
    439 
    440     pub fn renderFullyQualifiedName(decl: Decl, zcu: *Zcu, writer: anytype) !void {
    441         if (decl.name_fully_qualified) {
    442             try writer.print("{}", .{decl.name.fmt(&zcu.intern_pool)});
    443         } else {
    444             try zcu.namespacePtr(decl.src_namespace).renderFullyQualifiedName(zcu, decl.name, writer);
    445         }
    446     }
    447 
    448     pub fn renderFullyQualifiedDebugName(decl: Decl, zcu: *Zcu, writer: anytype) !void {
    449         return zcu.namespacePtr(decl.src_namespace).renderFullyQualifiedDebugName(zcu, decl.name, writer);
    450     }
    451 
    452     pub fn fullyQualifiedName(decl: Decl, zcu: *Zcu) !InternPool.NullTerminatedString {
    453         return if (decl.name_fully_qualified)
    454             decl.name
    455         else
    456             zcu.namespacePtr(decl.src_namespace).fullyQualifiedName(zcu, decl.name);
    457     }
    458 
    459     pub fn typeOf(decl: Decl, zcu: *const Zcu) Type {
    460         assert(decl.has_tv);
    461         return decl.val.typeOf(zcu);
    462     }
    463 
    464     /// Small wrapper for Sema to use over direct access to the `val` field.
    465     /// If the value is not populated, instead returns `error.AnalysisFail`.
    466     pub fn valueOrFail(decl: Decl) error{AnalysisFail}!Value {
    467         if (!decl.has_tv) return error.AnalysisFail;
    468         return decl.val;
    469     }
    470 
    471     pub fn getOwnedFunction(decl: Decl, zcu: *Zcu) ?InternPool.Key.Func {
    472         const i = decl.getOwnedFunctionIndex();
    473         if (i == .none) return null;
    474         return switch (zcu.intern_pool.indexToKey(i)) {
    475             .func => |func| func,
    476             else => null,
    477         };
    478     }
    479 
    480     /// This returns an InternPool.Index even when the value is not a function.
    481     pub fn getOwnedFunctionIndex(decl: Decl) InternPool.Index {
    482         return if (decl.owns_tv) decl.val.toIntern() else .none;
    483     }
    484 
    485     /// If the Decl owns its value and it is an extern function, returns it,
    486     /// otherwise null.
    487     pub fn getOwnedExternFunc(decl: Decl, zcu: *Zcu) ?InternPool.Key.ExternFunc {
    488         return if (decl.owns_tv) decl.val.getExternFunc(zcu) else null;
    489     }
    490 
    491     /// If the Decl owns its value and it is a variable, returns it,
    492     /// otherwise null.
    493     pub fn getOwnedVariable(decl: Decl, zcu: *Zcu) ?InternPool.Key.Variable {
    494         return if (decl.owns_tv) decl.val.getVariable(zcu) else null;
    495     }
    496 
    497     /// Gets the namespace that this Decl creates by being a struct, union,
    498     /// enum, or opaque.
    499     pub fn getInnerNamespaceIndex(decl: Decl, zcu: *Zcu) Namespace.OptionalIndex {
    500         if (!decl.has_tv) return .none;
    501         const ip = &zcu.intern_pool;
    502         return switch (decl.val.ip_index) {
    503             .empty_struct_type => .none,
    504             .none => .none,
    505             else => switch (ip.indexToKey(decl.val.toIntern())) {
    506                 .opaque_type => ip.loadOpaqueType(decl.val.toIntern()).namespace,
    507                 .struct_type => ip.loadStructType(decl.val.toIntern()).namespace,
    508                 .union_type => ip.loadUnionType(decl.val.toIntern()).namespace,
    509                 .enum_type => ip.loadEnumType(decl.val.toIntern()).namespace,
    510                 else => .none,
    511             },
    512         };
    513     }
    514 
    515     /// Like `getInnerNamespaceIndex`, but only returns it if the Decl is the owner.
    516     pub fn getOwnedInnerNamespaceIndex(decl: Decl, zcu: *Zcu) Namespace.OptionalIndex {
    517         if (!decl.owns_tv) return .none;
    518         return decl.getInnerNamespaceIndex(zcu);
    519     }
    520 
    521     /// Same as `getOwnedInnerNamespaceIndex` but additionally obtains the pointer.
    522     pub fn getOwnedInnerNamespace(decl: Decl, zcu: *Zcu) ?*Namespace {
    523         return zcu.namespacePtrUnwrap(decl.getOwnedInnerNamespaceIndex(zcu));
    524     }
    525 
    526     /// Same as `getInnerNamespaceIndex` but additionally obtains the pointer.
    527     pub fn getInnerNamespace(decl: Decl, zcu: *Zcu) ?*Namespace {
    528         return zcu.namespacePtrUnwrap(decl.getInnerNamespaceIndex(zcu));
    529     }
    530 
    531     pub fn getFileScope(decl: Decl, zcu: *Zcu) *File {
    532         return zcu.namespacePtr(decl.src_namespace).file_scope;
    533     }
    534 
    535     pub fn getExternDecl(decl: Decl, zcu: *Zcu) OptionalIndex {
    536         assert(decl.has_tv);
    537         return switch (zcu.intern_pool.indexToKey(decl.val.toIntern())) {
    538             .variable => |variable| if (variable.is_extern) variable.decl.toOptional() else .none,
    539             .extern_func => |extern_func| extern_func.decl.toOptional(),
    540             else => .none,
    541         };
    542     }
    543 
    544     pub fn isExtern(decl: Decl, zcu: *Zcu) bool {
    545         return decl.getExternDecl(zcu) != .none;
    546     }
    547 
    548     pub fn getAlignment(decl: Decl, zcu: *Zcu) Alignment {
    549         assert(decl.has_tv);
    550         if (decl.alignment != .none) return decl.alignment;
    551         return decl.typeOf(zcu).abiAlignment(zcu);
    552     }
    553 
    554     /// Upgrade a `LazySrcLoc` to a `SrcLoc` based on the `Decl` provided.
    555     pub fn toSrcLoc(decl: *Decl, lazy: LazySrcLoc, mod: *Module) SrcLoc {
    556         return switch (lazy) {
    557             .unneeded,
    558             .entire_file,
    559             .byte_abs,
    560             .token_abs,
    561             .node_abs,
    562             => .{
    563                 .file_scope = decl.getFileScope(mod),
    564                 .parent_decl_node = 0,
    565                 .lazy = lazy,
    566             },
    567 
    568             .byte_offset,
    569             .token_offset,
    570             .node_offset,
    571             .node_offset_main_token,
    572             .node_offset_initializer,
    573             .node_offset_var_decl_ty,
    574             .node_offset_var_decl_align,
    575             .node_offset_var_decl_section,
    576             .node_offset_var_decl_addrspace,
    577             .node_offset_var_decl_init,
    578             .node_offset_builtin_call_arg0,
    579             .node_offset_builtin_call_arg1,
    580             .node_offset_builtin_call_arg2,
    581             .node_offset_builtin_call_arg3,
    582             .node_offset_builtin_call_arg4,
    583             .node_offset_builtin_call_arg5,
    584             .node_offset_ptrcast_operand,
    585             .node_offset_array_access_index,
    586             .node_offset_slice_ptr,
    587             .node_offset_slice_start,
    588             .node_offset_slice_end,
    589             .node_offset_slice_sentinel,
    590             .node_offset_call_func,
    591             .node_offset_field_name,
    592             .node_offset_field_name_init,
    593             .node_offset_deref_ptr,
    594             .node_offset_asm_source,
    595             .node_offset_asm_ret_ty,
    596             .node_offset_if_cond,
    597             .node_offset_bin_op,
    598             .node_offset_bin_lhs,
    599             .node_offset_bin_rhs,
    600             .node_offset_switch_operand,
    601             .node_offset_switch_special_prong,
    602             .node_offset_switch_range,
    603             .node_offset_switch_prong_capture,
    604             .node_offset_switch_prong_tag_capture,
    605             .node_offset_fn_type_align,
    606             .node_offset_fn_type_addrspace,
    607             .node_offset_fn_type_section,
    608             .node_offset_fn_type_cc,
    609             .node_offset_fn_type_ret_ty,
    610             .node_offset_param,
    611             .token_offset_param,
    612             .node_offset_anyframe_type,
    613             .node_offset_lib_name,
    614             .node_offset_array_type_len,
    615             .node_offset_array_type_sentinel,
    616             .node_offset_array_type_elem,
    617             .node_offset_un_op,
    618             .node_offset_ptr_elem,
    619             .node_offset_ptr_sentinel,
    620             .node_offset_ptr_align,
    621             .node_offset_ptr_addrspace,
    622             .node_offset_ptr_bitoffset,
    623             .node_offset_ptr_hostsize,
    624             .node_offset_container_tag,
    625             .node_offset_field_default,
    626             .node_offset_init_ty,
    627             .node_offset_store_ptr,
    628             .node_offset_store_operand,
    629             .node_offset_return_operand,
    630             .for_input,
    631             .for_capture_from_input,
    632             .array_cat_lhs,
    633             .array_cat_rhs,
    634             => .{
    635                 .file_scope = decl.getFileScope(mod),
    636                 .parent_decl_node = decl.src_node,
    637                 .lazy = lazy,
    638             },
    639             inline .call_arg,
    640             .fn_proto_param,
    641             => |x| .{
    642                 .file_scope = decl.getFileScope(mod),
    643                 .parent_decl_node = mod.declPtr(x.decl).src_node,
    644                 .lazy = lazy,
    645             },
    646         };
    647     }
    648 
    649     pub fn declPtrType(decl: Decl, zcu: *Zcu) !Type {
    650         assert(decl.has_tv);
    651         const decl_ty = decl.typeOf(zcu);
    652         return zcu.ptrType(.{
    653             .child = decl_ty.toIntern(),
    654             .flags = .{
    655                 .alignment = if (decl.alignment == decl_ty.abiAlignment(zcu))
    656                     .none
    657                 else
    658                     decl.alignment,
    659                 .address_space = decl.@"addrspace",
    660                 .is_const = decl.getOwnedVariable(zcu) == null,
    661             },
    662         });
    663     }
    664 };
    665 
    666 /// This state is attached to every Decl when Module emit_h is non-null.
    667 pub const EmitH = struct {
    668     fwd_decl: ArrayListUnmanaged(u8) = .{},
    669 };
    670 
    671 pub const DeclAdapter = struct {
    672     zcu: *Zcu,
    673 
    674     pub fn hash(self: @This(), s: InternPool.NullTerminatedString) u32 {
    675         _ = self;
    676         return std.hash.uint32(@intFromEnum(s));
    677     }
    678 
    679     pub fn eql(self: @This(), a: InternPool.NullTerminatedString, b_decl_index: Decl.Index, b_index: usize) bool {
    680         _ = b_index;
    681         return a == self.zcu.declPtr(b_decl_index).name;
    682     }
    683 };
    684 
    685 /// The container that structs, enums, unions, and opaques have.
    686 pub const Namespace = struct {
    687     parent: OptionalIndex,
    688     file_scope: *File,
    689     /// Will be a struct, enum, union, or opaque.
    690     decl_index: Decl.Index,
    691     /// Direct children of the namespace.
    692     /// Declaration order is preserved via entry order.
    693     /// These are only declarations named directly by the AST; anonymous
    694     /// declarations are not stored here.
    695     decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{},
    696     /// Key is usingnamespace Decl itself. To find the namespace being included,
    697     /// the Decl Value has to be resolved as a Type which has a Namespace.
    698     /// Value is whether the usingnamespace decl is marked `pub`.
    699     usingnamespace_set: std.AutoHashMapUnmanaged(Decl.Index, bool) = .{},
    700 
    701     const Index = InternPool.NamespaceIndex;
    702     const OptionalIndex = InternPool.OptionalNamespaceIndex;
    703 
    704     const DeclContext = struct {
    705         zcu: *Zcu,
    706 
    707         pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 {
    708             const decl = ctx.zcu.declPtr(decl_index);
    709             return std.hash.uint32(@intFromEnum(decl.name));
    710         }
    711 
    712         pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool {
    713             _ = b_index;
    714             const a_decl = ctx.zcu.declPtr(a_decl_index);
    715             const b_decl = ctx.zcu.declPtr(b_decl_index);
    716             return a_decl.name == b_decl.name;
    717         }
    718     };
    719 
    720     // This renders e.g. "std.fs.Dir.OpenOptions"
    721     pub fn renderFullyQualifiedName(
    722         ns: Namespace,
    723         zcu: *Zcu,
    724         name: InternPool.NullTerminatedString,
    725         writer: anytype,
    726     ) @TypeOf(writer).Error!void {
    727         if (ns.parent.unwrap()) |parent| {
    728             try zcu.namespacePtr(parent).renderFullyQualifiedName(
    729                 zcu,
    730                 zcu.declPtr(ns.decl_index).name,
    731                 writer,
    732             );
    733         } else {
    734             try ns.file_scope.renderFullyQualifiedName(writer);
    735         }
    736         if (name != .empty) try writer.print(".{}", .{name.fmt(&zcu.intern_pool)});
    737     }
    738 
    739     /// This renders e.g. "std/fs.zig:Dir.OpenOptions"
    740     pub fn renderFullyQualifiedDebugName(
    741         ns: Namespace,
    742         zcu: *Zcu,
    743         name: InternPool.NullTerminatedString,
    744         writer: anytype,
    745     ) @TypeOf(writer).Error!void {
    746         const sep: u8 = if (ns.parent.unwrap()) |parent| sep: {
    747             try zcu.namespacePtr(parent).renderFullyQualifiedDebugName(
    748                 zcu,
    749                 zcu.declPtr(ns.decl_index).name,
    750                 writer,
    751             );
    752             break :sep '.';
    753         } else sep: {
    754             try ns.file_scope.renderFullyQualifiedDebugName(writer);
    755             break :sep ':';
    756         };
    757         if (name != .empty) try writer.print("{c}{}", .{ sep, name.fmt(&zcu.intern_pool) });
    758     }
    759 
    760     pub fn fullyQualifiedName(
    761         ns: Namespace,
    762         zcu: *Zcu,
    763         name: InternPool.NullTerminatedString,
    764     ) !InternPool.NullTerminatedString {
    765         const ip = &zcu.intern_pool;
    766         const count = count: {
    767             var count: usize = name.length(ip) + 1;
    768             var cur_ns = &ns;
    769             while (true) {
    770                 const decl = zcu.declPtr(cur_ns.decl_index);
    771                 count += decl.name.length(ip) + 1;
    772                 cur_ns = zcu.namespacePtr(cur_ns.parent.unwrap() orelse {
    773                     count += ns.file_scope.sub_file_path.len;
    774                     break :count count;
    775                 });
    776             }
    777         };
    778 
    779         const gpa = zcu.gpa;
    780         const start = ip.string_bytes.items.len;
    781         // Protects reads of interned strings from being reallocated during the call to
    782         // renderFullyQualifiedName.
    783         try ip.string_bytes.ensureUnusedCapacity(gpa, count);
    784         ns.renderFullyQualifiedName(zcu, name, ip.string_bytes.writer(gpa)) catch unreachable;
    785 
    786         // Sanitize the name for nvptx which is more restrictive.
    787         // TODO This should be handled by the backend, not the frontend. Have a
    788         // look at how the C backend does it for inspiration.
    789         const cpu_arch = zcu.root_mod.resolved_target.result.cpu.arch;
    790         if (cpu_arch.isNvptx()) {
    791             for (ip.string_bytes.items[start..]) |*byte| switch (byte.*) {
    792                 '{', '}', '*', '[', ']', '(', ')', ',', ' ', '\'' => byte.* = '_',
    793                 else => {},
    794             };
    795         }
    796 
    797         return ip.getOrPutTrailingString(gpa, ip.string_bytes.items.len - start, .no_embedded_nulls);
    798     }
    799 
    800     pub fn getType(ns: Namespace, zcu: *Zcu) Type {
    801         const decl = zcu.declPtr(ns.decl_index);
    802         assert(decl.has_tv);
    803         return decl.val.toType();
    804     }
    805 };
    806 
    807 pub const File = struct {
    808     /// The Decl of the struct that represents this File.
    809     root_decl: Decl.OptionalIndex,
    810     status: enum {
    811         never_loaded,
    812         retryable_failure,
    813         parse_failure,
    814         astgen_failure,
    815         success_zir,
    816     },
    817     source_loaded: bool,
    818     tree_loaded: bool,
    819     zir_loaded: bool,
    820     /// Relative to the owning package's root_src_dir.
    821     /// Memory is stored in gpa, owned by File.
    822     sub_file_path: []const u8,
    823     /// Whether this is populated depends on `source_loaded`.
    824     source: [:0]const u8,
    825     /// Whether this is populated depends on `status`.
    826     stat: Cache.File.Stat,
    827     /// Whether this is populated or not depends on `tree_loaded`.
    828     tree: Ast,
    829     /// Whether this is populated or not depends on `zir_loaded`.
    830     zir: Zir,
    831     /// Module that this file is a part of, managed externally.
    832     mod: *Package.Module,
    833     /// Whether this file is a part of multiple packages. This is an error condition which will be reported after AstGen.
    834     multi_pkg: bool = false,
    835     /// List of references to this file, used for multi-package errors.
    836     references: std.ArrayListUnmanaged(Reference) = .{},
    837     /// The hash of the path to this file, used to store `InternPool.TrackedInst`.
    838     /// undefined until `zir_loaded == true`.
    839     path_digest: Cache.BinDigest = undefined,
    840 
    841     /// The most recent successful ZIR for this file, with no errors.
    842     /// This is only populated when a previously successful ZIR
    843     /// newly introduces compile errors during an update. When ZIR is
    844     /// successful, this field is unloaded.
    845     prev_zir: ?*Zir = null,
    846 
    847     /// A single reference to a file.
    848     pub const Reference = union(enum) {
    849         /// The file is imported directly (i.e. not as a package) with @import.
    850         import: SrcLoc,
    851         /// The file is the root of a module.
    852         root: *Package.Module,
    853     };
    854 
    855     pub fn unload(file: *File, gpa: Allocator) void {
    856         file.unloadTree(gpa);
    857         file.unloadSource(gpa);
    858         file.unloadZir(gpa);
    859     }
    860 
    861     pub fn unloadTree(file: *File, gpa: Allocator) void {
    862         if (file.tree_loaded) {
    863             file.tree_loaded = false;
    864             file.tree.deinit(gpa);
    865         }
    866     }
    867 
    868     pub fn unloadSource(file: *File, gpa: Allocator) void {
    869         if (file.source_loaded) {
    870             file.source_loaded = false;
    871             gpa.free(file.source);
    872         }
    873     }
    874 
    875     pub fn unloadZir(file: *File, gpa: Allocator) void {
    876         if (file.zir_loaded) {
    877             file.zir_loaded = false;
    878             file.zir.deinit(gpa);
    879         }
    880     }
    881 
    882     pub fn deinit(file: *File, mod: *Module) void {
    883         const gpa = mod.gpa;
    884         const is_builtin = file.mod.isBuiltin();
    885         log.debug("deinit File {s}", .{file.sub_file_path});
    886         if (is_builtin) {
    887             file.unloadTree(gpa);
    888             file.unloadZir(gpa);
    889         } else {
    890             gpa.free(file.sub_file_path);
    891             file.unload(gpa);
    892         }
    893         file.references.deinit(gpa);
    894         if (file.root_decl.unwrap()) |root_decl| {
    895             mod.destroyDecl(root_decl);
    896         }
    897         if (file.prev_zir) |prev_zir| {
    898             prev_zir.deinit(gpa);
    899             gpa.destroy(prev_zir);
    900         }
    901         file.* = undefined;
    902     }
    903 
    904     pub const Source = struct {
    905         bytes: [:0]const u8,
    906         stat: Cache.File.Stat,
    907     };
    908 
    909     pub fn getSource(file: *File, gpa: Allocator) !Source {
    910         if (file.source_loaded) return Source{
    911             .bytes = file.source,
    912             .stat = file.stat,
    913         };
    914 
    915         // Keep track of inode, file size, mtime, hash so we can detect which files
    916         // have been modified when an incremental update is requested.
    917         var f = try file.mod.root.openFile(file.sub_file_path, .{});
    918         defer f.close();
    919 
    920         const stat = try f.stat();
    921 
    922         if (stat.size > std.math.maxInt(u32))
    923             return error.FileTooBig;
    924 
    925         const source = try gpa.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);
    926         defer if (!file.source_loaded) gpa.free(source);
    927         const amt = try f.readAll(source);
    928         if (amt != stat.size)
    929             return error.UnexpectedEndOfFile;
    930 
    931         // Here we do not modify stat fields because this function is the one
    932         // used for error reporting. We need to keep the stat fields stale so that
    933         // astGenFile can know to regenerate ZIR.
    934 
    935         file.source = source;
    936         file.source_loaded = true;
    937         return Source{
    938             .bytes = source,
    939             .stat = .{
    940                 .size = stat.size,
    941                 .inode = stat.inode,
    942                 .mtime = stat.mtime,
    943             },
    944         };
    945     }
    946 
    947     pub fn getTree(file: *File, gpa: Allocator) !*const Ast {
    948         if (file.tree_loaded) return &file.tree;
    949 
    950         const source = try file.getSource(gpa);
    951         file.tree = try Ast.parse(gpa, source.bytes, .zig);
    952         file.tree_loaded = true;
    953         return &file.tree;
    954     }
    955 
    956     pub fn destroy(file: *File, mod: *Module) void {
    957         const gpa = mod.gpa;
    958         const is_builtin = file.mod.isBuiltin();
    959         file.deinit(mod);
    960         if (!is_builtin) gpa.destroy(file);
    961     }
    962 
    963     pub fn renderFullyQualifiedName(file: File, writer: anytype) !void {
    964         // Convert all the slashes into dots and truncate the extension.
    965         const ext = std.fs.path.extension(file.sub_file_path);
    966         const noext = file.sub_file_path[0 .. file.sub_file_path.len - ext.len];
    967         for (noext) |byte| switch (byte) {
    968             '/', '\\' => try writer.writeByte('.'),
    969             else => try writer.writeByte(byte),
    970         };
    971     }
    972 
    973     pub fn renderFullyQualifiedDebugName(file: File, writer: anytype) !void {
    974         for (file.sub_file_path) |byte| switch (byte) {
    975             '/', '\\' => try writer.writeByte('/'),
    976             else => try writer.writeByte(byte),
    977         };
    978     }
    979 
    980     pub fn fullyQualifiedName(file: File, mod: *Module) !InternPool.NullTerminatedString {
    981         const ip = &mod.intern_pool;
    982         const start = ip.string_bytes.items.len;
    983         try file.renderFullyQualifiedName(ip.string_bytes.writer(mod.gpa));
    984         return ip.getOrPutTrailingString(mod.gpa, ip.string_bytes.items.len - start, .no_embedded_nulls);
    985     }
    986 
    987     pub fn fullPath(file: File, ally: Allocator) ![]u8 {
    988         return file.mod.root.joinString(ally, file.sub_file_path);
    989     }
    990 
    991     pub fn dumpSrc(file: *File, src: LazySrcLoc) void {
    992         const loc = std.zig.findLineColumn(file.source.bytes, src);
    993         std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
    994     }
    995 
    996     pub fn okToReportErrors(file: File) bool {
    997         return switch (file.status) {
    998             .parse_failure, .astgen_failure => false,
    999             else => true,
   1000         };
   1001     }
   1002 
   1003     /// Add a reference to this file during AstGen.
   1004     pub fn addReference(file: *File, mod: Module, ref: Reference) !void {
   1005         // Don't add the same module root twice. Note that since we always add module roots at the
   1006         // front of the references array (see below), this loop is actually O(1) on valid code.
   1007         if (ref == .root) {
   1008             for (file.references.items) |other| {
   1009                 switch (other) {
   1010                     .root => |r| if (ref.root == r) return,
   1011                     else => break, // reached the end of the "is-root" references
   1012                 }
   1013             }
   1014         }
   1015 
   1016         switch (ref) {
   1017             // We put root references at the front of the list both to make the above loop fast and
   1018             // to make multi-module errors more helpful (since "root-of" notes are generally more
   1019             // informative than "imported-from" notes). This path is hit very rarely, so the speed
   1020             // of the insert operation doesn't matter too much.
   1021             .root => try file.references.insert(mod.gpa, 0, ref),
   1022 
   1023             // Other references we'll just put at the end.
   1024             else => try file.references.append(mod.gpa, ref),
   1025         }
   1026 
   1027         const pkg = switch (ref) {
   1028             .import => |loc| loc.file_scope.mod,
   1029             .root => |pkg| pkg,
   1030         };
   1031         if (pkg != file.mod) file.multi_pkg = true;
   1032     }
   1033 
   1034     /// Mark this file and every file referenced by it as multi_pkg and report an
   1035     /// astgen_failure error for them. AstGen must have completed in its entirety.
   1036     pub fn recursiveMarkMultiPkg(file: *File, mod: *Module) void {
   1037         file.multi_pkg = true;
   1038         file.status = .astgen_failure;
   1039 
   1040         // We can only mark children as failed if the ZIR is loaded, which may not
   1041         // be the case if there were other astgen failures in this file
   1042         if (!file.zir_loaded) return;
   1043 
   1044         const imports_index = file.zir.extra[@intFromEnum(Zir.ExtraIndex.imports)];
   1045         if (imports_index == 0) return;
   1046         const extra = file.zir.extraData(Zir.Inst.Imports, imports_index);
   1047 
   1048         var extra_index = extra.end;
   1049         for (0..extra.data.imports_len) |_| {
   1050             const item = file.zir.extraData(Zir.Inst.Imports.Item, extra_index);
   1051             extra_index = item.end;
   1052 
   1053             const import_path = file.zir.nullTerminatedString(item.data.name);
   1054             if (mem.eql(u8, import_path, "builtin")) continue;
   1055 
   1056             const res = mod.importFile(file, import_path) catch continue;
   1057             if (!res.is_pkg and !res.file.multi_pkg) {
   1058                 res.file.recursiveMarkMultiPkg(mod);
   1059             }
   1060         }
   1061     }
   1062 };
   1063 
   1064 pub const EmbedFile = struct {
   1065     /// Relative to the owning module's root directory.
   1066     sub_file_path: InternPool.NullTerminatedString,
   1067     /// Module that this file is a part of, managed externally.
   1068     owner: *Package.Module,
   1069     stat: Cache.File.Stat,
   1070     val: InternPool.Index,
   1071     src_loc: SrcLoc,
   1072 };
   1073 
   1074 /// This struct holds data necessary to construct API-facing `AllErrors.Message`.
   1075 /// Its memory is managed with the general purpose allocator so that they
   1076 /// can be created and destroyed in response to incremental updates.
   1077 /// In some cases, the File could have been inferred from where the ErrorMsg
   1078 /// is stored. For example, if it is stored in Module.failed_decls, then the File
   1079 /// would be determined by the Decl Scope. However, the data structure contains the field
   1080 /// anyway so that `ErrorMsg` can be reused for error notes, which may be in a different
   1081 /// file than the parent error message. It also simplifies processing of error messages.
   1082 pub const ErrorMsg = struct {
   1083     src_loc: SrcLoc,
   1084     msg: []const u8,
   1085     notes: []ErrorMsg = &.{},
   1086     reference_trace: []Trace = &.{},
   1087     hidden_references: u32 = 0,
   1088 
   1089     pub const Trace = struct {
   1090         decl: InternPool.NullTerminatedString,
   1091         src_loc: SrcLoc,
   1092     };
   1093 
   1094     pub fn create(
   1095         gpa: Allocator,
   1096         src_loc: SrcLoc,
   1097         comptime format: []const u8,
   1098         args: anytype,
   1099     ) !*ErrorMsg {
   1100         assert(src_loc.lazy != .unneeded);
   1101         const err_msg = try gpa.create(ErrorMsg);
   1102         errdefer gpa.destroy(err_msg);
   1103         err_msg.* = try ErrorMsg.init(gpa, src_loc, format, args);
   1104         return err_msg;
   1105     }
   1106 
   1107     /// Assumes the ErrorMsg struct and msg were both allocated with `gpa`,
   1108     /// as well as all notes.
   1109     pub fn destroy(err_msg: *ErrorMsg, gpa: Allocator) void {
   1110         err_msg.deinit(gpa);
   1111         gpa.destroy(err_msg);
   1112     }
   1113 
   1114     pub fn init(
   1115         gpa: Allocator,
   1116         src_loc: SrcLoc,
   1117         comptime format: []const u8,
   1118         args: anytype,
   1119     ) !ErrorMsg {
   1120         return ErrorMsg{
   1121             .src_loc = src_loc,
   1122             .msg = try std.fmt.allocPrint(gpa, format, args),
   1123         };
   1124     }
   1125 
   1126     pub fn deinit(err_msg: *ErrorMsg, gpa: Allocator) void {
   1127         for (err_msg.notes) |*note| {
   1128             note.deinit(gpa);
   1129         }
   1130         gpa.free(err_msg.notes);
   1131         gpa.free(err_msg.msg);
   1132         gpa.free(err_msg.reference_trace);
   1133         err_msg.* = undefined;
   1134     }
   1135 };
   1136 
   1137 /// Canonical reference to a position within a source file.
   1138 pub const SrcLoc = struct {
   1139     file_scope: *File,
   1140     /// Might be 0 depending on tag of `lazy`.
   1141     parent_decl_node: Ast.Node.Index,
   1142     /// Relative to `parent_decl_node`.
   1143     lazy: LazySrcLoc,
   1144 
   1145     pub fn declSrcToken(src_loc: SrcLoc) Ast.TokenIndex {
   1146         const tree = src_loc.file_scope.tree;
   1147         return tree.firstToken(src_loc.parent_decl_node);
   1148     }
   1149 
   1150     pub fn declRelativeToNodeIndex(src_loc: SrcLoc, offset: i32) Ast.Node.Index {
   1151         return @bitCast(offset + @as(i32, @bitCast(src_loc.parent_decl_node)));
   1152     }
   1153 
   1154     pub const Span = Ast.Span;
   1155 
   1156     pub fn span(src_loc: SrcLoc, gpa: Allocator) !Span {
   1157         switch (src_loc.lazy) {
   1158             .unneeded => unreachable,
   1159             .entire_file => return Span{ .start = 0, .end = 1, .main = 0 },
   1160 
   1161             .byte_abs => |byte_index| return Span{ .start = byte_index, .end = byte_index + 1, .main = byte_index },
   1162 
   1163             .token_abs => |tok_index| {
   1164                 const tree = try src_loc.file_scope.getTree(gpa);
   1165                 const start = tree.tokens.items(.start)[tok_index];
   1166                 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
   1167                 return Span{ .start = start, .end = end, .main = start };
   1168             },
   1169             .node_abs => |node| {
   1170                 const tree = try src_loc.file_scope.getTree(gpa);
   1171                 return tree.nodeToSpan(node);
   1172             },
   1173             .byte_offset => |byte_off| {
   1174                 const tree = try src_loc.file_scope.getTree(gpa);
   1175                 const tok_index = src_loc.declSrcToken();
   1176                 const start = tree.tokens.items(.start)[tok_index] + byte_off;
   1177                 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
   1178                 return Span{ .start = start, .end = end, .main = start };
   1179             },
   1180             .token_offset => |tok_off| {
   1181                 const tree = try src_loc.file_scope.getTree(gpa);
   1182                 const tok_index = src_loc.declSrcToken() + tok_off;
   1183                 const start = tree.tokens.items(.start)[tok_index];
   1184                 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
   1185                 return Span{ .start = start, .end = end, .main = start };
   1186             },
   1187             .node_offset => |traced_off| {
   1188                 const node_off = traced_off.x;
   1189                 const tree = try src_loc.file_scope.getTree(gpa);
   1190                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1191                 assert(src_loc.file_scope.tree_loaded);
   1192                 return tree.nodeToSpan(node);
   1193             },
   1194             .node_offset_main_token => |node_off| {
   1195                 const tree = try src_loc.file_scope.getTree(gpa);
   1196                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1197                 const main_token = tree.nodes.items(.main_token)[node];
   1198                 return tree.tokensToSpan(main_token, main_token, main_token);
   1199             },
   1200             .node_offset_bin_op => |node_off| {
   1201                 const tree = try src_loc.file_scope.getTree(gpa);
   1202                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1203                 assert(src_loc.file_scope.tree_loaded);
   1204                 return tree.nodeToSpan(node);
   1205             },
   1206             .node_offset_initializer => |node_off| {
   1207                 const tree = try src_loc.file_scope.getTree(gpa);
   1208                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1209                 return tree.tokensToSpan(
   1210                     tree.firstToken(node) - 3,
   1211                     tree.lastToken(node),
   1212                     tree.nodes.items(.main_token)[node] - 2,
   1213                 );
   1214             },
   1215             .node_offset_var_decl_ty => |node_off| {
   1216                 const tree = try src_loc.file_scope.getTree(gpa);
   1217                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1218                 const node_tags = tree.nodes.items(.tag);
   1219                 const full = switch (node_tags[node]) {
   1220                     .global_var_decl,
   1221                     .local_var_decl,
   1222                     .simple_var_decl,
   1223                     .aligned_var_decl,
   1224                     => tree.fullVarDecl(node).?,
   1225                     .@"usingnamespace" => {
   1226                         const node_data = tree.nodes.items(.data);
   1227                         return tree.nodeToSpan(node_data[node].lhs);
   1228                     },
   1229                     else => unreachable,
   1230                 };
   1231                 if (full.ast.type_node != 0) {
   1232                     return tree.nodeToSpan(full.ast.type_node);
   1233                 }
   1234                 const tok_index = full.ast.mut_token + 1; // the name token
   1235                 const start = tree.tokens.items(.start)[tok_index];
   1236                 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
   1237                 return Span{ .start = start, .end = end, .main = start };
   1238             },
   1239             .node_offset_var_decl_align => |node_off| {
   1240                 const tree = try src_loc.file_scope.getTree(gpa);
   1241                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1242                 const full = tree.fullVarDecl(node).?;
   1243                 return tree.nodeToSpan(full.ast.align_node);
   1244             },
   1245             .node_offset_var_decl_section => |node_off| {
   1246                 const tree = try src_loc.file_scope.getTree(gpa);
   1247                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1248                 const full = tree.fullVarDecl(node).?;
   1249                 return tree.nodeToSpan(full.ast.section_node);
   1250             },
   1251             .node_offset_var_decl_addrspace => |node_off| {
   1252                 const tree = try src_loc.file_scope.getTree(gpa);
   1253                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1254                 const full = tree.fullVarDecl(node).?;
   1255                 return tree.nodeToSpan(full.ast.addrspace_node);
   1256             },
   1257             .node_offset_var_decl_init => |node_off| {
   1258                 const tree = try src_loc.file_scope.getTree(gpa);
   1259                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1260                 const full = tree.fullVarDecl(node).?;
   1261                 return tree.nodeToSpan(full.ast.init_node);
   1262             },
   1263             .node_offset_builtin_call_arg0 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 0),
   1264             .node_offset_builtin_call_arg1 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 1),
   1265             .node_offset_builtin_call_arg2 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 2),
   1266             .node_offset_builtin_call_arg3 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 3),
   1267             .node_offset_builtin_call_arg4 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 4),
   1268             .node_offset_builtin_call_arg5 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 5),
   1269             .node_offset_ptrcast_operand => |node_off| {
   1270                 const tree = try src_loc.file_scope.getTree(gpa);
   1271                 const main_tokens = tree.nodes.items(.main_token);
   1272                 const node_datas = tree.nodes.items(.data);
   1273                 const node_tags = tree.nodes.items(.tag);
   1274 
   1275                 var node = src_loc.declRelativeToNodeIndex(node_off);
   1276                 while (true) {
   1277                     switch (node_tags[node]) {
   1278                         .builtin_call_two, .builtin_call_two_comma => {},
   1279                         else => break,
   1280                     }
   1281 
   1282                     if (node_datas[node].lhs == 0) break; // 0 args
   1283                     if (node_datas[node].rhs != 0) break; // 2 args
   1284 
   1285                     const builtin_token = main_tokens[node];
   1286                     const builtin_name = tree.tokenSlice(builtin_token);
   1287                     const info = BuiltinFn.list.get(builtin_name) orelse break;
   1288 
   1289                     switch (info.tag) {
   1290                         else => break,
   1291                         .ptr_cast,
   1292                         .align_cast,
   1293                         .addrspace_cast,
   1294                         .const_cast,
   1295                         .volatile_cast,
   1296                         => {},
   1297                     }
   1298 
   1299                     node = node_datas[node].lhs;
   1300                 }
   1301 
   1302                 return tree.nodeToSpan(node);
   1303             },
   1304             .node_offset_array_access_index => |node_off| {
   1305                 const tree = try src_loc.file_scope.getTree(gpa);
   1306                 const node_datas = tree.nodes.items(.data);
   1307                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1308                 return tree.nodeToSpan(node_datas[node].rhs);
   1309             },
   1310             .node_offset_slice_ptr,
   1311             .node_offset_slice_start,
   1312             .node_offset_slice_end,
   1313             .node_offset_slice_sentinel,
   1314             => |node_off| {
   1315                 const tree = try src_loc.file_scope.getTree(gpa);
   1316                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1317                 const full = tree.fullSlice(node).?;
   1318                 const part_node = switch (src_loc.lazy) {
   1319                     .node_offset_slice_ptr => full.ast.sliced,
   1320                     .node_offset_slice_start => full.ast.start,
   1321                     .node_offset_slice_end => full.ast.end,
   1322                     .node_offset_slice_sentinel => full.ast.sentinel,
   1323                     else => unreachable,
   1324                 };
   1325                 return tree.nodeToSpan(part_node);
   1326             },
   1327             .node_offset_call_func => |node_off| {
   1328                 const tree = try src_loc.file_scope.getTree(gpa);
   1329                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1330                 var buf: [1]Ast.Node.Index = undefined;
   1331                 const full = tree.fullCall(&buf, node).?;
   1332                 return tree.nodeToSpan(full.ast.fn_expr);
   1333             },
   1334             .node_offset_field_name => |node_off| {
   1335                 const tree = try src_loc.file_scope.getTree(gpa);
   1336                 const node_datas = tree.nodes.items(.data);
   1337                 const node_tags = tree.nodes.items(.tag);
   1338                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1339                 var buf: [1]Ast.Node.Index = undefined;
   1340                 const tok_index = switch (node_tags[node]) {
   1341                     .field_access => node_datas[node].rhs,
   1342                     .call_one,
   1343                     .call_one_comma,
   1344                     .async_call_one,
   1345                     .async_call_one_comma,
   1346                     .call,
   1347                     .call_comma,
   1348                     .async_call,
   1349                     .async_call_comma,
   1350                     => blk: {
   1351                         const full = tree.fullCall(&buf, node).?;
   1352                         break :blk tree.lastToken(full.ast.fn_expr);
   1353                     },
   1354                     else => tree.firstToken(node) - 2,
   1355                 };
   1356                 const start = tree.tokens.items(.start)[tok_index];
   1357                 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
   1358                 return Span{ .start = start, .end = end, .main = start };
   1359             },
   1360             .node_offset_field_name_init => |node_off| {
   1361                 const tree = try src_loc.file_scope.getTree(gpa);
   1362                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1363                 const tok_index = tree.firstToken(node) - 2;
   1364                 const start = tree.tokens.items(.start)[tok_index];
   1365                 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
   1366                 return Span{ .start = start, .end = end, .main = start };
   1367             },
   1368             .node_offset_deref_ptr => |node_off| {
   1369                 const tree = try src_loc.file_scope.getTree(gpa);
   1370                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1371                 return tree.nodeToSpan(node);
   1372             },
   1373             .node_offset_asm_source => |node_off| {
   1374                 const tree = try src_loc.file_scope.getTree(gpa);
   1375                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1376                 const full = tree.fullAsm(node).?;
   1377                 return tree.nodeToSpan(full.ast.template);
   1378             },
   1379             .node_offset_asm_ret_ty => |node_off| {
   1380                 const tree = try src_loc.file_scope.getTree(gpa);
   1381                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1382                 const full = tree.fullAsm(node).?;
   1383                 const asm_output = full.outputs[0];
   1384                 const node_datas = tree.nodes.items(.data);
   1385                 return tree.nodeToSpan(node_datas[asm_output].lhs);
   1386             },
   1387 
   1388             .node_offset_if_cond => |node_off| {
   1389                 const tree = try src_loc.file_scope.getTree(gpa);
   1390                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1391                 const node_tags = tree.nodes.items(.tag);
   1392                 const src_node = switch (node_tags[node]) {
   1393                     .if_simple,
   1394                     .@"if",
   1395                     => tree.fullIf(node).?.ast.cond_expr,
   1396 
   1397                     .while_simple,
   1398                     .while_cont,
   1399                     .@"while",
   1400                     => tree.fullWhile(node).?.ast.cond_expr,
   1401 
   1402                     .for_simple,
   1403                     .@"for",
   1404                     => {
   1405                         const inputs = tree.fullFor(node).?.ast.inputs;
   1406                         const start = tree.firstToken(inputs[0]);
   1407                         const end = tree.lastToken(inputs[inputs.len - 1]);
   1408                         return tree.tokensToSpan(start, end, start);
   1409                     },
   1410 
   1411                     .@"orelse" => node,
   1412                     .@"catch" => node,
   1413                     else => unreachable,
   1414                 };
   1415                 return tree.nodeToSpan(src_node);
   1416             },
   1417             .for_input => |for_input| {
   1418                 const tree = try src_loc.file_scope.getTree(gpa);
   1419                 const node = src_loc.declRelativeToNodeIndex(for_input.for_node_offset);
   1420                 const for_full = tree.fullFor(node).?;
   1421                 const src_node = for_full.ast.inputs[for_input.input_index];
   1422                 return tree.nodeToSpan(src_node);
   1423             },
   1424             .for_capture_from_input => |node_off| {
   1425                 const tree = try src_loc.file_scope.getTree(gpa);
   1426                 const token_tags = tree.tokens.items(.tag);
   1427                 const input_node = src_loc.declRelativeToNodeIndex(node_off);
   1428                 // We have to actually linear scan the whole AST to find the for loop
   1429                 // that contains this input.
   1430                 const node_tags = tree.nodes.items(.tag);
   1431                 for (node_tags, 0..) |node_tag, node_usize| {
   1432                     const node = @as(Ast.Node.Index, @intCast(node_usize));
   1433                     switch (node_tag) {
   1434                         .for_simple, .@"for" => {
   1435                             const for_full = tree.fullFor(node).?;
   1436                             for (for_full.ast.inputs, 0..) |input, input_index| {
   1437                                 if (input_node == input) {
   1438                                     var count = input_index;
   1439                                     var tok = for_full.payload_token;
   1440                                     while (true) {
   1441                                         switch (token_tags[tok]) {
   1442                                             .comma => {
   1443                                                 count -= 1;
   1444                                                 tok += 1;
   1445                                             },
   1446                                             .identifier => {
   1447                                                 if (count == 0)
   1448                                                     return tree.tokensToSpan(tok, tok + 1, tok);
   1449                                                 tok += 1;
   1450                                             },
   1451                                             .asterisk => {
   1452                                                 if (count == 0)
   1453                                                     return tree.tokensToSpan(tok, tok + 2, tok);
   1454                                                 tok += 1;
   1455                                             },
   1456                                             else => unreachable,
   1457                                         }
   1458                                     }
   1459                                 }
   1460                             }
   1461                         },
   1462                         else => continue,
   1463                     }
   1464                 } else unreachable;
   1465             },
   1466             .call_arg => |call_arg| {
   1467                 const tree = try src_loc.file_scope.getTree(gpa);
   1468                 const node = src_loc.declRelativeToNodeIndex(call_arg.call_node_offset);
   1469                 var buf: [2]Ast.Node.Index = undefined;
   1470                 const call_full = tree.fullCall(buf[0..1], node) orelse {
   1471                     const node_tags = tree.nodes.items(.tag);
   1472                     assert(node_tags[node] == .builtin_call);
   1473                     const call_args_node = tree.extra_data[tree.nodes.items(.data)[node].rhs - 1];
   1474                     switch (node_tags[call_args_node]) {
   1475                         .array_init_one,
   1476                         .array_init_one_comma,
   1477                         .array_init_dot_two,
   1478                         .array_init_dot_two_comma,
   1479                         .array_init_dot,
   1480                         .array_init_dot_comma,
   1481                         .array_init,
   1482                         .array_init_comma,
   1483                         => {
   1484                             const full = tree.fullArrayInit(&buf, call_args_node).?.ast.elements;
   1485                             return tree.nodeToSpan(full[call_arg.arg_index]);
   1486                         },
   1487                         .struct_init_one,
   1488                         .struct_init_one_comma,
   1489                         .struct_init_dot_two,
   1490                         .struct_init_dot_two_comma,
   1491                         .struct_init_dot,
   1492                         .struct_init_dot_comma,
   1493                         .struct_init,
   1494                         .struct_init_comma,
   1495                         => {
   1496                             const full = tree.fullStructInit(&buf, call_args_node).?.ast.fields;
   1497                             return tree.nodeToSpan(full[call_arg.arg_index]);
   1498                         },
   1499                         else => return tree.nodeToSpan(call_args_node),
   1500                     }
   1501                 };
   1502                 return tree.nodeToSpan(call_full.ast.params[call_arg.arg_index]);
   1503             },
   1504             .fn_proto_param => |fn_proto_param| {
   1505                 const tree = try src_loc.file_scope.getTree(gpa);
   1506                 const node = src_loc.declRelativeToNodeIndex(fn_proto_param.fn_proto_node_offset);
   1507                 var buf: [1]Ast.Node.Index = undefined;
   1508                 const full = tree.fullFnProto(&buf, node).?;
   1509                 var it = full.iterate(tree);
   1510                 var i: usize = 0;
   1511                 while (it.next()) |param| : (i += 1) {
   1512                     if (i == fn_proto_param.param_index) {
   1513                         if (param.anytype_ellipsis3) |token| return tree.tokenToSpan(token);
   1514                         const first_token = param.comptime_noalias orelse
   1515                             param.name_token orelse
   1516                             tree.firstToken(param.type_expr);
   1517                         return tree.tokensToSpan(
   1518                             first_token,
   1519                             tree.lastToken(param.type_expr),
   1520                             first_token,
   1521                         );
   1522                     }
   1523                 }
   1524                 unreachable;
   1525             },
   1526             .node_offset_bin_lhs => |node_off| {
   1527                 const tree = try src_loc.file_scope.getTree(gpa);
   1528                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1529                 const node_datas = tree.nodes.items(.data);
   1530                 return tree.nodeToSpan(node_datas[node].lhs);
   1531             },
   1532             .node_offset_bin_rhs => |node_off| {
   1533                 const tree = try src_loc.file_scope.getTree(gpa);
   1534                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1535                 const node_datas = tree.nodes.items(.data);
   1536                 return tree.nodeToSpan(node_datas[node].rhs);
   1537             },
   1538             .array_cat_lhs, .array_cat_rhs => |cat| {
   1539                 const tree = try src_loc.file_scope.getTree(gpa);
   1540                 const node = src_loc.declRelativeToNodeIndex(cat.array_cat_offset);
   1541                 const node_datas = tree.nodes.items(.data);
   1542                 const arr_node = if (src_loc.lazy == .array_cat_lhs)
   1543                     node_datas[node].lhs
   1544                 else
   1545                     node_datas[node].rhs;
   1546 
   1547                 const node_tags = tree.nodes.items(.tag);
   1548                 var buf: [2]Ast.Node.Index = undefined;
   1549                 switch (node_tags[arr_node]) {
   1550                     .array_init_one,
   1551                     .array_init_one_comma,
   1552                     .array_init_dot_two,
   1553                     .array_init_dot_two_comma,
   1554                     .array_init_dot,
   1555                     .array_init_dot_comma,
   1556                     .array_init,
   1557                     .array_init_comma,
   1558                     => {
   1559                         const full = tree.fullArrayInit(&buf, arr_node).?.ast.elements;
   1560                         return tree.nodeToSpan(full[cat.elem_index]);
   1561                     },
   1562                     else => return tree.nodeToSpan(arr_node),
   1563                 }
   1564             },
   1565 
   1566             .node_offset_switch_operand => |node_off| {
   1567                 const tree = try src_loc.file_scope.getTree(gpa);
   1568                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1569                 const node_datas = tree.nodes.items(.data);
   1570                 return tree.nodeToSpan(node_datas[node].lhs);
   1571             },
   1572 
   1573             .node_offset_switch_special_prong => |node_off| {
   1574                 const tree = try src_loc.file_scope.getTree(gpa);
   1575                 const switch_node = src_loc.declRelativeToNodeIndex(node_off);
   1576                 const node_datas = tree.nodes.items(.data);
   1577                 const node_tags = tree.nodes.items(.tag);
   1578                 const main_tokens = tree.nodes.items(.main_token);
   1579                 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
   1580                 const case_nodes = tree.extra_data[extra.start..extra.end];
   1581                 for (case_nodes) |case_node| {
   1582                     const case = tree.fullSwitchCase(case_node).?;
   1583                     const is_special = (case.ast.values.len == 0) or
   1584                         (case.ast.values.len == 1 and
   1585                         node_tags[case.ast.values[0]] == .identifier and
   1586                         mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"));
   1587                     if (!is_special) continue;
   1588 
   1589                     return tree.nodeToSpan(case_node);
   1590                 } else unreachable;
   1591             },
   1592 
   1593             .node_offset_switch_range => |node_off| {
   1594                 const tree = try src_loc.file_scope.getTree(gpa);
   1595                 const switch_node = src_loc.declRelativeToNodeIndex(node_off);
   1596                 const node_datas = tree.nodes.items(.data);
   1597                 const node_tags = tree.nodes.items(.tag);
   1598                 const main_tokens = tree.nodes.items(.main_token);
   1599                 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
   1600                 const case_nodes = tree.extra_data[extra.start..extra.end];
   1601                 for (case_nodes) |case_node| {
   1602                     const case = tree.fullSwitchCase(case_node).?;
   1603                     const is_special = (case.ast.values.len == 0) or
   1604                         (case.ast.values.len == 1 and
   1605                         node_tags[case.ast.values[0]] == .identifier and
   1606                         mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"));
   1607                     if (is_special) continue;
   1608 
   1609                     for (case.ast.values) |item_node| {
   1610                         if (node_tags[item_node] == .switch_range) {
   1611                             return tree.nodeToSpan(item_node);
   1612                         }
   1613                     }
   1614                 } else unreachable;
   1615             },
   1616             .node_offset_switch_prong_capture,
   1617             .node_offset_switch_prong_tag_capture,
   1618             => |node_off| {
   1619                 const tree = try src_loc.file_scope.getTree(gpa);
   1620                 const case_node = src_loc.declRelativeToNodeIndex(node_off);
   1621                 const case = tree.fullSwitchCase(case_node).?;
   1622                 const token_tags = tree.tokens.items(.tag);
   1623                 const start_tok = switch (src_loc.lazy) {
   1624                     .node_offset_switch_prong_capture => case.payload_token.?,
   1625                     .node_offset_switch_prong_tag_capture => blk: {
   1626                         var tok = case.payload_token.?;
   1627                         if (token_tags[tok] == .asterisk) tok += 1;
   1628                         tok += 2; // skip over comma
   1629                         break :blk tok;
   1630                     },
   1631                     else => unreachable,
   1632                 };
   1633                 const end_tok = switch (token_tags[start_tok]) {
   1634                     .asterisk => start_tok + 1,
   1635                     else => start_tok,
   1636                 };
   1637                 const start = tree.tokens.items(.start)[start_tok];
   1638                 const end_start = tree.tokens.items(.start)[end_tok];
   1639                 const end = end_start + @as(u32, @intCast(tree.tokenSlice(end_tok).len));
   1640                 return Span{ .start = start, .end = end, .main = start };
   1641             },
   1642             .node_offset_fn_type_align => |node_off| {
   1643                 const tree = try src_loc.file_scope.getTree(gpa);
   1644                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1645                 var buf: [1]Ast.Node.Index = undefined;
   1646                 const full = tree.fullFnProto(&buf, node).?;
   1647                 return tree.nodeToSpan(full.ast.align_expr);
   1648             },
   1649             .node_offset_fn_type_addrspace => |node_off| {
   1650                 const tree = try src_loc.file_scope.getTree(gpa);
   1651                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1652                 var buf: [1]Ast.Node.Index = undefined;
   1653                 const full = tree.fullFnProto(&buf, node).?;
   1654                 return tree.nodeToSpan(full.ast.addrspace_expr);
   1655             },
   1656             .node_offset_fn_type_section => |node_off| {
   1657                 const tree = try src_loc.file_scope.getTree(gpa);
   1658                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1659                 var buf: [1]Ast.Node.Index = undefined;
   1660                 const full = tree.fullFnProto(&buf, node).?;
   1661                 return tree.nodeToSpan(full.ast.section_expr);
   1662             },
   1663             .node_offset_fn_type_cc => |node_off| {
   1664                 const tree = try src_loc.file_scope.getTree(gpa);
   1665                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1666                 var buf: [1]Ast.Node.Index = undefined;
   1667                 const full = tree.fullFnProto(&buf, node).?;
   1668                 return tree.nodeToSpan(full.ast.callconv_expr);
   1669             },
   1670 
   1671             .node_offset_fn_type_ret_ty => |node_off| {
   1672                 const tree = try src_loc.file_scope.getTree(gpa);
   1673                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1674                 var buf: [1]Ast.Node.Index = undefined;
   1675                 const full = tree.fullFnProto(&buf, node).?;
   1676                 return tree.nodeToSpan(full.ast.return_type);
   1677             },
   1678             .node_offset_param => |node_off| {
   1679                 const tree = try src_loc.file_scope.getTree(gpa);
   1680                 const token_tags = tree.tokens.items(.tag);
   1681                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1682 
   1683                 var first_tok = tree.firstToken(node);
   1684                 while (true) switch (token_tags[first_tok - 1]) {
   1685                     .colon, .identifier, .keyword_comptime, .keyword_noalias => first_tok -= 1,
   1686                     else => break,
   1687                 };
   1688                 return tree.tokensToSpan(
   1689                     first_tok,
   1690                     tree.lastToken(node),
   1691                     first_tok,
   1692                 );
   1693             },
   1694             .token_offset_param => |token_off| {
   1695                 const tree = try src_loc.file_scope.getTree(gpa);
   1696                 const token_tags = tree.tokens.items(.tag);
   1697                 const main_token = tree.nodes.items(.main_token)[src_loc.parent_decl_node];
   1698                 const tok_index = @as(Ast.TokenIndex, @bitCast(token_off + @as(i32, @bitCast(main_token))));
   1699 
   1700                 var first_tok = tok_index;
   1701                 while (true) switch (token_tags[first_tok - 1]) {
   1702                     .colon, .identifier, .keyword_comptime, .keyword_noalias => first_tok -= 1,
   1703                     else => break,
   1704                 };
   1705                 return tree.tokensToSpan(
   1706                     first_tok,
   1707                     tok_index,
   1708                     first_tok,
   1709                 );
   1710             },
   1711 
   1712             .node_offset_anyframe_type => |node_off| {
   1713                 const tree = try src_loc.file_scope.getTree(gpa);
   1714                 const node_datas = tree.nodes.items(.data);
   1715                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   1716                 return tree.nodeToSpan(node_datas[parent_node].rhs);
   1717             },
   1718 
   1719             .node_offset_lib_name => |node_off| {
   1720                 const tree = try src_loc.file_scope.getTree(gpa);
   1721                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   1722                 var buf: [1]Ast.Node.Index = undefined;
   1723                 const full = tree.fullFnProto(&buf, parent_node).?;
   1724                 const tok_index = full.lib_name.?;
   1725                 const start = tree.tokens.items(.start)[tok_index];
   1726                 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
   1727                 return Span{ .start = start, .end = end, .main = start };
   1728             },
   1729 
   1730             .node_offset_array_type_len => |node_off| {
   1731                 const tree = try src_loc.file_scope.getTree(gpa);
   1732                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   1733 
   1734                 const full = tree.fullArrayType(parent_node).?;
   1735                 return tree.nodeToSpan(full.ast.elem_count);
   1736             },
   1737             .node_offset_array_type_sentinel => |node_off| {
   1738                 const tree = try src_loc.file_scope.getTree(gpa);
   1739                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   1740 
   1741                 const full = tree.fullArrayType(parent_node).?;
   1742                 return tree.nodeToSpan(full.ast.sentinel);
   1743             },
   1744             .node_offset_array_type_elem => |node_off| {
   1745                 const tree = try src_loc.file_scope.getTree(gpa);
   1746                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   1747 
   1748                 const full = tree.fullArrayType(parent_node).?;
   1749                 return tree.nodeToSpan(full.ast.elem_type);
   1750             },
   1751             .node_offset_un_op => |node_off| {
   1752                 const tree = try src_loc.file_scope.getTree(gpa);
   1753                 const node_datas = tree.nodes.items(.data);
   1754                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1755 
   1756                 return tree.nodeToSpan(node_datas[node].lhs);
   1757             },
   1758             .node_offset_ptr_elem => |node_off| {
   1759                 const tree = try src_loc.file_scope.getTree(gpa);
   1760                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   1761 
   1762                 const full = tree.fullPtrType(parent_node).?;
   1763                 return tree.nodeToSpan(full.ast.child_type);
   1764             },
   1765             .node_offset_ptr_sentinel => |node_off| {
   1766                 const tree = try src_loc.file_scope.getTree(gpa);
   1767                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   1768 
   1769                 const full = tree.fullPtrType(parent_node).?;
   1770                 return tree.nodeToSpan(full.ast.sentinel);
   1771             },
   1772             .node_offset_ptr_align => |node_off| {
   1773                 const tree = try src_loc.file_scope.getTree(gpa);
   1774                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   1775 
   1776                 const full = tree.fullPtrType(parent_node).?;
   1777                 return tree.nodeToSpan(full.ast.align_node);
   1778             },
   1779             .node_offset_ptr_addrspace => |node_off| {
   1780                 const tree = try src_loc.file_scope.getTree(gpa);
   1781                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   1782 
   1783                 const full = tree.fullPtrType(parent_node).?;
   1784                 return tree.nodeToSpan(full.ast.addrspace_node);
   1785             },
   1786             .node_offset_ptr_bitoffset => |node_off| {
   1787                 const tree = try src_loc.file_scope.getTree(gpa);
   1788                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   1789 
   1790                 const full = tree.fullPtrType(parent_node).?;
   1791                 return tree.nodeToSpan(full.ast.bit_range_start);
   1792             },
   1793             .node_offset_ptr_hostsize => |node_off| {
   1794                 const tree = try src_loc.file_scope.getTree(gpa);
   1795                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   1796 
   1797                 const full = tree.fullPtrType(parent_node).?;
   1798                 return tree.nodeToSpan(full.ast.bit_range_end);
   1799             },
   1800             .node_offset_container_tag => |node_off| {
   1801                 const tree = try src_loc.file_scope.getTree(gpa);
   1802                 const node_tags = tree.nodes.items(.tag);
   1803                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   1804 
   1805                 switch (node_tags[parent_node]) {
   1806                     .container_decl_arg, .container_decl_arg_trailing => {
   1807                         const full = tree.containerDeclArg(parent_node);
   1808                         return tree.nodeToSpan(full.ast.arg);
   1809                     },
   1810                     .tagged_union_enum_tag, .tagged_union_enum_tag_trailing => {
   1811                         const full = tree.taggedUnionEnumTag(parent_node);
   1812 
   1813                         return tree.tokensToSpan(
   1814                             tree.firstToken(full.ast.arg) - 2,
   1815                             tree.lastToken(full.ast.arg) + 1,
   1816                             tree.nodes.items(.main_token)[full.ast.arg],
   1817                         );
   1818                     },
   1819                     else => unreachable,
   1820                 }
   1821             },
   1822             .node_offset_field_default => |node_off| {
   1823                 const tree = try src_loc.file_scope.getTree(gpa);
   1824                 const node_tags = tree.nodes.items(.tag);
   1825                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   1826 
   1827                 const full: Ast.full.ContainerField = switch (node_tags[parent_node]) {
   1828                     .container_field => tree.containerField(parent_node),
   1829                     .container_field_init => tree.containerFieldInit(parent_node),
   1830                     else => unreachable,
   1831                 };
   1832                 return tree.nodeToSpan(full.ast.value_expr);
   1833             },
   1834             .node_offset_init_ty => |node_off| {
   1835                 const tree = try src_loc.file_scope.getTree(gpa);
   1836                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   1837 
   1838                 var buf: [2]Ast.Node.Index = undefined;
   1839                 const type_expr = if (tree.fullArrayInit(&buf, parent_node)) |array_init|
   1840                     array_init.ast.type_expr
   1841                 else
   1842                     tree.fullStructInit(&buf, parent_node).?.ast.type_expr;
   1843                 return tree.nodeToSpan(type_expr);
   1844             },
   1845             .node_offset_store_ptr => |node_off| {
   1846                 const tree = try src_loc.file_scope.getTree(gpa);
   1847                 const node_tags = tree.nodes.items(.tag);
   1848                 const node_datas = tree.nodes.items(.data);
   1849                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1850 
   1851                 switch (node_tags[node]) {
   1852                     .assign => {
   1853                         return tree.nodeToSpan(node_datas[node].lhs);
   1854                     },
   1855                     else => return tree.nodeToSpan(node),
   1856                 }
   1857             },
   1858             .node_offset_store_operand => |node_off| {
   1859                 const tree = try src_loc.file_scope.getTree(gpa);
   1860                 const node_tags = tree.nodes.items(.tag);
   1861                 const node_datas = tree.nodes.items(.data);
   1862                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1863 
   1864                 switch (node_tags[node]) {
   1865                     .assign => {
   1866                         return tree.nodeToSpan(node_datas[node].rhs);
   1867                     },
   1868                     else => return tree.nodeToSpan(node),
   1869                 }
   1870             },
   1871             .node_offset_return_operand => |node_off| {
   1872                 const tree = try src_loc.file_scope.getTree(gpa);
   1873                 const node = src_loc.declRelativeToNodeIndex(node_off);
   1874                 const node_tags = tree.nodes.items(.tag);
   1875                 const node_datas = tree.nodes.items(.data);
   1876                 if (node_tags[node] == .@"return" and node_datas[node].lhs != 0) {
   1877                     return tree.nodeToSpan(node_datas[node].lhs);
   1878                 }
   1879                 return tree.nodeToSpan(node);
   1880             },
   1881         }
   1882     }
   1883 
   1884     pub fn byteOffsetBuiltinCallArg(
   1885         src_loc: SrcLoc,
   1886         gpa: Allocator,
   1887         node_off: i32,
   1888         arg_index: u32,
   1889     ) !Span {
   1890         const tree = try src_loc.file_scope.getTree(gpa);
   1891         const node_datas = tree.nodes.items(.data);
   1892         const node_tags = tree.nodes.items(.tag);
   1893         const node = src_loc.declRelativeToNodeIndex(node_off);
   1894         const param = switch (node_tags[node]) {
   1895             .builtin_call_two, .builtin_call_two_comma => switch (arg_index) {
   1896                 0 => node_datas[node].lhs,
   1897                 1 => node_datas[node].rhs,
   1898                 else => unreachable,
   1899             },
   1900             .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + arg_index],
   1901             else => unreachable,
   1902         };
   1903         return tree.nodeToSpan(param);
   1904     }
   1905 };
   1906 
   1907 pub const SemaError = error{ OutOfMemory, AnalysisFail };
   1908 pub const CompileError = error{
   1909     OutOfMemory,
   1910     /// When this is returned, the compile error for the failure has already been recorded.
   1911     AnalysisFail,
   1912     /// Returned when a compile error needed to be reported but a provided LazySrcLoc was set
   1913     /// to the `unneeded` tag. The source location was, in fact, needed. It is expected that
   1914     /// somewhere up the call stack, the operation will be retried after doing expensive work
   1915     /// to compute a source location.
   1916     NeededSourceLocation,
   1917     /// A Type or Value was needed to be used during semantic analysis, but it was not available
   1918     /// because the function is generic. This is only seen when analyzing the body of a param
   1919     /// instruction.
   1920     GenericPoison,
   1921     /// In a comptime scope, a return instruction was encountered. This error is only seen when
   1922     /// doing a comptime function call.
   1923     ComptimeReturn,
   1924     /// In a comptime scope, a break instruction was encountered. This error is only seen when
   1925     /// evaluating a comptime block.
   1926     ComptimeBreak,
   1927 };
   1928 
   1929 pub fn init(mod: *Module) !void {
   1930     const gpa = mod.gpa;
   1931     try mod.intern_pool.init(gpa);
   1932     try mod.global_error_set.put(gpa, .empty, {});
   1933 }
   1934 
   1935 pub fn deinit(zcu: *Zcu) void {
   1936     const gpa = zcu.gpa;
   1937 
   1938     if (zcu.llvm_object) |llvm_object| {
   1939         if (build_options.only_c) unreachable;
   1940         llvm_object.deinit();
   1941     }
   1942 
   1943     for (zcu.import_table.keys()) |key| {
   1944         gpa.free(key);
   1945     }
   1946     var failed_decls = zcu.failed_decls;
   1947     zcu.failed_decls = .{};
   1948     for (zcu.import_table.values()) |value| {
   1949         value.destroy(zcu);
   1950     }
   1951     zcu.import_table.deinit(gpa);
   1952 
   1953     for (zcu.embed_table.keys(), zcu.embed_table.values()) |path, embed_file| {
   1954         gpa.free(path);
   1955         gpa.destroy(embed_file);
   1956     }
   1957     zcu.embed_table.deinit(gpa);
   1958 
   1959     zcu.compile_log_text.deinit(gpa);
   1960 
   1961     zcu.local_zir_cache.handle.close();
   1962     zcu.global_zir_cache.handle.close();
   1963 
   1964     for (failed_decls.values()) |value| {
   1965         value.destroy(gpa);
   1966     }
   1967     failed_decls.deinit(gpa);
   1968 
   1969     if (zcu.emit_h) |emit_h| {
   1970         for (emit_h.failed_decls.values()) |value| {
   1971             value.destroy(gpa);
   1972         }
   1973         emit_h.failed_decls.deinit(gpa);
   1974         emit_h.decl_table.deinit(gpa);
   1975         emit_h.allocated_emit_h.deinit(gpa);
   1976     }
   1977 
   1978     for (zcu.failed_files.values()) |value| {
   1979         if (value) |msg| msg.destroy(gpa);
   1980     }
   1981     zcu.failed_files.deinit(gpa);
   1982 
   1983     for (zcu.failed_embed_files.values()) |msg| {
   1984         msg.destroy(gpa);
   1985     }
   1986     zcu.failed_embed_files.deinit(gpa);
   1987 
   1988     for (zcu.failed_exports.values()) |value| {
   1989         value.destroy(gpa);
   1990     }
   1991     zcu.failed_exports.deinit(gpa);
   1992 
   1993     for (zcu.cimport_errors.values()) |*errs| {
   1994         errs.deinit(gpa);
   1995     }
   1996     zcu.cimport_errors.deinit(gpa);
   1997 
   1998     zcu.compile_log_decls.deinit(gpa);
   1999 
   2000     for (zcu.decl_exports.values()) |*export_list| {
   2001         export_list.deinit(gpa);
   2002     }
   2003     zcu.decl_exports.deinit(gpa);
   2004 
   2005     for (zcu.value_exports.values()) |*export_list| {
   2006         export_list.deinit(gpa);
   2007     }
   2008     zcu.value_exports.deinit(gpa);
   2009 
   2010     for (zcu.export_owners.values()) |*value| {
   2011         freeExportList(gpa, value);
   2012     }
   2013     zcu.export_owners.deinit(gpa);
   2014 
   2015     zcu.global_error_set.deinit(gpa);
   2016 
   2017     zcu.potentially_outdated.deinit(gpa);
   2018     zcu.outdated.deinit(gpa);
   2019     zcu.outdated_ready.deinit(gpa);
   2020     zcu.outdated_file_root.deinit(gpa);
   2021     zcu.retryable_failures.deinit(gpa);
   2022 
   2023     zcu.test_functions.deinit(gpa);
   2024 
   2025     for (zcu.global_assembly.values()) |s| {
   2026         gpa.free(s);
   2027     }
   2028     zcu.global_assembly.deinit(gpa);
   2029 
   2030     zcu.reference_table.deinit(gpa);
   2031 
   2032     {
   2033         var it = zcu.intern_pool.allocated_namespaces.iterator(0);
   2034         while (it.next()) |namespace| {
   2035             namespace.decls.deinit(gpa);
   2036             namespace.usingnamespace_set.deinit(gpa);
   2037         }
   2038     }
   2039 
   2040     zcu.intern_pool.deinit(gpa);
   2041 }
   2042 
   2043 pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {
   2044     const gpa = mod.gpa;
   2045     const ip = &mod.intern_pool;
   2046 
   2047     {
   2048         _ = mod.test_functions.swapRemove(decl_index);
   2049         if (mod.global_assembly.fetchSwapRemove(decl_index)) |kv| {
   2050             gpa.free(kv.value);
   2051         }
   2052     }
   2053 
   2054     ip.destroyDecl(gpa, decl_index);
   2055 
   2056     if (mod.emit_h) |mod_emit_h| {
   2057         const decl_emit_h = mod_emit_h.declPtr(decl_index);
   2058         decl_emit_h.fwd_decl.deinit(gpa);
   2059         decl_emit_h.* = undefined;
   2060     }
   2061 }
   2062 
   2063 pub fn declPtr(mod: *Module, index: Decl.Index) *Decl {
   2064     return mod.intern_pool.declPtr(index);
   2065 }
   2066 
   2067 pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace {
   2068     return mod.intern_pool.namespacePtr(index);
   2069 }
   2070 
   2071 pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namespace {
   2072     return mod.namespacePtr(index.unwrap() orelse return null);
   2073 }
   2074 
   2075 /// Returns true if and only if the Decl is the top level struct associated with a File.
   2076 pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {
   2077     const decl = mod.declPtr(decl_index);
   2078     const namespace = mod.namespacePtr(decl.src_namespace);
   2079     if (namespace.parent != .none) return false;
   2080     return decl_index == namespace.decl_index;
   2081 }
   2082 
   2083 fn freeExportList(gpa: Allocator, export_list: *ArrayListUnmanaged(*Export)) void {
   2084     for (export_list.items) |exp| gpa.destroy(exp);
   2085     export_list.deinit(gpa);
   2086 }
   2087 
   2088 // TODO https://github.com/ziglang/zig/issues/8643
   2089 const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8;
   2090 const HackDataLayout = extern struct {
   2091     data: [8]u8 align(@alignOf(Zir.Inst.Data)),
   2092     safety_tag: u8,
   2093 };
   2094 comptime {
   2095     if (data_has_safety_tag) {
   2096         assert(@sizeOf(HackDataLayout) == @sizeOf(Zir.Inst.Data));
   2097     }
   2098 }
   2099 
   2100 pub fn astGenFile(mod: *Module, file: *File) !void {
   2101     assert(!file.mod.isBuiltin());
   2102 
   2103     const tracy = trace(@src());
   2104     defer tracy.end();
   2105 
   2106     const comp = mod.comp;
   2107     const gpa = mod.gpa;
   2108 
   2109     // In any case we need to examine the stat of the file to determine the course of action.
   2110     var source_file = try file.mod.root.openFile(file.sub_file_path, .{});
   2111     defer source_file.close();
   2112 
   2113     const stat = try source_file.stat();
   2114 
   2115     const want_local_cache = file.mod == mod.main_mod;
   2116     const bin_digest = hash: {
   2117         var path_hash: Cache.HashHelper = .{};
   2118         path_hash.addBytes(build_options.version);
   2119         path_hash.add(builtin.zig_backend);
   2120         if (!want_local_cache) {
   2121             path_hash.addOptionalBytes(file.mod.root.root_dir.path);
   2122             path_hash.addBytes(file.mod.root.sub_path);
   2123         }
   2124         path_hash.addBytes(file.sub_file_path);
   2125         var bin: Cache.BinDigest = undefined;
   2126         path_hash.hasher.final(&bin);
   2127         break :hash bin;
   2128     };
   2129     file.path_digest = bin_digest;
   2130     const hex_digest = hex: {
   2131         var hex: Cache.HexDigest = undefined;
   2132         _ = std.fmt.bufPrint(
   2133             &hex,
   2134             "{s}",
   2135             .{std.fmt.fmtSliceHexLower(&bin_digest)},
   2136         ) catch unreachable;
   2137         break :hex hex;
   2138     };
   2139     const cache_directory = if (want_local_cache) mod.local_zir_cache else mod.global_zir_cache;
   2140     const zir_dir = cache_directory.handle;
   2141 
   2142     // Determine whether we need to reload the file from disk and redo parsing and AstGen.
   2143     var lock: std.fs.File.Lock = switch (file.status) {
   2144         .never_loaded, .retryable_failure => lock: {
   2145             // First, load the cached ZIR code, if any.
   2146             log.debug("AstGen checking cache: {s} (local={}, digest={s})", .{
   2147                 file.sub_file_path, want_local_cache, &hex_digest,
   2148             });
   2149 
   2150             break :lock .shared;
   2151         },
   2152         .parse_failure, .astgen_failure, .success_zir => lock: {
   2153             const unchanged_metadata =
   2154                 stat.size == file.stat.size and
   2155                 stat.mtime == file.stat.mtime and
   2156                 stat.inode == file.stat.inode;
   2157 
   2158             if (unchanged_metadata) {
   2159                 log.debug("unmodified metadata of file: {s}", .{file.sub_file_path});
   2160                 return;
   2161             }
   2162 
   2163             log.debug("metadata changed: {s}", .{file.sub_file_path});
   2164 
   2165             break :lock .exclusive;
   2166         },
   2167     };
   2168 
   2169     // We ask for a lock in order to coordinate with other zig processes.
   2170     // If another process is already working on this file, we will get the cached
   2171     // version. Likewise if we're working on AstGen and another process asks for
   2172     // the cached file, they'll get it.
   2173     const cache_file = while (true) {
   2174         break zir_dir.createFile(&hex_digest, .{
   2175             .read = true,
   2176             .truncate = false,
   2177             .lock = lock,
   2178         }) catch |err| switch (err) {
   2179             error.NotDir => unreachable, // no dir components
   2180             error.InvalidUtf8 => unreachable, // it's a hex encoded name
   2181             error.InvalidWtf8 => unreachable, // it's a hex encoded name
   2182             error.BadPathName => unreachable, // it's a hex encoded name
   2183             error.NameTooLong => unreachable, // it's a fixed size name
   2184             error.PipeBusy => unreachable, // it's not a pipe
   2185             error.WouldBlock => unreachable, // not asking for non-blocking I/O
   2186             // There are no dir components, so you would think that this was
   2187             // unreachable, however we have observed on macOS two processes racing
   2188             // to do openat() with O_CREAT manifest in ENOENT.
   2189             error.FileNotFound => continue,
   2190 
   2191             else => |e| return e, // Retryable errors are handled at callsite.
   2192         };
   2193     };
   2194     defer cache_file.close();
   2195 
   2196     while (true) {
   2197         update: {
   2198             // First we read the header to determine the lengths of arrays.
   2199             const header = cache_file.reader().readStruct(Zir.Header) catch |err| switch (err) {
   2200                 // This can happen if Zig bails out of this function between creating
   2201                 // the cached file and writing it.
   2202                 error.EndOfStream => break :update,
   2203                 else => |e| return e,
   2204             };
   2205             const unchanged_metadata =
   2206                 stat.size == header.stat_size and
   2207                 stat.mtime == header.stat_mtime and
   2208                 stat.inode == header.stat_inode;
   2209 
   2210             if (!unchanged_metadata) {
   2211                 log.debug("AstGen cache stale: {s}", .{file.sub_file_path});
   2212                 break :update;
   2213             }
   2214             log.debug("AstGen cache hit: {s} instructions_len={d}", .{
   2215                 file.sub_file_path, header.instructions_len,
   2216             });
   2217 
   2218             file.zir = loadZirCacheBody(gpa, header, cache_file) catch |err| switch (err) {
   2219                 error.UnexpectedFileSize => {
   2220                     log.warn("unexpected EOF reading cached ZIR for {s}", .{file.sub_file_path});
   2221                     break :update;
   2222                 },
   2223                 else => |e| return e,
   2224             };
   2225             file.zir_loaded = true;
   2226             file.stat = .{
   2227                 .size = header.stat_size,
   2228                 .inode = header.stat_inode,
   2229                 .mtime = header.stat_mtime,
   2230             };
   2231             file.status = .success_zir;
   2232             log.debug("AstGen cached success: {s}", .{file.sub_file_path});
   2233 
   2234             // TODO don't report compile errors until Sema @importFile
   2235             if (file.zir.hasCompileErrors()) {
   2236                 {
   2237                     comp.mutex.lock();
   2238                     defer comp.mutex.unlock();
   2239                     try mod.failed_files.putNoClobber(gpa, file, null);
   2240                 }
   2241                 file.status = .astgen_failure;
   2242                 return error.AnalysisFail;
   2243             }
   2244             return;
   2245         }
   2246 
   2247         // If we already have the exclusive lock then it is our job to update.
   2248         if (builtin.os.tag == .wasi or lock == .exclusive) break;
   2249         // Otherwise, unlock to give someone a chance to get the exclusive lock
   2250         // and then upgrade to an exclusive lock.
   2251         cache_file.unlock();
   2252         lock = .exclusive;
   2253         try cache_file.lock(lock);
   2254     }
   2255 
   2256     // The cache is definitely stale so delete the contents to avoid an underwrite later.
   2257     cache_file.setEndPos(0) catch |err| switch (err) {
   2258         error.FileTooBig => unreachable, // 0 is not too big
   2259 
   2260         else => |e| return e,
   2261     };
   2262 
   2263     mod.lockAndClearFileCompileError(file);
   2264 
   2265     // If the previous ZIR does not have compile errors, keep it around
   2266     // in case parsing or new ZIR fails. In case of successful ZIR update
   2267     // at the end of this function we will free it.
   2268     // We keep the previous ZIR loaded so that we can use it
   2269     // for the update next time it does not have any compile errors. This avoids
   2270     // needlessly tossing out semantic analysis work when an error is
   2271     // temporarily introduced.
   2272     if (file.zir_loaded and !file.zir.hasCompileErrors()) {
   2273         assert(file.prev_zir == null);
   2274         const prev_zir_ptr = try gpa.create(Zir);
   2275         file.prev_zir = prev_zir_ptr;
   2276         prev_zir_ptr.* = file.zir;
   2277         file.zir = undefined;
   2278         file.zir_loaded = false;
   2279     }
   2280     file.unload(gpa);
   2281 
   2282     if (stat.size > std.math.maxInt(u32))
   2283         return error.FileTooBig;
   2284 
   2285     const source = try gpa.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);
   2286     defer if (!file.source_loaded) gpa.free(source);
   2287     const amt = try source_file.readAll(source);
   2288     if (amt != stat.size)
   2289         return error.UnexpectedEndOfFile;
   2290 
   2291     file.stat = .{
   2292         .size = stat.size,
   2293         .inode = stat.inode,
   2294         .mtime = stat.mtime,
   2295     };
   2296     file.source = source;
   2297     file.source_loaded = true;
   2298 
   2299     file.tree = try Ast.parse(gpa, source, .zig);
   2300     file.tree_loaded = true;
   2301 
   2302     // Any potential AST errors are converted to ZIR errors here.
   2303     file.zir = try AstGen.generate(gpa, file.tree);
   2304     file.zir_loaded = true;
   2305     file.status = .success_zir;
   2306     log.debug("AstGen fresh success: {s}", .{file.sub_file_path});
   2307 
   2308     const safety_buffer = if (data_has_safety_tag)
   2309         try gpa.alloc([8]u8, file.zir.instructions.len)
   2310     else
   2311         undefined;
   2312     defer if (data_has_safety_tag) gpa.free(safety_buffer);
   2313     const data_ptr = if (data_has_safety_tag)
   2314         if (file.zir.instructions.len == 0)
   2315             @as([*]const u8, undefined)
   2316         else
   2317             @as([*]const u8, @ptrCast(safety_buffer.ptr))
   2318     else
   2319         @as([*]const u8, @ptrCast(file.zir.instructions.items(.data).ptr));
   2320     if (data_has_safety_tag) {
   2321         // The `Data` union has a safety tag but in the file format we store it without.
   2322         for (file.zir.instructions.items(.data), 0..) |*data, i| {
   2323             const as_struct = @as(*const HackDataLayout, @ptrCast(data));
   2324             safety_buffer[i] = as_struct.data;
   2325         }
   2326     }
   2327 
   2328     const header: Zir.Header = .{
   2329         .instructions_len = @as(u32, @intCast(file.zir.instructions.len)),
   2330         .string_bytes_len = @as(u32, @intCast(file.zir.string_bytes.len)),
   2331         .extra_len = @as(u32, @intCast(file.zir.extra.len)),
   2332 
   2333         .stat_size = stat.size,
   2334         .stat_inode = stat.inode,
   2335         .stat_mtime = stat.mtime,
   2336     };
   2337     var iovecs = [_]std.posix.iovec_const{
   2338         .{
   2339             .iov_base = @as([*]const u8, @ptrCast(&header)),
   2340             .iov_len = @sizeOf(Zir.Header),
   2341         },
   2342         .{
   2343             .iov_base = @as([*]const u8, @ptrCast(file.zir.instructions.items(.tag).ptr)),
   2344             .iov_len = file.zir.instructions.len,
   2345         },
   2346         .{
   2347             .iov_base = data_ptr,
   2348             .iov_len = file.zir.instructions.len * 8,
   2349         },
   2350         .{
   2351             .iov_base = file.zir.string_bytes.ptr,
   2352             .iov_len = file.zir.string_bytes.len,
   2353         },
   2354         .{
   2355             .iov_base = @as([*]const u8, @ptrCast(file.zir.extra.ptr)),
   2356             .iov_len = file.zir.extra.len * 4,
   2357         },
   2358     };
   2359     cache_file.writevAll(&iovecs) catch |err| {
   2360         log.warn("unable to write cached ZIR code for {}{s} to {}{s}: {s}", .{
   2361             file.mod.root, file.sub_file_path, cache_directory, &hex_digest, @errorName(err),
   2362         });
   2363     };
   2364 
   2365     if (file.zir.hasCompileErrors()) {
   2366         {
   2367             comp.mutex.lock();
   2368             defer comp.mutex.unlock();
   2369             try mod.failed_files.putNoClobber(gpa, file, null);
   2370         }
   2371         file.status = .astgen_failure;
   2372         return error.AnalysisFail;
   2373     }
   2374 
   2375     if (file.prev_zir) |prev_zir| {
   2376         try updateZirRefs(mod, file, prev_zir.*);
   2377         // No need to keep previous ZIR.
   2378         prev_zir.deinit(gpa);
   2379         gpa.destroy(prev_zir);
   2380         file.prev_zir = null;
   2381     }
   2382 
   2383     if (file.root_decl.unwrap()) |root_decl| {
   2384         // The root of this file must be re-analyzed, since the file has changed.
   2385         comp.mutex.lock();
   2386         defer comp.mutex.unlock();
   2387 
   2388         log.debug("outdated root Decl: {}", .{root_decl});
   2389         try mod.outdated_file_root.put(gpa, root_decl, {});
   2390     }
   2391 }
   2392 
   2393 pub fn loadZirCache(gpa: Allocator, cache_file: std.fs.File) !Zir {
   2394     return loadZirCacheBody(gpa, try cache_file.reader().readStruct(Zir.Header), cache_file);
   2395 }
   2396 
   2397 fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File) !Zir {
   2398     var instructions: std.MultiArrayList(Zir.Inst) = .{};
   2399     errdefer instructions.deinit(gpa);
   2400 
   2401     try instructions.setCapacity(gpa, header.instructions_len);
   2402     instructions.len = header.instructions_len;
   2403 
   2404     var zir: Zir = .{
   2405         .instructions = instructions.toOwnedSlice(),
   2406         .string_bytes = &.{},
   2407         .extra = &.{},
   2408     };
   2409     errdefer zir.deinit(gpa);
   2410 
   2411     zir.string_bytes = try gpa.alloc(u8, header.string_bytes_len);
   2412     zir.extra = try gpa.alloc(u32, header.extra_len);
   2413 
   2414     const safety_buffer = if (data_has_safety_tag)
   2415         try gpa.alloc([8]u8, header.instructions_len)
   2416     else
   2417         undefined;
   2418     defer if (data_has_safety_tag) gpa.free(safety_buffer);
   2419 
   2420     const data_ptr = if (data_has_safety_tag)
   2421         @as([*]u8, @ptrCast(safety_buffer.ptr))
   2422     else
   2423         @as([*]u8, @ptrCast(zir.instructions.items(.data).ptr));
   2424 
   2425     var iovecs = [_]std.posix.iovec{
   2426         .{
   2427             .iov_base = @as([*]u8, @ptrCast(zir.instructions.items(.tag).ptr)),
   2428             .iov_len = header.instructions_len,
   2429         },
   2430         .{
   2431             .iov_base = data_ptr,
   2432             .iov_len = header.instructions_len * 8,
   2433         },
   2434         .{
   2435             .iov_base = zir.string_bytes.ptr,
   2436             .iov_len = header.string_bytes_len,
   2437         },
   2438         .{
   2439             .iov_base = @as([*]u8, @ptrCast(zir.extra.ptr)),
   2440             .iov_len = header.extra_len * 4,
   2441         },
   2442     };
   2443     const amt_read = try cache_file.readvAll(&iovecs);
   2444     const amt_expected = zir.instructions.len * 9 +
   2445         zir.string_bytes.len +
   2446         zir.extra.len * 4;
   2447     if (amt_read != amt_expected) return error.UnexpectedFileSize;
   2448     if (data_has_safety_tag) {
   2449         const tags = zir.instructions.items(.tag);
   2450         for (zir.instructions.items(.data), 0..) |*data, i| {
   2451             const union_tag = Zir.Inst.Tag.data_tags[@intFromEnum(tags[i])];
   2452             const as_struct = @as(*HackDataLayout, @ptrCast(data));
   2453             as_struct.* = .{
   2454                 .safety_tag = @intFromEnum(union_tag),
   2455                 .data = safety_buffer[i],
   2456             };
   2457         }
   2458     }
   2459 
   2460     return zir;
   2461 }
   2462 
   2463 /// This is called from the AstGen thread pool, so must acquire
   2464 /// the Compilation mutex when acting on shared state.
   2465 fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void {
   2466     const gpa = zcu.gpa;
   2467     const new_zir = file.zir;
   2468 
   2469     var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
   2470     defer inst_map.deinit(gpa);
   2471 
   2472     try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map);
   2473 
   2474     const old_tag = old_zir.instructions.items(.tag);
   2475     const old_data = old_zir.instructions.items(.data);
   2476 
   2477     // TODO: this should be done after all AstGen workers complete, to avoid
   2478     // iterating over this full set for every updated file.
   2479     for (zcu.intern_pool.tracked_insts.keys(), 0..) |*ti, idx_raw| {
   2480         const ti_idx: InternPool.TrackedInst.Index = @enumFromInt(idx_raw);
   2481         if (!std.mem.eql(u8, &ti.path_digest, &file.path_digest)) continue;
   2482         const old_inst = ti.inst;
   2483         ti.inst = inst_map.get(ti.inst) orelse {
   2484             // Tracking failed for this instruction. Invalidate associated `src_hash` deps.
   2485             zcu.comp.mutex.lock();
   2486             defer zcu.comp.mutex.unlock();
   2487             log.debug("tracking failed for %{d}", .{old_inst});
   2488             try zcu.markDependeeOutdated(.{ .src_hash = ti_idx });
   2489             continue;
   2490         };
   2491 
   2492         if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: {
   2493             if (new_zir.getAssociatedSrcHash(ti.inst)) |new_hash| {
   2494                 if (std.zig.srcHashEql(old_hash, new_hash)) {
   2495                     break :hash_changed;
   2496                 }
   2497                 log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{
   2498                     old_inst,
   2499                     ti.inst,
   2500                     std.fmt.fmtSliceHexLower(&old_hash),
   2501                     std.fmt.fmtSliceHexLower(&new_hash),
   2502                 });
   2503             }
   2504             // The source hash associated with this instruction changed - invalidate relevant dependencies.
   2505             zcu.comp.mutex.lock();
   2506             defer zcu.comp.mutex.unlock();
   2507             try zcu.markDependeeOutdated(.{ .src_hash = ti_idx });
   2508         }
   2509 
   2510         // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies.
   2511         const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) {
   2512             .extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) {
   2513                 .struct_decl, .union_decl, .opaque_decl, .enum_decl => true,
   2514                 else => false,
   2515             },
   2516             else => false,
   2517         };
   2518         if (!has_namespace) continue;
   2519 
   2520         var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
   2521         defer old_names.deinit(zcu.gpa);
   2522         {
   2523             var it = old_zir.declIterator(old_inst);
   2524             while (it.next()) |decl_inst| {
   2525                 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;
   2526                 switch (decl_name) {
   2527                     .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
   2528                     _ => if (decl_name.isNamedTest(old_zir)) continue,
   2529                 }
   2530                 const name_zir = decl_name.toString(old_zir).?;
   2531                 const name_ip = try zcu.intern_pool.getOrPutString(
   2532                     zcu.gpa,
   2533                     old_zir.nullTerminatedString(name_zir),
   2534                     .no_embedded_nulls,
   2535                 );
   2536                 try old_names.put(zcu.gpa, name_ip, {});
   2537             }
   2538         }
   2539         var any_change = false;
   2540         {
   2541             var it = new_zir.declIterator(ti.inst);
   2542             while (it.next()) |decl_inst| {
   2543                 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;
   2544                 switch (decl_name) {
   2545                     .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
   2546                     _ => if (decl_name.isNamedTest(old_zir)) continue,
   2547                 }
   2548                 const name_zir = decl_name.toString(old_zir).?;
   2549                 const name_ip = try zcu.intern_pool.getOrPutString(
   2550                     zcu.gpa,
   2551                     old_zir.nullTerminatedString(name_zir),
   2552                     .no_embedded_nulls,
   2553                 );
   2554                 if (!old_names.swapRemove(name_ip)) continue;
   2555                 // Name added
   2556                 any_change = true;
   2557                 zcu.comp.mutex.lock();
   2558                 defer zcu.comp.mutex.unlock();
   2559                 try zcu.markDependeeOutdated(.{ .namespace_name = .{
   2560                     .namespace = ti_idx,
   2561                     .name = name_ip,
   2562                 } });
   2563             }
   2564         }
   2565         // The only elements remaining in `old_names` now are any names which were removed.
   2566         for (old_names.keys()) |name_ip| {
   2567             any_change = true;
   2568             zcu.comp.mutex.lock();
   2569             defer zcu.comp.mutex.unlock();
   2570             try zcu.markDependeeOutdated(.{ .namespace_name = .{
   2571                 .namespace = ti_idx,
   2572                 .name = name_ip,
   2573             } });
   2574         }
   2575 
   2576         if (any_change) {
   2577             zcu.comp.mutex.lock();
   2578             defer zcu.comp.mutex.unlock();
   2579             try zcu.markDependeeOutdated(.{ .namespace = ti_idx });
   2580         }
   2581     }
   2582 }
   2583 
   2584 pub fn markDependeeOutdated(zcu: *Zcu, dependee: InternPool.Dependee) !void {
   2585     log.debug("outdated dependee: {}", .{dependee});
   2586     var it = zcu.intern_pool.dependencyIterator(dependee);
   2587     while (it.next()) |depender| {
   2588         if (zcu.outdated.contains(depender)) {
   2589             // We do not need to increment the PO dep count, as if the outdated
   2590             // dependee is a Decl, we had already marked this as PO.
   2591             continue;
   2592         }
   2593         const opt_po_entry = zcu.potentially_outdated.fetchSwapRemove(depender);
   2594         try zcu.outdated.putNoClobber(
   2595             zcu.gpa,
   2596             depender,
   2597             // We do not need to increment this count for the same reason as above.
   2598             if (opt_po_entry) |e| e.value else 0,
   2599         );
   2600         log.debug("outdated: {}", .{depender});
   2601         if (opt_po_entry == null) {
   2602             // This is a new entry with no PO dependencies.
   2603             try zcu.outdated_ready.put(zcu.gpa, depender, {});
   2604         }
   2605         // If this is a Decl and was not previously PO, we must recursively
   2606         // mark dependencies on its tyval as PO.
   2607         if (opt_po_entry == null) {
   2608             try zcu.markTransitiveDependersPotentiallyOutdated(depender);
   2609         }
   2610     }
   2611 }
   2612 
   2613 fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
   2614     var it = zcu.intern_pool.dependencyIterator(dependee);
   2615     while (it.next()) |depender| {
   2616         if (zcu.outdated.getPtr(depender)) |po_dep_count| {
   2617             // This depender is already outdated, but it now has one
   2618             // less PO dependency!
   2619             po_dep_count.* -= 1;
   2620             if (po_dep_count.* == 0) {
   2621                 try zcu.outdated_ready.put(zcu.gpa, depender, {});
   2622             }
   2623             continue;
   2624         }
   2625         // This depender is definitely at least PO, because this Decl was just analyzed
   2626         // due to being outdated.
   2627         const ptr = zcu.potentially_outdated.getPtr(depender).?;
   2628         if (ptr.* > 1) {
   2629             ptr.* -= 1;
   2630             continue;
   2631         }
   2632 
   2633         // This dependency is no longer PO, i.e. is known to be up-to-date.
   2634         assert(zcu.potentially_outdated.swapRemove(depender));
   2635         // If this is a Decl, we must recursively mark dependencies on its tyval
   2636         // as no longer PO.
   2637         switch (depender.unwrap()) {
   2638             .decl => |decl_index| try zcu.markPoDependeeUpToDate(.{ .decl_val = decl_index }),
   2639             .func => |func_index| try zcu.markPoDependeeUpToDate(.{ .func_ies = func_index }),
   2640         }
   2641     }
   2642 }
   2643 
   2644 /// Given a Depender which is newly outdated or PO, mark all Dependers which may
   2645 /// in turn be PO, due to a dependency on the original Depender's tyval or IES.
   2646 fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: InternPool.Depender) !void {
   2647     var it = zcu.intern_pool.dependencyIterator(switch (maybe_outdated.unwrap()) {
   2648         .decl => |decl_index| .{ .decl_val = decl_index }, // TODO: also `decl_ref` deps when introduced
   2649         .func => |func_index| .{ .func_ies = func_index },
   2650     });
   2651 
   2652     while (it.next()) |po| {
   2653         if (zcu.outdated.getPtr(po)) |po_dep_count| {
   2654             // This dependency is already outdated, but it now has one more PO
   2655             // dependency.
   2656             if (po_dep_count.* == 0) {
   2657                 _ = zcu.outdated_ready.swapRemove(po);
   2658             }
   2659             po_dep_count.* += 1;
   2660             continue;
   2661         }
   2662         if (zcu.potentially_outdated.getPtr(po)) |n| {
   2663             // There is now one more PO dependency.
   2664             n.* += 1;
   2665             continue;
   2666         }
   2667         try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1);
   2668         // This Depender was not already PO, so we must recursively mark its dependers as also PO.
   2669         try zcu.markTransitiveDependersPotentiallyOutdated(po);
   2670     }
   2671 }
   2672 
   2673 pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.Depender {
   2674     if (!zcu.comp.debug_incremental) return null;
   2675 
   2676     if (zcu.outdated.count() == 0 and zcu.potentially_outdated.count() == 0) {
   2677         log.debug("findOutdatedToAnalyze: no outdated depender", .{});
   2678         return null;
   2679     }
   2680 
   2681     // Our goal is to find an outdated Depender which itself has no outdated or
   2682     // PO dependencies. Most of the time, such a Depender will exist - we track
   2683     // them in the `outdated_ready` set for efficiency. However, this is not
   2684     // necessarily the case, since the Decl dependency graph may contain loops
   2685     // via mutually recursive definitions:
   2686     //   pub const A = struct { b: *B };
   2687     //   pub const B = struct { b: *A };
   2688     // In this case, we must defer to more complex logic below.
   2689 
   2690     if (zcu.outdated_ready.count() > 0) {
   2691         log.debug("findOutdatedToAnalyze: trivial '{s} {d}'", .{
   2692             @tagName(zcu.outdated_ready.keys()[0].unwrap()),
   2693             switch (zcu.outdated_ready.keys()[0].unwrap()) {
   2694                 inline else => |x| @intFromEnum(x),
   2695             },
   2696         });
   2697         return zcu.outdated_ready.keys()[0];
   2698     }
   2699 
   2700     // Next, we will see if there is any outdated file root which was not in
   2701     // `outdated`. This set will be small (number of files changed in this
   2702     // update), so it's alright for us to just iterate here.
   2703     for (zcu.outdated_file_root.keys()) |file_decl| {
   2704         const decl_depender = InternPool.Depender.wrap(.{ .decl = file_decl });
   2705         if (zcu.outdated.contains(decl_depender)) {
   2706             // Since we didn't hit this in the first loop, this Decl must have
   2707             // pending dependencies, so is ineligible.
   2708             continue;
   2709         }
   2710         if (zcu.potentially_outdated.contains(decl_depender)) {
   2711             // This Decl's struct may or may not need to be recreated depending
   2712             // on whether it is outdated. If we analyzed it now, we would have
   2713             // to assume it was outdated and recreate it!
   2714             continue;
   2715         }
   2716         log.debug("findOutdatedToAnalyze: outdated file root decl '{d}'", .{file_decl});
   2717         return decl_depender;
   2718     }
   2719 
   2720     // There is no single Depender which is ready for re-analysis. Instead, we
   2721     // must assume that some Decl with PO dependencies is outdated - e.g. in the
   2722     // above example we arbitrarily pick one of A or B. We should select a Decl,
   2723     // since a Decl is definitely responsible for the loop in the dependency
   2724     // graph (since you can't depend on a runtime function analysis!).
   2725 
   2726     // The choice of this Decl could have a big impact on how much total
   2727     // analysis we perform, since if analysis concludes its tyval is unchanged,
   2728     // then other PO Dependers may be resolved as up-to-date. To hopefully avoid
   2729     // doing too much work, let's find a Decl which the most things depend on -
   2730     // the idea is that this will resolve a lot of loops (but this is only a
   2731     // heuristic).
   2732 
   2733     log.debug("findOutdatedToAnalyze: no trivial ready, using heuristic; {d} outdated, {d} PO", .{
   2734         zcu.outdated.count(),
   2735         zcu.potentially_outdated.count(),
   2736     });
   2737 
   2738     var chosen_decl_idx: ?Decl.Index = null;
   2739     var chosen_decl_dependers: u32 = undefined;
   2740 
   2741     for (zcu.outdated.keys()) |depender| {
   2742         const decl_index = switch (depender.unwrap()) {
   2743             .decl => |d| d,
   2744             .func => continue,
   2745         };
   2746 
   2747         var n: u32 = 0;
   2748         var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index });
   2749         while (it.next()) |_| n += 1;
   2750 
   2751         if (chosen_decl_idx == null or n > chosen_decl_dependers) {
   2752             chosen_decl_idx = decl_index;
   2753             chosen_decl_dependers = n;
   2754         }
   2755     }
   2756 
   2757     for (zcu.potentially_outdated.keys()) |depender| {
   2758         const decl_index = switch (depender.unwrap()) {
   2759             .decl => |d| d,
   2760             .func => continue,
   2761         };
   2762 
   2763         var n: u32 = 0;
   2764         var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index });
   2765         while (it.next()) |_| n += 1;
   2766 
   2767         if (chosen_decl_idx == null or n > chosen_decl_dependers) {
   2768             chosen_decl_idx = decl_index;
   2769             chosen_decl_dependers = n;
   2770         }
   2771     }
   2772 
   2773     log.debug("findOutdatedToAnalyze: heuristic returned Decl {d} ({d} dependers)", .{
   2774         chosen_decl_idx.?,
   2775         chosen_decl_dependers,
   2776     });
   2777 
   2778     return InternPool.Depender.wrap(.{ .decl = chosen_decl_idx.? });
   2779 }
   2780 
   2781 /// During an incremental update, before semantic analysis, call this to flush all values from
   2782 /// `retryable_failures` and mark them as outdated so they get re-analyzed.
   2783 pub fn flushRetryableFailures(zcu: *Zcu) !void {
   2784     const gpa = zcu.gpa;
   2785     for (zcu.retryable_failures.items) |depender| {
   2786         if (zcu.outdated.contains(depender)) continue;
   2787         if (zcu.potentially_outdated.fetchSwapRemove(depender)) |kv| {
   2788             // This Depender was already PO, but we now consider it outdated.
   2789             // Any transitive dependencies are already marked PO.
   2790             try zcu.outdated.put(gpa, depender, kv.value);
   2791             continue;
   2792         }
   2793         // This Depender was not marked PO, but is now outdated. Mark it as
   2794         // such, then recursively mark transitive dependencies as PO.
   2795         try zcu.outdated.put(gpa, depender, 0);
   2796         try zcu.markTransitiveDependersPotentiallyOutdated(depender);
   2797     }
   2798     zcu.retryable_failures.clearRetainingCapacity();
   2799 }
   2800 
   2801 pub fn mapOldZirToNew(
   2802     gpa: Allocator,
   2803     old_zir: Zir,
   2804     new_zir: Zir,
   2805     inst_map: *std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index),
   2806 ) Allocator.Error!void {
   2807     // Contain ZIR indexes of namespace declaration instructions, e.g. struct_decl, union_decl, etc.
   2808     // Not `declaration`, as this does not create a namespace.
   2809     const MatchedZirDecl = struct {
   2810         old_inst: Zir.Inst.Index,
   2811         new_inst: Zir.Inst.Index,
   2812     };
   2813     var match_stack: ArrayListUnmanaged(MatchedZirDecl) = .{};
   2814     defer match_stack.deinit(gpa);
   2815 
   2816     // Main struct inst is always matched
   2817     try match_stack.append(gpa, .{
   2818         .old_inst = .main_struct_inst,
   2819         .new_inst = .main_struct_inst,
   2820     });
   2821 
   2822     // Used as temporary buffers for namespace declaration instructions
   2823     var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
   2824     defer old_decls.deinit();
   2825     var new_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
   2826     defer new_decls.deinit();
   2827 
   2828     while (match_stack.popOrNull()) |match_item| {
   2829         // Match the namespace declaration itself
   2830         try inst_map.put(gpa, match_item.old_inst, match_item.new_inst);
   2831 
   2832         // Maps decl name to `declaration` instruction.
   2833         var named_decls: std.StringHashMapUnmanaged(Zir.Inst.Index) = .{};
   2834         defer named_decls.deinit(gpa);
   2835         // Maps test name to `declaration` instruction.
   2836         var named_tests: std.StringHashMapUnmanaged(Zir.Inst.Index) = .{};
   2837         defer named_tests.deinit(gpa);
   2838         // All unnamed tests, in order, for a best-effort match.
   2839         var unnamed_tests: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
   2840         defer unnamed_tests.deinit(gpa);
   2841         // All comptime declarations, in order, for a best-effort match.
   2842         var comptime_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
   2843         defer comptime_decls.deinit(gpa);
   2844         // All usingnamespace declarations, in order, for a best-effort match.
   2845         var usingnamespace_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
   2846         defer usingnamespace_decls.deinit(gpa);
   2847 
   2848         {
   2849             var old_decl_it = old_zir.declIterator(match_item.old_inst);
   2850             while (old_decl_it.next()) |old_decl_inst| {
   2851                 const old_decl, _ = old_zir.getDeclaration(old_decl_inst);
   2852                 switch (old_decl.name) {
   2853                     .@"comptime" => try comptime_decls.append(gpa, old_decl_inst),
   2854                     .@"usingnamespace" => try usingnamespace_decls.append(gpa, old_decl_inst),
   2855                     .unnamed_test, .decltest => try unnamed_tests.append(gpa, old_decl_inst),
   2856                     _ => {
   2857                         const name_nts = old_decl.name.toString(old_zir).?;
   2858                         const name = old_zir.nullTerminatedString(name_nts);
   2859                         if (old_decl.name.isNamedTest(old_zir)) {
   2860                             try named_tests.put(gpa, name, old_decl_inst);
   2861                         } else {
   2862                             try named_decls.put(gpa, name, old_decl_inst);
   2863                         }
   2864                     },
   2865                 }
   2866             }
   2867         }
   2868 
   2869         var unnamed_test_idx: u32 = 0;
   2870         var comptime_decl_idx: u32 = 0;
   2871         var usingnamespace_decl_idx: u32 = 0;
   2872 
   2873         var new_decl_it = new_zir.declIterator(match_item.new_inst);
   2874         while (new_decl_it.next()) |new_decl_inst| {
   2875             const new_decl, _ = new_zir.getDeclaration(new_decl_inst);
   2876             // Attempt to match this to a declaration in the old ZIR:
   2877             // * For named declarations (`const`/`var`/`fn`), we match based on name.
   2878             // * For named tests (`test "foo"`), we also match based on name.
   2879             // * For unnamed tests and decltests, we match based on order.
   2880             // * For comptime blocks, we match based on order.
   2881             // * For usingnamespace decls, we match based on order.
   2882             // If we cannot match this declaration, we can't match anything nested inside of it either, so we just `continue`.
   2883             const old_decl_inst = switch (new_decl.name) {
   2884                 .@"comptime" => inst: {
   2885                     if (comptime_decl_idx == comptime_decls.items.len) continue;
   2886                     defer comptime_decl_idx += 1;
   2887                     break :inst comptime_decls.items[comptime_decl_idx];
   2888                 },
   2889                 .@"usingnamespace" => inst: {
   2890                     if (usingnamespace_decl_idx == usingnamespace_decls.items.len) continue;
   2891                     defer usingnamespace_decl_idx += 1;
   2892                     break :inst usingnamespace_decls.items[usingnamespace_decl_idx];
   2893                 },
   2894                 .unnamed_test, .decltest => inst: {
   2895                     if (unnamed_test_idx == unnamed_tests.items.len) continue;
   2896                     defer unnamed_test_idx += 1;
   2897                     break :inst unnamed_tests.items[unnamed_test_idx];
   2898                 },
   2899                 _ => inst: {
   2900                     const name_nts = new_decl.name.toString(old_zir).?;
   2901                     const name = new_zir.nullTerminatedString(name_nts);
   2902                     if (new_decl.name.isNamedTest(new_zir)) {
   2903                         break :inst named_tests.get(name) orelse continue;
   2904                     } else {
   2905                         break :inst named_decls.get(name) orelse continue;
   2906                     }
   2907                 },
   2908             };
   2909 
   2910             // Match the `declaration` instruction
   2911             try inst_map.put(gpa, old_decl_inst, new_decl_inst);
   2912 
   2913             // Find namespace declarations within this declaration
   2914             try old_zir.findDecls(&old_decls, old_decl_inst);
   2915             try new_zir.findDecls(&new_decls, new_decl_inst);
   2916 
   2917             // We don't have any smart way of matching up these namespace declarations, so we always
   2918             // correlate them based on source order.
   2919             const n = @min(old_decls.items.len, new_decls.items.len);
   2920             try match_stack.ensureUnusedCapacity(gpa, n);
   2921             for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {
   2922                 match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
   2923             }
   2924         }
   2925     }
   2926 }
   2927 
   2928 /// Like `ensureDeclAnalyzed`, but the Decl is a file's root Decl.
   2929 pub fn ensureFileAnalyzed(zcu: *Zcu, file: *File) SemaError!void {
   2930     if (file.root_decl.unwrap()) |existing_root| {
   2931         return zcu.ensureDeclAnalyzed(existing_root);
   2932     } else {
   2933         return zcu.semaFile(file);
   2934     }
   2935 }
   2936 
   2937 /// This ensures that the Decl will have an up-to-date Type and Value populated.
   2938 /// However the resolution status of the Type may not be fully resolved.
   2939 /// For example an inferred error set is not resolved until after `analyzeFnBody`.
   2940 /// is called.
   2941 pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
   2942     const tracy = trace(@src());
   2943     defer tracy.end();
   2944 
   2945     const decl = mod.declPtr(decl_index);
   2946 
   2947     log.debug("ensureDeclAnalyzed '{d}' (name '{}')", .{
   2948         @intFromEnum(decl_index),
   2949         decl.name.fmt(&mod.intern_pool),
   2950     });
   2951 
   2952     // Determine whether or not this Decl is outdated, i.e. requires re-analysis
   2953     // even if `complete`. If a Decl is PO, we pessismistically assume that it
   2954     // *does* require re-analysis, to ensure that the Decl is definitely
   2955     // up-to-date when this function returns.
   2956 
   2957     // If analysis occurs in a poor order, this could result in over-analysis.
   2958     // We do our best to avoid this by the other dependency logic in this file
   2959     // which tries to limit re-analysis to Decls whose previously listed
   2960     // dependencies are all up-to-date.
   2961 
   2962     const decl_as_depender = InternPool.Depender.wrap(.{ .decl = decl_index });
   2963     const decl_was_outdated = mod.outdated.swapRemove(decl_as_depender) or
   2964         mod.potentially_outdated.swapRemove(decl_as_depender);
   2965 
   2966     if (decl_was_outdated) {
   2967         _ = mod.outdated_ready.swapRemove(decl_as_depender);
   2968     }
   2969 
   2970     const was_outdated = mod.outdated_file_root.swapRemove(decl_index) or decl_was_outdated;
   2971 
   2972     switch (decl.analysis) {
   2973         .in_progress => unreachable,
   2974 
   2975         .file_failure => return error.AnalysisFail,
   2976 
   2977         .sema_failure,
   2978         .dependency_failure,
   2979         .codegen_failure,
   2980         => if (!was_outdated) return error.AnalysisFail,
   2981 
   2982         .complete => if (!was_outdated) return,
   2983 
   2984         .unreferenced => {},
   2985     }
   2986 
   2987     if (was_outdated) {
   2988         // The exports this Decl performs will be re-discovered, so we remove them here
   2989         // prior to re-analysis.
   2990         if (build_options.only_c) unreachable;
   2991         try mod.deleteDeclExports(decl_index);
   2992     }
   2993 
   2994     var decl_prog_node = mod.sema_prog_node.start("", 0);
   2995     decl_prog_node.activate();
   2996     defer decl_prog_node.end();
   2997 
   2998     const sema_result: SemaDeclResult = blk: {
   2999         if (decl.zir_decl_index == .none and !mod.declIsRoot(decl_index)) {
   3000             // Anonymous decl. We don't semantically analyze these.
   3001             break :blk .{
   3002                 .invalidate_decl_val = false,
   3003                 .invalidate_decl_ref = false,
   3004             };
   3005         }
   3006 
   3007         if (mod.declIsRoot(decl_index)) {
   3008             const changed = try mod.semaFileUpdate(decl.getFileScope(mod), decl_was_outdated);
   3009             break :blk .{
   3010                 .invalidate_decl_val = changed,
   3011                 .invalidate_decl_ref = changed,
   3012             };
   3013         }
   3014 
   3015         break :blk mod.semaDecl(decl_index) catch |err| switch (err) {
   3016             error.AnalysisFail => {
   3017                 if (decl.analysis == .in_progress) {
   3018                     // If this decl caused the compile error, the analysis field would
   3019                     // be changed to indicate it was this Decl's fault. Because this
   3020                     // did not happen, we infer here that it was a dependency failure.
   3021                     decl.analysis = .dependency_failure;
   3022                 }
   3023                 return error.AnalysisFail;
   3024             },
   3025             error.NeededSourceLocation => unreachable,
   3026             error.GenericPoison => unreachable,
   3027             else => |e| {
   3028                 decl.analysis = .sema_failure;
   3029                 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
   3030                 try mod.retryable_failures.append(mod.gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
   3031                 mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
   3032                     mod.gpa,
   3033                     decl.srcLoc(mod),
   3034                     "unable to analyze: {s}",
   3035                     .{@errorName(e)},
   3036                 ));
   3037                 return error.AnalysisFail;
   3038             },
   3039         };
   3040     };
   3041 
   3042     // TODO: we do not yet have separate dependencies for decl values vs types.
   3043     if (decl_was_outdated) {
   3044         if (sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref) {
   3045             log.debug("Decl tv invalidated ('{d}')", .{@intFromEnum(decl_index)});
   3046             // This dependency was marked as PO, meaning dependees were waiting
   3047             // on its analysis result, and it has turned out to be outdated.
   3048             // Update dependees accordingly.
   3049             try mod.markDependeeOutdated(.{ .decl_val = decl_index });
   3050         } else {
   3051             log.debug("Decl tv up-to-date ('{d}')", .{@intFromEnum(decl_index)});
   3052             // This dependency was previously PO, but turned out to be up-to-date.
   3053             // We do not need to queue successive analysis.
   3054             try mod.markPoDependeeUpToDate(.{ .decl_val = decl_index });
   3055         }
   3056     }
   3057 }
   3058 
   3059 pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.Index) SemaError!void {
   3060     const tracy = trace(@src());
   3061     defer tracy.end();
   3062 
   3063     const gpa = zcu.gpa;
   3064     const ip = &zcu.intern_pool;
   3065 
   3066     // We only care about the uncoerced function.
   3067     // We need to do this for the "orphaned function" check below to be valid.
   3068     const func_index = ip.unwrapCoercedFunc(maybe_coerced_func_index);
   3069 
   3070     const func = zcu.funcInfo(maybe_coerced_func_index);
   3071     const decl_index = func.owner_decl;
   3072     const decl = zcu.declPtr(decl_index);
   3073 
   3074     log.debug("ensureFuncBodyAnalyzed '{d}' (instance of '{}')", .{
   3075         @intFromEnum(func_index),
   3076         decl.name.fmt(ip),
   3077     });
   3078 
   3079     // First, our owner decl must be up-to-date. This will always be the case
   3080     // during the first update, but may not on successive updates if we happen
   3081     // to get analyzed before our parent decl.
   3082     try zcu.ensureDeclAnalyzed(decl_index);
   3083 
   3084     // On an update, it's possible this function changed such that our owner
   3085     // decl now refers to a different function, making this one orphaned. If
   3086     // that's the case, we should remove this function from the binary.
   3087     if (decl.val.ip_index != func_index) {
   3088         try zcu.markDependeeOutdated(.{ .func_ies = func_index });
   3089         ip.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));
   3090         ip.remove(func_index);
   3091         @panic("TODO: remove orphaned function from binary");
   3092     }
   3093 
   3094     // We'll want to remember what the IES used to be before the update for
   3095     // dependency invalidation purposes.
   3096     const old_resolved_ies = if (func.analysis(ip).inferred_error_set)
   3097         func.resolvedErrorSet(ip).*
   3098     else
   3099         .none;
   3100 
   3101     switch (decl.analysis) {
   3102         .unreferenced => unreachable,
   3103         .in_progress => unreachable,
   3104 
   3105         .codegen_failure => unreachable, // functions do not perform constant value generation
   3106 
   3107         .file_failure,
   3108         .sema_failure,
   3109         .dependency_failure,
   3110         => return error.AnalysisFail,
   3111 
   3112         .complete => {},
   3113     }
   3114 
   3115     const func_as_depender = InternPool.Depender.wrap(.{ .func = func_index });
   3116     const was_outdated = zcu.outdated.swapRemove(func_as_depender) or
   3117         zcu.potentially_outdated.swapRemove(func_as_depender);
   3118 
   3119     if (was_outdated) {
   3120         _ = zcu.outdated_ready.swapRemove(func_as_depender);
   3121     }
   3122 
   3123     switch (func.analysis(ip).state) {
   3124         .success => if (!was_outdated) return,
   3125         .sema_failure,
   3126         .dependency_failure,
   3127         .codegen_failure,
   3128         => if (!was_outdated) return error.AnalysisFail,
   3129         .none, .queued => {},
   3130         .in_progress => unreachable,
   3131         .inline_only => unreachable, // don't queue work for this
   3132     }
   3133 
   3134     log.debug("analyze and generate fn body '{d}'; reason='{s}'", .{
   3135         @intFromEnum(func_index),
   3136         if (was_outdated) "outdated" else "never analyzed",
   3137     });
   3138 
   3139     var tmp_arena = std.heap.ArenaAllocator.init(gpa);
   3140     defer tmp_arena.deinit();
   3141     const sema_arena = tmp_arena.allocator();
   3142 
   3143     var air = zcu.analyzeFnBody(func_index, sema_arena) catch |err| switch (err) {
   3144         error.AnalysisFail => {
   3145             if (func.analysis(ip).state == .in_progress) {
   3146                 // If this decl caused the compile error, the analysis field would
   3147                 // be changed to indicate it was this Decl's fault. Because this
   3148                 // did not happen, we infer here that it was a dependency failure.
   3149                 func.analysis(ip).state = .dependency_failure;
   3150             }
   3151             return error.AnalysisFail;
   3152         },
   3153         error.OutOfMemory => return error.OutOfMemory,
   3154     };
   3155     defer air.deinit(gpa);
   3156 
   3157     const invalidate_ies_deps = i: {
   3158         if (!was_outdated) break :i false;
   3159         if (!func.analysis(ip).inferred_error_set) break :i true;
   3160         const new_resolved_ies = func.resolvedErrorSet(ip).*;
   3161         break :i new_resolved_ies != old_resolved_ies;
   3162     };
   3163     if (invalidate_ies_deps) {
   3164         log.debug("func IES invalidated ('{d}')", .{@intFromEnum(func_index)});
   3165         try zcu.markDependeeOutdated(.{ .func_ies = func_index });
   3166     } else if (was_outdated) {
   3167         log.debug("func IES up-to-date ('{d}')", .{@intFromEnum(func_index)});
   3168         try zcu.markPoDependeeUpToDate(.{ .func_ies = func_index });
   3169     }
   3170 
   3171     const comp = zcu.comp;
   3172 
   3173     const dump_air = build_options.enable_debug_extensions and comp.verbose_air;
   3174     const dump_llvm_ir = build_options.enable_debug_extensions and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null);
   3175 
   3176     if (comp.bin_file == null and zcu.llvm_object == null and !dump_air and !dump_llvm_ir) {
   3177         return;
   3178     }
   3179 
   3180     var liveness = try Liveness.analyze(gpa, air, ip);
   3181     defer liveness.deinit(gpa);
   3182 
   3183     if (dump_air) {
   3184         const fqn = try decl.fullyQualifiedName(zcu);
   3185         std.debug.print("# Begin Function AIR: {}:\n", .{fqn.fmt(ip)});
   3186         @import("print_air.zig").dump(zcu, air, liveness);
   3187         std.debug.print("# End Function AIR: {}\n\n", .{fqn.fmt(ip)});
   3188     }
   3189 
   3190     if (std.debug.runtime_safety) {
   3191         var verify = Liveness.Verify{
   3192             .gpa = gpa,
   3193             .air = air,
   3194             .liveness = liveness,
   3195             .intern_pool = ip,
   3196         };
   3197         defer verify.deinit();
   3198 
   3199         verify.verify() catch |err| switch (err) {
   3200             error.OutOfMemory => return error.OutOfMemory,
   3201             else => {
   3202                 try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);
   3203                 zcu.failed_decls.putAssumeCapacityNoClobber(
   3204                     decl_index,
   3205                     try Module.ErrorMsg.create(
   3206                         gpa,
   3207                         decl.srcLoc(zcu),
   3208                         "invalid liveness: {s}",
   3209                         .{@errorName(err)},
   3210                     ),
   3211                 );
   3212                 func.analysis(ip).state = .codegen_failure;
   3213                 return;
   3214             },
   3215         };
   3216     }
   3217 
   3218     if (comp.bin_file) |lf| {
   3219         lf.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {
   3220             error.OutOfMemory => return error.OutOfMemory,
   3221             error.AnalysisFail => {
   3222                 func.analysis(ip).state = .codegen_failure;
   3223             },
   3224             else => {
   3225                 try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);
   3226                 zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create(
   3227                     gpa,
   3228                     decl.srcLoc(zcu),
   3229                     "unable to codegen: {s}",
   3230                     .{@errorName(err)},
   3231                 ));
   3232                 func.analysis(ip).state = .codegen_failure;
   3233                 try zcu.retryable_failures.append(zcu.gpa, InternPool.Depender.wrap(.{ .func = func_index }));
   3234             },
   3235         };
   3236     } else if (zcu.llvm_object) |llvm_object| {
   3237         if (build_options.only_c) unreachable;
   3238         llvm_object.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {
   3239             error.OutOfMemory => return error.OutOfMemory,
   3240             error.AnalysisFail => {
   3241                 func.analysis(ip).state = .codegen_failure;
   3242             },
   3243         };
   3244     }
   3245 }
   3246 
   3247 /// Ensure this function's body is or will be analyzed and emitted. This should
   3248 /// be called whenever a potential runtime call of a function is seen.
   3249 ///
   3250 /// The caller is responsible for ensuring the function decl itself is already
   3251 /// analyzed, and for ensuring it can exist at runtime (see
   3252 /// `sema.fnHasRuntimeBits`). This function does *not* guarantee that the body
   3253 /// will be analyzed when it returns: for that, see `ensureFuncBodyAnalyzed`.
   3254 pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index) !void {
   3255     const ip = &mod.intern_pool;
   3256     const func = mod.funcInfo(func_index);
   3257     const decl_index = func.owner_decl;
   3258     const decl = mod.declPtr(decl_index);
   3259 
   3260     switch (decl.analysis) {
   3261         .unreferenced => unreachable,
   3262         .in_progress => unreachable,
   3263 
   3264         .file_failure,
   3265         .sema_failure,
   3266         .codegen_failure,
   3267         .dependency_failure,
   3268         // Analysis of the function Decl itself failed, but we've already
   3269         // emitted an error for that. The callee doesn't need the function to be
   3270         // analyzed right now, so its analysis can safely continue.
   3271         => return,
   3272 
   3273         .complete => {},
   3274     }
   3275 
   3276     assert(decl.has_tv);
   3277 
   3278     const func_as_depender = InternPool.Depender.wrap(.{ .func = func_index });
   3279     const is_outdated = mod.outdated.contains(func_as_depender) or
   3280         mod.potentially_outdated.contains(func_as_depender);
   3281 
   3282     switch (func.analysis(ip).state) {
   3283         .none => {},
   3284         .queued => return,
   3285         // As above, we don't need to forward errors here.
   3286         .sema_failure,
   3287         .dependency_failure,
   3288         .codegen_failure,
   3289         .success,
   3290         => if (!is_outdated) return,
   3291         .in_progress => return,
   3292         .inline_only => unreachable, // don't queue work for this
   3293     }
   3294 
   3295     // Decl itself is safely analyzed, and body analysis is not yet queued
   3296 
   3297     try mod.comp.work_queue.writeItem(.{ .codegen_func = func_index });
   3298     if (mod.emit_h != null) {
   3299         // TODO: we ideally only want to do this if the function's type changed
   3300         // since the last update
   3301         try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index });
   3302     }
   3303     func.analysis(ip).state = .queued;
   3304 }
   3305 
   3306 /// https://github.com/ziglang/zig/issues/14307
   3307 pub fn semaPkg(mod: *Module, pkg: *Package.Module) !void {
   3308     const file = (try mod.importPkg(pkg)).file;
   3309     if (file.root_decl == .none) {
   3310         return mod.semaFile(file);
   3311     }
   3312 }
   3313 
   3314 fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespace.Index, file: *File) Allocator.Error!InternPool.Index {
   3315     const gpa = zcu.gpa;
   3316     const ip = &zcu.intern_pool;
   3317     const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
   3318     assert(extended.opcode == .struct_decl);
   3319     const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
   3320     assert(!small.has_captures_len);
   3321     assert(!small.has_backing_int);
   3322     assert(small.layout == .auto);
   3323     var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
   3324     const fields_len = if (small.has_fields_len) blk: {
   3325         const fields_len = file.zir.extra[extra_index];
   3326         extra_index += 1;
   3327         break :blk fields_len;
   3328     } else 0;
   3329     const decls_len = if (small.has_decls_len) blk: {
   3330         const decls_len = file.zir.extra[extra_index];
   3331         extra_index += 1;
   3332         break :blk decls_len;
   3333     } else 0;
   3334     const decls = file.zir.bodySlice(extra_index, decls_len);
   3335     extra_index += decls_len;
   3336 
   3337     const tracked_inst = try ip.trackZir(gpa, file, .main_struct_inst);
   3338     const wip_ty = switch (try ip.getStructType(gpa, .{
   3339         .layout = .auto,
   3340         .fields_len = fields_len,
   3341         .known_non_opv = small.known_non_opv,
   3342         .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
   3343         .is_tuple = small.is_tuple,
   3344         .any_comptime_fields = small.any_comptime_fields,
   3345         .any_default_inits = small.any_default_inits,
   3346         .inits_resolved = false,
   3347         .any_aligned_fields = small.any_aligned_fields,
   3348         .has_namespace = true,
   3349         .key = .{ .declared = .{
   3350             .zir_index = tracked_inst,
   3351             .captures = &.{},
   3352         } },
   3353     })) {
   3354         .existing => unreachable, // we wouldn't be analysing the file root if this type existed
   3355         .wip => |wip| wip,
   3356     };
   3357     errdefer wip_ty.cancel(ip);
   3358 
   3359     if (zcu.comp.debug_incremental) {
   3360         try ip.addDependency(
   3361             gpa,
   3362             InternPool.Depender.wrap(.{ .decl = decl_index }),
   3363             .{ .src_hash = tracked_inst },
   3364         );
   3365     }
   3366 
   3367     const decl = zcu.declPtr(decl_index);
   3368     decl.val = Value.fromInterned(wip_ty.index);
   3369     decl.has_tv = true;
   3370     decl.owns_tv = true;
   3371     decl.analysis = .complete;
   3372 
   3373     try zcu.scanNamespace(namespace_index, decls, decl);
   3374 
   3375     return wip_ty.finish(ip, decl_index, namespace_index.toOptional());
   3376 }
   3377 
   3378 /// Re-analyze the root Decl of a file on an incremental update.
   3379 /// If `type_outdated`, the struct type itself is considered outdated and is
   3380 /// reconstructed at a new InternPool index. Otherwise, the namespace is just
   3381 /// re-analyzed. Returns whether the decl's tyval was invalidated.
   3382 fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {
   3383     const decl = zcu.declPtr(file.root_decl.unwrap().?);
   3384 
   3385     log.debug("semaFileUpdate mod={s} sub_file_path={s} type_outdated={}", .{
   3386         file.mod.fully_qualified_name,
   3387         file.sub_file_path,
   3388         type_outdated,
   3389     });
   3390 
   3391     if (file.status != .success_zir) {
   3392         if (decl.analysis == .file_failure) {
   3393             return false;
   3394         } else {
   3395             decl.analysis = .file_failure;
   3396             return true;
   3397         }
   3398     }
   3399 
   3400     if (decl.analysis == .file_failure) {
   3401         // No struct type currently exists. Create one!
   3402         _ = try zcu.getFileRootStruct(file.root_decl.unwrap().?, decl.src_namespace, file);
   3403         return true;
   3404     }
   3405 
   3406     assert(decl.has_tv);
   3407     assert(decl.owns_tv);
   3408 
   3409     if (type_outdated) {
   3410         // Invalidate the existing type, reusing the decl and namespace.
   3411         zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.Depender.wrap(.{ .decl = file.root_decl.unwrap().? }));
   3412         zcu.intern_pool.remove(decl.val.toIntern());
   3413         decl.val = undefined;
   3414         _ = try zcu.getFileRootStruct(file.root_decl.unwrap().?, decl.src_namespace, file);
   3415         return true;
   3416     }
   3417 
   3418     // Only the struct's namespace is outdated.
   3419     // Preserve the type - just scan the namespace again.
   3420 
   3421     const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
   3422     const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
   3423 
   3424     var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
   3425     extra_index += @intFromBool(small.has_fields_len);
   3426     const decls_len = if (small.has_decls_len) blk: {
   3427         const decls_len = file.zir.extra[extra_index];
   3428         extra_index += 1;
   3429         break :blk decls_len;
   3430     } else 0;
   3431     const decls = file.zir.bodySlice(extra_index, decls_len);
   3432 
   3433     if (!type_outdated) {
   3434         try zcu.scanNamespace(decl.src_namespace, decls, decl);
   3435     }
   3436 
   3437     return false;
   3438 }
   3439 
   3440 /// Regardless of the file status, will create a `Decl` if none exists so that we can track
   3441 /// dependencies and re-analyze when the file becomes outdated.
   3442 fn semaFile(mod: *Module, file: *File) SemaError!void {
   3443     const tracy = trace(@src());
   3444     defer tracy.end();
   3445 
   3446     assert(file.root_decl == .none);
   3447 
   3448     const gpa = mod.gpa;
   3449     log.debug("semaFile mod={s} sub_file_path={s}", .{
   3450         file.mod.fully_qualified_name, file.sub_file_path,
   3451     });
   3452 
   3453     // Because these three things each reference each other, `undefined`
   3454     // placeholders are used before being set after the struct type gains an
   3455     // InternPool index.
   3456     const new_namespace_index = try mod.createNamespace(.{
   3457         .parent = .none,
   3458         .decl_index = undefined,
   3459         .file_scope = file,
   3460     });
   3461     errdefer mod.destroyNamespace(new_namespace_index);
   3462 
   3463     const new_decl_index = try mod.allocateNewDecl(new_namespace_index, 0);
   3464     const new_decl = mod.declPtr(new_decl_index);
   3465     errdefer @panic("TODO error handling");
   3466 
   3467     file.root_decl = new_decl_index.toOptional();
   3468     mod.namespacePtr(new_namespace_index).decl_index = new_decl_index;
   3469 
   3470     new_decl.name = try file.fullyQualifiedName(mod);
   3471     new_decl.name_fully_qualified = true;
   3472     new_decl.src_line = 0;
   3473     new_decl.is_pub = true;
   3474     new_decl.is_exported = false;
   3475     new_decl.alignment = .none;
   3476     new_decl.@"linksection" = .none;
   3477     new_decl.analysis = .in_progress;
   3478 
   3479     if (file.status != .success_zir) {
   3480         new_decl.analysis = .file_failure;
   3481         return;
   3482     }
   3483     assert(file.zir_loaded);
   3484 
   3485     const struct_ty = try mod.getFileRootStruct(new_decl_index, new_namespace_index, file);
   3486     errdefer mod.intern_pool.remove(struct_ty);
   3487 
   3488     switch (mod.comp.cache_use) {
   3489         .whole => |whole| if (whole.cache_manifest) |man| {
   3490             const source = file.getSource(gpa) catch |err| {
   3491                 try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)});
   3492                 return error.AnalysisFail;
   3493             };
   3494 
   3495             const resolved_path = std.fs.path.resolve(gpa, &.{
   3496                 file.mod.root.root_dir.path orelse ".",
   3497                 file.mod.root.sub_path,
   3498                 file.sub_file_path,
   3499             }) catch |err| {
   3500                 try reportRetryableFileError(mod, file, "unable to resolve path: {s}", .{@errorName(err)});
   3501                 return error.AnalysisFail;
   3502             };
   3503             errdefer gpa.free(resolved_path);
   3504 
   3505             whole.cache_manifest_mutex.lock();
   3506             defer whole.cache_manifest_mutex.unlock();
   3507             try man.addFilePostContents(resolved_path, source.bytes, source.stat);
   3508         },
   3509         .incremental => {},
   3510     }
   3511 }
   3512 
   3513 const SemaDeclResult = packed struct {
   3514     /// Whether the value of a `decl_val` of this Decl changed.
   3515     invalidate_decl_val: bool,
   3516     /// Whether the type of a `decl_ref` of this Decl changed.
   3517     invalidate_decl_ref: bool,
   3518 };
   3519 
   3520 fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
   3521     const tracy = trace(@src());
   3522     defer tracy.end();
   3523 
   3524     const decl = mod.declPtr(decl_index);
   3525     const ip = &mod.intern_pool;
   3526 
   3527     if (decl.getFileScope(mod).status != .success_zir) {
   3528         return error.AnalysisFail;
   3529     }
   3530 
   3531     assert(!mod.declIsRoot(decl_index));
   3532 
   3533     if (decl.zir_decl_index == .none and decl.owns_tv) {
   3534         // We are re-analyzing an anonymous owner Decl (for a function or a namespace type).
   3535         return mod.semaAnonOwnerDecl(decl_index);
   3536     }
   3537 
   3538     log.debug("semaDecl '{d}'", .{@intFromEnum(decl_index)});
   3539     log.debug("decl name '{}'", .{(try decl.fullyQualifiedName(mod)).fmt(ip)});
   3540     defer blk: {
   3541         log.debug("finish decl name '{}'", .{(decl.fullyQualifiedName(mod) catch break :blk).fmt(ip)});
   3542     }
   3543 
   3544     const old_has_tv = decl.has_tv;
   3545     // The following values are ignored if `!old_has_tv`
   3546     const old_ty = if (old_has_tv) decl.typeOf(mod) else undefined;
   3547     const old_val = decl.val;
   3548     const old_align = decl.alignment;
   3549     const old_linksection = decl.@"linksection";
   3550     const old_addrspace = decl.@"addrspace";
   3551     const old_is_inline = if (decl.getOwnedFunction(mod)) |prev_func|
   3552         prev_func.analysis(ip).state == .inline_only
   3553     else
   3554         false;
   3555 
   3556     const decl_inst = decl.zir_decl_index.unwrap().?.resolve(ip);
   3557 
   3558     const gpa = mod.gpa;
   3559     const zir = decl.getFileScope(mod).zir;
   3560 
   3561     const builtin_type_target_index: InternPool.Index = ip_index: {
   3562         const std_mod = mod.std_mod;
   3563         if (decl.getFileScope(mod).mod != std_mod) break :ip_index .none;
   3564         // We're in the std module.
   3565         const std_file = (try mod.importPkg(std_mod)).file;
   3566         const std_decl = mod.declPtr(std_file.root_decl.unwrap().?);
   3567         const std_namespace = std_decl.getInnerNamespace(mod).?;
   3568         const builtin_str = try ip.getOrPutString(gpa, "builtin", .no_embedded_nulls);
   3569         const builtin_decl = mod.declPtr(std_namespace.decls.getKeyAdapted(builtin_str, DeclAdapter{ .zcu = mod }) orelse break :ip_index .none);
   3570         const builtin_namespace = builtin_decl.getInnerNamespaceIndex(mod).unwrap() orelse break :ip_index .none;
   3571         if (decl.src_namespace != builtin_namespace) break :ip_index .none;
   3572         // We're in builtin.zig. This could be a builtin we need to add to a specific InternPool index.
   3573         for ([_][]const u8{
   3574             "AtomicOrder",
   3575             "AtomicRmwOp",
   3576             "CallingConvention",
   3577             "AddressSpace",
   3578             "FloatMode",
   3579             "ReduceOp",
   3580             "CallModifier",
   3581             "PrefetchOptions",
   3582             "ExportOptions",
   3583             "ExternOptions",
   3584             "Type",
   3585         }, [_]InternPool.Index{
   3586             .atomic_order_type,
   3587             .atomic_rmw_op_type,
   3588             .calling_convention_type,
   3589             .address_space_type,
   3590             .float_mode_type,
   3591             .reduce_op_type,
   3592             .call_modifier_type,
   3593             .prefetch_options_type,
   3594             .export_options_type,
   3595             .extern_options_type,
   3596             .type_info_type,
   3597         }) |type_name, type_ip| {
   3598             if (decl.name.eqlSlice(type_name, ip)) break :ip_index type_ip;
   3599         }
   3600         break :ip_index .none;
   3601     };
   3602 
   3603     mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
   3604 
   3605     decl.analysis = .in_progress;
   3606 
   3607     var analysis_arena = std.heap.ArenaAllocator.init(gpa);
   3608     defer analysis_arena.deinit();
   3609 
   3610     var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);
   3611     defer comptime_err_ret_trace.deinit();
   3612 
   3613     var sema: Sema = .{
   3614         .mod = mod,
   3615         .gpa = gpa,
   3616         .arena = analysis_arena.allocator(),
   3617         .code = zir,
   3618         .owner_decl = decl,
   3619         .owner_decl_index = decl_index,
   3620         .func_index = .none,
   3621         .func_is_naked = false,
   3622         .fn_ret_ty = Type.void,
   3623         .fn_ret_ty_ies = null,
   3624         .owner_func_index = .none,
   3625         .comptime_err_ret_trace = &comptime_err_ret_trace,
   3626         .builtin_type_target_index = builtin_type_target_index,
   3627     };
   3628     defer sema.deinit();
   3629 
   3630     // Every Decl (other than file root Decls, which do not have a ZIR index) has a dependency on its own source.
   3631     try sema.declareDependency(.{ .src_hash = try ip.trackZir(
   3632         sema.gpa,
   3633         decl.getFileScope(mod),
   3634         decl_inst,
   3635     ) });
   3636 
   3637     var block_scope: Sema.Block = .{
   3638         .parent = null,
   3639         .sema = &sema,
   3640         .src_decl = decl_index,
   3641         .namespace = decl.src_namespace,
   3642         .instructions = .{},
   3643         .inlining = null,
   3644         .is_comptime = true,
   3645     };
   3646     defer block_scope.instructions.deinit(gpa);
   3647 
   3648     const decl_bodies = decl.zirBodies(mod);
   3649 
   3650     const result_ref = try sema.resolveInlineBody(&block_scope, decl_bodies.value_body, decl_inst);
   3651     // We'll do some other bits with the Sema. Clear the type target index just
   3652     // in case they analyze any type.
   3653     sema.builtin_type_target_index = .none;
   3654     const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 };
   3655     const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 };
   3656     const address_space_src: LazySrcLoc = .{ .node_offset_var_decl_addrspace = 0 };
   3657     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 };
   3658     const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 };
   3659     const decl_val = try sema.resolveFinalDeclValue(&block_scope, init_src, result_ref);
   3660     const decl_ty = decl_val.typeOf(mod);
   3661 
   3662     // Note this resolves the type of the Decl, not the value; if this Decl
   3663     // is a struct, for example, this resolves `type` (which needs no resolution),
   3664     // not the struct itself.
   3665     try sema.resolveTypeLayout(decl_ty);
   3666 
   3667     if (decl.kind == .@"usingnamespace") {
   3668         if (!decl_ty.eql(Type.type, mod)) {
   3669             return sema.fail(&block_scope, ty_src, "expected type, found {}", .{
   3670                 decl_ty.fmt(mod),
   3671             });
   3672         }
   3673         const ty = decl_val.toType();
   3674         if (ty.getNamespace(mod) == null) {
   3675             return sema.fail(&block_scope, ty_src, "type {} has no namespace", .{ty.fmt(mod)});
   3676         }
   3677 
   3678         decl.val = ty.toValue();
   3679         decl.alignment = .none;
   3680         decl.@"linksection" = .none;
   3681         decl.has_tv = true;
   3682         decl.owns_tv = false;
   3683         decl.analysis = .complete;
   3684 
   3685         // TODO: usingnamespace cannot currently participate in incremental compilation
   3686         return .{
   3687             .invalidate_decl_val = true,
   3688             .invalidate_decl_ref = true,
   3689         };
   3690     }
   3691 
   3692     var queue_linker_work = true;
   3693     var is_func = false;
   3694     var is_inline = false;
   3695     switch (decl_val.toIntern()) {
   3696         .generic_poison => unreachable,
   3697         .unreachable_value => unreachable,
   3698         else => switch (ip.indexToKey(decl_val.toIntern())) {
   3699             .variable => |variable| {
   3700                 decl.owns_tv = variable.decl == decl_index;
   3701                 queue_linker_work = decl.owns_tv;
   3702             },
   3703 
   3704             .extern_func => |extern_func| {
   3705                 decl.owns_tv = extern_func.decl == decl_index;
   3706                 queue_linker_work = decl.owns_tv;
   3707                 is_func = decl.owns_tv;
   3708             },
   3709 
   3710             .func => |func| {
   3711                 decl.owns_tv = func.owner_decl == decl_index;
   3712                 queue_linker_work = false;
   3713                 is_inline = decl.owns_tv and decl_ty.fnCallingConvention(mod) == .Inline;
   3714                 is_func = decl.owns_tv;
   3715             },
   3716 
   3717             else => {},
   3718         },
   3719     }
   3720 
   3721     decl.val = decl_val;
   3722     // Function linksection, align, and addrspace were already set by Sema
   3723     if (!is_func) {
   3724         decl.alignment = blk: {
   3725             const align_body = decl_bodies.align_body orelse break :blk .none;
   3726             const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst);
   3727             break :blk try sema.analyzeAsAlign(&block_scope, align_src, align_ref);
   3728         };
   3729         decl.@"linksection" = blk: {
   3730             const linksection_body = decl_bodies.linksection_body orelse break :blk .none;
   3731             const linksection_ref = try sema.resolveInlineBody(&block_scope, linksection_body, decl_inst);
   3732             const bytes = try sema.toConstString(&block_scope, section_src, linksection_ref, .{
   3733                 .needed_comptime_reason = "linksection must be comptime-known",
   3734             });
   3735             if (mem.indexOfScalar(u8, bytes, 0) != null) {
   3736                 return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{});
   3737             } else if (bytes.len == 0) {
   3738                 return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{});
   3739             }
   3740             break :blk try ip.getOrPutStringOpt(gpa, bytes, .no_embedded_nulls);
   3741         };
   3742         decl.@"addrspace" = blk: {
   3743             const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_val.toIntern())) {
   3744                 .variable => .variable,
   3745                 .extern_func, .func => .function,
   3746                 else => .constant,
   3747             };
   3748 
   3749             const target = sema.mod.getTarget();
   3750 
   3751             const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) {
   3752                 .function => target_util.defaultAddressSpace(target, .function),
   3753                 .variable => target_util.defaultAddressSpace(target, .global_mutable),
   3754                 .constant => target_util.defaultAddressSpace(target, .global_constant),
   3755                 else => unreachable,
   3756             };
   3757             const addrspace_ref = try sema.resolveInlineBody(&block_scope, addrspace_body, decl_inst);
   3758             break :blk try sema.analyzeAsAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx);
   3759         };
   3760     }
   3761     decl.has_tv = true;
   3762     decl.analysis = .complete;
   3763 
   3764     const result: SemaDeclResult = if (old_has_tv) .{
   3765         .invalidate_decl_val = !decl_ty.eql(old_ty, mod) or
   3766             !decl.val.eql(old_val, decl_ty, mod) or
   3767             is_inline != old_is_inline,
   3768         .invalidate_decl_ref = !decl_ty.eql(old_ty, mod) or
   3769             decl.alignment != old_align or
   3770             decl.@"linksection" != old_linksection or
   3771             decl.@"addrspace" != old_addrspace or
   3772             is_inline != old_is_inline,
   3773     } else .{
   3774         .invalidate_decl_val = true,
   3775         .invalidate_decl_ref = true,
   3776     };
   3777 
   3778     const has_runtime_bits = queue_linker_work and (is_func or try sema.typeHasRuntimeBits(decl_ty));
   3779     if (has_runtime_bits) {
   3780         // Needed for codegen_decl which will call updateDecl and then the
   3781         // codegen backend wants full access to the Decl Type.
   3782         try sema.resolveTypeFully(decl_ty);
   3783 
   3784         try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index });
   3785 
   3786         if (result.invalidate_decl_ref and mod.emit_h != null) {
   3787             try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index });
   3788         }
   3789     }
   3790 
   3791     if (decl.is_exported) {
   3792         const export_src: LazySrcLoc = .{ .token_offset = @intFromBool(decl.is_pub) };
   3793         if (is_inline) return sema.fail(&block_scope, export_src, "export of inline function", .{});
   3794         // The scope needs to have the decl in it.
   3795         try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
   3796     }
   3797 
   3798     return result;
   3799 }
   3800 
   3801 fn semaAnonOwnerDecl(zcu: *Zcu, decl_index: Decl.Index) !SemaDeclResult {
   3802     const decl = zcu.declPtr(decl_index);
   3803 
   3804     assert(decl.has_tv);
   3805     assert(decl.owns_tv);
   3806 
   3807     log.debug("semaAnonOwnerDecl '{d}'", .{@intFromEnum(decl_index)});
   3808 
   3809     switch (decl.typeOf(zcu).zigTypeTag(zcu)) {
   3810         .Fn => @panic("TODO: update fn instance"),
   3811         .Type => {},
   3812         else => unreachable,
   3813     }
   3814 
   3815     // We are the owner Decl of a type, and we were marked as outdated. That means the *structure*
   3816     // of this type changed; not just its namespace. Therefore, we need a new InternPool index.
   3817     //
   3818     // However, as soon as we make that, the context that created us will require re-analysis anyway
   3819     // (as it depends on this Decl's value), meaning the `struct_decl` (or equivalent) instruction
   3820     // will be analyzed again. Since Sema already needs to be able to reconstruct types like this,
   3821     // why should we bother implementing it here too when the Sema logic will be hit right after?
   3822     //
   3823     // So instead, let's just mark this Decl as failed - so that any remaining Decls which genuinely
   3824     // reference it (via `@This`) end up silently erroring too - and we'll let Sema make a new type
   3825     // with a new Decl.
   3826     //
   3827     // Yes, this does mean that any type owner Decl has a constant value for its entire lifetime.
   3828     zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
   3829     zcu.intern_pool.remove(decl.val.toIntern());
   3830     decl.analysis = .dependency_failure;
   3831     return .{
   3832         .invalidate_decl_val = true,
   3833         .invalidate_decl_ref = true,
   3834     };
   3835 }
   3836 
   3837 pub const ImportFileResult = struct {
   3838     file: *File,
   3839     is_new: bool,
   3840     is_pkg: bool,
   3841 };
   3842 
   3843 pub fn importPkg(zcu: *Zcu, mod: *Package.Module) !ImportFileResult {
   3844     const gpa = zcu.gpa;
   3845 
   3846     // The resolved path is used as the key in the import table, to detect if
   3847     // an import refers to the same as another, despite different relative paths
   3848     // or differently mapped package names.
   3849     const resolved_path = try std.fs.path.resolve(gpa, &.{
   3850         mod.root.root_dir.path orelse ".",
   3851         mod.root.sub_path,
   3852         mod.root_src_path,
   3853     });
   3854     var keep_resolved_path = false;
   3855     defer if (!keep_resolved_path) gpa.free(resolved_path);
   3856 
   3857     const gop = try zcu.import_table.getOrPut(gpa, resolved_path);
   3858     errdefer _ = zcu.import_table.pop();
   3859     if (gop.found_existing) {
   3860         try gop.value_ptr.*.addReference(zcu.*, .{ .root = mod });
   3861         return ImportFileResult{
   3862             .file = gop.value_ptr.*,
   3863             .is_new = false,
   3864             .is_pkg = true,
   3865         };
   3866     }
   3867 
   3868     if (mod.builtin_file) |builtin_file| {
   3869         keep_resolved_path = true; // It's now owned by import_table.
   3870         gop.value_ptr.* = builtin_file;
   3871         try builtin_file.addReference(zcu.*, .{ .root = mod });
   3872         return .{
   3873             .file = builtin_file,
   3874             .is_new = false,
   3875             .is_pkg = true,
   3876         };
   3877     }
   3878 
   3879     const sub_file_path = try gpa.dupe(u8, mod.root_src_path);
   3880     errdefer gpa.free(sub_file_path);
   3881 
   3882     const new_file = try gpa.create(File);
   3883     errdefer gpa.destroy(new_file);
   3884 
   3885     keep_resolved_path = true; // It's now owned by import_table.
   3886     gop.value_ptr.* = new_file;
   3887     new_file.* = .{
   3888         .sub_file_path = sub_file_path,
   3889         .source = undefined,
   3890         .source_loaded = false,
   3891         .tree_loaded = false,
   3892         .zir_loaded = false,
   3893         .stat = undefined,
   3894         .tree = undefined,
   3895         .zir = undefined,
   3896         .status = .never_loaded,
   3897         .mod = mod,
   3898         .root_decl = .none,
   3899     };
   3900     try new_file.addReference(zcu.*, .{ .root = mod });
   3901     return ImportFileResult{
   3902         .file = new_file,
   3903         .is_new = true,
   3904         .is_pkg = true,
   3905     };
   3906 }
   3907 
   3908 pub fn importFile(
   3909     mod: *Module,
   3910     cur_file: *File,
   3911     import_string: []const u8,
   3912 ) !ImportFileResult {
   3913     if (std.mem.eql(u8, import_string, "std")) {
   3914         return mod.importPkg(mod.std_mod);
   3915     }
   3916     if (std.mem.eql(u8, import_string, "root")) {
   3917         return mod.importPkg(mod.root_mod);
   3918     }
   3919     if (cur_file.mod.deps.get(import_string)) |pkg| {
   3920         return mod.importPkg(pkg);
   3921     }
   3922     if (!mem.endsWith(u8, import_string, ".zig")) {
   3923         return error.ModuleNotFound;
   3924     }
   3925     const gpa = mod.gpa;
   3926 
   3927     // The resolved path is used as the key in the import table, to detect if
   3928     // an import refers to the same as another, despite different relative paths
   3929     // or differently mapped package names.
   3930     const resolved_path = try std.fs.path.resolve(gpa, &.{
   3931         cur_file.mod.root.root_dir.path orelse ".",
   3932         cur_file.mod.root.sub_path,
   3933         cur_file.sub_file_path,
   3934         "..",
   3935         import_string,
   3936     });
   3937 
   3938     var keep_resolved_path = false;
   3939     defer if (!keep_resolved_path) gpa.free(resolved_path);
   3940 
   3941     const gop = try mod.import_table.getOrPut(gpa, resolved_path);
   3942     errdefer _ = mod.import_table.pop();
   3943     if (gop.found_existing) return ImportFileResult{
   3944         .file = gop.value_ptr.*,
   3945         .is_new = false,
   3946         .is_pkg = false,
   3947     };
   3948 
   3949     const new_file = try gpa.create(File);
   3950     errdefer gpa.destroy(new_file);
   3951 
   3952     const resolved_root_path = try std.fs.path.resolve(gpa, &.{
   3953         cur_file.mod.root.root_dir.path orelse ".",
   3954         cur_file.mod.root.sub_path,
   3955     });
   3956     defer gpa.free(resolved_root_path);
   3957 
   3958     const sub_file_path = p: {
   3959         const relative = try std.fs.path.relative(gpa, resolved_root_path, resolved_path);
   3960         errdefer gpa.free(relative);
   3961 
   3962         if (!isUpDir(relative) and !std.fs.path.isAbsolute(relative)) {
   3963             break :p relative;
   3964         }
   3965         return error.ImportOutsideModulePath;
   3966     };
   3967     errdefer gpa.free(sub_file_path);
   3968 
   3969     log.debug("new importFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, import_string={s}", .{
   3970         resolved_root_path, resolved_path, sub_file_path, import_string,
   3971     });
   3972 
   3973     keep_resolved_path = true; // It's now owned by import_table.
   3974     gop.value_ptr.* = new_file;
   3975     new_file.* = .{
   3976         .sub_file_path = sub_file_path,
   3977         .source = undefined,
   3978         .source_loaded = false,
   3979         .tree_loaded = false,
   3980         .zir_loaded = false,
   3981         .stat = undefined,
   3982         .tree = undefined,
   3983         .zir = undefined,
   3984         .status = .never_loaded,
   3985         .mod = cur_file.mod,
   3986         .root_decl = .none,
   3987     };
   3988     return ImportFileResult{
   3989         .file = new_file,
   3990         .is_new = true,
   3991         .is_pkg = false,
   3992     };
   3993 }
   3994 
   3995 pub fn embedFile(
   3996     mod: *Module,
   3997     cur_file: *File,
   3998     import_string: []const u8,
   3999     src_loc: SrcLoc,
   4000 ) !InternPool.Index {
   4001     const gpa = mod.gpa;
   4002 
   4003     if (cur_file.mod.deps.get(import_string)) |pkg| {
   4004         const resolved_path = try std.fs.path.resolve(gpa, &.{
   4005             pkg.root.root_dir.path orelse ".",
   4006             pkg.root.sub_path,
   4007             pkg.root_src_path,
   4008         });
   4009         var keep_resolved_path = false;
   4010         defer if (!keep_resolved_path) gpa.free(resolved_path);
   4011 
   4012         const gop = try mod.embed_table.getOrPut(gpa, resolved_path);
   4013         errdefer {
   4014             assert(std.mem.eql(u8, mod.embed_table.pop().key, resolved_path));
   4015             keep_resolved_path = false;
   4016         }
   4017         if (gop.found_existing) return gop.value_ptr.*.val;
   4018         keep_resolved_path = true;
   4019 
   4020         const sub_file_path = try gpa.dupe(u8, pkg.root_src_path);
   4021         errdefer gpa.free(sub_file_path);
   4022 
   4023         return newEmbedFile(mod, pkg, sub_file_path, resolved_path, gop.value_ptr, src_loc);
   4024     }
   4025 
   4026     // The resolved path is used as the key in the table, to detect if a file
   4027     // refers to the same as another, despite different relative paths.
   4028     const resolved_path = try std.fs.path.resolve(gpa, &.{
   4029         cur_file.mod.root.root_dir.path orelse ".",
   4030         cur_file.mod.root.sub_path,
   4031         cur_file.sub_file_path,
   4032         "..",
   4033         import_string,
   4034     });
   4035 
   4036     var keep_resolved_path = false;
   4037     defer if (!keep_resolved_path) gpa.free(resolved_path);
   4038 
   4039     const gop = try mod.embed_table.getOrPut(gpa, resolved_path);
   4040     errdefer {
   4041         assert(std.mem.eql(u8, mod.embed_table.pop().key, resolved_path));
   4042         keep_resolved_path = false;
   4043     }
   4044     if (gop.found_existing) return gop.value_ptr.*.val;
   4045     keep_resolved_path = true;
   4046 
   4047     const resolved_root_path = try std.fs.path.resolve(gpa, &.{
   4048         cur_file.mod.root.root_dir.path orelse ".",
   4049         cur_file.mod.root.sub_path,
   4050     });
   4051     defer gpa.free(resolved_root_path);
   4052 
   4053     const sub_file_path = p: {
   4054         const relative = try std.fs.path.relative(gpa, resolved_root_path, resolved_path);
   4055         errdefer gpa.free(relative);
   4056 
   4057         if (!isUpDir(relative) and !std.fs.path.isAbsolute(relative)) {
   4058             break :p relative;
   4059         }
   4060         return error.ImportOutsideModulePath;
   4061     };
   4062     defer gpa.free(sub_file_path);
   4063 
   4064     return newEmbedFile(mod, cur_file.mod, sub_file_path, resolved_path, gop.value_ptr, src_loc);
   4065 }
   4066 
   4067 /// https://github.com/ziglang/zig/issues/14307
   4068 fn newEmbedFile(
   4069     mod: *Module,
   4070     pkg: *Package.Module,
   4071     sub_file_path: []const u8,
   4072     resolved_path: []const u8,
   4073     result: **EmbedFile,
   4074     src_loc: SrcLoc,
   4075 ) !InternPool.Index {
   4076     const gpa = mod.gpa;
   4077     const ip = &mod.intern_pool;
   4078 
   4079     const new_file = try gpa.create(EmbedFile);
   4080     errdefer gpa.destroy(new_file);
   4081 
   4082     var file = try pkg.root.openFile(sub_file_path, .{});
   4083     defer file.close();
   4084 
   4085     const actual_stat = try file.stat();
   4086     const stat: Cache.File.Stat = .{
   4087         .size = actual_stat.size,
   4088         .inode = actual_stat.inode,
   4089         .mtime = actual_stat.mtime,
   4090     };
   4091     const size = std.math.cast(usize, actual_stat.size) orelse return error.Overflow;
   4092 
   4093     const bytes = try ip.string_bytes.addManyAsSlice(gpa, try std.math.add(usize, size, 1));
   4094     const actual_read = try file.readAll(bytes[0..size]);
   4095     if (actual_read != size) return error.UnexpectedEndOfFile;
   4096     bytes[size] = 0;
   4097 
   4098     const comp = mod.comp;
   4099     switch (comp.cache_use) {
   4100         .whole => |whole| if (whole.cache_manifest) |man| {
   4101             const copied_resolved_path = try gpa.dupe(u8, resolved_path);
   4102             errdefer gpa.free(copied_resolved_path);
   4103             whole.cache_manifest_mutex.lock();
   4104             defer whole.cache_manifest_mutex.unlock();
   4105             try man.addFilePostContents(copied_resolved_path, bytes[0..size], stat);
   4106         },
   4107         .incremental => {},
   4108     }
   4109 
   4110     const array_ty = try ip.get(gpa, .{ .array_type = .{
   4111         .len = size,
   4112         .sentinel = .zero_u8,
   4113         .child = .u8_type,
   4114     } });
   4115     const array_val = try ip.get(gpa, .{ .aggregate = .{
   4116         .ty = array_ty,
   4117         .storage = .{ .bytes = try ip.getOrPutTrailingString(gpa, bytes.len, .maybe_embedded_nulls) },
   4118     } });
   4119 
   4120     const ptr_ty = (try mod.ptrType(.{
   4121         .child = array_ty,
   4122         .flags = .{
   4123             .alignment = .none,
   4124             .is_const = true,
   4125             .address_space = .generic,
   4126         },
   4127     })).toIntern();
   4128     const ptr_val = try ip.get(gpa, .{ .ptr = .{
   4129         .ty = ptr_ty,
   4130         .base_addr = .{ .anon_decl = .{
   4131             .val = array_val,
   4132             .orig_ty = ptr_ty,
   4133         } },
   4134         .byte_offset = 0,
   4135     } });
   4136 
   4137     result.* = new_file;
   4138     new_file.* = .{
   4139         .sub_file_path = try ip.getOrPutString(gpa, sub_file_path, .no_embedded_nulls),
   4140         .owner = pkg,
   4141         .stat = stat,
   4142         .val = ptr_val,
   4143         .src_loc = src_loc,
   4144     };
   4145     return ptr_val;
   4146 }
   4147 
   4148 pub fn scanNamespace(
   4149     zcu: *Zcu,
   4150     namespace_index: Namespace.Index,
   4151     decls: []const Zir.Inst.Index,
   4152     parent_decl: *Decl,
   4153 ) Allocator.Error!void {
   4154     const tracy = trace(@src());
   4155     defer tracy.end();
   4156 
   4157     const gpa = zcu.gpa;
   4158     const namespace = zcu.namespacePtr(namespace_index);
   4159 
   4160     // For incremental updates, `scanDecl` wants to look up existing decls by their ZIR index rather
   4161     // than their name. We'll build an efficient mapping now, then discard the current `decls`.
   4162     var existing_by_inst: std.AutoHashMapUnmanaged(InternPool.TrackedInst.Index, Decl.Index) = .{};
   4163     defer existing_by_inst.deinit(gpa);
   4164 
   4165     try existing_by_inst.ensureTotalCapacity(gpa, @intCast(namespace.decls.count()));
   4166 
   4167     for (namespace.decls.keys()) |decl_index| {
   4168         const decl = zcu.declPtr(decl_index);
   4169         existing_by_inst.putAssumeCapacityNoClobber(decl.zir_decl_index.unwrap().?, decl_index);
   4170     }
   4171 
   4172     var seen_decls: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
   4173     defer seen_decls.deinit(gpa);
   4174 
   4175     try zcu.comp.work_queue.ensureUnusedCapacity(decls.len);
   4176 
   4177     namespace.decls.clearRetainingCapacity();
   4178     try namespace.decls.ensureTotalCapacity(gpa, decls.len);
   4179 
   4180     namespace.usingnamespace_set.clearRetainingCapacity();
   4181 
   4182     var scan_decl_iter: ScanDeclIter = .{
   4183         .zcu = zcu,
   4184         .namespace_index = namespace_index,
   4185         .parent_decl = parent_decl,
   4186         .seen_decls = &seen_decls,
   4187         .existing_by_inst = &existing_by_inst,
   4188         .pass = .named,
   4189     };
   4190     for (decls) |decl_inst| {
   4191         try scanDecl(&scan_decl_iter, decl_inst);
   4192     }
   4193     scan_decl_iter.pass = .unnamed;
   4194     for (decls) |decl_inst| {
   4195         try scanDecl(&scan_decl_iter, decl_inst);
   4196     }
   4197 
   4198     if (seen_decls.count() != namespace.decls.count()) {
   4199         // Do a pass over the namespace contents and remove any decls from the last update
   4200         // which were removed in this one.
   4201         var i: usize = 0;
   4202         while (i < namespace.decls.count()) {
   4203             const decl_index = namespace.decls.keys()[i];
   4204             const decl = zcu.declPtr(decl_index);
   4205             if (!seen_decls.contains(decl.name)) {
   4206                 // We must preserve namespace ordering for @typeInfo.
   4207                 namespace.decls.orderedRemoveAt(i);
   4208                 i -= 1;
   4209             }
   4210         }
   4211     }
   4212 }
   4213 
   4214 const ScanDeclIter = struct {
   4215     zcu: *Zcu,
   4216     namespace_index: Namespace.Index,
   4217     parent_decl: *Decl,
   4218     seen_decls: *std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),
   4219     existing_by_inst: *const std.AutoHashMapUnmanaged(InternPool.TrackedInst.Index, Decl.Index),
   4220     /// Decl scanning is run in two passes, so that we can detect when a generated
   4221     /// name would clash with an explicit name and use a different one.
   4222     pass: enum { named, unnamed },
   4223     usingnamespace_index: usize = 0,
   4224     comptime_index: usize = 0,
   4225     unnamed_test_index: usize = 0,
   4226 
   4227     fn avoidNameConflict(iter: *ScanDeclIter, comptime fmt: []const u8, args: anytype) !InternPool.NullTerminatedString {
   4228         const zcu = iter.zcu;
   4229         const gpa = zcu.gpa;
   4230         const ip = &zcu.intern_pool;
   4231         var name = try ip.getOrPutStringFmt(gpa, fmt, args, .no_embedded_nulls);
   4232         var gop = try iter.seen_decls.getOrPut(gpa, name);
   4233         var next_suffix: u32 = 0;
   4234         while (gop.found_existing) {
   4235             name = try ip.getOrPutStringFmt(gpa, "{}_{d}", .{ name.fmt(ip), next_suffix }, .no_embedded_nulls);
   4236             gop = try iter.seen_decls.getOrPut(gpa, name);
   4237             next_suffix += 1;
   4238         }
   4239         return name;
   4240     }
   4241 };
   4242 
   4243 fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void {
   4244     const tracy = trace(@src());
   4245     defer tracy.end();
   4246 
   4247     const zcu = iter.zcu;
   4248     const namespace_index = iter.namespace_index;
   4249     const namespace = zcu.namespacePtr(namespace_index);
   4250     const gpa = zcu.gpa;
   4251     const zir = namespace.file_scope.zir;
   4252     const ip = &zcu.intern_pool;
   4253 
   4254     const pl_node = zir.instructions.items(.data)[@intFromEnum(decl_inst)].pl_node;
   4255     const extra = zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
   4256     const declaration = extra.data;
   4257 
   4258     const line = iter.parent_decl.src_line + declaration.line_offset;
   4259     const decl_node = iter.parent_decl.relativeToNodeIndex(pl_node.src_node);
   4260 
   4261     // Every Decl needs a name.
   4262     const decl_name: InternPool.NullTerminatedString, const kind: Decl.Kind, const is_named_test: bool = switch (declaration.name) {
   4263         .@"comptime" => info: {
   4264             if (iter.pass != .unnamed) return;
   4265             const i = iter.comptime_index;
   4266             iter.comptime_index += 1;
   4267             break :info .{
   4268                 try iter.avoidNameConflict("comptime_{d}", .{i}),
   4269                 .@"comptime",
   4270                 false,
   4271             };
   4272         },
   4273         .@"usingnamespace" => info: {
   4274             // TODO: this isn't right! These should be considered unnamed. Name conflicts can happen here.
   4275             // The problem is, we need to preserve the decl ordering for `@typeInfo`.
   4276             // I'm not bothering to fix this now, since some upcoming changes will change this code significantly anyway.
   4277             if (iter.pass != .named) return;
   4278             const i = iter.usingnamespace_index;
   4279             iter.usingnamespace_index += 1;
   4280             break :info .{
   4281                 try iter.avoidNameConflict("usingnamespace_{d}", .{i}),
   4282                 .@"usingnamespace",
   4283                 false,
   4284             };
   4285         },
   4286         .unnamed_test => info: {
   4287             if (iter.pass != .unnamed) return;
   4288             const i = iter.unnamed_test_index;
   4289             iter.unnamed_test_index += 1;
   4290             break :info .{
   4291                 try iter.avoidNameConflict("test_{d}", .{i}),
   4292                 .@"test",
   4293                 false,
   4294             };
   4295         },
   4296         .decltest => info: {
   4297             // We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary.
   4298             if (iter.pass != .unnamed) return;
   4299             assert(declaration.flags.has_doc_comment);
   4300             const name = zir.nullTerminatedString(@enumFromInt(zir.extra[extra.end]));
   4301             break :info .{
   4302                 try iter.avoidNameConflict("decltest.{s}", .{name}),
   4303                 .@"test",
   4304                 true,
   4305             };
   4306         },
   4307         _ => if (declaration.name.isNamedTest(zir)) info: {
   4308             // We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary.
   4309             if (iter.pass != .unnamed) return;
   4310             break :info .{
   4311                 try iter.avoidNameConflict("test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}),
   4312                 .@"test",
   4313                 true,
   4314             };
   4315         } else info: {
   4316             if (iter.pass != .named) return;
   4317             const name = try ip.getOrPutString(
   4318                 gpa,
   4319                 zir.nullTerminatedString(declaration.name.toString(zir).?),
   4320                 .no_embedded_nulls,
   4321             );
   4322             try iter.seen_decls.putNoClobber(gpa, name, {});
   4323             break :info .{
   4324                 name,
   4325                 .named,
   4326                 false,
   4327             };
   4328         },
   4329     };
   4330 
   4331     switch (kind) {
   4332         .@"usingnamespace" => try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1),
   4333         .@"test" => try zcu.test_functions.ensureUnusedCapacity(gpa, 1),
   4334         else => {},
   4335     }
   4336 
   4337     const tracked_inst = try ip.trackZir(gpa, iter.parent_decl.getFileScope(zcu), decl_inst);
   4338 
   4339     // We create a Decl for it regardless of analysis status.
   4340 
   4341     const prev_exported, const decl_index = if (iter.existing_by_inst.get(tracked_inst)) |decl_index| decl_index: {
   4342         // We need only update this existing Decl.
   4343         const decl = zcu.declPtr(decl_index);
   4344         const was_exported = decl.is_exported;
   4345         assert(decl.kind == kind); // ZIR tracking should preserve this
   4346         decl.name = decl_name;
   4347         decl.src_node = decl_node;
   4348         decl.src_line = line;
   4349         decl.is_pub = declaration.flags.is_pub;
   4350         decl.is_exported = declaration.flags.is_export;
   4351         break :decl_index .{ was_exported, decl_index };
   4352     } else decl_index: {
   4353         // Create and set up a new Decl.
   4354         const new_decl_index = try zcu.allocateNewDecl(namespace_index, decl_node);
   4355         const new_decl = zcu.declPtr(new_decl_index);
   4356         new_decl.kind = kind;
   4357         new_decl.name = decl_name;
   4358         new_decl.src_line = line;
   4359         new_decl.is_pub = declaration.flags.is_pub;
   4360         new_decl.is_exported = declaration.flags.is_export;
   4361         new_decl.zir_decl_index = tracked_inst.toOptional();
   4362         break :decl_index .{ false, new_decl_index };
   4363     };
   4364 
   4365     const decl = zcu.declPtr(decl_index);
   4366 
   4367     namespace.decls.putAssumeCapacityNoClobberContext(decl_index, {}, .{ .zcu = zcu });
   4368 
   4369     const comp = zcu.comp;
   4370     const decl_mod = namespace.file_scope.mod;
   4371     const want_analysis = declaration.flags.is_export or switch (kind) {
   4372         .anon => unreachable,
   4373         .@"comptime" => true,
   4374         .@"usingnamespace" => a: {
   4375             namespace.usingnamespace_set.putAssumeCapacityNoClobber(decl_index, declaration.flags.is_pub);
   4376             break :a true;
   4377         },
   4378         .named => false,
   4379         .@"test" => a: {
   4380             if (!comp.config.is_test) break :a false;
   4381             if (decl_mod != zcu.main_mod) break :a false;
   4382             if (is_named_test and comp.test_filters.len > 0) {
   4383                 const decl_fqn = try namespace.fullyQualifiedName(zcu, decl_name);
   4384                 const decl_fqn_slice = decl_fqn.toSlice(ip);
   4385                 for (comp.test_filters) |test_filter| {
   4386                     if (mem.indexOf(u8, decl_fqn_slice, test_filter)) |_| break;
   4387                 } else break :a false;
   4388             }
   4389             zcu.test_functions.putAssumeCapacity(decl_index, {}); // may clobber on incremental update
   4390             break :a true;
   4391         },
   4392     };
   4393 
   4394     if (want_analysis) {
   4395         // We will not queue analysis if the decl has been analyzed on a previous update and
   4396         // `is_export` is unchanged. In this case, the incremental update mechanism will handle
   4397         // re-analysis for us if necessary.
   4398         if (prev_exported != declaration.flags.is_export or decl.analysis == .unreferenced) {
   4399             log.debug("scanDecl queue analyze_decl file='{s}' decl_name='{}' decl_index={d}", .{
   4400                 namespace.file_scope.sub_file_path, decl_name.fmt(ip), decl_index,
   4401             });
   4402             comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = decl_index });
   4403         }
   4404     }
   4405 
   4406     if (decl.getOwnedFunction(zcu) != null) {
   4407         // TODO this logic is insufficient; namespaces we don't re-scan may still require
   4408         // updated line numbers. Look into this!
   4409         // TODO Look into detecting when this would be unnecessary by storing enough state
   4410         // in `Decl` to notice that the line number did not change.
   4411         comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
   4412     }
   4413 }
   4414 
   4415 /// Cancel the creation of an anon decl and delete any references to it.
   4416 /// If other decls depend on this decl, they must be aborted first.
   4417 pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void {
   4418     assert(!mod.declIsRoot(decl_index));
   4419     mod.destroyDecl(decl_index);
   4420 }
   4421 
   4422 /// Finalize the creation of an anon decl.
   4423 pub fn finalizeAnonDecl(mod: *Module, decl_index: Decl.Index) Allocator.Error!void {
   4424     if (mod.declPtr(decl_index).typeOf(mod).isFnOrHasRuntimeBits(mod)) {
   4425         try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index });
   4426     }
   4427 }
   4428 
   4429 /// Delete all the Export objects that are caused by this Decl. Re-analysis of
   4430 /// this Decl will cause them to be re-created (or not).
   4431 fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void {
   4432     var export_owners = (mod.export_owners.fetchSwapRemove(decl_index) orelse return).value;
   4433 
   4434     for (export_owners.items) |exp| {
   4435         switch (exp.exported) {
   4436             .decl_index => |exported_decl_index| {
   4437                 if (mod.decl_exports.getPtr(exported_decl_index)) |export_list| {
   4438                     // Remove exports with owner_decl matching the regenerating decl.
   4439                     const list = export_list.items;
   4440                     var i: usize = 0;
   4441                     var new_len = list.len;
   4442                     while (i < new_len) {
   4443                         if (list[i].owner_decl == decl_index) {
   4444                             mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
   4445                             new_len -= 1;
   4446                         } else {
   4447                             i += 1;
   4448                         }
   4449                     }
   4450                     export_list.shrinkAndFree(mod.gpa, new_len);
   4451                     if (new_len == 0) {
   4452                         assert(mod.decl_exports.swapRemove(exported_decl_index));
   4453                     }
   4454                 }
   4455             },
   4456             .value => |value| {
   4457                 if (mod.value_exports.getPtr(value)) |export_list| {
   4458                     // Remove exports with owner_decl matching the regenerating decl.
   4459                     const list = export_list.items;
   4460                     var i: usize = 0;
   4461                     var new_len = list.len;
   4462                     while (i < new_len) {
   4463                         if (list[i].owner_decl == decl_index) {
   4464                             mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
   4465                             new_len -= 1;
   4466                         } else {
   4467                             i += 1;
   4468                         }
   4469                     }
   4470                     export_list.shrinkAndFree(mod.gpa, new_len);
   4471                     if (new_len == 0) {
   4472                         assert(mod.value_exports.swapRemove(value));
   4473                     }
   4474                 }
   4475             },
   4476         }
   4477         if (mod.comp.bin_file) |lf| {
   4478             try lf.deleteDeclExport(decl_index, exp.opts.name);
   4479         }
   4480         if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| {
   4481             failed_kv.value.destroy(mod.gpa);
   4482         }
   4483         mod.gpa.destroy(exp);
   4484     }
   4485     export_owners.deinit(mod.gpa);
   4486 }
   4487 
   4488 pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocator) SemaError!Air {
   4489     const tracy = trace(@src());
   4490     defer tracy.end();
   4491 
   4492     const gpa = mod.gpa;
   4493     const ip = &mod.intern_pool;
   4494     const func = mod.funcInfo(func_index);
   4495     const decl_index = func.owner_decl;
   4496     const decl = mod.declPtr(decl_index);
   4497 
   4498     log.debug("func name '{}'", .{(try decl.fullyQualifiedName(mod)).fmt(ip)});
   4499     defer blk: {
   4500         log.debug("finish func name '{}'", .{(decl.fullyQualifiedName(mod) catch break :blk).fmt(ip)});
   4501     }
   4502 
   4503     mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));
   4504 
   4505     var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);
   4506     defer comptime_err_ret_trace.deinit();
   4507 
   4508     // In the case of a generic function instance, this is the type of the
   4509     // instance, which has comptime parameters elided. In other words, it is
   4510     // the runtime-known parameters only, not to be confused with the
   4511     // generic_owner function type, which potentially has more parameters,
   4512     // including comptime parameters.
   4513     const fn_ty = decl.typeOf(mod);
   4514     const fn_ty_info = mod.typeToFunc(fn_ty).?;
   4515 
   4516     var sema: Sema = .{
   4517         .mod = mod,
   4518         .gpa = gpa,
   4519         .arena = arena,
   4520         .code = decl.getFileScope(mod).zir,
   4521         .owner_decl = decl,
   4522         .owner_decl_index = decl_index,
   4523         .func_index = func_index,
   4524         .func_is_naked = fn_ty_info.cc == .Naked,
   4525         .fn_ret_ty = Type.fromInterned(fn_ty_info.return_type),
   4526         .fn_ret_ty_ies = null,
   4527         .owner_func_index = func_index,
   4528         .branch_quota = @max(func.branchQuota(ip).*, Sema.default_branch_quota),
   4529         .comptime_err_ret_trace = &comptime_err_ret_trace,
   4530     };
   4531     defer sema.deinit();
   4532 
   4533     // Every runtime function has a dependency on the source of the Decl it originates from.
   4534     // It also depends on the value of its owner Decl.
   4535     try sema.declareDependency(.{ .src_hash = decl.zir_decl_index.unwrap().? });
   4536     try sema.declareDependency(.{ .decl_val = decl_index });
   4537 
   4538     if (func.analysis(ip).inferred_error_set) {
   4539         const ies = try arena.create(Sema.InferredErrorSet);
   4540         ies.* = .{ .func = func_index };
   4541         sema.fn_ret_ty_ies = ies;
   4542     }
   4543 
   4544     // reset in case calls to errorable functions are removed.
   4545     func.analysis(ip).calls_or_awaits_errorable_fn = false;
   4546 
   4547     // First few indexes of extra are reserved and set at the end.
   4548     const reserved_count = @typeInfo(Air.ExtraIndex).Enum.fields.len;
   4549     try sema.air_extra.ensureTotalCapacity(gpa, reserved_count);
   4550     sema.air_extra.items.len += reserved_count;
   4551 
   4552     var inner_block: Sema.Block = .{
   4553         .parent = null,
   4554         .sema = &sema,
   4555         .src_decl = decl_index,
   4556         .namespace = decl.src_namespace,
   4557         .instructions = .{},
   4558         .inlining = null,
   4559         .is_comptime = false,
   4560     };
   4561     defer inner_block.instructions.deinit(gpa);
   4562 
   4563     const fn_info = sema.code.getFnInfo(func.zirBodyInst(ip).resolve(ip));
   4564 
   4565     // Here we are performing "runtime semantic analysis" for a function body, which means
   4566     // we must map the parameter ZIR instructions to `arg` AIR instructions.
   4567     // AIR requires the `arg` parameters to be the first N instructions.
   4568     // This could be a generic function instantiation, however, in which case we need to
   4569     // map the comptime parameters to constant values and only emit arg AIR instructions
   4570     // for the runtime ones.
   4571     const runtime_params_len = fn_ty_info.param_types.len;
   4572     try inner_block.instructions.ensureTotalCapacityPrecise(gpa, runtime_params_len);
   4573     try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len);
   4574     try sema.inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);
   4575 
   4576     // In the case of a generic function instance, pre-populate all the comptime args.
   4577     if (func.comptime_args.len != 0) {
   4578         for (
   4579             fn_info.param_body[0..func.comptime_args.len],
   4580             func.comptime_args.get(ip),
   4581         ) |inst, comptime_arg| {
   4582             if (comptime_arg == .none) continue;
   4583             sema.inst_map.putAssumeCapacityNoClobber(inst, Air.internedToRef(comptime_arg));
   4584         }
   4585     }
   4586 
   4587     const src_params_len = if (func.comptime_args.len != 0)
   4588         func.comptime_args.len
   4589     else
   4590         runtime_params_len;
   4591 
   4592     var runtime_param_index: usize = 0;
   4593     for (fn_info.param_body[0..src_params_len], 0..) |inst, src_param_index| {
   4594         const gop = sema.inst_map.getOrPutAssumeCapacity(inst);
   4595         if (gop.found_existing) continue; // provided above by comptime arg
   4596 
   4597         const param_ty = fn_ty_info.param_types.get(ip)[runtime_param_index];
   4598         runtime_param_index += 1;
   4599 
   4600         const opt_opv = sema.typeHasOnePossibleValue(Type.fromInterned(param_ty)) catch |err| switch (err) {
   4601             error.NeededSourceLocation => unreachable,
   4602             error.GenericPoison => unreachable,
   4603             error.ComptimeReturn => unreachable,
   4604             error.ComptimeBreak => unreachable,
   4605             else => |e| return e,
   4606         };
   4607         if (opt_opv) |opv| {
   4608             gop.value_ptr.* = Air.internedToRef(opv.toIntern());
   4609             continue;
   4610         }
   4611         const arg_index: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
   4612         gop.value_ptr.* = arg_index.toRef();
   4613         inner_block.instructions.appendAssumeCapacity(arg_index);
   4614         sema.air_instructions.appendAssumeCapacity(.{
   4615             .tag = .arg,
   4616             .data = .{ .arg = .{
   4617                 .ty = Air.internedToRef(param_ty),
   4618                 .src_index = @intCast(src_param_index),
   4619             } },
   4620         });
   4621     }
   4622 
   4623     func.analysis(ip).state = .in_progress;
   4624 
   4625     const last_arg_index = inner_block.instructions.items.len;
   4626 
   4627     // Save the error trace as our first action in the function.
   4628     // If this is unnecessary after all, Liveness will clean it up for us.
   4629     const error_return_trace_index = try sema.analyzeSaveErrRetIndex(&inner_block);
   4630     sema.error_return_trace_index_on_fn_entry = error_return_trace_index;
   4631     inner_block.error_return_trace_index = error_return_trace_index;
   4632 
   4633     sema.analyzeFnBody(&inner_block, fn_info.body) catch |err| switch (err) {
   4634         // TODO make these unreachable instead of @panic
   4635         error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"),
   4636         error.GenericPoison => @panic("zig compiler bug: GenericPoison"),
   4637         error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"),
   4638         else => |e| return e,
   4639     };
   4640 
   4641     for (sema.unresolved_inferred_allocs.keys()) |ptr_inst| {
   4642         // The lack of a resolve_inferred_alloc means that this instruction
   4643         // is unused so it just has to be a no-op.
   4644         sema.air_instructions.set(@intFromEnum(ptr_inst), .{
   4645             .tag = .alloc,
   4646             .data = .{ .ty = Type.single_const_pointer_to_comptime_int },
   4647         });
   4648     }
   4649 
   4650     // If we don't get an error return trace from a caller, create our own.
   4651     if (func.analysis(ip).calls_or_awaits_errorable_fn and
   4652         mod.comp.config.any_error_tracing and
   4653         !sema.fn_ret_ty.isError(mod))
   4654     {
   4655         sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) {
   4656             // TODO make these unreachable instead of @panic
   4657             error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"),
   4658             error.GenericPoison => @panic("zig compiler bug: GenericPoison"),
   4659             error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"),
   4660             error.ComptimeBreak => @panic("zig compiler bug: ComptimeBreak"),
   4661             else => |e| return e,
   4662         };
   4663     }
   4664 
   4665     // Copy the block into place and mark that as the main block.
   4666     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
   4667         inner_block.instructions.items.len);
   4668     const main_block_index = sema.addExtraAssumeCapacity(Air.Block{
   4669         .body_len = @intCast(inner_block.instructions.items.len),
   4670     });
   4671     sema.air_extra.appendSliceAssumeCapacity(@ptrCast(inner_block.instructions.items));
   4672     sema.air_extra.items[@intFromEnum(Air.ExtraIndex.main_block)] = main_block_index;
   4673 
   4674     // Resolving inferred error sets is done *before* setting the function
   4675     // state to success, so that "unable to resolve inferred error set" errors
   4676     // can be emitted here.
   4677     if (sema.fn_ret_ty_ies) |ies| {
   4678         sema.resolveInferredErrorSetPtr(&inner_block, LazySrcLoc.nodeOffset(0), ies) catch |err| switch (err) {
   4679             error.NeededSourceLocation => unreachable,
   4680             error.GenericPoison => unreachable,
   4681             error.ComptimeReturn => unreachable,
   4682             error.ComptimeBreak => unreachable,
   4683             error.AnalysisFail => {
   4684                 // In this case our function depends on a type that had a compile error.
   4685                 // We should not try to lower this function.
   4686                 decl.analysis = .dependency_failure;
   4687                 return error.AnalysisFail;
   4688             },
   4689             else => |e| return e,
   4690         };
   4691         assert(ies.resolved != .none);
   4692         ip.funcIesResolved(func_index).* = ies.resolved;
   4693     }
   4694 
   4695     func.analysis(ip).state = .success;
   4696 
   4697     // Finally we must resolve the return type and parameter types so that backends
   4698     // have full access to type information.
   4699     // Crucially, this happens *after* we set the function state to success above,
   4700     // so that dependencies on the function body will now be satisfied rather than
   4701     // result in circular dependency errors.
   4702     sema.resolveFnTypes(fn_ty) catch |err| switch (err) {
   4703         error.NeededSourceLocation => unreachable,
   4704         error.GenericPoison => unreachable,
   4705         error.ComptimeReturn => unreachable,
   4706         error.ComptimeBreak => unreachable,
   4707         error.AnalysisFail => {
   4708             // In this case our function depends on a type that had a compile error.
   4709             // We should not try to lower this function.
   4710             decl.analysis = .dependency_failure;
   4711             return error.AnalysisFail;
   4712         },
   4713         else => |e| return e,
   4714     };
   4715 
   4716     // Similarly, resolve any queued up types that were requested to be resolved for
   4717     // the backends.
   4718     for (sema.types_to_resolve.keys()) |ty| {
   4719         sema.resolveTypeFully(Type.fromInterned(ty)) catch |err| switch (err) {
   4720             error.NeededSourceLocation => unreachable,
   4721             error.GenericPoison => unreachable,
   4722             error.ComptimeReturn => unreachable,
   4723             error.ComptimeBreak => unreachable,
   4724             error.AnalysisFail => {
   4725                 // In this case our function depends on a type that had a compile error.
   4726                 // We should not try to lower this function.
   4727                 decl.analysis = .dependency_failure;
   4728                 return error.AnalysisFail;
   4729             },
   4730             else => |e| return e,
   4731         };
   4732     }
   4733 
   4734     return .{
   4735         .instructions = sema.air_instructions.toOwnedSlice(),
   4736         .extra = try sema.air_extra.toOwnedSlice(gpa),
   4737     };
   4738 }
   4739 
   4740 pub fn createNamespace(mod: *Module, initialization: Namespace) !Namespace.Index {
   4741     return mod.intern_pool.createNamespace(mod.gpa, initialization);
   4742 }
   4743 
   4744 pub fn destroyNamespace(mod: *Module, index: Namespace.Index) void {
   4745     return mod.intern_pool.destroyNamespace(mod.gpa, index);
   4746 }
   4747 
   4748 pub fn allocateNewDecl(
   4749     mod: *Module,
   4750     namespace: Namespace.Index,
   4751     src_node: Ast.Node.Index,
   4752 ) !Decl.Index {
   4753     const ip = &mod.intern_pool;
   4754     const gpa = mod.gpa;
   4755     const decl_index = try ip.createDecl(gpa, .{
   4756         .name = undefined,
   4757         .src_namespace = namespace,
   4758         .src_node = src_node,
   4759         .src_line = undefined,
   4760         .has_tv = false,
   4761         .owns_tv = false,
   4762         .val = undefined,
   4763         .alignment = undefined,
   4764         .@"linksection" = .none,
   4765         .@"addrspace" = .generic,
   4766         .analysis = .unreferenced,
   4767         .zir_decl_index = .none,
   4768         .is_pub = false,
   4769         .is_exported = false,
   4770         .kind = .anon,
   4771     });
   4772 
   4773     if (mod.emit_h) |mod_emit_h| {
   4774         if (@intFromEnum(decl_index) >= mod_emit_h.allocated_emit_h.len) {
   4775             try mod_emit_h.allocated_emit_h.append(gpa, .{});
   4776             assert(@intFromEnum(decl_index) == mod_emit_h.allocated_emit_h.len);
   4777         }
   4778     }
   4779 
   4780     return decl_index;
   4781 }
   4782 
   4783 pub fn getErrorValue(
   4784     mod: *Module,
   4785     name: InternPool.NullTerminatedString,
   4786 ) Allocator.Error!ErrorInt {
   4787     const gop = try mod.global_error_set.getOrPut(mod.gpa, name);
   4788     return @as(ErrorInt, @intCast(gop.index));
   4789 }
   4790 
   4791 pub fn getErrorValueFromSlice(
   4792     mod: *Module,
   4793     name: []const u8,
   4794 ) Allocator.Error!ErrorInt {
   4795     const interned_name = try mod.intern_pool.getOrPutString(mod.gpa, name);
   4796     return getErrorValue(mod, interned_name);
   4797 }
   4798 
   4799 pub fn errorSetBits(mod: *Module) u16 {
   4800     if (mod.error_limit == 0) return 0;
   4801     return std.math.log2_int_ceil(ErrorInt, mod.error_limit + 1); // +1 for no error
   4802 }
   4803 
   4804 pub fn initNewAnonDecl(
   4805     mod: *Module,
   4806     new_decl_index: Decl.Index,
   4807     src_line: u32,
   4808     val: Value,
   4809     name: InternPool.NullTerminatedString,
   4810 ) Allocator.Error!void {
   4811     const new_decl = mod.declPtr(new_decl_index);
   4812 
   4813     new_decl.name = name;
   4814     new_decl.src_line = src_line;
   4815     new_decl.val = val;
   4816     new_decl.alignment = .none;
   4817     new_decl.@"linksection" = .none;
   4818     new_decl.has_tv = true;
   4819     new_decl.analysis = .complete;
   4820 }
   4821 
   4822 pub fn errNoteNonLazy(
   4823     mod: *Module,
   4824     src_loc: SrcLoc,
   4825     parent: *ErrorMsg,
   4826     comptime format: []const u8,
   4827     args: anytype,
   4828 ) error{OutOfMemory}!void {
   4829     if (src_loc.lazy == .unneeded) {
   4830         assert(parent.src_loc.lazy == .unneeded);
   4831         return;
   4832     }
   4833     const msg = try std.fmt.allocPrint(mod.gpa, format, args);
   4834     errdefer mod.gpa.free(msg);
   4835 
   4836     parent.notes = try mod.gpa.realloc(parent.notes, parent.notes.len + 1);
   4837     parent.notes[parent.notes.len - 1] = .{
   4838         .src_loc = src_loc,
   4839         .msg = msg,
   4840     };
   4841 }
   4842 
   4843 /// Deprecated. There is no global target for a Zig Compilation Unit. Instead,
   4844 /// look up the target based on the Module that contains the source code being
   4845 /// analyzed.
   4846 pub fn getTarget(zcu: Module) Target {
   4847     return zcu.root_mod.resolved_target.result;
   4848 }
   4849 
   4850 /// Deprecated. There is no global optimization mode for a Zig Compilation
   4851 /// Unit. Instead, look up the optimization mode based on the Module that
   4852 /// contains the source code being analyzed.
   4853 pub fn optimizeMode(zcu: Module) std.builtin.OptimizeMode {
   4854     return zcu.root_mod.optimize_mode;
   4855 }
   4856 
   4857 fn lockAndClearFileCompileError(mod: *Module, file: *File) void {
   4858     switch (file.status) {
   4859         .success_zir, .retryable_failure => {},
   4860         .never_loaded, .parse_failure, .astgen_failure => {
   4861             mod.comp.mutex.lock();
   4862             defer mod.comp.mutex.unlock();
   4863             if (mod.failed_files.fetchSwapRemove(file)) |kv| {
   4864                 if (kv.value) |msg| msg.destroy(mod.gpa); // Delete previous error message.
   4865             }
   4866         },
   4867     }
   4868 }
   4869 
   4870 pub const SwitchProngSrc = union(enum) {
   4871     /// The item for a scalar prong.
   4872     scalar: u32,
   4873     /// A given single item for a multi prong.
   4874     multi: Multi,
   4875     /// A given range item for a multi prong.
   4876     range: Multi,
   4877     /// The item for the special prong.
   4878     special,
   4879     /// The main capture for a scalar prong.
   4880     scalar_capture: u32,
   4881     /// The main capture for a multi prong.
   4882     multi_capture: u32,
   4883     /// The main capture for the special prong.
   4884     special_capture,
   4885     /// The tag capture for a scalar prong.
   4886     scalar_tag_capture: u32,
   4887     /// The tag capture for a multi prong.
   4888     multi_tag_capture: u32,
   4889     /// The tag capture for the special prong.
   4890     special_tag_capture,
   4891 
   4892     pub const Multi = struct {
   4893         prong: u32,
   4894         item: u32,
   4895     };
   4896 
   4897     pub const RangeExpand = enum { none, first, last };
   4898 
   4899     /// This function is intended to be called only when it is certain that we need
   4900     /// the LazySrcLoc in order to emit a compile error.
   4901     pub fn resolve(
   4902         prong_src: SwitchProngSrc,
   4903         mod: *Module,
   4904         decl: *Decl,
   4905         switch_node_offset: i32,
   4906         /// Ignored if `prong_src` is not `.range`
   4907         range_expand: RangeExpand,
   4908     ) LazySrcLoc {
   4909         @setCold(true);
   4910         const gpa = mod.gpa;
   4911         const tree = decl.getFileScope(mod).getTree(gpa) catch |err| {
   4912             // In this case we emit a warning + a less precise source location.
   4913             log.warn("unable to load {s}: {s}", .{
   4914                 decl.getFileScope(mod).sub_file_path, @errorName(err),
   4915             });
   4916             return LazySrcLoc.nodeOffset(0);
   4917         };
   4918         const switch_node = decl.relativeToNodeIndex(switch_node_offset);
   4919         const main_tokens = tree.nodes.items(.main_token);
   4920         const node_datas = tree.nodes.items(.data);
   4921         const node_tags = tree.nodes.items(.tag);
   4922         const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
   4923         const case_nodes = tree.extra_data[extra.start..extra.end];
   4924 
   4925         var multi_i: u32 = 0;
   4926         var scalar_i: u32 = 0;
   4927         const case_node = for (case_nodes) |case_node| {
   4928             const case = tree.fullSwitchCase(case_node).?;
   4929 
   4930             const is_special = special: {
   4931                 if (case.ast.values.len == 0) break :special true;
   4932                 if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .identifier) {
   4933                     break :special mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_");
   4934                 }
   4935                 break :special false;
   4936             };
   4937 
   4938             if (is_special) {
   4939                 switch (prong_src) {
   4940                     .special, .special_capture, .special_tag_capture => break case_node,
   4941                     else => continue,
   4942                 }
   4943             }
   4944 
   4945             const is_multi = case.ast.values.len != 1 or
   4946                 node_tags[case.ast.values[0]] == .switch_range;
   4947 
   4948             switch (prong_src) {
   4949                 .scalar,
   4950                 .scalar_capture,
   4951                 .scalar_tag_capture,
   4952                 => |i| if (!is_multi and i == scalar_i) break case_node,
   4953 
   4954                 .multi_capture,
   4955                 .multi_tag_capture,
   4956                 => |i| if (is_multi and i == multi_i) break case_node,
   4957 
   4958                 .multi,
   4959                 .range,
   4960                 => |m| if (is_multi and m.prong == multi_i) break case_node,
   4961 
   4962                 .special,
   4963                 .special_capture,
   4964                 .special_tag_capture,
   4965                 => {},
   4966             }
   4967 
   4968             if (is_multi) {
   4969                 multi_i += 1;
   4970             } else {
   4971                 scalar_i += 1;
   4972             }
   4973         } else unreachable;
   4974 
   4975         const case = tree.fullSwitchCase(case_node).?;
   4976 
   4977         switch (prong_src) {
   4978             .scalar, .special => return LazySrcLoc.nodeOffset(
   4979                 decl.nodeIndexToRelative(case.ast.values[0]),
   4980             ),
   4981             .multi => |m| {
   4982                 var item_i: u32 = 0;
   4983                 for (case.ast.values) |item_node| {
   4984                     if (node_tags[item_node] == .switch_range) continue;
   4985                     if (item_i == m.item) return LazySrcLoc.nodeOffset(
   4986                         decl.nodeIndexToRelative(item_node),
   4987                     );
   4988                     item_i += 1;
   4989                 }
   4990                 unreachable;
   4991             },
   4992             .range => |m| {
   4993                 var range_i: u32 = 0;
   4994                 for (case.ast.values) |range| {
   4995                     if (node_tags[range] != .switch_range) continue;
   4996                     if (range_i == m.item) switch (range_expand) {
   4997                         .none => return LazySrcLoc.nodeOffset(
   4998                             decl.nodeIndexToRelative(range),
   4999                         ),
   5000                         .first => return LazySrcLoc.nodeOffset(
   5001                             decl.nodeIndexToRelative(node_datas[range].lhs),
   5002                         ),
   5003                         .last => return LazySrcLoc.nodeOffset(
   5004                             decl.nodeIndexToRelative(node_datas[range].rhs),
   5005                         ),
   5006                     };
   5007                     range_i += 1;
   5008                 }
   5009                 unreachable;
   5010             },
   5011             .scalar_capture, .multi_capture, .special_capture => {
   5012                 return .{ .node_offset_switch_prong_capture = decl.nodeIndexToRelative(case_node) };
   5013             },
   5014             .scalar_tag_capture, .multi_tag_capture, .special_tag_capture => {
   5015                 return .{ .node_offset_switch_prong_tag_capture = decl.nodeIndexToRelative(case_node) };
   5016             },
   5017         }
   5018     }
   5019 };
   5020 
   5021 pub const PeerTypeCandidateSrc = union(enum) {
   5022     /// Do not print out error notes for candidate sources
   5023     none: void,
   5024     /// When we want to know the the src of candidate i, look up at
   5025     /// index i in this slice
   5026     override: []const ?LazySrcLoc,
   5027     /// resolvePeerTypes originates from a @TypeOf(...) call
   5028     typeof_builtin_call_node_offset: i32,
   5029 
   5030     pub fn resolve(
   5031         self: PeerTypeCandidateSrc,
   5032         mod: *Module,
   5033         decl: *Decl,
   5034         candidate_i: usize,
   5035     ) ?LazySrcLoc {
   5036         @setCold(true);
   5037         const gpa = mod.gpa;
   5038 
   5039         switch (self) {
   5040             .none => {
   5041                 return null;
   5042             },
   5043             .override => |candidate_srcs| {
   5044                 if (candidate_i >= candidate_srcs.len)
   5045                     return null;
   5046                 return candidate_srcs[candidate_i];
   5047             },
   5048             .typeof_builtin_call_node_offset => |node_offset| {
   5049                 switch (candidate_i) {
   5050                     0 => return LazySrcLoc{ .node_offset_builtin_call_arg0 = node_offset },
   5051                     1 => return LazySrcLoc{ .node_offset_builtin_call_arg1 = node_offset },
   5052                     2 => return LazySrcLoc{ .node_offset_builtin_call_arg2 = node_offset },
   5053                     3 => return LazySrcLoc{ .node_offset_builtin_call_arg3 = node_offset },
   5054                     4 => return LazySrcLoc{ .node_offset_builtin_call_arg4 = node_offset },
   5055                     5 => return LazySrcLoc{ .node_offset_builtin_call_arg5 = node_offset },
   5056                     else => {},
   5057                 }
   5058 
   5059                 const tree = decl.getFileScope(mod).getTree(gpa) catch |err| {
   5060                     // In this case we emit a warning + a less precise source location.
   5061                     log.warn("unable to load {s}: {s}", .{
   5062                         decl.getFileScope(mod).sub_file_path, @errorName(err),
   5063                     });
   5064                     return LazySrcLoc.nodeOffset(0);
   5065                 };
   5066                 const node = decl.relativeToNodeIndex(node_offset);
   5067                 const node_datas = tree.nodes.items(.data);
   5068                 const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
   5069 
   5070                 return LazySrcLoc{ .node_abs = params[candidate_i] };
   5071             },
   5072         }
   5073     }
   5074 };
   5075 
   5076 const FieldSrcQuery = struct {
   5077     index: usize,
   5078     range: enum { name, type, value, alignment } = .name,
   5079 };
   5080 
   5081 fn queryFieldSrc(
   5082     tree: Ast,
   5083     query: FieldSrcQuery,
   5084     file_scope: *File,
   5085     container_decl: Ast.full.ContainerDecl,
   5086 ) SrcLoc {
   5087     var field_index: usize = 0;
   5088     for (container_decl.ast.members) |member_node| {
   5089         const field = tree.fullContainerField(member_node) orelse continue;
   5090         if (field_index == query.index) {
   5091             return switch (query.range) {
   5092                 .name => .{
   5093                     .file_scope = file_scope,
   5094                     .parent_decl_node = 0,
   5095                     .lazy = .{ .token_abs = field.ast.main_token },
   5096                 },
   5097                 .type => .{
   5098                     .file_scope = file_scope,
   5099                     .parent_decl_node = 0,
   5100                     .lazy = .{ .node_abs = field.ast.type_expr },
   5101                 },
   5102                 .value => .{
   5103                     .file_scope = file_scope,
   5104                     .parent_decl_node = 0,
   5105                     .lazy = .{ .node_abs = field.ast.value_expr },
   5106                 },
   5107                 .alignment => .{
   5108                     .file_scope = file_scope,
   5109                     .parent_decl_node = 0,
   5110                     .lazy = .{ .node_abs = field.ast.align_expr },
   5111                 },
   5112             };
   5113         }
   5114         field_index += 1;
   5115     }
   5116     unreachable;
   5117 }
   5118 
   5119 pub fn paramSrc(
   5120     func_node_offset: i32,
   5121     mod: *Module,
   5122     decl: *Decl,
   5123     param_i: usize,
   5124 ) LazySrcLoc {
   5125     @setCold(true);
   5126     const gpa = mod.gpa;
   5127     const tree = decl.getFileScope(mod).getTree(gpa) catch |err| {
   5128         // In this case we emit a warning + a less precise source location.
   5129         log.warn("unable to load {s}: {s}", .{
   5130             decl.getFileScope(mod).sub_file_path, @errorName(err),
   5131         });
   5132         return LazySrcLoc.nodeOffset(0);
   5133     };
   5134     const node = decl.relativeToNodeIndex(func_node_offset);
   5135     var buf: [1]Ast.Node.Index = undefined;
   5136     const full = tree.fullFnProto(&buf, node).?;
   5137     var it = full.iterate(tree);
   5138     var i: usize = 0;
   5139     while (it.next()) |param| : (i += 1) {
   5140         if (i == param_i) {
   5141             if (param.anytype_ellipsis3) |some| {
   5142                 const main_token = tree.nodes.items(.main_token)[decl.src_node];
   5143                 return .{ .token_offset_param = @as(i32, @bitCast(some)) - @as(i32, @bitCast(main_token)) };
   5144             }
   5145             return .{ .node_offset_param = decl.nodeIndexToRelative(param.type_expr) };
   5146         }
   5147     }
   5148     unreachable;
   5149 }
   5150 
   5151 pub fn initSrc(
   5152     mod: *Module,
   5153     init_node_offset: i32,
   5154     decl: *Decl,
   5155     init_index: usize,
   5156 ) LazySrcLoc {
   5157     @setCold(true);
   5158     const gpa = mod.gpa;
   5159     const tree = decl.getFileScope(mod).getTree(gpa) catch |err| {
   5160         // In this case we emit a warning + a less precise source location.
   5161         log.warn("unable to load {s}: {s}", .{
   5162             decl.getFileScope(mod).sub_file_path, @errorName(err),
   5163         });
   5164         return LazySrcLoc.nodeOffset(0);
   5165     };
   5166     const node_tags = tree.nodes.items(.tag);
   5167     const node = decl.relativeToNodeIndex(init_node_offset);
   5168     var buf: [2]Ast.Node.Index = undefined;
   5169     switch (node_tags[node]) {
   5170         .array_init_one,
   5171         .array_init_one_comma,
   5172         .array_init_dot_two,
   5173         .array_init_dot_two_comma,
   5174         .array_init_dot,
   5175         .array_init_dot_comma,
   5176         .array_init,
   5177         .array_init_comma,
   5178         => {
   5179             const full = tree.fullArrayInit(&buf, node).?.ast.elements;
   5180             return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(full[init_index]));
   5181         },
   5182         .struct_init_one,
   5183         .struct_init_one_comma,
   5184         .struct_init_dot_two,
   5185         .struct_init_dot_two_comma,
   5186         .struct_init_dot,
   5187         .struct_init_dot_comma,
   5188         .struct_init,
   5189         .struct_init_comma,
   5190         => {
   5191             const full = tree.fullStructInit(&buf, node).?.ast.fields;
   5192             return LazySrcLoc{ .node_offset_initializer = decl.nodeIndexToRelative(full[init_index]) };
   5193         },
   5194         else => return LazySrcLoc.nodeOffset(init_node_offset),
   5195     }
   5196 }
   5197 
   5198 pub fn optionsSrc(mod: *Module, decl: *Decl, base_src: LazySrcLoc, wanted: []const u8) LazySrcLoc {
   5199     @setCold(true);
   5200     const gpa = mod.gpa;
   5201     const tree = decl.getFileScope(mod).getTree(gpa) catch |err| {
   5202         // In this case we emit a warning + a less precise source location.
   5203         log.warn("unable to load {s}: {s}", .{
   5204             decl.getFileScope(mod).sub_file_path, @errorName(err),
   5205         });
   5206         return LazySrcLoc.nodeOffset(0);
   5207     };
   5208 
   5209     const o_i: struct { off: i32, i: u8 } = switch (base_src) {
   5210         .node_offset_builtin_call_arg0 => |n| .{ .off = n, .i = 0 },
   5211         .node_offset_builtin_call_arg1 => |n| .{ .off = n, .i = 1 },
   5212         else => unreachable,
   5213     };
   5214 
   5215     const node = decl.relativeToNodeIndex(o_i.off);
   5216     const node_datas = tree.nodes.items(.data);
   5217     const node_tags = tree.nodes.items(.tag);
   5218     const arg_node = switch (node_tags[node]) {
   5219         .builtin_call_two, .builtin_call_two_comma => switch (o_i.i) {
   5220             0 => node_datas[node].lhs,
   5221             1 => node_datas[node].rhs,
   5222             else => unreachable,
   5223         },
   5224         .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + o_i.i],
   5225         else => unreachable,
   5226     };
   5227     var buf: [2]std.zig.Ast.Node.Index = undefined;
   5228     const init_nodes = if (tree.fullStructInit(&buf, arg_node)) |struct_init| struct_init.ast.fields else return base_src;
   5229     for (init_nodes) |init_node| {
   5230         // . IDENTIFIER = init_node
   5231         const name_token = tree.firstToken(init_node) - 2;
   5232         const name = tree.tokenSlice(name_token);
   5233         if (std.mem.eql(u8, name, wanted)) {
   5234             return LazySrcLoc{ .node_offset_initializer = decl.nodeIndexToRelative(init_node) };
   5235         }
   5236     }
   5237     return base_src;
   5238 }
   5239 
   5240 /// Called from `Compilation.update`, after everything is done, just before
   5241 /// reporting compile errors. In this function we emit exported symbol collision
   5242 /// errors and communicate exported symbols to the linker backend.
   5243 pub fn processExports(mod: *Module) !void {
   5244     // Map symbol names to `Export` for name collision detection.
   5245     var symbol_exports: SymbolExports = .{};
   5246     defer symbol_exports.deinit(mod.gpa);
   5247 
   5248     for (mod.decl_exports.keys(), mod.decl_exports.values()) |exported_decl, exports_list| {
   5249         const exported: Exported = .{ .decl_index = exported_decl };
   5250         try processExportsInner(mod, &symbol_exports, exported, exports_list.items);
   5251     }
   5252 
   5253     for (mod.value_exports.keys(), mod.value_exports.values()) |exported_value, exports_list| {
   5254         const exported: Exported = .{ .value = exported_value };
   5255         try processExportsInner(mod, &symbol_exports, exported, exports_list.items);
   5256     }
   5257 }
   5258 
   5259 const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, *Export);
   5260 
   5261 fn processExportsInner(
   5262     zcu: *Zcu,
   5263     symbol_exports: *SymbolExports,
   5264     exported: Exported,
   5265     exports: []const *Export,
   5266 ) error{OutOfMemory}!void {
   5267     const gpa = zcu.gpa;
   5268 
   5269     for (exports) |new_export| {
   5270         const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name);
   5271         if (gop.found_existing) {
   5272             new_export.status = .failed_retryable;
   5273             try zcu.failed_exports.ensureUnusedCapacity(gpa, 1);
   5274             const src_loc = new_export.getSrcLoc(zcu);
   5275             const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {}", .{
   5276                 new_export.opts.name.fmt(&zcu.intern_pool),
   5277             });
   5278             errdefer msg.destroy(gpa);
   5279             const other_export = gop.value_ptr.*;
   5280             const other_src_loc = other_export.getSrcLoc(zcu);
   5281             try zcu.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{});
   5282             zcu.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
   5283             new_export.status = .failed;
   5284         } else {
   5285             gop.value_ptr.* = new_export;
   5286         }
   5287     }
   5288     if (zcu.comp.bin_file) |lf| {
   5289         try handleUpdateExports(zcu, exports, lf.updateExports(zcu, exported, exports));
   5290     } else if (zcu.llvm_object) |llvm_object| {
   5291         if (build_options.only_c) unreachable;
   5292         try handleUpdateExports(zcu, exports, llvm_object.updateExports(zcu, exported, exports));
   5293     }
   5294 }
   5295 
   5296 fn handleUpdateExports(
   5297     zcu: *Zcu,
   5298     exports: []const *Export,
   5299     result: link.File.UpdateExportsError!void,
   5300 ) Allocator.Error!void {
   5301     const gpa = zcu.gpa;
   5302     result catch |err| switch (err) {
   5303         error.OutOfMemory => return error.OutOfMemory,
   5304         error.AnalysisFail => {
   5305             const new_export = exports[0];
   5306             new_export.status = .failed_retryable;
   5307             try zcu.failed_exports.ensureUnusedCapacity(gpa, 1);
   5308             const src_loc = new_export.getSrcLoc(zcu);
   5309             const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{
   5310                 @errorName(err),
   5311             });
   5312             zcu.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
   5313         },
   5314     };
   5315 }
   5316 
   5317 pub fn populateTestFunctions(
   5318     mod: *Module,
   5319     main_progress_node: *std.Progress.Node,
   5320 ) !void {
   5321     const gpa = mod.gpa;
   5322     const ip = &mod.intern_pool;
   5323     const builtin_mod = mod.root_mod.getBuiltinDependency();
   5324     const builtin_file = (mod.importPkg(builtin_mod) catch unreachable).file;
   5325     const root_decl = mod.declPtr(builtin_file.root_decl.unwrap().?);
   5326     const builtin_namespace = mod.namespacePtr(root_decl.src_namespace);
   5327     const test_functions_str = try ip.getOrPutString(gpa, "test_functions", .no_embedded_nulls);
   5328     const decl_index = builtin_namespace.decls.getKeyAdapted(
   5329         test_functions_str,
   5330         DeclAdapter{ .zcu = mod },
   5331     ).?;
   5332     {
   5333         // We have to call `ensureDeclAnalyzed` here in case `builtin.test_functions`
   5334         // was not referenced by start code.
   5335         mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
   5336         mod.sema_prog_node.activate();
   5337         defer {
   5338             mod.sema_prog_node.end();
   5339             mod.sema_prog_node = undefined;
   5340         }
   5341         try mod.ensureDeclAnalyzed(decl_index);
   5342     }
   5343     const decl = mod.declPtr(decl_index);
   5344     const test_fn_ty = decl.typeOf(mod).slicePtrFieldType(mod).childType(mod);
   5345 
   5346     const array_anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl = array: {
   5347         // Add mod.test_functions to an array decl then make the test_functions
   5348         // decl reference it as a slice.
   5349         const test_fn_vals = try gpa.alloc(InternPool.Index, mod.test_functions.count());
   5350         defer gpa.free(test_fn_vals);
   5351 
   5352         for (test_fn_vals, mod.test_functions.keys()) |*test_fn_val, test_decl_index| {
   5353             const test_decl = mod.declPtr(test_decl_index);
   5354             const test_decl_name = try test_decl.fullyQualifiedName(mod);
   5355             const test_decl_name_len = test_decl_name.length(ip);
   5356             const test_name_anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl = n: {
   5357                 const test_name_ty = try mod.arrayType(.{
   5358                     .len = test_decl_name_len,
   5359                     .child = .u8_type,
   5360                 });
   5361                 const test_name_val = try mod.intern(.{ .aggregate = .{
   5362                     .ty = test_name_ty.toIntern(),
   5363                     .storage = .{ .bytes = test_decl_name.toString() },
   5364                 } });
   5365                 break :n .{
   5366                     .orig_ty = (try mod.singleConstPtrType(test_name_ty)).toIntern(),
   5367                     .val = test_name_val,
   5368                 };
   5369             };
   5370 
   5371             const test_fn_fields = .{
   5372                 // name
   5373                 try mod.intern(.{ .slice = .{
   5374                     .ty = .slice_const_u8_type,
   5375                     .ptr = try mod.intern(.{ .ptr = .{
   5376                         .ty = .manyptr_const_u8_type,
   5377                         .base_addr = .{ .anon_decl = test_name_anon_decl },
   5378                         .byte_offset = 0,
   5379                     } }),
   5380                     .len = try mod.intern(.{ .int = .{
   5381                         .ty = .usize_type,
   5382                         .storage = .{ .u64 = test_decl_name_len },
   5383                     } }),
   5384                 } }),
   5385                 // func
   5386                 try mod.intern(.{ .ptr = .{
   5387                     .ty = try mod.intern(.{ .ptr_type = .{
   5388                         .child = test_decl.typeOf(mod).toIntern(),
   5389                         .flags = .{
   5390                             .is_const = true,
   5391                         },
   5392                     } }),
   5393                     .base_addr = .{ .decl = test_decl_index },
   5394                     .byte_offset = 0,
   5395                 } }),
   5396             };
   5397             test_fn_val.* = try mod.intern(.{ .aggregate = .{
   5398                 .ty = test_fn_ty.toIntern(),
   5399                 .storage = .{ .elems = &test_fn_fields },
   5400             } });
   5401         }
   5402 
   5403         const array_ty = try mod.arrayType(.{
   5404             .len = test_fn_vals.len,
   5405             .child = test_fn_ty.toIntern(),
   5406             .sentinel = .none,
   5407         });
   5408         const array_val = try mod.intern(.{ .aggregate = .{
   5409             .ty = array_ty.toIntern(),
   5410             .storage = .{ .elems = test_fn_vals },
   5411         } });
   5412         break :array .{
   5413             .orig_ty = (try mod.singleConstPtrType(array_ty)).toIntern(),
   5414             .val = array_val,
   5415         };
   5416     };
   5417 
   5418     {
   5419         const new_ty = try mod.ptrType(.{
   5420             .child = test_fn_ty.toIntern(),
   5421             .flags = .{
   5422                 .is_const = true,
   5423                 .size = .Slice,
   5424             },
   5425         });
   5426         const new_val = decl.val;
   5427         const new_init = try mod.intern(.{ .slice = .{
   5428             .ty = new_ty.toIntern(),
   5429             .ptr = try mod.intern(.{ .ptr = .{
   5430                 .ty = new_ty.slicePtrFieldType(mod).toIntern(),
   5431                 .base_addr = .{ .anon_decl = array_anon_decl },
   5432                 .byte_offset = 0,
   5433             } }),
   5434             .len = (try mod.intValue(Type.usize, mod.test_functions.count())).toIntern(),
   5435         } });
   5436         ip.mutateVarInit(decl.val.toIntern(), new_init);
   5437 
   5438         // Since we are replacing the Decl's value we must perform cleanup on the
   5439         // previous value.
   5440         decl.val = new_val;
   5441         decl.has_tv = true;
   5442     }
   5443     try mod.linkerUpdateDecl(decl_index);
   5444 }
   5445 
   5446 pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void {
   5447     const comp = zcu.comp;
   5448 
   5449     if (comp.bin_file) |lf| {
   5450         lf.updateDecl(zcu, decl_index) catch |err| switch (err) {
   5451             error.OutOfMemory => return error.OutOfMemory,
   5452             error.AnalysisFail => {
   5453                 const decl = zcu.declPtr(decl_index);
   5454                 decl.analysis = .codegen_failure;
   5455             },
   5456             else => {
   5457                 const decl = zcu.declPtr(decl_index);
   5458                 const gpa = zcu.gpa;
   5459                 try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);
   5460                 zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
   5461                     gpa,
   5462                     decl.srcLoc(zcu),
   5463                     "unable to codegen: {s}",
   5464                     .{@errorName(err)},
   5465                 ));
   5466                 decl.analysis = .codegen_failure;
   5467                 try zcu.retryable_failures.append(zcu.gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
   5468             },
   5469         };
   5470     } else if (zcu.llvm_object) |llvm_object| {
   5471         if (build_options.only_c) unreachable;
   5472         llvm_object.updateDecl(zcu, decl_index) catch |err| switch (err) {
   5473             error.OutOfMemory => return error.OutOfMemory,
   5474             error.AnalysisFail => {
   5475                 const decl = zcu.declPtr(decl_index);
   5476                 decl.analysis = .codegen_failure;
   5477             },
   5478         };
   5479     }
   5480 }
   5481 
   5482 fn reportRetryableFileError(
   5483     mod: *Module,
   5484     file: *File,
   5485     comptime format: []const u8,
   5486     args: anytype,
   5487 ) error{OutOfMemory}!void {
   5488     file.status = .retryable_failure;
   5489 
   5490     const err_msg = try ErrorMsg.create(
   5491         mod.gpa,
   5492         .{
   5493             .file_scope = file,
   5494             .parent_decl_node = 0,
   5495             .lazy = .entire_file,
   5496         },
   5497         format,
   5498         args,
   5499     );
   5500     errdefer err_msg.destroy(mod.gpa);
   5501 
   5502     mod.comp.mutex.lock();
   5503     defer mod.comp.mutex.unlock();
   5504 
   5505     const gop = try mod.failed_files.getOrPut(mod.gpa, file);
   5506     if (gop.found_existing) {
   5507         if (gop.value_ptr.*) |old_err_msg| {
   5508             old_err_msg.destroy(mod.gpa);
   5509         }
   5510     }
   5511     gop.value_ptr.* = err_msg;
   5512 }
   5513 
   5514 pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u8) !void {
   5515     const gop = try mod.global_assembly.getOrPut(mod.gpa, decl_index);
   5516     if (gop.found_existing) {
   5517         const new_value = try std.fmt.allocPrint(mod.gpa, "{s}\n{s}", .{ gop.value_ptr.*, source });
   5518         mod.gpa.free(gop.value_ptr.*);
   5519         gop.value_ptr.* = new_value;
   5520     } else {
   5521         gop.value_ptr.* = try mod.gpa.dupe(u8, source);
   5522     }
   5523 }
   5524 
   5525 pub fn getDeclExports(mod: Module, decl_index: Decl.Index) []const *Export {
   5526     if (mod.decl_exports.get(decl_index)) |l| {
   5527         return l.items;
   5528     } else {
   5529         return &[0]*Export{};
   5530     }
   5531 }
   5532 
   5533 pub const Feature = enum {
   5534     panic_fn,
   5535     panic_unwrap_error,
   5536     safety_check_formatted,
   5537     error_return_trace,
   5538     is_named_enum_value,
   5539     error_set_has_value,
   5540     field_reordering,
   5541     /// When this feature is supported, the backend supports the following AIR instructions:
   5542     /// * `Air.Inst.Tag.add_safe`
   5543     /// * `Air.Inst.Tag.sub_safe`
   5544     /// * `Air.Inst.Tag.mul_safe`
   5545     /// The motivation for this feature is that it makes AIR smaller, and makes it easier
   5546     /// to generate better machine code in the backends. All backends should migrate to
   5547     /// enabling this feature.
   5548     safety_checked_instructions,
   5549 };
   5550 
   5551 pub fn backendSupportsFeature(zcu: Module, feature: Feature) bool {
   5552     const cpu_arch = zcu.root_mod.resolved_target.result.cpu.arch;
   5553     const ofmt = zcu.root_mod.resolved_target.result.ofmt;
   5554     const use_llvm = zcu.comp.config.use_llvm;
   5555     return target_util.backendSupportsFeature(cpu_arch, ofmt, use_llvm, feature);
   5556 }
   5557 
   5558 /// Shortcut for calling `intern_pool.get`.
   5559 pub fn intern(mod: *Module, key: InternPool.Key) Allocator.Error!InternPool.Index {
   5560     return mod.intern_pool.get(mod.gpa, key);
   5561 }
   5562 
   5563 /// Shortcut for calling `intern_pool.getCoerced`.
   5564 pub fn getCoerced(mod: *Module, val: Value, new_ty: Type) Allocator.Error!Value {
   5565     return Value.fromInterned((try mod.intern_pool.getCoerced(mod.gpa, val.toIntern(), new_ty.toIntern())));
   5566 }
   5567 
   5568 pub fn intType(mod: *Module, signedness: std.builtin.Signedness, bits: u16) Allocator.Error!Type {
   5569     return Type.fromInterned((try intern(mod, .{ .int_type = .{
   5570         .signedness = signedness,
   5571         .bits = bits,
   5572     } })));
   5573 }
   5574 
   5575 pub fn errorIntType(mod: *Module) std.mem.Allocator.Error!Type {
   5576     return mod.intType(.unsigned, mod.errorSetBits());
   5577 }
   5578 
   5579 pub fn arrayType(mod: *Module, info: InternPool.Key.ArrayType) Allocator.Error!Type {
   5580     const i = try intern(mod, .{ .array_type = info });
   5581     return Type.fromInterned(i);
   5582 }
   5583 
   5584 pub fn vectorType(mod: *Module, info: InternPool.Key.VectorType) Allocator.Error!Type {
   5585     const i = try intern(mod, .{ .vector_type = info });
   5586     return Type.fromInterned(i);
   5587 }
   5588 
   5589 pub fn optionalType(mod: *Module, child_type: InternPool.Index) Allocator.Error!Type {
   5590     const i = try intern(mod, .{ .opt_type = child_type });
   5591     return Type.fromInterned(i);
   5592 }
   5593 
   5594 pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type {
   5595     var canon_info = info;
   5596 
   5597     if (info.flags.size == .C) canon_info.flags.is_allowzero = true;
   5598 
   5599     // Canonicalize non-zero alignment. If it matches the ABI alignment of the pointee
   5600     // type, we change it to 0 here. If this causes an assertion trip because the
   5601     // pointee type needs to be resolved more, that needs to be done before calling
   5602     // this ptr() function.
   5603     if (info.flags.alignment != .none and
   5604         info.flags.alignment == Type.fromInterned(info.child).abiAlignment(mod))
   5605     {
   5606         canon_info.flags.alignment = .none;
   5607     }
   5608 
   5609     switch (info.flags.vector_index) {
   5610         // Canonicalize host_size. If it matches the bit size of the pointee type,
   5611         // we change it to 0 here. If this causes an assertion trip, the pointee type
   5612         // needs to be resolved before calling this ptr() function.
   5613         .none => if (info.packed_offset.host_size != 0) {
   5614             const elem_bit_size = Type.fromInterned(info.child).bitSize(mod);
   5615             assert(info.packed_offset.bit_offset + elem_bit_size <= info.packed_offset.host_size * 8);
   5616             if (info.packed_offset.host_size * 8 == elem_bit_size) {
   5617                 canon_info.packed_offset.host_size = 0;
   5618             }
   5619         },
   5620         .runtime => {},
   5621         _ => assert(@intFromEnum(info.flags.vector_index) < info.packed_offset.host_size),
   5622     }
   5623 
   5624     return Type.fromInterned((try intern(mod, .{ .ptr_type = canon_info })));
   5625 }
   5626 
   5627 pub fn singleMutPtrType(mod: *Module, child_type: Type) Allocator.Error!Type {
   5628     return ptrType(mod, .{ .child = child_type.toIntern() });
   5629 }
   5630 
   5631 pub fn singleConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type {
   5632     return ptrType(mod, .{
   5633         .child = child_type.toIntern(),
   5634         .flags = .{
   5635             .is_const = true,
   5636         },
   5637     });
   5638 }
   5639 
   5640 pub fn manyConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type {
   5641     return ptrType(mod, .{
   5642         .child = child_type.toIntern(),
   5643         .flags = .{
   5644             .size = .Many,
   5645             .is_const = true,
   5646         },
   5647     });
   5648 }
   5649 
   5650 pub fn adjustPtrTypeChild(mod: *Module, ptr_ty: Type, new_child: Type) Allocator.Error!Type {
   5651     var info = ptr_ty.ptrInfo(mod);
   5652     info.child = new_child.toIntern();
   5653     return mod.ptrType(info);
   5654 }
   5655 
   5656 pub fn funcType(mod: *Module, key: InternPool.GetFuncTypeKey) Allocator.Error!Type {
   5657     return Type.fromInterned((try mod.intern_pool.getFuncType(mod.gpa, key)));
   5658 }
   5659 
   5660 /// Use this for `anyframe->T` only.
   5661 /// For `anyframe`, use the `InternPool.Index.anyframe` tag directly.
   5662 pub fn anyframeType(mod: *Module, payload_ty: Type) Allocator.Error!Type {
   5663     return Type.fromInterned((try intern(mod, .{ .anyframe_type = payload_ty.toIntern() })));
   5664 }
   5665 
   5666 pub fn errorUnionType(mod: *Module, error_set_ty: Type, payload_ty: Type) Allocator.Error!Type {
   5667     return Type.fromInterned((try intern(mod, .{ .error_union_type = .{
   5668         .error_set_type = error_set_ty.toIntern(),
   5669         .payload_type = payload_ty.toIntern(),
   5670     } })));
   5671 }
   5672 
   5673 pub fn singleErrorSetType(mod: *Module, name: InternPool.NullTerminatedString) Allocator.Error!Type {
   5674     const names: *const [1]InternPool.NullTerminatedString = &name;
   5675     const new_ty = try mod.intern_pool.getErrorSetType(mod.gpa, names);
   5676     return Type.fromInterned(new_ty);
   5677 }
   5678 
   5679 /// Sorts `names` in place.
   5680 pub fn errorSetFromUnsortedNames(
   5681     mod: *Module,
   5682     names: []InternPool.NullTerminatedString,
   5683 ) Allocator.Error!Type {
   5684     std.mem.sort(
   5685         InternPool.NullTerminatedString,
   5686         names,
   5687         {},
   5688         InternPool.NullTerminatedString.indexLessThan,
   5689     );
   5690     const new_ty = try mod.intern_pool.getErrorSetType(mod.gpa, names);
   5691     return Type.fromInterned(new_ty);
   5692 }
   5693 
   5694 /// Supports only pointers, not pointer-like optionals.
   5695 pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
   5696     assert(ty.zigTypeTag(mod) == .Pointer and !ty.isSlice(mod));
   5697     assert(x != 0 or ty.isAllowzeroPtr(mod));
   5698     const i = try intern(mod, .{ .ptr = .{
   5699         .ty = ty.toIntern(),
   5700         .base_addr = .int,
   5701         .byte_offset = x,
   5702     } });
   5703     return Value.fromInterned(i);
   5704 }
   5705 
   5706 /// Creates an enum tag value based on the integer tag value.
   5707 pub fn enumValue(mod: *Module, ty: Type, tag_int: InternPool.Index) Allocator.Error!Value {
   5708     if (std.debug.runtime_safety) {
   5709         const tag = ty.zigTypeTag(mod);
   5710         assert(tag == .Enum);
   5711     }
   5712     const i = try intern(mod, .{ .enum_tag = .{
   5713         .ty = ty.toIntern(),
   5714         .int = tag_int,
   5715     } });
   5716     return Value.fromInterned(i);
   5717 }
   5718 
   5719 /// Creates an enum tag value based on the field index according to source code
   5720 /// declaration order.
   5721 pub fn enumValueFieldIndex(mod: *Module, ty: Type, field_index: u32) Allocator.Error!Value {
   5722     const ip = &mod.intern_pool;
   5723     const gpa = mod.gpa;
   5724     const enum_type = ip.loadEnumType(ty.toIntern());
   5725 
   5726     if (enum_type.values.len == 0) {
   5727         // Auto-numbered fields.
   5728         return Value.fromInterned((try ip.get(gpa, .{ .enum_tag = .{
   5729             .ty = ty.toIntern(),
   5730             .int = try ip.get(gpa, .{ .int = .{
   5731                 .ty = enum_type.tag_ty,
   5732                 .storage = .{ .u64 = field_index },
   5733             } }),
   5734         } })));
   5735     }
   5736 
   5737     return Value.fromInterned((try ip.get(gpa, .{ .enum_tag = .{
   5738         .ty = ty.toIntern(),
   5739         .int = enum_type.values.get(ip)[field_index],
   5740     } })));
   5741 }
   5742 
   5743 pub fn undefValue(mod: *Module, ty: Type) Allocator.Error!Value {
   5744     return Value.fromInterned((try mod.intern(.{ .undef = ty.toIntern() })));
   5745 }
   5746 
   5747 pub fn undefRef(mod: *Module, ty: Type) Allocator.Error!Air.Inst.Ref {
   5748     return Air.internedToRef((try mod.undefValue(ty)).toIntern());
   5749 }
   5750 
   5751 pub fn intValue(mod: *Module, ty: Type, x: anytype) Allocator.Error!Value {
   5752     if (std.math.cast(u64, x)) |casted| return intValue_u64(mod, ty, casted);
   5753     if (std.math.cast(i64, x)) |casted| return intValue_i64(mod, ty, casted);
   5754     var limbs_buffer: [4]usize = undefined;
   5755     var big_int = BigIntMutable.init(&limbs_buffer, x);
   5756     return intValue_big(mod, ty, big_int.toConst());
   5757 }
   5758 
   5759 pub fn intRef(mod: *Module, ty: Type, x: anytype) Allocator.Error!Air.Inst.Ref {
   5760     return Air.internedToRef((try mod.intValue(ty, x)).toIntern());
   5761 }
   5762 
   5763 pub fn intValue_big(mod: *Module, ty: Type, x: BigIntConst) Allocator.Error!Value {
   5764     const i = try intern(mod, .{ .int = .{
   5765         .ty = ty.toIntern(),
   5766         .storage = .{ .big_int = x },
   5767     } });
   5768     return Value.fromInterned(i);
   5769 }
   5770 
   5771 pub fn intValue_u64(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
   5772     const i = try intern(mod, .{ .int = .{
   5773         .ty = ty.toIntern(),
   5774         .storage = .{ .u64 = x },
   5775     } });
   5776     return Value.fromInterned(i);
   5777 }
   5778 
   5779 pub fn intValue_i64(mod: *Module, ty: Type, x: i64) Allocator.Error!Value {
   5780     const i = try intern(mod, .{ .int = .{
   5781         .ty = ty.toIntern(),
   5782         .storage = .{ .i64 = x },
   5783     } });
   5784     return Value.fromInterned(i);
   5785 }
   5786 
   5787 pub fn unionValue(mod: *Module, union_ty: Type, tag: Value, val: Value) Allocator.Error!Value {
   5788     const i = try intern(mod, .{ .un = .{
   5789         .ty = union_ty.toIntern(),
   5790         .tag = tag.toIntern(),
   5791         .val = val.toIntern(),
   5792     } });
   5793     return Value.fromInterned(i);
   5794 }
   5795 
   5796 /// This function casts the float representation down to the representation of the type, potentially
   5797 /// losing data if the representation wasn't correct.
   5798 pub fn floatValue(mod: *Module, ty: Type, x: anytype) Allocator.Error!Value {
   5799     const storage: InternPool.Key.Float.Storage = switch (ty.floatBits(mod.getTarget())) {
   5800         16 => .{ .f16 = @as(f16, @floatCast(x)) },
   5801         32 => .{ .f32 = @as(f32, @floatCast(x)) },
   5802         64 => .{ .f64 = @as(f64, @floatCast(x)) },
   5803         80 => .{ .f80 = @as(f80, @floatCast(x)) },
   5804         128 => .{ .f128 = @as(f128, @floatCast(x)) },
   5805         else => unreachable,
   5806     };
   5807     const i = try intern(mod, .{ .float = .{
   5808         .ty = ty.toIntern(),
   5809         .storage = storage,
   5810     } });
   5811     return Value.fromInterned(i);
   5812 }
   5813 
   5814 pub fn nullValue(mod: *Module, opt_ty: Type) Allocator.Error!Value {
   5815     const ip = &mod.intern_pool;
   5816     assert(ip.isOptionalType(opt_ty.toIntern()));
   5817     const result = try ip.get(mod.gpa, .{ .opt = .{
   5818         .ty = opt_ty.toIntern(),
   5819         .val = .none,
   5820     } });
   5821     return Value.fromInterned(result);
   5822 }
   5823 
   5824 pub fn smallestUnsignedInt(mod: *Module, max: u64) Allocator.Error!Type {
   5825     return intType(mod, .unsigned, Type.smallestUnsignedBits(max));
   5826 }
   5827 
   5828 /// Returns the smallest possible integer type containing both `min` and
   5829 /// `max`. Asserts that neither value is undef.
   5830 /// TODO: if #3806 is implemented, this becomes trivial
   5831 pub fn intFittingRange(mod: *Module, min: Value, max: Value) !Type {
   5832     assert(!min.isUndef(mod));
   5833     assert(!max.isUndef(mod));
   5834 
   5835     if (std.debug.runtime_safety) {
   5836         assert(Value.order(min, max, mod).compare(.lte));
   5837     }
   5838 
   5839     const sign = min.orderAgainstZero(mod) == .lt;
   5840 
   5841     const min_val_bits = intBitsForValue(mod, min, sign);
   5842     const max_val_bits = intBitsForValue(mod, max, sign);
   5843 
   5844     return mod.intType(
   5845         if (sign) .signed else .unsigned,
   5846         @max(min_val_bits, max_val_bits),
   5847     );
   5848 }
   5849 
   5850 /// Given a value representing an integer, returns the number of bits necessary to represent
   5851 /// this value in an integer. If `sign` is true, returns the number of bits necessary in a
   5852 /// twos-complement integer; otherwise in an unsigned integer.
   5853 /// Asserts that `val` is not undef. If `val` is negative, asserts that `sign` is true.
   5854 pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 {
   5855     assert(!val.isUndef(mod));
   5856 
   5857     const key = mod.intern_pool.indexToKey(val.toIntern());
   5858     switch (key.int.storage) {
   5859         .i64 => |x| {
   5860             if (std.math.cast(u64, x)) |casted| return Type.smallestUnsignedBits(casted) + @intFromBool(sign);
   5861             assert(sign);
   5862             // Protect against overflow in the following negation.
   5863             if (x == std.math.minInt(i64)) return 64;
   5864             return Type.smallestUnsignedBits(@as(u64, @intCast(-(x + 1)))) + 1;
   5865         },
   5866         .u64 => |x| {
   5867             return Type.smallestUnsignedBits(x) + @intFromBool(sign);
   5868         },
   5869         .big_int => |big| {
   5870             if (big.positive) return @as(u16, @intCast(big.bitCountAbs() + @intFromBool(sign)));
   5871 
   5872             // Zero is still a possibility, in which case unsigned is fine
   5873             if (big.eqlZero()) return 0;
   5874 
   5875             return @as(u16, @intCast(big.bitCountTwosComp()));
   5876         },
   5877         .lazy_align => |lazy_ty| {
   5878             return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiAlignment(mod).toByteUnits() orelse 0) + @intFromBool(sign);
   5879         },
   5880         .lazy_size => |lazy_ty| {
   5881             return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiSize(mod)) + @intFromBool(sign);
   5882         },
   5883     }
   5884 }
   5885 
   5886 pub const AtomicPtrAlignmentError = error{
   5887     FloatTooBig,
   5888     IntTooBig,
   5889     BadType,
   5890     OutOfMemory,
   5891 };
   5892 
   5893 pub const AtomicPtrAlignmentDiagnostics = struct {
   5894     bits: u16 = undefined,
   5895     max_bits: u16 = undefined,
   5896 };
   5897 
   5898 /// If ABI alignment of `ty` is OK for atomic operations, returns 0.
   5899 /// Otherwise returns the alignment required on a pointer for the target
   5900 /// to perform atomic operations.
   5901 // TODO this function does not take into account CPU features, which can affect
   5902 // this value. Audit this!
   5903 pub fn atomicPtrAlignment(
   5904     mod: *Module,
   5905     ty: Type,
   5906     diags: *AtomicPtrAlignmentDiagnostics,
   5907 ) AtomicPtrAlignmentError!Alignment {
   5908     const target = mod.getTarget();
   5909     const max_atomic_bits: u16 = switch (target.cpu.arch) {
   5910         .avr,
   5911         .msp430,
   5912         .spu_2,
   5913         => 16,
   5914 
   5915         .arc,
   5916         .arm,
   5917         .armeb,
   5918         .hexagon,
   5919         .m68k,
   5920         .le32,
   5921         .mips,
   5922         .mipsel,
   5923         .nvptx,
   5924         .powerpc,
   5925         .powerpcle,
   5926         .r600,
   5927         .riscv32,
   5928         .sparc,
   5929         .sparcel,
   5930         .tce,
   5931         .tcele,
   5932         .thumb,
   5933         .thumbeb,
   5934         .x86,
   5935         .xcore,
   5936         .amdil,
   5937         .hsail,
   5938         .spir,
   5939         .kalimba,
   5940         .lanai,
   5941         .shave,
   5942         .wasm32,
   5943         .renderscript32,
   5944         .csky,
   5945         .spirv32,
   5946         .dxil,
   5947         .loongarch32,
   5948         .xtensa,
   5949         => 32,
   5950 
   5951         .amdgcn,
   5952         .bpfel,
   5953         .bpfeb,
   5954         .le64,
   5955         .mips64,
   5956         .mips64el,
   5957         .nvptx64,
   5958         .powerpc64,
   5959         .powerpc64le,
   5960         .riscv64,
   5961         .sparc64,
   5962         .s390x,
   5963         .amdil64,
   5964         .hsail64,
   5965         .spir64,
   5966         .wasm64,
   5967         .renderscript64,
   5968         .ve,
   5969         .spirv64,
   5970         .loongarch64,
   5971         => 64,
   5972 
   5973         .aarch64,
   5974         .aarch64_be,
   5975         .aarch64_32,
   5976         => 128,
   5977 
   5978         .x86_64 => if (std.Target.x86.featureSetHas(target.cpu.features, .cx16)) 128 else 64,
   5979     };
   5980 
   5981     const int_ty = switch (ty.zigTypeTag(mod)) {
   5982         .Int => ty,
   5983         .Enum => ty.intTagType(mod),
   5984         .Float => {
   5985             const bit_count = ty.floatBits(target);
   5986             if (bit_count > max_atomic_bits) {
   5987                 diags.* = .{
   5988                     .bits = bit_count,
   5989                     .max_bits = max_atomic_bits,
   5990                 };
   5991                 return error.FloatTooBig;
   5992             }
   5993             return .none;
   5994         },
   5995         .Bool => return .none,
   5996         else => {
   5997             if (ty.isPtrAtRuntime(mod)) return .none;
   5998             return error.BadType;
   5999         },
   6000     };
   6001 
   6002     const bit_count = int_ty.intInfo(mod).bits;
   6003     if (bit_count > max_atomic_bits) {
   6004         diags.* = .{
   6005             .bits = bit_count,
   6006             .max_bits = max_atomic_bits,
   6007         };
   6008         return error.IntTooBig;
   6009     }
   6010 
   6011     return .none;
   6012 }
   6013 
   6014 pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {
   6015     return mod.declPtr(decl_index).getFileScope(mod);
   6016 }
   6017 
   6018 /// Returns null in the following cases:
   6019 /// * `@TypeOf(.{})`
   6020 /// * A struct which has no fields (`struct {}`).
   6021 /// * Not a struct.
   6022 pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType {
   6023     if (ty.ip_index == .none) return null;
   6024     const ip = &mod.intern_pool;
   6025     return switch (ip.indexToKey(ty.ip_index)) {
   6026         .struct_type => ip.loadStructType(ty.ip_index),
   6027         else => null,
   6028     };
   6029 }
   6030 
   6031 pub fn typeToPackedStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType {
   6032     const s = mod.typeToStruct(ty) orelse return null;
   6033     if (s.layout != .@"packed") return null;
   6034     return s;
   6035 }
   6036 
   6037 pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.LoadedUnionType {
   6038     if (ty.ip_index == .none) return null;
   6039     const ip = &mod.intern_pool;
   6040     return switch (ip.indexToKey(ty.ip_index)) {
   6041         .union_type => ip.loadUnionType(ty.ip_index),
   6042         else => null,
   6043     };
   6044 }
   6045 
   6046 pub fn typeToFunc(mod: *Module, ty: Type) ?InternPool.Key.FuncType {
   6047     if (ty.ip_index == .none) return null;
   6048     return mod.intern_pool.indexToFuncType(ty.toIntern());
   6049 }
   6050 
   6051 pub fn funcOwnerDeclPtr(mod: *Module, func_index: InternPool.Index) *Decl {
   6052     return mod.declPtr(mod.funcOwnerDeclIndex(func_index));
   6053 }
   6054 
   6055 pub fn funcOwnerDeclIndex(mod: *Module, func_index: InternPool.Index) Decl.Index {
   6056     return mod.funcInfo(func_index).owner_decl;
   6057 }
   6058 
   6059 pub fn iesFuncIndex(mod: *const Module, ies_index: InternPool.Index) InternPool.Index {
   6060     return mod.intern_pool.iesFuncIndex(ies_index);
   6061 }
   6062 
   6063 pub fn funcInfo(mod: *Module, func_index: InternPool.Index) InternPool.Key.Func {
   6064     return mod.intern_pool.indexToKey(func_index).func;
   6065 }
   6066 
   6067 pub fn fieldSrcLoc(mod: *Module, owner_decl_index: Decl.Index, query: FieldSrcQuery) SrcLoc {
   6068     @setCold(true);
   6069     const owner_decl = mod.declPtr(owner_decl_index);
   6070     const file = owner_decl.getFileScope(mod);
   6071     const tree = file.getTree(mod.gpa) catch |err| {
   6072         // In this case we emit a warning + a less precise source location.
   6073         log.warn("unable to load {s}: {s}", .{
   6074             file.sub_file_path, @errorName(err),
   6075         });
   6076         return owner_decl.srcLoc(mod);
   6077     };
   6078     const node = owner_decl.relativeToNodeIndex(0);
   6079     var buf: [2]Ast.Node.Index = undefined;
   6080     if (tree.fullContainerDecl(&buf, node)) |container_decl| {
   6081         return queryFieldSrc(tree.*, query, file, container_decl);
   6082     } else {
   6083         // This type was generated using @Type
   6084         return owner_decl.srcLoc(mod);
   6085     }
   6086 }
   6087 
   6088 pub fn toEnum(mod: *Module, comptime E: type, val: Value) E {
   6089     return mod.intern_pool.toEnum(E, val.toIntern());
   6090 }
   6091 
   6092 pub fn isAnytypeParam(mod: *Module, func: InternPool.Index, index: u32) bool {
   6093     const file = mod.declPtr(func.owner_decl).getFileScope(mod);
   6094 
   6095     const tags = file.zir.instructions.items(.tag);
   6096 
   6097     const param_body = file.zir.getParamBody(func.zir_body_inst);
   6098     const param = param_body[index];
   6099 
   6100     return switch (tags[param]) {
   6101         .param, .param_comptime => false,
   6102         .param_anytype, .param_anytype_comptime => true,
   6103         else => unreachable,
   6104     };
   6105 }
   6106 
   6107 pub fn getParamName(mod: *Module, func_index: InternPool.Index, index: u32) [:0]const u8 {
   6108     const func = mod.funcInfo(func_index);
   6109     const file = mod.declPtr(func.owner_decl).getFileScope(mod);
   6110 
   6111     const tags = file.zir.instructions.items(.tag);
   6112     const data = file.zir.instructions.items(.data);
   6113 
   6114     const param_body = file.zir.getParamBody(func.zir_body_inst.resolve(&mod.intern_pool));
   6115     const param = param_body[index];
   6116 
   6117     return switch (tags[@intFromEnum(param)]) {
   6118         .param, .param_comptime => blk: {
   6119             const extra = file.zir.extraData(Zir.Inst.Param, data[@intFromEnum(param)].pl_tok.payload_index);
   6120             break :blk file.zir.nullTerminatedString(extra.data.name);
   6121         },
   6122         .param_anytype, .param_anytype_comptime => blk: {
   6123             const param_data = data[@intFromEnum(param)].str_tok;
   6124             break :blk param_data.get(file.zir);
   6125         },
   6126         else => unreachable,
   6127     };
   6128 }
   6129 
   6130 pub const UnionLayout = struct {
   6131     abi_size: u64,
   6132     abi_align: Alignment,
   6133     most_aligned_field: u32,
   6134     most_aligned_field_size: u64,
   6135     biggest_field: u32,
   6136     payload_size: u64,
   6137     payload_align: Alignment,
   6138     tag_align: Alignment,
   6139     tag_size: u64,
   6140     padding: u32,
   6141 };
   6142 
   6143 pub fn getUnionLayout(mod: *Module, u: InternPool.LoadedUnionType) UnionLayout {
   6144     const ip = &mod.intern_pool;
   6145     assert(u.haveLayout(ip));
   6146     var most_aligned_field: u32 = undefined;
   6147     var most_aligned_field_size: u64 = undefined;
   6148     var biggest_field: u32 = undefined;
   6149     var payload_size: u64 = 0;
   6150     var payload_align: Alignment = .@"1";
   6151     for (u.field_types.get(ip), 0..) |field_ty, i| {
   6152         if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(mod)) continue;
   6153 
   6154         const explicit_align = u.fieldAlign(ip, @intCast(i));
   6155         const field_align = if (explicit_align != .none)
   6156             explicit_align
   6157         else
   6158             Type.fromInterned(field_ty).abiAlignment(mod);
   6159         const field_size = Type.fromInterned(field_ty).abiSize(mod);
   6160         if (field_size > payload_size) {
   6161             payload_size = field_size;
   6162             biggest_field = @intCast(i);
   6163         }
   6164         if (field_align.compare(.gte, payload_align)) {
   6165             payload_align = field_align;
   6166             most_aligned_field = @intCast(i);
   6167             most_aligned_field_size = field_size;
   6168         }
   6169     }
   6170     const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();
   6171     if (!have_tag or !Type.fromInterned(u.enum_tag_ty).hasRuntimeBits(mod)) {
   6172         return .{
   6173             .abi_size = payload_align.forward(payload_size),
   6174             .abi_align = payload_align,
   6175             .most_aligned_field = most_aligned_field,
   6176             .most_aligned_field_size = most_aligned_field_size,
   6177             .biggest_field = biggest_field,
   6178             .payload_size = payload_size,
   6179             .payload_align = payload_align,
   6180             .tag_align = .none,
   6181             .tag_size = 0,
   6182             .padding = 0,
   6183         };
   6184     }
   6185 
   6186     const tag_size = Type.fromInterned(u.enum_tag_ty).abiSize(mod);
   6187     const tag_align = Type.fromInterned(u.enum_tag_ty).abiAlignment(mod).max(.@"1");
   6188     return .{
   6189         .abi_size = u.size(ip).*,
   6190         .abi_align = tag_align.max(payload_align),
   6191         .most_aligned_field = most_aligned_field,
   6192         .most_aligned_field_size = most_aligned_field_size,
   6193         .biggest_field = biggest_field,
   6194         .payload_size = payload_size,
   6195         .payload_align = payload_align,
   6196         .tag_align = tag_align,
   6197         .tag_size = tag_size,
   6198         .padding = u.padding(ip).*,
   6199     };
   6200 }
   6201 
   6202 pub fn unionAbiSize(mod: *Module, u: InternPool.LoadedUnionType) u64 {
   6203     return mod.getUnionLayout(u).abi_size;
   6204 }
   6205 
   6206 /// Returns 0 if the union is represented with 0 bits at runtime.
   6207 pub fn unionAbiAlignment(mod: *Module, u: InternPool.LoadedUnionType) Alignment {
   6208     const ip = &mod.intern_pool;
   6209     const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();
   6210     var max_align: Alignment = .none;
   6211     if (have_tag) max_align = Type.fromInterned(u.enum_tag_ty).abiAlignment(mod);
   6212     for (u.field_types.get(ip), 0..) |field_ty, field_index| {
   6213         if (!Type.fromInterned(field_ty).hasRuntimeBits(mod)) continue;
   6214 
   6215         const field_align = mod.unionFieldNormalAlignment(u, @intCast(field_index));
   6216         max_align = max_align.max(field_align);
   6217     }
   6218     return max_align;
   6219 }
   6220 
   6221 /// Returns the field alignment, assuming the union is not packed.
   6222 /// Keep implementation in sync with `Sema.unionFieldAlignment`.
   6223 /// Prefer to call that function instead of this one during Sema.
   6224 pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.LoadedUnionType, field_index: u32) Alignment {
   6225     const ip = &mod.intern_pool;
   6226     const field_align = u.fieldAlign(ip, field_index);
   6227     if (field_align != .none) return field_align;
   6228     const field_ty = Type.fromInterned(u.field_types.get(ip)[field_index]);
   6229     return field_ty.abiAlignment(mod);
   6230 }
   6231 
   6232 /// Returns the index of the active field, given the current tag value
   6233 pub fn unionTagFieldIndex(mod: *Module, u: InternPool.LoadedUnionType, enum_tag: Value) ?u32 {
   6234     const ip = &mod.intern_pool;
   6235     if (enum_tag.toIntern() == .none) return null;
   6236     assert(ip.typeOf(enum_tag.toIntern()) == u.enum_tag_ty);
   6237     return u.loadTagType(ip).tagValueIndex(ip, enum_tag.toIntern());
   6238 }
   6239 
   6240 /// Returns the field alignment of a non-packed struct in byte units.
   6241 /// Keep implementation in sync with `Sema.structFieldAlignment`.
   6242 /// asserts the layout is not packed.
   6243 pub fn structFieldAlignment(
   6244     mod: *Module,
   6245     explicit_alignment: InternPool.Alignment,
   6246     field_ty: Type,
   6247     layout: std.builtin.Type.ContainerLayout,
   6248 ) Alignment {
   6249     assert(layout != .@"packed");
   6250     if (explicit_alignment != .none) return explicit_alignment;
   6251     switch (layout) {
   6252         .@"packed" => unreachable,
   6253         .auto => {
   6254             if (mod.getTarget().ofmt == .c) {
   6255                 return structFieldAlignmentExtern(mod, field_ty);
   6256             } else {
   6257                 return field_ty.abiAlignment(mod);
   6258             }
   6259         },
   6260         .@"extern" => return structFieldAlignmentExtern(mod, field_ty),
   6261     }
   6262 }
   6263 
   6264 /// Returns the field alignment of an extern struct in byte units.
   6265 /// This logic is duplicated in Type.abiAlignmentAdvanced.
   6266 pub fn structFieldAlignmentExtern(mod: *Module, field_ty: Type) Alignment {
   6267     const ty_abi_align = field_ty.abiAlignment(mod);
   6268 
   6269     if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) {
   6270         // The C ABI requires 128 bit integer fields of structs
   6271         // to be 16-bytes aligned.
   6272         return ty_abi_align.max(.@"16");
   6273     }
   6274 
   6275     return ty_abi_align;
   6276 }
   6277 
   6278 /// https://github.com/ziglang/zig/issues/17178 explored storing these bit offsets
   6279 /// into the packed struct InternPool data rather than computing this on the
   6280 /// fly, however it was found to perform worse when measured on real world
   6281 /// projects.
   6282 pub fn structPackedFieldBitOffset(
   6283     mod: *Module,
   6284     struct_type: InternPool.LoadedStructType,
   6285     field_index: u32,
   6286 ) u16 {
   6287     const ip = &mod.intern_pool;
   6288     assert(struct_type.layout == .@"packed");
   6289     assert(struct_type.haveLayout(ip));
   6290     var bit_sum: u64 = 0;
   6291     for (0..struct_type.field_types.len) |i| {
   6292         if (i == field_index) {
   6293             return @intCast(bit_sum);
   6294         }
   6295         const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
   6296         bit_sum += field_ty.bitSize(mod);
   6297     }
   6298     unreachable; // index out of bounds
   6299 }