zig

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

blob 5dcda2ea (150746B) - 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 assert = std.debug.assert;
     10 const log = std.log.scoped(.module);
     11 const BigIntConst = std.math.big.int.Const;
     12 const BigIntMutable = std.math.big.int.Mutable;
     13 const Target = std.Target;
     14 const Ast = std.zig.Ast;
     15 
     16 /// Deprecated, use `Zcu`.
     17 const Module = Zcu;
     18 const Zcu = @This();
     19 const Compilation = @import("Compilation.zig");
     20 const Cache = std.Build.Cache;
     21 const Value = @import("Value.zig");
     22 const Type = @import("Type.zig");
     23 const Package = @import("Package.zig");
     24 const link = @import("link.zig");
     25 const Air = @import("Air.zig");
     26 const Zir = std.zig.Zir;
     27 const trace = @import("tracy.zig").trace;
     28 const AstGen = std.zig.AstGen;
     29 const Sema = @import("Sema.zig");
     30 const target_util = @import("target.zig");
     31 const build_options = @import("build_options");
     32 const Liveness = @import("Liveness.zig");
     33 const isUpDir = @import("introspect.zig").isUpDir;
     34 const clang = @import("clang.zig");
     35 const InternPool = @import("InternPool.zig");
     36 const Alignment = InternPool.Alignment;
     37 const AnalUnit = InternPool.AnalUnit;
     38 const BuiltinFn = std.zig.BuiltinFn;
     39 const LlvmObject = @import("codegen/llvm.zig").Object;
     40 
     41 comptime {
     42     @setEvalBranchQuota(4000);
     43     for (
     44         @typeInfo(Zir.Inst.Ref).Enum.fields,
     45         @typeInfo(Air.Inst.Ref).Enum.fields,
     46         @typeInfo(InternPool.Index).Enum.fields,
     47     ) |zir_field, air_field, ip_field| {
     48         assert(mem.eql(u8, zir_field.name, ip_field.name));
     49         assert(mem.eql(u8, air_field.name, ip_field.name));
     50     }
     51 }
     52 
     53 /// General-purpose allocator. Used for both temporary and long-term storage.
     54 gpa: Allocator,
     55 comp: *Compilation,
     56 /// Usually, the LlvmObject is managed by linker code, however, in the case
     57 /// that -fno-emit-bin is specified, the linker code never executes, so we
     58 /// store the LlvmObject here.
     59 llvm_object: ?*LlvmObject,
     60 
     61 /// Pointer to externally managed resource.
     62 root_mod: *Package.Module,
     63 /// Normally, `main_mod` and `root_mod` are the same. The exception is `zig test`, in which
     64 /// `root_mod` is the test runner, and `main_mod` is the user's source file which has the tests.
     65 main_mod: *Package.Module,
     66 std_mod: *Package.Module,
     67 sema_prog_node: std.Progress.Node = std.Progress.Node.none,
     68 codegen_prog_node: std.Progress.Node = std.Progress.Node.none,
     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 
     75 /// This is where all `Export` values are stored. Not all values here are necessarily valid exports;
     76 /// to enumerate all exports, `single_exports` and `multi_exports` must be consulted.
     77 all_exports: std.ArrayListUnmanaged(Export) = .{},
     78 /// This is a list of free indices in `all_exports`. These indices may be reused by exports from
     79 /// future semantic analysis.
     80 free_exports: std.ArrayListUnmanaged(u32) = .{},
     81 /// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of
     82 /// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit`
     83 /// whose analysis triggered the export.
     84 single_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
     85 /// Like `single_exports`, but for `AnalUnit`s which perform multiple exports.
     86 /// The exports are `all_exports.items[index..][0..len]`.
     87 multi_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
     88     index: u32,
     89     len: u32,
     90 }) = .{},
     91 
     92 /// The set of all the Zig source files in the Zig Compilation Unit. Tracked in
     93 /// order to iterate over it and check which source files have been modified on
     94 /// the file system when an update is requested, as well as to cache `@import`
     95 /// results.
     96 ///
     97 /// Keys are fully resolved file paths. This table owns the keys and values.
     98 ///
     99 /// Protected by Compilation's mutex.
    100 ///
    101 /// Not serialized. This state is reconstructed during the first call to
    102 /// `Compilation.update` of the process for a given `Compilation`.
    103 ///
    104 /// Indexes correspond 1:1 to `files`.
    105 import_table: std.StringArrayHashMapUnmanaged(File.Index) = .{},
    106 
    107 /// The set of all the files which have been loaded with `@embedFile` in the Module.
    108 /// We keep track of this in order to iterate over it and check which files have been
    109 /// modified on the file system when an update is requested, as well as to cache
    110 /// `@embedFile` results.
    111 /// Keys are fully resolved file paths. This table owns the keys and values.
    112 embed_table: std.StringArrayHashMapUnmanaged(*EmbedFile) = .{},
    113 
    114 /// Stores all Type and Value objects.
    115 /// The idea is that this will be periodically garbage-collected, but such logic
    116 /// is not yet implemented.
    117 intern_pool: InternPool = .{},
    118 
    119 /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
    120 failed_analysis: std.AutoArrayHashMapUnmanaged(AnalUnit, *ErrorMsg) = .{},
    121 /// Keep track of one `@compileLog` callsite per `AnalUnit`.
    122 /// The value is the source location of the `@compileLog` call, convertible to a `LazySrcLoc`.
    123 compile_log_sources: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
    124     base_node_inst: InternPool.TrackedInst.Index,
    125     node_offset: i32,
    126     pub fn src(self: @This()) LazySrcLoc {
    127         return .{
    128             .base_node_inst = self.base_node_inst,
    129             .offset = LazySrcLoc.Offset.nodeOffset(self.node_offset),
    130         };
    131     }
    132 }) = .{},
    133 /// Using a map here for consistency with the other fields here.
    134 /// The ErrorMsg memory is owned by the `File`, using Module's general purpose allocator.
    135 failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .{},
    136 /// The ErrorMsg memory is owned by the `EmbedFile`, using Module's general purpose allocator.
    137 failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .{},
    138 /// Key is index into `all_exports`.
    139 failed_exports: std.AutoArrayHashMapUnmanaged(u32, *ErrorMsg) = .{},
    140 /// If analysis failed due to a cimport error, the corresponding Clang errors
    141 /// are stored here.
    142 cimport_errors: std.AutoArrayHashMapUnmanaged(AnalUnit, std.zig.ErrorBundle) = .{},
    143 
    144 /// Key is the error name, index is the error tag value. Index 0 has a length-0 string.
    145 global_error_set: GlobalErrorSet = .{},
    146 
    147 /// Maximum amount of distinct error values, set by --error-limit
    148 error_limit: ErrorInt,
    149 
    150 /// Value is the number of PO or outdated Decls which this AnalUnit depends on.
    151 potentially_outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
    152 /// Value is the number of PO or outdated Decls which this AnalUnit depends on.
    153 /// Once this value drops to 0, the AnalUnit is a candidate for re-analysis.
    154 outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
    155 /// This contains all `AnalUnit`s in `outdated` whose PO dependency count is 0.
    156 /// Such `AnalUnit`s are ready for immediate re-analysis.
    157 /// See `findOutdatedToAnalyze` for details.
    158 outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{},
    159 /// This contains a set of Decls which may not be in `outdated`, but are the
    160 /// root Decls of files which have updated source and thus must be re-analyzed.
    161 /// If such a Decl is only in this set, the struct type index may be preserved
    162 /// (only the namespace might change). If such a Decl is also `outdated`, the
    163 /// struct type index must be recreated.
    164 outdated_file_root: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
    165 /// This contains a list of AnalUnit whose analysis or codegen failed, but the
    166 /// failure was something like running out of disk space, and trying again may
    167 /// succeed. On the next update, we will flush this list, marking all members of
    168 /// it as outdated.
    169 retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .{},
    170 
    171 stage1_flags: packed struct {
    172     have_winmain: bool = false,
    173     have_wwinmain: bool = false,
    174     have_winmain_crt_startup: bool = false,
    175     have_wwinmain_crt_startup: bool = false,
    176     have_dllmain_crt_startup: bool = false,
    177     have_c_main: bool = false,
    178     reserved: u2 = 0,
    179 } = .{},
    180 
    181 compile_log_text: std.ArrayListUnmanaged(u8) = .{},
    182 
    183 emit_h: ?*GlobalEmitH,
    184 
    185 test_functions: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
    186 
    187 /// TODO: the key here will be a `Cau.Index`.
    188 global_assembly: std.AutoArrayHashMapUnmanaged(Decl.Index, []u8) = .{},
    189 
    190 /// Key is the `AnalUnit` *performing* the reference. This representation allows
    191 /// incremental updates to quickly delete references caused by a specific `AnalUnit`.
    192 /// Value is index into `all_reference` of the first reference triggered by the unit.
    193 /// The `next` field on the `Reference` forms a linked list of all references
    194 /// triggered by the key `AnalUnit`.
    195 reference_table: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
    196 all_references: std.ArrayListUnmanaged(Reference) = .{},
    197 /// Freelist of indices in `all_references`.
    198 free_references: std.ArrayListUnmanaged(u32) = .{},
    199 
    200 panic_messages: [PanicId.len]Decl.OptionalIndex = .{.none} ** PanicId.len,
    201 /// The panic function body.
    202 panic_func_index: InternPool.Index = .none,
    203 null_stack_trace: InternPool.Index = .none,
    204 
    205 pub const PerThread = @import("Zcu/PerThread.zig");
    206 
    207 pub const PanicId = enum {
    208     unreach,
    209     unwrap_null,
    210     cast_to_null,
    211     incorrect_alignment,
    212     invalid_error_code,
    213     cast_truncated_data,
    214     negative_to_unsigned,
    215     integer_overflow,
    216     shl_overflow,
    217     shr_overflow,
    218     divide_by_zero,
    219     exact_division_remainder,
    220     inactive_union_field,
    221     integer_part_out_of_bounds,
    222     corrupt_switch,
    223     shift_rhs_too_big,
    224     invalid_enum_value,
    225     sentinel_mismatch,
    226     unwrap_error,
    227     index_out_of_bounds,
    228     start_index_greater_than_end,
    229     for_len_mismatch,
    230     memcpy_len_mismatch,
    231     memcpy_alias,
    232     noreturn_returned,
    233 
    234     pub const len = @typeInfo(PanicId).Enum.fields.len;
    235 };
    236 
    237 pub const GlobalErrorSet = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void);
    238 
    239 pub const CImportError = struct {
    240     offset: u32,
    241     line: u32,
    242     column: u32,
    243     path: ?[*:0]u8,
    244     source_line: ?[*:0]u8,
    245     msg: [*:0]u8,
    246 
    247     pub fn deinit(err: CImportError, gpa: Allocator) void {
    248         if (err.path) |some| gpa.free(std.mem.span(some));
    249         if (err.source_line) |some| gpa.free(std.mem.span(some));
    250         gpa.free(std.mem.span(err.msg));
    251     }
    252 };
    253 
    254 /// A `Module` has zero or one of these depending on whether `-femit-h` is enabled.
    255 pub const GlobalEmitH = struct {
    256     /// Where to put the output.
    257     loc: Compilation.EmitLoc,
    258     /// When emit_h is non-null, each Decl gets one more compile error slot for
    259     /// emit-h failing for that Decl. This table is also how we tell if a Decl has
    260     /// failed emit-h or succeeded.
    261     failed_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, *ErrorMsg) = .{},
    262     /// Tracks all decls in order to iterate over them and emit .h code for them.
    263     decl_table: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
    264     /// Similar to the allocated_decls field of Module, this is where `EmitH` objects
    265     /// are allocated. There will be exactly one EmitH object per Decl object, with
    266     /// identical indexes.
    267     allocated_emit_h: std.SegmentedList(EmitH, 0) = .{},
    268 
    269     pub fn declPtr(global_emit_h: *GlobalEmitH, decl_index: Decl.Index) *EmitH {
    270         return global_emit_h.allocated_emit_h.at(@intFromEnum(decl_index));
    271     }
    272 };
    273 
    274 pub const ErrorInt = u32;
    275 
    276 pub const Exported = union(enum) {
    277     /// The Decl being exported. Note this is *not* the Decl performing the export.
    278     decl_index: Decl.Index,
    279     /// Constant value being exported.
    280     value: InternPool.Index,
    281 
    282     pub fn getValue(exported: Exported, zcu: *Zcu) Value {
    283         return switch (exported) {
    284             .decl_index => |decl_index| zcu.declPtr(decl_index).val,
    285             .value => |value| Value.fromInterned(value),
    286         };
    287     }
    288 
    289     pub fn getAlign(exported: Exported, zcu: *Zcu) Alignment {
    290         return switch (exported) {
    291             .decl_index => |decl_index| zcu.declPtr(decl_index).alignment,
    292             .value => .none,
    293         };
    294     }
    295 };
    296 
    297 pub const Export = struct {
    298     opts: Options,
    299     src: LazySrcLoc,
    300     exported: Exported,
    301     status: enum {
    302         in_progress,
    303         failed,
    304         /// Indicates that the failure was due to a temporary issue, such as an I/O error
    305         /// when writing to the output file. Retrying the export may succeed.
    306         failed_retryable,
    307         complete,
    308     },
    309 
    310     pub const Options = struct {
    311         name: InternPool.NullTerminatedString,
    312         linkage: std.builtin.GlobalLinkage = .strong,
    313         section: InternPool.OptionalNullTerminatedString = .none,
    314         visibility: std.builtin.SymbolVisibility = .default,
    315     };
    316 };
    317 
    318 pub const Reference = struct {
    319     /// The `AnalUnit` whose semantic analysis was triggered by this reference.
    320     referenced: AnalUnit,
    321     /// Index into `all_references` of the next `Reference` triggered by the same `AnalUnit`.
    322     /// `std.math.maxInt(u32)` is the sentinel.
    323     next: u32,
    324     /// The source location of the reference.
    325     src: LazySrcLoc,
    326 };
    327 
    328 pub const Decl = struct {
    329     /// Equal to `fqn` if already fully qualified.
    330     name: InternPool.NullTerminatedString,
    331     /// Fully qualified name.
    332     fqn: InternPool.NullTerminatedString,
    333     /// The most recent Value of the Decl after a successful semantic analysis.
    334     /// Populated when `has_tv`.
    335     val: Value,
    336     /// Populated when `has_tv`.
    337     @"linksection": InternPool.OptionalNullTerminatedString,
    338     /// Populated when `has_tv`.
    339     alignment: Alignment,
    340     /// Populated when `has_tv`.
    341     @"addrspace": std.builtin.AddressSpace,
    342     /// The direct parent namespace of the Decl. In the case of the Decl
    343     /// corresponding to a file, this is the namespace of the struct, since
    344     /// there is no parent.
    345     src_namespace: Namespace.Index,
    346 
    347     /// Index of the ZIR `declaration` instruction from which this `Decl` was created.
    348     /// For the root `Decl` of a `File` and legacy anonymous decls, this is `.none`.
    349     zir_decl_index: InternPool.TrackedInst.Index.Optional,
    350 
    351     /// Represents the "shallow" analysis status. For example, for decls that are functions,
    352     /// the function type is analyzed with this set to `in_progress`, however, the semantic
    353     /// analysis of the function body is performed with this value set to `success`. Functions
    354     /// have their own analysis status field.
    355     analysis: enum {
    356         /// This Decl corresponds to an AST Node that has not been referenced yet, and therefore
    357         /// because of Zig's lazy declaration analysis, it will remain unanalyzed until referenced.
    358         unreferenced,
    359         /// Semantic analysis for this Decl is running right now.
    360         /// This state detects dependency loops.
    361         in_progress,
    362         /// The file corresponding to this Decl had a parse error or ZIR error.
    363         /// There will be a corresponding ErrorMsg in Zcu.failed_files.
    364         file_failure,
    365         /// This Decl might be OK but it depends on another one which did not
    366         /// successfully complete semantic analysis.
    367         dependency_failure,
    368         /// Semantic analysis failure.
    369         /// There will be a corresponding ErrorMsg in Zcu.failed_analysis.
    370         sema_failure,
    371         /// There will be a corresponding ErrorMsg in Zcu.failed_analysis.
    372         codegen_failure,
    373         /// Sematic analysis and constant value codegen of this Decl has
    374         /// succeeded. However, the Decl may be outdated due to an in-progress
    375         /// update. Note that for a function, this does not mean codegen of the
    376         /// function body succeded: that state is indicated by the function's
    377         /// `analysis` field.
    378         complete,
    379     },
    380     /// Whether `typed_value`, `align`, `linksection` and `addrspace` are populated.
    381     has_tv: bool,
    382     /// If `true` it means the `Decl` is the resource owner of the type/value associated
    383     /// with it. That means when `Decl` is destroyed, the cleanup code should additionally
    384     /// check if the value owns a `Namespace`, and destroy that too.
    385     owns_tv: bool,
    386     /// Whether the corresponding AST decl has a `pub` keyword.
    387     is_pub: bool,
    388     /// Whether the corresponding AST decl has a `export` keyword.
    389     is_exported: bool,
    390     /// What kind of a declaration is this.
    391     kind: Kind,
    392 
    393     pub const Kind = enum {
    394         @"usingnamespace",
    395         @"test",
    396         @"comptime",
    397         named,
    398         anon,
    399     };
    400 
    401     pub const Index = InternPool.DeclIndex;
    402     pub const OptionalIndex = InternPool.OptionalDeclIndex;
    403 
    404     pub fn zirBodies(decl: Decl, zcu: *Zcu) Zir.Inst.Declaration.Bodies {
    405         const zir = decl.getFileScope(zcu).zir;
    406         const zir_index = decl.zir_decl_index.unwrap().?.resolve(&zcu.intern_pool);
    407         const declaration = zir.instructions.items(.data)[@intFromEnum(zir_index)].declaration;
    408         const extra = zir.extraData(Zir.Inst.Declaration, declaration.payload_index);
    409         return extra.data.getBodies(@intCast(extra.end), zir);
    410     }
    411 
    412     pub fn typeOf(decl: Decl, zcu: *const Zcu) Type {
    413         assert(decl.has_tv);
    414         return decl.val.typeOf(zcu);
    415     }
    416 
    417     /// Small wrapper for Sema to use over direct access to the `val` field.
    418     /// If the value is not populated, instead returns `error.AnalysisFail`.
    419     pub fn valueOrFail(decl: Decl) error{AnalysisFail}!Value {
    420         if (!decl.has_tv) return error.AnalysisFail;
    421         return decl.val;
    422     }
    423 
    424     pub fn getOwnedFunction(decl: Decl, zcu: *Zcu) ?InternPool.Key.Func {
    425         const i = decl.getOwnedFunctionIndex();
    426         if (i == .none) return null;
    427         return switch (zcu.intern_pool.indexToKey(i)) {
    428             .func => |func| func,
    429             else => null,
    430         };
    431     }
    432 
    433     /// This returns an InternPool.Index even when the value is not a function.
    434     pub fn getOwnedFunctionIndex(decl: Decl) InternPool.Index {
    435         return if (decl.owns_tv) decl.val.toIntern() else .none;
    436     }
    437 
    438     /// If the Decl owns its value and it is an extern function, returns it,
    439     /// otherwise null.
    440     pub fn getOwnedExternFunc(decl: Decl, zcu: *Zcu) ?InternPool.Key.ExternFunc {
    441         return if (decl.owns_tv) decl.val.getExternFunc(zcu) else null;
    442     }
    443 
    444     /// If the Decl owns its value and it is a variable, returns it,
    445     /// otherwise null.
    446     pub fn getOwnedVariable(decl: Decl, zcu: *Zcu) ?InternPool.Key.Variable {
    447         return if (decl.owns_tv) decl.val.getVariable(zcu) else null;
    448     }
    449 
    450     /// Gets the namespace that this Decl creates by being a struct, union,
    451     /// enum, or opaque.
    452     pub fn getInnerNamespaceIndex(decl: Decl, zcu: *Zcu) Namespace.OptionalIndex {
    453         if (!decl.has_tv) return .none;
    454         const ip = &zcu.intern_pool;
    455         return switch (decl.val.ip_index) {
    456             .empty_struct_type => .none,
    457             .none => .none,
    458             else => switch (ip.indexToKey(decl.val.toIntern())) {
    459                 .opaque_type => ip.loadOpaqueType(decl.val.toIntern()).namespace,
    460                 .struct_type => ip.loadStructType(decl.val.toIntern()).namespace,
    461                 .union_type => ip.loadUnionType(decl.val.toIntern()).namespace,
    462                 .enum_type => ip.loadEnumType(decl.val.toIntern()).namespace,
    463                 else => .none,
    464             },
    465         };
    466     }
    467 
    468     /// Like `getInnerNamespaceIndex`, but only returns it if the Decl is the owner.
    469     pub fn getOwnedInnerNamespaceIndex(decl: Decl, zcu: *Zcu) Namespace.OptionalIndex {
    470         if (!decl.owns_tv) return .none;
    471         return decl.getInnerNamespaceIndex(zcu);
    472     }
    473 
    474     /// Same as `getOwnedInnerNamespaceIndex` but additionally obtains the pointer.
    475     pub fn getOwnedInnerNamespace(decl: Decl, zcu: *Zcu) ?*Namespace {
    476         return zcu.namespacePtrUnwrap(decl.getOwnedInnerNamespaceIndex(zcu));
    477     }
    478 
    479     /// Same as `getInnerNamespaceIndex` but additionally obtains the pointer.
    480     pub fn getInnerNamespace(decl: Decl, zcu: *Zcu) ?*Namespace {
    481         return zcu.namespacePtrUnwrap(decl.getInnerNamespaceIndex(zcu));
    482     }
    483 
    484     pub fn getFileScope(decl: Decl, zcu: *Zcu) *File {
    485         return zcu.fileByIndex(getFileScopeIndex(decl, zcu));
    486     }
    487 
    488     pub fn getFileScopeIndex(decl: Decl, zcu: *Zcu) File.Index {
    489         return zcu.namespacePtr(decl.src_namespace).file_scope;
    490     }
    491 
    492     pub fn getExternDecl(decl: Decl, zcu: *Zcu) OptionalIndex {
    493         assert(decl.has_tv);
    494         return switch (zcu.intern_pool.indexToKey(decl.val.toIntern())) {
    495             .variable => |variable| if (variable.is_extern) variable.decl.toOptional() else .none,
    496             .extern_func => |extern_func| extern_func.decl.toOptional(),
    497             else => .none,
    498         };
    499     }
    500 
    501     pub fn isExtern(decl: Decl, zcu: *Zcu) bool {
    502         return decl.getExternDecl(zcu) != .none;
    503     }
    504 
    505     pub fn getAlignment(decl: Decl, pt: Zcu.PerThread) Alignment {
    506         assert(decl.has_tv);
    507         if (decl.alignment != .none) return decl.alignment;
    508         return decl.typeOf(pt.zcu).abiAlignment(pt);
    509     }
    510 
    511     pub fn declPtrType(decl: Decl, pt: Zcu.PerThread) !Type {
    512         assert(decl.has_tv);
    513         const decl_ty = decl.typeOf(pt.zcu);
    514         return pt.ptrType(.{
    515             .child = decl_ty.toIntern(),
    516             .flags = .{
    517                 .alignment = if (decl.alignment == decl_ty.abiAlignment(pt))
    518                     .none
    519                 else
    520                     decl.alignment,
    521                 .address_space = decl.@"addrspace",
    522                 .is_const = decl.getOwnedVariable(pt.zcu) == null,
    523             },
    524         });
    525     }
    526 
    527     /// Returns the source location of this `Decl`.
    528     /// Asserts that this `Decl` corresponds to what will in future be a `Nav` (Named
    529     /// Addressable Value): a source-level declaration or generic instantiation.
    530     pub fn navSrcLoc(decl: Decl, zcu: *Zcu) LazySrcLoc {
    531         return .{
    532             .base_node_inst = decl.zir_decl_index.unwrap() orelse inst: {
    533                 // generic instantiation
    534                 assert(decl.has_tv);
    535                 assert(decl.owns_tv);
    536                 const owner = zcu.funcInfo(decl.val.toIntern()).generic_owner;
    537                 const generic_owner_decl = zcu.declPtr(zcu.funcInfo(owner).owner_decl);
    538                 break :inst generic_owner_decl.zir_decl_index.unwrap().?;
    539             },
    540             .offset = LazySrcLoc.Offset.nodeOffset(0),
    541         };
    542     }
    543 
    544     pub fn navSrcLine(decl: Decl, zcu: *Zcu) u32 {
    545         const ip = &zcu.intern_pool;
    546         const tracked = decl.zir_decl_index.unwrap() orelse inst: {
    547             // generic instantiation
    548             assert(decl.has_tv);
    549             assert(decl.owns_tv);
    550             const generic_owner_func = switch (ip.indexToKey(decl.val.toIntern())) {
    551                 .func => |func| func.generic_owner,
    552                 else => return 0, // TODO: this is probably a `variable` or something; figure this out when we finish sorting out `Decl`.
    553             };
    554             const generic_owner_decl = zcu.declPtr(zcu.funcInfo(generic_owner_func).owner_decl);
    555             break :inst generic_owner_decl.zir_decl_index.unwrap().?;
    556         };
    557         const info = tracked.resolveFull(ip);
    558         const file = zcu.fileByIndex(info.file);
    559         assert(file.zir_loaded);
    560         const zir = file.zir;
    561         const inst = zir.instructions.get(@intFromEnum(info.inst));
    562         assert(inst.tag == .declaration);
    563         return zir.extraData(Zir.Inst.Declaration, inst.data.declaration.payload_index).data.src_line;
    564     }
    565 
    566     pub fn typeSrcLine(decl: Decl, zcu: *Zcu) u32 {
    567         assert(decl.has_tv);
    568         assert(decl.owns_tv);
    569         return decl.val.toType().typeDeclSrcLine(zcu).?;
    570     }
    571 };
    572 
    573 /// This state is attached to every Decl when Module emit_h is non-null.
    574 pub const EmitH = struct {
    575     fwd_decl: std.ArrayListUnmanaged(u8) = .{},
    576 };
    577 
    578 pub const DeclAdapter = struct {
    579     zcu: *Zcu,
    580 
    581     pub fn hash(self: @This(), s: InternPool.NullTerminatedString) u32 {
    582         _ = self;
    583         return std.hash.uint32(@intFromEnum(s));
    584     }
    585 
    586     pub fn eql(self: @This(), a: InternPool.NullTerminatedString, b_decl_index: Decl.Index, b_index: usize) bool {
    587         _ = b_index;
    588         return a == self.zcu.declPtr(b_decl_index).name;
    589     }
    590 };
    591 
    592 /// The container that structs, enums, unions, and opaques have.
    593 pub const Namespace = struct {
    594     parent: OptionalIndex,
    595     file_scope: File.Index,
    596     /// Will be a struct, enum, union, or opaque.
    597     decl_index: Decl.Index,
    598     /// Direct children of the namespace.
    599     /// Declaration order is preserved via entry order.
    600     /// These are only declarations named directly by the AST; anonymous
    601     /// declarations are not stored here.
    602     decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{},
    603     /// Key is usingnamespace Decl itself. To find the namespace being included,
    604     /// the Decl Value has to be resolved as a Type which has a Namespace.
    605     /// Value is whether the usingnamespace decl is marked `pub`.
    606     usingnamespace_set: std.AutoHashMapUnmanaged(Decl.Index, bool) = .{},
    607 
    608     pub const Index = InternPool.NamespaceIndex;
    609     pub const OptionalIndex = InternPool.OptionalNamespaceIndex;
    610 
    611     const DeclContext = struct {
    612         zcu: *Zcu,
    613 
    614         pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 {
    615             const decl = ctx.zcu.declPtr(decl_index);
    616             return std.hash.uint32(@intFromEnum(decl.name));
    617         }
    618 
    619         pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool {
    620             _ = b_index;
    621             const a_decl = ctx.zcu.declPtr(a_decl_index);
    622             const b_decl = ctx.zcu.declPtr(b_decl_index);
    623             return a_decl.name == b_decl.name;
    624         }
    625     };
    626 
    627     pub fn fileScope(ns: Namespace, zcu: *Zcu) *File {
    628         return zcu.fileByIndex(ns.file_scope);
    629     }
    630 
    631     // This renders e.g. "std.fs.Dir.OpenOptions"
    632     pub fn renderFullyQualifiedName(
    633         ns: Namespace,
    634         zcu: *Zcu,
    635         name: InternPool.NullTerminatedString,
    636         writer: anytype,
    637     ) @TypeOf(writer).Error!void {
    638         if (ns.parent.unwrap()) |parent| {
    639             try zcu.namespacePtr(parent).renderFullyQualifiedName(
    640                 zcu,
    641                 zcu.declPtr(ns.decl_index).name,
    642                 writer,
    643             );
    644         } else {
    645             try ns.fileScope(zcu).renderFullyQualifiedName(writer);
    646         }
    647         if (name != .empty) try writer.print(".{}", .{name.fmt(&zcu.intern_pool)});
    648     }
    649 
    650     /// This renders e.g. "std/fs.zig:Dir.OpenOptions"
    651     pub fn renderFullyQualifiedDebugName(
    652         ns: Namespace,
    653         zcu: *Zcu,
    654         name: InternPool.NullTerminatedString,
    655         writer: anytype,
    656     ) @TypeOf(writer).Error!void {
    657         const sep: u8 = if (ns.parent.unwrap()) |parent| sep: {
    658             try zcu.namespacePtr(parent).renderFullyQualifiedDebugName(
    659                 zcu,
    660                 zcu.declPtr(ns.decl_index).name,
    661                 writer,
    662             );
    663             break :sep '.';
    664         } else sep: {
    665             try ns.fileScope(zcu).renderFullyQualifiedDebugName(writer);
    666             break :sep ':';
    667         };
    668         if (name != .empty) try writer.print("{c}{}", .{ sep, name.fmt(&zcu.intern_pool) });
    669     }
    670 
    671     pub fn internFullyQualifiedName(
    672         ns: Namespace,
    673         pt: Zcu.PerThread,
    674         name: InternPool.NullTerminatedString,
    675     ) !InternPool.NullTerminatedString {
    676         const zcu = pt.zcu;
    677         const ip = &zcu.intern_pool;
    678 
    679         const gpa = zcu.gpa;
    680         const strings = ip.getLocal(pt.tid).getMutableStrings(gpa);
    681         // Protects reads of interned strings from being reallocated during the call to
    682         // renderFullyQualifiedName.
    683         const slice = try strings.addManyAsSlice(count: {
    684             var count: usize = name.length(ip) + 1;
    685             var cur_ns = &ns;
    686             while (true) {
    687                 const decl = zcu.declPtr(cur_ns.decl_index);
    688                 cur_ns = zcu.namespacePtr(cur_ns.parent.unwrap() orelse {
    689                     count += ns.fileScope(zcu).fullyQualifiedNameLen();
    690                     break :count count;
    691                 });
    692                 count += decl.name.length(ip) + 1;
    693             }
    694         });
    695         var fbs = std.io.fixedBufferStream(slice[0]);
    696         ns.renderFullyQualifiedName(zcu, name, fbs.writer()) catch unreachable;
    697         assert(fbs.pos == slice[0].len);
    698 
    699         // Sanitize the name for nvptx which is more restrictive.
    700         // TODO This should be handled by the backend, not the frontend. Have a
    701         // look at how the C backend does it for inspiration.
    702         const cpu_arch = zcu.root_mod.resolved_target.result.cpu.arch;
    703         if (cpu_arch.isNvptx()) {
    704             for (slice[0]) |*byte| switch (byte.*) {
    705                 '{', '}', '*', '[', ']', '(', ')', ',', ' ', '\'' => byte.* = '_',
    706                 else => {},
    707             };
    708         }
    709 
    710         return ip.getOrPutTrailingString(gpa, pt.tid, @intCast(slice[0].len), .no_embedded_nulls);
    711     }
    712 
    713     pub fn getType(ns: Namespace, zcu: *Zcu) Type {
    714         const decl = zcu.declPtr(ns.decl_index);
    715         assert(decl.has_tv);
    716         return decl.val.toType();
    717     }
    718 };
    719 
    720 pub const File = struct {
    721     status: enum {
    722         never_loaded,
    723         retryable_failure,
    724         parse_failure,
    725         astgen_failure,
    726         success_zir,
    727     },
    728     source_loaded: bool,
    729     tree_loaded: bool,
    730     zir_loaded: bool,
    731     /// Relative to the owning package's root_src_dir.
    732     /// Memory is stored in gpa, owned by File.
    733     sub_file_path: []const u8,
    734     /// Whether this is populated depends on `source_loaded`.
    735     source: [:0]const u8,
    736     /// Whether this is populated depends on `status`.
    737     stat: Cache.File.Stat,
    738     /// Whether this is populated or not depends on `tree_loaded`.
    739     tree: Ast,
    740     /// Whether this is populated or not depends on `zir_loaded`.
    741     zir: Zir,
    742     /// Module that this file is a part of, managed externally.
    743     mod: *Package.Module,
    744     /// Whether this file is a part of multiple packages. This is an error condition which will be reported after AstGen.
    745     multi_pkg: bool = false,
    746     /// List of references to this file, used for multi-package errors.
    747     references: std.ArrayListUnmanaged(File.Reference) = .{},
    748 
    749     /// The most recent successful ZIR for this file, with no errors.
    750     /// This is only populated when a previously successful ZIR
    751     /// newly introduces compile errors during an update. When ZIR is
    752     /// successful, this field is unloaded.
    753     prev_zir: ?*Zir = null,
    754 
    755     /// A single reference to a file.
    756     pub const Reference = union(enum) {
    757         /// The file is imported directly (i.e. not as a package) with @import.
    758         import: struct {
    759             file: File.Index,
    760             token: Ast.TokenIndex,
    761         },
    762         /// The file is the root of a module.
    763         root: *Package.Module,
    764     };
    765 
    766     pub fn unload(file: *File, gpa: Allocator) void {
    767         file.unloadTree(gpa);
    768         file.unloadSource(gpa);
    769         file.unloadZir(gpa);
    770     }
    771 
    772     pub fn unloadTree(file: *File, gpa: Allocator) void {
    773         if (file.tree_loaded) {
    774             file.tree_loaded = false;
    775             file.tree.deinit(gpa);
    776         }
    777     }
    778 
    779     pub fn unloadSource(file: *File, gpa: Allocator) void {
    780         if (file.source_loaded) {
    781             file.source_loaded = false;
    782             gpa.free(file.source);
    783         }
    784     }
    785 
    786     pub fn unloadZir(file: *File, gpa: Allocator) void {
    787         if (file.zir_loaded) {
    788             file.zir_loaded = false;
    789             file.zir.deinit(gpa);
    790         }
    791     }
    792 
    793     pub const Source = struct {
    794         bytes: [:0]const u8,
    795         stat: Cache.File.Stat,
    796     };
    797 
    798     pub fn getSource(file: *File, gpa: Allocator) !Source {
    799         if (file.source_loaded) return Source{
    800             .bytes = file.source,
    801             .stat = file.stat,
    802         };
    803 
    804         // Keep track of inode, file size, mtime, hash so we can detect which files
    805         // have been modified when an incremental update is requested.
    806         var f = try file.mod.root.openFile(file.sub_file_path, .{});
    807         defer f.close();
    808 
    809         const stat = try f.stat();
    810 
    811         if (stat.size > std.math.maxInt(u32))
    812             return error.FileTooBig;
    813 
    814         const source = try gpa.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);
    815         defer if (!file.source_loaded) gpa.free(source);
    816         const amt = try f.readAll(source);
    817         if (amt != stat.size)
    818             return error.UnexpectedEndOfFile;
    819 
    820         // Here we do not modify stat fields because this function is the one
    821         // used for error reporting. We need to keep the stat fields stale so that
    822         // astGenFile can know to regenerate ZIR.
    823 
    824         file.source = source;
    825         file.source_loaded = true;
    826         return Source{
    827             .bytes = source,
    828             .stat = .{
    829                 .size = stat.size,
    830                 .inode = stat.inode,
    831                 .mtime = stat.mtime,
    832             },
    833         };
    834     }
    835 
    836     pub fn getTree(file: *File, gpa: Allocator) !*const Ast {
    837         if (file.tree_loaded) return &file.tree;
    838 
    839         const source = try file.getSource(gpa);
    840         file.tree = try Ast.parse(gpa, source.bytes, .zig);
    841         file.tree_loaded = true;
    842         return &file.tree;
    843     }
    844 
    845     pub fn fullyQualifiedNameLen(file: File) usize {
    846         const ext = std.fs.path.extension(file.sub_file_path);
    847         return file.sub_file_path.len - ext.len;
    848     }
    849 
    850     pub fn renderFullyQualifiedName(file: File, writer: anytype) !void {
    851         // Convert all the slashes into dots and truncate the extension.
    852         const ext = std.fs.path.extension(file.sub_file_path);
    853         const noext = file.sub_file_path[0 .. file.sub_file_path.len - ext.len];
    854         for (noext) |byte| switch (byte) {
    855             '/', '\\' => try writer.writeByte('.'),
    856             else => try writer.writeByte(byte),
    857         };
    858     }
    859 
    860     pub fn renderFullyQualifiedDebugName(file: File, writer: anytype) !void {
    861         for (file.sub_file_path) |byte| switch (byte) {
    862             '/', '\\' => try writer.writeByte('/'),
    863             else => try writer.writeByte(byte),
    864         };
    865     }
    866 
    867     pub fn internFullyQualifiedName(file: File, pt: Zcu.PerThread) !InternPool.NullTerminatedString {
    868         const gpa = pt.zcu.gpa;
    869         const ip = &pt.zcu.intern_pool;
    870         const strings = ip.getLocal(pt.tid).getMutableStrings(gpa);
    871         const slice = try strings.addManyAsSlice(file.fullyQualifiedNameLen());
    872         var fbs = std.io.fixedBufferStream(slice[0]);
    873         file.renderFullyQualifiedName(fbs.writer()) catch unreachable;
    874         assert(fbs.pos == slice[0].len);
    875         return ip.getOrPutTrailingString(gpa, pt.tid, @intCast(slice[0].len), .no_embedded_nulls);
    876     }
    877 
    878     pub fn fullPath(file: File, ally: Allocator) ![]u8 {
    879         return file.mod.root.joinString(ally, file.sub_file_path);
    880     }
    881 
    882     pub fn dumpSrc(file: *File, src: LazySrcLoc) void {
    883         const loc = std.zig.findLineColumn(file.source.bytes, src);
    884         std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
    885     }
    886 
    887     pub fn okToReportErrors(file: File) bool {
    888         return switch (file.status) {
    889             .parse_failure, .astgen_failure => false,
    890             else => true,
    891         };
    892     }
    893 
    894     /// Add a reference to this file during AstGen.
    895     pub fn addReference(file: *File, zcu: *Zcu, ref: File.Reference) !void {
    896         // Don't add the same module root twice. Note that since we always add module roots at the
    897         // front of the references array (see below), this loop is actually O(1) on valid code.
    898         if (ref == .root) {
    899             for (file.references.items) |other| {
    900                 switch (other) {
    901                     .root => |r| if (ref.root == r) return,
    902                     else => break, // reached the end of the "is-root" references
    903                 }
    904             }
    905         }
    906 
    907         switch (ref) {
    908             // We put root references at the front of the list both to make the above loop fast and
    909             // to make multi-module errors more helpful (since "root-of" notes are generally more
    910             // informative than "imported-from" notes). This path is hit very rarely, so the speed
    911             // of the insert operation doesn't matter too much.
    912             .root => try file.references.insert(zcu.gpa, 0, ref),
    913 
    914             // Other references we'll just put at the end.
    915             else => try file.references.append(zcu.gpa, ref),
    916         }
    917 
    918         const mod = switch (ref) {
    919             .import => |import| zcu.fileByIndex(import.file).mod,
    920             .root => |mod| mod,
    921         };
    922         if (mod != file.mod) file.multi_pkg = true;
    923     }
    924 
    925     /// Mark this file and every file referenced by it as multi_pkg and report an
    926     /// astgen_failure error for them. AstGen must have completed in its entirety.
    927     pub fn recursiveMarkMultiPkg(file: *File, pt: Zcu.PerThread) void {
    928         file.multi_pkg = true;
    929         file.status = .astgen_failure;
    930 
    931         // We can only mark children as failed if the ZIR is loaded, which may not
    932         // be the case if there were other astgen failures in this file
    933         if (!file.zir_loaded) return;
    934 
    935         const imports_index = file.zir.extra[@intFromEnum(Zir.ExtraIndex.imports)];
    936         if (imports_index == 0) return;
    937         const extra = file.zir.extraData(Zir.Inst.Imports, imports_index);
    938 
    939         var extra_index = extra.end;
    940         for (0..extra.data.imports_len) |_| {
    941             const item = file.zir.extraData(Zir.Inst.Imports.Item, extra_index);
    942             extra_index = item.end;
    943 
    944             const import_path = file.zir.nullTerminatedString(item.data.name);
    945             if (mem.eql(u8, import_path, "builtin")) continue;
    946 
    947             const res = pt.importFile(file, import_path) catch continue;
    948             if (!res.is_pkg and !res.file.multi_pkg) {
    949                 res.file.recursiveMarkMultiPkg(pt);
    950             }
    951         }
    952     }
    953 
    954     pub const Index = InternPool.FileIndex;
    955 };
    956 
    957 pub const EmbedFile = struct {
    958     /// Relative to the owning module's root directory.
    959     sub_file_path: InternPool.NullTerminatedString,
    960     /// Module that this file is a part of, managed externally.
    961     owner: *Package.Module,
    962     stat: Cache.File.Stat,
    963     val: InternPool.Index,
    964     src_loc: LazySrcLoc,
    965 };
    966 
    967 /// This struct holds data necessary to construct API-facing `AllErrors.Message`.
    968 /// Its memory is managed with the general purpose allocator so that they
    969 /// can be created and destroyed in response to incremental updates.
    970 pub const ErrorMsg = struct {
    971     src_loc: LazySrcLoc,
    972     msg: []const u8,
    973     notes: []ErrorMsg = &.{},
    974     reference_trace_root: AnalUnit.Optional = .none,
    975 
    976     pub fn create(
    977         gpa: Allocator,
    978         src_loc: LazySrcLoc,
    979         comptime format: []const u8,
    980         args: anytype,
    981     ) !*ErrorMsg {
    982         assert(src_loc.offset != .unneeded);
    983         const err_msg = try gpa.create(ErrorMsg);
    984         errdefer gpa.destroy(err_msg);
    985         err_msg.* = try ErrorMsg.init(gpa, src_loc, format, args);
    986         return err_msg;
    987     }
    988 
    989     /// Assumes the ErrorMsg struct and msg were both allocated with `gpa`,
    990     /// as well as all notes.
    991     pub fn destroy(err_msg: *ErrorMsg, gpa: Allocator) void {
    992         err_msg.deinit(gpa);
    993         gpa.destroy(err_msg);
    994     }
    995 
    996     pub fn init(
    997         gpa: Allocator,
    998         src_loc: LazySrcLoc,
    999         comptime format: []const u8,
   1000         args: anytype,
   1001     ) !ErrorMsg {
   1002         return ErrorMsg{
   1003             .src_loc = src_loc,
   1004             .msg = try std.fmt.allocPrint(gpa, format, args),
   1005         };
   1006     }
   1007 
   1008     pub fn deinit(err_msg: *ErrorMsg, gpa: Allocator) void {
   1009         for (err_msg.notes) |*note| {
   1010             note.deinit(gpa);
   1011         }
   1012         gpa.free(err_msg.notes);
   1013         gpa.free(err_msg.msg);
   1014         err_msg.* = undefined;
   1015     }
   1016 };
   1017 
   1018 /// Canonical reference to a position within a source file.
   1019 pub const SrcLoc = struct {
   1020     file_scope: *File,
   1021     base_node: Ast.Node.Index,
   1022     /// Relative to `base_node`.
   1023     lazy: LazySrcLoc.Offset,
   1024 
   1025     pub fn baseSrcToken(src_loc: SrcLoc) Ast.TokenIndex {
   1026         const tree = src_loc.file_scope.tree;
   1027         return tree.firstToken(src_loc.base_node);
   1028     }
   1029 
   1030     pub fn relativeToNodeIndex(src_loc: SrcLoc, offset: i32) Ast.Node.Index {
   1031         return @bitCast(offset + @as(i32, @bitCast(src_loc.base_node)));
   1032     }
   1033 
   1034     pub const Span = Ast.Span;
   1035 
   1036     pub fn span(src_loc: SrcLoc, gpa: Allocator) !Span {
   1037         switch (src_loc.lazy) {
   1038             .unneeded => unreachable,
   1039             .entire_file => return Span{ .start = 0, .end = 1, .main = 0 },
   1040 
   1041             .byte_abs => |byte_index| return Span{ .start = byte_index, .end = byte_index + 1, .main = byte_index },
   1042 
   1043             .token_abs => |tok_index| {
   1044                 const tree = try src_loc.file_scope.getTree(gpa);
   1045                 const start = tree.tokens.items(.start)[tok_index];
   1046                 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
   1047                 return Span{ .start = start, .end = end, .main = start };
   1048             },
   1049             .node_abs => |node| {
   1050                 const tree = try src_loc.file_scope.getTree(gpa);
   1051                 return tree.nodeToSpan(node);
   1052             },
   1053             .byte_offset => |byte_off| {
   1054                 const tree = try src_loc.file_scope.getTree(gpa);
   1055                 const tok_index = src_loc.baseSrcToken();
   1056                 const start = tree.tokens.items(.start)[tok_index] + byte_off;
   1057                 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
   1058                 return Span{ .start = start, .end = end, .main = start };
   1059             },
   1060             .token_offset => |tok_off| {
   1061                 const tree = try src_loc.file_scope.getTree(gpa);
   1062                 const tok_index = src_loc.baseSrcToken() + tok_off;
   1063                 const start = tree.tokens.items(.start)[tok_index];
   1064                 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
   1065                 return Span{ .start = start, .end = end, .main = start };
   1066             },
   1067             .node_offset => |traced_off| {
   1068                 const node_off = traced_off.x;
   1069                 const tree = try src_loc.file_scope.getTree(gpa);
   1070                 const node = src_loc.relativeToNodeIndex(node_off);
   1071                 assert(src_loc.file_scope.tree_loaded);
   1072                 return tree.nodeToSpan(node);
   1073             },
   1074             .node_offset_main_token => |node_off| {
   1075                 const tree = try src_loc.file_scope.getTree(gpa);
   1076                 const node = src_loc.relativeToNodeIndex(node_off);
   1077                 const main_token = tree.nodes.items(.main_token)[node];
   1078                 return tree.tokensToSpan(main_token, main_token, main_token);
   1079             },
   1080             .node_offset_bin_op => |node_off| {
   1081                 const tree = try src_loc.file_scope.getTree(gpa);
   1082                 const node = src_loc.relativeToNodeIndex(node_off);
   1083                 assert(src_loc.file_scope.tree_loaded);
   1084                 return tree.nodeToSpan(node);
   1085             },
   1086             .node_offset_initializer => |node_off| {
   1087                 const tree = try src_loc.file_scope.getTree(gpa);
   1088                 const node = src_loc.relativeToNodeIndex(node_off);
   1089                 return tree.tokensToSpan(
   1090                     tree.firstToken(node) - 3,
   1091                     tree.lastToken(node),
   1092                     tree.nodes.items(.main_token)[node] - 2,
   1093                 );
   1094             },
   1095             .node_offset_var_decl_ty => |node_off| {
   1096                 const tree = try src_loc.file_scope.getTree(gpa);
   1097                 const node = src_loc.relativeToNodeIndex(node_off);
   1098                 const node_tags = tree.nodes.items(.tag);
   1099                 const full = switch (node_tags[node]) {
   1100                     .global_var_decl,
   1101                     .local_var_decl,
   1102                     .simple_var_decl,
   1103                     .aligned_var_decl,
   1104                     => tree.fullVarDecl(node).?,
   1105                     .@"usingnamespace" => {
   1106                         const node_data = tree.nodes.items(.data);
   1107                         return tree.nodeToSpan(node_data[node].lhs);
   1108                     },
   1109                     else => unreachable,
   1110                 };
   1111                 if (full.ast.type_node != 0) {
   1112                     return tree.nodeToSpan(full.ast.type_node);
   1113                 }
   1114                 const tok_index = full.ast.mut_token + 1; // the name token
   1115                 const start = tree.tokens.items(.start)[tok_index];
   1116                 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
   1117                 return Span{ .start = start, .end = end, .main = start };
   1118             },
   1119             .node_offset_var_decl_align => |node_off| {
   1120                 const tree = try src_loc.file_scope.getTree(gpa);
   1121                 const node = src_loc.relativeToNodeIndex(node_off);
   1122                 const full = tree.fullVarDecl(node).?;
   1123                 return tree.nodeToSpan(full.ast.align_node);
   1124             },
   1125             .node_offset_var_decl_section => |node_off| {
   1126                 const tree = try src_loc.file_scope.getTree(gpa);
   1127                 const node = src_loc.relativeToNodeIndex(node_off);
   1128                 const full = tree.fullVarDecl(node).?;
   1129                 return tree.nodeToSpan(full.ast.section_node);
   1130             },
   1131             .node_offset_var_decl_addrspace => |node_off| {
   1132                 const tree = try src_loc.file_scope.getTree(gpa);
   1133                 const node = src_loc.relativeToNodeIndex(node_off);
   1134                 const full = tree.fullVarDecl(node).?;
   1135                 return tree.nodeToSpan(full.ast.addrspace_node);
   1136             },
   1137             .node_offset_var_decl_init => |node_off| {
   1138                 const tree = try src_loc.file_scope.getTree(gpa);
   1139                 const node = src_loc.relativeToNodeIndex(node_off);
   1140                 const full = tree.fullVarDecl(node).?;
   1141                 return tree.nodeToSpan(full.ast.init_node);
   1142             },
   1143             .node_offset_builtin_call_arg => |builtin_arg| {
   1144                 const tree = try src_loc.file_scope.getTree(gpa);
   1145                 const node_datas = tree.nodes.items(.data);
   1146                 const node_tags = tree.nodes.items(.tag);
   1147                 const node = src_loc.relativeToNodeIndex(builtin_arg.builtin_call_node);
   1148                 const param = switch (node_tags[node]) {
   1149                     .builtin_call_two, .builtin_call_two_comma => switch (builtin_arg.arg_index) {
   1150                         0 => node_datas[node].lhs,
   1151                         1 => node_datas[node].rhs,
   1152                         else => unreachable,
   1153                     },
   1154                     .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + builtin_arg.arg_index],
   1155                     else => unreachable,
   1156                 };
   1157                 return tree.nodeToSpan(param);
   1158             },
   1159             .node_offset_ptrcast_operand => |node_off| {
   1160                 const tree = try src_loc.file_scope.getTree(gpa);
   1161                 const main_tokens = tree.nodes.items(.main_token);
   1162                 const node_datas = tree.nodes.items(.data);
   1163                 const node_tags = tree.nodes.items(.tag);
   1164 
   1165                 var node = src_loc.relativeToNodeIndex(node_off);
   1166                 while (true) {
   1167                     switch (node_tags[node]) {
   1168                         .builtin_call_two, .builtin_call_two_comma => {},
   1169                         else => break,
   1170                     }
   1171 
   1172                     if (node_datas[node].lhs == 0) break; // 0 args
   1173                     if (node_datas[node].rhs != 0) break; // 2 args
   1174 
   1175                     const builtin_token = main_tokens[node];
   1176                     const builtin_name = tree.tokenSlice(builtin_token);
   1177                     const info = BuiltinFn.list.get(builtin_name) orelse break;
   1178 
   1179                     switch (info.tag) {
   1180                         else => break,
   1181                         .ptr_cast,
   1182                         .align_cast,
   1183                         .addrspace_cast,
   1184                         .const_cast,
   1185                         .volatile_cast,
   1186                         => {},
   1187                     }
   1188 
   1189                     node = node_datas[node].lhs;
   1190                 }
   1191 
   1192                 return tree.nodeToSpan(node);
   1193             },
   1194             .node_offset_array_access_index => |node_off| {
   1195                 const tree = try src_loc.file_scope.getTree(gpa);
   1196                 const node_datas = tree.nodes.items(.data);
   1197                 const node = src_loc.relativeToNodeIndex(node_off);
   1198                 return tree.nodeToSpan(node_datas[node].rhs);
   1199             },
   1200             .node_offset_slice_ptr,
   1201             .node_offset_slice_start,
   1202             .node_offset_slice_end,
   1203             .node_offset_slice_sentinel,
   1204             => |node_off| {
   1205                 const tree = try src_loc.file_scope.getTree(gpa);
   1206                 const node = src_loc.relativeToNodeIndex(node_off);
   1207                 const full = tree.fullSlice(node).?;
   1208                 const part_node = switch (src_loc.lazy) {
   1209                     .node_offset_slice_ptr => full.ast.sliced,
   1210                     .node_offset_slice_start => full.ast.start,
   1211                     .node_offset_slice_end => full.ast.end,
   1212                     .node_offset_slice_sentinel => full.ast.sentinel,
   1213                     else => unreachable,
   1214                 };
   1215                 return tree.nodeToSpan(part_node);
   1216             },
   1217             .node_offset_call_func => |node_off| {
   1218                 const tree = try src_loc.file_scope.getTree(gpa);
   1219                 const node = src_loc.relativeToNodeIndex(node_off);
   1220                 var buf: [1]Ast.Node.Index = undefined;
   1221                 const full = tree.fullCall(&buf, node).?;
   1222                 return tree.nodeToSpan(full.ast.fn_expr);
   1223             },
   1224             .node_offset_field_name => |node_off| {
   1225                 const tree = try src_loc.file_scope.getTree(gpa);
   1226                 const node_datas = tree.nodes.items(.data);
   1227                 const node_tags = tree.nodes.items(.tag);
   1228                 const node = src_loc.relativeToNodeIndex(node_off);
   1229                 var buf: [1]Ast.Node.Index = undefined;
   1230                 const tok_index = switch (node_tags[node]) {
   1231                     .field_access => node_datas[node].rhs,
   1232                     .call_one,
   1233                     .call_one_comma,
   1234                     .async_call_one,
   1235                     .async_call_one_comma,
   1236                     .call,
   1237                     .call_comma,
   1238                     .async_call,
   1239                     .async_call_comma,
   1240                     => blk: {
   1241                         const full = tree.fullCall(&buf, node).?;
   1242                         break :blk tree.lastToken(full.ast.fn_expr);
   1243                     },
   1244                     else => tree.firstToken(node) - 2,
   1245                 };
   1246                 const start = tree.tokens.items(.start)[tok_index];
   1247                 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
   1248                 return Span{ .start = start, .end = end, .main = start };
   1249             },
   1250             .node_offset_field_name_init => |node_off| {
   1251                 const tree = try src_loc.file_scope.getTree(gpa);
   1252                 const node = src_loc.relativeToNodeIndex(node_off);
   1253                 const tok_index = tree.firstToken(node) - 2;
   1254                 const start = tree.tokens.items(.start)[tok_index];
   1255                 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
   1256                 return Span{ .start = start, .end = end, .main = start };
   1257             },
   1258             .node_offset_deref_ptr => |node_off| {
   1259                 const tree = try src_loc.file_scope.getTree(gpa);
   1260                 const node = src_loc.relativeToNodeIndex(node_off);
   1261                 return tree.nodeToSpan(node);
   1262             },
   1263             .node_offset_asm_source => |node_off| {
   1264                 const tree = try src_loc.file_scope.getTree(gpa);
   1265                 const node = src_loc.relativeToNodeIndex(node_off);
   1266                 const full = tree.fullAsm(node).?;
   1267                 return tree.nodeToSpan(full.ast.template);
   1268             },
   1269             .node_offset_asm_ret_ty => |node_off| {
   1270                 const tree = try src_loc.file_scope.getTree(gpa);
   1271                 const node = src_loc.relativeToNodeIndex(node_off);
   1272                 const full = tree.fullAsm(node).?;
   1273                 const asm_output = full.outputs[0];
   1274                 const node_datas = tree.nodes.items(.data);
   1275                 return tree.nodeToSpan(node_datas[asm_output].lhs);
   1276             },
   1277 
   1278             .node_offset_if_cond => |node_off| {
   1279                 const tree = try src_loc.file_scope.getTree(gpa);
   1280                 const node = src_loc.relativeToNodeIndex(node_off);
   1281                 const node_tags = tree.nodes.items(.tag);
   1282                 const src_node = switch (node_tags[node]) {
   1283                     .if_simple,
   1284                     .@"if",
   1285                     => tree.fullIf(node).?.ast.cond_expr,
   1286 
   1287                     .while_simple,
   1288                     .while_cont,
   1289                     .@"while",
   1290                     => tree.fullWhile(node).?.ast.cond_expr,
   1291 
   1292                     .for_simple,
   1293                     .@"for",
   1294                     => {
   1295                         const inputs = tree.fullFor(node).?.ast.inputs;
   1296                         const start = tree.firstToken(inputs[0]);
   1297                         const end = tree.lastToken(inputs[inputs.len - 1]);
   1298                         return tree.tokensToSpan(start, end, start);
   1299                     },
   1300 
   1301                     .@"orelse" => node,
   1302                     .@"catch" => node,
   1303                     else => unreachable,
   1304                 };
   1305                 return tree.nodeToSpan(src_node);
   1306             },
   1307             .for_input => |for_input| {
   1308                 const tree = try src_loc.file_scope.getTree(gpa);
   1309                 const node = src_loc.relativeToNodeIndex(for_input.for_node_offset);
   1310                 const for_full = tree.fullFor(node).?;
   1311                 const src_node = for_full.ast.inputs[for_input.input_index];
   1312                 return tree.nodeToSpan(src_node);
   1313             },
   1314             .for_capture_from_input => |node_off| {
   1315                 const tree = try src_loc.file_scope.getTree(gpa);
   1316                 const token_tags = tree.tokens.items(.tag);
   1317                 const input_node = src_loc.relativeToNodeIndex(node_off);
   1318                 // We have to actually linear scan the whole AST to find the for loop
   1319                 // that contains this input.
   1320                 const node_tags = tree.nodes.items(.tag);
   1321                 for (node_tags, 0..) |node_tag, node_usize| {
   1322                     const node = @as(Ast.Node.Index, @intCast(node_usize));
   1323                     switch (node_tag) {
   1324                         .for_simple, .@"for" => {
   1325                             const for_full = tree.fullFor(node).?;
   1326                             for (for_full.ast.inputs, 0..) |input, input_index| {
   1327                                 if (input_node == input) {
   1328                                     var count = input_index;
   1329                                     var tok = for_full.payload_token;
   1330                                     while (true) {
   1331                                         switch (token_tags[tok]) {
   1332                                             .comma => {
   1333                                                 count -= 1;
   1334                                                 tok += 1;
   1335                                             },
   1336                                             .identifier => {
   1337                                                 if (count == 0)
   1338                                                     return tree.tokensToSpan(tok, tok + 1, tok);
   1339                                                 tok += 1;
   1340                                             },
   1341                                             .asterisk => {
   1342                                                 if (count == 0)
   1343                                                     return tree.tokensToSpan(tok, tok + 2, tok);
   1344                                                 tok += 1;
   1345                                             },
   1346                                             else => unreachable,
   1347                                         }
   1348                                     }
   1349                                 }
   1350                             }
   1351                         },
   1352                         else => continue,
   1353                     }
   1354                 } else unreachable;
   1355             },
   1356             .call_arg => |call_arg| {
   1357                 const tree = try src_loc.file_scope.getTree(gpa);
   1358                 const node = src_loc.relativeToNodeIndex(call_arg.call_node_offset);
   1359                 var buf: [2]Ast.Node.Index = undefined;
   1360                 const call_full = tree.fullCall(buf[0..1], node) orelse {
   1361                     const node_tags = tree.nodes.items(.tag);
   1362                     assert(node_tags[node] == .builtin_call);
   1363                     const call_args_node = tree.extra_data[tree.nodes.items(.data)[node].rhs - 1];
   1364                     switch (node_tags[call_args_node]) {
   1365                         .array_init_one,
   1366                         .array_init_one_comma,
   1367                         .array_init_dot_two,
   1368                         .array_init_dot_two_comma,
   1369                         .array_init_dot,
   1370                         .array_init_dot_comma,
   1371                         .array_init,
   1372                         .array_init_comma,
   1373                         => {
   1374                             const full = tree.fullArrayInit(&buf, call_args_node).?.ast.elements;
   1375                             return tree.nodeToSpan(full[call_arg.arg_index]);
   1376                         },
   1377                         .struct_init_one,
   1378                         .struct_init_one_comma,
   1379                         .struct_init_dot_two,
   1380                         .struct_init_dot_two_comma,
   1381                         .struct_init_dot,
   1382                         .struct_init_dot_comma,
   1383                         .struct_init,
   1384                         .struct_init_comma,
   1385                         => {
   1386                             const full = tree.fullStructInit(&buf, call_args_node).?.ast.fields;
   1387                             return tree.nodeToSpan(full[call_arg.arg_index]);
   1388                         },
   1389                         else => return tree.nodeToSpan(call_args_node),
   1390                     }
   1391                 };
   1392                 return tree.nodeToSpan(call_full.ast.params[call_arg.arg_index]);
   1393             },
   1394             .fn_proto_param, .fn_proto_param_type => |fn_proto_param| {
   1395                 const tree = try src_loc.file_scope.getTree(gpa);
   1396                 const node = src_loc.relativeToNodeIndex(fn_proto_param.fn_proto_node_offset);
   1397                 var buf: [1]Ast.Node.Index = undefined;
   1398                 const full = tree.fullFnProto(&buf, node).?;
   1399                 var it = full.iterate(tree);
   1400                 var i: usize = 0;
   1401                 while (it.next()) |param| : (i += 1) {
   1402                     if (i != fn_proto_param.param_index) continue;
   1403 
   1404                     switch (src_loc.lazy) {
   1405                         .fn_proto_param_type => if (param.anytype_ellipsis3) |tok| {
   1406                             return tree.tokenToSpan(tok);
   1407                         } else {
   1408                             return tree.nodeToSpan(param.type_expr);
   1409                         },
   1410                         .fn_proto_param => if (param.anytype_ellipsis3) |tok| {
   1411                             const first = param.comptime_noalias orelse param.name_token orelse tok;
   1412                             return tree.tokensToSpan(first, tok, first);
   1413                         } else {
   1414                             const first = param.comptime_noalias orelse param.name_token orelse tree.firstToken(param.type_expr);
   1415                             return tree.tokensToSpan(first, tree.lastToken(param.type_expr), first);
   1416                         },
   1417                         else => unreachable,
   1418                     }
   1419                 }
   1420                 unreachable;
   1421             },
   1422             .node_offset_bin_lhs => |node_off| {
   1423                 const tree = try src_loc.file_scope.getTree(gpa);
   1424                 const node = src_loc.relativeToNodeIndex(node_off);
   1425                 const node_datas = tree.nodes.items(.data);
   1426                 return tree.nodeToSpan(node_datas[node].lhs);
   1427             },
   1428             .node_offset_bin_rhs => |node_off| {
   1429                 const tree = try src_loc.file_scope.getTree(gpa);
   1430                 const node = src_loc.relativeToNodeIndex(node_off);
   1431                 const node_datas = tree.nodes.items(.data);
   1432                 return tree.nodeToSpan(node_datas[node].rhs);
   1433             },
   1434             .array_cat_lhs, .array_cat_rhs => |cat| {
   1435                 const tree = try src_loc.file_scope.getTree(gpa);
   1436                 const node = src_loc.relativeToNodeIndex(cat.array_cat_offset);
   1437                 const node_datas = tree.nodes.items(.data);
   1438                 const arr_node = if (src_loc.lazy == .array_cat_lhs)
   1439                     node_datas[node].lhs
   1440                 else
   1441                     node_datas[node].rhs;
   1442 
   1443                 const node_tags = tree.nodes.items(.tag);
   1444                 var buf: [2]Ast.Node.Index = undefined;
   1445                 switch (node_tags[arr_node]) {
   1446                     .array_init_one,
   1447                     .array_init_one_comma,
   1448                     .array_init_dot_two,
   1449                     .array_init_dot_two_comma,
   1450                     .array_init_dot,
   1451                     .array_init_dot_comma,
   1452                     .array_init,
   1453                     .array_init_comma,
   1454                     => {
   1455                         const full = tree.fullArrayInit(&buf, arr_node).?.ast.elements;
   1456                         return tree.nodeToSpan(full[cat.elem_index]);
   1457                     },
   1458                     else => return tree.nodeToSpan(arr_node),
   1459                 }
   1460             },
   1461 
   1462             .node_offset_switch_operand => |node_off| {
   1463                 const tree = try src_loc.file_scope.getTree(gpa);
   1464                 const node = src_loc.relativeToNodeIndex(node_off);
   1465                 const node_datas = tree.nodes.items(.data);
   1466                 return tree.nodeToSpan(node_datas[node].lhs);
   1467             },
   1468 
   1469             .node_offset_switch_special_prong => |node_off| {
   1470                 const tree = try src_loc.file_scope.getTree(gpa);
   1471                 const switch_node = src_loc.relativeToNodeIndex(node_off);
   1472                 const node_datas = tree.nodes.items(.data);
   1473                 const node_tags = tree.nodes.items(.tag);
   1474                 const main_tokens = tree.nodes.items(.main_token);
   1475                 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
   1476                 const case_nodes = tree.extra_data[extra.start..extra.end];
   1477                 for (case_nodes) |case_node| {
   1478                     const case = tree.fullSwitchCase(case_node).?;
   1479                     const is_special = (case.ast.values.len == 0) or
   1480                         (case.ast.values.len == 1 and
   1481                         node_tags[case.ast.values[0]] == .identifier and
   1482                         mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"));
   1483                     if (!is_special) continue;
   1484 
   1485                     return tree.nodeToSpan(case_node);
   1486                 } else unreachable;
   1487             },
   1488 
   1489             .node_offset_switch_range => |node_off| {
   1490                 const tree = try src_loc.file_scope.getTree(gpa);
   1491                 const switch_node = src_loc.relativeToNodeIndex(node_off);
   1492                 const node_datas = tree.nodes.items(.data);
   1493                 const node_tags = tree.nodes.items(.tag);
   1494                 const main_tokens = tree.nodes.items(.main_token);
   1495                 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
   1496                 const case_nodes = tree.extra_data[extra.start..extra.end];
   1497                 for (case_nodes) |case_node| {
   1498                     const case = tree.fullSwitchCase(case_node).?;
   1499                     const is_special = (case.ast.values.len == 0) or
   1500                         (case.ast.values.len == 1 and
   1501                         node_tags[case.ast.values[0]] == .identifier and
   1502                         mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"));
   1503                     if (is_special) continue;
   1504 
   1505                     for (case.ast.values) |item_node| {
   1506                         if (node_tags[item_node] == .switch_range) {
   1507                             return tree.nodeToSpan(item_node);
   1508                         }
   1509                     }
   1510                 } else unreachable;
   1511             },
   1512             .node_offset_fn_type_align => |node_off| {
   1513                 const tree = try src_loc.file_scope.getTree(gpa);
   1514                 const node = src_loc.relativeToNodeIndex(node_off);
   1515                 var buf: [1]Ast.Node.Index = undefined;
   1516                 const full = tree.fullFnProto(&buf, node).?;
   1517                 return tree.nodeToSpan(full.ast.align_expr);
   1518             },
   1519             .node_offset_fn_type_addrspace => |node_off| {
   1520                 const tree = try src_loc.file_scope.getTree(gpa);
   1521                 const node = src_loc.relativeToNodeIndex(node_off);
   1522                 var buf: [1]Ast.Node.Index = undefined;
   1523                 const full = tree.fullFnProto(&buf, node).?;
   1524                 return tree.nodeToSpan(full.ast.addrspace_expr);
   1525             },
   1526             .node_offset_fn_type_section => |node_off| {
   1527                 const tree = try src_loc.file_scope.getTree(gpa);
   1528                 const node = src_loc.relativeToNodeIndex(node_off);
   1529                 var buf: [1]Ast.Node.Index = undefined;
   1530                 const full = tree.fullFnProto(&buf, node).?;
   1531                 return tree.nodeToSpan(full.ast.section_expr);
   1532             },
   1533             .node_offset_fn_type_cc => |node_off| {
   1534                 const tree = try src_loc.file_scope.getTree(gpa);
   1535                 const node = src_loc.relativeToNodeIndex(node_off);
   1536                 var buf: [1]Ast.Node.Index = undefined;
   1537                 const full = tree.fullFnProto(&buf, node).?;
   1538                 return tree.nodeToSpan(full.ast.callconv_expr);
   1539             },
   1540 
   1541             .node_offset_fn_type_ret_ty => |node_off| {
   1542                 const tree = try src_loc.file_scope.getTree(gpa);
   1543                 const node = src_loc.relativeToNodeIndex(node_off);
   1544                 var buf: [1]Ast.Node.Index = undefined;
   1545                 const full = tree.fullFnProto(&buf, node).?;
   1546                 return tree.nodeToSpan(full.ast.return_type);
   1547             },
   1548             .node_offset_param => |node_off| {
   1549                 const tree = try src_loc.file_scope.getTree(gpa);
   1550                 const token_tags = tree.tokens.items(.tag);
   1551                 const node = src_loc.relativeToNodeIndex(node_off);
   1552 
   1553                 var first_tok = tree.firstToken(node);
   1554                 while (true) switch (token_tags[first_tok - 1]) {
   1555                     .colon, .identifier, .keyword_comptime, .keyword_noalias => first_tok -= 1,
   1556                     else => break,
   1557                 };
   1558                 return tree.tokensToSpan(
   1559                     first_tok,
   1560                     tree.lastToken(node),
   1561                     first_tok,
   1562                 );
   1563             },
   1564             .token_offset_param => |token_off| {
   1565                 const tree = try src_loc.file_scope.getTree(gpa);
   1566                 const token_tags = tree.tokens.items(.tag);
   1567                 const main_token = tree.nodes.items(.main_token)[src_loc.base_node];
   1568                 const tok_index = @as(Ast.TokenIndex, @bitCast(token_off + @as(i32, @bitCast(main_token))));
   1569 
   1570                 var first_tok = tok_index;
   1571                 while (true) switch (token_tags[first_tok - 1]) {
   1572                     .colon, .identifier, .keyword_comptime, .keyword_noalias => first_tok -= 1,
   1573                     else => break,
   1574                 };
   1575                 return tree.tokensToSpan(
   1576                     first_tok,
   1577                     tok_index,
   1578                     first_tok,
   1579                 );
   1580             },
   1581 
   1582             .node_offset_anyframe_type => |node_off| {
   1583                 const tree = try src_loc.file_scope.getTree(gpa);
   1584                 const node_datas = tree.nodes.items(.data);
   1585                 const parent_node = src_loc.relativeToNodeIndex(node_off);
   1586                 return tree.nodeToSpan(node_datas[parent_node].rhs);
   1587             },
   1588 
   1589             .node_offset_lib_name => |node_off| {
   1590                 const tree = try src_loc.file_scope.getTree(gpa);
   1591                 const parent_node = src_loc.relativeToNodeIndex(node_off);
   1592                 var buf: [1]Ast.Node.Index = undefined;
   1593                 const full = tree.fullFnProto(&buf, parent_node).?;
   1594                 const tok_index = full.lib_name.?;
   1595                 const start = tree.tokens.items(.start)[tok_index];
   1596                 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
   1597                 return Span{ .start = start, .end = end, .main = start };
   1598             },
   1599 
   1600             .node_offset_array_type_len => |node_off| {
   1601                 const tree = try src_loc.file_scope.getTree(gpa);
   1602                 const parent_node = src_loc.relativeToNodeIndex(node_off);
   1603 
   1604                 const full = tree.fullArrayType(parent_node).?;
   1605                 return tree.nodeToSpan(full.ast.elem_count);
   1606             },
   1607             .node_offset_array_type_sentinel => |node_off| {
   1608                 const tree = try src_loc.file_scope.getTree(gpa);
   1609                 const parent_node = src_loc.relativeToNodeIndex(node_off);
   1610 
   1611                 const full = tree.fullArrayType(parent_node).?;
   1612                 return tree.nodeToSpan(full.ast.sentinel);
   1613             },
   1614             .node_offset_array_type_elem => |node_off| {
   1615                 const tree = try src_loc.file_scope.getTree(gpa);
   1616                 const parent_node = src_loc.relativeToNodeIndex(node_off);
   1617 
   1618                 const full = tree.fullArrayType(parent_node).?;
   1619                 return tree.nodeToSpan(full.ast.elem_type);
   1620             },
   1621             .node_offset_un_op => |node_off| {
   1622                 const tree = try src_loc.file_scope.getTree(gpa);
   1623                 const node_datas = tree.nodes.items(.data);
   1624                 const node = src_loc.relativeToNodeIndex(node_off);
   1625 
   1626                 return tree.nodeToSpan(node_datas[node].lhs);
   1627             },
   1628             .node_offset_ptr_elem => |node_off| {
   1629                 const tree = try src_loc.file_scope.getTree(gpa);
   1630                 const parent_node = src_loc.relativeToNodeIndex(node_off);
   1631 
   1632                 const full = tree.fullPtrType(parent_node).?;
   1633                 return tree.nodeToSpan(full.ast.child_type);
   1634             },
   1635             .node_offset_ptr_sentinel => |node_off| {
   1636                 const tree = try src_loc.file_scope.getTree(gpa);
   1637                 const parent_node = src_loc.relativeToNodeIndex(node_off);
   1638 
   1639                 const full = tree.fullPtrType(parent_node).?;
   1640                 return tree.nodeToSpan(full.ast.sentinel);
   1641             },
   1642             .node_offset_ptr_align => |node_off| {
   1643                 const tree = try src_loc.file_scope.getTree(gpa);
   1644                 const parent_node = src_loc.relativeToNodeIndex(node_off);
   1645 
   1646                 const full = tree.fullPtrType(parent_node).?;
   1647                 return tree.nodeToSpan(full.ast.align_node);
   1648             },
   1649             .node_offset_ptr_addrspace => |node_off| {
   1650                 const tree = try src_loc.file_scope.getTree(gpa);
   1651                 const parent_node = src_loc.relativeToNodeIndex(node_off);
   1652 
   1653                 const full = tree.fullPtrType(parent_node).?;
   1654                 return tree.nodeToSpan(full.ast.addrspace_node);
   1655             },
   1656             .node_offset_ptr_bitoffset => |node_off| {
   1657                 const tree = try src_loc.file_scope.getTree(gpa);
   1658                 const parent_node = src_loc.relativeToNodeIndex(node_off);
   1659 
   1660                 const full = tree.fullPtrType(parent_node).?;
   1661                 return tree.nodeToSpan(full.ast.bit_range_start);
   1662             },
   1663             .node_offset_ptr_hostsize => |node_off| {
   1664                 const tree = try src_loc.file_scope.getTree(gpa);
   1665                 const parent_node = src_loc.relativeToNodeIndex(node_off);
   1666 
   1667                 const full = tree.fullPtrType(parent_node).?;
   1668                 return tree.nodeToSpan(full.ast.bit_range_end);
   1669             },
   1670             .node_offset_container_tag => |node_off| {
   1671                 const tree = try src_loc.file_scope.getTree(gpa);
   1672                 const node_tags = tree.nodes.items(.tag);
   1673                 const parent_node = src_loc.relativeToNodeIndex(node_off);
   1674 
   1675                 switch (node_tags[parent_node]) {
   1676                     .container_decl_arg, .container_decl_arg_trailing => {
   1677                         const full = tree.containerDeclArg(parent_node);
   1678                         return tree.nodeToSpan(full.ast.arg);
   1679                     },
   1680                     .tagged_union_enum_tag, .tagged_union_enum_tag_trailing => {
   1681                         const full = tree.taggedUnionEnumTag(parent_node);
   1682 
   1683                         return tree.tokensToSpan(
   1684                             tree.firstToken(full.ast.arg) - 2,
   1685                             tree.lastToken(full.ast.arg) + 1,
   1686                             tree.nodes.items(.main_token)[full.ast.arg],
   1687                         );
   1688                     },
   1689                     else => unreachable,
   1690                 }
   1691             },
   1692             .node_offset_field_default => |node_off| {
   1693                 const tree = try src_loc.file_scope.getTree(gpa);
   1694                 const node_tags = tree.nodes.items(.tag);
   1695                 const parent_node = src_loc.relativeToNodeIndex(node_off);
   1696 
   1697                 const full: Ast.full.ContainerField = switch (node_tags[parent_node]) {
   1698                     .container_field => tree.containerField(parent_node),
   1699                     .container_field_init => tree.containerFieldInit(parent_node),
   1700                     else => unreachable,
   1701                 };
   1702                 return tree.nodeToSpan(full.ast.value_expr);
   1703             },
   1704             .node_offset_init_ty => |node_off| {
   1705                 const tree = try src_loc.file_scope.getTree(gpa);
   1706                 const parent_node = src_loc.relativeToNodeIndex(node_off);
   1707 
   1708                 var buf: [2]Ast.Node.Index = undefined;
   1709                 const type_expr = if (tree.fullArrayInit(&buf, parent_node)) |array_init|
   1710                     array_init.ast.type_expr
   1711                 else
   1712                     tree.fullStructInit(&buf, parent_node).?.ast.type_expr;
   1713                 return tree.nodeToSpan(type_expr);
   1714             },
   1715             .node_offset_store_ptr => |node_off| {
   1716                 const tree = try src_loc.file_scope.getTree(gpa);
   1717                 const node_tags = tree.nodes.items(.tag);
   1718                 const node_datas = tree.nodes.items(.data);
   1719                 const node = src_loc.relativeToNodeIndex(node_off);
   1720 
   1721                 switch (node_tags[node]) {
   1722                     .assign => {
   1723                         return tree.nodeToSpan(node_datas[node].lhs);
   1724                     },
   1725                     else => return tree.nodeToSpan(node),
   1726                 }
   1727             },
   1728             .node_offset_store_operand => |node_off| {
   1729                 const tree = try src_loc.file_scope.getTree(gpa);
   1730                 const node_tags = tree.nodes.items(.tag);
   1731                 const node_datas = tree.nodes.items(.data);
   1732                 const node = src_loc.relativeToNodeIndex(node_off);
   1733 
   1734                 switch (node_tags[node]) {
   1735                     .assign => {
   1736                         return tree.nodeToSpan(node_datas[node].rhs);
   1737                     },
   1738                     else => return tree.nodeToSpan(node),
   1739                 }
   1740             },
   1741             .node_offset_return_operand => |node_off| {
   1742                 const tree = try src_loc.file_scope.getTree(gpa);
   1743                 const node = src_loc.relativeToNodeIndex(node_off);
   1744                 const node_tags = tree.nodes.items(.tag);
   1745                 const node_datas = tree.nodes.items(.data);
   1746                 if (node_tags[node] == .@"return" and node_datas[node].lhs != 0) {
   1747                     return tree.nodeToSpan(node_datas[node].lhs);
   1748                 }
   1749                 return tree.nodeToSpan(node);
   1750             },
   1751             .container_field_name,
   1752             .container_field_value,
   1753             .container_field_type,
   1754             .container_field_align,
   1755             => |field_idx| {
   1756                 const tree = try src_loc.file_scope.getTree(gpa);
   1757                 const node = src_loc.relativeToNodeIndex(0);
   1758                 var buf: [2]Ast.Node.Index = undefined;
   1759                 const container_decl = tree.fullContainerDecl(&buf, node) orelse
   1760                     return tree.nodeToSpan(node);
   1761 
   1762                 var cur_field_idx: usize = 0;
   1763                 for (container_decl.ast.members) |member_node| {
   1764                     const field = tree.fullContainerField(member_node) orelse continue;
   1765                     if (cur_field_idx < field_idx) {
   1766                         cur_field_idx += 1;
   1767                         continue;
   1768                     }
   1769                     const field_component_node = switch (src_loc.lazy) {
   1770                         .container_field_name => 0,
   1771                         .container_field_value => field.ast.value_expr,
   1772                         .container_field_type => field.ast.type_expr,
   1773                         .container_field_align => field.ast.align_expr,
   1774                         else => unreachable,
   1775                     };
   1776                     if (field_component_node == 0) {
   1777                         return tree.tokenToSpan(field.ast.main_token);
   1778                     } else {
   1779                         return tree.nodeToSpan(field_component_node);
   1780                     }
   1781                 } else unreachable;
   1782             },
   1783             .init_elem => |init_elem| {
   1784                 const tree = try src_loc.file_scope.getTree(gpa);
   1785                 const init_node = src_loc.relativeToNodeIndex(init_elem.init_node_offset);
   1786                 var buf: [2]Ast.Node.Index = undefined;
   1787                 if (tree.fullArrayInit(&buf, init_node)) |full| {
   1788                     const elem_node = full.ast.elements[init_elem.elem_index];
   1789                     return tree.nodeToSpan(elem_node);
   1790                 } else if (tree.fullStructInit(&buf, init_node)) |full| {
   1791                     const field_node = full.ast.fields[init_elem.elem_index];
   1792                     return tree.tokensToSpan(
   1793                         tree.firstToken(field_node) - 3,
   1794                         tree.lastToken(field_node),
   1795                         tree.nodes.items(.main_token)[field_node] - 2,
   1796                     );
   1797                 } else unreachable;
   1798             },
   1799             .init_field_name,
   1800             .init_field_linkage,
   1801             .init_field_section,
   1802             .init_field_visibility,
   1803             .init_field_rw,
   1804             .init_field_locality,
   1805             .init_field_cache,
   1806             .init_field_library,
   1807             .init_field_thread_local,
   1808             => |builtin_call_node| {
   1809                 const wanted = switch (src_loc.lazy) {
   1810                     .init_field_name => "name",
   1811                     .init_field_linkage => "linkage",
   1812                     .init_field_section => "section",
   1813                     .init_field_visibility => "visibility",
   1814                     .init_field_rw => "rw",
   1815                     .init_field_locality => "locality",
   1816                     .init_field_cache => "cache",
   1817                     .init_field_library => "library",
   1818                     .init_field_thread_local => "thread_local",
   1819                     else => unreachable,
   1820                 };
   1821                 const tree = try src_loc.file_scope.getTree(gpa);
   1822                 const node_datas = tree.nodes.items(.data);
   1823                 const node_tags = tree.nodes.items(.tag);
   1824                 const node = src_loc.relativeToNodeIndex(builtin_call_node);
   1825                 const arg_node = switch (node_tags[node]) {
   1826                     .builtin_call_two, .builtin_call_two_comma => node_datas[node].rhs,
   1827                     .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + 1],
   1828                     else => unreachable,
   1829                 };
   1830                 var buf: [2]Ast.Node.Index = undefined;
   1831                 const full = tree.fullStructInit(&buf, arg_node) orelse
   1832                     return tree.nodeToSpan(arg_node);
   1833                 for (full.ast.fields) |field_node| {
   1834                     // . IDENTIFIER = field_node
   1835                     const name_token = tree.firstToken(field_node) - 2;
   1836                     const name = tree.tokenSlice(name_token);
   1837                     if (std.mem.eql(u8, name, wanted)) {
   1838                         return tree.tokensToSpan(
   1839                             name_token - 1,
   1840                             tree.lastToken(field_node),
   1841                             tree.nodes.items(.main_token)[field_node] - 2,
   1842                         );
   1843                     }
   1844                 }
   1845                 return tree.nodeToSpan(arg_node);
   1846             },
   1847             .switch_case_item,
   1848             .switch_case_item_range_first,
   1849             .switch_case_item_range_last,
   1850             .switch_capture,
   1851             .switch_tag_capture,
   1852             => {
   1853                 const switch_node_offset, const want_case_idx = switch (src_loc.lazy) {
   1854                     .switch_case_item,
   1855                     .switch_case_item_range_first,
   1856                     .switch_case_item_range_last,
   1857                     => |x| .{ x.switch_node_offset, x.case_idx },
   1858                     .switch_capture,
   1859                     .switch_tag_capture,
   1860                     => |x| .{ x.switch_node_offset, x.case_idx },
   1861                     else => unreachable,
   1862                 };
   1863 
   1864                 const tree = try src_loc.file_scope.getTree(gpa);
   1865                 const node_datas = tree.nodes.items(.data);
   1866                 const node_tags = tree.nodes.items(.tag);
   1867                 const main_tokens = tree.nodes.items(.main_token);
   1868                 const switch_node = src_loc.relativeToNodeIndex(switch_node_offset);
   1869                 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
   1870                 const case_nodes = tree.extra_data[extra.start..extra.end];
   1871 
   1872                 var multi_i: u32 = 0;
   1873                 var scalar_i: u32 = 0;
   1874                 const case = for (case_nodes) |case_node| {
   1875                     const case = tree.fullSwitchCase(case_node).?;
   1876                     const is_special = special: {
   1877                         if (case.ast.values.len == 0) break :special true;
   1878                         if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .identifier) {
   1879                             break :special mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_");
   1880                         }
   1881                         break :special false;
   1882                     };
   1883                     if (is_special) {
   1884                         if (want_case_idx.isSpecial()) {
   1885                             break case;
   1886                         }
   1887                     }
   1888 
   1889                     const is_multi = case.ast.values.len != 1 or
   1890                         node_tags[case.ast.values[0]] == .switch_range;
   1891 
   1892                     if (!want_case_idx.isSpecial()) switch (want_case_idx.kind) {
   1893                         .scalar => if (!is_multi and want_case_idx.index == scalar_i) break case,
   1894                         .multi => if (is_multi and want_case_idx.index == multi_i) break case,
   1895                     };
   1896 
   1897                     if (is_multi) {
   1898                         multi_i += 1;
   1899                     } else {
   1900                         scalar_i += 1;
   1901                     }
   1902                 } else unreachable;
   1903 
   1904                 const want_item = switch (src_loc.lazy) {
   1905                     .switch_case_item,
   1906                     .switch_case_item_range_first,
   1907                     .switch_case_item_range_last,
   1908                     => |x| x.item_idx,
   1909                     .switch_capture, .switch_tag_capture => {
   1910                         const token_tags = tree.tokens.items(.tag);
   1911                         const start = switch (src_loc.lazy) {
   1912                             .switch_capture => case.payload_token.?,
   1913                             .switch_tag_capture => tok: {
   1914                                 var tok = case.payload_token.?;
   1915                                 if (token_tags[tok] == .asterisk) tok += 1;
   1916                                 tok += 2; // skip over comma
   1917                                 break :tok tok;
   1918                             },
   1919                             else => unreachable,
   1920                         };
   1921                         const end = switch (token_tags[start]) {
   1922                             .asterisk => start + 1,
   1923                             else => start,
   1924                         };
   1925                         return tree.tokensToSpan(start, end, start);
   1926                     },
   1927                     else => unreachable,
   1928                 };
   1929 
   1930                 switch (want_item.kind) {
   1931                     .single => {
   1932                         var item_i: u32 = 0;
   1933                         for (case.ast.values) |item_node| {
   1934                             if (node_tags[item_node] == .switch_range) continue;
   1935                             if (item_i != want_item.index) {
   1936                                 item_i += 1;
   1937                                 continue;
   1938                             }
   1939                             return tree.nodeToSpan(item_node);
   1940                         } else unreachable;
   1941                     },
   1942                     .range => {
   1943                         var range_i: u32 = 0;
   1944                         for (case.ast.values) |item_node| {
   1945                             if (node_tags[item_node] != .switch_range) continue;
   1946                             if (range_i != want_item.index) {
   1947                                 range_i += 1;
   1948                                 continue;
   1949                             }
   1950                             return switch (src_loc.lazy) {
   1951                                 .switch_case_item => tree.nodeToSpan(item_node),
   1952                                 .switch_case_item_range_first => tree.nodeToSpan(node_datas[item_node].lhs),
   1953                                 .switch_case_item_range_last => tree.nodeToSpan(node_datas[item_node].rhs),
   1954                                 else => unreachable,
   1955                             };
   1956                         } else unreachable;
   1957                     },
   1958                 }
   1959             },
   1960         }
   1961     }
   1962 };
   1963 
   1964 pub const LazySrcLoc = struct {
   1965     /// This instruction provides the source node locations are resolved relative to.
   1966     /// It is a `declaration`, `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl`.
   1967     /// This must be valid even if `relative` is an absolute value, since it is required to
   1968     /// determine the file which the `LazySrcLoc` refers to.
   1969     base_node_inst: InternPool.TrackedInst.Index,
   1970     /// This field determines the source location relative to `base_node_inst`.
   1971     offset: Offset,
   1972 
   1973     pub const Offset = union(enum) {
   1974         /// When this tag is set, the code that constructed this `LazySrcLoc` is asserting
   1975         /// that all code paths which would need to resolve the source location are
   1976         /// unreachable. If you are debugging this tag incorrectly being this value,
   1977         /// look into using reverse-continue with a memory watchpoint to see where the
   1978         /// value is being set to this tag.
   1979         /// `base_node_inst` is unused.
   1980         unneeded,
   1981         /// Means the source location points to an entire file; not any particular
   1982         /// location within the file. `file_scope` union field will be active.
   1983         entire_file,
   1984         /// The source location points to a byte offset within a source file,
   1985         /// offset from 0. The source file is determined contextually.
   1986         byte_abs: u32,
   1987         /// The source location points to a token within a source file,
   1988         /// offset from 0. The source file is determined contextually.
   1989         token_abs: u32,
   1990         /// The source location points to an AST node within a source file,
   1991         /// offset from 0. The source file is determined contextually.
   1992         node_abs: u32,
   1993         /// The source location points to a byte offset within a source file,
   1994         /// offset from the byte offset of the base node within the file.
   1995         byte_offset: u32,
   1996         /// This data is the offset into the token list from the base node's first token.
   1997         token_offset: u32,
   1998         /// The source location points to an AST node, which is this value offset
   1999         /// from its containing base node AST index.
   2000         node_offset: TracedOffset,
   2001         /// The source location points to the main token of an AST node, found
   2002         /// by taking this AST node index offset from the containing base node.
   2003         node_offset_main_token: i32,
   2004         /// The source location points to the beginning of a struct initializer.
   2005         node_offset_initializer: i32,
   2006         /// The source location points to a variable declaration type expression,
   2007         /// found by taking this AST node index offset from the containing
   2008         /// base node, which points to a variable declaration AST node. Next, navigate
   2009         /// to the type expression.
   2010         node_offset_var_decl_ty: i32,
   2011         /// The source location points to the alignment expression of a var decl.
   2012         node_offset_var_decl_align: i32,
   2013         /// The source location points to the linksection expression of a var decl.
   2014         node_offset_var_decl_section: i32,
   2015         /// The source location points to the addrspace expression of a var decl.
   2016         node_offset_var_decl_addrspace: i32,
   2017         /// The source location points to the initializer of a var decl.
   2018         node_offset_var_decl_init: i32,
   2019         /// The source location points to the given argument of a builtin function call.
   2020         /// `builtin_call_node` points to the builtin call.
   2021         /// `arg_index` is the index of the argument which hte source location refers to.
   2022         node_offset_builtin_call_arg: struct {
   2023             builtin_call_node: i32,
   2024             arg_index: u32,
   2025         },
   2026         /// Like `node_offset_builtin_call_arg` but recurses through arbitrarily many calls
   2027         /// to pointer cast builtins (taking the first argument of the most nested).
   2028         node_offset_ptrcast_operand: i32,
   2029         /// The source location points to the index expression of an array access
   2030         /// expression, found by taking this AST node index offset from the containing
   2031         /// base node, which points to an array access AST node. Next, navigate
   2032         /// to the index expression.
   2033         node_offset_array_access_index: i32,
   2034         /// The source location points to the LHS of a slice expression
   2035         /// expression, found by taking this AST node index offset from the containing
   2036         /// base node, which points to a slice AST node. Next, navigate
   2037         /// to the sentinel expression.
   2038         node_offset_slice_ptr: i32,
   2039         /// The source location points to start expression of a slice expression
   2040         /// expression, found by taking this AST node index offset from the containing
   2041         /// base node, which points to a slice AST node. Next, navigate
   2042         /// to the sentinel expression.
   2043         node_offset_slice_start: i32,
   2044         /// The source location points to the end expression of a slice
   2045         /// expression, found by taking this AST node index offset from the containing
   2046         /// base node, which points to a slice AST node. Next, navigate
   2047         /// to the sentinel expression.
   2048         node_offset_slice_end: i32,
   2049         /// The source location points to the sentinel expression of a slice
   2050         /// expression, found by taking this AST node index offset from the containing
   2051         /// base node, which points to a slice AST node. Next, navigate
   2052         /// to the sentinel expression.
   2053         node_offset_slice_sentinel: i32,
   2054         /// The source location points to the callee expression of a function
   2055         /// call expression, found by taking this AST node index offset from the containing
   2056         /// base node, which points to a function call AST node. Next, navigate
   2057         /// to the callee expression.
   2058         node_offset_call_func: i32,
   2059         /// The payload is offset from the containing base node.
   2060         /// The source location points to the field name of:
   2061         ///  * a field access expression (`a.b`), or
   2062         ///  * the callee of a method call (`a.b()`)
   2063         node_offset_field_name: i32,
   2064         /// The payload is offset from the containing base node.
   2065         /// The source location points to the field name of the operand ("b" node)
   2066         /// of a field initialization expression (`.a = b`)
   2067         node_offset_field_name_init: i32,
   2068         /// The source location points to the pointer of a pointer deref expression,
   2069         /// found by taking this AST node index offset from the containing
   2070         /// base node, which points to a pointer deref AST node. Next, navigate
   2071         /// to the pointer expression.
   2072         node_offset_deref_ptr: i32,
   2073         /// The source location points to the assembly source code of an inline assembly
   2074         /// expression, found by taking this AST node index offset from the containing
   2075         /// base node, which points to inline assembly AST node. Next, navigate
   2076         /// to the asm template source code.
   2077         node_offset_asm_source: i32,
   2078         /// The source location points to the return type of an inline assembly
   2079         /// expression, found by taking this AST node index offset from the containing
   2080         /// base node, which points to inline assembly AST node. Next, navigate
   2081         /// to the return type expression.
   2082         node_offset_asm_ret_ty: i32,
   2083         /// The source location points to the condition expression of an if
   2084         /// expression, found by taking this AST node index offset from the containing
   2085         /// base node, which points to an if expression AST node. Next, navigate
   2086         /// to the condition expression.
   2087         node_offset_if_cond: i32,
   2088         /// The source location points to a binary expression, such as `a + b`, found
   2089         /// by taking this AST node index offset from the containing base node.
   2090         node_offset_bin_op: i32,
   2091         /// The source location points to the LHS of a binary expression, found
   2092         /// by taking this AST node index offset from the containing base node,
   2093         /// which points to a binary expression AST node. Next, navigate to the LHS.
   2094         node_offset_bin_lhs: i32,
   2095         /// The source location points to the RHS of a binary expression, found
   2096         /// by taking this AST node index offset from the containing base node,
   2097         /// which points to a binary expression AST node. Next, navigate to the RHS.
   2098         node_offset_bin_rhs: i32,
   2099         /// The source location points to the operand of a switch expression, found
   2100         /// by taking this AST node index offset from the containing base node,
   2101         /// which points to a switch expression AST node. Next, navigate to the operand.
   2102         node_offset_switch_operand: i32,
   2103         /// The source location points to the else/`_` prong of a switch expression, found
   2104         /// by taking this AST node index offset from the containing base node,
   2105         /// which points to a switch expression AST node. Next, navigate to the else/`_` prong.
   2106         node_offset_switch_special_prong: i32,
   2107         /// The source location points to all the ranges of a switch expression, found
   2108         /// by taking this AST node index offset from the containing base node,
   2109         /// which points to a switch expression AST node. Next, navigate to any of the
   2110         /// range nodes. The error applies to all of them.
   2111         node_offset_switch_range: i32,
   2112         /// The source location points to the align expr of a function type
   2113         /// expression, found by taking this AST node index offset from the containing
   2114         /// base node, which points to a function type AST node. Next, navigate to
   2115         /// the calling convention node.
   2116         node_offset_fn_type_align: i32,
   2117         /// The source location points to the addrspace expr of a function type
   2118         /// expression, found by taking this AST node index offset from the containing
   2119         /// base node, which points to a function type AST node. Next, navigate to
   2120         /// the calling convention node.
   2121         node_offset_fn_type_addrspace: i32,
   2122         /// The source location points to the linksection expr of a function type
   2123         /// expression, found by taking this AST node index offset from the containing
   2124         /// base node, which points to a function type AST node. Next, navigate to
   2125         /// the calling convention node.
   2126         node_offset_fn_type_section: i32,
   2127         /// The source location points to the calling convention of a function type
   2128         /// expression, found by taking this AST node index offset from the containing
   2129         /// base node, which points to a function type AST node. Next, navigate to
   2130         /// the calling convention node.
   2131         node_offset_fn_type_cc: i32,
   2132         /// The source location points to the return type of a function type
   2133         /// expression, found by taking this AST node index offset from the containing
   2134         /// base node, which points to a function type AST node. Next, navigate to
   2135         /// the return type node.
   2136         node_offset_fn_type_ret_ty: i32,
   2137         node_offset_param: i32,
   2138         token_offset_param: i32,
   2139         /// The source location points to the type expression of an `anyframe->T`
   2140         /// expression, found by taking this AST node index offset from the containing
   2141         /// base node, which points to a `anyframe->T` expression AST node. Next, navigate
   2142         /// to the type expression.
   2143         node_offset_anyframe_type: i32,
   2144         /// The source location points to the string literal of `extern "foo"`, found
   2145         /// by taking this AST node index offset from the containing
   2146         /// base node, which points to a function prototype or variable declaration
   2147         /// expression AST node. Next, navigate to the string literal of the `extern "foo"`.
   2148         node_offset_lib_name: i32,
   2149         /// The source location points to the len expression of an `[N:S]T`
   2150         /// expression, found by taking this AST node index offset from the containing
   2151         /// base node, which points to an `[N:S]T` expression AST node. Next, navigate
   2152         /// to the len expression.
   2153         node_offset_array_type_len: i32,
   2154         /// The source location points to the sentinel expression of an `[N:S]T`
   2155         /// expression, found by taking this AST node index offset from the containing
   2156         /// base node, which points to an `[N:S]T` expression AST node. Next, navigate
   2157         /// to the sentinel expression.
   2158         node_offset_array_type_sentinel: i32,
   2159         /// The source location points to the elem expression of an `[N:S]T`
   2160         /// expression, found by taking this AST node index offset from the containing
   2161         /// base node, which points to an `[N:S]T` expression AST node. Next, navigate
   2162         /// to the elem expression.
   2163         node_offset_array_type_elem: i32,
   2164         /// The source location points to the operand of an unary expression.
   2165         node_offset_un_op: i32,
   2166         /// The source location points to the elem type of a pointer.
   2167         node_offset_ptr_elem: i32,
   2168         /// The source location points to the sentinel of a pointer.
   2169         node_offset_ptr_sentinel: i32,
   2170         /// The source location points to the align expr of a pointer.
   2171         node_offset_ptr_align: i32,
   2172         /// The source location points to the addrspace expr of a pointer.
   2173         node_offset_ptr_addrspace: i32,
   2174         /// The source location points to the bit-offset of a pointer.
   2175         node_offset_ptr_bitoffset: i32,
   2176         /// The source location points to the host size of a pointer.
   2177         node_offset_ptr_hostsize: i32,
   2178         /// The source location points to the tag type of an union or an enum.
   2179         node_offset_container_tag: i32,
   2180         /// The source location points to the default value of a field.
   2181         node_offset_field_default: i32,
   2182         /// The source location points to the type of an array or struct initializer.
   2183         node_offset_init_ty: i32,
   2184         /// The source location points to the LHS of an assignment.
   2185         node_offset_store_ptr: i32,
   2186         /// The source location points to the RHS of an assignment.
   2187         node_offset_store_operand: i32,
   2188         /// The source location points to the operand of a `return` statement, or
   2189         /// the `return` itself if there is no explicit operand.
   2190         node_offset_return_operand: i32,
   2191         /// The source location points to a for loop input.
   2192         for_input: struct {
   2193             /// Points to the for loop AST node.
   2194             for_node_offset: i32,
   2195             /// Picks one of the inputs from the condition.
   2196             input_index: u32,
   2197         },
   2198         /// The source location points to one of the captures of a for loop, found
   2199         /// by taking this AST node index offset from the containing
   2200         /// base node, which points to one of the input nodes of a for loop.
   2201         /// Next, navigate to the corresponding capture.
   2202         for_capture_from_input: i32,
   2203         /// The source location points to the argument node of a function call.
   2204         call_arg: struct {
   2205             /// Points to the function call AST node.
   2206             call_node_offset: i32,
   2207             /// The index of the argument the source location points to.
   2208             arg_index: u32,
   2209         },
   2210         fn_proto_param: FnProtoParam,
   2211         fn_proto_param_type: FnProtoParam,
   2212         array_cat_lhs: ArrayCat,
   2213         array_cat_rhs: ArrayCat,
   2214         /// The source location points to the name of the field at the given index
   2215         /// of the container type declaration at the base node.
   2216         container_field_name: u32,
   2217         /// Like `continer_field_name`, but points at the field's default value.
   2218         container_field_value: u32,
   2219         /// Like `continer_field_name`, but points at the field's type.
   2220         container_field_type: u32,
   2221         /// Like `continer_field_name`, but points at the field's alignment.
   2222         container_field_align: u32,
   2223         /// The source location points to the given element/field of a struct or
   2224         /// array initialization expression.
   2225         init_elem: struct {
   2226             /// Points to the AST node of the initialization expression.
   2227             init_node_offset: i32,
   2228             /// The index of the field/element the source location points to.
   2229             elem_index: u32,
   2230         },
   2231         // The following source locations are like `init_elem`, but refer to a
   2232         // field with a specific name. If such a field is not given, the entire
   2233         // initialization expression is used instead.
   2234         // The `i32` points to the AST node of a builtin call, whose *second*
   2235         // argument is the init expression.
   2236         init_field_name: i32,
   2237         init_field_linkage: i32,
   2238         init_field_section: i32,
   2239         init_field_visibility: i32,
   2240         init_field_rw: i32,
   2241         init_field_locality: i32,
   2242         init_field_cache: i32,
   2243         init_field_library: i32,
   2244         init_field_thread_local: i32,
   2245         /// The source location points to the value of an item in a specific
   2246         /// case of a `switch`.
   2247         switch_case_item: SwitchItem,
   2248         /// The source location points to the "first" value of a range item in
   2249         /// a specific case of a `switch`.
   2250         switch_case_item_range_first: SwitchItem,
   2251         /// The source location points to the "last" value of a range item in
   2252         /// a specific case of a `switch`.
   2253         switch_case_item_range_last: SwitchItem,
   2254         /// The source location points to the main capture of a specific case of
   2255         /// a `switch`.
   2256         switch_capture: SwitchCapture,
   2257         /// The source location points to the "tag" capture (second capture) of
   2258         /// a specific case of a `switch`.
   2259         switch_tag_capture: SwitchCapture,
   2260 
   2261         pub const FnProtoParam = struct {
   2262             /// The offset of the function prototype AST node.
   2263             fn_proto_node_offset: i32,
   2264             /// The index of the parameter the source location points to.
   2265             param_index: u32,
   2266         };
   2267 
   2268         pub const SwitchItem = struct {
   2269             /// The offset of the switch AST node.
   2270             switch_node_offset: i32,
   2271             /// The index of the case to point to within this switch.
   2272             case_idx: SwitchCaseIndex,
   2273             /// The index of the item to point to within this case.
   2274             item_idx: SwitchItemIndex,
   2275         };
   2276 
   2277         pub const SwitchCapture = struct {
   2278             /// The offset of the switch AST node.
   2279             switch_node_offset: i32,
   2280             /// The index of the case whose capture to point to.
   2281             case_idx: SwitchCaseIndex,
   2282         };
   2283 
   2284         pub const SwitchCaseIndex = packed struct(u32) {
   2285             kind: enum(u1) { scalar, multi },
   2286             index: u31,
   2287 
   2288             pub const special: SwitchCaseIndex = @bitCast(@as(u32, std.math.maxInt(u32)));
   2289             pub fn isSpecial(idx: SwitchCaseIndex) bool {
   2290                 return @as(u32, @bitCast(idx)) == @as(u32, @bitCast(special));
   2291             }
   2292         };
   2293 
   2294         pub const SwitchItemIndex = packed struct(u32) {
   2295             kind: enum(u1) { single, range },
   2296             index: u31,
   2297         };
   2298 
   2299         const ArrayCat = struct {
   2300             /// Points to the array concat AST node.
   2301             array_cat_offset: i32,
   2302             /// The index of the element the source location points to.
   2303             elem_index: u32,
   2304         };
   2305 
   2306         pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
   2307 
   2308         noinline fn nodeOffsetDebug(node_offset: i32) Offset {
   2309             var result: LazySrcLoc = .{ .node_offset = .{ .x = node_offset } };
   2310             result.node_offset.trace.addAddr(@returnAddress(), "init");
   2311             return result;
   2312         }
   2313 
   2314         fn nodeOffsetRelease(node_offset: i32) Offset {
   2315             return .{ .node_offset = .{ .x = node_offset } };
   2316         }
   2317 
   2318         /// This wraps a simple integer in debug builds so that later on we can find out
   2319         /// where in semantic analysis the value got set.
   2320         pub const TracedOffset = struct {
   2321             x: i32,
   2322             trace: std.debug.Trace = std.debug.Trace.init,
   2323 
   2324             const want_tracing = false;
   2325         };
   2326     };
   2327 
   2328     pub const unneeded: LazySrcLoc = .{
   2329         .base_node_inst = undefined,
   2330         .offset = .unneeded,
   2331     };
   2332 
   2333     pub fn resolveBaseNode(base_node_inst: InternPool.TrackedInst.Index, zcu: *Zcu) struct { *File, Ast.Node.Index } {
   2334         const ip = &zcu.intern_pool;
   2335         const file_index, const zir_inst = inst: {
   2336             const info = base_node_inst.resolveFull(ip);
   2337             break :inst .{ info.file, info.inst };
   2338         };
   2339         const file = zcu.fileByIndex(file_index);
   2340         assert(file.zir_loaded);
   2341 
   2342         const zir = file.zir;
   2343         const inst = zir.instructions.get(@intFromEnum(zir_inst));
   2344         const base_node: Ast.Node.Index = switch (inst.tag) {
   2345             .declaration => inst.data.declaration.src_node,
   2346             .extended => switch (inst.data.extended.opcode) {
   2347                 .struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_node,
   2348                 .union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_node,
   2349                 .enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_node,
   2350                 .opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_node,
   2351                 .reify => zir.extraData(Zir.Inst.Reify, inst.data.extended.operand).data.node,
   2352                 else => unreachable,
   2353             },
   2354             else => unreachable,
   2355         };
   2356         return .{ file, base_node };
   2357     }
   2358 
   2359     /// Resolve the file and AST node of `base_node_inst` to get a resolved `SrcLoc`.
   2360     /// The resulting `SrcLoc` should only be used ephemerally, as it is not correct across incremental updates.
   2361     pub fn upgrade(lazy: LazySrcLoc, zcu: *Zcu) SrcLoc {
   2362         const file, const base_node = resolveBaseNode(lazy.base_node_inst, zcu);
   2363         return .{
   2364             .file_scope = file,
   2365             .base_node = base_node,
   2366             .lazy = lazy.offset,
   2367         };
   2368     }
   2369 };
   2370 
   2371 pub const SemaError = error{ OutOfMemory, AnalysisFail };
   2372 pub const CompileError = error{
   2373     OutOfMemory,
   2374     /// When this is returned, the compile error for the failure has already been recorded.
   2375     AnalysisFail,
   2376     /// A Type or Value was needed to be used during semantic analysis, but it was not available
   2377     /// because the function is generic. This is only seen when analyzing the body of a param
   2378     /// instruction.
   2379     GenericPoison,
   2380     /// In a comptime scope, a return instruction was encountered. This error is only seen when
   2381     /// doing a comptime function call.
   2382     ComptimeReturn,
   2383     /// In a comptime scope, a break instruction was encountered. This error is only seen when
   2384     /// evaluating a comptime block.
   2385     ComptimeBreak,
   2386 };
   2387 
   2388 pub fn init(mod: *Module, thread_count: usize) !void {
   2389     const gpa = mod.gpa;
   2390     try mod.intern_pool.init(gpa, thread_count);
   2391     try mod.global_error_set.put(gpa, .empty, {});
   2392 }
   2393 
   2394 pub fn deinit(zcu: *Zcu) void {
   2395     const pt: Zcu.PerThread = .{ .tid = .main, .zcu = zcu };
   2396     const gpa = zcu.gpa;
   2397 
   2398     if (zcu.llvm_object) |llvm_object| {
   2399         if (build_options.only_c) unreachable;
   2400         llvm_object.deinit();
   2401     }
   2402 
   2403     for (zcu.import_table.keys()) |key| {
   2404         gpa.free(key);
   2405     }
   2406     for (0..zcu.import_table.entries.len) |file_index_usize| {
   2407         const file_index: File.Index = @enumFromInt(file_index_usize);
   2408         pt.destroyFile(file_index);
   2409     }
   2410     zcu.import_table.deinit(gpa);
   2411 
   2412     for (zcu.embed_table.keys(), zcu.embed_table.values()) |path, embed_file| {
   2413         gpa.free(path);
   2414         gpa.destroy(embed_file);
   2415     }
   2416     zcu.embed_table.deinit(gpa);
   2417 
   2418     zcu.compile_log_text.deinit(gpa);
   2419 
   2420     zcu.local_zir_cache.handle.close();
   2421     zcu.global_zir_cache.handle.close();
   2422 
   2423     for (zcu.failed_analysis.values()) |value| {
   2424         value.destroy(gpa);
   2425     }
   2426     zcu.failed_analysis.deinit(gpa);
   2427 
   2428     if (zcu.emit_h) |emit_h| {
   2429         for (emit_h.failed_decls.values()) |value| {
   2430             value.destroy(gpa);
   2431         }
   2432         emit_h.failed_decls.deinit(gpa);
   2433         emit_h.decl_table.deinit(gpa);
   2434         emit_h.allocated_emit_h.deinit(gpa);
   2435     }
   2436 
   2437     for (zcu.failed_files.values()) |value| {
   2438         if (value) |msg| msg.destroy(gpa);
   2439     }
   2440     zcu.failed_files.deinit(gpa);
   2441 
   2442     for (zcu.failed_embed_files.values()) |msg| {
   2443         msg.destroy(gpa);
   2444     }
   2445     zcu.failed_embed_files.deinit(gpa);
   2446 
   2447     for (zcu.failed_exports.values()) |value| {
   2448         value.destroy(gpa);
   2449     }
   2450     zcu.failed_exports.deinit(gpa);
   2451 
   2452     for (zcu.cimport_errors.values()) |*errs| {
   2453         errs.deinit(gpa);
   2454     }
   2455     zcu.cimport_errors.deinit(gpa);
   2456 
   2457     zcu.compile_log_sources.deinit(gpa);
   2458 
   2459     zcu.all_exports.deinit(gpa);
   2460     zcu.free_exports.deinit(gpa);
   2461     zcu.single_exports.deinit(gpa);
   2462     zcu.multi_exports.deinit(gpa);
   2463 
   2464     zcu.global_error_set.deinit(gpa);
   2465 
   2466     zcu.potentially_outdated.deinit(gpa);
   2467     zcu.outdated.deinit(gpa);
   2468     zcu.outdated_ready.deinit(gpa);
   2469     zcu.outdated_file_root.deinit(gpa);
   2470     zcu.retryable_failures.deinit(gpa);
   2471 
   2472     zcu.test_functions.deinit(gpa);
   2473 
   2474     for (zcu.global_assembly.values()) |s| {
   2475         gpa.free(s);
   2476     }
   2477     zcu.global_assembly.deinit(gpa);
   2478 
   2479     zcu.reference_table.deinit(gpa);
   2480     zcu.all_references.deinit(gpa);
   2481     zcu.free_references.deinit(gpa);
   2482 
   2483     zcu.intern_pool.deinit(gpa);
   2484 }
   2485 
   2486 pub fn declPtr(mod: *Module, index: Decl.Index) *Decl {
   2487     return mod.intern_pool.declPtr(index);
   2488 }
   2489 
   2490 pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace {
   2491     return mod.intern_pool.namespacePtr(index);
   2492 }
   2493 
   2494 pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namespace {
   2495     return mod.namespacePtr(index.unwrap() orelse return null);
   2496 }
   2497 
   2498 /// Returns true if and only if the Decl is the top level struct associated with a File.
   2499 pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {
   2500     const decl = mod.declPtr(decl_index);
   2501     const namespace = mod.namespacePtr(decl.src_namespace);
   2502     if (namespace.parent != .none) return false;
   2503     return decl_index == namespace.decl_index;
   2504 }
   2505 
   2506 // TODO https://github.com/ziglang/zig/issues/8643
   2507 pub const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8;
   2508 pub const HackDataLayout = extern struct {
   2509     data: [8]u8 align(@alignOf(Zir.Inst.Data)),
   2510     safety_tag: u8,
   2511 };
   2512 comptime {
   2513     if (data_has_safety_tag) {
   2514         assert(@sizeOf(HackDataLayout) == @sizeOf(Zir.Inst.Data));
   2515     }
   2516 }
   2517 
   2518 pub fn loadZirCache(gpa: Allocator, cache_file: std.fs.File) !Zir {
   2519     return loadZirCacheBody(gpa, try cache_file.reader().readStruct(Zir.Header), cache_file);
   2520 }
   2521 
   2522 pub fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File) !Zir {
   2523     var instructions: std.MultiArrayList(Zir.Inst) = .{};
   2524     errdefer instructions.deinit(gpa);
   2525 
   2526     try instructions.setCapacity(gpa, header.instructions_len);
   2527     instructions.len = header.instructions_len;
   2528 
   2529     var zir: Zir = .{
   2530         .instructions = instructions.toOwnedSlice(),
   2531         .string_bytes = &.{},
   2532         .extra = &.{},
   2533     };
   2534     errdefer zir.deinit(gpa);
   2535 
   2536     zir.string_bytes = try gpa.alloc(u8, header.string_bytes_len);
   2537     zir.extra = try gpa.alloc(u32, header.extra_len);
   2538 
   2539     const safety_buffer = if (data_has_safety_tag)
   2540         try gpa.alloc([8]u8, header.instructions_len)
   2541     else
   2542         undefined;
   2543     defer if (data_has_safety_tag) gpa.free(safety_buffer);
   2544 
   2545     const data_ptr = if (data_has_safety_tag)
   2546         @as([*]u8, @ptrCast(safety_buffer.ptr))
   2547     else
   2548         @as([*]u8, @ptrCast(zir.instructions.items(.data).ptr));
   2549 
   2550     var iovecs = [_]std.posix.iovec{
   2551         .{
   2552             .base = @as([*]u8, @ptrCast(zir.instructions.items(.tag).ptr)),
   2553             .len = header.instructions_len,
   2554         },
   2555         .{
   2556             .base = data_ptr,
   2557             .len = header.instructions_len * 8,
   2558         },
   2559         .{
   2560             .base = zir.string_bytes.ptr,
   2561             .len = header.string_bytes_len,
   2562         },
   2563         .{
   2564             .base = @as([*]u8, @ptrCast(zir.extra.ptr)),
   2565             .len = header.extra_len * 4,
   2566         },
   2567     };
   2568     const amt_read = try cache_file.readvAll(&iovecs);
   2569     const amt_expected = zir.instructions.len * 9 +
   2570         zir.string_bytes.len +
   2571         zir.extra.len * 4;
   2572     if (amt_read != amt_expected) return error.UnexpectedFileSize;
   2573     if (data_has_safety_tag) {
   2574         const tags = zir.instructions.items(.tag);
   2575         for (zir.instructions.items(.data), 0..) |*data, i| {
   2576             const union_tag = Zir.Inst.Tag.data_tags[@intFromEnum(tags[i])];
   2577             const as_struct = @as(*HackDataLayout, @ptrCast(data));
   2578             as_struct.* = .{
   2579                 .safety_tag = @intFromEnum(union_tag),
   2580                 .data = safety_buffer[i],
   2581             };
   2582         }
   2583     }
   2584 
   2585     return zir;
   2586 }
   2587 
   2588 pub fn markDependeeOutdated(zcu: *Zcu, dependee: InternPool.Dependee) !void {
   2589     log.debug("outdated dependee: {}", .{dependee});
   2590     var it = zcu.intern_pool.dependencyIterator(dependee);
   2591     while (it.next()) |depender| {
   2592         if (zcu.outdated.contains(depender)) {
   2593             // We do not need to increment the PO dep count, as if the outdated
   2594             // dependee is a Decl, we had already marked this as PO.
   2595             continue;
   2596         }
   2597         const opt_po_entry = zcu.potentially_outdated.fetchSwapRemove(depender);
   2598         try zcu.outdated.putNoClobber(
   2599             zcu.gpa,
   2600             depender,
   2601             // We do not need to increment this count for the same reason as above.
   2602             if (opt_po_entry) |e| e.value else 0,
   2603         );
   2604         log.debug("outdated: {}", .{depender});
   2605         if (opt_po_entry == null) {
   2606             // This is a new entry with no PO dependencies.
   2607             try zcu.outdated_ready.put(zcu.gpa, depender, {});
   2608         }
   2609         // If this is a Decl and was not previously PO, we must recursively
   2610         // mark dependencies on its tyval as PO.
   2611         if (opt_po_entry == null) {
   2612             try zcu.markTransitiveDependersPotentiallyOutdated(depender);
   2613         }
   2614     }
   2615 }
   2616 
   2617 pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
   2618     var it = zcu.intern_pool.dependencyIterator(dependee);
   2619     while (it.next()) |depender| {
   2620         if (zcu.outdated.getPtr(depender)) |po_dep_count| {
   2621             // This depender is already outdated, but it now has one
   2622             // less PO dependency!
   2623             po_dep_count.* -= 1;
   2624             if (po_dep_count.* == 0) {
   2625                 try zcu.outdated_ready.put(zcu.gpa, depender, {});
   2626             }
   2627             continue;
   2628         }
   2629         // This depender is definitely at least PO, because this Decl was just analyzed
   2630         // due to being outdated.
   2631         const ptr = zcu.potentially_outdated.getPtr(depender).?;
   2632         if (ptr.* > 1) {
   2633             ptr.* -= 1;
   2634             continue;
   2635         }
   2636 
   2637         // This dependency is no longer PO, i.e. is known to be up-to-date.
   2638         assert(zcu.potentially_outdated.swapRemove(depender));
   2639         // If this is a Decl, we must recursively mark dependencies on its tyval
   2640         // as no longer PO.
   2641         switch (depender.unwrap()) {
   2642             .decl => |decl_index| try zcu.markPoDependeeUpToDate(.{ .decl_val = decl_index }),
   2643             .func => |func_index| try zcu.markPoDependeeUpToDate(.{ .func_ies = func_index }),
   2644         }
   2645     }
   2646 }
   2647 
   2648 /// Given a AnalUnit which is newly outdated or PO, mark all AnalUnits which may
   2649 /// in turn be PO, due to a dependency on the original AnalUnit's tyval or IES.
   2650 fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) !void {
   2651     var it = zcu.intern_pool.dependencyIterator(switch (maybe_outdated.unwrap()) {
   2652         .decl => |decl_index| .{ .decl_val = decl_index }, // TODO: also `decl_ref` deps when introduced
   2653         .func => |func_index| .{ .func_ies = func_index },
   2654     });
   2655 
   2656     while (it.next()) |po| {
   2657         if (zcu.outdated.getPtr(po)) |po_dep_count| {
   2658             // This dependency is already outdated, but it now has one more PO
   2659             // dependency.
   2660             if (po_dep_count.* == 0) {
   2661                 _ = zcu.outdated_ready.swapRemove(po);
   2662             }
   2663             po_dep_count.* += 1;
   2664             continue;
   2665         }
   2666         if (zcu.potentially_outdated.getPtr(po)) |n| {
   2667             // There is now one more PO dependency.
   2668             n.* += 1;
   2669             continue;
   2670         }
   2671         try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1);
   2672         // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO.
   2673         try zcu.markTransitiveDependersPotentiallyOutdated(po);
   2674     }
   2675 }
   2676 
   2677 pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
   2678     if (!zcu.comp.debug_incremental) return null;
   2679 
   2680     if (zcu.outdated.count() == 0 and zcu.potentially_outdated.count() == 0) {
   2681         log.debug("findOutdatedToAnalyze: no outdated depender", .{});
   2682         return null;
   2683     }
   2684 
   2685     // Our goal is to find an outdated AnalUnit which itself has no outdated or
   2686     // PO dependencies. Most of the time, such an AnalUnit will exist - we track
   2687     // them in the `outdated_ready` set for efficiency. However, this is not
   2688     // necessarily the case, since the Decl dependency graph may contain loops
   2689     // via mutually recursive definitions:
   2690     //   pub const A = struct { b: *B };
   2691     //   pub const B = struct { b: *A };
   2692     // In this case, we must defer to more complex logic below.
   2693 
   2694     if (zcu.outdated_ready.count() > 0) {
   2695         log.debug("findOutdatedToAnalyze: trivial '{s} {d}'", .{
   2696             @tagName(zcu.outdated_ready.keys()[0].unwrap()),
   2697             switch (zcu.outdated_ready.keys()[0].unwrap()) {
   2698                 inline else => |x| @intFromEnum(x),
   2699             },
   2700         });
   2701         return zcu.outdated_ready.keys()[0];
   2702     }
   2703 
   2704     // Next, we will see if there is any outdated file root which was not in
   2705     // `outdated`. This set will be small (number of files changed in this
   2706     // update), so it's alright for us to just iterate here.
   2707     for (zcu.outdated_file_root.keys()) |file_decl| {
   2708         const decl_depender = AnalUnit.wrap(.{ .decl = file_decl });
   2709         if (zcu.outdated.contains(decl_depender)) {
   2710             // Since we didn't hit this in the first loop, this Decl must have
   2711             // pending dependencies, so is ineligible.
   2712             continue;
   2713         }
   2714         if (zcu.potentially_outdated.contains(decl_depender)) {
   2715             // This Decl's struct may or may not need to be recreated depending
   2716             // on whether it is outdated. If we analyzed it now, we would have
   2717             // to assume it was outdated and recreate it!
   2718             continue;
   2719         }
   2720         log.debug("findOutdatedToAnalyze: outdated file root decl '{d}'", .{file_decl});
   2721         return decl_depender;
   2722     }
   2723 
   2724     // There is no single AnalUnit which is ready for re-analysis. Instead, we
   2725     // must assume that some Decl with PO dependencies is outdated - e.g. in the
   2726     // above example we arbitrarily pick one of A or B. We should select a Decl,
   2727     // since a Decl is definitely responsible for the loop in the dependency
   2728     // graph (since you can't depend on a runtime function analysis!).
   2729 
   2730     // The choice of this Decl could have a big impact on how much total
   2731     // analysis we perform, since if analysis concludes its tyval is unchanged,
   2732     // then other PO AnalUnit may be resolved as up-to-date. To hopefully avoid
   2733     // doing too much work, let's find a Decl which the most things depend on -
   2734     // the idea is that this will resolve a lot of loops (but this is only a
   2735     // heuristic).
   2736 
   2737     log.debug("findOutdatedToAnalyze: no trivial ready, using heuristic; {d} outdated, {d} PO", .{
   2738         zcu.outdated.count(),
   2739         zcu.potentially_outdated.count(),
   2740     });
   2741 
   2742     var chosen_decl_idx: ?Decl.Index = null;
   2743     var chosen_decl_dependers: u32 = undefined;
   2744 
   2745     for (zcu.outdated.keys()) |depender| {
   2746         const decl_index = switch (depender.unwrap()) {
   2747             .decl => |d| d,
   2748             .func => continue,
   2749         };
   2750 
   2751         var n: u32 = 0;
   2752         var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index });
   2753         while (it.next()) |_| n += 1;
   2754 
   2755         if (chosen_decl_idx == null or n > chosen_decl_dependers) {
   2756             chosen_decl_idx = decl_index;
   2757             chosen_decl_dependers = n;
   2758         }
   2759     }
   2760 
   2761     for (zcu.potentially_outdated.keys()) |depender| {
   2762         const decl_index = switch (depender.unwrap()) {
   2763             .decl => |d| d,
   2764             .func => continue,
   2765         };
   2766 
   2767         var n: u32 = 0;
   2768         var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index });
   2769         while (it.next()) |_| n += 1;
   2770 
   2771         if (chosen_decl_idx == null or n > chosen_decl_dependers) {
   2772             chosen_decl_idx = decl_index;
   2773             chosen_decl_dependers = n;
   2774         }
   2775     }
   2776 
   2777     log.debug("findOutdatedToAnalyze: heuristic returned Decl {d} ({d} dependers)", .{
   2778         chosen_decl_idx.?,
   2779         chosen_decl_dependers,
   2780     });
   2781 
   2782     return AnalUnit.wrap(.{ .decl = chosen_decl_idx.? });
   2783 }
   2784 
   2785 /// During an incremental update, before semantic analysis, call this to flush all values from
   2786 /// `retryable_failures` and mark them as outdated so they get re-analyzed.
   2787 pub fn flushRetryableFailures(zcu: *Zcu) !void {
   2788     const gpa = zcu.gpa;
   2789     for (zcu.retryable_failures.items) |depender| {
   2790         if (zcu.outdated.contains(depender)) continue;
   2791         if (zcu.potentially_outdated.fetchSwapRemove(depender)) |kv| {
   2792             // This AnalUnit was already PO, but we now consider it outdated.
   2793             // Any transitive dependencies are already marked PO.
   2794             try zcu.outdated.put(gpa, depender, kv.value);
   2795             continue;
   2796         }
   2797         // This AnalUnit was not marked PO, but is now outdated. Mark it as
   2798         // such, then recursively mark transitive dependencies as PO.
   2799         try zcu.outdated.put(gpa, depender, 0);
   2800         try zcu.markTransitiveDependersPotentiallyOutdated(depender);
   2801     }
   2802     zcu.retryable_failures.clearRetainingCapacity();
   2803 }
   2804 
   2805 pub fn mapOldZirToNew(
   2806     gpa: Allocator,
   2807     old_zir: Zir,
   2808     new_zir: Zir,
   2809     inst_map: *std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index),
   2810 ) Allocator.Error!void {
   2811     // Contain ZIR indexes of namespace declaration instructions, e.g. struct_decl, union_decl, etc.
   2812     // Not `declaration`, as this does not create a namespace.
   2813     const MatchedZirDecl = struct {
   2814         old_inst: Zir.Inst.Index,
   2815         new_inst: Zir.Inst.Index,
   2816     };
   2817     var match_stack: std.ArrayListUnmanaged(MatchedZirDecl) = .{};
   2818     defer match_stack.deinit(gpa);
   2819 
   2820     // Main struct inst is always matched
   2821     try match_stack.append(gpa, .{
   2822         .old_inst = .main_struct_inst,
   2823         .new_inst = .main_struct_inst,
   2824     });
   2825 
   2826     // Used as temporary buffers for namespace declaration instructions
   2827     var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
   2828     defer old_decls.deinit();
   2829     var new_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
   2830     defer new_decls.deinit();
   2831 
   2832     while (match_stack.popOrNull()) |match_item| {
   2833         // Match the namespace declaration itself
   2834         try inst_map.put(gpa, match_item.old_inst, match_item.new_inst);
   2835 
   2836         // Maps decl name to `declaration` instruction.
   2837         var named_decls: std.StringHashMapUnmanaged(Zir.Inst.Index) = .{};
   2838         defer named_decls.deinit(gpa);
   2839         // Maps test name to `declaration` instruction.
   2840         var named_tests: std.StringHashMapUnmanaged(Zir.Inst.Index) = .{};
   2841         defer named_tests.deinit(gpa);
   2842         // All unnamed tests, in order, for a best-effort match.
   2843         var unnamed_tests: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
   2844         defer unnamed_tests.deinit(gpa);
   2845         // All comptime declarations, in order, for a best-effort match.
   2846         var comptime_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
   2847         defer comptime_decls.deinit(gpa);
   2848         // All usingnamespace declarations, in order, for a best-effort match.
   2849         var usingnamespace_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
   2850         defer usingnamespace_decls.deinit(gpa);
   2851 
   2852         {
   2853             var old_decl_it = old_zir.declIterator(match_item.old_inst);
   2854             while (old_decl_it.next()) |old_decl_inst| {
   2855                 const old_decl, _ = old_zir.getDeclaration(old_decl_inst);
   2856                 switch (old_decl.name) {
   2857                     .@"comptime" => try comptime_decls.append(gpa, old_decl_inst),
   2858                     .@"usingnamespace" => try usingnamespace_decls.append(gpa, old_decl_inst),
   2859                     .unnamed_test, .decltest => try unnamed_tests.append(gpa, old_decl_inst),
   2860                     _ => {
   2861                         const name_nts = old_decl.name.toString(old_zir).?;
   2862                         const name = old_zir.nullTerminatedString(name_nts);
   2863                         if (old_decl.name.isNamedTest(old_zir)) {
   2864                             try named_tests.put(gpa, name, old_decl_inst);
   2865                         } else {
   2866                             try named_decls.put(gpa, name, old_decl_inst);
   2867                         }
   2868                     },
   2869                 }
   2870             }
   2871         }
   2872 
   2873         var unnamed_test_idx: u32 = 0;
   2874         var comptime_decl_idx: u32 = 0;
   2875         var usingnamespace_decl_idx: u32 = 0;
   2876 
   2877         var new_decl_it = new_zir.declIterator(match_item.new_inst);
   2878         while (new_decl_it.next()) |new_decl_inst| {
   2879             const new_decl, _ = new_zir.getDeclaration(new_decl_inst);
   2880             // Attempt to match this to a declaration in the old ZIR:
   2881             // * For named declarations (`const`/`var`/`fn`), we match based on name.
   2882             // * For named tests (`test "foo"`), we also match based on name.
   2883             // * For unnamed tests and decltests, we match based on order.
   2884             // * For comptime blocks, we match based on order.
   2885             // * For usingnamespace decls, we match based on order.
   2886             // If we cannot match this declaration, we can't match anything nested inside of it either, so we just `continue`.
   2887             const old_decl_inst = switch (new_decl.name) {
   2888                 .@"comptime" => inst: {
   2889                     if (comptime_decl_idx == comptime_decls.items.len) continue;
   2890                     defer comptime_decl_idx += 1;
   2891                     break :inst comptime_decls.items[comptime_decl_idx];
   2892                 },
   2893                 .@"usingnamespace" => inst: {
   2894                     if (usingnamespace_decl_idx == usingnamespace_decls.items.len) continue;
   2895                     defer usingnamespace_decl_idx += 1;
   2896                     break :inst usingnamespace_decls.items[usingnamespace_decl_idx];
   2897                 },
   2898                 .unnamed_test, .decltest => inst: {
   2899                     if (unnamed_test_idx == unnamed_tests.items.len) continue;
   2900                     defer unnamed_test_idx += 1;
   2901                     break :inst unnamed_tests.items[unnamed_test_idx];
   2902                 },
   2903                 _ => inst: {
   2904                     const name_nts = new_decl.name.toString(old_zir).?;
   2905                     const name = new_zir.nullTerminatedString(name_nts);
   2906                     if (new_decl.name.isNamedTest(new_zir)) {
   2907                         break :inst named_tests.get(name) orelse continue;
   2908                     } else {
   2909                         break :inst named_decls.get(name) orelse continue;
   2910                     }
   2911                 },
   2912             };
   2913 
   2914             // Match the `declaration` instruction
   2915             try inst_map.put(gpa, old_decl_inst, new_decl_inst);
   2916 
   2917             // Find namespace declarations within this declaration
   2918             try old_zir.findDecls(&old_decls, old_decl_inst);
   2919             try new_zir.findDecls(&new_decls, new_decl_inst);
   2920 
   2921             // We don't have any smart way of matching up these namespace declarations, so we always
   2922             // correlate them based on source order.
   2923             const n = @min(old_decls.items.len, new_decls.items.len);
   2924             try match_stack.ensureUnusedCapacity(gpa, n);
   2925             for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {
   2926                 match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
   2927             }
   2928         }
   2929     }
   2930 }
   2931 
   2932 /// Ensure this function's body is or will be analyzed and emitted. This should
   2933 /// be called whenever a potential runtime call of a function is seen.
   2934 ///
   2935 /// The caller is responsible for ensuring the function decl itself is already
   2936 /// analyzed, and for ensuring it can exist at runtime (see
   2937 /// `sema.fnHasRuntimeBits`). This function does *not* guarantee that the body
   2938 /// will be analyzed when it returns: for that, see `ensureFuncBodyAnalyzed`.
   2939 pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index) !void {
   2940     const ip = &mod.intern_pool;
   2941     const func = mod.funcInfo(func_index);
   2942     const decl_index = func.owner_decl;
   2943     const decl = mod.declPtr(decl_index);
   2944 
   2945     switch (decl.analysis) {
   2946         .unreferenced => unreachable,
   2947         .in_progress => unreachable,
   2948 
   2949         .file_failure,
   2950         .sema_failure,
   2951         .codegen_failure,
   2952         .dependency_failure,
   2953         // Analysis of the function Decl itself failed, but we've already
   2954         // emitted an error for that. The callee doesn't need the function to be
   2955         // analyzed right now, so its analysis can safely continue.
   2956         => return,
   2957 
   2958         .complete => {},
   2959     }
   2960 
   2961     assert(decl.has_tv);
   2962 
   2963     const func_as_depender = AnalUnit.wrap(.{ .func = func_index });
   2964     const is_outdated = mod.outdated.contains(func_as_depender) or
   2965         mod.potentially_outdated.contains(func_as_depender);
   2966 
   2967     switch (func.analysis(ip).state) {
   2968         .none => {},
   2969         .queued => return,
   2970         // As above, we don't need to forward errors here.
   2971         .sema_failure,
   2972         .dependency_failure,
   2973         .codegen_failure,
   2974         .success,
   2975         => if (!is_outdated) return,
   2976         .in_progress => return,
   2977         .inline_only => unreachable, // don't queue work for this
   2978     }
   2979 
   2980     // Decl itself is safely analyzed, and body analysis is not yet queued
   2981 
   2982     try mod.comp.work_queue.writeItem(.{ .analyze_func = func_index });
   2983     if (mod.emit_h != null) {
   2984         // TODO: we ideally only want to do this if the function's type changed
   2985         // since the last update
   2986         try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index });
   2987     }
   2988     func.analysis(ip).state = .queued;
   2989 }
   2990 
   2991 pub const SemaDeclResult = packed struct {
   2992     /// Whether the value of a `decl_val` of this Decl changed.
   2993     invalidate_decl_val: bool,
   2994     /// Whether the type of a `decl_ref` of this Decl changed.
   2995     invalidate_decl_ref: bool,
   2996 };
   2997 
   2998 pub const ImportFileResult = struct {
   2999     file: *File,
   3000     file_index: File.Index,
   3001     is_new: bool,
   3002     is_pkg: bool,
   3003 };
   3004 
   3005 pub fn computePathDigest(zcu: *Zcu, mod: *Package.Module, sub_file_path: []const u8) Cache.BinDigest {
   3006     const want_local_cache = mod == zcu.main_mod;
   3007     var path_hash: Cache.HashHelper = .{};
   3008     path_hash.addBytes(build_options.version);
   3009     path_hash.add(builtin.zig_backend);
   3010     if (!want_local_cache) {
   3011         path_hash.addOptionalBytes(mod.root.root_dir.path);
   3012         path_hash.addBytes(mod.root.sub_path);
   3013     }
   3014     path_hash.addBytes(sub_file_path);
   3015     var bin: Cache.BinDigest = undefined;
   3016     path_hash.hasher.final(&bin);
   3017     return bin;
   3018 }
   3019 
   3020 /// Delete all the Export objects that are caused by this `AnalUnit`. Re-analysis of
   3021 /// this `AnalUnit` will cause them to be re-created (or not).
   3022 pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
   3023     const gpa = zcu.gpa;
   3024 
   3025     const exports_base, const exports_len = if (zcu.single_exports.fetchSwapRemove(anal_unit)) |kv|
   3026         .{ kv.value, 1 }
   3027     else if (zcu.multi_exports.fetchSwapRemove(anal_unit)) |info|
   3028         .{ info.value.index, info.value.len }
   3029     else
   3030         return;
   3031 
   3032     const exports = zcu.all_exports.items[exports_base..][0..exports_len];
   3033 
   3034     // In an only-c build, we're guaranteed to never use incremental compilation, so there are
   3035     // guaranteed not to be any exports in the output file that need deleting (since we only call
   3036     // `updateExports` on flush).
   3037     // This case is needed because in some rare edge cases, `Sema` wants to add and delete exports
   3038     // within a single update.
   3039     if (!build_options.only_c) {
   3040         for (exports, exports_base..) |exp, export_idx| {
   3041             if (zcu.comp.bin_file) |lf| {
   3042                 lf.deleteExport(exp.exported, exp.opts.name);
   3043             }
   3044             if (zcu.failed_exports.fetchSwapRemove(@intCast(export_idx))) |failed_kv| {
   3045                 failed_kv.value.destroy(gpa);
   3046             }
   3047         }
   3048     }
   3049 
   3050     zcu.free_exports.ensureUnusedCapacity(gpa, exports_len) catch {
   3051         // This space will be reused eventually, so we need not propagate this error.
   3052         // Just leak it for now, and let GC reclaim it later on.
   3053         return;
   3054     };
   3055     for (exports_base..exports_base + exports_len) |export_idx| {
   3056         zcu.free_exports.appendAssumeCapacity(@intCast(export_idx));
   3057     }
   3058 }
   3059 
   3060 /// Delete all references in `reference_table` which are caused by this `AnalUnit`.
   3061 /// Re-analysis of the `AnalUnit` will cause appropriate references to be recreated.
   3062 pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
   3063     const gpa = zcu.gpa;
   3064 
   3065     const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse return;
   3066     var idx = kv.value;
   3067 
   3068     while (idx != std.math.maxInt(u32)) {
   3069         zcu.free_references.append(gpa, idx) catch {
   3070             // This space will be reused eventually, so we need not propagate this error.
   3071             // Just leak it for now, and let GC reclaim it later on.
   3072             return;
   3073         };
   3074         idx = zcu.all_references.items[idx].next;
   3075     }
   3076 }
   3077 
   3078 pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit, ref_src: LazySrcLoc) Allocator.Error!void {
   3079     const gpa = zcu.gpa;
   3080 
   3081     try zcu.reference_table.ensureUnusedCapacity(gpa, 1);
   3082 
   3083     const ref_idx = zcu.free_references.popOrNull() orelse idx: {
   3084         _ = try zcu.all_references.addOne(gpa);
   3085         break :idx zcu.all_references.items.len - 1;
   3086     };
   3087 
   3088     errdefer comptime unreachable;
   3089 
   3090     const gop = zcu.reference_table.getOrPutAssumeCapacity(src_unit);
   3091 
   3092     zcu.all_references.items[ref_idx] = .{
   3093         .referenced = referenced_unit,
   3094         .next = if (gop.found_existing) gop.value_ptr.* else std.math.maxInt(u32),
   3095         .src = ref_src,
   3096     };
   3097 
   3098     gop.value_ptr.* = @intCast(ref_idx);
   3099 }
   3100 
   3101 pub fn getErrorValue(
   3102     mod: *Module,
   3103     name: InternPool.NullTerminatedString,
   3104 ) Allocator.Error!ErrorInt {
   3105     const gop = try mod.global_error_set.getOrPut(mod.gpa, name);
   3106     return @as(ErrorInt, @intCast(gop.index));
   3107 }
   3108 
   3109 pub fn getErrorValueFromSlice(
   3110     mod: *Module,
   3111     name: []const u8,
   3112 ) Allocator.Error!ErrorInt {
   3113     const interned_name = try mod.intern_pool.getOrPutString(mod.gpa, name);
   3114     return getErrorValue(mod, interned_name);
   3115 }
   3116 
   3117 pub fn errorSetBits(mod: *Module) u16 {
   3118     if (mod.error_limit == 0) return 0;
   3119     return std.math.log2_int_ceil(ErrorInt, mod.error_limit + 1); // +1 for no error
   3120 }
   3121 
   3122 pub fn errNote(
   3123     mod: *Module,
   3124     src_loc: LazySrcLoc,
   3125     parent: *ErrorMsg,
   3126     comptime format: []const u8,
   3127     args: anytype,
   3128 ) error{OutOfMemory}!void {
   3129     const msg = try std.fmt.allocPrint(mod.gpa, format, args);
   3130     errdefer mod.gpa.free(msg);
   3131 
   3132     parent.notes = try mod.gpa.realloc(parent.notes, parent.notes.len + 1);
   3133     parent.notes[parent.notes.len - 1] = .{
   3134         .src_loc = src_loc,
   3135         .msg = msg,
   3136     };
   3137 }
   3138 
   3139 /// Deprecated. There is no global target for a Zig Compilation Unit. Instead,
   3140 /// look up the target based on the Module that contains the source code being
   3141 /// analyzed.
   3142 pub fn getTarget(zcu: Module) Target {
   3143     return zcu.root_mod.resolved_target.result;
   3144 }
   3145 
   3146 /// Deprecated. There is no global optimization mode for a Zig Compilation
   3147 /// Unit. Instead, look up the optimization mode based on the Module that
   3148 /// contains the source code being analyzed.
   3149 pub fn optimizeMode(zcu: Module) std.builtin.OptimizeMode {
   3150     return zcu.root_mod.optimize_mode;
   3151 }
   3152 
   3153 fn lockAndClearFileCompileError(mod: *Module, file: *File) void {
   3154     switch (file.status) {
   3155         .success_zir, .retryable_failure => {},
   3156         .never_loaded, .parse_failure, .astgen_failure => {
   3157             mod.comp.mutex.lock();
   3158             defer mod.comp.mutex.unlock();
   3159             if (mod.failed_files.fetchSwapRemove(file)) |kv| {
   3160                 if (kv.value) |msg| msg.destroy(mod.gpa); // Delete previous error message.
   3161             }
   3162         },
   3163     }
   3164 }
   3165 
   3166 pub fn handleUpdateExports(
   3167     zcu: *Zcu,
   3168     export_indices: []const u32,
   3169     result: link.File.UpdateExportsError!void,
   3170 ) Allocator.Error!void {
   3171     const gpa = zcu.gpa;
   3172     result catch |err| switch (err) {
   3173         error.OutOfMemory => return error.OutOfMemory,
   3174         error.AnalysisFail => {
   3175             const export_idx = export_indices[0];
   3176             const new_export = &zcu.all_exports.items[export_idx];
   3177             new_export.status = .failed_retryable;
   3178             try zcu.failed_exports.ensureUnusedCapacity(gpa, 1);
   3179             const msg = try ErrorMsg.create(gpa, new_export.src, "unable to export: {s}", .{
   3180                 @errorName(err),
   3181             });
   3182             zcu.failed_exports.putAssumeCapacityNoClobber(export_idx, msg);
   3183         },
   3184     };
   3185 }
   3186 
   3187 pub fn reportRetryableFileError(
   3188     zcu: *Zcu,
   3189     file_index: File.Index,
   3190     comptime format: []const u8,
   3191     args: anytype,
   3192 ) error{OutOfMemory}!void {
   3193     const gpa = zcu.gpa;
   3194     const ip = &zcu.intern_pool;
   3195 
   3196     const file = zcu.fileByIndex(file_index);
   3197     file.status = .retryable_failure;
   3198 
   3199     const err_msg = try ErrorMsg.create(
   3200         gpa,
   3201         .{
   3202             .base_node_inst = try ip.trackZir(gpa, file_index, .main_struct_inst),
   3203             .offset = .entire_file,
   3204         },
   3205         format,
   3206         args,
   3207     );
   3208     errdefer err_msg.destroy(gpa);
   3209 
   3210     zcu.comp.mutex.lock();
   3211     defer zcu.comp.mutex.unlock();
   3212 
   3213     const gop = try zcu.failed_files.getOrPut(gpa, file);
   3214     if (gop.found_existing) {
   3215         if (gop.value_ptr.*) |old_err_msg| {
   3216             old_err_msg.destroy(gpa);
   3217         }
   3218     }
   3219     gop.value_ptr.* = err_msg;
   3220 }
   3221 
   3222 pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u8) !void {
   3223     const gop = try mod.global_assembly.getOrPut(mod.gpa, decl_index);
   3224     if (gop.found_existing) {
   3225         const new_value = try std.fmt.allocPrint(mod.gpa, "{s}\n{s}", .{ gop.value_ptr.*, source });
   3226         mod.gpa.free(gop.value_ptr.*);
   3227         gop.value_ptr.* = new_value;
   3228     } else {
   3229         gop.value_ptr.* = try mod.gpa.dupe(u8, source);
   3230     }
   3231 }
   3232 
   3233 pub const Feature = enum {
   3234     panic_fn,
   3235     panic_unwrap_error,
   3236     safety_check_formatted,
   3237     error_return_trace,
   3238     is_named_enum_value,
   3239     error_set_has_value,
   3240     field_reordering,
   3241     /// When this feature is supported, the backend supports the following AIR instructions:
   3242     /// * `Air.Inst.Tag.add_safe`
   3243     /// * `Air.Inst.Tag.sub_safe`
   3244     /// * `Air.Inst.Tag.mul_safe`
   3245     /// The motivation for this feature is that it makes AIR smaller, and makes it easier
   3246     /// to generate better machine code in the backends. All backends should migrate to
   3247     /// enabling this feature.
   3248     safety_checked_instructions,
   3249     /// If the backend supports running from another thread.
   3250     separate_thread,
   3251 };
   3252 
   3253 pub fn backendSupportsFeature(zcu: Module, comptime feature: Feature) bool {
   3254     const backend = target_util.zigBackend(zcu.root_mod.resolved_target.result, zcu.comp.config.use_llvm);
   3255     return target_util.backendSupportsFeature(backend, feature);
   3256 }
   3257 
   3258 pub const AtomicPtrAlignmentError = error{
   3259     FloatTooBig,
   3260     IntTooBig,
   3261     BadType,
   3262     OutOfMemory,
   3263 };
   3264 
   3265 pub const AtomicPtrAlignmentDiagnostics = struct {
   3266     bits: u16 = undefined,
   3267     max_bits: u16 = undefined,
   3268 };
   3269 
   3270 /// If ABI alignment of `ty` is OK for atomic operations, returns 0.
   3271 /// Otherwise returns the alignment required on a pointer for the target
   3272 /// to perform atomic operations.
   3273 // TODO this function does not take into account CPU features, which can affect
   3274 // this value. Audit this!
   3275 pub fn atomicPtrAlignment(
   3276     mod: *Module,
   3277     ty: Type,
   3278     diags: *AtomicPtrAlignmentDiagnostics,
   3279 ) AtomicPtrAlignmentError!Alignment {
   3280     const target = mod.getTarget();
   3281     const max_atomic_bits: u16 = switch (target.cpu.arch) {
   3282         .avr,
   3283         .msp430,
   3284         .spu_2,
   3285         => 16,
   3286 
   3287         .arc,
   3288         .arm,
   3289         .armeb,
   3290         .hexagon,
   3291         .m68k,
   3292         .le32,
   3293         .mips,
   3294         .mipsel,
   3295         .nvptx,
   3296         .powerpc,
   3297         .powerpcle,
   3298         .r600,
   3299         .riscv32,
   3300         .sparc,
   3301         .sparcel,
   3302         .tce,
   3303         .tcele,
   3304         .thumb,
   3305         .thumbeb,
   3306         .x86,
   3307         .xcore,
   3308         .amdil,
   3309         .hsail,
   3310         .spir,
   3311         .kalimba,
   3312         .lanai,
   3313         .shave,
   3314         .wasm32,
   3315         .renderscript32,
   3316         .csky,
   3317         .spirv32,
   3318         .dxil,
   3319         .loongarch32,
   3320         .xtensa,
   3321         => 32,
   3322 
   3323         .amdgcn,
   3324         .bpfel,
   3325         .bpfeb,
   3326         .le64,
   3327         .mips64,
   3328         .mips64el,
   3329         .nvptx64,
   3330         .powerpc64,
   3331         .powerpc64le,
   3332         .riscv64,
   3333         .sparc64,
   3334         .s390x,
   3335         .amdil64,
   3336         .hsail64,
   3337         .spir64,
   3338         .wasm64,
   3339         .renderscript64,
   3340         .ve,
   3341         .spirv64,
   3342         .loongarch64,
   3343         => 64,
   3344 
   3345         .aarch64,
   3346         .aarch64_be,
   3347         .aarch64_32,
   3348         => 128,
   3349 
   3350         .x86_64 => if (std.Target.x86.featureSetHas(target.cpu.features, .cx16)) 128 else 64,
   3351 
   3352         .spirv => @panic("TODO what should this value be?"),
   3353     };
   3354 
   3355     const int_ty = switch (ty.zigTypeTag(mod)) {
   3356         .Int => ty,
   3357         .Enum => ty.intTagType(mod),
   3358         .Float => {
   3359             const bit_count = ty.floatBits(target);
   3360             if (bit_count > max_atomic_bits) {
   3361                 diags.* = .{
   3362                     .bits = bit_count,
   3363                     .max_bits = max_atomic_bits,
   3364                 };
   3365                 return error.FloatTooBig;
   3366             }
   3367             return .none;
   3368         },
   3369         .Bool => return .none,
   3370         else => {
   3371             if (ty.isPtrAtRuntime(mod)) return .none;
   3372             return error.BadType;
   3373         },
   3374     };
   3375 
   3376     const bit_count = int_ty.intInfo(mod).bits;
   3377     if (bit_count > max_atomic_bits) {
   3378         diags.* = .{
   3379             .bits = bit_count,
   3380             .max_bits = max_atomic_bits,
   3381         };
   3382         return error.IntTooBig;
   3383     }
   3384 
   3385     return .none;
   3386 }
   3387 
   3388 pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {
   3389     return mod.declPtr(decl_index).getFileScope(mod);
   3390 }
   3391 
   3392 /// Returns null in the following cases:
   3393 /// * `@TypeOf(.{})`
   3394 /// * A struct which has no fields (`struct {}`).
   3395 /// * Not a struct.
   3396 pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType {
   3397     if (ty.ip_index == .none) return null;
   3398     const ip = &mod.intern_pool;
   3399     return switch (ip.indexToKey(ty.ip_index)) {
   3400         .struct_type => ip.loadStructType(ty.ip_index),
   3401         else => null,
   3402     };
   3403 }
   3404 
   3405 pub fn typeToPackedStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType {
   3406     const s = mod.typeToStruct(ty) orelse return null;
   3407     if (s.layout != .@"packed") return null;
   3408     return s;
   3409 }
   3410 
   3411 pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.LoadedUnionType {
   3412     if (ty.ip_index == .none) return null;
   3413     const ip = &mod.intern_pool;
   3414     return switch (ip.indexToKey(ty.ip_index)) {
   3415         .union_type => ip.loadUnionType(ty.ip_index),
   3416         else => null,
   3417     };
   3418 }
   3419 
   3420 pub fn typeToFunc(mod: *Module, ty: Type) ?InternPool.Key.FuncType {
   3421     if (ty.ip_index == .none) return null;
   3422     return mod.intern_pool.indexToFuncType(ty.toIntern());
   3423 }
   3424 
   3425 pub fn funcOwnerDeclPtr(mod: *Module, func_index: InternPool.Index) *Decl {
   3426     return mod.declPtr(mod.funcOwnerDeclIndex(func_index));
   3427 }
   3428 
   3429 pub fn funcOwnerDeclIndex(mod: *Module, func_index: InternPool.Index) Decl.Index {
   3430     return mod.funcInfo(func_index).owner_decl;
   3431 }
   3432 
   3433 pub fn iesFuncIndex(mod: *const Module, ies_index: InternPool.Index) InternPool.Index {
   3434     return mod.intern_pool.iesFuncIndex(ies_index);
   3435 }
   3436 
   3437 pub fn funcInfo(mod: *Module, func_index: InternPool.Index) InternPool.Key.Func {
   3438     return mod.intern_pool.indexToKey(func_index).func;
   3439 }
   3440 
   3441 pub fn toEnum(mod: *Module, comptime E: type, val: Value) E {
   3442     return mod.intern_pool.toEnum(E, val.toIntern());
   3443 }
   3444 
   3445 pub fn isAnytypeParam(mod: *Module, func: InternPool.Index, index: u32) bool {
   3446     const file = mod.declPtr(func.owner_decl).getFileScope(mod);
   3447 
   3448     const tags = file.zir.instructions.items(.tag);
   3449 
   3450     const param_body = file.zir.getParamBody(func.zir_body_inst);
   3451     const param = param_body[index];
   3452 
   3453     return switch (tags[param]) {
   3454         .param, .param_comptime => false,
   3455         .param_anytype, .param_anytype_comptime => true,
   3456         else => unreachable,
   3457     };
   3458 }
   3459 
   3460 pub fn getParamName(mod: *Module, func_index: InternPool.Index, index: u32) [:0]const u8 {
   3461     const func = mod.funcInfo(func_index);
   3462     const file = mod.declPtr(func.owner_decl).getFileScope(mod);
   3463 
   3464     const tags = file.zir.instructions.items(.tag);
   3465     const data = file.zir.instructions.items(.data);
   3466 
   3467     const param_body = file.zir.getParamBody(func.zir_body_inst.resolve(&mod.intern_pool));
   3468     const param = param_body[index];
   3469 
   3470     return switch (tags[@intFromEnum(param)]) {
   3471         .param, .param_comptime => blk: {
   3472             const extra = file.zir.extraData(Zir.Inst.Param, data[@intFromEnum(param)].pl_tok.payload_index);
   3473             break :blk file.zir.nullTerminatedString(extra.data.name);
   3474         },
   3475         .param_anytype, .param_anytype_comptime => blk: {
   3476             const param_data = data[@intFromEnum(param)].str_tok;
   3477             break :blk param_data.get(file.zir);
   3478         },
   3479         else => unreachable,
   3480     };
   3481 }
   3482 
   3483 pub const UnionLayout = struct {
   3484     abi_size: u64,
   3485     abi_align: Alignment,
   3486     most_aligned_field: u32,
   3487     most_aligned_field_size: u64,
   3488     biggest_field: u32,
   3489     payload_size: u64,
   3490     payload_align: Alignment,
   3491     tag_align: Alignment,
   3492     tag_size: u64,
   3493     padding: u32,
   3494 };
   3495 
   3496 /// Returns the index of the active field, given the current tag value
   3497 pub fn unionTagFieldIndex(mod: *Module, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 {
   3498     const ip = &mod.intern_pool;
   3499     if (enum_tag.toIntern() == .none) return null;
   3500     assert(ip.typeOf(enum_tag.toIntern()) == loaded_union.enum_tag_ty);
   3501     return loaded_union.loadTagType(ip).tagValueIndex(ip, enum_tag.toIntern());
   3502 }
   3503 
   3504 pub const ResolvedReference = struct {
   3505     referencer: AnalUnit,
   3506     src: LazySrcLoc,
   3507 };
   3508 
   3509 /// Returns a mapping from an `AnalUnit` to where it is referenced.
   3510 /// TODO: in future, this must be adapted to traverse from roots of analysis. That way, we can
   3511 /// use the returned map to determine which units have become unreferenced in an incremental update.
   3512 pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ResolvedReference) {
   3513     const gpa = zcu.gpa;
   3514 
   3515     var result: std.AutoHashMapUnmanaged(AnalUnit, ResolvedReference) = .{};
   3516     errdefer result.deinit(gpa);
   3517 
   3518     // This is not a sufficient size, but a lower bound.
   3519     try result.ensureTotalCapacity(gpa, @intCast(zcu.reference_table.count()));
   3520 
   3521     for (zcu.reference_table.keys(), zcu.reference_table.values()) |referencer, first_ref_idx| {
   3522         assert(first_ref_idx != std.math.maxInt(u32));
   3523         var ref_idx = first_ref_idx;
   3524         while (ref_idx != std.math.maxInt(u32)) {
   3525             const ref = zcu.all_references.items[ref_idx];
   3526             const gop = try result.getOrPut(gpa, ref.referenced);
   3527             if (!gop.found_existing) {
   3528                 gop.value_ptr.* = .{ .referencer = referencer, .src = ref.src };
   3529             }
   3530             ref_idx = ref.next;
   3531         }
   3532     }
   3533 
   3534     return result;
   3535 }
   3536 
   3537 pub fn fileByIndex(zcu: *Zcu, i: File.Index) *File {
   3538     const ip = &zcu.intern_pool;
   3539     return ip.filePtr(i);
   3540 }
   3541 
   3542 /// Returns the `Decl` of the struct that represents this `File`.
   3543 pub fn fileRootDecl(zcu: *const Zcu, i: File.Index) Decl.OptionalIndex {
   3544     const ip = &zcu.intern_pool;
   3545     return ip.files.values()[@intFromEnum(i)];
   3546 }
   3547 
   3548 pub fn setFileRootDecl(zcu: *Zcu, i: File.Index, root_decl: Decl.OptionalIndex) void {
   3549     const ip = &zcu.intern_pool;
   3550     ip.files.values()[@intFromEnum(i)] = root_decl;
   3551 }
   3552 
   3553 pub fn filePathDigest(zcu: *const Zcu, i: File.Index) Cache.BinDigest {
   3554     const ip = &zcu.intern_pool;
   3555     return ip.files.keys()[@intFromEnum(i)];
   3556 }