Commit b8d2323b88

mlugg <mlugg@mlugg.co.uk>
2024-06-15 01:52:26
Sema: eliminate Block.src_decl
🦀 src_decl is gone 🦀 This commit eliminates the `src_decl` field from `Sema.Block`. This change goes further to eliminating unnecessary responsibilities of `Decl` in preparation for its major upcoming refactor. The two main remaining reponsibilities had to do with namespace types: `src_decl` was used to determine their line number and their name. The former use case is solved by storing the line number alongside type declarations (and reifications) in ZIR; this is actually more correct, since previously the line number assigned to the type was really the line number of the source declaration it was syntactically contained within, which does not necessarily line up. Consequently, this change makes debug info for namespace types more correct, although I am not sure how debuggers actually utilize this line number, if at all. Naming types was solved by a new field on `Block`, called `type_name_ctx`. In a sense, it represents the "namespace" we are currently within, including comptime function calls etc. We might want to revisit this in future, since the type naming rules seem to be a bit hand-wavey right now. As far as I can tell, there isn't any more preliminary work needed for me to start work on the behemoth task of splitting `Zcu.Decl` into the new `Nav` (Named Addressable Value) and `Cau` (Comptime Analysis Unit) types. This will be a sweeping change, impacting essentially every part of the pipeline after `AstGen`.
1 parent 1eaeb4a
lib/std/zig/AstGen.zig
@@ -13132,6 +13132,7 @@ const GenZir = struct {
             .fields_hash_1 = fields_hash_arr[1],
             .fields_hash_2 = fields_hash_arr[2],
             .fields_hash_3 = fields_hash_arr[3],
+            .src_line = astgen.source_line,
             .src_node = args.src_node,
         });
 
@@ -13192,6 +13193,7 @@ const GenZir = struct {
             .fields_hash_1 = fields_hash_arr[1],
             .fields_hash_2 = fields_hash_arr[2],
             .fields_hash_3 = fields_hash_arr[3],
+            .src_line = astgen.source_line,
             .src_node = args.src_node,
         });
 
@@ -13253,6 +13255,7 @@ const GenZir = struct {
             .fields_hash_1 = fields_hash_arr[1],
             .fields_hash_2 = fields_hash_arr[2],
             .fields_hash_3 = fields_hash_arr[3],
+            .src_line = astgen.source_line,
             .src_node = args.src_node,
         });
 
@@ -13300,7 +13303,10 @@ const GenZir = struct {
         assert(args.src_node != 0);
 
         try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.OpaqueDecl).Struct.fields.len + 2);
-        const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{ .src_node = args.src_node });
+        const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{
+            .src_line = astgen.source_line,
+            .src_node = args.src_node,
+        });
 
         if (args.captures_len != 0) {
             astgen.extra.appendAssumeCapacity(args.captures_len);
lib/std/zig/Zir.zig
@@ -1981,7 +1981,7 @@ pub const Inst = struct {
         /// `operand` is payload index to `UnNode`.
         error_from_int,
         /// Implement builtin `@Type`.
-        /// `operand` is payload index to `UnNode`.
+        /// `operand` is payload index to `Reify`.
         /// `small` contains `NameStrategy`.
         reify,
         /// Implements the `@asyncCall` builtin.
@@ -2834,6 +2834,12 @@ pub const Inst = struct {
         index: u32,
     };
 
+    pub const Reify = struct {
+        node: i32,
+        operand: Ref,
+        src_line: u32,
+    };
+
     pub const SwitchBlockErrUnion = struct {
         operand: Ref,
         bits: Bits,
@@ -2992,6 +2998,7 @@ pub const Inst = struct {
         fields_hash_1: u32,
         fields_hash_2: u32,
         fields_hash_3: u32,
+        src_line: u32,
         /// This node provides a new absolute baseline node for all instructions within this struct.
         src_node: Ast.Node.Index,
 
@@ -3121,6 +3128,7 @@ pub const Inst = struct {
         fields_hash_1: u32,
         fields_hash_2: u32,
         fields_hash_3: u32,
+        src_line: u32,
         /// This node provides a new absolute baseline node for all instructions within this struct.
         src_node: Ast.Node.Index,
 
@@ -3166,6 +3174,7 @@ pub const Inst = struct {
         fields_hash_1: u32,
         fields_hash_2: u32,
         fields_hash_3: u32,
+        src_line: u32,
         /// This node provides a new absolute baseline node for all instructions within this struct.
         src_node: Ast.Node.Index,
 
@@ -3195,6 +3204,7 @@ pub const Inst = struct {
     /// 2. capture: Capture, // for every captures_len
     /// 3. decl: Index, // for every decls_len; points to a `declaration` instruction
     pub const OpaqueDecl = struct {
+        src_line: u32,
         /// This node provides a new absolute baseline node for all instructions within this struct.
         src_node: Ast.Node.Index,
 
src/crash_report.zig
@@ -81,7 +81,7 @@ fn dumpStatusReport() !void {
     const file, const src_base_node = Module.LazySrcLoc.resolveBaseNode(block.src_base_inst, mod);
 
     try stderr.writeAll("Analyzing ");
-    try writeFullyQualifiedDeclWithFile(mod, block.src_decl, stderr);
+    try writeFilePath(file, stderr);
     try stderr.writeAll("\n");
 
     print_zir.renderInstructionContext(
@@ -105,7 +105,7 @@ fn dumpStatusReport() !void {
         fba.reset();
         try stderr.writeAll("  in ");
         const cur_block_file, const cur_block_src_base_node = Module.LazySrcLoc.resolveBaseNode(curr.block.src_base_inst, mod);
-        try writeFullyQualifiedDeclWithFile(mod, curr.block.src_decl, stderr);
+        try writeFilePath(cur_block_file, stderr);
         try stderr.writeAll("\n    > ");
         print_zir.renderSingleInstruction(
             allocator,
@@ -140,13 +140,6 @@ fn writeFilePath(file: *Module.File, writer: anytype) !void {
     try writer.writeAll(file.sub_file_path);
 }
 
-fn writeFullyQualifiedDeclWithFile(mod: *Module, decl_index: InternPool.DeclIndex, writer: anytype) !void {
-    const decl = mod.declPtr(decl_index);
-    try writeFilePath(decl.getFileScope(mod), writer);
-    try writer.writeAll(": ");
-    try decl.renderFullyQualifiedDebugName(mod, writer);
-}
-
 pub fn compilerPanic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, maybe_ret_addr: ?usize) noreturn {
     PanicSwitch.preDispatch();
     @setCold(true);
src/main.zig
@@ -5965,6 +5965,7 @@ fn cmdAstCheck(
         .zir = undefined,
         .mod = undefined,
         .root_decl = .none,
+        .path_digest = undefined,
     };
     if (zig_source_file) |file_name| {
         var f = fs.cwd().openFile(file_name, .{}) catch |err| {
@@ -6283,6 +6284,7 @@ fn cmdDumpZir(
         .zir = try Module.loadZirCache(gpa, f),
         .mod = undefined,
         .root_decl = .none,
+        .path_digest = undefined,
     };
     defer file.zir.deinit(gpa);
 
@@ -6353,6 +6355,7 @@ fn cmdChangelist(
         .zir = undefined,
         .mod = undefined,
         .root_decl = .none,
+        .path_digest = undefined,
     };
 
     file.mod = try Package.Module.createLimited(arena, .{
src/Module.zig
@@ -88,6 +88,9 @@ export_owners: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Exp
 /// an update is requested, as well as to cache `@import` results.
 /// Keys are fully resolved file paths. This table owns the keys and values.
 import_table: std.StringArrayHashMapUnmanaged(*File) = .{},
+/// This acts as a map from `path_digest` to the corresponding `File`.
+/// The value is omitted, as keys are ordered identically to `import_table`.
+path_digest_map: std.AutoArrayHashMapUnmanaged(Cache.BinDigest, void) = .{},
 /// The set of all the files which have been loaded with `@embedFile` in the Module.
 /// We keep track of this in order to iterate over it and check which files have been
 /// modified on the file system when an update is requested, as well as to cache
@@ -735,8 +738,7 @@ pub const File = struct {
     /// List of references to this file, used for multi-package errors.
     references: std.ArrayListUnmanaged(Reference) = .{},
     /// The hash of the path to this file, used to store `InternPool.TrackedInst`.
-    /// undefined until `zir_loaded == true`.
-    path_digest: Cache.BinDigest = undefined,
+    path_digest: Cache.BinDigest,
 
     /// The most recent successful ZIR for this file, with no errors.
     /// This is only populated when a previously successful ZIR
@@ -2357,10 +2359,10 @@ pub const LazySrcLoc = struct {
             const info = base_node_inst.resolveFull(&zcu.intern_pool);
             break :inst .{ info.path_digest, info.inst };
         };
-        // TODO: avoid iterating all files for this!
-        const file = for (zcu.import_table.values()) |file| {
-            if (std.mem.eql(u8, &file.path_digest, &want_path_digest)) break file;
-        } else unreachable;
+        const file = file: {
+            const index = zcu.path_digest_map.getIndex(want_path_digest).?;
+            break :file zcu.import_table.values()[index];
+        };
         assert(file.zir_loaded);
 
         const zir = file.zir;
@@ -2432,6 +2434,7 @@ pub fn deinit(zcu: *Zcu) void {
         value.destroy(zcu);
     }
     zcu.import_table.deinit(gpa);
+    zcu.path_digest_map.deinit(gpa);
 
     for (zcu.embed_table.keys(), zcu.embed_table.values()) |path, embed_file| {
         gpa.free(path);
@@ -2596,26 +2599,12 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
     const stat = try source_file.stat();
 
     const want_local_cache = file.mod == mod.main_mod;
-    const bin_digest = hash: {
-        var path_hash: Cache.HashHelper = .{};
-        path_hash.addBytes(build_options.version);
-        path_hash.add(builtin.zig_backend);
-        if (!want_local_cache) {
-            path_hash.addOptionalBytes(file.mod.root.root_dir.path);
-            path_hash.addBytes(file.mod.root.sub_path);
-        }
-        path_hash.addBytes(file.sub_file_path);
-        var bin: Cache.BinDigest = undefined;
-        path_hash.hasher.final(&bin);
-        break :hash bin;
-    };
-    file.path_digest = bin_digest;
     const hex_digest = hex: {
         var hex: Cache.HexDigest = undefined;
         _ = std.fmt.bufPrint(
             &hex,
             "{s}",
-            .{std.fmt.fmtSliceHexLower(&bin_digest)},
+            .{std.fmt.fmtSliceHexLower(&file.path_digest)},
         ) catch unreachable;
         break :hex hex;
     };
@@ -4122,12 +4111,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
     var block_scope: Sema.Block = .{
         .parent = null,
         .sema = &sema,
-        .src_decl = decl_index,
         .namespace = decl.src_namespace,
         .instructions = .{},
         .inlining = null,
         .is_comptime = true,
         .src_base_inst = decl.zir_decl_index.unwrap().?,
+        .type_name_ctx = decl.name,
     };
     defer block_scope.instructions.deinit(gpa);
 
@@ -4355,6 +4344,7 @@ pub fn importPkg(zcu: *Zcu, mod: *Package.Module) !ImportFileResult {
         keep_resolved_path = true; // It's now owned by import_table.
         gop.value_ptr.* = builtin_file;
         try builtin_file.addReference(zcu.*, .{ .root = mod });
+        try zcu.path_digest_map.put(gpa, builtin_file.path_digest, {});
         return .{
             .file = builtin_file,
             .is_new = false,
@@ -4382,8 +4372,23 @@ pub fn importPkg(zcu: *Zcu, mod: *Package.Module) !ImportFileResult {
         .status = .never_loaded,
         .mod = mod,
         .root_decl = .none,
+        .path_digest = digest: {
+            const want_local_cache = mod == zcu.main_mod;
+            var path_hash: Cache.HashHelper = .{};
+            path_hash.addBytes(build_options.version);
+            path_hash.add(builtin.zig_backend);
+            if (!want_local_cache) {
+                path_hash.addOptionalBytes(mod.root.root_dir.path);
+                path_hash.addBytes(mod.root.sub_path);
+            }
+            path_hash.addBytes(sub_file_path);
+            var bin: Cache.BinDigest = undefined;
+            path_hash.hasher.final(&bin);
+            break :digest bin;
+        },
     };
     try new_file.addReference(zcu.*, .{ .root = mod });
+    try zcu.path_digest_map.put(gpa, new_file.path_digest, {});
     return ImportFileResult{
         .file = new_file,
         .is_new = true,
@@ -4392,23 +4397,23 @@ pub fn importPkg(zcu: *Zcu, mod: *Package.Module) !ImportFileResult {
 }
 
 pub fn importFile(
-    mod: *Module,
+    zcu: *Zcu,
     cur_file: *File,
     import_string: []const u8,
 ) !ImportFileResult {
     if (std.mem.eql(u8, import_string, "std")) {
-        return mod.importPkg(mod.std_mod);
+        return zcu.importPkg(zcu.std_mod);
     }
     if (std.mem.eql(u8, import_string, "root")) {
-        return mod.importPkg(mod.root_mod);
+        return zcu.importPkg(zcu.root_mod);
     }
     if (cur_file.mod.deps.get(import_string)) |pkg| {
-        return mod.importPkg(pkg);
+        return zcu.importPkg(pkg);
     }
     if (!mem.endsWith(u8, import_string, ".zig")) {
         return error.ModuleNotFound;
     }
-    const gpa = mod.gpa;
+    const gpa = zcu.gpa;
 
     // The resolved path is used as the key in the import table, to detect if
     // an import refers to the same as another, despite different relative paths
@@ -4424,8 +4429,8 @@ pub fn importFile(
     var keep_resolved_path = false;
     defer if (!keep_resolved_path) gpa.free(resolved_path);
 
-    const gop = try mod.import_table.getOrPut(gpa, resolved_path);
-    errdefer _ = mod.import_table.pop();
+    const gop = try zcu.import_table.getOrPut(gpa, resolved_path);
+    errdefer _ = zcu.import_table.pop();
     if (gop.found_existing) return ImportFileResult{
         .file = gop.value_ptr.*,
         .is_new = false,
@@ -4470,7 +4475,22 @@ pub fn importFile(
         .status = .never_loaded,
         .mod = cur_file.mod,
         .root_decl = .none,
+        .path_digest = digest: {
+            const want_local_cache = cur_file.mod == zcu.main_mod;
+            var path_hash: Cache.HashHelper = .{};
+            path_hash.addBytes(build_options.version);
+            path_hash.add(builtin.zig_backend);
+            if (!want_local_cache) {
+                path_hash.addOptionalBytes(cur_file.mod.root.root_dir.path);
+                path_hash.addBytes(cur_file.mod.root.sub_path);
+            }
+            path_hash.addBytes(sub_file_path);
+            var bin: Cache.BinDigest = undefined;
+            path_hash.hasher.final(&bin);
+            break :digest bin;
+        },
     };
+    try zcu.path_digest_map.put(gpa, new_file.path_digest, {});
     return ImportFileResult{
         .file = new_file,
         .is_new = true,
@@ -5039,7 +5059,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
     var inner_block: Sema.Block = .{
         .parent = null,
         .sema = &sema,
-        .src_decl = decl_index,
         .namespace = decl.src_namespace,
         .instructions = .{},
         .inlining = null,
@@ -5052,6 +5071,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
             const orig_decl = mod.declPtr(owner_info.owner_decl);
             break :inst orig_decl.zir_decl_index.unwrap().?;
         },
+        .type_name_ctx = decl.name,
     };
     defer inner_block.instructions.deinit(gpa);
 
src/print_zir.zig
@@ -569,7 +569,6 @@ const Writer = struct {
             .wasm_memory_size,
             .int_from_error,
             .error_from_int,
-            .reify,
             .c_va_copy,
             .c_va_end,
             .work_item_id,
@@ -582,6 +581,14 @@ const Writer = struct {
                 try self.writeSrcNode(stream, inst_data.node);
             },
 
+            .reify => {
+                const inst_data = self.code.extraData(Zir.Inst.Reify, extended.operand).data;
+                try stream.print("{d}, ", .{inst_data.src_line});
+                try self.writeInstRef(stream, inst_data.operand);
+                try stream.writeAll(")) ");
+                try self.writeSrcNode(stream, inst_data.node);
+            },
+
             .builtin_extern,
             .c_define,
             .error_cast,
src/Sema.zig
@@ -16,9 +16,7 @@ air_instructions: std.MultiArrayList(Air.Inst) = .{},
 air_extra: std.ArrayListUnmanaged(u32) = .{},
 /// Maps ZIR to AIR.
 inst_map: InstMap = .{},
-/// When analyzing an inline function call, owner_decl is the Decl of the caller
-/// and `src_decl` of `Block` is the `Decl` of the callee.
-/// This `Decl` owns the arena memory of this `Sema`.
+/// When analyzing an inline function call, owner_decl is the Decl of the caller.
 owner_decl: *Decl,
 owner_decl_index: InternPool.DeclIndex,
 /// For an inline or comptime function call, this will be the root parent function
@@ -342,7 +340,6 @@ pub const Block = struct {
     /// Shared among all child blocks.
     sema: *Sema,
     /// The namespace to use for lookups from this source block
-    /// When analyzing fields, this is different from src_decl.src_namespace.
     namespace: InternPool.NamespaceIndex,
     /// The AIR instructions generated for this block.
     instructions: std.ArrayListUnmanaged(Air.Inst.Index),
@@ -360,10 +357,6 @@ pub const Block = struct {
     /// If runtime_index is not 0 then one of these is guaranteed to be non null.
     runtime_cond: ?LazySrcLoc = null,
     runtime_loop: ?LazySrcLoc = null,
-    /// This Decl is the Decl according to the Zig source code corresponding to this Block.
-    /// This can vary during inline or comptime function calls. See `Sema.owner_decl`
-    /// for the one that will be the same for all Block instances.
-    src_decl: InternPool.DeclIndex,
     /// Non zero if a non-inline loop or a runtime conditional have been encountered.
     /// Stores to comptime variables are only allowed when var.runtime_index <= runtime_index.
     runtime_index: Value.RuntimeIndex = .zero,
@@ -396,6 +389,12 @@ pub const Block = struct {
     /// treated as relative to the AST node of this ZIR instruction.
     src_base_inst: InternPool.TrackedInst.Index,
 
+    /// The name of the current "context" for naming namespace types.
+    /// The interpretation of this depends on the name strategy in ZIR, but the name
+    /// is always incorporated into the type name somehow.
+    /// See `Sema.createAnonymousDeclTypeNamed`.
+    type_name_ctx: InternPool.NullTerminatedString,
+
     /// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block.
     /// Specifically, the given `Offset` is treated as relative to `block.src_base_inst`.
     pub fn src(block: Block, offset: LazySrcLoc.Offset) LazySrcLoc {
@@ -516,7 +515,6 @@ pub const Block = struct {
         return .{
             .parent = parent,
             .sema = parent.sema,
-            .src_decl = parent.src_decl,
             .namespace = parent.namespace,
             .instructions = .{},
             .label = null,
@@ -533,6 +531,7 @@ pub const Block = struct {
             .error_return_trace_index = parent.error_return_trace_index,
             .need_debug_scope = parent.need_debug_scope,
             .src_base_inst = parent.src_base_inst,
+            .type_name_ctx = parent.type_name_ctx,
         };
     }
 
@@ -993,9 +992,11 @@ fn analyzeBodyInner(
     while (true) {
         crash_info.setBodyIndex(i);
         const inst = body[i];
-        std.log.scoped(.sema_zir).debug("sema ZIR {s} %{d}", .{
-            mod.namespacePtr(mod.declPtr(block.src_decl).src_namespace).file_scope.sub_file_path, inst,
-        });
+        std.log.scoped(.sema_zir).debug("sema ZIR {s} %{d}", .{ sub_file_path: {
+            const path_digest = block.src_base_inst.resolveFull(&mod.intern_pool).path_digest;
+            const index = mod.path_digest_map.getIndex(path_digest).?;
+            break :sub_file_path mod.import_table.values()[index].sub_file_path;
+        }, inst });
         const air_inst: Air.Inst.Ref = switch (tags[@intFromEnum(inst)]) {
             // zig fmt: off
             .alloc                        => try sema.zirAlloc(block, inst),
@@ -2821,6 +2822,7 @@ fn zirStructDecl(
         small.name_strategy,
         "struct",
         inst,
+        extra.data.src_line,
     );
     mod.declPtr(new_decl_index).owns_tv = true;
     errdefer mod.abortAnonDecl(new_decl_index);
@@ -2857,20 +2859,19 @@ fn createAnonymousDeclTypeNamed(
     name_strategy: Zir.Inst.NameStrategy,
     anon_prefix: []const u8,
     inst: ?Zir.Inst.Index,
+    src_line: u32,
 ) !InternPool.DeclIndex {
     const zcu = sema.mod;
     const ip = &zcu.intern_pool;
     const gpa = sema.gpa;
     const namespace = block.namespace;
-    const src_decl = zcu.declPtr(block.src_decl);
     const new_decl_index = try zcu.allocateNewDecl(namespace);
     errdefer zcu.destroyDecl(new_decl_index);
 
     switch (name_strategy) {
         .anon => {}, // handled after switch
         .parent => {
-            const name = zcu.declPtr(block.src_decl).name;
-            try zcu.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);
+            try zcu.initNewAnonDecl(new_decl_index, src_line, val, block.type_name_ctx);
             return new_decl_index;
         },
         .func => func_strat: {
@@ -2881,7 +2882,7 @@ fn createAnonymousDeclTypeNamed(
             defer buf.deinit();
 
             const writer = buf.writer();
-            try writer.print("{}(", .{zcu.declPtr(block.src_decl).name.fmt(ip)});
+            try writer.print("{}(", .{block.type_name_ctx.fmt(ip)});
 
             var arg_i: usize = 0;
             for (fn_info.param_body) |zir_inst| switch (zir_tags[@intFromEnum(zir_inst)]) {
@@ -2915,7 +2916,7 @@ fn createAnonymousDeclTypeNamed(
 
             try writer.writeByte(')');
             const name = try ip.getOrPutString(gpa, buf.items, .no_embedded_nulls);
-            try zcu.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);
+            try zcu.initNewAnonDecl(new_decl_index, src_line, val, name);
             return new_decl_index;
         },
         .dbg_var => {
@@ -2927,9 +2928,9 @@ fn createAnonymousDeclTypeNamed(
                     if (zir_data[i].str_op.operand != ref) continue;
 
                     const name = try ip.getOrPutStringFmt(gpa, "{}.{s}", .{
-                        src_decl.name.fmt(ip), zir_data[i].str_op.getStr(sema.code),
+                        block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code),
                     }, .no_embedded_nulls);
-                    try zcu.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);
+                    try zcu.initNewAnonDecl(new_decl_index, src_line, val, name);
                     return new_decl_index;
                 },
                 else => {},
@@ -2948,9 +2949,9 @@ fn createAnonymousDeclTypeNamed(
     // renamed.
 
     const name = ip.getOrPutStringFmt(gpa, "{}__{s}_{d}", .{
-        src_decl.name.fmt(ip), anon_prefix, @intFromEnum(new_decl_index),
+        block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(new_decl_index),
     }, .no_embedded_nulls) catch unreachable;
-    try zcu.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);
+    try zcu.initNewAnonDecl(new_decl_index, src_line, val, name);
     return new_decl_index;
 }
 
@@ -3056,6 +3057,7 @@ fn zirEnumDecl(
         small.name_strategy,
         "enum",
         inst,
+        extra.data.src_line,
     );
     const new_decl = mod.declPtr(new_decl_index);
     new_decl.owns_tv = true;
@@ -3112,12 +3114,12 @@ fn zirEnumDecl(
         var enum_block: Block = .{
             .parent = null,
             .sema = sema,
-            .src_decl = new_decl_index,
             .namespace = new_namespace_index.unwrap() orelse block.namespace,
             .instructions = .{},
             .inlining = null,
             .is_comptime = true,
             .src_base_inst = tracked_inst,
+            .type_name_ctx = new_decl.name,
         };
         defer enum_block.instructions.deinit(sema.gpa);
 
@@ -3323,6 +3325,7 @@ fn zirUnionDecl(
         small.name_strategy,
         "union",
         inst,
+        extra.data.src_line,
     );
     mod.declPtr(new_decl_index).owns_tv = true;
     errdefer mod.abortAnonDecl(new_decl_index);
@@ -3411,6 +3414,7 @@ fn zirOpaqueDecl(
         small.name_strategy,
         "opaque",
         inst,
+        extra.data.src_line,
     );
     mod.declPtr(new_decl_index).owns_tv = true;
     errdefer mod.abortAnonDecl(new_decl_index);
@@ -5942,7 +5946,6 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
     var child_block: Block = .{
         .parent = parent_block,
         .sema = sema,
-        .src_decl = parent_block.src_decl,
         .namespace = parent_block.namespace,
         .instructions = .{},
         .inlining = parent_block.inlining,
@@ -5953,6 +5956,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
         .runtime_loop = parent_block.runtime_loop,
         .runtime_index = parent_block.runtime_index,
         .src_base_inst = parent_block.src_base_inst,
+        .type_name_ctx = parent_block.type_name_ctx,
     };
     defer child_block.instructions.deinit(gpa);
 
@@ -6063,7 +6067,6 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index, force_compt
     var child_block: Block = .{
         .parent = parent_block,
         .sema = sema,
-        .src_decl = parent_block.src_decl,
         .namespace = parent_block.namespace,
         .instructions = .{},
         .label = &label,
@@ -6079,6 +6082,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index, force_compt
         .runtime_index = parent_block.runtime_index,
         .error_return_trace_index = parent_block.error_return_trace_index,
         .src_base_inst = parent_block.src_base_inst,
+        .type_name_ctx = parent_block.type_name_ctx,
     };
 
     defer child_block.instructions.deinit(gpa);
@@ -6726,7 +6730,7 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
         .no_embedded_nulls,
     );
     const decl_index = try sema.lookupIdentifier(block, src, decl_name);
-    try sema.addReferencedBy(block, src, decl_index);
+    try sema.addReferencedBy(src, decl_index);
     return sema.analyzeDeclRef(decl_index);
 }
 
@@ -7695,7 +7699,6 @@ fn analyzeCall(
         var child_block: Block = .{
             .parent = null,
             .sema = sema,
-            .src_decl = module_fn.owner_decl,
             .namespace = fn_owner_decl.src_namespace,
             .instructions = .{},
             .label = null,
@@ -7708,6 +7711,7 @@ fn analyzeCall(
             .runtime_loop = block.runtime_loop,
             .runtime_index = block.runtime_index,
             .src_base_inst = fn_owner_decl.zir_decl_index.unwrap().?,
+            .type_name_ctx = fn_owner_decl.name,
         };
 
         const merges = &child_block.inlining.?.merges;
@@ -8217,12 +8221,12 @@ fn instantiateGenericCall(
     var child_block: Block = .{
         .parent = null,
         .sema = &child_sema,
-        .src_decl = generic_owner_func.owner_decl,
         .namespace = namespace_index,
         .instructions = .{},
         .inlining = null,
         .is_comptime = true,
         .src_base_inst = fn_owner_decl.zir_decl_index.unwrap().?,
+        .type_name_ctx = fn_owner_decl.name,
     };
     defer child_block.instructions.deinit(gpa);
 
@@ -8366,7 +8370,7 @@ fn instantiateGenericCall(
     const callee = mod.funcInfo(callee_index);
     callee.branchQuota(ip).* = @max(callee.branchQuota(ip).*, sema.branch_quota);
 
-    try sema.addReferencedBy(block, call_src, callee.owner_decl);
+    try sema.addReferencedBy(call_src, callee.owner_decl);
 
     // Make a runtime call to the new function, making sure to omit the comptime args.
     const func_ty = Type.fromInterned(callee.ty);
@@ -9346,7 +9350,7 @@ fn zirFunc(
     // If this instruction has a body it means it's the type of the `owner_decl`
     // otherwise it's a function type without a `callconv` attribute and should
     // never be `.C`.
-    const cc: std.builtin.CallingConvention = if (has_body and mod.declPtr(block.src_decl).is_exported)
+    const cc: std.builtin.CallingConvention = if (has_body and mod.declPtr(sema.owner_decl_index).is_exported)
         .C
     else
         .Unspecified;
@@ -11595,7 +11599,6 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
     var child_block: Block = .{
         .parent = block,
         .sema = sema,
-        .src_decl = block.src_decl,
         .namespace = block.namespace,
         .instructions = .{},
         .label = &label,
@@ -11610,6 +11613,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
         .error_return_trace_index = block.error_return_trace_index,
         .want_safety = block.want_safety,
         .src_base_inst = block.src_base_inst,
+        .type_name_ctx = block.type_name_ctx,
     };
     const merges = &child_block.label.?.merges;
     defer child_block.instructions.deinit(gpa);
@@ -12327,7 +12331,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
     var child_block: Block = .{
         .parent = block,
         .sema = sema,
-        .src_decl = block.src_decl,
         .namespace = block.namespace,
         .instructions = .{},
         .label = &label,
@@ -12342,6 +12345,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
         .want_safety = block.want_safety,
         .error_return_trace_index = block.error_return_trace_index,
         .src_base_inst = block.src_base_inst,
+        .type_name_ctx = block.type_name_ctx,
     };
     const merges = &child_block.label.?.merges;
     defer child_block.instructions.deinit(gpa);
@@ -18843,7 +18847,6 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
     var child_block: Block = .{
         .parent = block,
         .sema = sema,
-        .src_decl = block.src_decl,
         .namespace = block.namespace,
         .instructions = .{},
         .inlining = block.inlining,
@@ -18852,6 +18855,7 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
         .want_safety = false,
         .error_return_trace_index = block.error_return_trace_index,
         .src_base_inst = block.src_base_inst,
+        .type_name_ctx = block.type_name_ctx,
     };
     defer child_block.instructions.deinit(sema.gpa);
 
@@ -18922,7 +18926,6 @@ fn zirTypeofPeer(
     var child_block: Block = .{
         .parent = block,
         .sema = sema,
-        .src_decl = block.src_decl,
         .namespace = block.namespace,
         .instructions = .{},
         .inlining = block.inlining,
@@ -18932,6 +18935,7 @@ fn zirTypeofPeer(
         .runtime_loop = block.runtime_loop,
         .runtime_index = block.runtime_index,
         .src_base_inst = block.src_base_inst,
+        .type_name_ctx = block.type_name_ctx,
     };
     defer child_block.instructions.deinit(sema.gpa);
     // Ignore the result, we only care about the instructions in `args`.
@@ -19398,13 +19402,13 @@ fn ensurePostHoc(sema: *Sema, block: *Block, dest_block: Zir.Inst.Index) !*Label
         .block = .{
             .parent = block,
             .sema = sema,
-            .src_decl = block.src_decl,
             .namespace = block.namespace,
             .instructions = .{},
             .label = &labeled_block.label,
             .inlining = block.inlining,
             .is_comptime = block.is_comptime,
             .src_base_inst = block.src_base_inst,
+            .type_name_ctx = block.type_name_ctx,
         },
     };
     sema.post_hoc_blocks.putAssumeCapacityNoClobber(new_block_inst, labeled_block);
@@ -21201,7 +21205,7 @@ fn zirReify(
     const gpa = sema.gpa;
     const ip = &mod.intern_pool;
     const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
-    const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
+    const extra = sema.code.extraData(Zir.Inst.Reify, extended.operand).data;
     const src = block.nodeOffset(extra.node);
     const type_info_ty = try sema.getBuiltinType("Type");
     const uncasted_operand = try sema.resolveInst(extra.operand);
@@ -21521,7 +21525,7 @@ fn zirReify(
                 .needed_comptime_reason = "struct fields must be comptime-known",
             });
 
-            return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_arr, name_strategy, is_tuple_val.toBool());
+            return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_arr, name_strategy, is_tuple_val.toBool(), extra.src_line);
         },
         .Enum => {
             const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
@@ -21550,7 +21554,7 @@ fn zirReify(
                 .needed_comptime_reason = "enum fields must be comptime-known",
             });
 
-            return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_arr, name_strategy);
+            return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_arr, name_strategy, extra.src_line);
         },
         .Opaque => {
             const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
@@ -21581,6 +21585,7 @@ fn zirReify(
                 name_strategy,
                 "opaque",
                 inst,
+                extra.src_line,
             );
             mod.declPtr(new_decl_index).owns_tv = true;
             errdefer mod.abortAnonDecl(new_decl_index);
@@ -21617,7 +21622,7 @@ fn zirReify(
                 .needed_comptime_reason = "union fields must be comptime-known",
             });
 
-            return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_arr, name_strategy);
+            return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_arr, name_strategy, extra.src_line);
         },
         .Fn => {
             const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
@@ -21719,6 +21724,7 @@ fn reifyEnum(
     is_exhaustive: bool,
     fields_val: Value,
     name_strategy: Zir.Inst.NameStrategy,
+    src_line: u32,
 ) CompileError!Air.Inst.Ref {
     const mod = sema.mod;
     const gpa = sema.gpa;
@@ -21780,6 +21786,7 @@ fn reifyEnum(
         name_strategy,
         "enum",
         inst,
+        src_line,
     );
     mod.declPtr(new_decl_index).owns_tv = true;
     errdefer mod.abortAnonDecl(new_decl_index);
@@ -21843,6 +21850,7 @@ fn reifyUnion(
     opt_tag_type_val: Value,
     fields_val: Value,
     name_strategy: Zir.Inst.NameStrategy,
+    src_line: u32,
 ) CompileError!Air.Inst.Ref {
     const mod = sema.mod;
     const gpa = sema.gpa;
@@ -21926,6 +21934,7 @@ fn reifyUnion(
         name_strategy,
         "union",
         inst,
+        src_line,
     );
     mod.declPtr(new_decl_index).owns_tv = true;
     errdefer mod.abortAnonDecl(new_decl_index);
@@ -22021,7 +22030,7 @@ fn reifyUnion(
             }
         }
 
-        const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), mod.declPtr(new_decl_index));
+        const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), mod.declPtr(new_decl_index), src_line);
         break :tag_ty .{ enum_tag_ty, false };
     };
     errdefer if (!has_explicit_tag) ip.remove(enum_tag_ty); // remove generated tag type on error
@@ -22082,6 +22091,7 @@ fn reifyStruct(
     fields_val: Value,
     name_strategy: Zir.Inst.NameStrategy,
     is_tuple: bool,
+    src_line: u32,
 ) CompileError!Air.Inst.Ref {
     const mod = sema.mod;
     const gpa = sema.gpa;
@@ -22182,6 +22192,7 @@ fn reifyStruct(
         name_strategy,
         "struct",
         inst,
+        src_line,
     );
     mod.declPtr(new_decl_index).owns_tv = true;
     errdefer mod.abortAnonDecl(new_decl_index);
@@ -26903,12 +26914,12 @@ fn addSafetyCheck(
     var fail_block: Block = .{
         .parent = parent_block,
         .sema = sema,
-        .src_decl = parent_block.src_decl,
         .namespace = parent_block.namespace,
         .instructions = .{},
         .inlining = parent_block.inlining,
         .is_comptime = false,
         .src_base_inst = parent_block.src_base_inst,
+        .type_name_ctx = parent_block.type_name_ctx,
     };
 
     defer fail_block.instructions.deinit(gpa);
@@ -27012,12 +27023,12 @@ fn panicUnwrapError(
     var fail_block: Block = .{
         .parent = parent_block,
         .sema = sema,
-        .src_decl = parent_block.src_decl,
         .namespace = parent_block.namespace,
         .instructions = .{},
         .inlining = parent_block.inlining,
         .is_comptime = false,
         .src_base_inst = parent_block.src_base_inst,
+        .type_name_ctx = parent_block.type_name_ctx,
     };
 
     defer fail_block.instructions.deinit(gpa);
@@ -27129,12 +27140,12 @@ fn safetyCheckFormatted(
     var fail_block: Block = .{
         .parent = parent_block,
         .sema = sema,
-        .src_decl = parent_block.src_decl,
         .namespace = parent_block.namespace,
         .instructions = .{},
         .inlining = parent_block.inlining,
         .is_comptime = false,
         .src_base_inst = parent_block.src_base_inst,
+        .type_name_ctx = parent_block.type_name_ctx,
     };
 
     defer fail_block.instructions.deinit(gpa);
@@ -27682,7 +27693,7 @@ fn fieldCallBind(
         const decl_idx = (try sema.namespaceLookup(block, src, namespace, field_name)) orelse
             break :found_decl null;
 
-        try sema.addReferencedBy(block, src, decl_idx);
+        try sema.addReferencedBy(src, decl_idx);
         const decl_val = try sema.analyzeDeclVal(block, src, decl_idx);
         const decl_type = sema.typeOf(decl_val);
         if (mod.typeToFunc(decl_type)) |func_type| f: {
@@ -27838,7 +27849,7 @@ fn namespaceLookupRef(
     decl_name: InternPool.NullTerminatedString,
 ) CompileError!?Air.Inst.Ref {
     const decl = (try sema.namespaceLookup(block, src, opt_namespace, decl_name)) orelse return null;
-    try sema.addReferencedBy(block, src, decl);
+    try sema.addReferencedBy(src, decl);
     return try sema.analyzeDeclRef(decl);
 }
 
@@ -31757,7 +31768,7 @@ fn analyzeDeclVal(
     src: LazySrcLoc,
     decl_index: InternPool.DeclIndex,
 ) CompileError!Air.Inst.Ref {
-    try sema.addReferencedBy(block, src, decl_index);
+    try sema.addReferencedBy(src, decl_index);
     if (sema.decl_val_table.get(decl_index)) |result| {
         return result;
     }
@@ -31773,13 +31784,14 @@ fn analyzeDeclVal(
 
 fn addReferencedBy(
     sema: *Sema,
-    block: *Block,
     src: LazySrcLoc,
     decl_index: InternPool.DeclIndex,
 ) !void {
     if (sema.mod.comp.reference_trace == 0) return;
     try sema.mod.reference_table.put(sema.gpa, decl_index, .{
-        .referencer = block.src_decl,
+        // TODO: this can make the reference trace suboptimal. This will be fixed
+        // once the reference table is reworked for incremental compilation.
+        .referencer = sema.owner_decl_index,
         .src = src,
     });
 }
@@ -35181,12 +35193,12 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co
     var block: Block = .{
         .parent = null,
         .sema = &sema,
-        .src_decl = decl_index,
         .namespace = struct_type.namespace.unwrap() orelse decl.src_namespace,
         .instructions = .{},
         .inlining = null,
         .is_comptime = true,
         .src_base_inst = struct_type.zir_index.unwrap().?,
+        .type_name_ctx = decl.name,
     };
     defer assert(block.instructions.items.len == 0);
 
@@ -36036,12 +36048,12 @@ fn semaStructFields(
     var block_scope: Block = .{
         .parent = null,
         .sema = &sema,
-        .src_decl = decl_index,
         .namespace = namespace_index,
         .instructions = .{},
         .inlining = null,
         .is_comptime = true,
         .src_base_inst = struct_type.zir_index.unwrap().?,
+        .type_name_ctx = decl.name,
     };
     defer assert(block_scope.instructions.items.len == 0);
 
@@ -36247,12 +36259,12 @@ fn semaStructFieldInits(
     var block_scope: Block = .{
         .parent = null,
         .sema = &sema,
-        .src_decl = decl_index,
         .namespace = namespace_index,
         .instructions = .{},
         .inlining = null,
         .is_comptime = true,
         .src_base_inst = struct_type.zir_index.unwrap().?,
+        .type_name_ctx = decl.name,
     };
     defer assert(block_scope.instructions.items.len == 0);
 
@@ -36359,7 +36371,8 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
     const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
     assert(extended.opcode == .union_decl);
     const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
-    var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len;
+    const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
+    var extra_index: usize = extra.end;
 
     const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: {
         const ty_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
@@ -36421,12 +36434,12 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
     var block_scope: Block = .{
         .parent = null,
         .sema = &sema,
-        .src_decl = decl_index,
         .namespace = union_type.namespace.unwrap().?,
         .instructions = .{},
         .inlining = null,
         .is_comptime = true,
         .src_base_inst = union_type.zir_index,
+        .type_name_ctx = decl.name,
     };
     defer assert(block_scope.instructions.items.len == 0);
 
@@ -36711,10 +36724,10 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
             return sema.failWithOwnedErrorMsg(&block_scope, msg);
         }
     } else if (enum_field_vals.count() > 0) {
-        const enum_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), mod.declPtr(union_type.decl));
+        const enum_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), mod.declPtr(union_type.decl), extra.data.src_line);
         union_type.tagTypePtr(ip).* = enum_ty;
     } else {
-        const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, mod.declPtr(union_type.decl));
+        const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, mod.declPtr(union_type.decl), extra.data.src_line);
         union_type.tagTypePtr(ip).* = enum_ty;
     }
 }
@@ -36732,12 +36745,12 @@ fn generateUnionTagTypeNumbered(
     enum_field_names: []const InternPool.NullTerminatedString,
     enum_field_vals: []const InternPool.Index,
     union_owner_decl: *Module.Decl,
+    src_line: u32,
 ) !InternPool.Index {
     const mod = sema.mod;
     const gpa = sema.gpa;
     const ip = &mod.intern_pool;
 
-    const src_decl = mod.declPtr(block.src_decl);
     const new_decl_index = try mod.allocateNewDecl(block.namespace);
     errdefer mod.destroyDecl(new_decl_index);
     const fqn = try union_owner_decl.fullyQualifiedName(mod);
@@ -36749,7 +36762,7 @@ fn generateUnionTagTypeNumbered(
     );
     try mod.initNewAnonDecl(
         new_decl_index,
-        src_decl.src_line,
+        src_line,
         Value.@"unreachable",
         name,
     );
@@ -36782,6 +36795,7 @@ fn generateUnionTagTypeSimple(
     block: *Block,
     enum_field_names: []const InternPool.NullTerminatedString,
     union_owner_decl: *Module.Decl,
+    src_line: u32,
 ) !InternPool.Index {
     const mod = sema.mod;
     const ip = &mod.intern_pool;
@@ -36789,7 +36803,6 @@ fn generateUnionTagTypeSimple(
 
     const new_decl_index = new_decl_index: {
         const fqn = try union_owner_decl.fullyQualifiedName(mod);
-        const src_decl = mod.declPtr(block.src_decl);
         const new_decl_index = try mod.allocateNewDecl(block.namespace);
         errdefer mod.destroyDecl(new_decl_index);
         const name = try ip.getOrPutStringFmt(
@@ -36800,7 +36813,7 @@ fn generateUnionTagTypeSimple(
         );
         try mod.initNewAnonDecl(
             new_decl_index,
-            src_decl.src_line,
+            src_line,
             Value.@"unreachable",
             name,
         );
@@ -36835,7 +36848,6 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
     var block: Block = .{
         .parent = null,
         .sema = sema,
-        .src_decl = sema.owner_decl_index,
         .namespace = sema.owner_decl.src_namespace,
         .instructions = .{},
         .inlining = null,
@@ -36853,6 +36865,7 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
                 else => unreachable,
             }
         },
+        .type_name_ctx = sema.owner_decl.name,
     };
     defer block.instructions.deinit(sema.gpa);
 
@@ -36898,7 +36911,6 @@ fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
     var block: Block = .{
         .parent = null,
         .sema = sema,
-        .src_decl = sema.owner_decl_index,
         .namespace = sema.owner_decl.src_namespace,
         .instructions = .{},
         .inlining = null,
@@ -36916,6 +36928,7 @@ fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
                 else => unreachable,
             }
         },
+        .type_name_ctx = sema.owner_decl.name,
     };
     defer block.instructions.deinit(sema.gpa);