Commit 53a36eacfa

Martin Wickham <spexguy070@gmail.com>
2021-10-01 19:05:12
Remove my dumb "namespace decl" hack
1 parent d1a4bdb
src/codegen/c.zig
@@ -1696,7 +1696,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
 fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
     const air_datas = f.air.instructions.items(.data);
     const air_extra = f.air.extraData(Air.Asm, air_datas[inst].ty_pl.payload);
-    const zir = f.object.dg.decl.namespace.file_scope.zir;
+    const zir = f.object.dg.decl.getFileScope().zir;
     const extended = zir.instructions.items(.data)[air_extra.data.zir_index].extended;
     const zir_extra = zir.extraData(Zir.Inst.Asm, extended.operand);
     const asm_source = zir.nullTerminatedString(zir_extra.data.asm_source);
src/codegen/llvm.zig
@@ -1819,7 +1819,7 @@ pub const FuncGen = struct {
 
         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
         const air_asm = self.air.extraData(Air.Asm, ty_pl.payload);
-        const zir = self.dg.decl.namespace.file_scope.zir;
+        const zir = self.dg.decl.getFileScope().zir;
         const extended = zir.instructions.items(.data)[air_asm.data.zir_index].extended;
         const zir_extra = zir.extraData(Zir.Inst.Asm, extended.operand);
         const asm_source = zir.nullTerminatedString(zir_extra.data.asm_source);
src/codegen/spirv.zig
@@ -139,7 +139,7 @@ pub const SPIRVModule = struct {
     }
 
     fn resolveSourceFileName(self: *SPIRVModule, decl: *Decl) !ResultId {
-        const path = decl.namespace.file_scope.sub_file_path;
+        const path = decl.getFileScope().sub_file_path;
         const result = try self.file_names.getOrPut(path);
         if (!result.found_existing) {
             result.value_ptr.* = self.allocResultId();
src/link/Plan9.zig
@@ -163,11 +163,11 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
 
 fn putFn(self: *Plan9, decl: *Module.Decl, out: FnDeclOutput) !void {
     const gpa = self.base.allocator;
-    const fn_map_res = try self.fn_decl_table.getOrPut(gpa, decl.namespace.file_scope);
+    const fn_map_res = try self.fn_decl_table.getOrPut(gpa, decl.getFileScope());
     if (fn_map_res.found_existing) {
         try fn_map_res.value_ptr.functions.put(gpa, decl, out);
     } else {
-        const file = decl.namespace.file_scope;
+        const file = decl.getFileScope();
         const arena = &self.path_arena.allocator;
         // each file gets a symbol
         fn_map_res.value_ptr.* = .{
@@ -548,7 +548,7 @@ pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void {
     const is_fn = (decl.val.tag() == .function);
     if (is_fn) {
         var symidx_and_submap =
-            self.fn_decl_table.get(decl.namespace.file_scope).?;
+            self.fn_decl_table.get(decl.getFileScope()).?;
         var submap = symidx_and_submap.functions;
         _ = submap.swapRemove(decl);
         if (submap.count() == 0) {
src/codegen.zig
@@ -2584,7 +2584,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
 
         fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue) !void {
             const ty_str = self.air.instructions.items(.data)[inst].ty_str;
-            const zir = &self.mod_fn.owner_decl.namespace.file_scope.zir;
+            const zir = &self.mod_fn.owner_decl.getFileScope().zir;
             const name = zir.nullTerminatedString(ty_str.str);
             const name_with_null = name.ptr[0 .. name.len + 1];
             const ty = self.air.getRefType(ty_str.ty);
@@ -3834,7 +3834,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
         fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
             const air_datas = self.air.instructions.items(.data);
             const air_extra = self.air.extraData(Air.Asm, air_datas[inst].ty_pl.payload);
-            const zir = self.mod_fn.owner_decl.namespace.file_scope.zir;
+            const zir = self.mod_fn.owner_decl.getFileScope().zir;
             const extended = zir.instructions.items(.data)[air_extra.data.zir_index].extended;
             const zir_extra = zir.extraData(Zir.Inst.Asm, extended.operand);
             const asm_source = zir.nullTerminatedString(zir_extra.data.asm_source);
src/Compilation.zig
@@ -1770,7 +1770,7 @@ pub fn update(self: *Compilation) !void {
                 assert(decl.deletion_flag);
                 assert(decl.dependants.count() == 0);
                 const is_anon = if (decl.zir_decl_index == 0) blk: {
-                    break :blk decl.namespace.anon_decls.swapRemove(decl);
+                    break :blk decl.src_namespace.anon_decls.swapRemove(decl);
                 } else false;
 
                 try module.clearDecl(decl, null);
@@ -1889,13 +1889,13 @@ pub fn totalErrorCount(self: *Compilation) usize {
         // the previous parse success, including compile errors, but we cannot
         // emit them until the file succeeds parsing.
         for (module.failed_decls.keys()) |key| {
-            if (key.namespace.file_scope.okToReportErrors()) {
+            if (key.getFileScope().okToReportErrors()) {
                 total += 1;
             }
         }
         if (module.emit_h) |emit_h| {
             for (emit_h.failed_decls.keys()) |key| {
-                if (key.namespace.file_scope.okToReportErrors()) {
+                if (key.getFileScope().okToReportErrors()) {
                     total += 1;
                 }
             }
@@ -1968,7 +1968,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
             while (it.next()) |entry| {
                 // Skip errors for Decls within files that had a parse failure.
                 // We'll try again once parsing succeeds.
-                if (entry.key_ptr.*.namespace.file_scope.okToReportErrors()) {
+                if (entry.key_ptr.*.getFileScope().okToReportErrors()) {
                     try AllErrors.add(module, &arena, &errors, entry.value_ptr.*.*);
                 }
             }
@@ -1978,7 +1978,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
             while (it.next()) |entry| {
                 // Skip errors for Decls within files that had a parse failure.
                 // We'll try again once parsing succeeds.
-                if (entry.key_ptr.*.namespace.file_scope.okToReportErrors()) {
+                if (entry.key_ptr.*.getFileScope().okToReportErrors()) {
                     try AllErrors.add(module, &arena, &errors, entry.value_ptr.*.*);
                 }
             }
@@ -2169,12 +2169,12 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
                 defer air.deinit(gpa);
 
                 log.debug("analyze liveness of {s}", .{decl.name});
-                var liveness = try Liveness.analyze(gpa, air, decl.namespace.file_scope.zir);
+                var liveness = try Liveness.analyze(gpa, air, decl.getFileScope().zir);
                 defer liveness.deinit(gpa);
 
                 if (builtin.mode == .Debug and self.verbose_air) {
                     std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});
-                    @import("print_air.zig").dump(gpa, air, decl.namespace.file_scope.zir, liveness);
+                    @import("print_air.zig").dump(gpa, air, decl.getFileScope().zir, liveness);
                     std.debug.print("# End Function AIR: {s}\n\n", .{decl.name});
                 }
 
src/crash_report.zig
@@ -97,7 +97,7 @@ fn dumpStatusReport() !void {
         allocator,
         anal.body,
         anal.body_index,
-        block.src_decl.getFileScope(),
+        block.namespace.file_scope,
         block.src_decl.src_node,
         6, // indent
         stderr,
@@ -106,7 +106,7 @@ fn dumpStatusReport() !void {
         else => |e| return e,
     };
     try stderr.writeAll("    For full context, use the command\n      zig ast-check -t ");
-    try writeFilePath(block.src_decl.getFileScope(), stderr);
+    try writeFilePath(block.namespace.file_scope, stderr);
     try stderr.writeAll("\n\n");
 
     var parent = anal.parent;
@@ -118,7 +118,7 @@ fn dumpStatusReport() !void {
         print_zir.renderSingleInstruction(
             allocator,
             curr.body[curr.body_index],
-            curr.block.src_decl.getFileScope(),
+            curr.block.namespace.file_scope,
             curr.block.src_decl.src_node,
             6, // indent
             stderr,
src/Module.zig
@@ -264,7 +264,7 @@ pub const Export = struct {
 
     pub fn getSrcLoc(exp: Export) SrcLoc {
         return .{
-            .file_scope = exp.src_decl.namespace.file_scope,
+            .file_scope = exp.src_decl.getFileScope(),
             .parent_decl_node = exp.src_decl.src_node,
             .lazy = exp.src,
         };
@@ -350,7 +350,7 @@ pub const Decl = struct {
     /// Reference to externally owned memory.
     /// In the case of the Decl corresponding to a file, this is
     /// the namespace of the struct, since there is no parent.
-    namespace: *Scope.Namespace,
+    src_namespace: *Scope.Namespace,
 
     /// The scope which lexically contains this decl.  A decl must depend
     /// on its lexical parent, in order to ensure that this pointer is valid.
@@ -516,7 +516,7 @@ pub const Decl = struct {
     /// This name is relative to the containing namespace of the decl.
     /// The memory is owned by the containing File ZIR.
     pub fn getName(decl: Decl) ?[:0]const u8 {
-        const zir = decl.namespace.file_scope.zir;
+        const zir = decl.getFileScope().zir;
         return decl.getNameZir(zir);
     }
 
@@ -528,7 +528,7 @@ pub const Decl = struct {
     }
 
     pub fn contentsHash(decl: Decl) std.zig.SrcHash {
-        const zir = decl.namespace.file_scope.zir;
+        const zir = decl.getFileScope().zir;
         return decl.contentsHashZir(zir);
     }
 
@@ -541,21 +541,21 @@ pub const Decl = struct {
 
     pub fn zirBlockIndex(decl: *const Decl) Zir.Inst.Index {
         assert(decl.zir_decl_index != 0);
-        const zir = decl.namespace.file_scope.zir;
+        const zir = decl.getFileScope().zir;
         return zir.extra[decl.zir_decl_index + 6];
     }
 
     pub fn zirAlignRef(decl: Decl) Zir.Inst.Ref {
         if (!decl.has_align) return .none;
         assert(decl.zir_decl_index != 0);
-        const zir = decl.namespace.file_scope.zir;
+        const zir = decl.getFileScope().zir;
         return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 7]);
     }
 
     pub fn zirLinksectionRef(decl: Decl) Zir.Inst.Ref {
         if (!decl.has_linksection_or_addrspace) return .none;
         assert(decl.zir_decl_index != 0);
-        const zir = decl.namespace.file_scope.zir;
+        const zir = decl.getFileScope().zir;
         const extra_index = decl.zir_decl_index + 7 + @boolToInt(decl.has_align);
         return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
     }
@@ -563,16 +563,16 @@ pub const Decl = struct {
     pub fn zirAddrspaceRef(decl: Decl) Zir.Inst.Ref {
         if (!decl.has_linksection_or_addrspace) return .none;
         assert(decl.zir_decl_index != 0);
-        const zir = decl.namespace.file_scope.zir;
+        const zir = decl.getFileScope().zir;
         const extra_index = decl.zir_decl_index + 7 + @boolToInt(decl.has_align) + 1;
         return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
     }
 
     /// Returns true if and only if the Decl is the top level struct associated with a File.
     pub fn isRoot(decl: *const Decl) bool {
-        if (decl.namespace.parent != null)
+        if (decl.src_namespace.parent != null)
             return false;
-        return decl == decl.namespace.ty.getOwnerDecl();
+        return decl == decl.src_namespace.getDecl();
     }
 
     pub fn relativeToLine(decl: Decl, offset: u32) u32 {
@@ -608,29 +608,21 @@ pub const Decl = struct {
     }
 
     pub fn srcToken(decl: Decl) Ast.TokenIndex {
-        const tree = &decl.namespace.file_scope.tree;
+        const tree = &decl.getFileScope().tree;
         return tree.firstToken(decl.src_node);
     }
 
     pub fn srcByteOffset(decl: Decl) u32 {
-        const tree = &decl.namespace.file_scope.tree;
+        const tree = &decl.getFileScope().tree;
         return tree.tokens.items(.start)[decl.srcToken()];
     }
 
     pub fn renderFullyQualifiedName(decl: *const Decl, writer: anytype) @TypeOf(writer).Error!void {
-        // Namespace decls (struct/enum/union/opaque) use their own namespace,
-        // which means the decl name and the namespace name are the same.
-        // In that case we want to omit the decl name, unless this is the root decl.
-        const unqualified_name = if (decl.namespace.getDecl() != decl or decl.namespace.parent == null) mem.spanZ(decl.name) else "";
-        return try decl.namespace.renderFullyQualifiedName(unqualified_name, writer);
+        return try decl.src_namespace.renderFullyQualifiedName(mem.spanZ(decl.name), writer);
     }
 
     pub fn renderFullyQualifiedDebugName(decl: *const Decl, writer: anytype) @TypeOf(writer).Error!void {
-        // Namespace decls (struct/enum/union/opaque) use their own namespace,
-        // which means the decl name and the namespace name are the same.
-        // In that case we want to omit the decl name, unless this is the root decl.
-        const unqualified_name = if (decl.namespace.getDecl() != decl or decl.namespace.parent == null) mem.spanZ(decl.name) else "";
-        return try decl.namespace.renderFullyQualifiedDebugName(unqualified_name, writer);
+        return try decl.src_namespace.renderFullyQualifiedDebugName(mem.spanZ(decl.name), writer);
     }
 
     pub fn getFullyQualifiedName(decl: *const Decl, gpa: *Allocator) ![:0]u8 {
@@ -742,7 +734,7 @@ pub const Decl = struct {
     }
 
     pub fn getFileScope(decl: Decl) *Scope.File {
-        return decl.namespace.file_scope;
+        return decl.src_namespace.file_scope;
     }
 
     pub fn getEmitH(decl: *Decl, module: *Module) *EmitH {
@@ -1118,8 +1110,8 @@ pub const Scope = struct {
     /// Asserts the scope has a parent which is a Namespace and returns it.
     pub fn namespace(scope: *Scope) *Namespace {
         switch (scope.tag) {
-            .block => return scope.cast(Block).?.src_decl.namespace,
-            .file => return scope.cast(File).?.root_decl.?.namespace,
+            .block => return scope.cast(Block).?.namespace,
+            .file => return scope.cast(File).?.root_decl.?.src_namespace,
             .namespace => return scope.cast(Namespace).?,
         }
     }
@@ -1134,14 +1126,14 @@ pub const Scope = struct {
         }
     }
 
-    /// When called from inside a Block Scope, chases the src_decl, not the owner_decl.
+    /// When called from inside a Block Scope, chases the namespace, not the owner_decl.
     pub fn getFileScope(base: *Scope) *Scope.File {
         var cur = base;
         while (true) {
             cur = switch (cur.tag) {
                 .namespace => return @fieldParentPtr(Namespace, "base", cur).file_scope,
                 .file => return @fieldParentPtr(File, "base", cur),
-                .block => return @fieldParentPtr(Block, "base", cur).src_decl.namespace.file_scope,
+                .block => return @fieldParentPtr(Block, "base", cur).namespace.file_scope,
             };
         }
     }
@@ -1475,6 +1467,10 @@ pub const Scope = struct {
         /// 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: *Decl,
+        /// The namespace to use for lookups from this source block
+        /// When analyzing fields, this is different from src_decl.src_namepsace.
+        namespace: *Namespace,
+        /// The AIR instructions generated for this block.
         instructions: ArrayListUnmanaged(Air.Inst.Index),
         // `param` instructions are collected here to be used by the `func` instruction.
         params: std.ArrayListUnmanaged(Param) = .{},
@@ -1541,6 +1537,7 @@ pub const Scope = struct {
                 .parent = parent,
                 .sema = parent.sema,
                 .src_decl = parent.src_decl,
+                .namespace = parent.namespace,
                 .instructions = .{},
                 .wip_capture_scope = parent.wip_capture_scope,
                 .label = null,
@@ -1564,7 +1561,7 @@ pub const Scope = struct {
         }
 
         pub fn getFileScope(block: *Block) *Scope.File {
-            return block.src_decl.namespace.file_scope;
+            return block.namespace.file_scope;
         }
 
         pub fn addTy(
@@ -3327,6 +3324,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
             .parent = null,
             .sema = &sema,
             .src_decl = new_decl,
+            .namespace = &struct_obj.namespace,
             .wip_capture_scope = wip_captures.scope,
             .instructions = .{},
             .inlining = null,
@@ -3355,12 +3353,12 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
     const tracy = trace(@src());
     defer tracy.end();
 
-    if (decl.namespace.file_scope.status != .success_zir) {
+    if (decl.getFileScope().status != .success_zir) {
         return error.AnalysisFail;
     }
 
     const gpa = mod.gpa;
-    const zir = decl.namespace.file_scope.zir;
+    const zir = decl.getFileScope().zir;
     const zir_datas = zir.instructions.items(.data);
 
     decl.analysis = .in_progress;
@@ -3406,6 +3404,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
         .parent = null,
         .sema = &sema,
         .src_decl = decl,
+        .namespace = decl.src_namespace,
         .wip_capture_scope = wip_captures.scope,
         .instructions = .{},
         .inlining = null,
@@ -4042,8 +4041,8 @@ pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {
         },
     }
 
-    const owner_namespace = if (decl.namespace.getDecl() == decl and decl.namespace.parent != null) decl.namespace.parent.? else decl.namespace;
-    assert(owner_namespace.anon_decls.swapRemove(decl));
+    assert(!decl.isRoot());
+    assert(decl.src_namespace.anon_decls.swapRemove(decl));
 
     const dependants = decl.dependants.keys();
     for (dependants) |dep| {
@@ -4059,8 +4058,8 @@ pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {
 pub fn abortAnonDecl(mod: *Module, decl: *Decl) void {
     log.debug("abortAnonDecl {*} ({s})", .{ decl, decl.name });
 
-    const owner_namespace = if (decl.namespace.getDecl() == decl and decl.namespace.parent != null) decl.namespace.parent.? else decl.namespace;
-    assert(owner_namespace.anon_decls.swapRemove(decl));
+    assert(!decl.isRoot());
+    assert(decl.src_namespace.anon_decls.swapRemove(decl));
 
     const dependants = decl.dependants.keys();
     for (dependants) |dep| {
@@ -4128,7 +4127,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: *Allocator) Se
         .gpa = gpa,
         .arena = arena,
         .perm_arena = &decl_arena.allocator,
-        .code = decl.namespace.file_scope.zir,
+        .code = decl.getFileScope().zir,
         .owner_decl = decl,
         .func = func,
         .fn_ret_ty = func.owner_decl.ty.fnReturnType(),
@@ -4148,6 +4147,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: *Allocator) Se
         .parent = null,
         .sema = &sema,
         .src_decl = decl,
+        .namespace = decl.src_namespace,
         .wip_capture_scope = wip_captures.scope,
         .instructions = .{},
         .inlining = null,
@@ -4279,7 +4279,7 @@ pub fn allocateNewDecl(mod: *Module, name: [:0]const u8, namespace: *Scope.Names
 
     new_decl.* = .{
         .name = name,
-        .namespace = namespace,
+        .src_namespace = namespace,
         .src_node = src_node,
         .src_line = undefined,
         .has_tv = false,
@@ -4426,32 +4426,38 @@ pub fn createAnonymousDeclNamed(
     typed_value: TypedValue,
     name: [:0]u8,
 ) !*Decl {
-    return mod.createAnonymousDeclFromDeclNamed(scope.srcDecl().?, scope.srcScope(), typed_value, name);
+    return mod.createAnonymousDeclFromDeclNamed(scope.srcDecl().?, scope.namespace(), scope.srcScope(), typed_value, name);
 }
 
 pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) !*Decl {
-    return mod.createAnonymousDeclFromDecl(scope.srcDecl().?, scope.srcScope(), typed_value);
+    return mod.createAnonymousDeclFromDecl(scope.srcDecl().?, scope.namespace(), scope.srcScope(), typed_value);
 }
 
-pub fn createAnonymousDeclFromDecl(mod: *Module, src_decl: *Decl, src_scope: ?*CaptureScope, tv: TypedValue) !*Decl {
+pub fn createAnonymousDeclFromDecl(
+    mod: *Module,
+    src_decl: *Decl,
+    namespace: *Scope.Namespace,
+    src_scope: ?*CaptureScope,
+    tv: TypedValue,
+) !*Decl {
     const name_index = mod.getNextAnonNameIndex();
     const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{
         src_decl.name, name_index,
     });
-    return mod.createAnonymousDeclFromDeclNamed(src_decl, src_scope, tv, name);
+    return mod.createAnonymousDeclFromDeclNamed(src_decl, namespace, src_scope, tv, name);
 }
 
 /// Takes ownership of `name` even if it returns an error.
 pub fn createAnonymousDeclFromDeclNamed(
     mod: *Module,
     src_decl: *Decl,
+    namespace: *Scope.Namespace,
     src_scope: ?*CaptureScope,
     typed_value: TypedValue,
     name: [:0]u8,
 ) !*Decl {
     errdefer mod.gpa.free(name);
 
-    const namespace = src_decl.namespace;
     try namespace.anon_decls.ensureUnusedCapacity(mod.gpa, 1);
 
     const new_decl = try mod.allocateNewDecl(name, namespace, src_decl.src_node, src_scope);
@@ -4705,10 +4711,10 @@ pub const SwitchProngSrc = union(enum) {
         range_expand: RangeExpand,
     ) LazySrcLoc {
         @setCold(true);
-        const tree = decl.namespace.file_scope.getTree(gpa) catch |err| {
+        const tree = decl.getFileScope().getTree(gpa) catch |err| {
             // In this case we emit a warning + a less precise source location.
             log.warn("unable to load {s}: {s}", .{
-                decl.namespace.file_scope.sub_file_path, @errorName(err),
+                decl.getFileScope().sub_file_path, @errorName(err),
             });
             return LazySrcLoc{ .node_offset = 0 };
         };
@@ -4817,10 +4823,10 @@ pub const PeerTypeCandidateSrc = union(enum) {
                     else => {},
                 }
 
-                const tree = decl.namespace.file_scope.getTree(gpa) catch |err| {
+                const tree = decl.getFileScope().getTree(gpa) catch |err| {
                     // In this case we emit a warning + a less precise source location.
                     log.warn("unable to load {s}: {s}", .{
-                        decl.namespace.file_scope.sub_file_path, @errorName(err),
+                        decl.getFileScope().sub_file_path, @errorName(err),
                     });
                     return LazySrcLoc{ .node_offset = 0 };
                 };
@@ -4863,7 +4869,7 @@ pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {
 
             // Remove from the namespace it resides in, preserving declaration order.
             assert(decl.zir_decl_index != 0);
-            _ = decl.namespace.decls.orderedRemove(mem.spanZ(decl.name));
+            _ = decl.src_namespace.decls.orderedRemove(mem.spanZ(decl.name));
 
             try mod.clearDecl(decl, &outdated_decls);
             decl.destroy(mod);
@@ -4929,7 +4935,7 @@ pub fn populateTestFunctions(mod: *Module) !void {
     const gpa = mod.gpa;
     const builtin_pkg = mod.main_pkg.table.get("builtin").?;
     const builtin_file = (mod.importPkg(builtin_pkg) catch unreachable).file;
-    const builtin_namespace = builtin_file.root_decl.?.namespace;
+    const builtin_namespace = builtin_file.root_decl.?.src_namespace;
     const decl = builtin_namespace.decls.get("test_functions").?;
     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
     const tmp_test_fn_ty = decl.ty.slicePtrFieldType(&buf).elemType();
@@ -4942,7 +4948,7 @@ pub fn populateTestFunctions(mod: *Module) !void {
         const arena = &new_decl_arena.allocator;
 
         const test_fn_vals = try arena.alloc(Value, mod.test_functions.count());
-        const array_decl = try mod.createAnonymousDeclFromDecl(decl, null, .{
+        const array_decl = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, null, .{
             .ty = try Type.Tag.array.create(arena, .{
                 .len = test_fn_vals.len,
                 .elem_type = try tmp_test_fn_ty.copy(arena),
@@ -4955,7 +4961,7 @@ pub fn populateTestFunctions(mod: *Module) !void {
                 var name_decl_arena = std.heap.ArenaAllocator.init(gpa);
                 errdefer name_decl_arena.deinit();
                 const bytes = try name_decl_arena.allocator.dupe(u8, test_name_slice);
-                const test_name_decl = try mod.createAnonymousDeclFromDecl(array_decl, null, .{
+                const test_name_decl = try mod.createAnonymousDeclFromDecl(array_decl, array_decl.src_namespace, null, .{
                     .ty = try Type.Tag.array_u8.create(&name_decl_arena.allocator, bytes.len),
                     .val = try Value.Tag.bytes.create(&name_decl_arena.allocator, bytes),
                 });
src/Sema.zig
@@ -1042,8 +1042,6 @@ pub fn analyzeStructDecl(
     } else 0;
 
     _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra_index, decls_len, new_decl);
-
-    new_decl.namespace = &struct_obj.namespace;
 }
 
 fn zirStructDecl(
@@ -1080,7 +1078,7 @@ fn zirStructDecl(
         .status = .none,
         .known_has_bits = undefined,
         .namespace = .{
-            .parent = block.src_decl.namespace,
+            .parent = block.namespace,
             .ty = struct_ty,
             .file_scope = block.getFileScope(),
         },
@@ -1188,7 +1186,7 @@ fn zirEnumDecl(
         .values = .{},
         .node_offset = src.node_offset,
         .namespace = .{
-            .parent = block.src_decl.namespace,
+            .parent = block.namespace,
             .ty = enum_ty,
             .file_scope = block.getFileScope(),
         },
@@ -1199,8 +1197,6 @@ fn zirEnumDecl(
 
     extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);
 
-    new_decl.namespace = &enum_obj.namespace;
-
     const body = sema.code.extra[extra_index..][0..body_len];
     if (fields_len == 0) {
         assert(body.len == 0);
@@ -1238,6 +1234,7 @@ fn zirEnumDecl(
             .parent = null,
             .sema = sema,
             .src_decl = new_decl,
+            .namespace = &enum_obj.namespace,
             .wip_capture_scope = wip_captures.scope,
             .instructions = .{},
             .inlining = null,
@@ -1377,7 +1374,7 @@ fn zirUnionDecl(
         .layout = small.layout,
         .status = .none,
         .namespace = .{
-            .parent = block.src_decl.namespace,
+            .parent = block.namespace,
             .ty = union_ty,
             .file_scope = block.getFileScope(),
         },
@@ -1388,8 +1385,6 @@ fn zirUnionDecl(
 
     _ = try sema.mod.scanNamespace(&union_obj.namespace, extra_index, decls_len, new_decl);
 
-    new_decl.namespace = &union_obj.namespace;
-
     try new_decl.finalizeNewArena(&new_decl_arena);
     return sema.analyzeDeclVal(block, src, new_decl);
 }
@@ -2283,6 +2278,7 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Com
         .parent = parent_block,
         .sema = sema,
         .src_decl = parent_block.src_decl,
+        .namespace = parent_block.namespace,
         .wip_capture_scope = parent_block.wip_capture_scope,
         .instructions = .{},
         .inlining = parent_block.inlining,
@@ -2383,6 +2379,7 @@ fn zirBlock(
         .parent = parent_block,
         .sema = sema,
         .src_decl = parent_block.src_decl,
+        .namespace = parent_block.namespace,
         .wip_capture_scope = parent_block.wip_capture_scope,
         .instructions = .{},
         .label = &label,
@@ -2684,7 +2681,7 @@ fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr
 }
 
 fn lookupIdentifier(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, name: []const u8) !*Decl {
-    var namespace = block.src_decl.namespace;
+    var namespace = block.namespace;
     while (true) {
         if (try sema.lookupInNamespace(block, src, namespace, name, false)) |decl| {
             return decl;
@@ -2713,7 +2710,7 @@ fn lookupInNamespace(
     }
 
     if (observe_usingnamespace and namespace.usingnamespace_set.count() != 0) {
-        const src_file = block.src_decl.namespace.file_scope;
+        const src_file = block.namespace.file_scope;
 
         const gpa = sema.gpa;
         var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Scope.Namespace, void) = .{};
@@ -2731,7 +2728,7 @@ fn lookupInNamespace(
             if (check_ns.decls.get(ident_name)) |decl| {
                 // Skip decls which are not marked pub, which are in a different
                 // file than the `a.b`/`@hasDecl` syntax.
-                if (decl.is_pub or src_file == decl.namespace.file_scope) {
+                if (decl.is_pub or src_file == decl.getFileScope()) {
                     try candidates.append(gpa, decl);
                 }
             }
@@ -2739,7 +2736,7 @@ fn lookupInNamespace(
             while (it.next()) |entry| {
                 const sub_usingnamespace_decl = entry.key_ptr.*;
                 const sub_is_pub = entry.value_ptr.*;
-                if (!sub_is_pub and src_file != sub_usingnamespace_decl.namespace.file_scope) {
+                if (!sub_is_pub and src_file != sub_usingnamespace_decl.getFileScope()) {
                     // Skip usingnamespace decls which are not marked pub, which are in
                     // a different file than the `a.b`/`@hasDecl` syntax.
                     continue;
@@ -2992,7 +2989,7 @@ fn analyzeCall(
         // In order to save a bit of stack space, directly modify Sema rather
         // than create a child one.
         const parent_zir = sema.code;
-        sema.code = module_fn.owner_decl.namespace.file_scope.zir;
+        sema.code = module_fn.owner_decl.getFileScope().zir;
         defer sema.code = parent_zir;
 
         const parent_inst_map = sema.inst_map;
@@ -3013,6 +3010,7 @@ fn analyzeCall(
             .parent = null,
             .sema = sema,
             .src_decl = module_fn.owner_decl,
+            .namespace = module_fn.owner_decl.src_namespace,
             .wip_capture_scope = wip_captures.scope,
             .instructions = .{},
             .label = null,
@@ -3182,7 +3180,7 @@ fn analyzeCall(
         // Check the Module's generic function map with an adapted context, so that we
         // can match against `uncasted_args` rather than doing the work below to create a
         // generic Scope only to junk it if it matches an existing instantiation.
-        const namespace = module_fn.owner_decl.namespace;
+        const namespace = module_fn.owner_decl.src_namespace;
         const fn_zir = namespace.file_scope.zir;
         const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst);
         const zir_tags = fn_zir.instructions.items(.tag);
@@ -3314,6 +3312,7 @@ fn analyzeCall(
                 .parent = null,
                 .sema = &child_sema,
                 .src_decl = new_decl,
+                .namespace = namespace,
                 .wip_capture_scope = wip_captures.scope,
                 .instructions = .{},
                 .inlining = null,
@@ -5338,6 +5337,7 @@ fn analyzeSwitch(
         .parent = block,
         .sema = sema,
         .src_decl = block.src_decl,
+        .namespace = block.namespace,
         .wip_capture_scope = block.wip_capture_scope,
         .instructions = .{},
         .label = &label,
@@ -5861,7 +5861,7 @@ fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr
         .{container_type},
     );
     if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl| {
-        if (decl.is_pub or decl.namespace.file_scope == block.base.namespace().file_scope) {
+        if (decl.is_pub or decl.getFileScope() == block.base.namespace().file_scope) {
             return Air.Inst.Ref.bool_true;
         }
     }
@@ -9603,8 +9603,9 @@ fn addSafetyCheck(
     var fail_block: Scope.Block = .{
         .parent = parent_block,
         .sema = sema,
-        .wip_capture_scope = parent_block.wip_capture_scope,
         .src_decl = parent_block.src_decl,
+        .namespace = parent_block.namespace,
+        .wip_capture_scope = parent_block.wip_capture_scope,
         .instructions = .{},
         .inlining = parent_block.inlining,
         .is_comptime = parent_block.is_comptime,
@@ -10259,7 +10260,7 @@ fn namespaceLookup(
     const mod = sema.mod;
     const gpa = sema.gpa;
     if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl| {
-        if (!decl.is_pub and decl.namespace.file_scope != block.getFileScope()) {
+        if (!decl.is_pub and decl.getFileScope() != block.getFileScope()) {
             const msg = msg: {
                 const msg = try mod.errMsg(&block.base, src, "'{s}' is not marked 'pub'", .{
                     decl_name,
@@ -11911,6 +11912,7 @@ fn semaStructFields(
         .parent = null,
         .sema = &sema,
         .src_decl = decl,
+        .namespace = &struct_obj.namespace,
         .wip_capture_scope = wip_captures.scope,
         .instructions = .{},
         .inlining = null,
@@ -12080,6 +12082,7 @@ fn semaUnionFields(
         .parent = null,
         .sema = &sema,
         .src_decl = decl,
+        .namespace = &union_obj.namespace,
         .wip_capture_scope = wip_captures.scope,
         .instructions = .{},
         .inlining = null,
@@ -12290,7 +12293,7 @@ fn getBuiltin(
     const opt_builtin_inst = try sema.namespaceLookupRef(
         block,
         src,
-        std_file.root_decl.?.namespace,
+        std_file.root_decl.?.src_namespace,
         "builtin",
     );
     const builtin_inst = try sema.analyzeLoad(block, src, opt_builtin_inst.?, src);
@@ -12484,7 +12487,7 @@ fn typeHasOnePossibleValue(
 }
 
 fn getAstTree(sema: *Sema, block: *Scope.Block) CompileError!*const std.zig.Ast {
-    return block.src_decl.namespace.file_scope.getTree(sema.gpa) catch |err| {
+    return block.namespace.file_scope.getTree(sema.gpa) catch |err| {
         log.err("unable to load AST to report compile error: {s}", .{@errorName(err)});
         return error.AnalysisFail;
     };