zig

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

blob bdf20649 (234527B) - Raw


      1 //! Compilation of all Zig source code is represented by one `Module`.
      2 //! Each `Compilation` has exactly one or zero `Module`, depending on whether
      3 //! there is or is not any zig source code, respectively.
      4 
      5 const std = @import("std");
      6 const builtin = @import("builtin");
      7 const mem = std.mem;
      8 const Allocator = std.mem.Allocator;
      9 const ArrayListUnmanaged = std.ArrayListUnmanaged;
     10 const assert = std.debug.assert;
     11 const log = std.log.scoped(.module);
     12 const BigIntConst = std.math.big.int.Const;
     13 const BigIntMutable = std.math.big.int.Mutable;
     14 const Target = std.Target;
     15 const Ast = std.zig.Ast;
     16 
     17 const Module = @This();
     18 const Compilation = @import("Compilation.zig");
     19 const Cache = @import("Cache.zig");
     20 const Value = @import("value.zig").Value;
     21 const Type = @import("type.zig").Type;
     22 const TypedValue = @import("TypedValue.zig");
     23 const Package = @import("Package.zig");
     24 const link = @import("link.zig");
     25 const Air = @import("Air.zig");
     26 const Zir = @import("Zir.zig");
     27 const trace = @import("tracy.zig").trace;
     28 const AstGen = @import("AstGen.zig");
     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 
     34 /// General-purpose allocator. Used for both temporary and long-term storage.
     35 gpa: Allocator,
     36 comp: *Compilation,
     37 
     38 /// Where build artifacts and incremental compilation metadata serialization go.
     39 zig_cache_artifact_directory: Compilation.Directory,
     40 /// Pointer to externally managed resource.
     41 root_pkg: *Package,
     42 /// Normally, `main_pkg` and `root_pkg` are the same. The exception is `zig test`, in which
     43 /// `root_pkg` is the test runner, and `main_pkg` is the user's source file which has the tests.
     44 main_pkg: *Package,
     45 sema_prog_node: std.Progress.Node = undefined,
     46 
     47 /// Used by AstGen worker to load and store ZIR cache.
     48 global_zir_cache: Compilation.Directory,
     49 /// Used by AstGen worker to load and store ZIR cache.
     50 local_zir_cache: Compilation.Directory,
     51 /// It's rare for a decl to be exported, so we save memory by having a sparse
     52 /// map of Decl indexes to details about them being exported.
     53 /// The Export memory is owned by the `export_owners` table; the slice itself
     54 /// is owned by this table. The slice is guaranteed to not be empty.
     55 decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, []*Export) = .{},
     56 /// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl
     57 /// is modified. Note that the key of this table is not the Decl being exported, but the Decl that
     58 /// is performing the export of another Decl.
     59 /// This table owns the Export memory.
     60 export_owners: std.AutoArrayHashMapUnmanaged(Decl.Index, []*Export) = .{},
     61 /// The set of all the Zig source files in the Module. We keep track of this in order
     62 /// to iterate over it and check which source files have been modified on the file system when
     63 /// an update is requested, as well as to cache `@import` results.
     64 /// Keys are fully resolved file paths. This table owns the keys and values.
     65 import_table: std.StringArrayHashMapUnmanaged(*File) = .{},
     66 /// The set of all the files which have been loaded with `@embedFile` in the Module.
     67 /// We keep track of this in order to iterate over it and check which files have been
     68 /// modified on the file system when an update is requested, as well as to cache
     69 /// `@embedFile` results.
     70 /// Keys are fully resolved file paths. This table owns the keys and values.
     71 embed_table: std.StringHashMapUnmanaged(*EmbedFile) = .{},
     72 
     73 /// This is a temporary addition to stage2 in order to match stage1 behavior,
     74 /// however the end-game once the lang spec is settled will be to use a global
     75 /// InternPool for comptime memoized objects, making this behavior consistent across all types,
     76 /// not only string literals. Or, we might decide to not guarantee string literals
     77 /// to have equal comptime pointers, in which case this field can be deleted (perhaps
     78 /// the commit that introduced it can simply be reverted).
     79 /// This table uses an optional index so that when a Decl is destroyed, the string literal
     80 /// is still reclaimable by a future Decl.
     81 string_literal_table: std.HashMapUnmanaged(StringLiteralContext.Key, Decl.OptionalIndex, StringLiteralContext, std.hash_map.default_max_load_percentage) = .{},
     82 string_literal_bytes: std.ArrayListUnmanaged(u8) = .{},
     83 
     84 /// The set of all the generic function instantiations. This is used so that when a generic
     85 /// function is called twice with the same comptime parameter arguments, both calls dispatch
     86 /// to the same function.
     87 /// TODO: remove functions from this set when they are destroyed.
     88 monomorphed_funcs: MonomorphedFuncsSet = .{},
     89 /// The set of all comptime function calls that have been cached so that future calls
     90 /// with the same parameters will get the same return value.
     91 memoized_calls: MemoizedCallSet = .{},
     92 /// Contains the values from `@setAlignStack`. A sparse table is used here
     93 /// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while
     94 /// functions are many.
     95 /// TODO: remove functions from this set when they are destroyed.
     96 align_stack_fns: std.AutoHashMapUnmanaged(*const Fn, SetAlignStack) = .{},
     97 
     98 /// We optimize memory usage for a compilation with no compile errors by storing the
     99 /// error messages and mapping outside of `Decl`.
    100 /// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.
    101 /// Note that a Decl can succeed but the Fn it represents can fail. In this case,
    102 /// a Decl can have a failed_decls entry but have analysis status of success.
    103 failed_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, *ErrorMsg) = .{},
    104 /// Keep track of one `@compileLog` callsite per owner Decl.
    105 /// The value is the AST node index offset from the Decl.
    106 compile_log_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, i32) = .{},
    107 /// Using a map here for consistency with the other fields here.
    108 /// The ErrorMsg memory is owned by the `File`, using Module's general purpose allocator.
    109 failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .{},
    110 /// The ErrorMsg memory is owned by the `EmbedFile`, using Module's general purpose allocator.
    111 failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .{},
    112 /// Using a map here for consistency with the other fields here.
    113 /// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
    114 failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
    115 
    116 /// Candidates for deletion. After a semantic analysis update completes, this list
    117 /// contains Decls that need to be deleted if they end up having no references to them.
    118 deletion_set: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
    119 
    120 /// Error tags and their values, tag names are duped with mod.gpa.
    121 /// Corresponds with `error_name_list`.
    122 global_error_set: std.StringHashMapUnmanaged(ErrorInt) = .{},
    123 
    124 /// ErrorInt -> []const u8 for fast lookups for @intToError at comptime
    125 /// Corresponds with `global_error_set`.
    126 error_name_list: ArrayListUnmanaged([]const u8),
    127 
    128 /// Incrementing integer used to compare against the corresponding Decl
    129 /// field to determine whether a Decl's status applies to an ongoing update, or a
    130 /// previous analysis.
    131 generation: u32 = 0,
    132 
    133 stage1_flags: packed struct {
    134     have_winmain: bool = false,
    135     have_wwinmain: bool = false,
    136     have_winmain_crt_startup: bool = false,
    137     have_wwinmain_crt_startup: bool = false,
    138     have_dllmain_crt_startup: bool = false,
    139     have_c_main: bool = false,
    140     reserved: u2 = 0,
    141 } = .{},
    142 
    143 job_queued_update_builtin_zig: bool = true,
    144 /// This makes it so that we can run `zig test` on the standard library.
    145 /// Otherwise, the logic for scanning test decls skips all of them because
    146 /// `main_pkg != std_pkg`.
    147 main_pkg_in_std: bool,
    148 
    149 compile_log_text: ArrayListUnmanaged(u8) = .{},
    150 
    151 emit_h: ?*GlobalEmitH,
    152 
    153 test_functions: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
    154 
    155 /// Rather than allocating Decl objects with an Allocator, we instead allocate
    156 /// them with this SegmentedList. This provides four advantages:
    157 ///  * Stable memory so that one thread can access a Decl object while another
    158 ///    thread allocates additional Decl objects from this list.
    159 ///  * It allows us to use u32 indexes to reference Decl objects rather than
    160 ///    pointers, saving memory in Type, Value, and dependency sets.
    161 ///  * Using integers to reference Decl objects rather than pointers makes
    162 ///    serialization trivial.
    163 ///  * It provides a unique integer to be used for anonymous symbol names, avoiding
    164 ///    multi-threaded contention on an atomic counter.
    165 allocated_decls: std.SegmentedList(Decl, 0) = .{},
    166 /// When a Decl object is freed from `allocated_decls`, it is pushed into this stack.
    167 decls_free_list: std.ArrayListUnmanaged(Decl.Index) = .{},
    168 
    169 global_assembly: std.AutoHashMapUnmanaged(Decl.Index, []u8) = .{},
    170 
    171 pub const StringLiteralContext = struct {
    172     bytes: *std.ArrayListUnmanaged(u8),
    173 
    174     pub const Key = struct {
    175         index: u32,
    176         len: u32,
    177     };
    178 
    179     pub fn eql(self: @This(), a: Key, b: Key) bool {
    180         _ = self;
    181         return a.index == b.index and a.len == b.len;
    182     }
    183 
    184     pub fn hash(self: @This(), x: Key) u64 {
    185         const x_slice = self.bytes.items[x.index..][0..x.len];
    186         return std.hash_map.hashString(x_slice);
    187     }
    188 };
    189 
    190 pub const StringLiteralAdapter = struct {
    191     bytes: *std.ArrayListUnmanaged(u8),
    192 
    193     pub fn eql(self: @This(), a_slice: []const u8, b: StringLiteralContext.Key) bool {
    194         const b_slice = self.bytes.items[b.index..][0..b.len];
    195         return mem.eql(u8, a_slice, b_slice);
    196     }
    197 
    198     pub fn hash(self: @This(), adapted_key: []const u8) u64 {
    199         _ = self;
    200         return std.hash_map.hashString(adapted_key);
    201     }
    202 };
    203 
    204 const MonomorphedFuncsSet = std.HashMapUnmanaged(
    205     *Fn,
    206     void,
    207     MonomorphedFuncsContext,
    208     std.hash_map.default_max_load_percentage,
    209 );
    210 
    211 const MonomorphedFuncsContext = struct {
    212     pub fn eql(ctx: @This(), a: *Fn, b: *Fn) bool {
    213         _ = ctx;
    214         return a == b;
    215     }
    216 
    217     /// Must match `Sema.GenericCallAdapter.hash`.
    218     pub fn hash(ctx: @This(), key: *Fn) u64 {
    219         _ = ctx;
    220         return key.hash;
    221     }
    222 };
    223 
    224 pub const WipAnalysis = struct {
    225     sema: *Sema,
    226     block: *Sema.Block,
    227     src: Module.LazySrcLoc,
    228 };
    229 
    230 pub const MemoizedCallSet = std.HashMapUnmanaged(
    231     MemoizedCall.Key,
    232     MemoizedCall.Result,
    233     MemoizedCall,
    234     std.hash_map.default_max_load_percentage,
    235 );
    236 
    237 pub const MemoizedCall = struct {
    238     module: *Module,
    239 
    240     pub const Key = struct {
    241         func: *Fn,
    242         args: []TypedValue,
    243     };
    244 
    245     pub const Result = struct {
    246         val: Value,
    247         arena: std.heap.ArenaAllocator.State,
    248     };
    249 
    250     pub fn eql(ctx: @This(), a: Key, b: Key) bool {
    251         if (a.func != b.func) return false;
    252 
    253         assert(a.args.len == b.args.len);
    254         for (a.args) |a_arg, arg_i| {
    255             const b_arg = b.args[arg_i];
    256             if (!a_arg.eql(b_arg, ctx.module)) {
    257                 return false;
    258             }
    259         }
    260 
    261         return true;
    262     }
    263 
    264     /// Must match `Sema.GenericCallAdapter.hash`.
    265     pub fn hash(ctx: @This(), key: Key) u64 {
    266         var hasher = std.hash.Wyhash.init(0);
    267 
    268         // The generic function Decl is guaranteed to be the first dependency
    269         // of each of its instantiations.
    270         std.hash.autoHash(&hasher, key.func);
    271 
    272         // This logic must be kept in sync with the logic in `analyzeCall` that
    273         // computes the hash.
    274         for (key.args) |arg| {
    275             arg.hash(&hasher, ctx.module);
    276         }
    277 
    278         return hasher.final();
    279     }
    280 };
    281 
    282 pub const SetAlignStack = struct {
    283     alignment: u32,
    284     /// TODO: This needs to store a non-lazy source location for the case of an inline function
    285     /// which does `@setAlignStack` (applying it to the caller).
    286     src: LazySrcLoc,
    287 };
    288 
    289 /// A `Module` has zero or one of these depending on whether `-femit-h` is enabled.
    290 pub const GlobalEmitH = struct {
    291     /// Where to put the output.
    292     loc: Compilation.EmitLoc,
    293     /// When emit_h is non-null, each Decl gets one more compile error slot for
    294     /// emit-h failing for that Decl. This table is also how we tell if a Decl has
    295     /// failed emit-h or succeeded.
    296     failed_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, *ErrorMsg) = .{},
    297     /// Tracks all decls in order to iterate over them and emit .h code for them.
    298     decl_table: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
    299     /// Similar to the allocated_decls field of Module, this is where `EmitH` objects
    300     /// are allocated. There will be exactly one EmitH object per Decl object, with
    301     /// identical indexes.
    302     allocated_emit_h: std.SegmentedList(EmitH, 0) = .{},
    303 
    304     pub fn declPtr(global_emit_h: *GlobalEmitH, decl_index: Decl.Index) *EmitH {
    305         return global_emit_h.allocated_emit_h.at(@enumToInt(decl_index));
    306     }
    307 };
    308 
    309 pub const ErrorInt = u32;
    310 
    311 pub const Export = struct {
    312     options: std.builtin.ExportOptions,
    313     src: LazySrcLoc,
    314     /// Represents the position of the export, if any, in the output file.
    315     link: link.File.Export,
    316     /// The Decl that performs the export. Note that this is *not* the Decl being exported.
    317     owner_decl: Decl.Index,
    318     /// The Decl containing the export statement.  Inline function calls
    319     /// may cause this to be different from the owner_decl.
    320     src_decl: Decl.Index,
    321     /// The Decl being exported. Note this is *not* the Decl performing the export.
    322     exported_decl: Decl.Index,
    323     status: enum {
    324         in_progress,
    325         failed,
    326         /// Indicates that the failure was due to a temporary issue, such as an I/O error
    327         /// when writing to the output file. Retrying the export may succeed.
    328         failed_retryable,
    329         complete,
    330     },
    331 
    332     pub fn getSrcLoc(exp: Export, mod: *Module) SrcLoc {
    333         const src_decl = mod.declPtr(exp.src_decl);
    334         return .{
    335             .file_scope = src_decl.getFileScope(),
    336             .parent_decl_node = src_decl.src_node,
    337             .lazy = exp.src,
    338         };
    339     }
    340 };
    341 
    342 pub const CaptureScope = struct {
    343     parent: ?*CaptureScope,
    344 
    345     /// Values from this decl's evaluation that will be closed over in
    346     /// child decls. Values stored in the value_arena of the linked decl.
    347     /// During sema, this map is backed by the gpa.  Once sema completes,
    348     /// it is reallocated using the value_arena.
    349     captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, TypedValue) = .{},
    350 };
    351 
    352 pub const WipCaptureScope = struct {
    353     scope: *CaptureScope,
    354     finalized: bool,
    355     gpa: Allocator,
    356     perm_arena: Allocator,
    357 
    358     pub fn init(gpa: Allocator, perm_arena: Allocator, parent: ?*CaptureScope) !@This() {
    359         const scope = try perm_arena.create(CaptureScope);
    360         scope.* = .{ .parent = parent };
    361         return @This(){
    362             .scope = scope,
    363             .finalized = false,
    364             .gpa = gpa,
    365             .perm_arena = perm_arena,
    366         };
    367     }
    368 
    369     pub fn finalize(noalias self: *@This()) !void {
    370         assert(!self.finalized);
    371         // use a temp to avoid unintentional aliasing due to RLS
    372         const tmp = try self.scope.captures.clone(self.perm_arena);
    373         self.scope.captures.deinit(self.gpa);
    374         self.scope.captures = tmp;
    375         self.finalized = true;
    376     }
    377 
    378     pub fn reset(noalias self: *@This(), parent: ?*CaptureScope) !void {
    379         if (!self.finalized) try self.finalize();
    380         self.scope = try self.perm_arena.create(CaptureScope);
    381         self.scope.* = .{ .parent = parent };
    382         self.finalized = false;
    383     }
    384 
    385     pub fn deinit(noalias self: *@This()) void {
    386         if (!self.finalized) {
    387             self.scope.captures.deinit(self.gpa);
    388         }
    389         self.* = undefined;
    390     }
    391 };
    392 
    393 pub const Decl = struct {
    394     /// Allocated with Module's allocator; outlives the ZIR code.
    395     name: [*:0]const u8,
    396     /// The most recent Type of the Decl after a successful semantic analysis.
    397     /// Populated when `has_tv`.
    398     ty: Type,
    399     /// The most recent Value of the Decl after a successful semantic analysis.
    400     /// Populated when `has_tv`.
    401     val: Value,
    402     /// Populated when `has_tv`.
    403     /// Points to memory inside value_arena.
    404     @"linksection": ?[*:0]const u8,
    405     /// Populated when `has_tv`.
    406     @"align": u32,
    407     /// Populated when `has_tv`.
    408     @"addrspace": std.builtin.AddressSpace,
    409     /// The memory for ty, val, align, linksection, and captures.
    410     /// If this is `null` then there is no memory management needed.
    411     value_arena: ?*std.heap.ArenaAllocator.State = null,
    412     /// The direct parent namespace of the Decl.
    413     /// Reference to externally owned memory.
    414     /// In the case of the Decl corresponding to a file, this is
    415     /// the namespace of the struct, since there is no parent.
    416     src_namespace: *Namespace,
    417 
    418     /// The scope which lexically contains this decl.  A decl must depend
    419     /// on its lexical parent, in order to ensure that this pointer is valid.
    420     /// This scope is allocated out of the arena of the parent decl.
    421     src_scope: ?*CaptureScope,
    422 
    423     /// An integer that can be checked against the corresponding incrementing
    424     /// generation field of Module. This is used to determine whether `complete` status
    425     /// represents pre- or post- re-analysis.
    426     generation: u32,
    427     /// The AST node index of this declaration.
    428     /// Must be recomputed when the corresponding source file is modified.
    429     src_node: Ast.Node.Index,
    430     /// Line number corresponding to `src_node`. Stored separately so that source files
    431     /// do not need to be loaded into memory in order to compute debug line numbers.
    432     /// This value is absolute.
    433     src_line: u32,
    434     /// Index to ZIR `extra` array to the entry in the parent's decl structure
    435     /// (the part that says "for every decls_len"). The first item at this index is
    436     /// the contents hash, followed by line, name, etc.
    437     /// For anonymous decls and also the root Decl for a File, this is 0.
    438     zir_decl_index: Zir.Inst.Index,
    439 
    440     /// Represents the "shallow" analysis status. For example, for decls that are functions,
    441     /// the function type is analyzed with this set to `in_progress`, however, the semantic
    442     /// analysis of the function body is performed with this value set to `success`. Functions
    443     /// have their own analysis status field.
    444     analysis: enum {
    445         /// This Decl corresponds to an AST Node that has not been referenced yet, and therefore
    446         /// because of Zig's lazy declaration analysis, it will remain unanalyzed until referenced.
    447         unreferenced,
    448         /// Semantic analysis for this Decl is running right now.
    449         /// This state detects dependency loops.
    450         in_progress,
    451         /// The file corresponding to this Decl had a parse error or ZIR error.
    452         /// There will be a corresponding ErrorMsg in Module.failed_files.
    453         file_failure,
    454         /// This Decl might be OK but it depends on another one which did not successfully complete
    455         /// semantic analysis.
    456         dependency_failure,
    457         /// Semantic analysis failure.
    458         /// There will be a corresponding ErrorMsg in Module.failed_decls.
    459         sema_failure,
    460         /// There will be a corresponding ErrorMsg in Module.failed_decls.
    461         /// This indicates the failure was something like running out of disk space,
    462         /// and attempting semantic analysis again may succeed.
    463         sema_failure_retryable,
    464         /// There will be a corresponding ErrorMsg in Module.failed_decls.
    465         codegen_failure,
    466         /// There will be a corresponding ErrorMsg in Module.failed_decls.
    467         /// This indicates the failure was something like running out of disk space,
    468         /// and attempting codegen again may succeed.
    469         codegen_failure_retryable,
    470         /// Everything is done. During an update, this Decl may be out of date, depending
    471         /// on its dependencies. The `generation` field can be used to determine if this
    472         /// completion status occurred before or after a given update.
    473         complete,
    474         /// A Module update is in progress, and this Decl has been flagged as being known
    475         /// to require re-analysis.
    476         outdated,
    477     },
    478     /// Whether `typed_value`, `align`, `linksection` and `addrspace` are populated.
    479     has_tv: bool,
    480     /// If `true` it means the `Decl` is the resource owner of the type/value associated
    481     /// with it. That means when `Decl` is destroyed, the cleanup code should additionally
    482     /// check if the value owns a `Namespace`, and destroy that too.
    483     owns_tv: bool,
    484     /// This flag is set when this Decl is added to `Module.deletion_set`, and cleared
    485     /// when removed.
    486     deletion_flag: bool,
    487     /// Whether the corresponding AST decl has a `pub` keyword.
    488     is_pub: bool,
    489     /// Whether the corresponding AST decl has a `export` keyword.
    490     is_exported: bool,
    491     /// Whether the ZIR code provides an align instruction.
    492     has_align: bool,
    493     /// Whether the ZIR code provides a linksection and address space instruction.
    494     has_linksection_or_addrspace: bool,
    495     /// Flag used by garbage collection to mark and sweep.
    496     /// Decls which correspond to an AST node always have this field set to `true`.
    497     /// Anonymous Decls are initialized with this field set to `false` and then it
    498     /// is the responsibility of machine code backends to mark it `true` whenever
    499     /// a `decl_ref` Value is encountered that points to this Decl.
    500     /// When the `codegen_decl` job is encountered in the main work queue, if the
    501     /// Decl is marked alive, then it sends the Decl to the linker. Otherwise it
    502     /// deletes the Decl on the spot.
    503     alive: bool,
    504     /// Whether the Decl is a `usingnamespace` declaration.
    505     is_usingnamespace: bool,
    506 
    507     /// Represents the position of the code in the output file.
    508     /// This is populated regardless of semantic analysis and code generation.
    509     link: link.File.LinkBlock,
    510 
    511     /// Represents the function in the linked output file, if the `Decl` is a function.
    512     /// This is stored here and not in `Fn` because `Decl` survives across updates but
    513     /// `Fn` does not.
    514     /// TODO Look into making `Fn` a longer lived structure and moving this field there
    515     /// to save on memory usage.
    516     fn_link: link.File.LinkFn,
    517 
    518     /// The shallow set of other decls whose typed_value could possibly change if this Decl's
    519     /// typed_value is modified.
    520     dependants: DepsTable = .{},
    521     /// The shallow set of other decls whose typed_value changing indicates that this Decl's
    522     /// typed_value may need to be regenerated.
    523     dependencies: DepsTable = .{},
    524 
    525     pub const Index = enum(u32) {
    526         _,
    527 
    528         pub fn toOptional(i: Index) OptionalIndex {
    529             return @intToEnum(OptionalIndex, @enumToInt(i));
    530         }
    531     };
    532 
    533     pub const OptionalIndex = enum(u32) {
    534         none = std.math.maxInt(u32),
    535         _,
    536 
    537         pub fn init(oi: ?Index) OptionalIndex {
    538             return oi orelse .none;
    539         }
    540 
    541         pub fn unwrap(oi: OptionalIndex) ?Index {
    542             if (oi == .none) return null;
    543             return @intToEnum(Index, @enumToInt(oi));
    544         }
    545     };
    546 
    547     pub const DepsTable = std.AutoArrayHashMapUnmanaged(Decl.Index, void);
    548 
    549     pub fn clearName(decl: *Decl, gpa: Allocator) void {
    550         gpa.free(mem.sliceTo(decl.name, 0));
    551         decl.name = undefined;
    552     }
    553 
    554     pub fn clearValues(decl: *Decl, mod: *Module) void {
    555         const gpa = mod.gpa;
    556         if (decl.getExternFn()) |extern_fn| {
    557             extern_fn.deinit(gpa);
    558             gpa.destroy(extern_fn);
    559         }
    560         if (decl.getFunction()) |func| {
    561             func.deinit(gpa);
    562             gpa.destroy(func);
    563         }
    564         if (decl.getVariable()) |variable| {
    565             variable.deinit(gpa);
    566             gpa.destroy(variable);
    567         }
    568         if (decl.value_arena) |arena_state| {
    569             if (decl.owns_tv) {
    570                 if (decl.val.castTag(.str_lit)) |str_lit| {
    571                     mod.string_literal_table.getPtrContext(str_lit.data, .{
    572                         .bytes = &mod.string_literal_bytes,
    573                     }).?.* = .none;
    574                 }
    575             }
    576             arena_state.promote(gpa).deinit();
    577             decl.value_arena = null;
    578             decl.has_tv = false;
    579             decl.owns_tv = false;
    580         }
    581     }
    582 
    583     pub fn finalizeNewArena(decl: *Decl, arena: *std.heap.ArenaAllocator) !void {
    584         assert(decl.value_arena == null);
    585         const arena_state = try arena.allocator().create(std.heap.ArenaAllocator.State);
    586         arena_state.* = arena.state;
    587         decl.value_arena = arena_state;
    588     }
    589 
    590     /// This name is relative to the containing namespace of the decl.
    591     /// The memory is owned by the containing File ZIR.
    592     pub fn getName(decl: Decl) ?[:0]const u8 {
    593         const zir = decl.getFileScope().zir;
    594         return decl.getNameZir(zir);
    595     }
    596 
    597     pub fn getNameZir(decl: Decl, zir: Zir) ?[:0]const u8 {
    598         assert(decl.zir_decl_index != 0);
    599         const name_index = zir.extra[decl.zir_decl_index + 5];
    600         if (name_index <= 1) return null;
    601         return zir.nullTerminatedString(name_index);
    602     }
    603 
    604     pub fn contentsHash(decl: Decl) std.zig.SrcHash {
    605         const zir = decl.getFileScope().zir;
    606         return decl.contentsHashZir(zir);
    607     }
    608 
    609     pub fn contentsHashZir(decl: Decl, zir: Zir) std.zig.SrcHash {
    610         assert(decl.zir_decl_index != 0);
    611         const hash_u32s = zir.extra[decl.zir_decl_index..][0..4];
    612         const contents_hash = @bitCast(std.zig.SrcHash, hash_u32s.*);
    613         return contents_hash;
    614     }
    615 
    616     pub fn zirBlockIndex(decl: *const Decl) Zir.Inst.Index {
    617         assert(decl.zir_decl_index != 0);
    618         const zir = decl.getFileScope().zir;
    619         return zir.extra[decl.zir_decl_index + 6];
    620     }
    621 
    622     pub fn zirAlignRef(decl: Decl) Zir.Inst.Ref {
    623         if (!decl.has_align) return .none;
    624         assert(decl.zir_decl_index != 0);
    625         const zir = decl.getFileScope().zir;
    626         return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 8]);
    627     }
    628 
    629     pub fn zirLinksectionRef(decl: Decl) Zir.Inst.Ref {
    630         if (!decl.has_linksection_or_addrspace) return .none;
    631         assert(decl.zir_decl_index != 0);
    632         const zir = decl.getFileScope().zir;
    633         const extra_index = decl.zir_decl_index + 8 + @boolToInt(decl.has_align);
    634         return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
    635     }
    636 
    637     pub fn zirAddrspaceRef(decl: Decl) Zir.Inst.Ref {
    638         if (!decl.has_linksection_or_addrspace) return .none;
    639         assert(decl.zir_decl_index != 0);
    640         const zir = decl.getFileScope().zir;
    641         const extra_index = decl.zir_decl_index + 8 + @boolToInt(decl.has_align) + 1;
    642         return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
    643     }
    644 
    645     pub fn relativeToLine(decl: Decl, offset: u32) u32 {
    646         return decl.src_line + offset;
    647     }
    648 
    649     pub fn relativeToNodeIndex(decl: Decl, offset: i32) Ast.Node.Index {
    650         return @bitCast(Ast.Node.Index, offset + @bitCast(i32, decl.src_node));
    651     }
    652 
    653     pub fn nodeIndexToRelative(decl: Decl, node_index: Ast.Node.Index) i32 {
    654         return @bitCast(i32, node_index) - @bitCast(i32, decl.src_node);
    655     }
    656 
    657     pub fn tokSrcLoc(decl: Decl, token_index: Ast.TokenIndex) LazySrcLoc {
    658         return .{ .token_offset = token_index - decl.srcToken() };
    659     }
    660 
    661     pub fn nodeSrcLoc(decl: Decl, node_index: Ast.Node.Index) LazySrcLoc {
    662         return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(node_index));
    663     }
    664 
    665     pub fn srcLoc(decl: Decl) SrcLoc {
    666         return decl.nodeOffsetSrcLoc(0);
    667     }
    668 
    669     pub fn nodeOffsetSrcLoc(decl: Decl, node_offset: i32) SrcLoc {
    670         return .{
    671             .file_scope = decl.getFileScope(),
    672             .parent_decl_node = decl.src_node,
    673             .lazy = LazySrcLoc.nodeOffset(node_offset),
    674         };
    675     }
    676 
    677     pub fn srcToken(decl: Decl) Ast.TokenIndex {
    678         const tree = &decl.getFileScope().tree;
    679         return tree.firstToken(decl.src_node);
    680     }
    681 
    682     pub fn srcByteOffset(decl: Decl) u32 {
    683         const tree = &decl.getFileScope().tree;
    684         return tree.tokens.items(.start)[decl.srcToken()];
    685     }
    686 
    687     pub fn renderFullyQualifiedName(decl: Decl, mod: *Module, writer: anytype) !void {
    688         const unqualified_name = mem.sliceTo(decl.name, 0);
    689         return decl.src_namespace.renderFullyQualifiedName(mod, unqualified_name, writer);
    690     }
    691 
    692     pub fn renderFullyQualifiedDebugName(decl: Decl, mod: *Module, writer: anytype) !void {
    693         const unqualified_name = mem.sliceTo(decl.name, 0);
    694         return decl.src_namespace.renderFullyQualifiedDebugName(mod, unqualified_name, writer);
    695     }
    696 
    697     pub fn getFullyQualifiedName(decl: Decl, mod: *Module) ![:0]u8 {
    698         var buffer = std.ArrayList(u8).init(mod.gpa);
    699         defer buffer.deinit();
    700         try decl.renderFullyQualifiedName(mod, buffer.writer());
    701         return buffer.toOwnedSliceSentinel(0);
    702     }
    703 
    704     pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue {
    705         if (!decl.has_tv) return error.AnalysisFail;
    706         return TypedValue{
    707             .ty = decl.ty,
    708             .val = decl.val,
    709         };
    710     }
    711 
    712     pub fn value(decl: *Decl) error{AnalysisFail}!Value {
    713         return (try decl.typedValue()).val;
    714     }
    715 
    716     pub fn isFunction(decl: Decl) !bool {
    717         const tv = try decl.typedValue();
    718         return tv.ty.zigTypeTag() == .Fn;
    719     }
    720 
    721     /// If the Decl has a value and it is a struct, return it,
    722     /// otherwise null.
    723     pub fn getStruct(decl: *Decl) ?*Struct {
    724         if (!decl.owns_tv) return null;
    725         const ty = (decl.val.castTag(.ty) orelse return null).data;
    726         const struct_obj = (ty.castTag(.@"struct") orelse return null).data;
    727         return struct_obj;
    728     }
    729 
    730     /// If the Decl has a value and it is a union, return it,
    731     /// otherwise null.
    732     pub fn getUnion(decl: *Decl) ?*Union {
    733         if (!decl.owns_tv) return null;
    734         const ty = (decl.val.castTag(.ty) orelse return null).data;
    735         const union_obj = (ty.cast(Type.Payload.Union) orelse return null).data;
    736         return union_obj;
    737     }
    738 
    739     /// If the Decl has a value and it is a function, return it,
    740     /// otherwise null.
    741     pub fn getFunction(decl: *const Decl) ?*Fn {
    742         if (!decl.owns_tv) return null;
    743         const func = (decl.val.castTag(.function) orelse return null).data;
    744         return func;
    745     }
    746 
    747     /// If the Decl has a value and it is an extern function, returns it,
    748     /// otherwise null.
    749     pub fn getExternFn(decl: *const Decl) ?*ExternFn {
    750         if (!decl.owns_tv) return null;
    751         const extern_fn = (decl.val.castTag(.extern_fn) orelse return null).data;
    752         return extern_fn;
    753     }
    754 
    755     /// If the Decl has a value and it is a variable, returns it,
    756     /// otherwise null.
    757     pub fn getVariable(decl: *const Decl) ?*Var {
    758         if (!decl.owns_tv) return null;
    759         const variable = (decl.val.castTag(.variable) orelse return null).data;
    760         return variable;
    761     }
    762 
    763     /// Gets the namespace that this Decl creates by being a struct, union,
    764     /// enum, or opaque.
    765     /// Only returns it if the Decl is the owner.
    766     pub fn getInnerNamespace(decl: *Decl) ?*Namespace {
    767         if (!decl.owns_tv) return null;
    768         const ty = (decl.val.castTag(.ty) orelse return null).data;
    769         switch (ty.tag()) {
    770             .@"struct" => {
    771                 const struct_obj = ty.castTag(.@"struct").?.data;
    772                 return &struct_obj.namespace;
    773             },
    774             .enum_full, .enum_nonexhaustive => {
    775                 const enum_obj = ty.cast(Type.Payload.EnumFull).?.data;
    776                 return &enum_obj.namespace;
    777             },
    778             .empty_struct => {
    779                 return ty.castTag(.empty_struct).?.data;
    780             },
    781             .@"opaque" => {
    782                 const opaque_obj = ty.cast(Type.Payload.Opaque).?.data;
    783                 return &opaque_obj.namespace;
    784             },
    785             .@"union", .union_tagged => {
    786                 const union_obj = ty.cast(Type.Payload.Union).?.data;
    787                 return &union_obj.namespace;
    788             },
    789 
    790             else => return null,
    791         }
    792     }
    793 
    794     pub fn dump(decl: *Decl) void {
    795         const loc = std.zig.findLineColumn(decl.scope.source.bytes, decl.src);
    796         std.debug.print("{s}:{d}:{d} name={s} status={s}", .{
    797             decl.scope.sub_file_path,
    798             loc.line + 1,
    799             loc.column + 1,
    800             mem.sliceTo(decl.name, 0),
    801             @tagName(decl.analysis),
    802         });
    803         if (decl.has_tv) {
    804             std.debug.print(" ty={} val={}", .{ decl.ty, decl.val });
    805         }
    806         std.debug.print("\n", .{});
    807     }
    808 
    809     pub fn getFileScope(decl: Decl) *File {
    810         return decl.src_namespace.file_scope;
    811     }
    812 
    813     pub fn removeDependant(decl: *Decl, other: Decl.Index) void {
    814         assert(decl.dependants.swapRemove(other));
    815     }
    816 
    817     pub fn removeDependency(decl: *Decl, other: Decl.Index) void {
    818         assert(decl.dependencies.swapRemove(other));
    819     }
    820 
    821     pub fn isExtern(decl: Decl) bool {
    822         assert(decl.has_tv);
    823         return switch (decl.val.tag()) {
    824             .extern_fn => true,
    825             .variable => decl.val.castTag(.variable).?.data.init.tag() == .unreachable_value,
    826             else => false,
    827         };
    828     }
    829 
    830     pub fn getAlignment(decl: Decl, target: Target) u32 {
    831         assert(decl.has_tv);
    832         if (decl.@"align" != 0) {
    833             // Explicit alignment.
    834             return decl.@"align";
    835         } else {
    836             // Natural alignment.
    837             return decl.ty.abiAlignment(target);
    838         }
    839     }
    840 };
    841 
    842 /// This state is attached to every Decl when Module emit_h is non-null.
    843 pub const EmitH = struct {
    844     fwd_decl: ArrayListUnmanaged(u8) = .{},
    845 };
    846 
    847 /// Represents the data that an explicit error set syntax provides.
    848 pub const ErrorSet = struct {
    849     /// The Decl that corresponds to the error set itself.
    850     owner_decl: Decl.Index,
    851     /// Offset from Decl node index, points to the error set AST node.
    852     node_offset: i32,
    853     /// The string bytes are stored in the owner Decl arena.
    854     /// These must be in sorted order. See sortNames.
    855     names: NameMap,
    856 
    857     pub const NameMap = std.StringArrayHashMapUnmanaged(void);
    858 
    859     pub fn srcLoc(self: ErrorSet, mod: *Module) SrcLoc {
    860         const owner_decl = mod.declPtr(self.owner_decl);
    861         return .{
    862             .file_scope = owner_decl.getFileScope(),
    863             .parent_decl_node = owner_decl.src_node,
    864             .lazy = LazySrcLoc.nodeOffset(self.node_offset),
    865         };
    866     }
    867 
    868     /// sort the NameMap. This should be called whenever the map is modified.
    869     /// alloc should be the allocator used for the NameMap data.
    870     pub fn sortNames(names: *NameMap) void {
    871         const Context = struct {
    872             keys: [][]const u8,
    873             pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool {
    874                 return std.mem.lessThan(u8, ctx.keys[a_index], ctx.keys[b_index]);
    875             }
    876         };
    877         names.sort(Context{ .keys = names.keys() });
    878     }
    879 };
    880 
    881 pub const PropertyBoolean = enum { no, yes, unknown, wip };
    882 
    883 /// Represents the data that a struct declaration provides.
    884 pub const Struct = struct {
    885     /// Set of field names in declaration order.
    886     fields: Fields,
    887     /// Represents the declarations inside this struct.
    888     namespace: Namespace,
    889     /// The Decl that corresponds to the struct itself.
    890     owner_decl: Decl.Index,
    891     /// Offset from `owner_decl`, points to the struct AST node.
    892     node_offset: i32,
    893     /// Index of the struct_decl ZIR instruction.
    894     zir_index: Zir.Inst.Index,
    895 
    896     layout: std.builtin.Type.ContainerLayout,
    897     status: enum {
    898         none,
    899         field_types_wip,
    900         have_field_types,
    901         layout_wip,
    902         have_layout,
    903         fully_resolved_wip,
    904         // The types and all its fields have had their layout resolved. Even through pointer,
    905         // which `have_layout` does not ensure.
    906         fully_resolved,
    907     },
    908     /// If true, has more than one possible value. However it may still be non-runtime type
    909     /// if it is a comptime-only type.
    910     /// If false, resolving the fields is necessary to determine whether the type has only
    911     /// one possible value.
    912     known_non_opv: bool,
    913     requires_comptime: PropertyBoolean = .unknown,
    914 
    915     pub const Fields = std.StringArrayHashMapUnmanaged(Field);
    916 
    917     /// The `Type` and `Value` memory is owned by the arena of the Struct's owner_decl.
    918     pub const Field = struct {
    919         /// Uses `noreturn` to indicate `anytype`.
    920         /// undefined until `status` is `have_field_types` or `have_layout`.
    921         ty: Type,
    922         /// Uses `unreachable_value` to indicate no default.
    923         default_val: Value,
    924         /// Zero means to use the ABI alignment of the type.
    925         abi_align: u32,
    926         /// undefined until `status` is `have_layout`.
    927         offset: u32,
    928         /// If true then `default_val` is the comptime field value.
    929         is_comptime: bool,
    930 
    931         /// Returns the field alignment, assuming the struct is not packed.
    932         pub fn normalAlignment(field: Field, target: Target) u32 {
    933             if (field.abi_align == 0) {
    934                 return field.ty.abiAlignment(target);
    935             } else {
    936                 return field.abi_align;
    937             }
    938         }
    939     };
    940 
    941     pub fn getFullyQualifiedName(s: *Struct, mod: *Module) ![:0]u8 {
    942         return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod);
    943     }
    944 
    945     pub fn srcLoc(s: Struct, mod: *Module) SrcLoc {
    946         const owner_decl = mod.declPtr(s.owner_decl);
    947         return .{
    948             .file_scope = owner_decl.getFileScope(),
    949             .parent_decl_node = owner_decl.src_node,
    950             .lazy = LazySrcLoc.nodeOffset(s.node_offset),
    951         };
    952     }
    953 
    954     pub fn fieldSrcLoc(s: Struct, mod: *Module, query: FieldSrcQuery) SrcLoc {
    955         @setCold(true);
    956         const owner_decl = mod.declPtr(s.owner_decl);
    957         const file = owner_decl.getFileScope();
    958         const tree = file.getTree(mod.gpa) catch |err| {
    959             // In this case we emit a warning + a less precise source location.
    960             log.warn("unable to load {s}: {s}", .{
    961                 file.sub_file_path, @errorName(err),
    962             });
    963             return s.srcLoc(mod);
    964         };
    965         const node = owner_decl.relativeToNodeIndex(s.node_offset);
    966         const node_tags = tree.nodes.items(.tag);
    967         switch (node_tags[node]) {
    968             .container_decl,
    969             .container_decl_trailing,
    970             => return queryFieldSrc(tree.*, query, file, tree.containerDecl(node)),
    971             .container_decl_two, .container_decl_two_trailing => {
    972                 var buffer: [2]Ast.Node.Index = undefined;
    973                 return queryFieldSrc(tree.*, query, file, tree.containerDeclTwo(&buffer, node));
    974             },
    975             .container_decl_arg,
    976             .container_decl_arg_trailing,
    977             => return queryFieldSrc(tree.*, query, file, tree.containerDeclArg(node)),
    978 
    979             .tagged_union,
    980             .tagged_union_trailing,
    981             => return queryFieldSrc(tree.*, query, file, tree.taggedUnion(node)),
    982             .tagged_union_two, .tagged_union_two_trailing => {
    983                 var buffer: [2]Ast.Node.Index = undefined;
    984                 return queryFieldSrc(tree.*, query, file, tree.taggedUnionTwo(&buffer, node));
    985             },
    986             .tagged_union_enum_tag,
    987             .tagged_union_enum_tag_trailing,
    988             => return queryFieldSrc(tree.*, query, file, tree.taggedUnionEnumTag(node)),
    989 
    990             .root => return queryFieldSrc(tree.*, query, file, tree.containerDeclRoot()),
    991 
    992             else => unreachable,
    993         }
    994     }
    995 
    996     pub fn haveFieldTypes(s: Struct) bool {
    997         return switch (s.status) {
    998             .none,
    999             .field_types_wip,
   1000             => false,
   1001             .have_field_types,
   1002             .layout_wip,
   1003             .have_layout,
   1004             .fully_resolved_wip,
   1005             .fully_resolved,
   1006             => true,
   1007         };
   1008     }
   1009 
   1010     pub fn haveLayout(s: Struct) bool {
   1011         return switch (s.status) {
   1012             .none,
   1013             .field_types_wip,
   1014             .have_field_types,
   1015             .layout_wip,
   1016             => false,
   1017             .have_layout,
   1018             .fully_resolved_wip,
   1019             .fully_resolved,
   1020             => true,
   1021         };
   1022     }
   1023 
   1024     pub fn packedFieldBitOffset(s: Struct, target: Target, index: usize) u16 {
   1025         assert(s.layout == .Packed);
   1026         assert(s.haveFieldTypes());
   1027         var bit_sum: u64 = 0;
   1028         for (s.fields.values()) |field, i| {
   1029             if (i == index) {
   1030                 return @intCast(u16, bit_sum);
   1031             }
   1032             bit_sum += field.ty.bitSize(target);
   1033         }
   1034         return @intCast(u16, bit_sum);
   1035     }
   1036 
   1037     pub fn packedIntegerBits(s: Struct, target: Target) u16 {
   1038         return s.packedFieldBitOffset(target, s.fields.count());
   1039     }
   1040 
   1041     pub fn packedIntegerType(s: Struct, target: Target, buf: *Type.Payload.Bits) Type {
   1042         buf.* = .{
   1043             .base = .{ .tag = .int_unsigned },
   1044             .data = s.packedIntegerBits(target),
   1045         };
   1046         return Type.initPayload(&buf.base);
   1047     }
   1048 };
   1049 
   1050 /// Represents the data that an enum declaration provides, when the fields
   1051 /// are auto-numbered, and there are no declarations. The integer tag type
   1052 /// is inferred to be the smallest power of two unsigned int that fits
   1053 /// the number of fields.
   1054 pub const EnumSimple = struct {
   1055     /// The Decl that corresponds to the enum itself.
   1056     owner_decl: Decl.Index,
   1057     /// Offset from `owner_decl`, points to the enum decl AST node.
   1058     node_offset: i32,
   1059     /// Set of field names in declaration order.
   1060     fields: NameMap,
   1061 
   1062     pub const NameMap = EnumFull.NameMap;
   1063 
   1064     pub fn srcLoc(self: EnumSimple, mod: *Module) SrcLoc {
   1065         const owner_decl = mod.declPtr(self.owner_decl);
   1066         return .{
   1067             .file_scope = owner_decl.getFileScope(),
   1068             .parent_decl_node = owner_decl.src_node,
   1069             .lazy = LazySrcLoc.nodeOffset(self.node_offset),
   1070         };
   1071     }
   1072 };
   1073 
   1074 /// Represents the data that an enum declaration provides, when there are no
   1075 /// declarations. However an integer tag type is provided, and the enum tag values
   1076 /// are explicitly provided.
   1077 pub const EnumNumbered = struct {
   1078     /// The Decl that corresponds to the enum itself.
   1079     owner_decl: Decl.Index,
   1080     /// Offset from `owner_decl`, points to the enum decl AST node.
   1081     node_offset: i32,
   1082     /// An integer type which is used for the numerical value of the enum.
   1083     /// Whether zig chooses this type or the user specifies it, it is stored here.
   1084     tag_ty: Type,
   1085     /// Set of field names in declaration order.
   1086     fields: NameMap,
   1087     /// Maps integer tag value to field index.
   1088     /// Entries are in declaration order, same as `fields`.
   1089     /// If this hash map is empty, it means the enum tags are auto-numbered.
   1090     values: ValueMap,
   1091 
   1092     pub const NameMap = EnumFull.NameMap;
   1093     pub const ValueMap = EnumFull.ValueMap;
   1094 
   1095     pub fn srcLoc(self: EnumNumbered, mod: *Module) SrcLoc {
   1096         const owner_decl = mod.declPtr(self.owner_decl);
   1097         return .{
   1098             .file_scope = owner_decl.getFileScope(),
   1099             .parent_decl_node = owner_decl.src_node,
   1100             .lazy = LazySrcLoc.nodeOffset(self.node_offset),
   1101         };
   1102     }
   1103 };
   1104 
   1105 /// Represents the data that an enum declaration provides, when there is
   1106 /// at least one tag value explicitly specified, or at least one declaration.
   1107 pub const EnumFull = struct {
   1108     /// The Decl that corresponds to the enum itself.
   1109     owner_decl: Decl.Index,
   1110     /// Offset from `owner_decl`, points to the enum decl AST node.
   1111     node_offset: i32,
   1112     /// An integer type which is used for the numerical value of the enum.
   1113     /// Whether zig chooses this type or the user specifies it, it is stored here.
   1114     tag_ty: Type,
   1115     /// Set of field names in declaration order.
   1116     fields: NameMap,
   1117     /// Maps integer tag value to field index.
   1118     /// Entries are in declaration order, same as `fields`.
   1119     /// If this hash map is empty, it means the enum tags are auto-numbered.
   1120     values: ValueMap,
   1121     /// Represents the declarations inside this enum.
   1122     namespace: Namespace,
   1123     /// true if zig inferred this tag type, false if user specified it
   1124     tag_ty_inferred: bool,
   1125 
   1126     pub const NameMap = std.StringArrayHashMapUnmanaged(void);
   1127     pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.ArrayHashContext, false);
   1128 
   1129     pub fn srcLoc(self: EnumFull, mod: *Module) SrcLoc {
   1130         const owner_decl = mod.declPtr(self.owner_decl);
   1131         return .{
   1132             .file_scope = owner_decl.getFileScope(),
   1133             .parent_decl_node = owner_decl.src_node,
   1134             .lazy = LazySrcLoc.nodeOffset(self.node_offset),
   1135         };
   1136     }
   1137 };
   1138 
   1139 pub const Union = struct {
   1140     /// An enum type which is used for the tag of the union.
   1141     /// This type is created even for untagged unions, even when the memory
   1142     /// layout does not store the tag.
   1143     /// Whether zig chooses this type or the user specifies it, it is stored here.
   1144     /// This will be set to the null type until status is `have_field_types`.
   1145     tag_ty: Type,
   1146     /// Set of field names in declaration order.
   1147     fields: Fields,
   1148     /// Represents the declarations inside this union.
   1149     namespace: Namespace,
   1150     /// The Decl that corresponds to the union itself.
   1151     owner_decl: Decl.Index,
   1152     /// Offset from `owner_decl`, points to the union decl AST node.
   1153     node_offset: i32,
   1154     /// Index of the union_decl ZIR instruction.
   1155     zir_index: Zir.Inst.Index,
   1156 
   1157     layout: std.builtin.Type.ContainerLayout,
   1158     status: enum {
   1159         none,
   1160         field_types_wip,
   1161         have_field_types,
   1162         layout_wip,
   1163         have_layout,
   1164         fully_resolved_wip,
   1165         // The types and all its fields have had their layout resolved. Even through pointer,
   1166         // which `have_layout` does not ensure.
   1167         fully_resolved,
   1168     },
   1169     requires_comptime: PropertyBoolean = .unknown,
   1170 
   1171     pub const Field = struct {
   1172         /// undefined until `status` is `have_field_types` or `have_layout`.
   1173         ty: Type,
   1174         /// 0 means the ABI alignment of the type.
   1175         abi_align: u32,
   1176 
   1177         /// Returns the field alignment, assuming the union is not packed.
   1178         /// Keep implementation in sync with `Sema.unionFieldAlignment`.
   1179         /// Prefer to call that function instead of this one during Sema.
   1180         pub fn normalAlignment(field: Field, target: Target) u32 {
   1181             if (field.abi_align == 0) {
   1182                 return field.ty.abiAlignment(target);
   1183             } else {
   1184                 return field.abi_align;
   1185             }
   1186         }
   1187     };
   1188 
   1189     pub const Fields = std.StringArrayHashMapUnmanaged(Field);
   1190 
   1191     pub fn getFullyQualifiedName(s: *Union, mod: *Module) ![:0]u8 {
   1192         return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod);
   1193     }
   1194 
   1195     pub fn srcLoc(self: Union, mod: *Module) SrcLoc {
   1196         const owner_decl = mod.declPtr(self.owner_decl);
   1197         return .{
   1198             .file_scope = owner_decl.getFileScope(),
   1199             .parent_decl_node = owner_decl.src_node,
   1200             .lazy = LazySrcLoc.nodeOffset(self.node_offset),
   1201         };
   1202     }
   1203 
   1204     pub fn fieldSrcLoc(u: Union, mod: *Module, query: FieldSrcQuery) SrcLoc {
   1205         @setCold(true);
   1206         const owner_decl = mod.declPtr(u.owner_decl);
   1207         const file = owner_decl.getFileScope();
   1208         const tree = file.getTree(mod.gpa) catch |err| {
   1209             // In this case we emit a warning + a less precise source location.
   1210             log.warn("unable to load {s}: {s}", .{
   1211                 file.sub_file_path, @errorName(err),
   1212             });
   1213             return u.srcLoc(mod);
   1214         };
   1215         const node = owner_decl.relativeToNodeIndex(u.node_offset);
   1216         const node_tags = tree.nodes.items(.tag);
   1217         switch (node_tags[node]) {
   1218             .container_decl,
   1219             .container_decl_trailing,
   1220             => return queryFieldSrc(tree.*, query, file, tree.containerDecl(node)),
   1221             .container_decl_two, .container_decl_two_trailing => {
   1222                 var buffer: [2]Ast.Node.Index = undefined;
   1223                 return queryFieldSrc(tree.*, query, file, tree.containerDeclTwo(&buffer, node));
   1224             },
   1225             .container_decl_arg,
   1226             .container_decl_arg_trailing,
   1227             => return queryFieldSrc(tree.*, query, file, tree.containerDeclArg(node)),
   1228             else => unreachable,
   1229         }
   1230     }
   1231 
   1232     pub fn haveFieldTypes(u: Union) bool {
   1233         return switch (u.status) {
   1234             .none,
   1235             .field_types_wip,
   1236             => false,
   1237             .have_field_types,
   1238             .layout_wip,
   1239             .have_layout,
   1240             .fully_resolved_wip,
   1241             .fully_resolved,
   1242             => true,
   1243         };
   1244     }
   1245 
   1246     pub fn hasAllZeroBitFieldTypes(u: Union) bool {
   1247         assert(u.haveFieldTypes());
   1248         for (u.fields.values()) |field| {
   1249             if (field.ty.hasRuntimeBits()) return false;
   1250         }
   1251         return true;
   1252     }
   1253 
   1254     pub fn mostAlignedField(u: Union, target: Target) u32 {
   1255         assert(u.haveFieldTypes());
   1256         var most_alignment: u32 = 0;
   1257         var most_index: usize = undefined;
   1258         for (u.fields.values()) |field, i| {
   1259             if (!field.ty.hasRuntimeBits()) continue;
   1260 
   1261             const field_align = field.normalAlignment(target);
   1262             if (field_align > most_alignment) {
   1263                 most_alignment = field_align;
   1264                 most_index = i;
   1265             }
   1266         }
   1267         return @intCast(u32, most_index);
   1268     }
   1269 
   1270     /// Returns 0 if the union is represented with 0 bits at runtime.
   1271     pub fn abiAlignment(u: Union, target: Target, have_tag: bool) u32 {
   1272         var max_align: u32 = 0;
   1273         if (have_tag) max_align = u.tag_ty.abiAlignment(target);
   1274         for (u.fields.values()) |field| {
   1275             if (!field.ty.hasRuntimeBits()) continue;
   1276 
   1277             const field_align = field.normalAlignment(target);
   1278             max_align = @maximum(max_align, field_align);
   1279         }
   1280         return max_align;
   1281     }
   1282 
   1283     pub fn abiSize(u: Union, target: Target, have_tag: bool) u64 {
   1284         return u.getLayout(target, have_tag).abi_size;
   1285     }
   1286 
   1287     pub const Layout = struct {
   1288         abi_size: u64,
   1289         abi_align: u32,
   1290         most_aligned_field: u32,
   1291         most_aligned_field_size: u64,
   1292         biggest_field: u32,
   1293         payload_size: u64,
   1294         payload_align: u32,
   1295         tag_align: u32,
   1296         tag_size: u64,
   1297         padding: u32,
   1298     };
   1299 
   1300     pub fn haveLayout(u: Union) bool {
   1301         return switch (u.status) {
   1302             .none,
   1303             .field_types_wip,
   1304             .have_field_types,
   1305             .layout_wip,
   1306             => false,
   1307             .have_layout,
   1308             .fully_resolved_wip,
   1309             .fully_resolved,
   1310             => true,
   1311         };
   1312     }
   1313 
   1314     pub fn getLayout(u: Union, target: Target, have_tag: bool) Layout {
   1315         assert(u.haveLayout());
   1316         var most_aligned_field: u32 = undefined;
   1317         var most_aligned_field_size: u64 = undefined;
   1318         var biggest_field: u32 = undefined;
   1319         var payload_size: u64 = 0;
   1320         var payload_align: u32 = 0;
   1321         const fields = u.fields.values();
   1322         for (fields) |field, i| {
   1323             if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue;
   1324 
   1325             const field_align = a: {
   1326                 if (field.abi_align == 0) {
   1327                     break :a field.ty.abiAlignment(target);
   1328                 } else {
   1329                     break :a field.abi_align;
   1330                 }
   1331             };
   1332             const field_size = field.ty.abiSize(target);
   1333             if (field_size > payload_size) {
   1334                 payload_size = field_size;
   1335                 biggest_field = @intCast(u32, i);
   1336             }
   1337             if (field_align > payload_align) {
   1338                 payload_align = field_align;
   1339                 most_aligned_field = @intCast(u32, i);
   1340                 most_aligned_field_size = field_size;
   1341             }
   1342         }
   1343         payload_align = @maximum(payload_align, 1);
   1344         if (!have_tag or fields.len <= 1) return .{
   1345             .abi_size = std.mem.alignForwardGeneric(u64, payload_size, payload_align),
   1346             .abi_align = payload_align,
   1347             .most_aligned_field = most_aligned_field,
   1348             .most_aligned_field_size = most_aligned_field_size,
   1349             .biggest_field = biggest_field,
   1350             .payload_size = payload_size,
   1351             .payload_align = payload_align,
   1352             .tag_align = 0,
   1353             .tag_size = 0,
   1354             .padding = 0,
   1355         };
   1356         // Put the tag before or after the payload depending on which one's
   1357         // alignment is greater.
   1358         const tag_size = u.tag_ty.abiSize(target);
   1359         const tag_align = @maximum(1, u.tag_ty.abiAlignment(target));
   1360         var size: u64 = 0;
   1361         var padding: u32 = undefined;
   1362         if (tag_align >= payload_align) {
   1363             // {Tag, Payload}
   1364             size += tag_size;
   1365             size = std.mem.alignForwardGeneric(u64, size, payload_align);
   1366             size += payload_size;
   1367             const prev_size = size;
   1368             size = std.mem.alignForwardGeneric(u64, size, tag_align);
   1369             padding = @intCast(u32, size - prev_size);
   1370         } else {
   1371             // {Payload, Tag}
   1372             size += payload_size;
   1373             size = std.mem.alignForwardGeneric(u64, size, tag_align);
   1374             size += tag_size;
   1375             const prev_size = size;
   1376             size = std.mem.alignForwardGeneric(u64, size, payload_align);
   1377             padding = @intCast(u32, size - prev_size);
   1378         }
   1379         return .{
   1380             .abi_size = size,
   1381             .abi_align = @maximum(tag_align, payload_align),
   1382             .most_aligned_field = most_aligned_field,
   1383             .most_aligned_field_size = most_aligned_field_size,
   1384             .biggest_field = biggest_field,
   1385             .payload_size = payload_size,
   1386             .payload_align = payload_align,
   1387             .tag_align = tag_align,
   1388             .tag_size = tag_size,
   1389             .padding = padding,
   1390         };
   1391     }
   1392 };
   1393 
   1394 pub const Opaque = struct {
   1395     /// The Decl that corresponds to the opaque itself.
   1396     owner_decl: Decl.Index,
   1397     /// Offset from `owner_decl`, points to the opaque decl AST node.
   1398     node_offset: i32,
   1399     /// Represents the declarations inside this opaque.
   1400     namespace: Namespace,
   1401 
   1402     pub fn srcLoc(self: Opaque, mod: *Module) SrcLoc {
   1403         const owner_decl = mod.declPtr(self.owner_decl);
   1404         return .{
   1405             .file_scope = owner_decl.getFileScope(),
   1406             .parent_decl_node = owner_decl.src_node,
   1407             .lazy = LazySrcLoc.nodeOffset(self.node_offset),
   1408         };
   1409     }
   1410 
   1411     pub fn getFullyQualifiedName(s: *Opaque, mod: *Module) ![:0]u8 {
   1412         return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod);
   1413     }
   1414 };
   1415 
   1416 /// Some extern function struct memory is owned by the Decl's TypedValue.Managed
   1417 /// arena allocator.
   1418 pub const ExternFn = struct {
   1419     /// The Decl that corresponds to the function itself.
   1420     owner_decl: Decl.Index,
   1421     /// Library name if specified.
   1422     /// For example `extern "c" fn write(...) usize` would have 'c' as library name.
   1423     /// Allocated with Module's allocator; outlives the ZIR code.
   1424     lib_name: ?[*:0]const u8,
   1425 
   1426     pub fn deinit(extern_fn: *ExternFn, gpa: Allocator) void {
   1427         if (extern_fn.lib_name) |lib_name| {
   1428             gpa.free(mem.sliceTo(lib_name, 0));
   1429         }
   1430     }
   1431 };
   1432 
   1433 /// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
   1434 /// Extern functions do not have this data structure; they are represented by `ExternFn`
   1435 /// instead.
   1436 pub const Fn = struct {
   1437     /// The Decl that corresponds to the function itself.
   1438     owner_decl: Decl.Index,
   1439     /// The ZIR instruction that is a function instruction. Use this to find
   1440     /// the body. We store this rather than the body directly so that when ZIR
   1441     /// is regenerated on update(), we can map this to the new corresponding
   1442     /// ZIR instruction.
   1443     zir_body_inst: Zir.Inst.Index,
   1444     /// If this is not null, this function is a generic function instantiation, and
   1445     /// there is a `TypedValue` here for each parameter of the function.
   1446     /// Non-comptime parameters are marked with a `generic_poison` for the value.
   1447     /// Non-anytype parameters are marked with a `generic_poison` for the type.
   1448     /// These never have .generic_poison for the Type
   1449     /// because the Type is needed to pass to `Type.eql` and for inserting comptime arguments
   1450     /// into the inst_map when analyzing the body of a generic function instantiation.
   1451     /// Instead, the is_anytype knowledge is communicated via `anytype_args`.
   1452     comptime_args: ?[*]TypedValue,
   1453     /// When comptime_args is null, this is undefined. Otherwise, this flags each
   1454     /// parameter and tells whether it is anytype.
   1455     /// TODO apply the same enhancement for param_names below to this field.
   1456     anytype_args: [*]bool,
   1457 
   1458     /// Prefer to use `getParamName` to access this because of the future improvement
   1459     /// we want to do mentioned in the TODO below.
   1460     /// Stored in gpa.
   1461     /// TODO: change param ZIR instructions to be embedded inside the function
   1462     /// ZIR instruction instead of before it, so that `zir_body_inst` can be used to
   1463     /// determine param names rather than redundantly storing them here.
   1464     param_names: []const [:0]const u8,
   1465 
   1466     /// Precomputed hash for monomorphed_funcs.
   1467     /// This is important because it may be accessed when resizing monomorphed_funcs
   1468     /// while this Fn has already been added to the set, but does not have the
   1469     /// owner_decl, comptime_args, or other fields populated yet.
   1470     hash: u64,
   1471 
   1472     /// Relative to owner Decl.
   1473     lbrace_line: u32,
   1474     /// Relative to owner Decl.
   1475     rbrace_line: u32,
   1476     lbrace_column: u16,
   1477     rbrace_column: u16,
   1478 
   1479     /// When a generic function is instantiated, this value is inherited from the
   1480     /// active Sema context. Importantly, this value is also updated when an existing
   1481     /// generic function instantiation is found and called.
   1482     branch_quota: u32,
   1483     state: Analysis,
   1484     is_cold: bool = false,
   1485     is_noinline: bool = false,
   1486     calls_or_awaits_errorable_fn: bool = false,
   1487 
   1488     /// Any inferred error sets that this function owns, both its own inferred error set and
   1489     /// inferred error sets of any inline/comptime functions called. Not to be confused
   1490     /// with inferred error sets of generic instantiations of this function, which are
   1491     /// *not* tracked here - they are tracked in the new `Fn` object created for the
   1492     /// instantiations.
   1493     inferred_error_sets: InferredErrorSetList = .{},
   1494 
   1495     pub const Analysis = enum {
   1496         queued,
   1497         /// This function intentionally only has ZIR generated because it is marked
   1498         /// inline, which means no runtime version of the function will be generated.
   1499         inline_only,
   1500         in_progress,
   1501         /// There will be a corresponding ErrorMsg in Module.failed_decls
   1502         sema_failure,
   1503         /// This Fn might be OK but it depends on another Decl which did not
   1504         /// successfully complete semantic analysis.
   1505         dependency_failure,
   1506         success,
   1507     };
   1508 
   1509     /// This struct is used to keep track of any dependencies related to functions instances
   1510     /// that return inferred error sets. Note that a function may be associated to
   1511     /// multiple different error sets, for example an inferred error set which
   1512     /// this function returns, but also any inferred error sets of called inline
   1513     /// or comptime functions.
   1514     pub const InferredErrorSet = struct {
   1515         /// The function from which this error set originates.
   1516         func: *Fn,
   1517 
   1518         /// All currently known errors that this error set contains. This includes
   1519         /// direct additions via `return error.Foo;`, and possibly also errors that
   1520         /// are returned from any dependent functions. When the inferred error set is
   1521         /// fully resolved, this map contains all the errors that the function might return.
   1522         errors: ErrorSet.NameMap = .{},
   1523 
   1524         /// Other inferred error sets which this inferred error set should include.
   1525         inferred_error_sets: std.AutoHashMapUnmanaged(*InferredErrorSet, void) = .{},
   1526 
   1527         /// Whether the function returned anyerror. This is true if either of
   1528         /// the dependent functions returns anyerror.
   1529         is_anyerror: bool = false,
   1530 
   1531         /// Whether this error set is already fully resolved. If true, resolving
   1532         /// can skip resolving any dependents of this inferred error set.
   1533         is_resolved: bool = false,
   1534 
   1535         pub fn addErrorSet(self: *InferredErrorSet, gpa: Allocator, err_set_ty: Type) !void {
   1536             switch (err_set_ty.tag()) {
   1537                 .error_set => {
   1538                     const names = err_set_ty.castTag(.error_set).?.data.names.keys();
   1539                     for (names) |name| {
   1540                         try self.errors.put(gpa, name, {});
   1541                     }
   1542                 },
   1543                 .error_set_single => {
   1544                     const name = err_set_ty.castTag(.error_set_single).?.data;
   1545                     try self.errors.put(gpa, name, {});
   1546                 },
   1547                 .error_set_inferred => {
   1548                     const ies = err_set_ty.castTag(.error_set_inferred).?.data;
   1549                     try self.inferred_error_sets.put(gpa, ies, {});
   1550                 },
   1551                 .error_set_merged => {
   1552                     const names = err_set_ty.castTag(.error_set_merged).?.data.keys();
   1553                     for (names) |name| {
   1554                         try self.errors.put(gpa, name, {});
   1555                     }
   1556                 },
   1557                 .anyerror => {
   1558                     self.is_anyerror = true;
   1559                 },
   1560                 else => unreachable,
   1561             }
   1562         }
   1563     };
   1564 
   1565     pub const InferredErrorSetList = std.SinglyLinkedList(InferredErrorSet);
   1566     pub const InferredErrorSetListNode = InferredErrorSetList.Node;
   1567 
   1568     pub fn deinit(func: *Fn, gpa: Allocator) void {
   1569         var it = func.inferred_error_sets.first;
   1570         while (it) |node| {
   1571             const next = node.next;
   1572             node.data.errors.deinit(gpa);
   1573             node.data.inferred_error_sets.deinit(gpa);
   1574             gpa.destroy(node);
   1575             it = next;
   1576         }
   1577 
   1578         for (func.param_names) |param_name| {
   1579             gpa.free(param_name);
   1580         }
   1581         gpa.free(func.param_names);
   1582     }
   1583 
   1584     pub fn getParamName(func: Fn, index: u32) [:0]const u8 {
   1585         // TODO rework ZIR of parameters so that this function looks up
   1586         // param names in ZIR instead of redundantly saving them into Fn.
   1587         // const zir = func.owner_decl.getFileScope().zir;
   1588         return func.param_names[index];
   1589     }
   1590 
   1591     pub fn hasInferredErrorSet(func: Fn, mod: *Module) bool {
   1592         const owner_decl = mod.declPtr(func.owner_decl);
   1593         const zir = owner_decl.getFileScope().zir;
   1594         const zir_tags = zir.instructions.items(.tag);
   1595         switch (zir_tags[func.zir_body_inst]) {
   1596             .func => return false,
   1597             .func_inferred => return true,
   1598             .func_fancy => {
   1599                 const inst_data = zir.instructions.items(.data)[func.zir_body_inst].pl_node;
   1600                 const extra = zir.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
   1601                 return extra.data.bits.is_inferred_error;
   1602             },
   1603             else => unreachable,
   1604         }
   1605     }
   1606 };
   1607 
   1608 pub const Var = struct {
   1609     /// if is_extern == true this is undefined
   1610     init: Value,
   1611     owner_decl: Decl.Index,
   1612 
   1613     /// Library name if specified.
   1614     /// For example `extern "c" var stderrp = ...` would have 'c' as library name.
   1615     /// Allocated with Module's allocator; outlives the ZIR code.
   1616     lib_name: ?[*:0]const u8,
   1617 
   1618     is_extern: bool,
   1619     is_mutable: bool,
   1620     is_threadlocal: bool,
   1621     is_weak_linkage: bool,
   1622 
   1623     pub fn deinit(variable: *Var, gpa: Allocator) void {
   1624         if (variable.lib_name) |lib_name| {
   1625             gpa.free(mem.sliceTo(lib_name, 0));
   1626         }
   1627     }
   1628 };
   1629 
   1630 pub const DeclAdapter = struct {
   1631     mod: *Module,
   1632 
   1633     pub fn hash(self: @This(), s: []const u8) u32 {
   1634         _ = self;
   1635         return @truncate(u32, std.hash.Wyhash.hash(0, s));
   1636     }
   1637 
   1638     pub fn eql(self: @This(), a: []const u8, b_decl_index: Decl.Index, b_index: usize) bool {
   1639         _ = b_index;
   1640         const b_decl = self.mod.declPtr(b_decl_index);
   1641         return mem.eql(u8, a, mem.sliceTo(b_decl.name, 0));
   1642     }
   1643 };
   1644 
   1645 /// The container that structs, enums, unions, and opaques have.
   1646 pub const Namespace = struct {
   1647     parent: ?*Namespace,
   1648     file_scope: *File,
   1649     /// Will be a struct, enum, union, or opaque.
   1650     ty: Type,
   1651     /// Direct children of the namespace. Used during an update to detect
   1652     /// which decls have been added/removed from source.
   1653     /// Declaration order is preserved via entry order.
   1654     /// Key memory is owned by `decl.name`.
   1655     /// Anonymous decls are not stored here; they are kept in `anon_decls` instead.
   1656     decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{},
   1657 
   1658     anon_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
   1659 
   1660     /// Key is usingnamespace Decl itself. To find the namespace being included,
   1661     /// the Decl Value has to be resolved as a Type which has a Namespace.
   1662     /// Value is whether the usingnamespace decl is marked `pub`.
   1663     usingnamespace_set: std.AutoHashMapUnmanaged(Decl.Index, bool) = .{},
   1664 
   1665     const DeclContext = struct {
   1666         module: *Module,
   1667 
   1668         pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 {
   1669             const decl = ctx.module.declPtr(decl_index);
   1670             return @truncate(u32, std.hash.Wyhash.hash(0, mem.sliceTo(decl.name, 0)));
   1671         }
   1672 
   1673         pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool {
   1674             _ = b_index;
   1675             const a_decl = ctx.module.declPtr(a_decl_index);
   1676             const b_decl = ctx.module.declPtr(b_decl_index);
   1677             const a_name = mem.sliceTo(a_decl.name, 0);
   1678             const b_name = mem.sliceTo(b_decl.name, 0);
   1679             return mem.eql(u8, a_name, b_name);
   1680         }
   1681     };
   1682 
   1683     pub fn deinit(ns: *Namespace, mod: *Module) void {
   1684         ns.destroyDecls(mod);
   1685         ns.* = undefined;
   1686     }
   1687 
   1688     pub fn destroyDecls(ns: *Namespace, mod: *Module) void {
   1689         const gpa = mod.gpa;
   1690 
   1691         log.debug("destroyDecls {*}", .{ns});
   1692 
   1693         var decls = ns.decls;
   1694         ns.decls = .{};
   1695 
   1696         var anon_decls = ns.anon_decls;
   1697         ns.anon_decls = .{};
   1698 
   1699         for (decls.keys()) |decl_index| {
   1700             mod.destroyDecl(decl_index);
   1701         }
   1702         decls.deinit(gpa);
   1703 
   1704         for (anon_decls.keys()) |key| {
   1705             mod.destroyDecl(key);
   1706         }
   1707         anon_decls.deinit(gpa);
   1708         ns.usingnamespace_set.deinit(gpa);
   1709     }
   1710 
   1711     pub fn deleteAllDecls(
   1712         ns: *Namespace,
   1713         mod: *Module,
   1714         outdated_decls: ?*std.AutoArrayHashMap(Decl.Index, void),
   1715     ) !void {
   1716         const gpa = mod.gpa;
   1717 
   1718         log.debug("deleteAllDecls {*}", .{ns});
   1719 
   1720         var decls = ns.decls;
   1721         ns.decls = .{};
   1722 
   1723         var anon_decls = ns.anon_decls;
   1724         ns.anon_decls = .{};
   1725 
   1726         // TODO rework this code to not panic on OOM.
   1727         // (might want to coordinate with the clearDecl function)
   1728 
   1729         for (decls.keys()) |child_decl| {
   1730             mod.clearDecl(child_decl, outdated_decls) catch @panic("out of memory");
   1731             mod.destroyDecl(child_decl);
   1732         }
   1733         decls.deinit(gpa);
   1734 
   1735         for (anon_decls.keys()) |child_decl| {
   1736             mod.clearDecl(child_decl, outdated_decls) catch @panic("out of memory");
   1737             mod.destroyDecl(child_decl);
   1738         }
   1739         anon_decls.deinit(gpa);
   1740 
   1741         ns.usingnamespace_set.deinit(gpa);
   1742     }
   1743 
   1744     // This renders e.g. "std.fs.Dir.OpenOptions"
   1745     pub fn renderFullyQualifiedName(
   1746         ns: Namespace,
   1747         mod: *Module,
   1748         name: []const u8,
   1749         writer: anytype,
   1750     ) @TypeOf(writer).Error!void {
   1751         if (ns.parent) |parent| {
   1752             const decl_index = ns.getDeclIndex();
   1753             const decl = mod.declPtr(decl_index);
   1754             try parent.renderFullyQualifiedName(mod, mem.sliceTo(decl.name, 0), writer);
   1755         } else {
   1756             try ns.file_scope.renderFullyQualifiedName(writer);
   1757         }
   1758         if (name.len != 0) {
   1759             try writer.writeAll(".");
   1760             try writer.writeAll(name);
   1761         }
   1762     }
   1763 
   1764     /// This renders e.g. "std/fs.zig:Dir.OpenOptions"
   1765     pub fn renderFullyQualifiedDebugName(
   1766         ns: Namespace,
   1767         mod: *Module,
   1768         name: []const u8,
   1769         writer: anytype,
   1770     ) @TypeOf(writer).Error!void {
   1771         var separator_char: u8 = '.';
   1772         if (ns.parent) |parent| {
   1773             const decl_index = ns.getDeclIndex();
   1774             const decl = mod.declPtr(decl_index);
   1775             try parent.renderFullyQualifiedDebugName(mod, mem.sliceTo(decl.name, 0), writer);
   1776         } else {
   1777             try ns.file_scope.renderFullyQualifiedDebugName(writer);
   1778             separator_char = ':';
   1779         }
   1780         if (name.len != 0) {
   1781             try writer.writeByte(separator_char);
   1782             try writer.writeAll(name);
   1783         }
   1784     }
   1785 
   1786     pub fn getDeclIndex(ns: Namespace) Decl.Index {
   1787         return ns.ty.getOwnerDecl();
   1788     }
   1789 };
   1790 
   1791 pub const File = struct {
   1792     /// The Decl of the struct that represents this File.
   1793     root_decl: Decl.OptionalIndex,
   1794     status: enum {
   1795         never_loaded,
   1796         retryable_failure,
   1797         parse_failure,
   1798         astgen_failure,
   1799         success_zir,
   1800     },
   1801     source_loaded: bool,
   1802     tree_loaded: bool,
   1803     zir_loaded: bool,
   1804     /// Relative to the owning package's root_src_dir.
   1805     /// Memory is stored in gpa, owned by File.
   1806     sub_file_path: []const u8,
   1807     /// Whether this is populated depends on `source_loaded`.
   1808     source: [:0]const u8,
   1809     /// Whether this is populated depends on `status`.
   1810     stat: Cache.File.Stat,
   1811     /// Whether this is populated or not depends on `tree_loaded`.
   1812     tree: Ast,
   1813     /// Whether this is populated or not depends on `zir_loaded`.
   1814     zir: Zir,
   1815     /// Package that this file is a part of, managed externally.
   1816     pkg: *Package,
   1817 
   1818     /// Used by change detection algorithm, after astgen, contains the
   1819     /// set of decls that existed in the previous ZIR but not in the new one.
   1820     deleted_decls: std.ArrayListUnmanaged(Decl.Index) = .{},
   1821     /// Used by change detection algorithm, after astgen, contains the
   1822     /// set of decls that existed both in the previous ZIR and in the new one,
   1823     /// but their source code has been modified.
   1824     outdated_decls: std.ArrayListUnmanaged(Decl.Index) = .{},
   1825 
   1826     /// The most recent successful ZIR for this file, with no errors.
   1827     /// This is only populated when a previously successful ZIR
   1828     /// newly introduces compile errors during an update. When ZIR is
   1829     /// successful, this field is unloaded.
   1830     prev_zir: ?*Zir = null,
   1831 
   1832     pub fn unload(file: *File, gpa: Allocator) void {
   1833         file.unloadTree(gpa);
   1834         file.unloadSource(gpa);
   1835         file.unloadZir(gpa);
   1836     }
   1837 
   1838     pub fn unloadTree(file: *File, gpa: Allocator) void {
   1839         if (file.tree_loaded) {
   1840             file.tree_loaded = false;
   1841             file.tree.deinit(gpa);
   1842         }
   1843     }
   1844 
   1845     pub fn unloadSource(file: *File, gpa: Allocator) void {
   1846         if (file.source_loaded) {
   1847             file.source_loaded = false;
   1848             gpa.free(file.source);
   1849         }
   1850     }
   1851 
   1852     pub fn unloadZir(file: *File, gpa: Allocator) void {
   1853         if (file.zir_loaded) {
   1854             file.zir_loaded = false;
   1855             file.zir.deinit(gpa);
   1856         }
   1857     }
   1858 
   1859     pub fn deinit(file: *File, mod: *Module) void {
   1860         const gpa = mod.gpa;
   1861         log.debug("deinit File {s}", .{file.sub_file_path});
   1862         file.deleted_decls.deinit(gpa);
   1863         file.outdated_decls.deinit(gpa);
   1864         if (file.root_decl.unwrap()) |root_decl| {
   1865             mod.destroyDecl(root_decl);
   1866         }
   1867         gpa.free(file.sub_file_path);
   1868         file.unload(gpa);
   1869         if (file.prev_zir) |prev_zir| {
   1870             prev_zir.deinit(gpa);
   1871             gpa.destroy(prev_zir);
   1872         }
   1873         file.* = undefined;
   1874     }
   1875 
   1876     pub const Source = struct {
   1877         bytes: [:0]const u8,
   1878         stat: Cache.File.Stat,
   1879     };
   1880 
   1881     pub fn getSource(file: *File, gpa: Allocator) !Source {
   1882         if (file.source_loaded) return Source{
   1883             .bytes = file.source,
   1884             .stat = file.stat,
   1885         };
   1886 
   1887         const root_dir_path = file.pkg.root_src_directory.path orelse ".";
   1888         log.debug("File.getSource, not cached. pkgdir={s} sub_file_path={s}", .{
   1889             root_dir_path, file.sub_file_path,
   1890         });
   1891 
   1892         // Keep track of inode, file size, mtime, hash so we can detect which files
   1893         // have been modified when an incremental update is requested.
   1894         var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
   1895         defer f.close();
   1896 
   1897         const stat = try f.stat();
   1898 
   1899         if (stat.size > std.math.maxInt(u32))
   1900             return error.FileTooBig;
   1901 
   1902         const source = try gpa.allocSentinel(u8, @intCast(usize, stat.size), 0);
   1903         defer if (!file.source_loaded) gpa.free(source);
   1904         const amt = try f.readAll(source);
   1905         if (amt != stat.size)
   1906             return error.UnexpectedEndOfFile;
   1907 
   1908         // Here we do not modify stat fields because this function is the one
   1909         // used for error reporting. We need to keep the stat fields stale so that
   1910         // astGenFile can know to regenerate ZIR.
   1911 
   1912         file.source = source;
   1913         file.source_loaded = true;
   1914         return Source{
   1915             .bytes = source,
   1916             .stat = .{
   1917                 .size = stat.size,
   1918                 .inode = stat.inode,
   1919                 .mtime = stat.mtime,
   1920             },
   1921         };
   1922     }
   1923 
   1924     pub fn getTree(file: *File, gpa: Allocator) !*const Ast {
   1925         if (file.tree_loaded) return &file.tree;
   1926 
   1927         const source = try file.getSource(gpa);
   1928         file.tree = try std.zig.parse(gpa, source.bytes);
   1929         file.tree_loaded = true;
   1930         return &file.tree;
   1931     }
   1932 
   1933     pub fn destroy(file: *File, mod: *Module) void {
   1934         const gpa = mod.gpa;
   1935         file.deinit(mod);
   1936         gpa.destroy(file);
   1937     }
   1938 
   1939     pub fn renderFullyQualifiedName(file: File, writer: anytype) !void {
   1940         // Convert all the slashes into dots and truncate the extension.
   1941         const ext = std.fs.path.extension(file.sub_file_path);
   1942         const noext = file.sub_file_path[0 .. file.sub_file_path.len - ext.len];
   1943         for (noext) |byte| switch (byte) {
   1944             '/', '\\' => try writer.writeByte('.'),
   1945             else => try writer.writeByte(byte),
   1946         };
   1947     }
   1948 
   1949     pub fn renderFullyQualifiedDebugName(file: File, writer: anytype) !void {
   1950         for (file.sub_file_path) |byte| switch (byte) {
   1951             '/', '\\' => try writer.writeByte('/'),
   1952             else => try writer.writeByte(byte),
   1953         };
   1954     }
   1955 
   1956     pub fn fullyQualifiedNameZ(file: File, gpa: Allocator) ![:0]u8 {
   1957         var buf = std.ArrayList(u8).init(gpa);
   1958         defer buf.deinit();
   1959         try file.renderFullyQualifiedName(buf.writer());
   1960         return buf.toOwnedSliceSentinel(0);
   1961     }
   1962 
   1963     /// Returns the full path to this file relative to its package.
   1964     pub fn fullPath(file: File, ally: Allocator) ![]u8 {
   1965         return file.pkg.root_src_directory.join(ally, &[_][]const u8{file.sub_file_path});
   1966     }
   1967 
   1968     /// Returns the full path to this file relative to its package.
   1969     pub fn fullPathZ(file: File, ally: Allocator) ![:0]u8 {
   1970         return file.pkg.root_src_directory.joinZ(ally, &[_][]const u8{file.sub_file_path});
   1971     }
   1972 
   1973     pub fn dumpSrc(file: *File, src: LazySrcLoc) void {
   1974         const loc = std.zig.findLineColumn(file.source.bytes, src);
   1975         std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
   1976     }
   1977 
   1978     pub fn okToReportErrors(file: File) bool {
   1979         return switch (file.status) {
   1980             .parse_failure, .astgen_failure => false,
   1981             else => true,
   1982         };
   1983     }
   1984 };
   1985 
   1986 /// Represents the contents of a file loaded with `@embedFile`.
   1987 pub const EmbedFile = struct {
   1988     /// Relative to the owning package's root_src_dir.
   1989     /// Memory is stored in gpa, owned by EmbedFile.
   1990     sub_file_path: []const u8,
   1991     bytes: [:0]const u8,
   1992     stat: Cache.File.Stat,
   1993     /// Package that this file is a part of, managed externally.
   1994     pkg: *Package,
   1995     /// The Decl that was created from the `@embedFile` to own this resource.
   1996     /// This is how zig knows what other Decl objects to invalidate if the file
   1997     /// changes on disk.
   1998     owner_decl: Decl.Index,
   1999 
   2000     fn destroy(embed_file: *EmbedFile, mod: *Module) void {
   2001         const gpa = mod.gpa;
   2002         gpa.free(embed_file.sub_file_path);
   2003         gpa.free(embed_file.bytes);
   2004         gpa.destroy(embed_file);
   2005     }
   2006 };
   2007 
   2008 /// This struct holds data necessary to construct API-facing `AllErrors.Message`.
   2009 /// Its memory is managed with the general purpose allocator so that they
   2010 /// can be created and destroyed in response to incremental updates.
   2011 /// In some cases, the File could have been inferred from where the ErrorMsg
   2012 /// is stored. For example, if it is stored in Module.failed_decls, then the File
   2013 /// would be determined by the Decl Scope. However, the data structure contains the field
   2014 /// anyway so that `ErrorMsg` can be reused for error notes, which may be in a different
   2015 /// file than the parent error message. It also simplifies processing of error messages.
   2016 pub const ErrorMsg = struct {
   2017     src_loc: SrcLoc,
   2018     msg: []const u8,
   2019     notes: []ErrorMsg = &.{},
   2020 
   2021     pub fn create(
   2022         gpa: Allocator,
   2023         src_loc: SrcLoc,
   2024         comptime format: []const u8,
   2025         args: anytype,
   2026     ) !*ErrorMsg {
   2027         const err_msg = try gpa.create(ErrorMsg);
   2028         errdefer gpa.destroy(err_msg);
   2029         err_msg.* = try init(gpa, src_loc, format, args);
   2030         return err_msg;
   2031     }
   2032 
   2033     /// Assumes the ErrorMsg struct and msg were both allocated with `gpa`,
   2034     /// as well as all notes.
   2035     pub fn destroy(err_msg: *ErrorMsg, gpa: Allocator) void {
   2036         err_msg.deinit(gpa);
   2037         gpa.destroy(err_msg);
   2038     }
   2039 
   2040     pub fn init(
   2041         gpa: Allocator,
   2042         src_loc: SrcLoc,
   2043         comptime format: []const u8,
   2044         args: anytype,
   2045     ) !ErrorMsg {
   2046         return ErrorMsg{
   2047             .src_loc = src_loc,
   2048             .msg = try std.fmt.allocPrint(gpa, format, args),
   2049         };
   2050     }
   2051 
   2052     pub fn deinit(err_msg: *ErrorMsg, gpa: Allocator) void {
   2053         for (err_msg.notes) |*note| {
   2054             note.deinit(gpa);
   2055         }
   2056         gpa.free(err_msg.notes);
   2057         gpa.free(err_msg.msg);
   2058         err_msg.* = undefined;
   2059     }
   2060 };
   2061 
   2062 /// Canonical reference to a position within a source file.
   2063 pub const SrcLoc = struct {
   2064     file_scope: *File,
   2065     /// Might be 0 depending on tag of `lazy`.
   2066     parent_decl_node: Ast.Node.Index,
   2067     /// Relative to `parent_decl_node`.
   2068     lazy: LazySrcLoc,
   2069 
   2070     pub fn declSrcToken(src_loc: SrcLoc) Ast.TokenIndex {
   2071         const tree = src_loc.file_scope.tree;
   2072         return tree.firstToken(src_loc.parent_decl_node);
   2073     }
   2074 
   2075     pub fn declRelativeToNodeIndex(src_loc: SrcLoc, offset: i32) Ast.TokenIndex {
   2076         return @bitCast(Ast.Node.Index, offset + @bitCast(i32, src_loc.parent_decl_node));
   2077     }
   2078 
   2079     pub fn byteOffset(src_loc: SrcLoc, gpa: Allocator) !u32 {
   2080         switch (src_loc.lazy) {
   2081             .unneeded => unreachable,
   2082             .entire_file => return 0,
   2083 
   2084             .byte_abs => |byte_index| return byte_index,
   2085 
   2086             .token_abs => |tok_index| {
   2087                 const tree = try src_loc.file_scope.getTree(gpa);
   2088                 const token_starts = tree.tokens.items(.start);
   2089                 return token_starts[tok_index];
   2090             },
   2091             .node_abs => |node| {
   2092                 const tree = try src_loc.file_scope.getTree(gpa);
   2093                 const token_starts = tree.tokens.items(.start);
   2094                 const tok_index = tree.firstToken(node);
   2095                 return token_starts[tok_index];
   2096             },
   2097             .byte_offset => |byte_off| {
   2098                 const tree = try src_loc.file_scope.getTree(gpa);
   2099                 const token_starts = tree.tokens.items(.start);
   2100                 return token_starts[src_loc.declSrcToken()] + byte_off;
   2101             },
   2102             .token_offset => |tok_off| {
   2103                 const tree = try src_loc.file_scope.getTree(gpa);
   2104                 const tok_index = src_loc.declSrcToken() + tok_off;
   2105                 const token_starts = tree.tokens.items(.start);
   2106                 return token_starts[tok_index];
   2107             },
   2108             .node_offset => |traced_off| {
   2109                 const node_off = traced_off.x;
   2110                 const tree = try src_loc.file_scope.getTree(gpa);
   2111                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2112                 assert(src_loc.file_scope.tree_loaded);
   2113                 const main_tokens = tree.nodes.items(.main_token);
   2114                 const tok_index = main_tokens[node];
   2115                 const token_starts = tree.tokens.items(.start);
   2116                 return token_starts[tok_index];
   2117             },
   2118             .node_offset_bin_op => |node_off| {
   2119                 const tree = try src_loc.file_scope.getTree(gpa);
   2120                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2121                 assert(src_loc.file_scope.tree_loaded);
   2122                 const main_tokens = tree.nodes.items(.main_token);
   2123                 const tok_index = main_tokens[node];
   2124                 const token_starts = tree.tokens.items(.start);
   2125                 return token_starts[tok_index];
   2126             },
   2127             .node_offset_back2tok => |node_off| {
   2128                 const tree = try src_loc.file_scope.getTree(gpa);
   2129                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2130                 const tok_index = tree.firstToken(node) - 2;
   2131                 const token_starts = tree.tokens.items(.start);
   2132                 return token_starts[tok_index];
   2133             },
   2134             .node_offset_var_decl_ty => |node_off| {
   2135                 const tree = try src_loc.file_scope.getTree(gpa);
   2136                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2137                 const node_tags = tree.nodes.items(.tag);
   2138                 const full = switch (node_tags[node]) {
   2139                     .global_var_decl => tree.globalVarDecl(node),
   2140                     .local_var_decl => tree.localVarDecl(node),
   2141                     .simple_var_decl => tree.simpleVarDecl(node),
   2142                     .aligned_var_decl => tree.alignedVarDecl(node),
   2143                     else => unreachable,
   2144                 };
   2145                 const tok_index = if (full.ast.type_node != 0) blk: {
   2146                     const main_tokens = tree.nodes.items(.main_token);
   2147                     break :blk main_tokens[full.ast.type_node];
   2148                 } else blk: {
   2149                     break :blk full.ast.mut_token + 1; // the name token
   2150                 };
   2151                 const token_starts = tree.tokens.items(.start);
   2152                 return token_starts[tok_index];
   2153             },
   2154             .node_offset_builtin_call_arg0 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 0),
   2155             .node_offset_builtin_call_arg1 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 1),
   2156             .node_offset_builtin_call_arg2 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 2),
   2157             .node_offset_builtin_call_arg3 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 3),
   2158             .node_offset_builtin_call_arg4 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 4),
   2159             .node_offset_builtin_call_arg5 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 5),
   2160             .node_offset_array_access_index => |node_off| {
   2161                 const tree = try src_loc.file_scope.getTree(gpa);
   2162                 const node_datas = tree.nodes.items(.data);
   2163                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2164                 const main_tokens = tree.nodes.items(.main_token);
   2165                 const tok_index = main_tokens[node_datas[node].rhs];
   2166                 const token_starts = tree.tokens.items(.start);
   2167                 return token_starts[tok_index];
   2168             },
   2169             .node_offset_slice_sentinel => |node_off| {
   2170                 const tree = try src_loc.file_scope.getTree(gpa);
   2171                 const node_tags = tree.nodes.items(.tag);
   2172                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2173                 const full = switch (node_tags[node]) {
   2174                     .slice_open => tree.sliceOpen(node),
   2175                     .slice => tree.slice(node),
   2176                     .slice_sentinel => tree.sliceSentinel(node),
   2177                     else => unreachable,
   2178                 };
   2179                 const main_tokens = tree.nodes.items(.main_token);
   2180                 const tok_index = main_tokens[full.ast.sentinel];
   2181                 const token_starts = tree.tokens.items(.start);
   2182                 return token_starts[tok_index];
   2183             },
   2184             .node_offset_call_func => |node_off| {
   2185                 const tree = try src_loc.file_scope.getTree(gpa);
   2186                 const node_tags = tree.nodes.items(.tag);
   2187                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2188                 var params: [1]Ast.Node.Index = undefined;
   2189                 const full = switch (node_tags[node]) {
   2190                     .call_one,
   2191                     .call_one_comma,
   2192                     .async_call_one,
   2193                     .async_call_one_comma,
   2194                     => tree.callOne(&params, node),
   2195 
   2196                     .call,
   2197                     .call_comma,
   2198                     .async_call,
   2199                     .async_call_comma,
   2200                     => tree.callFull(node),
   2201 
   2202                     else => unreachable,
   2203                 };
   2204                 const main_tokens = tree.nodes.items(.main_token);
   2205                 const tok_index = main_tokens[full.ast.fn_expr];
   2206                 const token_starts = tree.tokens.items(.start);
   2207                 return token_starts[tok_index];
   2208             },
   2209             .node_offset_field_name => |node_off| {
   2210                 const tree = try src_loc.file_scope.getTree(gpa);
   2211                 const node_datas = tree.nodes.items(.data);
   2212                 const node_tags = tree.nodes.items(.tag);
   2213                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2214                 const tok_index = switch (node_tags[node]) {
   2215                     .field_access => node_datas[node].rhs,
   2216                     else => tree.firstToken(node) - 2,
   2217                 };
   2218                 const token_starts = tree.tokens.items(.start);
   2219                 return token_starts[tok_index];
   2220             },
   2221             .node_offset_deref_ptr => |node_off| {
   2222                 const tree = try src_loc.file_scope.getTree(gpa);
   2223                 const node_datas = tree.nodes.items(.data);
   2224                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2225                 const tok_index = node_datas[node].lhs;
   2226                 const token_starts = tree.tokens.items(.start);
   2227                 return token_starts[tok_index];
   2228             },
   2229             .node_offset_asm_source => |node_off| {
   2230                 const tree = try src_loc.file_scope.getTree(gpa);
   2231                 const node_tags = tree.nodes.items(.tag);
   2232                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2233                 const full = switch (node_tags[node]) {
   2234                     .asm_simple => tree.asmSimple(node),
   2235                     .@"asm" => tree.asmFull(node),
   2236                     else => unreachable,
   2237                 };
   2238                 const main_tokens = tree.nodes.items(.main_token);
   2239                 const tok_index = main_tokens[full.ast.template];
   2240                 const token_starts = tree.tokens.items(.start);
   2241                 return token_starts[tok_index];
   2242             },
   2243             .node_offset_asm_ret_ty => |node_off| {
   2244                 const tree = try src_loc.file_scope.getTree(gpa);
   2245                 const node_tags = tree.nodes.items(.tag);
   2246                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2247                 const full = switch (node_tags[node]) {
   2248                     .asm_simple => tree.asmSimple(node),
   2249                     .@"asm" => tree.asmFull(node),
   2250                     else => unreachable,
   2251                 };
   2252                 const asm_output = full.outputs[0];
   2253                 const node_datas = tree.nodes.items(.data);
   2254                 const ret_ty_node = node_datas[asm_output].lhs;
   2255                 const main_tokens = tree.nodes.items(.main_token);
   2256                 const tok_index = main_tokens[ret_ty_node];
   2257                 const token_starts = tree.tokens.items(.start);
   2258                 return token_starts[tok_index];
   2259             },
   2260 
   2261             .node_offset_for_cond, .node_offset_if_cond => |node_off| {
   2262                 const tree = try src_loc.file_scope.getTree(gpa);
   2263                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2264                 const node_tags = tree.nodes.items(.tag);
   2265                 const src_node = switch (node_tags[node]) {
   2266                     .if_simple => tree.ifSimple(node).ast.cond_expr,
   2267                     .@"if" => tree.ifFull(node).ast.cond_expr,
   2268                     .while_simple => tree.whileSimple(node).ast.cond_expr,
   2269                     .while_cont => tree.whileCont(node).ast.cond_expr,
   2270                     .@"while" => tree.whileFull(node).ast.cond_expr,
   2271                     .for_simple => tree.forSimple(node).ast.cond_expr,
   2272                     .@"for" => tree.forFull(node).ast.cond_expr,
   2273                     else => unreachable,
   2274                 };
   2275                 const main_tokens = tree.nodes.items(.main_token);
   2276                 const tok_index = main_tokens[src_node];
   2277                 const token_starts = tree.tokens.items(.start);
   2278                 return token_starts[tok_index];
   2279             },
   2280             .node_offset_bin_lhs => |node_off| {
   2281                 const tree = try src_loc.file_scope.getTree(gpa);
   2282                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2283                 const node_datas = tree.nodes.items(.data);
   2284                 const src_node = node_datas[node].lhs;
   2285                 const main_tokens = tree.nodes.items(.main_token);
   2286                 const tok_index = main_tokens[src_node];
   2287                 const token_starts = tree.tokens.items(.start);
   2288                 return token_starts[tok_index];
   2289             },
   2290             .node_offset_bin_rhs => |node_off| {
   2291                 const tree = try src_loc.file_scope.getTree(gpa);
   2292                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2293                 const node_datas = tree.nodes.items(.data);
   2294                 const src_node = node_datas[node].rhs;
   2295                 const main_tokens = tree.nodes.items(.main_token);
   2296                 const tok_index = main_tokens[src_node];
   2297                 const token_starts = tree.tokens.items(.start);
   2298                 return token_starts[tok_index];
   2299             },
   2300 
   2301             .node_offset_switch_operand => |node_off| {
   2302                 const tree = try src_loc.file_scope.getTree(gpa);
   2303                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2304                 const node_datas = tree.nodes.items(.data);
   2305                 const src_node = node_datas[node].lhs;
   2306                 const main_tokens = tree.nodes.items(.main_token);
   2307                 const tok_index = main_tokens[src_node];
   2308                 const token_starts = tree.tokens.items(.start);
   2309                 return token_starts[tok_index];
   2310             },
   2311 
   2312             .node_offset_switch_special_prong => |node_off| {
   2313                 const tree = try src_loc.file_scope.getTree(gpa);
   2314                 const switch_node = src_loc.declRelativeToNodeIndex(node_off);
   2315                 const node_datas = tree.nodes.items(.data);
   2316                 const node_tags = tree.nodes.items(.tag);
   2317                 const main_tokens = tree.nodes.items(.main_token);
   2318                 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
   2319                 const case_nodes = tree.extra_data[extra.start..extra.end];
   2320                 for (case_nodes) |case_node| {
   2321                     const case = switch (node_tags[case_node]) {
   2322                         .switch_case_one => tree.switchCaseOne(case_node),
   2323                         .switch_case => tree.switchCase(case_node),
   2324                         else => unreachable,
   2325                     };
   2326                     const is_special = (case.ast.values.len == 0) or
   2327                         (case.ast.values.len == 1 and
   2328                         node_tags[case.ast.values[0]] == .identifier and
   2329                         mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"));
   2330                     if (!is_special) continue;
   2331 
   2332                     const tok_index = main_tokens[case_node];
   2333                     const token_starts = tree.tokens.items(.start);
   2334                     return token_starts[tok_index];
   2335                 } else unreachable;
   2336             },
   2337 
   2338             .node_offset_switch_range => |node_off| {
   2339                 const tree = try src_loc.file_scope.getTree(gpa);
   2340                 const switch_node = src_loc.declRelativeToNodeIndex(node_off);
   2341                 const node_datas = tree.nodes.items(.data);
   2342                 const node_tags = tree.nodes.items(.tag);
   2343                 const main_tokens = tree.nodes.items(.main_token);
   2344                 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
   2345                 const case_nodes = tree.extra_data[extra.start..extra.end];
   2346                 for (case_nodes) |case_node| {
   2347                     const case = switch (node_tags[case_node]) {
   2348                         .switch_case_one => tree.switchCaseOne(case_node),
   2349                         .switch_case => tree.switchCase(case_node),
   2350                         else => unreachable,
   2351                     };
   2352                     const is_special = (case.ast.values.len == 0) or
   2353                         (case.ast.values.len == 1 and
   2354                         node_tags[case.ast.values[0]] == .identifier and
   2355                         mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"));
   2356                     if (is_special) continue;
   2357 
   2358                     for (case.ast.values) |item_node| {
   2359                         if (node_tags[item_node] == .switch_range) {
   2360                             const tok_index = main_tokens[item_node];
   2361                             const token_starts = tree.tokens.items(.start);
   2362                             return token_starts[tok_index];
   2363                         }
   2364                     }
   2365                 } else unreachable;
   2366             },
   2367 
   2368             .node_offset_fn_type_cc => |node_off| {
   2369                 const tree = try src_loc.file_scope.getTree(gpa);
   2370                 const node_datas = tree.nodes.items(.data);
   2371                 const node_tags = tree.nodes.items(.tag);
   2372                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2373                 var params: [1]Ast.Node.Index = undefined;
   2374                 const full = switch (node_tags[node]) {
   2375                     .fn_proto_simple => tree.fnProtoSimple(&params, node),
   2376                     .fn_proto_multi => tree.fnProtoMulti(node),
   2377                     .fn_proto_one => tree.fnProtoOne(&params, node),
   2378                     .fn_proto => tree.fnProto(node),
   2379                     .fn_decl => switch (node_tags[node_datas[node].lhs]) {
   2380                         .fn_proto_simple => tree.fnProtoSimple(&params, node_datas[node].lhs),
   2381                         .fn_proto_multi => tree.fnProtoMulti(node_datas[node].lhs),
   2382                         .fn_proto_one => tree.fnProtoOne(&params, node_datas[node].lhs),
   2383                         .fn_proto => tree.fnProto(node_datas[node].lhs),
   2384                         else => unreachable,
   2385                     },
   2386                     else => unreachable,
   2387                 };
   2388                 const main_tokens = tree.nodes.items(.main_token);
   2389                 const tok_index = main_tokens[full.ast.callconv_expr];
   2390                 const token_starts = tree.tokens.items(.start);
   2391                 return token_starts[tok_index];
   2392             },
   2393 
   2394             .node_offset_fn_type_ret_ty => |node_off| {
   2395                 const tree = try src_loc.file_scope.getTree(gpa);
   2396                 const node_tags = tree.nodes.items(.tag);
   2397                 const node = src_loc.declRelativeToNodeIndex(node_off);
   2398                 var params: [1]Ast.Node.Index = undefined;
   2399                 const full = switch (node_tags[node]) {
   2400                     .fn_proto_simple => tree.fnProtoSimple(&params, node),
   2401                     .fn_proto_multi => tree.fnProtoMulti(node),
   2402                     .fn_proto_one => tree.fnProtoOne(&params, node),
   2403                     .fn_proto => tree.fnProto(node),
   2404                     else => unreachable,
   2405                 };
   2406                 const main_tokens = tree.nodes.items(.main_token);
   2407                 const tok_index = main_tokens[full.ast.return_type];
   2408                 const token_starts = tree.tokens.items(.start);
   2409                 return token_starts[tok_index];
   2410             },
   2411 
   2412             .node_offset_anyframe_type => |node_off| {
   2413                 const tree = try src_loc.file_scope.getTree(gpa);
   2414                 const node_datas = tree.nodes.items(.data);
   2415                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   2416                 const node = node_datas[parent_node].rhs;
   2417                 const main_tokens = tree.nodes.items(.main_token);
   2418                 const tok_index = main_tokens[node];
   2419                 const token_starts = tree.tokens.items(.start);
   2420                 return token_starts[tok_index];
   2421             },
   2422 
   2423             .node_offset_lib_name => |node_off| {
   2424                 const tree = try src_loc.file_scope.getTree(gpa);
   2425                 const node_datas = tree.nodes.items(.data);
   2426                 const node_tags = tree.nodes.items(.tag);
   2427                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   2428                 var params: [1]Ast.Node.Index = undefined;
   2429                 const full = switch (node_tags[parent_node]) {
   2430                     .fn_proto_simple => tree.fnProtoSimple(&params, parent_node),
   2431                     .fn_proto_multi => tree.fnProtoMulti(parent_node),
   2432                     .fn_proto_one => tree.fnProtoOne(&params, parent_node),
   2433                     .fn_proto => tree.fnProto(parent_node),
   2434                     .fn_decl => blk: {
   2435                         const fn_proto = node_datas[parent_node].lhs;
   2436                         break :blk switch (node_tags[fn_proto]) {
   2437                             .fn_proto_simple => tree.fnProtoSimple(&params, fn_proto),
   2438                             .fn_proto_multi => tree.fnProtoMulti(fn_proto),
   2439                             .fn_proto_one => tree.fnProtoOne(&params, fn_proto),
   2440                             .fn_proto => tree.fnProto(fn_proto),
   2441                             else => unreachable,
   2442                         };
   2443                     },
   2444                     else => unreachable,
   2445                 };
   2446                 const tok_index = full.lib_name.?;
   2447                 const token_starts = tree.tokens.items(.start);
   2448                 return token_starts[tok_index];
   2449             },
   2450 
   2451             .node_offset_array_type_len => |node_off| {
   2452                 const tree = try src_loc.file_scope.getTree(gpa);
   2453                 const node_tags = tree.nodes.items(.tag);
   2454                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   2455 
   2456                 const full: Ast.full.ArrayType = switch (node_tags[parent_node]) {
   2457                     .array_type => tree.arrayType(parent_node),
   2458                     .array_type_sentinel => tree.arrayTypeSentinel(parent_node),
   2459                     else => unreachable,
   2460                 };
   2461                 const node = full.ast.elem_count;
   2462                 const main_tokens = tree.nodes.items(.main_token);
   2463                 const tok_index = main_tokens[node];
   2464                 const token_starts = tree.tokens.items(.start);
   2465                 return token_starts[tok_index];
   2466             },
   2467             .node_offset_array_type_sentinel => |node_off| {
   2468                 const tree = try src_loc.file_scope.getTree(gpa);
   2469                 const node_tags = tree.nodes.items(.tag);
   2470                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   2471 
   2472                 const full: Ast.full.ArrayType = switch (node_tags[parent_node]) {
   2473                     .array_type => tree.arrayType(parent_node),
   2474                     .array_type_sentinel => tree.arrayTypeSentinel(parent_node),
   2475                     else => unreachable,
   2476                 };
   2477                 const node = full.ast.sentinel;
   2478                 const main_tokens = tree.nodes.items(.main_token);
   2479                 const tok_index = main_tokens[node];
   2480                 const token_starts = tree.tokens.items(.start);
   2481                 return token_starts[tok_index];
   2482             },
   2483             .node_offset_array_type_elem => |node_off| {
   2484                 const tree = try src_loc.file_scope.getTree(gpa);
   2485                 const node_tags = tree.nodes.items(.tag);
   2486                 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
   2487 
   2488                 const full: Ast.full.ArrayType = switch (node_tags[parent_node]) {
   2489                     .array_type => tree.arrayType(parent_node),
   2490                     .array_type_sentinel => tree.arrayTypeSentinel(parent_node),
   2491                     else => unreachable,
   2492                 };
   2493                 const node = full.ast.elem_type;
   2494                 const main_tokens = tree.nodes.items(.main_token);
   2495                 const tok_index = main_tokens[node];
   2496                 const token_starts = tree.tokens.items(.start);
   2497                 return token_starts[tok_index];
   2498             },
   2499         }
   2500     }
   2501 
   2502     pub fn byteOffsetBuiltinCallArg(
   2503         src_loc: SrcLoc,
   2504         gpa: Allocator,
   2505         node_off: i32,
   2506         arg_index: u32,
   2507     ) !u32 {
   2508         const tree = try src_loc.file_scope.getTree(gpa);
   2509         const node_datas = tree.nodes.items(.data);
   2510         const node_tags = tree.nodes.items(.tag);
   2511         const node = src_loc.declRelativeToNodeIndex(node_off);
   2512         const param = switch (node_tags[node]) {
   2513             .builtin_call_two, .builtin_call_two_comma => switch (arg_index) {
   2514                 0 => node_datas[node].lhs,
   2515                 1 => node_datas[node].rhs,
   2516                 else => unreachable,
   2517             },
   2518             .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + arg_index],
   2519             else => unreachable,
   2520         };
   2521         const main_tokens = tree.nodes.items(.main_token);
   2522         const tok_index = main_tokens[param];
   2523         const token_starts = tree.tokens.items(.start);
   2524         return token_starts[tok_index];
   2525     }
   2526 };
   2527 
   2528 /// This wraps a simple integer in debug builds so that later on we can find out
   2529 /// where in semantic analysis the value got set.
   2530 const TracedOffset = struct {
   2531     x: i32,
   2532     trace: std.debug.Trace = .{},
   2533 
   2534     const want_tracing = build_options.value_tracing;
   2535 };
   2536 
   2537 /// Resolving a source location into a byte offset may require doing work
   2538 /// that we would rather not do unless the error actually occurs.
   2539 /// Therefore we need a data structure that contains the information necessary
   2540 /// to lazily produce a `SrcLoc` as required.
   2541 /// Most of the offsets in this data structure are relative to the containing Decl.
   2542 /// This makes the source location resolve properly even when a Decl gets
   2543 /// shifted up or down in the file, as long as the Decl's contents itself
   2544 /// do not change.
   2545 pub const LazySrcLoc = union(enum) {
   2546     /// When this tag is set, the code that constructed this `LazySrcLoc` is asserting
   2547     /// that all code paths which would need to resolve the source location are
   2548     /// unreachable. If you are debugging this tag incorrectly being this value,
   2549     /// look into using reverse-continue with a memory watchpoint to see where the
   2550     /// value is being set to this tag.
   2551     unneeded,
   2552     /// Means the source location points to an entire file; not any particular
   2553     /// location within the file. `file_scope` union field will be active.
   2554     entire_file,
   2555     /// The source location points to a byte offset within a source file,
   2556     /// offset from 0. The source file is determined contextually.
   2557     /// Inside a `SrcLoc`, the `file_scope` union field will be active.
   2558     byte_abs: u32,
   2559     /// The source location points to a token within a source file,
   2560     /// offset from 0. The source file is determined contextually.
   2561     /// Inside a `SrcLoc`, the `file_scope` union field will be active.
   2562     token_abs: u32,
   2563     /// The source location points to an AST node within a source file,
   2564     /// offset from 0. The source file is determined contextually.
   2565     /// Inside a `SrcLoc`, the `file_scope` union field will be active.
   2566     node_abs: u32,
   2567     /// The source location points to a byte offset within a source file,
   2568     /// offset from the byte offset of the Decl within the file.
   2569     /// The Decl is determined contextually.
   2570     byte_offset: u32,
   2571     /// This data is the offset into the token list from the Decl token.
   2572     /// The Decl is determined contextually.
   2573     token_offset: u32,
   2574     /// The source location points to an AST node, which is this value offset
   2575     /// from its containing Decl node AST index.
   2576     /// The Decl is determined contextually.
   2577     node_offset: TracedOffset,
   2578     /// The source location points to two tokens left of the first token of an AST node,
   2579     /// which is this value offset from its containing Decl node AST index.
   2580     /// The Decl is determined contextually.
   2581     node_offset_back2tok: i32,
   2582     /// The source location points to a variable declaration type expression,
   2583     /// found by taking this AST node index offset from the containing
   2584     /// Decl AST node, which points to a variable declaration AST node. Next, navigate
   2585     /// to the type expression.
   2586     /// The Decl is determined contextually.
   2587     node_offset_var_decl_ty: i32,
   2588     /// The source location points to a for loop condition expression,
   2589     /// found by taking this AST node index offset from the containing
   2590     /// Decl AST node, which points to a for loop AST node. Next, navigate
   2591     /// to the condition expression.
   2592     /// The Decl is determined contextually.
   2593     node_offset_for_cond: i32,
   2594     /// The source location points to the first parameter of a builtin
   2595     /// function call, found by taking this AST node index offset from the containing
   2596     /// Decl AST node, which points to a builtin call AST node. Next, navigate
   2597     /// to the first parameter.
   2598     /// The Decl is determined contextually.
   2599     node_offset_builtin_call_arg0: i32,
   2600     /// Same as `node_offset_builtin_call_arg0` except arg index 1.
   2601     node_offset_builtin_call_arg1: i32,
   2602     node_offset_builtin_call_arg2: i32,
   2603     node_offset_builtin_call_arg3: i32,
   2604     node_offset_builtin_call_arg4: i32,
   2605     node_offset_builtin_call_arg5: i32,
   2606     /// The source location points to the index expression of an array access
   2607     /// expression, found by taking this AST node index offset from the containing
   2608     /// Decl AST node, which points to an array access AST node. Next, navigate
   2609     /// to the index expression.
   2610     /// The Decl is determined contextually.
   2611     node_offset_array_access_index: i32,
   2612     /// The source location points to the sentinel expression of a slice
   2613     /// expression, found by taking this AST node index offset from the containing
   2614     /// Decl AST node, which points to a slice AST node. Next, navigate
   2615     /// to the sentinel expression.
   2616     /// The Decl is determined contextually.
   2617     node_offset_slice_sentinel: i32,
   2618     /// The source location points to the callee expression of a function
   2619     /// call expression, found by taking this AST node index offset from the containing
   2620     /// Decl AST node, which points to a function call AST node. Next, navigate
   2621     /// to the callee expression.
   2622     /// The Decl is determined contextually.
   2623     node_offset_call_func: i32,
   2624     /// The payload is offset from the containing Decl AST node.
   2625     /// The source location points to the field name of:
   2626     ///  * a field access expression (`a.b`), or
   2627     ///  * the operand ("b" node) of a field initialization expression (`.a = b`)
   2628     /// The Decl is determined contextually.
   2629     node_offset_field_name: i32,
   2630     /// The source location points to the pointer of a pointer deref expression,
   2631     /// found by taking this AST node index offset from the containing
   2632     /// Decl AST node, which points to a pointer deref AST node. Next, navigate
   2633     /// to the pointer expression.
   2634     /// The Decl is determined contextually.
   2635     node_offset_deref_ptr: i32,
   2636     /// The source location points to the assembly source code of an inline assembly
   2637     /// expression, found by taking this AST node index offset from the containing
   2638     /// Decl AST node, which points to inline assembly AST node. Next, navigate
   2639     /// to the asm template source code.
   2640     /// The Decl is determined contextually.
   2641     node_offset_asm_source: i32,
   2642     /// The source location points to the return type of an inline assembly
   2643     /// expression, found by taking this AST node index offset from the containing
   2644     /// Decl AST node, which points to inline assembly AST node. Next, navigate
   2645     /// to the return type expression.
   2646     /// The Decl is determined contextually.
   2647     node_offset_asm_ret_ty: i32,
   2648     /// The source location points to the condition expression of an if
   2649     /// expression, found by taking this AST node index offset from the containing
   2650     /// Decl AST node, which points to an if expression AST node. Next, navigate
   2651     /// to the condition expression.
   2652     /// The Decl is determined contextually.
   2653     node_offset_if_cond: i32,
   2654     /// The source location points to a binary expression, such as `a + b`, found
   2655     /// by taking this AST node index offset from the containing Decl AST node.
   2656     /// The Decl is determined contextually.
   2657     node_offset_bin_op: i32,
   2658     /// The source location points to the LHS of a binary expression, found
   2659     /// by taking this AST node index offset from the containing Decl AST node,
   2660     /// which points to a binary expression AST node. Next, navigate to the LHS.
   2661     /// The Decl is determined contextually.
   2662     node_offset_bin_lhs: i32,
   2663     /// The source location points to the RHS of a binary expression, found
   2664     /// by taking this AST node index offset from the containing Decl AST node,
   2665     /// which points to a binary expression AST node. Next, navigate to the RHS.
   2666     /// The Decl is determined contextually.
   2667     node_offset_bin_rhs: i32,
   2668     /// The source location points to the operand of a switch expression, found
   2669     /// by taking this AST node index offset from the containing Decl AST node,
   2670     /// which points to a switch expression AST node. Next, navigate to the operand.
   2671     /// The Decl is determined contextually.
   2672     node_offset_switch_operand: i32,
   2673     /// The source location points to the else/`_` prong of a switch expression, found
   2674     /// by taking this AST node index offset from the containing Decl AST node,
   2675     /// which points to a switch expression AST node. Next, navigate to the else/`_` prong.
   2676     /// The Decl is determined contextually.
   2677     node_offset_switch_special_prong: i32,
   2678     /// The source location points to all the ranges of a switch expression, found
   2679     /// by taking this AST node index offset from the containing Decl AST node,
   2680     /// which points to a switch expression AST node. Next, navigate to any of the
   2681     /// range nodes. The error applies to all of them.
   2682     /// The Decl is determined contextually.
   2683     node_offset_switch_range: i32,
   2684     /// The source location points to the calling convention of a function type
   2685     /// expression, found by taking this AST node index offset from the containing
   2686     /// Decl AST node, which points to a function type AST node. Next, navigate to
   2687     /// the calling convention node.
   2688     /// The Decl is determined contextually.
   2689     node_offset_fn_type_cc: i32,
   2690     /// The source location points to the return type of a function type
   2691     /// expression, found by taking this AST node index offset from the containing
   2692     /// Decl AST node, which points to a function type AST node. Next, navigate to
   2693     /// the return type node.
   2694     /// The Decl is determined contextually.
   2695     node_offset_fn_type_ret_ty: i32,
   2696     /// The source location points to the type expression of an `anyframe->T`
   2697     /// expression, found by taking this AST node index offset from the containing
   2698     /// Decl AST node, which points to a `anyframe->T` expression AST node. Next, navigate
   2699     /// to the type expression.
   2700     /// The Decl is determined contextually.
   2701     node_offset_anyframe_type: i32,
   2702     /// The source location points to the string literal of `extern "foo"`, found
   2703     /// by taking this AST node index offset from the containing
   2704     /// Decl AST node, which points to a function prototype or variable declaration
   2705     /// expression AST node. Next, navigate to the string literal of the `extern "foo"`.
   2706     /// The Decl is determined contextually.
   2707     node_offset_lib_name: i32,
   2708     /// The source location points to the len expression of an `[N:S]T`
   2709     /// expression, found by taking this AST node index offset from the containing
   2710     /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
   2711     /// to the len expression.
   2712     /// The Decl is determined contextually.
   2713     node_offset_array_type_len: i32,
   2714     /// The source location points to the sentinel expression of an `[N:S]T`
   2715     /// expression, found by taking this AST node index offset from the containing
   2716     /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
   2717     /// to the sentinel expression.
   2718     /// The Decl is determined contextually.
   2719     node_offset_array_type_sentinel: i32,
   2720     /// The source location points to the elem expression of an `[N:S]T`
   2721     /// expression, found by taking this AST node index offset from the containing
   2722     /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
   2723     /// to the elem expression.
   2724     /// The Decl is determined contextually.
   2725     node_offset_array_type_elem: i32,
   2726 
   2727     pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
   2728 
   2729     noinline fn nodeOffsetDebug(node_offset: i32) LazySrcLoc {
   2730         var result: LazySrcLoc = .{ .node_offset = .{ .x = node_offset } };
   2731         result.node_offset.trace.addAddr(@returnAddress(), "init");
   2732         return result;
   2733     }
   2734 
   2735     fn nodeOffsetRelease(node_offset: i32) LazySrcLoc {
   2736         return .{ .node_offset = .{ .x = node_offset } };
   2737     }
   2738 
   2739     /// Upgrade to a `SrcLoc` based on the `Decl` provided.
   2740     pub fn toSrcLoc(lazy: LazySrcLoc, decl: *Decl) SrcLoc {
   2741         return switch (lazy) {
   2742             .unneeded,
   2743             .entire_file,
   2744             .byte_abs,
   2745             .token_abs,
   2746             .node_abs,
   2747             => .{
   2748                 .file_scope = decl.getFileScope(),
   2749                 .parent_decl_node = 0,
   2750                 .lazy = lazy,
   2751             },
   2752 
   2753             .byte_offset,
   2754             .token_offset,
   2755             .node_offset,
   2756             .node_offset_back2tok,
   2757             .node_offset_var_decl_ty,
   2758             .node_offset_for_cond,
   2759             .node_offset_builtin_call_arg0,
   2760             .node_offset_builtin_call_arg1,
   2761             .node_offset_builtin_call_arg2,
   2762             .node_offset_builtin_call_arg3,
   2763             .node_offset_builtin_call_arg4,
   2764             .node_offset_builtin_call_arg5,
   2765             .node_offset_array_access_index,
   2766             .node_offset_slice_sentinel,
   2767             .node_offset_call_func,
   2768             .node_offset_field_name,
   2769             .node_offset_deref_ptr,
   2770             .node_offset_asm_source,
   2771             .node_offset_asm_ret_ty,
   2772             .node_offset_if_cond,
   2773             .node_offset_bin_op,
   2774             .node_offset_bin_lhs,
   2775             .node_offset_bin_rhs,
   2776             .node_offset_switch_operand,
   2777             .node_offset_switch_special_prong,
   2778             .node_offset_switch_range,
   2779             .node_offset_fn_type_cc,
   2780             .node_offset_fn_type_ret_ty,
   2781             .node_offset_anyframe_type,
   2782             .node_offset_lib_name,
   2783             .node_offset_array_type_len,
   2784             .node_offset_array_type_sentinel,
   2785             .node_offset_array_type_elem,
   2786             => .{
   2787                 .file_scope = decl.getFileScope(),
   2788                 .parent_decl_node = decl.src_node,
   2789                 .lazy = lazy,
   2790             },
   2791         };
   2792     }
   2793 };
   2794 
   2795 pub const SemaError = error{ OutOfMemory, AnalysisFail };
   2796 pub const CompileError = error{
   2797     OutOfMemory,
   2798     /// When this is returned, the compile error for the failure has already been recorded.
   2799     AnalysisFail,
   2800     /// Returned when a compile error needed to be reported but a provided LazySrcLoc was set
   2801     /// to the `unneeded` tag. The source location was, in fact, needed. It is expected that
   2802     /// somewhere up the call stack, the operation will be retried after doing expensive work
   2803     /// to compute a source location.
   2804     NeededSourceLocation,
   2805     /// A Type or Value was needed to be used during semantic analysis, but it was not available
   2806     /// because the function is generic. This is only seen when analyzing the body of a param
   2807     /// instruction.
   2808     GenericPoison,
   2809     /// In a comptime scope, a return instruction was encountered. This error is only seen when
   2810     /// doing a comptime function call.
   2811     ComptimeReturn,
   2812     /// In a comptime scope, a break instruction was encountered. This error is only seen when
   2813     /// evaluating a comptime block.
   2814     ComptimeBreak,
   2815 };
   2816 
   2817 pub fn deinit(mod: *Module) void {
   2818     const gpa = mod.gpa;
   2819 
   2820     for (mod.import_table.keys()) |key| {
   2821         gpa.free(key);
   2822     }
   2823     for (mod.import_table.values()) |value| {
   2824         value.destroy(mod);
   2825     }
   2826     mod.import_table.deinit(gpa);
   2827 
   2828     {
   2829         var it = mod.embed_table.iterator();
   2830         while (it.next()) |entry| {
   2831             gpa.free(entry.key_ptr.*);
   2832             entry.value_ptr.*.destroy(mod);
   2833         }
   2834         mod.embed_table.deinit(gpa);
   2835     }
   2836 
   2837     mod.deletion_set.deinit(gpa);
   2838 
   2839     // The callsite of `Compilation.create` owns the `main_pkg`, however
   2840     // Module owns the builtin and std packages that it adds.
   2841     if (mod.main_pkg.table.fetchRemove("builtin")) |kv| {
   2842         gpa.free(kv.key);
   2843         kv.value.destroy(gpa);
   2844     }
   2845     if (mod.main_pkg.table.fetchRemove("std")) |kv| {
   2846         gpa.free(kv.key);
   2847         kv.value.destroy(gpa);
   2848     }
   2849     if (mod.main_pkg.table.fetchRemove("root")) |kv| {
   2850         gpa.free(kv.key);
   2851     }
   2852     if (mod.root_pkg != mod.main_pkg) {
   2853         mod.root_pkg.destroy(gpa);
   2854     }
   2855 
   2856     mod.compile_log_text.deinit(gpa);
   2857 
   2858     mod.zig_cache_artifact_directory.handle.close();
   2859     mod.local_zir_cache.handle.close();
   2860     mod.global_zir_cache.handle.close();
   2861 
   2862     for (mod.failed_decls.values()) |value| {
   2863         value.destroy(gpa);
   2864     }
   2865     mod.failed_decls.deinit(gpa);
   2866 
   2867     if (mod.emit_h) |emit_h| {
   2868         for (emit_h.failed_decls.values()) |value| {
   2869             value.destroy(gpa);
   2870         }
   2871         emit_h.failed_decls.deinit(gpa);
   2872         emit_h.decl_table.deinit(gpa);
   2873         emit_h.allocated_emit_h.deinit(gpa);
   2874         gpa.destroy(emit_h);
   2875     }
   2876 
   2877     for (mod.failed_files.values()) |value| {
   2878         if (value) |msg| msg.destroy(gpa);
   2879     }
   2880     mod.failed_files.deinit(gpa);
   2881 
   2882     for (mod.failed_embed_files.values()) |msg| {
   2883         msg.destroy(gpa);
   2884     }
   2885     mod.failed_embed_files.deinit(gpa);
   2886 
   2887     for (mod.failed_exports.values()) |value| {
   2888         value.destroy(gpa);
   2889     }
   2890     mod.failed_exports.deinit(gpa);
   2891 
   2892     mod.compile_log_decls.deinit(gpa);
   2893 
   2894     for (mod.decl_exports.values()) |export_list| {
   2895         gpa.free(export_list);
   2896     }
   2897     mod.decl_exports.deinit(gpa);
   2898 
   2899     for (mod.export_owners.values()) |value| {
   2900         freeExportList(gpa, value);
   2901     }
   2902     mod.export_owners.deinit(gpa);
   2903 
   2904     {
   2905         var it = mod.global_error_set.keyIterator();
   2906         while (it.next()) |key| {
   2907             gpa.free(key.*);
   2908         }
   2909         mod.global_error_set.deinit(gpa);
   2910     }
   2911 
   2912     mod.error_name_list.deinit(gpa);
   2913     mod.test_functions.deinit(gpa);
   2914     mod.align_stack_fns.deinit(gpa);
   2915     mod.monomorphed_funcs.deinit(gpa);
   2916 
   2917     {
   2918         var it = mod.memoized_calls.iterator();
   2919         while (it.next()) |entry| {
   2920             gpa.free(entry.key_ptr.args);
   2921             entry.value_ptr.arena.promote(gpa).deinit();
   2922         }
   2923         mod.memoized_calls.deinit(gpa);
   2924     }
   2925 
   2926     mod.decls_free_list.deinit(gpa);
   2927     mod.allocated_decls.deinit(gpa);
   2928     mod.global_assembly.deinit(gpa);
   2929 
   2930     mod.string_literal_table.deinit(gpa);
   2931     mod.string_literal_bytes.deinit(gpa);
   2932 }
   2933 
   2934 pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {
   2935     const gpa = mod.gpa;
   2936     {
   2937         const decl = mod.declPtr(decl_index);
   2938         log.debug("destroy {*} ({s})", .{ decl, decl.name });
   2939         _ = mod.test_functions.swapRemove(decl_index);
   2940         if (decl.deletion_flag) {
   2941             assert(mod.deletion_set.swapRemove(decl_index));
   2942         }
   2943         if (mod.global_assembly.fetchRemove(decl_index)) |kv| {
   2944             gpa.free(kv.value);
   2945         }
   2946         if (decl.has_tv) {
   2947             if (decl.getInnerNamespace()) |namespace| {
   2948                 namespace.destroyDecls(mod);
   2949             }
   2950             decl.clearValues(mod);
   2951         }
   2952         decl.dependants.deinit(gpa);
   2953         decl.dependencies.deinit(gpa);
   2954         decl.clearName(gpa);
   2955         decl.* = undefined;
   2956     }
   2957     mod.decls_free_list.append(gpa, decl_index) catch {
   2958         // In order to keep `destroyDecl` a non-fallible function, we ignore memory
   2959         // allocation failures here, instead leaking the Decl until garbage collection.
   2960     };
   2961     if (mod.emit_h) |mod_emit_h| {
   2962         const decl_emit_h = mod_emit_h.declPtr(decl_index);
   2963         decl_emit_h.fwd_decl.deinit(gpa);
   2964         decl_emit_h.* = undefined;
   2965     }
   2966 }
   2967 
   2968 pub fn declPtr(mod: *Module, decl_index: Decl.Index) *Decl {
   2969     return mod.allocated_decls.at(@enumToInt(decl_index));
   2970 }
   2971 
   2972 /// Returns true if and only if the Decl is the top level struct associated with a File.
   2973 pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {
   2974     const decl = mod.declPtr(decl_index);
   2975     if (decl.src_namespace.parent != null)
   2976         return false;
   2977     return decl_index == decl.src_namespace.getDeclIndex();
   2978 }
   2979 
   2980 fn freeExportList(gpa: Allocator, export_list: []*Export) void {
   2981     for (export_list) |exp| {
   2982         gpa.free(exp.options.name);
   2983         if (exp.options.section) |s| gpa.free(s);
   2984         gpa.destroy(exp);
   2985     }
   2986     gpa.free(export_list);
   2987 }
   2988 
   2989 const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8;
   2990 // TODO This is taking advantage of matching stage1 debug union layout.
   2991 // We need a better language feature for initializing a union with
   2992 // a runtime known tag.
   2993 const Stage1DataLayout = extern struct {
   2994     data: [8]u8 align(@alignOf(Zir.Inst.Data)),
   2995     safety_tag: u8,
   2996 };
   2997 comptime {
   2998     if (data_has_safety_tag) {
   2999         assert(@sizeOf(Stage1DataLayout) == @sizeOf(Zir.Inst.Data));
   3000     }
   3001 }
   3002 
   3003 pub fn astGenFile(mod: *Module, file: *File) !void {
   3004     const tracy = trace(@src());
   3005     defer tracy.end();
   3006 
   3007     const comp = mod.comp;
   3008     const gpa = mod.gpa;
   3009 
   3010     // In any case we need to examine the stat of the file to determine the course of action.
   3011     var source_file = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
   3012     defer source_file.close();
   3013 
   3014     const stat = try source_file.stat();
   3015 
   3016     const want_local_cache = file.pkg == mod.main_pkg;
   3017     const digest = hash: {
   3018         var path_hash: Cache.HashHelper = .{};
   3019         path_hash.addBytes(build_options.version);
   3020         if (!want_local_cache) {
   3021             path_hash.addOptionalBytes(file.pkg.root_src_directory.path);
   3022         }
   3023         path_hash.addBytes(file.sub_file_path);
   3024         break :hash path_hash.final();
   3025     };
   3026     const cache_directory = if (want_local_cache) mod.local_zir_cache else mod.global_zir_cache;
   3027     const zir_dir = cache_directory.handle;
   3028 
   3029     var cache_file: ?std.fs.File = null;
   3030     defer if (cache_file) |f| f.close();
   3031 
   3032     // Determine whether we need to reload the file from disk and redo parsing and AstGen.
   3033     switch (file.status) {
   3034         .never_loaded, .retryable_failure => cached: {
   3035             // First, load the cached ZIR code, if any.
   3036             log.debug("AstGen checking cache: {s} (local={}, digest={s})", .{
   3037                 file.sub_file_path, want_local_cache, &digest,
   3038             });
   3039 
   3040             // We ask for a lock in order to coordinate with other zig processes.
   3041             // If another process is already working on this file, we will get the cached
   3042             // version. Likewise if we're working on AstGen and another process asks for
   3043             // the cached file, they'll get it.
   3044             cache_file = zir_dir.openFile(&digest, .{ .lock = .Shared }) catch |err| switch (err) {
   3045                 error.PathAlreadyExists => unreachable, // opening for reading
   3046                 error.NoSpaceLeft => unreachable, // opening for reading
   3047                 error.NotDir => unreachable, // no dir components
   3048                 error.InvalidUtf8 => unreachable, // it's a hex encoded name
   3049                 error.BadPathName => unreachable, // it's a hex encoded name
   3050                 error.NameTooLong => unreachable, // it's a fixed size name
   3051                 error.PipeBusy => unreachable, // it's not a pipe
   3052                 error.WouldBlock => unreachable, // not asking for non-blocking I/O
   3053 
   3054                 error.SymLinkLoop,
   3055                 error.FileNotFound,
   3056                 error.Unexpected,
   3057                 => break :cached,
   3058 
   3059                 else => |e| return e, // Retryable errors are handled at callsite.
   3060             };
   3061 
   3062             // First we read the header to determine the lengths of arrays.
   3063             const header = cache_file.?.reader().readStruct(Zir.Header) catch |err| switch (err) {
   3064                 // This can happen if Zig bails out of this function between creating
   3065                 // the cached file and writing it.
   3066                 error.EndOfStream => break :cached,
   3067                 else => |e| return e,
   3068             };
   3069             const unchanged_metadata =
   3070                 stat.size == header.stat_size and
   3071                 stat.mtime == header.stat_mtime and
   3072                 stat.inode == header.stat_inode;
   3073 
   3074             if (!unchanged_metadata) {
   3075                 log.debug("AstGen cache stale: {s}", .{file.sub_file_path});
   3076                 break :cached;
   3077             }
   3078             log.debug("AstGen cache hit: {s} instructions_len={d}", .{
   3079                 file.sub_file_path, header.instructions_len,
   3080             });
   3081 
   3082             var instructions: std.MultiArrayList(Zir.Inst) = .{};
   3083             defer instructions.deinit(gpa);
   3084 
   3085             try instructions.setCapacity(gpa, header.instructions_len);
   3086             instructions.len = header.instructions_len;
   3087 
   3088             var zir: Zir = .{
   3089                 .instructions = instructions.toOwnedSlice(),
   3090                 .string_bytes = &.{},
   3091                 .extra = &.{},
   3092             };
   3093             var keep_zir = false;
   3094             defer if (!keep_zir) zir.deinit(gpa);
   3095 
   3096             zir.string_bytes = try gpa.alloc(u8, header.string_bytes_len);
   3097             zir.extra = try gpa.alloc(u32, header.extra_len);
   3098 
   3099             const safety_buffer = if (data_has_safety_tag)
   3100                 try gpa.alloc([8]u8, header.instructions_len)
   3101             else
   3102                 undefined;
   3103             defer if (data_has_safety_tag) gpa.free(safety_buffer);
   3104 
   3105             const data_ptr = if (data_has_safety_tag)
   3106                 @ptrCast([*]u8, safety_buffer.ptr)
   3107             else
   3108                 @ptrCast([*]u8, zir.instructions.items(.data).ptr);
   3109 
   3110             var iovecs = [_]std.os.iovec{
   3111                 .{
   3112                     .iov_base = @ptrCast([*]u8, zir.instructions.items(.tag).ptr),
   3113                     .iov_len = header.instructions_len,
   3114                 },
   3115                 .{
   3116                     .iov_base = data_ptr,
   3117                     .iov_len = header.instructions_len * 8,
   3118                 },
   3119                 .{
   3120                     .iov_base = zir.string_bytes.ptr,
   3121                     .iov_len = header.string_bytes_len,
   3122                 },
   3123                 .{
   3124                     .iov_base = @ptrCast([*]u8, zir.extra.ptr),
   3125                     .iov_len = header.extra_len * 4,
   3126                 },
   3127             };
   3128             const amt_read = try cache_file.?.readvAll(&iovecs);
   3129             const amt_expected = zir.instructions.len * 9 +
   3130                 zir.string_bytes.len +
   3131                 zir.extra.len * 4;
   3132             if (amt_read != amt_expected) {
   3133                 log.warn("unexpected EOF reading cached ZIR for {s}", .{file.sub_file_path});
   3134                 break :cached;
   3135             }
   3136             if (data_has_safety_tag) {
   3137                 const tags = zir.instructions.items(.tag);
   3138                 for (zir.instructions.items(.data)) |*data, i| {
   3139                     const union_tag = Zir.Inst.Tag.data_tags[@enumToInt(tags[i])];
   3140                     const as_struct = @ptrCast(*Stage1DataLayout, data);
   3141                     as_struct.* = .{
   3142                         .safety_tag = @enumToInt(union_tag),
   3143                         .data = safety_buffer[i],
   3144                     };
   3145                 }
   3146             }
   3147 
   3148             keep_zir = true;
   3149             file.zir = zir;
   3150             file.zir_loaded = true;
   3151             file.stat = .{
   3152                 .size = header.stat_size,
   3153                 .inode = header.stat_inode,
   3154                 .mtime = header.stat_mtime,
   3155             };
   3156             file.status = .success_zir;
   3157             log.debug("AstGen cached success: {s}", .{file.sub_file_path});
   3158 
   3159             // TODO don't report compile errors until Sema @importFile
   3160             if (file.zir.hasCompileErrors()) {
   3161                 {
   3162                     comp.mutex.lock();
   3163                     defer comp.mutex.unlock();
   3164                     try mod.failed_files.putNoClobber(gpa, file, null);
   3165                 }
   3166                 file.status = .astgen_failure;
   3167                 return error.AnalysisFail;
   3168             }
   3169             return;
   3170         },
   3171         .parse_failure, .astgen_failure, .success_zir => {
   3172             const unchanged_metadata =
   3173                 stat.size == file.stat.size and
   3174                 stat.mtime == file.stat.mtime and
   3175                 stat.inode == file.stat.inode;
   3176 
   3177             if (unchanged_metadata) {
   3178                 log.debug("unmodified metadata of file: {s}", .{file.sub_file_path});
   3179                 return;
   3180             }
   3181 
   3182             log.debug("metadata changed: {s}", .{file.sub_file_path});
   3183         },
   3184     }
   3185     if (cache_file) |f| {
   3186         f.close();
   3187         cache_file = null;
   3188     }
   3189     cache_file = zir_dir.createFile(&digest, .{ .lock = .Exclusive }) catch |err| switch (err) {
   3190         error.NotDir => unreachable, // no dir components
   3191         error.InvalidUtf8 => unreachable, // it's a hex encoded name
   3192         error.BadPathName => unreachable, // it's a hex encoded name
   3193         error.NameTooLong => unreachable, // it's a fixed size name
   3194         error.PipeBusy => unreachable, // it's not a pipe
   3195         error.WouldBlock => unreachable, // not asking for non-blocking I/O
   3196         error.FileNotFound => unreachable, // no dir components
   3197 
   3198         else => |e| {
   3199             const pkg_path = file.pkg.root_src_directory.path orelse ".";
   3200             const cache_path = cache_directory.path orelse ".";
   3201             log.warn("unable to save cached ZIR code for {s}/{s} to {s}/{s}: {s}", .{
   3202                 pkg_path, file.sub_file_path, cache_path, &digest, @errorName(e),
   3203             });
   3204             return;
   3205         },
   3206     };
   3207 
   3208     mod.lockAndClearFileCompileError(file);
   3209 
   3210     // If the previous ZIR does not have compile errors, keep it around
   3211     // in case parsing or new ZIR fails. In case of successful ZIR update
   3212     // at the end of this function we will free it.
   3213     // We keep the previous ZIR loaded so that we can use it
   3214     // for the update next time it does not have any compile errors. This avoids
   3215     // needlessly tossing out semantic analysis work when an error is
   3216     // temporarily introduced.
   3217     if (file.zir_loaded and !file.zir.hasCompileErrors()) {
   3218         assert(file.prev_zir == null);
   3219         const prev_zir_ptr = try gpa.create(Zir);
   3220         file.prev_zir = prev_zir_ptr;
   3221         prev_zir_ptr.* = file.zir;
   3222         file.zir = undefined;
   3223         file.zir_loaded = false;
   3224     }
   3225     file.unload(gpa);
   3226 
   3227     if (stat.size > std.math.maxInt(u32))
   3228         return error.FileTooBig;
   3229 
   3230     const source = try gpa.allocSentinel(u8, @intCast(usize, stat.size), 0);
   3231     defer if (!file.source_loaded) gpa.free(source);
   3232     const amt = try source_file.readAll(source);
   3233     if (amt != stat.size)
   3234         return error.UnexpectedEndOfFile;
   3235 
   3236     file.stat = .{
   3237         .size = stat.size,
   3238         .inode = stat.inode,
   3239         .mtime = stat.mtime,
   3240     };
   3241     file.source = source;
   3242     file.source_loaded = true;
   3243 
   3244     file.tree = try std.zig.parse(gpa, source);
   3245     defer if (!file.tree_loaded) file.tree.deinit(gpa);
   3246 
   3247     if (file.tree.errors.len != 0) {
   3248         const parse_err = file.tree.errors[0];
   3249 
   3250         var msg = std.ArrayList(u8).init(gpa);
   3251         defer msg.deinit();
   3252 
   3253         const token_starts = file.tree.tokens.items(.start);
   3254         const token_tags = file.tree.tokens.items(.tag);
   3255 
   3256         const extra_offset = file.tree.errorOffset(parse_err);
   3257         try file.tree.renderError(parse_err, msg.writer());
   3258         const err_msg = try gpa.create(ErrorMsg);
   3259         err_msg.* = .{
   3260             .src_loc = .{
   3261                 .file_scope = file,
   3262                 .parent_decl_node = 0,
   3263                 .lazy = .{ .byte_abs = token_starts[parse_err.token] + extra_offset },
   3264             },
   3265             .msg = msg.toOwnedSlice(),
   3266         };
   3267         if (token_tags[parse_err.token + @boolToInt(parse_err.token_is_prev)] == .invalid) {
   3268             const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token + @boolToInt(parse_err.token_is_prev)).len);
   3269             const byte_abs = token_starts[parse_err.token + @boolToInt(parse_err.token_is_prev)] + bad_off;
   3270             try mod.errNoteNonLazy(.{
   3271                 .file_scope = file,
   3272                 .parent_decl_node = 0,
   3273                 .lazy = .{ .byte_abs = byte_abs },
   3274             }, err_msg, "invalid byte: '{'}'", .{std.zig.fmtEscapes(source[byte_abs..][0..1])});
   3275         } else if (parse_err.tag == .decl_between_fields) {
   3276             try mod.errNoteNonLazy(.{
   3277                 .file_scope = file,
   3278                 .parent_decl_node = 0,
   3279                 .lazy = .{ .byte_abs = token_starts[file.tree.errors[1].token] },
   3280             }, err_msg, "field before declarations here", .{});
   3281             try mod.errNoteNonLazy(.{
   3282                 .file_scope = file,
   3283                 .parent_decl_node = 0,
   3284                 .lazy = .{ .byte_abs = token_starts[file.tree.errors[2].token] },
   3285             }, err_msg, "field after declarations here", .{});
   3286         }
   3287 
   3288         {
   3289             comp.mutex.lock();
   3290             defer comp.mutex.unlock();
   3291             try mod.failed_files.putNoClobber(gpa, file, err_msg);
   3292         }
   3293         file.status = .parse_failure;
   3294         return error.AnalysisFail;
   3295     }
   3296     file.tree_loaded = true;
   3297 
   3298     file.zir = try AstGen.generate(gpa, file.tree);
   3299     file.zir_loaded = true;
   3300     file.status = .success_zir;
   3301     log.debug("AstGen fresh success: {s}", .{file.sub_file_path});
   3302 
   3303     const safety_buffer = if (data_has_safety_tag)
   3304         try gpa.alloc([8]u8, file.zir.instructions.len)
   3305     else
   3306         undefined;
   3307     defer if (data_has_safety_tag) gpa.free(safety_buffer);
   3308     const data_ptr = if (data_has_safety_tag)
   3309         if (file.zir.instructions.len == 0)
   3310             @as([*]const u8, undefined)
   3311         else
   3312             @ptrCast([*]const u8, safety_buffer.ptr)
   3313     else
   3314         @ptrCast([*]const u8, file.zir.instructions.items(.data).ptr);
   3315     if (data_has_safety_tag) {
   3316         // The `Data` union has a safety tag but in the file format we store it without.
   3317         for (file.zir.instructions.items(.data)) |*data, i| {
   3318             const as_struct = @ptrCast(*const Stage1DataLayout, data);
   3319             safety_buffer[i] = as_struct.data;
   3320         }
   3321     }
   3322 
   3323     const header: Zir.Header = .{
   3324         .instructions_len = @intCast(u32, file.zir.instructions.len),
   3325         .string_bytes_len = @intCast(u32, file.zir.string_bytes.len),
   3326         .extra_len = @intCast(u32, file.zir.extra.len),
   3327 
   3328         .stat_size = stat.size,
   3329         .stat_inode = stat.inode,
   3330         .stat_mtime = stat.mtime,
   3331     };
   3332     var iovecs = [_]std.os.iovec_const{
   3333         .{
   3334             .iov_base = @ptrCast([*]const u8, &header),
   3335             .iov_len = @sizeOf(Zir.Header),
   3336         },
   3337         .{
   3338             .iov_base = @ptrCast([*]const u8, file.zir.instructions.items(.tag).ptr),
   3339             .iov_len = file.zir.instructions.len,
   3340         },
   3341         .{
   3342             .iov_base = data_ptr,
   3343             .iov_len = file.zir.instructions.len * 8,
   3344         },
   3345         .{
   3346             .iov_base = file.zir.string_bytes.ptr,
   3347             .iov_len = file.zir.string_bytes.len,
   3348         },
   3349         .{
   3350             .iov_base = @ptrCast([*]const u8, file.zir.extra.ptr),
   3351             .iov_len = file.zir.extra.len * 4,
   3352         },
   3353     };
   3354     cache_file.?.writevAll(&iovecs) catch |err| {
   3355         const pkg_path = file.pkg.root_src_directory.path orelse ".";
   3356         const cache_path = cache_directory.path orelse ".";
   3357         log.warn("unable to write cached ZIR code for {s}/{s} to {s}/{s}: {s}", .{
   3358             pkg_path, file.sub_file_path, cache_path, &digest, @errorName(err),
   3359         });
   3360     };
   3361 
   3362     if (file.zir.hasCompileErrors()) {
   3363         {
   3364             comp.mutex.lock();
   3365             defer comp.mutex.unlock();
   3366             try mod.failed_files.putNoClobber(gpa, file, null);
   3367         }
   3368         file.status = .astgen_failure;
   3369         return error.AnalysisFail;
   3370     }
   3371 
   3372     if (file.prev_zir) |prev_zir| {
   3373         // Iterate over all Namespace objects contained within this File, looking at the
   3374         // previous and new ZIR together and update the references to point
   3375         // to the new one. For example, Decl name, Decl zir_decl_index, and Namespace
   3376         // decl_table keys need to get updated to point to the new memory, even if the
   3377         // underlying source code is unchanged.
   3378         // We do not need to hold any locks at this time because all the Decl and Namespace
   3379         // objects being touched are specific to this File, and the only other concurrent
   3380         // tasks are touching other File objects.
   3381         try updateZirRefs(mod, file, prev_zir.*);
   3382         // At this point, `file.outdated_decls` and `file.deleted_decls` are populated,
   3383         // and semantic analysis will deal with them properly.
   3384         // No need to keep previous ZIR.
   3385         prev_zir.deinit(gpa);
   3386         gpa.destroy(prev_zir);
   3387         file.prev_zir = null;
   3388     } else if (file.root_decl.unwrap()) |root_decl| {
   3389         // This is an update, but it is the first time the File has succeeded
   3390         // ZIR. We must mark it outdated since we have already tried to
   3391         // semantically analyze it.
   3392         try file.outdated_decls.resize(gpa, 1);
   3393         file.outdated_decls.items[0] = root_decl;
   3394     }
   3395 }
   3396 
   3397 /// Patch ups:
   3398 /// * Struct.zir_index
   3399 /// * Decl.zir_index
   3400 /// * Fn.zir_body_inst
   3401 /// * Decl.zir_decl_index
   3402 fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
   3403     const gpa = mod.gpa;
   3404     const new_zir = file.zir;
   3405 
   3406     // Maps from old ZIR to new ZIR, struct_decl, enum_decl, etc. Any instruction which
   3407     // creates a namespace, gets mapped from old to new here.
   3408     var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
   3409     defer inst_map.deinit(gpa);
   3410     // Maps from old ZIR to new ZIR, the extra data index for the sub-decl item.
   3411     // e.g. the thing that Decl.zir_decl_index points to.
   3412     var extra_map: std.AutoHashMapUnmanaged(u32, u32) = .{};
   3413     defer extra_map.deinit(gpa);
   3414 
   3415     try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map, &extra_map);
   3416 
   3417     // Walk the Decl graph, updating ZIR indexes, strings, and populating
   3418     // the deleted and outdated lists.
   3419 
   3420     var decl_stack: std.ArrayListUnmanaged(Decl.Index) = .{};
   3421     defer decl_stack.deinit(gpa);
   3422 
   3423     const root_decl = file.root_decl.unwrap().?;
   3424     try decl_stack.append(gpa, root_decl);
   3425 
   3426     file.deleted_decls.clearRetainingCapacity();
   3427     file.outdated_decls.clearRetainingCapacity();
   3428 
   3429     // The root decl is always outdated; otherwise we would not have had
   3430     // to re-generate ZIR for the File.
   3431     try file.outdated_decls.append(gpa, root_decl);
   3432 
   3433     while (decl_stack.popOrNull()) |decl_index| {
   3434         const decl = mod.declPtr(decl_index);
   3435         // Anonymous decls and the root decl have this set to 0. We still need
   3436         // to walk them but we do not need to modify this value.
   3437         // Anonymous decls should not be marked outdated. They will be re-generated
   3438         // if their owner decl is marked outdated.
   3439         if (decl.zir_decl_index != 0) {
   3440             const old_zir_decl_index = decl.zir_decl_index;
   3441             const new_zir_decl_index = extra_map.get(old_zir_decl_index) orelse {
   3442                 log.debug("updateZirRefs {s}: delete {*} ({s})", .{
   3443                     file.sub_file_path, decl, decl.name,
   3444                 });
   3445                 try file.deleted_decls.append(gpa, decl_index);
   3446                 continue;
   3447             };
   3448             const old_hash = decl.contentsHashZir(old_zir);
   3449             decl.zir_decl_index = new_zir_decl_index;
   3450             const new_hash = decl.contentsHashZir(new_zir);
   3451             if (!std.zig.srcHashEql(old_hash, new_hash)) {
   3452                 log.debug("updateZirRefs {s}: outdated {*} ({s}) {d} => {d}", .{
   3453                     file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index,
   3454                 });
   3455                 try file.outdated_decls.append(gpa, decl_index);
   3456             } else {
   3457                 log.debug("updateZirRefs {s}: unchanged {*} ({s}) {d} => {d}", .{
   3458                     file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index,
   3459                 });
   3460             }
   3461         }
   3462 
   3463         if (!decl.owns_tv) continue;
   3464 
   3465         if (decl.getStruct()) |struct_obj| {
   3466             struct_obj.zir_index = inst_map.get(struct_obj.zir_index) orelse {
   3467                 try file.deleted_decls.append(gpa, decl_index);
   3468                 continue;
   3469             };
   3470         }
   3471 
   3472         if (decl.getUnion()) |union_obj| {
   3473             union_obj.zir_index = inst_map.get(union_obj.zir_index) orelse {
   3474                 try file.deleted_decls.append(gpa, decl_index);
   3475                 continue;
   3476             };
   3477         }
   3478 
   3479         if (decl.getFunction()) |func| {
   3480             func.zir_body_inst = inst_map.get(func.zir_body_inst) orelse {
   3481                 try file.deleted_decls.append(gpa, decl_index);
   3482                 continue;
   3483             };
   3484         }
   3485 
   3486         if (decl.getInnerNamespace()) |namespace| {
   3487             for (namespace.decls.keys()) |sub_decl| {
   3488                 try decl_stack.append(gpa, sub_decl);
   3489             }
   3490             for (namespace.anon_decls.keys()) |sub_decl| {
   3491                 try decl_stack.append(gpa, sub_decl);
   3492             }
   3493         }
   3494     }
   3495 }
   3496 
   3497 pub fn populateBuiltinFile(mod: *Module) !void {
   3498     const tracy = trace(@src());
   3499     defer tracy.end();
   3500 
   3501     const comp = mod.comp;
   3502     const pkg_and_file = blk: {
   3503         comp.mutex.lock();
   3504         defer comp.mutex.unlock();
   3505 
   3506         const builtin_pkg = mod.main_pkg.table.get("builtin").?;
   3507         const result = try mod.importPkg(builtin_pkg);
   3508         break :blk .{
   3509             .file = result.file,
   3510             .pkg = builtin_pkg,
   3511         };
   3512     };
   3513     const file = pkg_and_file.file;
   3514     const builtin_pkg = pkg_and_file.pkg;
   3515     const gpa = mod.gpa;
   3516     file.source = try comp.generateBuiltinZigSource(gpa);
   3517     file.source_loaded = true;
   3518 
   3519     if (builtin_pkg.root_src_directory.handle.statFile(builtin_pkg.root_src_path)) |stat| {
   3520         if (stat.size != file.source.len) {
   3521             const full_path = try builtin_pkg.root_src_directory.join(gpa, &.{
   3522                 builtin_pkg.root_src_path,
   3523             });
   3524             defer gpa.free(full_path);
   3525 
   3526             log.warn(
   3527                 "the cached file '{s}' had the wrong size. Expected {d}, found {d}. " ++
   3528                     "Overwriting with correct file contents now",
   3529                 .{ full_path, file.source.len, stat.size },
   3530             );
   3531 
   3532             try writeBuiltinFile(file, builtin_pkg);
   3533         } else {
   3534             file.stat = .{
   3535                 .size = stat.size,
   3536                 .inode = stat.inode,
   3537                 .mtime = stat.mtime,
   3538             };
   3539         }
   3540     } else |err| switch (err) {
   3541         error.BadPathName => unreachable, // it's always "builtin.zig"
   3542         error.NameTooLong => unreachable, // it's always "builtin.zig"
   3543         error.PipeBusy => unreachable, // it's not a pipe
   3544         error.WouldBlock => unreachable, // not asking for non-blocking I/O
   3545 
   3546         error.FileNotFound => try writeBuiltinFile(file, builtin_pkg),
   3547 
   3548         else => |e| return e,
   3549     }
   3550 
   3551     file.tree = try std.zig.parse(gpa, file.source);
   3552     file.tree_loaded = true;
   3553     assert(file.tree.errors.len == 0); // builtin.zig must parse
   3554 
   3555     file.zir = try AstGen.generate(gpa, file.tree);
   3556     file.zir_loaded = true;
   3557     file.status = .success_zir;
   3558 }
   3559 
   3560 pub fn writeBuiltinFile(file: *File, builtin_pkg: *Package) !void {
   3561     var af = try builtin_pkg.root_src_directory.handle.atomicFile(builtin_pkg.root_src_path, .{});
   3562     defer af.deinit();
   3563     try af.file.writeAll(file.source);
   3564     try af.finish();
   3565 
   3566     file.stat = .{
   3567         .size = file.source.len,
   3568         .inode = 0, // dummy value
   3569         .mtime = 0, // dummy value
   3570     };
   3571 }
   3572 
   3573 pub fn mapOldZirToNew(
   3574     gpa: Allocator,
   3575     old_zir: Zir,
   3576     new_zir: Zir,
   3577     inst_map: *std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index),
   3578     extra_map: *std.AutoHashMapUnmanaged(u32, u32),
   3579 ) Allocator.Error!void {
   3580     // Contain ZIR indexes of declaration instructions.
   3581     const MatchedZirDecl = struct {
   3582         old_inst: Zir.Inst.Index,
   3583         new_inst: Zir.Inst.Index,
   3584     };
   3585     var match_stack: std.ArrayListUnmanaged(MatchedZirDecl) = .{};
   3586     defer match_stack.deinit(gpa);
   3587 
   3588     // Main struct inst is always the same
   3589     try match_stack.append(gpa, .{
   3590         .old_inst = Zir.main_struct_inst,
   3591         .new_inst = Zir.main_struct_inst,
   3592     });
   3593 
   3594     var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
   3595     defer old_decls.deinit();
   3596     var new_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
   3597     defer new_decls.deinit();
   3598 
   3599     while (match_stack.popOrNull()) |match_item| {
   3600         try inst_map.put(gpa, match_item.old_inst, match_item.new_inst);
   3601 
   3602         // Maps name to extra index of decl sub item.
   3603         var decl_map: std.StringHashMapUnmanaged(u32) = .{};
   3604         defer decl_map.deinit(gpa);
   3605 
   3606         {
   3607             var old_decl_it = old_zir.declIterator(match_item.old_inst);
   3608             while (old_decl_it.next()) |old_decl| {
   3609                 try decl_map.put(gpa, old_decl.name, old_decl.sub_index);
   3610             }
   3611         }
   3612 
   3613         var new_decl_it = new_zir.declIterator(match_item.new_inst);
   3614         while (new_decl_it.next()) |new_decl| {
   3615             const old_extra_index = decl_map.get(new_decl.name) orelse continue;
   3616             const new_extra_index = new_decl.sub_index;
   3617             try extra_map.put(gpa, old_extra_index, new_extra_index);
   3618 
   3619             try old_zir.findDecls(&old_decls, old_extra_index);
   3620             try new_zir.findDecls(&new_decls, new_extra_index);
   3621             var i: usize = 0;
   3622             while (true) : (i += 1) {
   3623                 if (i >= old_decls.items.len) break;
   3624                 if (i >= new_decls.items.len) break;
   3625                 try match_stack.append(gpa, .{
   3626                     .old_inst = old_decls.items[i],
   3627                     .new_inst = new_decls.items[i],
   3628                 });
   3629             }
   3630         }
   3631     }
   3632 }
   3633 
   3634 /// This ensures that the Decl will have a Type and Value populated.
   3635 /// However the resolution status of the Type may not be fully resolved.
   3636 /// For example an inferred error set is not resolved until after `analyzeFnBody`.
   3637 /// is called.
   3638 pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
   3639     const tracy = trace(@src());
   3640     defer tracy.end();
   3641 
   3642     const decl = mod.declPtr(decl_index);
   3643 
   3644     const subsequent_analysis = switch (decl.analysis) {
   3645         .in_progress => unreachable,
   3646 
   3647         .file_failure,
   3648         .sema_failure,
   3649         .sema_failure_retryable,
   3650         .codegen_failure,
   3651         .dependency_failure,
   3652         .codegen_failure_retryable,
   3653         => return error.AnalysisFail,
   3654 
   3655         .complete => return,
   3656 
   3657         .outdated => blk: {
   3658             log.debug("re-analyzing {*} ({s})", .{ decl, decl.name });
   3659 
   3660             // The exports this Decl performs will be re-discovered, so we remove them here
   3661             // prior to re-analysis.
   3662             mod.deleteDeclExports(decl_index);
   3663             // Dependencies will be re-discovered, so we remove them here prior to re-analysis.
   3664             for (decl.dependencies.keys()) |dep_index| {
   3665                 const dep = mod.declPtr(dep_index);
   3666                 dep.removeDependant(decl_index);
   3667                 if (dep.dependants.count() == 0 and !dep.deletion_flag) {
   3668                     log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{
   3669                         decl, decl.name, dep, dep.name,
   3670                     });
   3671                     try mod.markDeclForDeletion(dep_index);
   3672                 }
   3673             }
   3674             decl.dependencies.clearRetainingCapacity();
   3675 
   3676             break :blk true;
   3677         },
   3678 
   3679         .unreferenced => false,
   3680     };
   3681 
   3682     var decl_prog_node = mod.sema_prog_node.start(mem.sliceTo(decl.name, 0), 0);
   3683     decl_prog_node.activate();
   3684     defer decl_prog_node.end();
   3685 
   3686     const type_changed = mod.semaDecl(decl_index) catch |err| switch (err) {
   3687         error.AnalysisFail => {
   3688             if (decl.analysis == .in_progress) {
   3689                 // If this decl caused the compile error, the analysis field would
   3690                 // be changed to indicate it was this Decl's fault. Because this
   3691                 // did not happen, we infer here that it was a dependency failure.
   3692                 decl.analysis = .dependency_failure;
   3693             }
   3694             return error.AnalysisFail;
   3695         },
   3696         error.NeededSourceLocation => unreachable,
   3697         error.GenericPoison => unreachable,
   3698         else => |e| {
   3699             decl.analysis = .sema_failure_retryable;
   3700             try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
   3701             mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
   3702                 mod.gpa,
   3703                 decl.srcLoc(),
   3704                 "unable to analyze: {s}",
   3705                 .{@errorName(e)},
   3706             ));
   3707             return error.AnalysisFail;
   3708         },
   3709     };
   3710 
   3711     if (subsequent_analysis) {
   3712         // We may need to chase the dependants and re-analyze them.
   3713         // However, if the decl is a function, and the type is the same, we do not need to.
   3714         if (type_changed or decl.ty.zigTypeTag() != .Fn) {
   3715             for (decl.dependants.keys()) |dep_index| {
   3716                 const dep = mod.declPtr(dep_index);
   3717                 switch (dep.analysis) {
   3718                     .unreferenced => unreachable,
   3719                     .in_progress => continue, // already doing analysis, ok
   3720                     .outdated => continue, // already queued for update
   3721 
   3722                     .file_failure,
   3723                     .dependency_failure,
   3724                     .sema_failure,
   3725                     .sema_failure_retryable,
   3726                     .codegen_failure,
   3727                     .codegen_failure_retryable,
   3728                     .complete,
   3729                     => if (dep.generation != mod.generation) {
   3730                         try mod.markOutdatedDecl(dep_index);
   3731                     },
   3732                 }
   3733             }
   3734         }
   3735     }
   3736 }
   3737 
   3738 pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void {
   3739     const tracy = trace(@src());
   3740     defer tracy.end();
   3741 
   3742     const decl_index = func.owner_decl;
   3743     const decl = mod.declPtr(decl_index);
   3744 
   3745     switch (decl.analysis) {
   3746         .unreferenced => unreachable,
   3747         .in_progress => unreachable,
   3748         .outdated => unreachable,
   3749 
   3750         .file_failure,
   3751         .sema_failure,
   3752         .codegen_failure,
   3753         .dependency_failure,
   3754         .sema_failure_retryable,
   3755         => return error.AnalysisFail,
   3756 
   3757         .complete, .codegen_failure_retryable => {
   3758             switch (func.state) {
   3759                 .sema_failure, .dependency_failure => return error.AnalysisFail,
   3760                 .queued => {},
   3761                 .in_progress => unreachable,
   3762                 .inline_only => unreachable, // don't queue work for this
   3763                 .success => return,
   3764             }
   3765 
   3766             const gpa = mod.gpa;
   3767 
   3768             var tmp_arena = std.heap.ArenaAllocator.init(gpa);
   3769             defer tmp_arena.deinit();
   3770             const sema_arena = tmp_arena.allocator();
   3771 
   3772             var air = mod.analyzeFnBody(func, sema_arena) catch |err| switch (err) {
   3773                 error.AnalysisFail => {
   3774                     if (func.state == .in_progress) {
   3775                         // If this decl caused the compile error, the analysis field would
   3776                         // be changed to indicate it was this Decl's fault. Because this
   3777                         // did not happen, we infer here that it was a dependency failure.
   3778                         func.state = .dependency_failure;
   3779                     }
   3780                     return error.AnalysisFail;
   3781                 },
   3782                 error.OutOfMemory => return error.OutOfMemory,
   3783             };
   3784             defer air.deinit(gpa);
   3785 
   3786             if (mod.comp.bin_file.options.emit == null) return;
   3787 
   3788             log.debug("analyze liveness of {s}", .{decl.name});
   3789             var liveness = try Liveness.analyze(gpa, air);
   3790             defer liveness.deinit(gpa);
   3791 
   3792             if (builtin.mode == .Debug and mod.comp.verbose_air) {
   3793                 const fqn = try decl.getFullyQualifiedName(mod);
   3794                 defer mod.gpa.free(fqn);
   3795 
   3796                 std.debug.print("# Begin Function AIR: {s}:\n", .{fqn});
   3797                 @import("print_air.zig").dump(mod, air, liveness);
   3798                 std.debug.print("# End Function AIR: {s}\n\n", .{fqn});
   3799             }
   3800 
   3801             mod.comp.bin_file.updateFunc(mod, func, air, liveness) catch |err| switch (err) {
   3802                 error.OutOfMemory => return error.OutOfMemory,
   3803                 error.AnalysisFail => {
   3804                     decl.analysis = .codegen_failure;
   3805                     return;
   3806                 },
   3807                 else => {
   3808                     try mod.failed_decls.ensureUnusedCapacity(gpa, 1);
   3809                     mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create(
   3810                         gpa,
   3811                         decl.srcLoc(),
   3812                         "unable to codegen: {s}",
   3813                         .{@errorName(err)},
   3814                     ));
   3815                     decl.analysis = .codegen_failure_retryable;
   3816                     return;
   3817                 },
   3818             };
   3819             return;
   3820         },
   3821     }
   3822 }
   3823 
   3824 pub fn updateEmbedFile(mod: *Module, embed_file: *EmbedFile) SemaError!void {
   3825     const tracy = trace(@src());
   3826     defer tracy.end();
   3827 
   3828     // TODO we can potentially relax this if we store some more information along
   3829     // with decl dependency edges
   3830     const owner_decl = mod.declPtr(embed_file.owner_decl);
   3831     for (owner_decl.dependants.keys()) |dep_index| {
   3832         const dep = mod.declPtr(dep_index);
   3833         switch (dep.analysis) {
   3834             .unreferenced => unreachable,
   3835             .in_progress => continue, // already doing analysis, ok
   3836             .outdated => continue, // already queued for update
   3837 
   3838             .file_failure,
   3839             .dependency_failure,
   3840             .sema_failure,
   3841             .sema_failure_retryable,
   3842             .codegen_failure,
   3843             .codegen_failure_retryable,
   3844             .complete,
   3845             => if (dep.generation != mod.generation) {
   3846                 try mod.markOutdatedDecl(dep_index);
   3847             },
   3848         }
   3849     }
   3850 }
   3851 
   3852 pub fn semaPkg(mod: *Module, pkg: *Package) !void {
   3853     const file = (try mod.importPkg(pkg)).file;
   3854     return mod.semaFile(file);
   3855 }
   3856 
   3857 /// Regardless of the file status, will create a `Decl` so that we
   3858 /// can track dependencies and re-analyze when the file becomes outdated.
   3859 pub fn semaFile(mod: *Module, file: *File) SemaError!void {
   3860     const tracy = trace(@src());
   3861     defer tracy.end();
   3862 
   3863     if (file.root_decl != .none) return;
   3864 
   3865     const gpa = mod.gpa;
   3866     var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
   3867     errdefer new_decl_arena.deinit();
   3868     const new_decl_arena_allocator = new_decl_arena.allocator();
   3869 
   3870     const struct_obj = try new_decl_arena_allocator.create(Module.Struct);
   3871     const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
   3872     const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty);
   3873     const ty_ty = comptime Type.initTag(.type);
   3874     struct_obj.* = .{
   3875         .owner_decl = undefined, // set below
   3876         .fields = .{},
   3877         .node_offset = 0, // it's the struct for the root file
   3878         .zir_index = undefined, // set below
   3879         .layout = .Auto,
   3880         .status = .none,
   3881         .known_non_opv = undefined,
   3882         .namespace = .{
   3883             .parent = null,
   3884             .ty = struct_ty,
   3885             .file_scope = file,
   3886         },
   3887     };
   3888     const new_decl_index = try mod.allocateNewDecl(&struct_obj.namespace, 0, null);
   3889     const new_decl = mod.declPtr(new_decl_index);
   3890     file.root_decl = new_decl_index.toOptional();
   3891     struct_obj.owner_decl = new_decl_index;
   3892     new_decl.name = try file.fullyQualifiedNameZ(gpa);
   3893     new_decl.src_line = 0;
   3894     new_decl.is_pub = true;
   3895     new_decl.is_exported = false;
   3896     new_decl.has_align = false;
   3897     new_decl.has_linksection_or_addrspace = false;
   3898     new_decl.ty = ty_ty;
   3899     new_decl.val = struct_val;
   3900     new_decl.has_tv = true;
   3901     new_decl.owns_tv = true;
   3902     new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive.
   3903     new_decl.analysis = .in_progress;
   3904     new_decl.generation = mod.generation;
   3905 
   3906     if (file.status == .success_zir) {
   3907         assert(file.zir_loaded);
   3908         const main_struct_inst = Zir.main_struct_inst;
   3909         struct_obj.zir_index = main_struct_inst;
   3910 
   3911         var sema_arena = std.heap.ArenaAllocator.init(gpa);
   3912         defer sema_arena.deinit();
   3913         const sema_arena_allocator = sema_arena.allocator();
   3914 
   3915         var sema: Sema = .{
   3916             .mod = mod,
   3917             .gpa = gpa,
   3918             .arena = sema_arena_allocator,
   3919             .perm_arena = new_decl_arena_allocator,
   3920             .code = file.zir,
   3921             .owner_decl = new_decl,
   3922             .owner_decl_index = new_decl_index,
   3923             .func = null,
   3924             .fn_ret_ty = Type.void,
   3925             .owner_func = null,
   3926         };
   3927         defer sema.deinit();
   3928 
   3929         var wip_captures = try WipCaptureScope.init(gpa, new_decl_arena_allocator, null);
   3930         defer wip_captures.deinit();
   3931 
   3932         var block_scope: Sema.Block = .{
   3933             .parent = null,
   3934             .sema = &sema,
   3935             .src_decl = new_decl_index,
   3936             .namespace = &struct_obj.namespace,
   3937             .wip_capture_scope = wip_captures.scope,
   3938             .instructions = .{},
   3939             .inlining = null,
   3940             .is_comptime = true,
   3941         };
   3942         defer block_scope.instructions.deinit(gpa);
   3943 
   3944         if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_obj)) |_| {
   3945             try wip_captures.finalize();
   3946             new_decl.analysis = .complete;
   3947         } else |err| switch (err) {
   3948             error.OutOfMemory => return error.OutOfMemory,
   3949             error.AnalysisFail => {},
   3950         }
   3951 
   3952         if (mod.comp.whole_cache_manifest) |man| {
   3953             const source = file.getSource(gpa) catch |err| {
   3954                 try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)});
   3955                 return error.AnalysisFail;
   3956             };
   3957             const resolved_path = try file.pkg.root_src_directory.join(gpa, &.{
   3958                 file.sub_file_path,
   3959             });
   3960             errdefer gpa.free(resolved_path);
   3961 
   3962             try man.addFilePostContents(resolved_path, source.bytes, source.stat);
   3963         }
   3964     } else {
   3965         new_decl.analysis = .file_failure;
   3966     }
   3967 
   3968     try new_decl.finalizeNewArena(&new_decl_arena);
   3969 }
   3970 
   3971 /// Returns `true` if the Decl type changed.
   3972 /// Returns `true` if this is the first time analyzing the Decl.
   3973 /// Returns `false` otherwise.
   3974 fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
   3975     const tracy = trace(@src());
   3976     defer tracy.end();
   3977 
   3978     const decl = mod.declPtr(decl_index);
   3979 
   3980     if (decl.getFileScope().status != .success_zir) {
   3981         return error.AnalysisFail;
   3982     }
   3983 
   3984     const gpa = mod.gpa;
   3985     const zir = decl.getFileScope().zir;
   3986     const zir_datas = zir.instructions.items(.data);
   3987 
   3988     decl.analysis = .in_progress;
   3989 
   3990     // We need the memory for the Type to go into the arena for the Decl
   3991     var decl_arena = std.heap.ArenaAllocator.init(gpa);
   3992     errdefer decl_arena.deinit();
   3993     const decl_arena_allocator = decl_arena.allocator();
   3994 
   3995     var analysis_arena = std.heap.ArenaAllocator.init(gpa);
   3996     defer analysis_arena.deinit();
   3997     const analysis_arena_allocator = analysis_arena.allocator();
   3998 
   3999     var sema: Sema = .{
   4000         .mod = mod,
   4001         .gpa = gpa,
   4002         .arena = analysis_arena_allocator,
   4003         .perm_arena = decl_arena_allocator,
   4004         .code = zir,
   4005         .owner_decl = decl,
   4006         .owner_decl_index = decl_index,
   4007         .func = null,
   4008         .fn_ret_ty = Type.void,
   4009         .owner_func = null,
   4010     };
   4011     defer sema.deinit();
   4012 
   4013     if (mod.declIsRoot(decl_index)) {
   4014         log.debug("semaDecl root {*} ({s})", .{ decl, decl.name });
   4015         const main_struct_inst = Zir.main_struct_inst;
   4016         const struct_obj = decl.getStruct().?;
   4017         // This might not have gotten set in `semaFile` if the first time had
   4018         // a ZIR failure, so we set it here in case.
   4019         struct_obj.zir_index = main_struct_inst;
   4020         try sema.analyzeStructDecl(decl, main_struct_inst, struct_obj);
   4021         decl.analysis = .complete;
   4022         decl.generation = mod.generation;
   4023         return false;
   4024     }
   4025     log.debug("semaDecl {*} ({s})", .{ decl, decl.name });
   4026 
   4027     var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope);
   4028     defer wip_captures.deinit();
   4029 
   4030     var block_scope: Sema.Block = .{
   4031         .parent = null,
   4032         .sema = &sema,
   4033         .src_decl = decl_index,
   4034         .namespace = decl.src_namespace,
   4035         .wip_capture_scope = wip_captures.scope,
   4036         .instructions = .{},
   4037         .inlining = null,
   4038         .is_comptime = true,
   4039     };
   4040     defer {
   4041         block_scope.instructions.deinit(gpa);
   4042         block_scope.params.deinit(gpa);
   4043     }
   4044 
   4045     const zir_block_index = decl.zirBlockIndex();
   4046     const inst_data = zir_datas[zir_block_index].pl_node;
   4047     const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index);
   4048     const body = zir.extra[extra.end..][0..extra.data.body_len];
   4049     const result_ref = (try sema.analyzeBodyBreak(&block_scope, body)).?.operand;
   4050     try wip_captures.finalize();
   4051     const src = LazySrcLoc.nodeOffset(0);
   4052     const decl_tv = try sema.resolveInstValue(&block_scope, src, result_ref);
   4053     const decl_align: u32 = blk: {
   4054         const align_ref = decl.zirAlignRef();
   4055         if (align_ref == .none) break :blk 0;
   4056         break :blk try sema.resolveAlign(&block_scope, src, align_ref);
   4057     };
   4058     const decl_linksection: ?[*:0]const u8 = blk: {
   4059         const linksection_ref = decl.zirLinksectionRef();
   4060         if (linksection_ref == .none) break :blk null;
   4061         const bytes = try sema.resolveConstString(&block_scope, src, linksection_ref);
   4062         break :blk (try decl_arena_allocator.dupeZ(u8, bytes)).ptr;
   4063     };
   4064     const target = sema.mod.getTarget();
   4065     const address_space = blk: {
   4066         const addrspace_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.tag()) {
   4067             .function, .extern_fn => .function,
   4068             .variable => .variable,
   4069             else => .constant,
   4070         };
   4071 
   4072         break :blk switch (decl.zirAddrspaceRef()) {
   4073             .none => switch (addrspace_ctx) {
   4074                 .function => target_util.defaultAddressSpace(target, .function),
   4075                 .variable => target_util.defaultAddressSpace(target, .global_mutable),
   4076                 .constant => target_util.defaultAddressSpace(target, .global_constant),
   4077                 else => unreachable,
   4078             },
   4079             else => |addrspace_ref| try sema.analyzeAddrspace(&block_scope, src, addrspace_ref, addrspace_ctx),
   4080         };
   4081     };
   4082 
   4083     // Note this resolves the type of the Decl, not the value; if this Decl
   4084     // is a struct, for example, this resolves `type` (which needs no resolution),
   4085     // not the struct itself.
   4086     try sema.resolveTypeLayout(&block_scope, src, decl_tv.ty);
   4087 
   4088     const decl_arena_state = try decl_arena_allocator.create(std.heap.ArenaAllocator.State);
   4089 
   4090     if (decl.is_usingnamespace) {
   4091         if (!decl_tv.ty.eql(Type.type, mod)) {
   4092             return sema.fail(&block_scope, src, "expected type, found {}", .{
   4093                 decl_tv.ty.fmt(mod),
   4094             });
   4095         }
   4096         var buffer: Value.ToTypeBuffer = undefined;
   4097         const ty = try decl_tv.val.toType(&buffer).copy(decl_arena_allocator);
   4098         if (ty.getNamespace() == null) {
   4099             return sema.fail(&block_scope, src, "type {} has no namespace", .{ty.fmt(mod)});
   4100         }
   4101 
   4102         decl.ty = Type.type;
   4103         decl.val = try Value.Tag.ty.create(decl_arena_allocator, ty);
   4104         decl.@"align" = 0;
   4105         decl.@"linksection" = null;
   4106         decl.has_tv = true;
   4107         decl.owns_tv = false;
   4108         decl_arena_state.* = decl_arena.state;
   4109         decl.value_arena = decl_arena_state;
   4110         decl.analysis = .complete;
   4111         decl.generation = mod.generation;
   4112 
   4113         return true;
   4114     }
   4115 
   4116     if (decl_tv.val.castTag(.function)) |fn_payload| {
   4117         const func = fn_payload.data;
   4118         const owns_tv = func.owner_decl == decl_index;
   4119         if (owns_tv) {
   4120             var prev_type_has_bits = false;
   4121             var prev_is_inline = false;
   4122             var type_changed = true;
   4123 
   4124             if (decl.has_tv) {
   4125                 prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits();
   4126                 type_changed = !decl.ty.eql(decl_tv.ty, mod);
   4127                 if (decl.getFunction()) |prev_func| {
   4128                     prev_is_inline = prev_func.state == .inline_only;
   4129                 }
   4130                 decl.clearValues(mod);
   4131             }
   4132 
   4133             decl.ty = try decl_tv.ty.copy(decl_arena_allocator);
   4134             decl.val = try decl_tv.val.copy(decl_arena_allocator);
   4135             decl.@"align" = decl_align;
   4136             decl.@"linksection" = decl_linksection;
   4137             decl.@"addrspace" = address_space;
   4138             decl.has_tv = true;
   4139             decl.owns_tv = owns_tv;
   4140             decl_arena_state.* = decl_arena.state;
   4141             decl.value_arena = decl_arena_state;
   4142             decl.analysis = .complete;
   4143             decl.generation = mod.generation;
   4144 
   4145             const has_runtime_bits = try sema.fnHasRuntimeBits(&block_scope, src, decl.ty);
   4146 
   4147             if (has_runtime_bits) {
   4148                 // We don't fully codegen the decl until later, but we do need to reserve a global
   4149                 // offset table index for it. This allows us to codegen decls out of dependency
   4150                 // order, increasing how many computations can be done in parallel.
   4151                 try mod.comp.bin_file.allocateDeclIndexes(decl_index);
   4152                 try mod.comp.work_queue.writeItem(.{ .codegen_func = func });
   4153                 if (type_changed and mod.emit_h != null) {
   4154                     try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index });
   4155                 }
   4156             } else if (!prev_is_inline and prev_type_has_bits) {
   4157                 mod.comp.bin_file.freeDecl(decl_index);
   4158             }
   4159 
   4160             const is_inline = decl.ty.fnCallingConvention() == .Inline;
   4161             if (decl.is_exported) {
   4162                 const export_src = src; // TODO make this point at `export` token
   4163                 if (is_inline) {
   4164                     return sema.fail(&block_scope, export_src, "export of inline function", .{});
   4165                 }
   4166                 // The scope needs to have the decl in it.
   4167                 const options: std.builtin.ExportOptions = .{ .name = mem.sliceTo(decl.name, 0) };
   4168                 try sema.analyzeExport(&block_scope, export_src, options, decl_index);
   4169             }
   4170             return type_changed or is_inline != prev_is_inline;
   4171         }
   4172     }
   4173     var type_changed = true;
   4174     if (decl.has_tv) {
   4175         type_changed = !decl.ty.eql(decl_tv.ty, mod);
   4176         decl.clearValues(mod);
   4177     }
   4178 
   4179     decl.owns_tv = false;
   4180     var queue_linker_work = false;
   4181     var is_extern = false;
   4182     switch (decl_tv.val.tag()) {
   4183         .variable => {
   4184             const variable = decl_tv.val.castTag(.variable).?.data;
   4185             if (variable.owner_decl == decl_index) {
   4186                 decl.owns_tv = true;
   4187                 queue_linker_work = true;
   4188 
   4189                 const copied_init = try variable.init.copy(decl_arena_allocator);
   4190                 variable.init = copied_init;
   4191             }
   4192         },
   4193         .extern_fn => {
   4194             const extern_fn = decl_tv.val.castTag(.extern_fn).?.data;
   4195             if (extern_fn.owner_decl == decl_index) {
   4196                 decl.owns_tv = true;
   4197                 queue_linker_work = true;
   4198                 is_extern = true;
   4199             }
   4200         },
   4201 
   4202         .generic_poison => unreachable,
   4203         .unreachable_value => unreachable,
   4204 
   4205         .function => {},
   4206 
   4207         else => {
   4208             log.debug("send global const to linker: {*} ({s})", .{ decl, decl.name });
   4209             queue_linker_work = true;
   4210         },
   4211     }
   4212 
   4213     decl.ty = try decl_tv.ty.copy(decl_arena_allocator);
   4214     decl.val = try decl_tv.val.copy(decl_arena_allocator);
   4215     decl.@"align" = decl_align;
   4216     decl.@"linksection" = decl_linksection;
   4217     decl.@"addrspace" = address_space;
   4218     decl.has_tv = true;
   4219     decl_arena_state.* = decl_arena.state;
   4220     decl.value_arena = decl_arena_state;
   4221     decl.analysis = .complete;
   4222     decl.generation = mod.generation;
   4223 
   4224     const has_runtime_bits = is_extern or
   4225         (queue_linker_work and try sema.typeHasRuntimeBits(&block_scope, src, decl.ty));
   4226 
   4227     if (has_runtime_bits) {
   4228         log.debug("queue linker work for {*} ({s})", .{ decl, decl.name });
   4229 
   4230         // Needed for codegen_decl which will call updateDecl and then the
   4231         // codegen backend wants full access to the Decl Type.
   4232         try sema.resolveTypeFully(&block_scope, src, decl.ty);
   4233 
   4234         try mod.comp.bin_file.allocateDeclIndexes(decl_index);
   4235         try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index });
   4236 
   4237         if (type_changed and mod.emit_h != null) {
   4238             try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index });
   4239         }
   4240     }
   4241 
   4242     if (decl.is_exported) {
   4243         const export_src = src; // TODO point to the export token
   4244         // The scope needs to have the decl in it.
   4245         const options: std.builtin.ExportOptions = .{ .name = mem.sliceTo(decl.name, 0) };
   4246         try sema.analyzeExport(&block_scope, export_src, options, decl_index);
   4247     }
   4248 
   4249     return type_changed;
   4250 }
   4251 
   4252 /// Returns the depender's index of the dependee.
   4253 pub fn declareDeclDependency(mod: *Module, depender_index: Decl.Index, dependee_index: Decl.Index) !void {
   4254     if (depender_index == dependee_index) return;
   4255 
   4256     const depender = mod.declPtr(depender_index);
   4257     const dependee = mod.declPtr(dependee_index);
   4258 
   4259     log.debug("{*} ({s}) depends on {*} ({s})", .{
   4260         depender, depender.name, dependee, dependee.name,
   4261     });
   4262 
   4263     try depender.dependencies.ensureUnusedCapacity(mod.gpa, 1);
   4264     try dependee.dependants.ensureUnusedCapacity(mod.gpa, 1);
   4265 
   4266     if (dependee.deletion_flag) {
   4267         dependee.deletion_flag = false;
   4268         assert(mod.deletion_set.swapRemove(dependee_index));
   4269     }
   4270 
   4271     dependee.dependants.putAssumeCapacity(depender_index, {});
   4272     depender.dependencies.putAssumeCapacity(dependee_index, {});
   4273 }
   4274 
   4275 pub const ImportFileResult = struct {
   4276     file: *File,
   4277     is_new: bool,
   4278 };
   4279 
   4280 pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult {
   4281     const gpa = mod.gpa;
   4282 
   4283     // The resolved path is used as the key in the import table, to detect if
   4284     // an import refers to the same as another, despite different relative paths
   4285     // or differently mapped package names.
   4286     const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{
   4287         pkg.root_src_directory.path orelse ".", pkg.root_src_path,
   4288     });
   4289     var keep_resolved_path = false;
   4290     defer if (!keep_resolved_path) gpa.free(resolved_path);
   4291 
   4292     const gop = try mod.import_table.getOrPut(gpa, resolved_path);
   4293     errdefer _ = mod.import_table.pop();
   4294     if (gop.found_existing) return ImportFileResult{
   4295         .file = gop.value_ptr.*,
   4296         .is_new = false,
   4297     };
   4298 
   4299     const sub_file_path = try gpa.dupe(u8, pkg.root_src_path);
   4300     errdefer gpa.free(sub_file_path);
   4301 
   4302     const new_file = try gpa.create(File);
   4303     errdefer gpa.destroy(new_file);
   4304 
   4305     keep_resolved_path = true; // It's now owned by import_table.
   4306     gop.value_ptr.* = new_file;
   4307     new_file.* = .{
   4308         .sub_file_path = sub_file_path,
   4309         .source = undefined,
   4310         .source_loaded = false,
   4311         .tree_loaded = false,
   4312         .zir_loaded = false,
   4313         .stat = undefined,
   4314         .tree = undefined,
   4315         .zir = undefined,
   4316         .status = .never_loaded,
   4317         .pkg = pkg,
   4318         .root_decl = .none,
   4319     };
   4320     return ImportFileResult{
   4321         .file = new_file,
   4322         .is_new = true,
   4323     };
   4324 }
   4325 
   4326 pub fn importFile(
   4327     mod: *Module,
   4328     cur_file: *File,
   4329     import_string: []const u8,
   4330 ) !ImportFileResult {
   4331     if (cur_file.pkg.table.get(import_string)) |pkg| {
   4332         return mod.importPkg(pkg);
   4333     }
   4334     if (!mem.endsWith(u8, import_string, ".zig")) {
   4335         return error.PackageNotFound;
   4336     }
   4337     const gpa = mod.gpa;
   4338 
   4339     // The resolved path is used as the key in the import table, to detect if
   4340     // an import refers to the same as another, despite different relative paths
   4341     // or differently mapped package names.
   4342     const cur_pkg_dir_path = cur_file.pkg.root_src_directory.path orelse ".";
   4343     const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{
   4344         cur_pkg_dir_path, cur_file.sub_file_path, "..", import_string,
   4345     });
   4346     var keep_resolved_path = false;
   4347     defer if (!keep_resolved_path) gpa.free(resolved_path);
   4348 
   4349     const gop = try mod.import_table.getOrPut(gpa, resolved_path);
   4350     errdefer _ = mod.import_table.pop();
   4351     if (gop.found_existing) return ImportFileResult{
   4352         .file = gop.value_ptr.*,
   4353         .is_new = false,
   4354     };
   4355 
   4356     const new_file = try gpa.create(File);
   4357     errdefer gpa.destroy(new_file);
   4358 
   4359     const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path});
   4360     defer gpa.free(resolved_root_path);
   4361 
   4362     if (!mem.startsWith(u8, resolved_path, resolved_root_path)) {
   4363         return error.ImportOutsidePkgPath;
   4364     }
   4365     // +1 for the directory separator here.
   4366     const sub_file_path = try gpa.dupe(u8, resolved_path[resolved_root_path.len + 1 ..]);
   4367     errdefer gpa.free(sub_file_path);
   4368 
   4369     log.debug("new importFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, import_string={s}", .{
   4370         resolved_root_path, resolved_path, sub_file_path, import_string,
   4371     });
   4372 
   4373     keep_resolved_path = true; // It's now owned by import_table.
   4374     gop.value_ptr.* = new_file;
   4375     new_file.* = .{
   4376         .sub_file_path = sub_file_path,
   4377         .source = undefined,
   4378         .source_loaded = false,
   4379         .tree_loaded = false,
   4380         .zir_loaded = false,
   4381         .stat = undefined,
   4382         .tree = undefined,
   4383         .zir = undefined,
   4384         .status = .never_loaded,
   4385         .pkg = cur_file.pkg,
   4386         .root_decl = .none,
   4387     };
   4388     return ImportFileResult{
   4389         .file = new_file,
   4390         .is_new = true,
   4391     };
   4392 }
   4393 
   4394 pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*EmbedFile {
   4395     const gpa = mod.gpa;
   4396 
   4397     // The resolved path is used as the key in the table, to detect if
   4398     // a file refers to the same as another, despite different relative paths.
   4399     const cur_pkg_dir_path = cur_file.pkg.root_src_directory.path orelse ".";
   4400     const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{
   4401         cur_pkg_dir_path, cur_file.sub_file_path, "..", rel_file_path,
   4402     });
   4403     var keep_resolved_path = false;
   4404     defer if (!keep_resolved_path) gpa.free(resolved_path);
   4405 
   4406     const gop = try mod.embed_table.getOrPut(gpa, resolved_path);
   4407     errdefer assert(mod.embed_table.remove(resolved_path));
   4408     if (gop.found_existing) return gop.value_ptr.*;
   4409 
   4410     const new_file = try gpa.create(EmbedFile);
   4411     errdefer gpa.destroy(new_file);
   4412 
   4413     const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path});
   4414     defer gpa.free(resolved_root_path);
   4415 
   4416     if (!mem.startsWith(u8, resolved_path, resolved_root_path)) {
   4417         return error.ImportOutsidePkgPath;
   4418     }
   4419     // +1 for the directory separator here.
   4420     const sub_file_path = try gpa.dupe(u8, resolved_path[resolved_root_path.len + 1 ..]);
   4421     errdefer gpa.free(sub_file_path);
   4422 
   4423     var file = try cur_file.pkg.root_src_directory.handle.openFile(sub_file_path, .{});
   4424     defer file.close();
   4425 
   4426     const actual_stat = try file.stat();
   4427     const stat: Cache.File.Stat = .{
   4428         .size = actual_stat.size,
   4429         .inode = actual_stat.inode,
   4430         .mtime = actual_stat.mtime,
   4431     };
   4432     const size_usize = std.math.cast(usize, actual_stat.size) orelse return error.Overflow;
   4433     const bytes = try file.readToEndAllocOptions(gpa, std.math.maxInt(u32), size_usize, 1, 0);
   4434     errdefer gpa.free(bytes);
   4435 
   4436     log.debug("new embedFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, rel_file_path={s}", .{
   4437         resolved_root_path, resolved_path, sub_file_path, rel_file_path,
   4438     });
   4439 
   4440     if (mod.comp.whole_cache_manifest) |man| {
   4441         const copied_resolved_path = try gpa.dupe(u8, resolved_path);
   4442         errdefer gpa.free(copied_resolved_path);
   4443         try man.addFilePostContents(copied_resolved_path, bytes, stat);
   4444     }
   4445 
   4446     keep_resolved_path = true; // It's now owned by embed_table.
   4447     gop.value_ptr.* = new_file;
   4448     new_file.* = .{
   4449         .sub_file_path = sub_file_path,
   4450         .bytes = bytes,
   4451         .stat = stat,
   4452         .pkg = cur_file.pkg,
   4453         .owner_decl = undefined, // Set by Sema immediately after this function returns.
   4454     };
   4455     return new_file;
   4456 }
   4457 
   4458 pub fn detectEmbedFileUpdate(mod: *Module, embed_file: *EmbedFile) !void {
   4459     var file = try embed_file.pkg.root_src_directory.handle.openFile(embed_file.sub_file_path, .{});
   4460     defer file.close();
   4461 
   4462     const stat = try file.stat();
   4463 
   4464     const unchanged_metadata =
   4465         stat.size == embed_file.stat.size and
   4466         stat.mtime == embed_file.stat.mtime and
   4467         stat.inode == embed_file.stat.inode;
   4468 
   4469     if (unchanged_metadata) return;
   4470 
   4471     const gpa = mod.gpa;
   4472     const size_usize = std.math.cast(usize, stat.size) orelse return error.Overflow;
   4473     const bytes = try file.readToEndAllocOptions(gpa, std.math.maxInt(u32), size_usize, 1, 0);
   4474     gpa.free(embed_file.bytes);
   4475     embed_file.bytes = bytes;
   4476     embed_file.stat = .{
   4477         .size = stat.size,
   4478         .mtime = stat.mtime,
   4479         .inode = stat.inode,
   4480     };
   4481 
   4482     mod.comp.mutex.lock();
   4483     defer mod.comp.mutex.unlock();
   4484     try mod.comp.work_queue.writeItem(.{ .update_embed_file = embed_file });
   4485 }
   4486 
   4487 pub fn scanNamespace(
   4488     mod: *Module,
   4489     namespace: *Namespace,
   4490     extra_start: usize,
   4491     decls_len: u32,
   4492     parent_decl: *Decl,
   4493 ) SemaError!usize {
   4494     const tracy = trace(@src());
   4495     defer tracy.end();
   4496 
   4497     const gpa = mod.gpa;
   4498     const zir = namespace.file_scope.zir;
   4499 
   4500     try mod.comp.work_queue.ensureUnusedCapacity(decls_len);
   4501     try namespace.decls.ensureTotalCapacity(gpa, decls_len);
   4502 
   4503     const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
   4504     var extra_index = extra_start + bit_bags_count;
   4505     var bit_bag_index: usize = extra_start;
   4506     var cur_bit_bag: u32 = undefined;
   4507     var decl_i: u32 = 0;
   4508     var scan_decl_iter: ScanDeclIter = .{
   4509         .module = mod,
   4510         .namespace = namespace,
   4511         .parent_decl = parent_decl,
   4512     };
   4513     while (decl_i < decls_len) : (decl_i += 1) {
   4514         if (decl_i % 8 == 0) {
   4515             cur_bit_bag = zir.extra[bit_bag_index];
   4516             bit_bag_index += 1;
   4517         }
   4518         const flags = @truncate(u4, cur_bit_bag);
   4519         cur_bit_bag >>= 4;
   4520 
   4521         const decl_sub_index = extra_index;
   4522         extra_index += 8; // src_hash(4) + line(1) + name(1) + value(1) + doc_comment(1)
   4523         extra_index += @truncate(u1, flags >> 2); // Align
   4524         extra_index += @as(u2, @truncate(u1, flags >> 3)) * 2; // Link section or address space, consists of 2 Refs
   4525 
   4526         try scanDecl(&scan_decl_iter, decl_sub_index, flags);
   4527     }
   4528     return extra_index;
   4529 }
   4530 
   4531 const ScanDeclIter = struct {
   4532     module: *Module,
   4533     namespace: *Namespace,
   4534     parent_decl: *Decl,
   4535     usingnamespace_index: usize = 0,
   4536     comptime_index: usize = 0,
   4537     unnamed_test_index: usize = 0,
   4538 };
   4539 
   4540 fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!void {
   4541     const tracy = trace(@src());
   4542     defer tracy.end();
   4543 
   4544     const mod = iter.module;
   4545     const namespace = iter.namespace;
   4546     const gpa = mod.gpa;
   4547     const zir = namespace.file_scope.zir;
   4548 
   4549     // zig fmt: off
   4550     const is_pub                       = (flags & 0b0001) != 0;
   4551     const export_bit                   = (flags & 0b0010) != 0;
   4552     const has_align                    = (flags & 0b0100) != 0;
   4553     const has_linksection_or_addrspace = (flags & 0b1000) != 0;
   4554     // zig fmt: on
   4555 
   4556     const line_off = zir.extra[decl_sub_index + 4];
   4557     const line = iter.parent_decl.relativeToLine(line_off);
   4558     const decl_name_index = zir.extra[decl_sub_index + 5];
   4559     const decl_doccomment_index = zir.extra[decl_sub_index + 7];
   4560     const decl_zir_index = zir.extra[decl_sub_index + 6];
   4561     const decl_block_inst_data = zir.instructions.items(.data)[decl_zir_index].pl_node;
   4562     const decl_node = iter.parent_decl.relativeToNodeIndex(decl_block_inst_data.src_node);
   4563 
   4564     // Every Decl needs a name.
   4565     var is_named_test = false;
   4566     const decl_name: [:0]const u8 = switch (decl_name_index) {
   4567         0 => name: {
   4568             if (export_bit) {
   4569                 const i = iter.usingnamespace_index;
   4570                 iter.usingnamespace_index += 1;
   4571                 break :name try std.fmt.allocPrintZ(gpa, "usingnamespace_{d}", .{i});
   4572             } else {
   4573                 const i = iter.comptime_index;
   4574                 iter.comptime_index += 1;
   4575                 break :name try std.fmt.allocPrintZ(gpa, "comptime_{d}", .{i});
   4576             }
   4577         },
   4578         1 => name: {
   4579             const i = iter.unnamed_test_index;
   4580             iter.unnamed_test_index += 1;
   4581             break :name try std.fmt.allocPrintZ(gpa, "test_{d}", .{i});
   4582         },
   4583         2 => name: {
   4584             is_named_test = true;
   4585             const test_name = zir.nullTerminatedString(decl_doccomment_index);
   4586             break :name try std.fmt.allocPrintZ(gpa, "decltest.{s}", .{test_name});
   4587         },
   4588         else => name: {
   4589             const raw_name = zir.nullTerminatedString(decl_name_index);
   4590             if (raw_name.len == 0) {
   4591                 is_named_test = true;
   4592                 const test_name = zir.nullTerminatedString(decl_name_index + 1);
   4593                 break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name});
   4594             } else {
   4595                 break :name try gpa.dupeZ(u8, raw_name);
   4596             }
   4597         },
   4598     };
   4599     const is_exported = export_bit and decl_name_index != 0;
   4600     const is_usingnamespace = export_bit and decl_name_index == 0;
   4601     if (is_usingnamespace) try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1);
   4602 
   4603     // We create a Decl for it regardless of analysis status.
   4604     const gop = try namespace.decls.getOrPutContextAdapted(
   4605         gpa,
   4606         @as([]const u8, mem.sliceTo(decl_name, 0)),
   4607         DeclAdapter{ .mod = mod },
   4608         Namespace.DeclContext{ .module = mod },
   4609     );
   4610     const comp = mod.comp;
   4611     if (!gop.found_existing) {
   4612         const new_decl_index = try mod.allocateNewDecl(namespace, decl_node, iter.parent_decl.src_scope);
   4613         const new_decl = mod.declPtr(new_decl_index);
   4614         new_decl.name = decl_name;
   4615         if (is_usingnamespace) {
   4616             namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub);
   4617         }
   4618         log.debug("scan new {*} ({s}) into {*}", .{ new_decl, decl_name, namespace });
   4619         new_decl.src_line = line;
   4620         gop.key_ptr.* = new_decl_index;
   4621         // Exported decls, comptime decls, usingnamespace decls, and
   4622         // test decls if in test mode, get analyzed.
   4623         const decl_pkg = namespace.file_scope.pkg;
   4624         const want_analysis = is_exported or switch (decl_name_index) {
   4625             0 => true, // comptime or usingnamespace decl
   4626             1 => blk: {
   4627                 // test decl with no name. Skip the part where we check against
   4628                 // the test name filter.
   4629                 if (!comp.bin_file.options.is_test) break :blk false;
   4630                 if (decl_pkg != mod.main_pkg) {
   4631                     if (!mod.main_pkg_in_std) break :blk false;
   4632                     const std_pkg = mod.main_pkg.table.get("std").?;
   4633                     if (std_pkg != decl_pkg) break :blk false;
   4634                 }
   4635                 try mod.test_functions.put(gpa, new_decl_index, {});
   4636                 break :blk true;
   4637             },
   4638             else => blk: {
   4639                 if (!is_named_test) break :blk false;
   4640                 if (!comp.bin_file.options.is_test) break :blk false;
   4641                 if (decl_pkg != mod.main_pkg) {
   4642                     if (!mod.main_pkg_in_std) break :blk false;
   4643                     const std_pkg = mod.main_pkg.table.get("std").?;
   4644                     if (std_pkg != decl_pkg) break :blk false;
   4645                 }
   4646                 if (comp.test_filter) |test_filter| {
   4647                     if (mem.indexOf(u8, decl_name, test_filter) == null) {
   4648                         break :blk false;
   4649                     }
   4650                 }
   4651                 try mod.test_functions.put(gpa, new_decl_index, {});
   4652                 break :blk true;
   4653             },
   4654         };
   4655         if (want_analysis) {
   4656             comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl_index });
   4657         }
   4658         new_decl.is_pub = is_pub;
   4659         new_decl.is_exported = is_exported;
   4660         new_decl.is_usingnamespace = is_usingnamespace;
   4661         new_decl.has_align = has_align;
   4662         new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
   4663         new_decl.zir_decl_index = @intCast(u32, decl_sub_index);
   4664         new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive.
   4665         return;
   4666     }
   4667     gpa.free(decl_name);
   4668     const decl_index = gop.key_ptr.*;
   4669     const decl = mod.declPtr(decl_index);
   4670     log.debug("scan existing {*} ({s}) of {*}", .{ decl, decl.name, namespace });
   4671     // Update the AST node of the decl; even if its contents are unchanged, it may
   4672     // have been re-ordered.
   4673     decl.src_node = decl_node;
   4674     decl.src_line = line;
   4675 
   4676     decl.is_pub = is_pub;
   4677     decl.is_exported = is_exported;
   4678     decl.is_usingnamespace = is_usingnamespace;
   4679     decl.has_align = has_align;
   4680     decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
   4681     decl.zir_decl_index = @intCast(u32, decl_sub_index);
   4682     if (decl.getFunction()) |_| {
   4683         switch (comp.bin_file.tag) {
   4684             .coff => {
   4685                 // TODO Implement for COFF
   4686             },
   4687             .elf => if (decl.fn_link.elf.len != 0) {
   4688                 // TODO Look into detecting when this would be unnecessary by storing enough state
   4689                 // in `Decl` to notice that the line number did not change.
   4690                 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
   4691             },
   4692             .macho => if (decl.fn_link.macho.len != 0) {
   4693                 // TODO Look into detecting when this would be unnecessary by storing enough state
   4694                 // in `Decl` to notice that the line number did not change.
   4695                 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
   4696             },
   4697             .plan9 => {
   4698                 // TODO Look into detecting when this would be unnecessary by storing enough state
   4699                 // in `Decl` to notice that the line number did not change.
   4700                 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
   4701             },
   4702             .c, .wasm, .spirv, .nvptx => {},
   4703         }
   4704     }
   4705 }
   4706 
   4707 /// Make it as if the semantic analysis for this Decl never happened.
   4708 pub fn clearDecl(
   4709     mod: *Module,
   4710     decl_index: Decl.Index,
   4711     outdated_decls: ?*std.AutoArrayHashMap(Decl.Index, void),
   4712 ) Allocator.Error!void {
   4713     const tracy = trace(@src());
   4714     defer tracy.end();
   4715 
   4716     const decl = mod.declPtr(decl_index);
   4717     log.debug("clearing {*} ({s})", .{ decl, decl.name });
   4718 
   4719     const gpa = mod.gpa;
   4720     try mod.deletion_set.ensureUnusedCapacity(gpa, decl.dependencies.count());
   4721 
   4722     if (outdated_decls) |map| {
   4723         _ = map.swapRemove(decl_index);
   4724         try map.ensureUnusedCapacity(decl.dependants.count());
   4725     }
   4726 
   4727     // Remove itself from its dependencies.
   4728     for (decl.dependencies.keys()) |dep_index| {
   4729         const dep = mod.declPtr(dep_index);
   4730         dep.removeDependant(decl_index);
   4731         if (dep.dependants.count() == 0 and !dep.deletion_flag) {
   4732             log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{
   4733                 decl, decl.name, dep, dep.name,
   4734             });
   4735             // We don't recursively perform a deletion here, because during the update,
   4736             // another reference to it may turn up.
   4737             dep.deletion_flag = true;
   4738             mod.deletion_set.putAssumeCapacity(dep_index, {});
   4739         }
   4740     }
   4741     decl.dependencies.clearRetainingCapacity();
   4742 
   4743     // Anything that depends on this deleted decl needs to be re-analyzed.
   4744     for (decl.dependants.keys()) |dep_index| {
   4745         const dep = mod.declPtr(dep_index);
   4746         dep.removeDependency(decl_index);
   4747         if (outdated_decls) |map| {
   4748             map.putAssumeCapacity(dep_index, {});
   4749         }
   4750     }
   4751     decl.dependants.clearRetainingCapacity();
   4752 
   4753     if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| {
   4754         kv.value.destroy(gpa);
   4755     }
   4756     if (mod.emit_h) |emit_h| {
   4757         if (emit_h.failed_decls.fetchSwapRemove(decl_index)) |kv| {
   4758             kv.value.destroy(gpa);
   4759         }
   4760         assert(emit_h.decl_table.swapRemove(decl_index));
   4761     }
   4762     _ = mod.compile_log_decls.swapRemove(decl_index);
   4763     mod.deleteDeclExports(decl_index);
   4764 
   4765     if (decl.has_tv) {
   4766         if (decl.ty.isFnOrHasRuntimeBits()) {
   4767             mod.comp.bin_file.freeDecl(decl_index);
   4768 
   4769             // TODO instead of a union, put this memory trailing Decl objects,
   4770             // and allow it to be variably sized.
   4771             decl.link = switch (mod.comp.bin_file.tag) {
   4772                 .coff => .{ .coff = link.File.Coff.TextBlock.empty },
   4773                 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
   4774                 .macho => .{ .macho = link.File.MachO.TextBlock.empty },
   4775                 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
   4776                 .c => .{ .c = {} },
   4777                 .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },
   4778                 .spirv => .{ .spirv = {} },
   4779                 .nvptx => .{ .nvptx = {} },
   4780             };
   4781             decl.fn_link = switch (mod.comp.bin_file.tag) {
   4782                 .coff => .{ .coff = {} },
   4783                 .elf => .{ .elf = link.File.Dwarf.SrcFn.empty },
   4784                 .macho => .{ .macho = link.File.Dwarf.SrcFn.empty },
   4785                 .plan9 => .{ .plan9 = {} },
   4786                 .c => .{ .c = {} },
   4787                 .wasm => .{ .wasm = link.File.Wasm.FnData.empty },
   4788                 .spirv => .{ .spirv = .{} },
   4789                 .nvptx => .{ .nvptx = {} },
   4790             };
   4791         }
   4792         if (decl.getInnerNamespace()) |namespace| {
   4793             try namespace.deleteAllDecls(mod, outdated_decls);
   4794         }
   4795         decl.clearValues(mod);
   4796     }
   4797 
   4798     if (decl.deletion_flag) {
   4799         decl.deletion_flag = false;
   4800         assert(mod.deletion_set.swapRemove(decl_index));
   4801     }
   4802 
   4803     decl.analysis = .unreferenced;
   4804 }
   4805 
   4806 /// This function is exclusively called for anonymous decls.
   4807 pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void {
   4808     const decl = mod.declPtr(decl_index);
   4809     log.debug("deleteUnusedDecl {d} ({s})", .{ decl_index, decl.name });
   4810 
   4811     // TODO: remove `allocateDeclIndexes` and make the API that the linker backends
   4812     // are required to notice the first time `updateDecl` happens and keep track
   4813     // of it themselves. However they can rely on getting a `freeDecl` call if any
   4814     // `updateDecl` or `updateFunc` calls happen. This will allow us to avoid any call
   4815     // into the linker backend here, since the linker backend will never have been told
   4816     // about the Decl in the first place.
   4817     // Until then, we did call `allocateDeclIndexes` on this anonymous Decl and so we
   4818     // must call `freeDecl` in the linker backend now.
   4819     switch (mod.comp.bin_file.tag) {
   4820         .c => {}, // this linker backend has already migrated to the new API
   4821         else => if (decl.has_tv) {
   4822             if (decl.ty.isFnOrHasRuntimeBits()) {
   4823                 mod.comp.bin_file.freeDecl(decl_index);
   4824             }
   4825         },
   4826     }
   4827 
   4828     assert(!mod.declIsRoot(decl_index));
   4829     assert(decl.src_namespace.anon_decls.swapRemove(decl_index));
   4830 
   4831     const dependants = decl.dependants.keys();
   4832     for (dependants) |dep| {
   4833         mod.declPtr(dep).removeDependency(decl_index);
   4834     }
   4835 
   4836     for (decl.dependencies.keys()) |dep| {
   4837         mod.declPtr(dep).removeDependant(decl_index);
   4838     }
   4839     mod.destroyDecl(decl_index);
   4840 }
   4841 
   4842 /// We don't perform a deletion here, because this Decl or another one
   4843 /// may end up referencing it before the update is complete.
   4844 fn markDeclForDeletion(mod: *Module, decl_index: Decl.Index) !void {
   4845     const decl = mod.declPtr(decl_index);
   4846     decl.deletion_flag = true;
   4847     try mod.deletion_set.put(mod.gpa, decl_index, {});
   4848 }
   4849 
   4850 /// Cancel the creation of an anon decl and delete any references to it.
   4851 /// If other decls depend on this decl, they must be aborted first.
   4852 pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void {
   4853     const decl = mod.declPtr(decl_index);
   4854     log.debug("abortAnonDecl {*} ({s})", .{ decl, decl.name });
   4855 
   4856     assert(!mod.declIsRoot(decl_index));
   4857     assert(decl.src_namespace.anon_decls.swapRemove(decl_index));
   4858 
   4859     // An aborted decl must not have dependants -- they must have
   4860     // been aborted first and removed from this list.
   4861     assert(decl.dependants.count() == 0);
   4862 
   4863     for (decl.dependencies.keys()) |dep_index| {
   4864         const dep = mod.declPtr(dep_index);
   4865         dep.removeDependant(decl_index);
   4866     }
   4867 
   4868     mod.destroyDecl(decl_index);
   4869 }
   4870 
   4871 /// Delete all the Export objects that are caused by this Decl. Re-analysis of
   4872 /// this Decl will cause them to be re-created (or not).
   4873 fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) void {
   4874     const kv = mod.export_owners.fetchSwapRemove(decl_index) orelse return;
   4875 
   4876     for (kv.value) |exp| {
   4877         if (mod.decl_exports.getPtr(exp.exported_decl)) |value_ptr| {
   4878             // Remove exports with owner_decl matching the regenerating decl.
   4879             const list = value_ptr.*;
   4880             var i: usize = 0;
   4881             var new_len = list.len;
   4882             while (i < new_len) {
   4883                 if (list[i].owner_decl == decl_index) {
   4884                     mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
   4885                     new_len -= 1;
   4886                 } else {
   4887                     i += 1;
   4888                 }
   4889             }
   4890             value_ptr.* = mod.gpa.shrink(list, new_len);
   4891             if (new_len == 0) {
   4892                 assert(mod.decl_exports.swapRemove(exp.exported_decl));
   4893             }
   4894         }
   4895         if (mod.comp.bin_file.cast(link.File.Elf)) |elf| {
   4896             elf.deleteExport(exp.link.elf);
   4897         }
   4898         if (mod.comp.bin_file.cast(link.File.MachO)) |macho| {
   4899             macho.deleteExport(exp.link.macho);
   4900         }
   4901         if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| {
   4902             wasm.deleteExport(exp.link.wasm);
   4903         }
   4904         if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| {
   4905             failed_kv.value.destroy(mod.gpa);
   4906         }
   4907         mod.gpa.free(exp.options.name);
   4908         mod.gpa.destroy(exp);
   4909     }
   4910     mod.gpa.free(kv.value);
   4911 }
   4912 
   4913 pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air {
   4914     const tracy = trace(@src());
   4915     defer tracy.end();
   4916 
   4917     const gpa = mod.gpa;
   4918     const decl_index = func.owner_decl;
   4919     const decl = mod.declPtr(decl_index);
   4920 
   4921     // Use the Decl's arena for captured values.
   4922     var decl_arena = decl.value_arena.?.promote(gpa);
   4923     defer decl.value_arena.?.* = decl_arena.state;
   4924     const decl_arena_allocator = decl_arena.allocator();
   4925 
   4926     var sema: Sema = .{
   4927         .mod = mod,
   4928         .gpa = gpa,
   4929         .arena = arena,
   4930         .perm_arena = decl_arena_allocator,
   4931         .code = decl.getFileScope().zir,
   4932         .owner_decl = decl,
   4933         .owner_decl_index = decl_index,
   4934         .func = func,
   4935         .fn_ret_ty = decl.ty.fnReturnType(),
   4936         .owner_func = func,
   4937         .branch_quota = @maximum(func.branch_quota, Sema.default_branch_quota),
   4938     };
   4939     defer sema.deinit();
   4940 
   4941     // reset in case calls to errorable functions are removed.
   4942     func.calls_or_awaits_errorable_fn = false;
   4943 
   4944     // First few indexes of extra are reserved and set at the end.
   4945     const reserved_count = @typeInfo(Air.ExtraIndex).Enum.fields.len;
   4946     try sema.air_extra.ensureTotalCapacity(gpa, reserved_count);
   4947     sema.air_extra.items.len += reserved_count;
   4948 
   4949     var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope);
   4950     defer wip_captures.deinit();
   4951 
   4952     var inner_block: Sema.Block = .{
   4953         .parent = null,
   4954         .sema = &sema,
   4955         .src_decl = decl_index,
   4956         .namespace = decl.src_namespace,
   4957         .wip_capture_scope = wip_captures.scope,
   4958         .instructions = .{},
   4959         .inlining = null,
   4960         .is_comptime = false,
   4961     };
   4962     defer inner_block.instructions.deinit(gpa);
   4963 
   4964     const fn_info = sema.code.getFnInfo(func.zir_body_inst);
   4965     const zir_tags = sema.code.instructions.items(.tag);
   4966 
   4967     // Here we are performing "runtime semantic analysis" for a function body, which means
   4968     // we must map the parameter ZIR instructions to `arg` AIR instructions.
   4969     // AIR requires the `arg` parameters to be the first N instructions.
   4970     // This could be a generic function instantiation, however, in which case we need to
   4971     // map the comptime parameters to constant values and only emit arg AIR instructions
   4972     // for the runtime ones.
   4973     const fn_ty = decl.ty;
   4974     const fn_ty_info = fn_ty.fnInfo();
   4975     const runtime_params_len = @intCast(u32, fn_ty_info.param_types.len);
   4976     try inner_block.instructions.ensureTotalCapacityPrecise(gpa, runtime_params_len);
   4977     try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len * 2); // * 2 for the `addType`
   4978     try sema.inst_map.ensureUnusedCapacity(gpa, fn_info.total_params_len);
   4979 
   4980     var runtime_param_index: usize = 0;
   4981     var total_param_index: usize = 0;
   4982     for (fn_info.param_body) |inst| {
   4983         const param: struct { name: u32, src: LazySrcLoc } = switch (zir_tags[inst]) {
   4984             .param, .param_comptime => blk: {
   4985                 const pl_tok = sema.code.instructions.items(.data)[inst].pl_tok;
   4986                 const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index).data;
   4987                 break :blk .{ .name = extra.name, .src = pl_tok.src() };
   4988             },
   4989 
   4990             .param_anytype, .param_anytype_comptime => blk: {
   4991                 const str_tok = sema.code.instructions.items(.data)[inst].str_tok;
   4992                 break :blk .{ .name = str_tok.start, .src = str_tok.src() };
   4993             },
   4994 
   4995             else => continue,
   4996         };
   4997 
   4998         const param_ty = if (func.comptime_args) |comptime_args| t: {
   4999             const arg_tv = comptime_args[total_param_index];
   5000 
   5001             const arg_val = if (arg_tv.val.tag() != .generic_poison)
   5002                 arg_tv.val
   5003             else if (arg_tv.ty.onePossibleValue()) |opv|
   5004                 opv
   5005             else
   5006                 break :t arg_tv.ty;
   5007 
   5008             const arg = try sema.addConstant(arg_tv.ty, arg_val);
   5009             sema.inst_map.putAssumeCapacityNoClobber(inst, arg);
   5010             total_param_index += 1;
   5011             continue;
   5012         } else fn_ty_info.param_types[runtime_param_index];
   5013 
   5014         const opt_opv = sema.typeHasOnePossibleValue(&inner_block, param.src, param_ty) catch |err| switch (err) {
   5015             error.NeededSourceLocation => unreachable,
   5016             error.GenericPoison => unreachable,
   5017             error.ComptimeReturn => unreachable,
   5018             error.ComptimeBreak => unreachable,
   5019             else => |e| return e,
   5020         };
   5021         if (opt_opv) |opv| {
   5022             const arg = try sema.addConstant(param_ty, opv);
   5023             sema.inst_map.putAssumeCapacityNoClobber(inst, arg);
   5024             total_param_index += 1;
   5025             runtime_param_index += 1;
   5026             continue;
   5027         }
   5028         const arg_index = @intCast(u32, sema.air_instructions.len);
   5029         inner_block.instructions.appendAssumeCapacity(arg_index);
   5030         sema.air_instructions.appendAssumeCapacity(.{
   5031             .tag = .arg,
   5032             .data = .{ .ty = param_ty },
   5033         });
   5034         sema.inst_map.putAssumeCapacityNoClobber(inst, Air.indexToRef(arg_index));
   5035         total_param_index += 1;
   5036         runtime_param_index += 1;
   5037     }
   5038 
   5039     func.state = .in_progress;
   5040     log.debug("set {s} to in_progress", .{decl.name});
   5041 
   5042     const last_arg_index = inner_block.instructions.items.len;
   5043 
   5044     sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) {
   5045         // TODO make these unreachable instead of @panic
   5046         error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"),
   5047         error.GenericPoison => @panic("zig compiler bug: GenericPoison"),
   5048         error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"),
   5049         else => |e| return e,
   5050     };
   5051 
   5052     // If we don't get an error return trace from a caller, create our own.
   5053     if (func.calls_or_awaits_errorable_fn and
   5054         mod.comp.bin_file.options.error_return_tracing and
   5055         !sema.fn_ret_ty.isError())
   5056     {
   5057         sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) {
   5058             // TODO make these unreachable instead of @panic
   5059             error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"),
   5060             error.GenericPoison => @panic("zig compiler bug: GenericPoison"),
   5061             error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"),
   5062             error.ComptimeBreak => @panic("zig compiler bug: ComptimeBreak"),
   5063             else => |e| return e,
   5064         };
   5065     }
   5066 
   5067     try wip_captures.finalize();
   5068 
   5069     // Copy the block into place and mark that as the main block.
   5070     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
   5071         inner_block.instructions.items.len);
   5072     const main_block_index = sema.addExtraAssumeCapacity(Air.Block{
   5073         .body_len = @intCast(u32, inner_block.instructions.items.len),
   5074     });
   5075     sema.air_extra.appendSliceAssumeCapacity(inner_block.instructions.items);
   5076     sema.air_extra.items[@enumToInt(Air.ExtraIndex.main_block)] = main_block_index;
   5077 
   5078     func.state = .success;
   5079     log.debug("set {s} to success", .{decl.name});
   5080 
   5081     // Finally we must resolve the return type and parameter types so that backends
   5082     // have full access to type information.
   5083     // Crucially, this happens *after* we set the function state to success above,
   5084     // so that dependencies on the function body will now be satisfied rather than
   5085     // result in circular dependency errors.
   5086     const src = LazySrcLoc.nodeOffset(0);
   5087     sema.resolveFnTypes(&inner_block, src, fn_ty_info) catch |err| switch (err) {
   5088         error.NeededSourceLocation => unreachable,
   5089         error.GenericPoison => unreachable,
   5090         error.ComptimeReturn => unreachable,
   5091         error.ComptimeBreak => unreachable,
   5092         error.AnalysisFail => {
   5093             // In this case our function depends on a type that had a compile error.
   5094             // We should not try to lower this function.
   5095             decl.analysis = .dependency_failure;
   5096             return error.AnalysisFail;
   5097         },
   5098         else => |e| return e,
   5099     };
   5100 
   5101     // Similarly, resolve any queued up types that were requested to be resolved for
   5102     // the backends.
   5103     for (sema.types_to_resolve.items) |inst_ref| {
   5104         const ty = sema.getTmpAir().getRefType(inst_ref);
   5105         sema.resolveTypeFully(&inner_block, src, ty) catch |err| switch (err) {
   5106             error.NeededSourceLocation => unreachable,
   5107             error.GenericPoison => unreachable,
   5108             error.ComptimeReturn => unreachable,
   5109             error.ComptimeBreak => unreachable,
   5110             error.AnalysisFail => {
   5111                 // In this case our function depends on a type that had a compile error.
   5112                 // We should not try to lower this function.
   5113                 decl.analysis = .dependency_failure;
   5114                 return error.AnalysisFail;
   5115             },
   5116             else => |e| return e,
   5117         };
   5118     }
   5119 
   5120     return Air{
   5121         .instructions = sema.air_instructions.toOwnedSlice(),
   5122         .extra = sema.air_extra.toOwnedSlice(gpa),
   5123         .values = sema.air_values.toOwnedSlice(gpa),
   5124     };
   5125 }
   5126 
   5127 fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void {
   5128     const decl = mod.declPtr(decl_index);
   5129     log.debug("mark outdated {*} ({s})", .{ decl, decl.name });
   5130     try mod.comp.work_queue.writeItem(.{ .analyze_decl = decl_index });
   5131     if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| {
   5132         kv.value.destroy(mod.gpa);
   5133     }
   5134     if (decl.has_tv and decl.owns_tv) {
   5135         if (decl.val.castTag(.function)) |payload| {
   5136             const func = payload.data;
   5137             _ = mod.align_stack_fns.remove(func);
   5138         }
   5139     }
   5140     if (mod.emit_h) |emit_h| {
   5141         if (emit_h.failed_decls.fetchSwapRemove(decl_index)) |kv| {
   5142             kv.value.destroy(mod.gpa);
   5143         }
   5144     }
   5145     _ = mod.compile_log_decls.swapRemove(decl_index);
   5146     decl.analysis = .outdated;
   5147 }
   5148 
   5149 pub fn allocateNewDecl(
   5150     mod: *Module,
   5151     namespace: *Namespace,
   5152     src_node: Ast.Node.Index,
   5153     src_scope: ?*CaptureScope,
   5154 ) !Decl.Index {
   5155     const decl_and_index: struct {
   5156         new_decl: *Decl,
   5157         decl_index: Decl.Index,
   5158     } = if (mod.decls_free_list.popOrNull()) |decl_index| d: {
   5159         break :d .{
   5160             .new_decl = mod.declPtr(decl_index),
   5161             .decl_index = decl_index,
   5162         };
   5163     } else d: {
   5164         const decl = try mod.allocated_decls.addOne(mod.gpa);
   5165         errdefer mod.allocated_decls.shrinkRetainingCapacity(mod.allocated_decls.len - 1);
   5166         if (mod.emit_h) |mod_emit_h| {
   5167             const decl_emit_h = try mod_emit_h.allocated_emit_h.addOne(mod.gpa);
   5168             decl_emit_h.* = .{};
   5169         }
   5170         break :d .{
   5171             .new_decl = decl,
   5172             .decl_index = @intToEnum(Decl.Index, mod.allocated_decls.len - 1),
   5173         };
   5174     };
   5175 
   5176     decl_and_index.new_decl.* = .{
   5177         .name = undefined,
   5178         .src_namespace = namespace,
   5179         .src_node = src_node,
   5180         .src_line = undefined,
   5181         .has_tv = false,
   5182         .owns_tv = false,
   5183         .ty = undefined,
   5184         .val = undefined,
   5185         .@"align" = undefined,
   5186         .@"linksection" = undefined,
   5187         .@"addrspace" = .generic,
   5188         .analysis = .unreferenced,
   5189         .deletion_flag = false,
   5190         .zir_decl_index = 0,
   5191         .src_scope = src_scope,
   5192         .link = switch (mod.comp.bin_file.tag) {
   5193             .coff => .{ .coff = link.File.Coff.TextBlock.empty },
   5194             .elf => .{ .elf = link.File.Elf.TextBlock.empty },
   5195             .macho => .{ .macho = link.File.MachO.TextBlock.empty },
   5196             .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
   5197             .c => .{ .c = {} },
   5198             .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },
   5199             .spirv => .{ .spirv = {} },
   5200             .nvptx => .{ .nvptx = {} },
   5201         },
   5202         .fn_link = switch (mod.comp.bin_file.tag) {
   5203             .coff => .{ .coff = {} },
   5204             .elf => .{ .elf = link.File.Dwarf.SrcFn.empty },
   5205             .macho => .{ .macho = link.File.Dwarf.SrcFn.empty },
   5206             .plan9 => .{ .plan9 = {} },
   5207             .c => .{ .c = {} },
   5208             .wasm => .{ .wasm = link.File.Wasm.FnData.empty },
   5209             .spirv => .{ .spirv = .{} },
   5210             .nvptx => .{ .nvptx = {} },
   5211         },
   5212         .generation = 0,
   5213         .is_pub = false,
   5214         .is_exported = false,
   5215         .has_linksection_or_addrspace = false,
   5216         .has_align = false,
   5217         .alive = false,
   5218         .is_usingnamespace = false,
   5219     };
   5220 
   5221     return decl_and_index.decl_index;
   5222 }
   5223 
   5224 /// Get error value for error tag `name`.
   5225 pub fn getErrorValue(mod: *Module, name: []const u8) !std.StringHashMapUnmanaged(ErrorInt).KV {
   5226     const gop = try mod.global_error_set.getOrPut(mod.gpa, name);
   5227     if (gop.found_existing) {
   5228         return std.StringHashMapUnmanaged(ErrorInt).KV{
   5229             .key = gop.key_ptr.*,
   5230             .value = gop.value_ptr.*,
   5231         };
   5232     }
   5233 
   5234     errdefer assert(mod.global_error_set.remove(name));
   5235     try mod.error_name_list.ensureUnusedCapacity(mod.gpa, 1);
   5236     gop.key_ptr.* = try mod.gpa.dupe(u8, name);
   5237     gop.value_ptr.* = @intCast(ErrorInt, mod.error_name_list.items.len);
   5238     mod.error_name_list.appendAssumeCapacity(gop.key_ptr.*);
   5239     return std.StringHashMapUnmanaged(ErrorInt).KV{
   5240         .key = gop.key_ptr.*,
   5241         .value = gop.value_ptr.*,
   5242     };
   5243 }
   5244 
   5245 pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedValue) !Decl.Index {
   5246     const src_decl = mod.declPtr(block.src_decl);
   5247     return mod.createAnonymousDeclFromDecl(src_decl, block.namespace, block.wip_capture_scope, typed_value);
   5248 }
   5249 
   5250 pub fn createAnonymousDeclFromDecl(
   5251     mod: *Module,
   5252     src_decl: *Decl,
   5253     namespace: *Namespace,
   5254     src_scope: ?*CaptureScope,
   5255     tv: TypedValue,
   5256 ) !Decl.Index {
   5257     const new_decl_index = try mod.allocateNewDecl(namespace, src_decl.src_node, src_scope);
   5258     errdefer mod.destroyDecl(new_decl_index);
   5259     const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{
   5260         src_decl.name, @enumToInt(new_decl_index),
   5261     });
   5262     try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, tv, name);
   5263     return new_decl_index;
   5264 }
   5265 
   5266 /// Takes ownership of `name` even if it returns an error.
   5267 pub fn initNewAnonDecl(
   5268     mod: *Module,
   5269     new_decl_index: Decl.Index,
   5270     src_line: u32,
   5271     namespace: *Namespace,
   5272     typed_value: TypedValue,
   5273     name: [:0]u8,
   5274 ) !void {
   5275     errdefer mod.gpa.free(name);
   5276 
   5277     const new_decl = mod.declPtr(new_decl_index);
   5278 
   5279     new_decl.name = name;
   5280     new_decl.src_line = src_line;
   5281     new_decl.ty = typed_value.ty;
   5282     new_decl.val = typed_value.val;
   5283     new_decl.@"align" = 0;
   5284     new_decl.@"linksection" = null;
   5285     new_decl.has_tv = true;
   5286     new_decl.analysis = .complete;
   5287     new_decl.generation = mod.generation;
   5288 
   5289     try namespace.anon_decls.putNoClobber(mod.gpa, new_decl_index, {});
   5290 
   5291     // The Decl starts off with alive=false and the codegen backend will set alive=true
   5292     // if the Decl is referenced by an instruction or another constant. Otherwise,
   5293     // the Decl will be garbage collected by the `codegen_decl` task instead of sent
   5294     // to the linker.
   5295     if (typed_value.ty.isFnOrHasRuntimeBits()) {
   5296         try mod.comp.bin_file.allocateDeclIndexes(new_decl_index);
   5297         try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl_index });
   5298     }
   5299 }
   5300 
   5301 pub fn makeIntType(arena: Allocator, signedness: std.builtin.Signedness, bits: u16) !Type {
   5302     const int_payload = try arena.create(Type.Payload.Bits);
   5303     int_payload.* = .{
   5304         .base = .{
   5305             .tag = switch (signedness) {
   5306                 .signed => .int_signed,
   5307                 .unsigned => .int_unsigned,
   5308             },
   5309         },
   5310         .data = bits,
   5311     };
   5312     return Type.initPayload(&int_payload.base);
   5313 }
   5314 
   5315 pub fn errNoteNonLazy(
   5316     mod: *Module,
   5317     src_loc: SrcLoc,
   5318     parent: *ErrorMsg,
   5319     comptime format: []const u8,
   5320     args: anytype,
   5321 ) error{OutOfMemory}!void {
   5322     const msg = try std.fmt.allocPrint(mod.gpa, format, args);
   5323     errdefer mod.gpa.free(msg);
   5324 
   5325     parent.notes = try mod.gpa.realloc(parent.notes, parent.notes.len + 1);
   5326     parent.notes[parent.notes.len - 1] = .{
   5327         .src_loc = src_loc,
   5328         .msg = msg,
   5329     };
   5330 }
   5331 
   5332 pub fn getTarget(mod: Module) Target {
   5333     return mod.comp.bin_file.options.target;
   5334 }
   5335 
   5336 pub fn optimizeMode(mod: Module) std.builtin.Mode {
   5337     return mod.comp.bin_file.options.optimize_mode;
   5338 }
   5339 
   5340 fn lockAndClearFileCompileError(mod: *Module, file: *File) void {
   5341     switch (file.status) {
   5342         .success_zir, .retryable_failure => {},
   5343         .never_loaded, .parse_failure, .astgen_failure => {
   5344             mod.comp.mutex.lock();
   5345             defer mod.comp.mutex.unlock();
   5346             if (mod.failed_files.fetchSwapRemove(file)) |kv| {
   5347                 if (kv.value) |msg| msg.destroy(mod.gpa); // Delete previous error message.
   5348             }
   5349         },
   5350     }
   5351 }
   5352 
   5353 pub const SwitchProngSrc = union(enum) {
   5354     scalar: u32,
   5355     multi: Multi,
   5356     range: Multi,
   5357 
   5358     pub const Multi = struct {
   5359         prong: u32,
   5360         item: u32,
   5361     };
   5362 
   5363     pub const RangeExpand = enum { none, first, last };
   5364 
   5365     /// This function is intended to be called only when it is certain that we need
   5366     /// the LazySrcLoc in order to emit a compile error.
   5367     pub fn resolve(
   5368         prong_src: SwitchProngSrc,
   5369         gpa: Allocator,
   5370         decl: *Decl,
   5371         switch_node_offset: i32,
   5372         range_expand: RangeExpand,
   5373     ) LazySrcLoc {
   5374         @setCold(true);
   5375         const tree = decl.getFileScope().getTree(gpa) catch |err| {
   5376             // In this case we emit a warning + a less precise source location.
   5377             log.warn("unable to load {s}: {s}", .{
   5378                 decl.getFileScope().sub_file_path, @errorName(err),
   5379             });
   5380             return LazySrcLoc.nodeOffset(0);
   5381         };
   5382         const switch_node = decl.relativeToNodeIndex(switch_node_offset);
   5383         const main_tokens = tree.nodes.items(.main_token);
   5384         const node_datas = tree.nodes.items(.data);
   5385         const node_tags = tree.nodes.items(.tag);
   5386         const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
   5387         const case_nodes = tree.extra_data[extra.start..extra.end];
   5388 
   5389         var multi_i: u32 = 0;
   5390         var scalar_i: u32 = 0;
   5391         for (case_nodes) |case_node| {
   5392             const case = switch (node_tags[case_node]) {
   5393                 .switch_case_one => tree.switchCaseOne(case_node),
   5394                 .switch_case => tree.switchCase(case_node),
   5395                 else => unreachable,
   5396             };
   5397             if (case.ast.values.len == 0)
   5398                 continue;
   5399             if (case.ast.values.len == 1 and
   5400                 node_tags[case.ast.values[0]] == .identifier and
   5401                 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"))
   5402             {
   5403                 continue;
   5404             }
   5405             const is_multi = case.ast.values.len != 1 or
   5406                 node_tags[case.ast.values[0]] == .switch_range;
   5407 
   5408             switch (prong_src) {
   5409                 .scalar => |i| if (!is_multi and i == scalar_i) return LazySrcLoc.nodeOffset(
   5410                     decl.nodeIndexToRelative(case.ast.values[0]),
   5411                 ),
   5412                 .multi => |s| if (is_multi and s.prong == multi_i) {
   5413                     var item_i: u32 = 0;
   5414                     for (case.ast.values) |item_node| {
   5415                         if (node_tags[item_node] == .switch_range) continue;
   5416 
   5417                         if (item_i == s.item) return LazySrcLoc.nodeOffset(
   5418                             decl.nodeIndexToRelative(item_node),
   5419                         );
   5420                         item_i += 1;
   5421                     } else unreachable;
   5422                 },
   5423                 .range => |s| if (is_multi and s.prong == multi_i) {
   5424                     var range_i: u32 = 0;
   5425                     for (case.ast.values) |range| {
   5426                         if (node_tags[range] != .switch_range) continue;
   5427 
   5428                         if (range_i == s.item) switch (range_expand) {
   5429                             .none => return LazySrcLoc.nodeOffset(
   5430                                 decl.nodeIndexToRelative(range),
   5431                             ),
   5432                             .first => return LazySrcLoc.nodeOffset(
   5433                                 decl.nodeIndexToRelative(node_datas[range].lhs),
   5434                             ),
   5435                             .last => return LazySrcLoc.nodeOffset(
   5436                                 decl.nodeIndexToRelative(node_datas[range].rhs),
   5437                             ),
   5438                         };
   5439                         range_i += 1;
   5440                     } else unreachable;
   5441                 },
   5442             }
   5443             if (is_multi) {
   5444                 multi_i += 1;
   5445             } else {
   5446                 scalar_i += 1;
   5447             }
   5448         } else unreachable;
   5449     }
   5450 };
   5451 
   5452 pub const PeerTypeCandidateSrc = union(enum) {
   5453     /// Do not print out error notes for candidate sources
   5454     none: void,
   5455     /// When we want to know the the src of candidate i, look up at
   5456     /// index i in this slice
   5457     override: []LazySrcLoc,
   5458     /// resolvePeerTypes originates from a @TypeOf(...) call
   5459     typeof_builtin_call_node_offset: i32,
   5460 
   5461     pub fn resolve(
   5462         self: PeerTypeCandidateSrc,
   5463         gpa: Allocator,
   5464         decl: *Decl,
   5465         candidate_i: usize,
   5466     ) ?LazySrcLoc {
   5467         @setCold(true);
   5468 
   5469         switch (self) {
   5470             .none => {
   5471                 return null;
   5472             },
   5473             .override => |candidate_srcs| {
   5474                 return candidate_srcs[candidate_i];
   5475             },
   5476             .typeof_builtin_call_node_offset => |node_offset| {
   5477                 switch (candidate_i) {
   5478                     0 => return LazySrcLoc{ .node_offset_builtin_call_arg0 = node_offset },
   5479                     1 => return LazySrcLoc{ .node_offset_builtin_call_arg1 = node_offset },
   5480                     2 => return LazySrcLoc{ .node_offset_builtin_call_arg2 = node_offset },
   5481                     3 => return LazySrcLoc{ .node_offset_builtin_call_arg3 = node_offset },
   5482                     4 => return LazySrcLoc{ .node_offset_builtin_call_arg4 = node_offset },
   5483                     5 => return LazySrcLoc{ .node_offset_builtin_call_arg5 = node_offset },
   5484                     else => {},
   5485                 }
   5486 
   5487                 const tree = decl.getFileScope().getTree(gpa) catch |err| {
   5488                     // In this case we emit a warning + a less precise source location.
   5489                     log.warn("unable to load {s}: {s}", .{
   5490                         decl.getFileScope().sub_file_path, @errorName(err),
   5491                     });
   5492                     return LazySrcLoc.nodeOffset(0);
   5493                 };
   5494                 const node = decl.relativeToNodeIndex(node_offset);
   5495                 const node_datas = tree.nodes.items(.data);
   5496                 const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
   5497 
   5498                 return LazySrcLoc{ .node_abs = params[candidate_i] };
   5499             },
   5500         }
   5501     }
   5502 };
   5503 
   5504 const FieldSrcQuery = struct {
   5505     index: usize,
   5506     range: enum { name, type, value, alignment },
   5507 };
   5508 
   5509 fn queryFieldSrc(
   5510     tree: Ast,
   5511     query: FieldSrcQuery,
   5512     file_scope: *File,
   5513     container_decl: Ast.full.ContainerDecl,
   5514 ) SrcLoc {
   5515     const node_tags = tree.nodes.items(.tag);
   5516     var field_index: usize = 0;
   5517     for (container_decl.ast.members) |member_node| {
   5518         const field = switch (node_tags[member_node]) {
   5519             .container_field_init => tree.containerFieldInit(member_node),
   5520             .container_field_align => tree.containerFieldAlign(member_node),
   5521             .container_field => tree.containerField(member_node),
   5522             else => continue,
   5523         };
   5524         if (field_index == query.index) {
   5525             return switch (query.range) {
   5526                 .name => .{
   5527                     .file_scope = file_scope,
   5528                     .parent_decl_node = 0,
   5529                     .lazy = .{ .token_abs = field.ast.name_token },
   5530                 },
   5531                 .type => .{
   5532                     .file_scope = file_scope,
   5533                     .parent_decl_node = 0,
   5534                     .lazy = .{ .node_abs = field.ast.type_expr },
   5535                 },
   5536                 .value => .{
   5537                     .file_scope = file_scope,
   5538                     .parent_decl_node = 0,
   5539                     .lazy = .{ .node_abs = field.ast.value_expr },
   5540                 },
   5541                 .alignment => .{
   5542                     .file_scope = file_scope,
   5543                     .parent_decl_node = 0,
   5544                     .lazy = .{ .node_abs = field.ast.align_expr },
   5545                 },
   5546             };
   5547         }
   5548         field_index += 1;
   5549     }
   5550     unreachable;
   5551 }
   5552 
   5553 /// Called from `performAllTheWork`, after all AstGen workers have finished,
   5554 /// and before the main semantic analysis loop begins.
   5555 pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {
   5556     // Ultimately, the goal is to queue up `analyze_decl` tasks in the work queue
   5557     // for the outdated decls, but we cannot queue up the tasks until after
   5558     // we find out which ones have been deleted, otherwise there would be
   5559     // deleted Decl pointers in the work queue.
   5560     var outdated_decls = std.AutoArrayHashMap(Decl.Index, void).init(mod.gpa);
   5561     defer outdated_decls.deinit();
   5562     for (mod.import_table.values()) |file| {
   5563         try outdated_decls.ensureUnusedCapacity(file.outdated_decls.items.len);
   5564         for (file.outdated_decls.items) |decl_index| {
   5565             outdated_decls.putAssumeCapacity(decl_index, {});
   5566         }
   5567         file.outdated_decls.clearRetainingCapacity();
   5568 
   5569         // Handle explicitly deleted decls from the source code. This is one of two
   5570         // places that Decl deletions happen. The other is in `Compilation`, after
   5571         // `performAllTheWork`, where we iterate over `Module.deletion_set` and
   5572         // delete Decls which are no longer referenced.
   5573         // If a Decl is explicitly deleted from source, and also no longer referenced,
   5574         // it may be both in this `deleted_decls` set, as well as in the
   5575         // `Module.deletion_set`. To avoid deleting it twice, we remove it from the
   5576         // deletion set at this time.
   5577         for (file.deleted_decls.items) |decl_index| {
   5578             const decl = mod.declPtr(decl_index);
   5579             log.debug("deleted from source: {*} ({s})", .{ decl, decl.name });
   5580 
   5581             // Remove from the namespace it resides in, preserving declaration order.
   5582             assert(decl.zir_decl_index != 0);
   5583             _ = decl.src_namespace.decls.orderedRemoveAdapted(@as([]const u8, mem.sliceTo(decl.name, 0)), DeclAdapter{ .mod = mod });
   5584 
   5585             try mod.clearDecl(decl_index, &outdated_decls);
   5586             mod.destroyDecl(decl_index);
   5587         }
   5588         file.deleted_decls.clearRetainingCapacity();
   5589     }
   5590     // Finally we can queue up re-analysis tasks after we have processed
   5591     // the deleted decls.
   5592     for (outdated_decls.keys()) |key| {
   5593         try mod.markOutdatedDecl(key);
   5594     }
   5595 }
   5596 
   5597 /// Called from `Compilation.update`, after everything is done, just before
   5598 /// reporting compile errors. In this function we emit exported symbol collision
   5599 /// errors and communicate exported symbols to the linker backend.
   5600 pub fn processExports(mod: *Module) !void {
   5601     const gpa = mod.gpa;
   5602     // Map symbol names to `Export` for name collision detection.
   5603     var symbol_exports: std.StringArrayHashMapUnmanaged(*Export) = .{};
   5604     defer symbol_exports.deinit(gpa);
   5605 
   5606     var it = mod.decl_exports.iterator();
   5607     while (it.next()) |entry| {
   5608         const exported_decl = entry.key_ptr.*;
   5609         const exports = entry.value_ptr.*;
   5610         for (exports) |new_export| {
   5611             const gop = try symbol_exports.getOrPut(gpa, new_export.options.name);
   5612             if (gop.found_existing) {
   5613                 new_export.status = .failed_retryable;
   5614                 try mod.failed_exports.ensureUnusedCapacity(gpa, 1);
   5615                 const src_loc = new_export.getSrcLoc(mod);
   5616                 const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {s}", .{
   5617                     new_export.options.name,
   5618                 });
   5619                 errdefer msg.destroy(gpa);
   5620                 const other_export = gop.value_ptr.*;
   5621                 const other_src_loc = other_export.getSrcLoc(mod);
   5622                 try mod.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{});
   5623                 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
   5624                 new_export.status = .failed;
   5625             } else {
   5626                 gop.value_ptr.* = new_export;
   5627             }
   5628         }
   5629         mod.comp.bin_file.updateDeclExports(mod, exported_decl, exports) catch |err| switch (err) {
   5630             error.OutOfMemory => return error.OutOfMemory,
   5631             else => {
   5632                 const new_export = exports[0];
   5633                 new_export.status = .failed_retryable;
   5634                 try mod.failed_exports.ensureUnusedCapacity(gpa, 1);
   5635                 const src_loc = new_export.getSrcLoc(mod);
   5636                 const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{
   5637                     @errorName(err),
   5638                 });
   5639                 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
   5640             },
   5641         };
   5642     }
   5643 }
   5644 
   5645 pub fn populateTestFunctions(mod: *Module) !void {
   5646     const gpa = mod.gpa;
   5647     const builtin_pkg = mod.main_pkg.table.get("builtin").?;
   5648     const builtin_file = (mod.importPkg(builtin_pkg) catch unreachable).file;
   5649     const root_decl = mod.declPtr(builtin_file.root_decl.unwrap().?);
   5650     const builtin_namespace = root_decl.src_namespace;
   5651     const decl_index = builtin_namespace.decls.getKeyAdapted(@as([]const u8, "test_functions"), DeclAdapter{ .mod = mod }).?;
   5652     const decl = mod.declPtr(decl_index);
   5653     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
   5654     const tmp_test_fn_ty = decl.ty.slicePtrFieldType(&buf).elemType();
   5655 
   5656     const array_decl_index = d: {
   5657         // Add mod.test_functions to an array decl then make the test_functions
   5658         // decl reference it as a slice.
   5659         var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
   5660         errdefer new_decl_arena.deinit();
   5661         const arena = new_decl_arena.allocator();
   5662 
   5663         const test_fn_vals = try arena.alloc(Value, mod.test_functions.count());
   5664         const array_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, null, .{
   5665             .ty = try Type.Tag.array.create(arena, .{
   5666                 .len = test_fn_vals.len,
   5667                 .elem_type = try tmp_test_fn_ty.copy(arena),
   5668             }),
   5669             .val = try Value.Tag.aggregate.create(arena, test_fn_vals),
   5670         });
   5671         const array_decl = mod.declPtr(array_decl_index);
   5672 
   5673         // Add a dependency on each test name and function pointer.
   5674         try array_decl.dependencies.ensureUnusedCapacity(gpa, test_fn_vals.len * 2);
   5675 
   5676         for (mod.test_functions.keys()) |test_decl_index, i| {
   5677             const test_decl = mod.declPtr(test_decl_index);
   5678             const test_name_slice = mem.sliceTo(test_decl.name, 0);
   5679             const test_name_decl_index = n: {
   5680                 var name_decl_arena = std.heap.ArenaAllocator.init(gpa);
   5681                 errdefer name_decl_arena.deinit();
   5682                 const bytes = try name_decl_arena.allocator().dupe(u8, test_name_slice);
   5683                 const test_name_decl_index = try mod.createAnonymousDeclFromDecl(array_decl, array_decl.src_namespace, null, .{
   5684                     .ty = try Type.Tag.array_u8.create(name_decl_arena.allocator(), bytes.len),
   5685                     .val = try Value.Tag.bytes.create(name_decl_arena.allocator(), bytes),
   5686                 });
   5687                 try mod.declPtr(test_name_decl_index).finalizeNewArena(&name_decl_arena);
   5688                 break :n test_name_decl_index;
   5689             };
   5690             array_decl.dependencies.putAssumeCapacityNoClobber(test_decl_index, {});
   5691             array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl_index, {});
   5692             try mod.linkerUpdateDecl(test_name_decl_index);
   5693 
   5694             const field_vals = try arena.create([3]Value);
   5695             field_vals.* = .{
   5696                 try Value.Tag.slice.create(arena, .{
   5697                     .ptr = try Value.Tag.decl_ref.create(arena, test_name_decl_index),
   5698                     .len = try Value.Tag.int_u64.create(arena, test_name_slice.len),
   5699                 }), // name
   5700                 try Value.Tag.decl_ref.create(arena, test_decl_index), // func
   5701                 Value.initTag(.null_value), // async_frame_size
   5702             };
   5703             test_fn_vals[i] = try Value.Tag.aggregate.create(arena, field_vals);
   5704         }
   5705 
   5706         try array_decl.finalizeNewArena(&new_decl_arena);
   5707         break :d array_decl_index;
   5708     };
   5709     try mod.linkerUpdateDecl(array_decl_index);
   5710 
   5711     {
   5712         var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
   5713         errdefer new_decl_arena.deinit();
   5714         const arena = new_decl_arena.allocator();
   5715 
   5716         // This copy accesses the old Decl Type/Value so it must be done before `clearValues`.
   5717         const new_ty = try Type.Tag.const_slice.create(arena, try tmp_test_fn_ty.copy(arena));
   5718         const new_val = try Value.Tag.slice.create(arena, .{
   5719             .ptr = try Value.Tag.decl_ref.create(arena, array_decl_index),
   5720             .len = try Value.Tag.int_u64.create(arena, mod.test_functions.count()),
   5721         });
   5722 
   5723         // Since we are replacing the Decl's value we must perform cleanup on the
   5724         // previous value.
   5725         decl.clearValues(mod);
   5726         decl.ty = new_ty;
   5727         decl.val = new_val;
   5728         decl.has_tv = true;
   5729 
   5730         try decl.finalizeNewArena(&new_decl_arena);
   5731     }
   5732     try mod.linkerUpdateDecl(decl_index);
   5733 }
   5734 
   5735 pub fn linkerUpdateDecl(mod: *Module, decl_index: Decl.Index) !void {
   5736     const comp = mod.comp;
   5737 
   5738     if (comp.bin_file.options.emit == null) return;
   5739 
   5740     const decl = mod.declPtr(decl_index);
   5741 
   5742     comp.bin_file.updateDecl(mod, decl_index) catch |err| switch (err) {
   5743         error.OutOfMemory => return error.OutOfMemory,
   5744         error.AnalysisFail => {
   5745             decl.analysis = .codegen_failure;
   5746             return;
   5747         },
   5748         else => {
   5749             const gpa = mod.gpa;
   5750             try mod.failed_decls.ensureUnusedCapacity(gpa, 1);
   5751             mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
   5752                 gpa,
   5753                 decl.srcLoc(),
   5754                 "unable to codegen: {s}",
   5755                 .{@errorName(err)},
   5756             ));
   5757             decl.analysis = .codegen_failure_retryable;
   5758             return;
   5759         },
   5760     };
   5761 }
   5762 
   5763 fn reportRetryableFileError(
   5764     mod: *Module,
   5765     file: *File,
   5766     comptime format: []const u8,
   5767     args: anytype,
   5768 ) error{OutOfMemory}!void {
   5769     file.status = .retryable_failure;
   5770 
   5771     const err_msg = try ErrorMsg.create(
   5772         mod.gpa,
   5773         .{
   5774             .file_scope = file,
   5775             .parent_decl_node = 0,
   5776             .lazy = .entire_file,
   5777         },
   5778         format,
   5779         args,
   5780     );
   5781     errdefer err_msg.destroy(mod.gpa);
   5782 
   5783     mod.comp.mutex.lock();
   5784     defer mod.comp.mutex.unlock();
   5785 
   5786     const gop = try mod.failed_files.getOrPut(mod.gpa, file);
   5787     if (gop.found_existing) {
   5788         if (gop.value_ptr.*) |old_err_msg| {
   5789             old_err_msg.destroy(mod.gpa);
   5790         }
   5791     }
   5792     gop.value_ptr.* = err_msg;
   5793 }
   5794 
   5795 pub fn markReferencedDeclsAlive(mod: *Module, val: Value) void {
   5796     switch (val.tag()) {
   5797         .decl_ref_mut => return mod.markDeclIndexAlive(val.castTag(.decl_ref_mut).?.data.decl_index),
   5798         .extern_fn => return mod.markDeclIndexAlive(val.castTag(.extern_fn).?.data.owner_decl),
   5799         .function => return mod.markDeclIndexAlive(val.castTag(.function).?.data.owner_decl),
   5800         .variable => return mod.markDeclIndexAlive(val.castTag(.variable).?.data.owner_decl),
   5801         .decl_ref => return mod.markDeclIndexAlive(val.cast(Value.Payload.Decl).?.data),
   5802 
   5803         .repeated,
   5804         .eu_payload,
   5805         .opt_payload,
   5806         .empty_array_sentinel,
   5807         => return mod.markReferencedDeclsAlive(val.cast(Value.Payload.SubValue).?.data),
   5808 
   5809         .eu_payload_ptr,
   5810         .opt_payload_ptr,
   5811         => return mod.markReferencedDeclsAlive(val.cast(Value.Payload.PayloadPtr).?.data.container_ptr),
   5812 
   5813         .slice => {
   5814             const slice = val.cast(Value.Payload.Slice).?.data;
   5815             mod.markReferencedDeclsAlive(slice.ptr);
   5816             mod.markReferencedDeclsAlive(slice.len);
   5817         },
   5818 
   5819         .elem_ptr => {
   5820             const elem_ptr = val.cast(Value.Payload.ElemPtr).?.data;
   5821             return mod.markReferencedDeclsAlive(elem_ptr.array_ptr);
   5822         },
   5823         .field_ptr => {
   5824             const field_ptr = val.cast(Value.Payload.FieldPtr).?.data;
   5825             return mod.markReferencedDeclsAlive(field_ptr.container_ptr);
   5826         },
   5827         .aggregate => {
   5828             for (val.castTag(.aggregate).?.data) |field_val| {
   5829                 mod.markReferencedDeclsAlive(field_val);
   5830             }
   5831         },
   5832         .@"union" => {
   5833             const data = val.cast(Value.Payload.Union).?.data;
   5834             mod.markReferencedDeclsAlive(data.tag);
   5835             mod.markReferencedDeclsAlive(data.val);
   5836         },
   5837 
   5838         else => {},
   5839     }
   5840 }
   5841 
   5842 pub fn markDeclAlive(mod: *Module, decl: *Decl) void {
   5843     if (decl.alive) return;
   5844     decl.alive = true;
   5845 
   5846     // This is the first time we are marking this Decl alive. We must
   5847     // therefore recurse into its value and mark any Decl it references
   5848     // as also alive, so that any Decl referenced does not get garbage collected.
   5849     mod.markReferencedDeclsAlive(decl.val);
   5850 }
   5851 
   5852 fn markDeclIndexAlive(mod: *Module, decl_index: Decl.Index) void {
   5853     return mod.markDeclAlive(mod.declPtr(decl_index));
   5854 }
   5855 
   5856 pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u8) !void {
   5857     try mod.global_assembly.ensureUnusedCapacity(mod.gpa, 1);
   5858 
   5859     const duped_source = try mod.gpa.dupe(u8, source);
   5860     errdefer mod.gpa.free(duped_source);
   5861 
   5862     mod.global_assembly.putAssumeCapacityNoClobber(decl_index, duped_source);
   5863 }