Commit f34b198251

Jacob Young <jacobly0@users.noreply.github.com>
2024-09-05 21:58:24
Dwarf: implement and test decls
1 parent 778519b
ci/x86_64-linux-debug.sh
@@ -64,7 +64,7 @@ stage3-debug/bin/zig build \
 
 stage3-debug/bin/zig build test docs \
   --maxrss 21000000000 \
-  -Dlldb=$HOME/deps/lldb-zig/Debug-befcd57a8/bin/lldb \
+  -Dlldb=$HOME/deps/lldb-zig/Debug-4a44163df/bin/lldb \
   -fqemu \
   -fwasmtime \
   -Dstatic-llvm \
ci/x86_64-linux-release.sh
@@ -64,7 +64,7 @@ stage3-release/bin/zig build \
 
 stage3-release/bin/zig build test docs \
   --maxrss 21000000000 \
-  -Dlldb=$HOME/deps/lldb-zig/Release-befcd57a8/bin/lldb \
+  -Dlldb=$HOME/deps/lldb-zig/Release-4a44163df/bin/lldb \
   -fqemu \
   -fwasmtime \
   -Dstatic-llvm \
src/link/Dwarf.zig
@@ -2509,6 +2509,19 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
         return;
     }
 
+    const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
+        const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
+        break :parent .{
+            parent_namespace_ptr.owner_type,
+            if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
+                DW.ACCESS.public
+            else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
+                DW.ACCESS.private
+            else
+                unreachable,
+        };
+    } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
+
     const tree = try file.getTree(dwarf.gpa);
     const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]);
     assert(loc.line == zcu.navSrcLine(nav_index));
@@ -2534,459 +2547,380 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
 
     const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
     errdefer _ = dwarf.navs.pop();
-    switch (ip.indexToKey(nav_val.toIntern())) {
-        .func => |func| {
-            if (nav_gop.found_existing) {
-                const unit_ptr = dwarf.debug_info.section.getUnit(wip_nav.unit);
-                const entry_ptr = unit_ptr.getEntry(nav_gop.value_ptr.*);
-                if (entry_ptr.len >= AbbrevCode.decl_bytes) {
-                    var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined;
-                    if (try dwarf.getFile().?.preadAll(
-                        &abbrev_code_buf,
-                        dwarf.debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off,
-                    ) != abbrev_code_buf.len) return error.InputOutput;
-                    var abbrev_code_fbs = std.io.fixedBufferStream(&abbrev_code_buf);
-                    const abbrev_code: AbbrevCode = @enumFromInt(
-                        std.leb.readUleb128(@typeInfo(AbbrevCode).@"enum".tag_type, abbrev_code_fbs.reader()) catch unreachable,
-                    );
-                    switch (abbrev_code) {
-                        else => unreachable,
-                        .decl_func, .decl_empty_func => return,
-                        .decl_func_generic, .decl_empty_func_generic => {},
-                    }
-                }
-                entry_ptr.clear();
-            } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
-            wip_nav.entry = nav_gop.value_ptr.*;
-
-            const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
-                const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
-                break :parent .{
-                    parent_namespace_ptr.owner_type,
-                    if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
-                        DW.ACCESS.public
-                    else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
-                        DW.ACCESS.private
-                    else
-                        unreachable,
-                };
-            } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
 
-            const func_type = ip.indexToKey(func.ty).func_type;
-            const diw = wip_nav.debug_info.writer(dwarf.gpa);
-            try wip_nav.abbrevCode(if (func_type.param_types.len > 0 or func_type.is_var_args)
-                .decl_func_generic
-            else
-                .decl_empty_func_generic);
-            try wip_nav.refType(Type.fromInterned(parent_type));
-            assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
-            try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
-            try uleb128(diw, loc.column + 1);
-            try diw.writeByte(accessibility);
-            try wip_nav.strp(nav.name.toSlice(ip));
-            try wip_nav.refType(Type.fromInterned(func_type.return_type));
-            if (func_type.param_types.len > 0 or func_type.is_var_args) {
-                for (0..func_type.param_types.len) |param_index| {
-                    try wip_nav.abbrevCode(.func_type_param);
-                    try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index]));
-                }
-                if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
-                try uleb128(diw, @intFromEnum(AbbrevCode.null));
-            }
-        },
-        .struct_type => done: {
+    const tag: enum { done, decl_alias } = switch (ip.indexToKey(nav_val.toIntern())) {
+        .int_type,
+        .ptr_type,
+        .array_type,
+        .vector_type,
+        .opt_type,
+        .anyframe_type,
+        .error_union_type,
+        .simple_type,
+        .anon_struct_type,
+        .func_type,
+        .error_set_type,
+        .inferred_error_set_type,
+        => .decl_alias,
+        .struct_type => tag: {
             const loaded_struct = ip.loadStructType(nav_val.toIntern());
-
-            const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
-                const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
-                break :parent .{
-                    parent_namespace_ptr.owner_type,
-                    if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
-                        DW.ACCESS.public
-                    else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
-                        DW.ACCESS.private
-                    else
-                        unreachable,
+            if (loaded_struct.zir_index == .none) break :tag .decl_alias;
+
+            const type_inst_info = loaded_struct.zir_index.unwrap().?.resolveFull(ip).?;
+            if (type_inst_info.file != inst_info.file) break :tag .decl_alias;
+
+            const value_inst = value_inst: {
+                const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
+                const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
+                if (break_inst.tag != .break_inline) break :value_inst null;
+                assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
+                var value_inst = break_inst.data.@"break".operand.toIndex();
+                while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
+                    else => break,
+                    .as_node => value_inst = file.zir.extraData(
+                        Zir.Inst.As,
+                        file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
+                    ).data.operand.toIndex(),
                 };
-            } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
-
-            decl_struct: {
-                if (loaded_struct.zir_index == .none) break :decl_struct;
-
-                const type_inst_info = loaded_struct.zir_index.unwrap().?.resolveFull(ip).?;
-                if (type_inst_info.file != inst_info.file) break :decl_struct;
-
-                const value_inst = value_inst: {
-                    const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
-                    const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
-                    if (break_inst.tag != .break_inline) break :value_inst null;
-                    assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
-                    var value_inst = break_inst.data.@"break".operand.toIndex();
-                    while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
-                        else => break,
-                        .as_node => value_inst = file.zir.extraData(
-                            Zir.Inst.As,
-                            file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
-                        ).data.operand.toIndex(),
-                    };
-                    break :value_inst value_inst;
-                };
-                if (type_inst_info.inst != value_inst) break :decl_struct;
+                break :value_inst value_inst;
+            };
+            if (type_inst_info.inst != value_inst) break :tag .decl_alias;
 
-                const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
-                if (type_gop.found_existing) {
-                    dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear();
-                    nav_gop.value_ptr.* = type_gop.value_ptr.*;
-                } else {
-                    if (nav_gop.found_existing)
-                        dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
-                    else
-                        nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
-                    type_gop.value_ptr.* = nav_gop.value_ptr.*;
-                }
-                wip_nav.entry = nav_gop.value_ptr.*;
+            const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
+            if (type_gop.found_existing) {
+                dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear();
+                nav_gop.value_ptr.* = type_gop.value_ptr.*;
+            } else {
+                if (nav_gop.found_existing)
+                    dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
+                else
+                    nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
+                type_gop.value_ptr.* = nav_gop.value_ptr.*;
+            }
+            wip_nav.entry = nav_gop.value_ptr.*;
 
-                const diw = wip_nav.debug_info.writer(dwarf.gpa);
+            const diw = wip_nav.debug_info.writer(dwarf.gpa);
 
-                switch (loaded_struct.layout) {
-                    .auto, .@"extern" => {
-                        try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .decl_namespace_struct else .decl_struct);
-                        try wip_nav.refType(Type.fromInterned(parent_type));
-                        assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
-                        try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
-                        try uleb128(diw, loc.column + 1);
-                        try diw.writeByte(accessibility);
-                        try wip_nav.strp(nav.name.toSlice(ip));
-                        if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
-                            try uleb128(diw, nav_val.toType().abiSize(zcu));
-                            try uleb128(diw, nav_val.toType().abiAlignment(zcu).toByteUnits().?);
-                            for (0..loaded_struct.field_types.len) |field_index| {
-                                const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
-                                try wip_nav.abbrevCode(if (is_comptime) .struct_field_comptime else .struct_field);
-                                if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
-                                    const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
-                                    defer dwarf.gpa.free(field_name);
-                                    try wip_nav.strp(field_name);
-                                }
-                                const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
-                                try wip_nav.refType(field_type);
-                                if (!is_comptime) {
-                                    try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]);
-                                    try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
-                                        field_type.abiAlignment(zcu).toByteUnits().?);
-                                }
-                            }
-                            try uleb128(diw, @intFromEnum(AbbrevCode.null));
-                        }
-                    },
-                    .@"packed" => {
-                        try wip_nav.abbrevCode(.decl_packed_struct);
-                        try wip_nav.refType(Type.fromInterned(parent_type));
-                        assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
-                        try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
-                        try uleb128(diw, loc.column + 1);
-                        try diw.writeByte(accessibility);
-                        try wip_nav.strp(nav.name.toSlice(ip));
-                        try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
-                        var field_bit_offset: u16 = 0;
+            switch (loaded_struct.layout) {
+                .auto, .@"extern" => {
+                    try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .decl_namespace_struct else .decl_struct);
+                    try wip_nav.refType(Type.fromInterned(parent_type));
+                    assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
+                    try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
+                    try uleb128(diw, loc.column + 1);
+                    try diw.writeByte(accessibility);
+                    try wip_nav.strp(nav.name.toSlice(ip));
+                    if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
+                        try uleb128(diw, nav_val.toType().abiSize(zcu));
+                        try uleb128(diw, nav_val.toType().abiAlignment(zcu).toByteUnits().?);
                         for (0..loaded_struct.field_types.len) |field_index| {
-                            try wip_nav.abbrevCode(.packed_struct_field);
-                            try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip));
+                            const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
+                            try wip_nav.abbrevCode(if (is_comptime) .struct_field_comptime else .struct_field);
+                            if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
+                                const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
+                                defer dwarf.gpa.free(field_name);
+                                try wip_nav.strp(field_name);
+                            }
                             const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
                             try wip_nav.refType(field_type);
-                            try uleb128(diw, field_bit_offset);
-                            field_bit_offset += @intCast(field_type.bitSize(zcu));
+                            if (!is_comptime) {
+                                try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]);
+                                try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
+                                    field_type.abiAlignment(zcu).toByteUnits().?);
+                            }
                         }
                         try uleb128(diw, @intFromEnum(AbbrevCode.null));
-                    },
-                }
-                break :done;
+                    }
+                },
+                .@"packed" => {
+                    try wip_nav.abbrevCode(.decl_packed_struct);
+                    try wip_nav.refType(Type.fromInterned(parent_type));
+                    assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
+                    try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
+                    try uleb128(diw, loc.column + 1);
+                    try diw.writeByte(accessibility);
+                    try wip_nav.strp(nav.name.toSlice(ip));
+                    try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
+                    var field_bit_offset: u16 = 0;
+                    for (0..loaded_struct.field_types.len) |field_index| {
+                        try wip_nav.abbrevCode(.packed_struct_field);
+                        try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip));
+                        const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
+                        try wip_nav.refType(field_type);
+                        try uleb128(diw, field_bit_offset);
+                        field_bit_offset += @intCast(field_type.bitSize(zcu));
+                    }
+                    try uleb128(diw, @intFromEnum(AbbrevCode.null));
+                },
             }
+            break :tag .done;
+        },
+        .enum_type => tag: {
+            const loaded_enum = ip.loadEnumType(nav_val.toIntern());
+            if (loaded_enum.zir_index == .none) break :tag .decl_alias;
+
+            const type_inst_info = loaded_enum.zir_index.unwrap().?.resolveFull(ip).?;
+            if (type_inst_info.file != inst_info.file) break :tag .decl_alias;
+
+            const value_inst = value_inst: {
+                const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
+                const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
+                if (break_inst.tag != .break_inline) break :value_inst null;
+                assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
+                var value_inst = break_inst.data.@"break".operand.toIndex();
+                while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
+                    else => break,
+                    .as_node => value_inst = file.zir.extraData(
+                        Zir.Inst.As,
+                        file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
+                    ).data.operand.toIndex(),
+                };
+                break :value_inst value_inst;
+            };
+            if (type_inst_info.inst != value_inst) break :tag .decl_alias;
 
-            if (nav_gop.found_existing)
-                dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
-            else
-                nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
+            const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
+            if (type_gop.found_existing) {
+                dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear();
+                nav_gop.value_ptr.* = type_gop.value_ptr.*;
+            } else {
+                if (nav_gop.found_existing)
+                    dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
+                else
+                    nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
+                type_gop.value_ptr.* = nav_gop.value_ptr.*;
+            }
             wip_nav.entry = nav_gop.value_ptr.*;
             const diw = wip_nav.debug_info.writer(dwarf.gpa);
-            try wip_nav.abbrevCode(.decl_alias);
+            try wip_nav.abbrevCode(if (loaded_enum.names.len > 0) .decl_enum else .decl_empty_enum);
             try wip_nav.refType(Type.fromInterned(parent_type));
             assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
             try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
             try uleb128(diw, loc.column + 1);
             try diw.writeByte(accessibility);
             try wip_nav.strp(nav.name.toSlice(ip));
-            try wip_nav.refType(nav_val.toType());
+            try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
+            for (0..loaded_enum.names.len) |field_index| {
+                try wip_nav.enumConstValue(loaded_enum, .{
+                    .sdata = .signed_enum_field,
+                    .udata = .unsigned_enum_field,
+                    .block = .big_enum_field,
+                }, field_index);
+                try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
+            }
+            if (loaded_enum.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
+            break :tag .done;
         },
-        .enum_type => done: {
-            const loaded_enum = ip.loadEnumType(nav_val.toIntern());
-
-            const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
-                const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
-                break :parent .{
-                    parent_namespace_ptr.owner_type,
-                    if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
-                        DW.ACCESS.public
-                    else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
-                        DW.ACCESS.private
-                    else
-                        unreachable,
-                };
-            } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
+        .union_type => tag: {
+            const loaded_union = ip.loadUnionType(nav_val.toIntern());
 
-            decl_enum: {
-                if (loaded_enum.zir_index == .none) break :decl_enum;
-
-                const type_inst_info = loaded_enum.zir_index.unwrap().?.resolveFull(ip).?;
-                if (type_inst_info.file != inst_info.file) break :decl_enum;
-
-                const value_inst = value_inst: {
-                    const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
-                    const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
-                    if (break_inst.tag != .break_inline) break :value_inst null;
-                    assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
-                    var value_inst = break_inst.data.@"break".operand.toIndex();
-                    while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
-                        else => break,
-                        .as_node => value_inst = file.zir.extraData(
-                            Zir.Inst.As,
-                            file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
-                        ).data.operand.toIndex(),
-                    };
-                    break :value_inst value_inst;
+            const type_inst_info = loaded_union.zir_index.resolveFull(ip).?;
+            if (type_inst_info.file != inst_info.file) break :tag .decl_alias;
+
+            const value_inst = value_inst: {
+                const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
+                const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
+                if (break_inst.tag != .break_inline) break :value_inst null;
+                assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
+                var value_inst = break_inst.data.@"break".operand.toIndex();
+                while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
+                    else => break,
+                    .as_node => value_inst = file.zir.extraData(
+                        Zir.Inst.As,
+                        file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
+                    ).data.operand.toIndex(),
                 };
-                if (type_inst_info.inst != value_inst) break :decl_enum;
+                break :value_inst value_inst;
+            };
+            if (type_inst_info.inst != value_inst) break :tag .decl_alias;
 
-                const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
-                if (type_gop.found_existing) {
-                    dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear();
-                    nav_gop.value_ptr.* = type_gop.value_ptr.*;
-                } else {
-                    if (nav_gop.found_existing)
-                        dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
-                    else
-                        nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
-                    type_gop.value_ptr.* = nav_gop.value_ptr.*;
-                }
-                wip_nav.entry = nav_gop.value_ptr.*;
-                const diw = wip_nav.debug_info.writer(dwarf.gpa);
-                try wip_nav.abbrevCode(if (loaded_enum.names.len > 0) .decl_enum else .decl_empty_enum);
-                try wip_nav.refType(Type.fromInterned(parent_type));
-                assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
-                try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
-                try uleb128(diw, loc.column + 1);
-                try diw.writeByte(accessibility);
-                try wip_nav.strp(nav.name.toSlice(ip));
-                try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
-                for (0..loaded_enum.names.len) |field_index| {
-                    try wip_nav.enumConstValue(loaded_enum, .{
-                        .sdata = .signed_enum_field,
-                        .udata = .unsigned_enum_field,
-                        .block = .big_enum_field,
-                    }, field_index);
-                    try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
-                }
-                if (loaded_enum.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
-                break :done;
+            const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
+            if (type_gop.found_existing) {
+                dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear();
+                nav_gop.value_ptr.* = type_gop.value_ptr.*;
+            } else {
+                if (nav_gop.found_existing)
+                    dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
+                else
+                    nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
+                type_gop.value_ptr.* = nav_gop.value_ptr.*;
             }
-
-            if (nav_gop.found_existing)
-                dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
-            else
-                nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
             wip_nav.entry = nav_gop.value_ptr.*;
             const diw = wip_nav.debug_info.writer(dwarf.gpa);
-            try wip_nav.abbrevCode(.decl_alias);
+            try wip_nav.abbrevCode(.decl_union);
             try wip_nav.refType(Type.fromInterned(parent_type));
             assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
             try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
             try uleb128(diw, loc.column + 1);
             try diw.writeByte(accessibility);
             try wip_nav.strp(nav.name.toSlice(ip));
-            try wip_nav.refType(nav_val.toType());
-        },
-        .union_type => done: {
-            const loaded_union = ip.loadUnionType(nav_val.toIntern());
-
-            const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
-                const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
-                break :parent .{
-                    parent_namespace_ptr.owner_type,
-                    if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
-                        DW.ACCESS.public
-                    else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
-                        DW.ACCESS.private
-                    else
-                        unreachable,
-                };
-            } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
-
-            decl_union: {
-                const type_inst_info = loaded_union.zir_index.resolveFull(ip).?;
-                if (type_inst_info.file != inst_info.file) break :decl_union;
-
-                const value_inst = value_inst: {
-                    const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
-                    const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
-                    if (break_inst.tag != .break_inline) break :value_inst null;
-                    assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
-                    var value_inst = break_inst.data.@"break".operand.toIndex();
-                    while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
-                        else => break,
-                        .as_node => value_inst = file.zir.extraData(
-                            Zir.Inst.As,
-                            file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
-                        ).data.operand.toIndex(),
-                    };
-                    break :value_inst value_inst;
-                };
-                if (type_inst_info.inst != value_inst) break :decl_union;
-
-                const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
-                if (type_gop.found_existing) {
-                    dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear();
-                    nav_gop.value_ptr.* = type_gop.value_ptr.*;
-                } else {
-                    if (nav_gop.found_existing)
-                        dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
-                    else
-                        nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
-                    type_gop.value_ptr.* = nav_gop.value_ptr.*;
-                }
-                wip_nav.entry = nav_gop.value_ptr.*;
-                const diw = wip_nav.debug_info.writer(dwarf.gpa);
-                try wip_nav.abbrevCode(.decl_union);
-                try wip_nav.refType(Type.fromInterned(parent_type));
-                assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
-                try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
-                try uleb128(diw, loc.column + 1);
-                try diw.writeByte(accessibility);
-                try wip_nav.strp(nav.name.toSlice(ip));
-                const union_layout = Type.getUnionLayout(loaded_union, zcu);
-                try uleb128(diw, union_layout.abi_size);
-                try uleb128(diw, union_layout.abi_align.toByteUnits().?);
-                const loaded_tag = loaded_union.loadTagType(ip);
-                if (loaded_union.hasTag(ip)) {
-                    try wip_nav.abbrevCode(.tagged_union);
-                    try wip_nav.infoSectionOffset(
-                        .debug_info,
-                        wip_nav.unit,
-                        wip_nav.entry,
-                        @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
-                    );
-                    {
-                        try wip_nav.abbrevCode(.generated_field);
-                        try wip_nav.strp("tag");
-                        try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty));
-                        try uleb128(diw, union_layout.tagOffset());
-
-                        for (0..loaded_union.field_types.len) |field_index| {
-                            try wip_nav.enumConstValue(loaded_tag, .{
-                                .sdata = .signed_tagged_union_field,
-                                .udata = .unsigned_tagged_union_field,
-                                .block = .big_tagged_union_field,
-                            }, field_index);
-                            {
-                                try wip_nav.abbrevCode(.struct_field);
-                                try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
-                                const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
-                                try wip_nav.refType(field_type);
-                                try uleb128(diw, union_layout.payloadOffset());
-                                try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
-                                    if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
-                            }
-                            try uleb128(diw, @intFromEnum(AbbrevCode.null));
+            const union_layout = Type.getUnionLayout(loaded_union, zcu);
+            try uleb128(diw, union_layout.abi_size);
+            try uleb128(diw, union_layout.abi_align.toByteUnits().?);
+            const loaded_tag = loaded_union.loadTagType(ip);
+            if (loaded_union.hasTag(ip)) {
+                try wip_nav.abbrevCode(.tagged_union);
+                try wip_nav.infoSectionOffset(
+                    .debug_info,
+                    wip_nav.unit,
+                    wip_nav.entry,
+                    @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
+                );
+                {
+                    try wip_nav.abbrevCode(.generated_field);
+                    try wip_nav.strp("tag");
+                    try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty));
+                    try uleb128(diw, union_layout.tagOffset());
+
+                    for (0..loaded_union.field_types.len) |field_index| {
+                        try wip_nav.enumConstValue(loaded_tag, .{
+                            .sdata = .signed_tagged_union_field,
+                            .udata = .unsigned_tagged_union_field,
+                            .block = .big_tagged_union_field,
+                        }, field_index);
+                        {
+                            try wip_nav.abbrevCode(.struct_field);
+                            try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
+                            const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
+                            try wip_nav.refType(field_type);
+                            try uleb128(diw, union_layout.payloadOffset());
+                            try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
+                                if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
                         }
+                        try uleb128(diw, @intFromEnum(AbbrevCode.null));
                     }
-                    try uleb128(diw, @intFromEnum(AbbrevCode.null));
-                } else for (0..loaded_union.field_types.len) |field_index| {
-                    try wip_nav.abbrevCode(.untagged_union_field);
-                    try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
-                    const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
-                    try wip_nav.refType(field_type);
-                    try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
-                        field_type.abiAlignment(zcu).toByteUnits().?);
                 }
                 try uleb128(diw, @intFromEnum(AbbrevCode.null));
-                break :done;
+            } else for (0..loaded_union.field_types.len) |field_index| {
+                try wip_nav.abbrevCode(.untagged_union_field);
+                try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
+                const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
+                try wip_nav.refType(field_type);
+                try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
+                    field_type.abiAlignment(zcu).toByteUnits().?);
             }
+            try uleb128(diw, @intFromEnum(AbbrevCode.null));
+            break :tag .done;
+        },
+        .opaque_type => tag: {
+            const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern());
 
-            if (nav_gop.found_existing)
-                dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
-            else
-                nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
+            const type_inst_info = loaded_opaque.zir_index.resolveFull(ip).?;
+            if (type_inst_info.file != inst_info.file) break :tag .decl_alias;
+
+            const value_inst = value_inst: {
+                const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
+                const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
+                if (break_inst.tag != .break_inline) break :value_inst null;
+                assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
+                var value_inst = break_inst.data.@"break".operand.toIndex();
+                while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
+                    else => break,
+                    .as_node => value_inst = file.zir.extraData(
+                        Zir.Inst.As,
+                        file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
+                    ).data.operand.toIndex(),
+                };
+                break :value_inst value_inst;
+            };
+            if (type_inst_info.inst != value_inst) break :tag .decl_alias;
+
+            const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
+            if (type_gop.found_existing) {
+                dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear();
+                nav_gop.value_ptr.* = type_gop.value_ptr.*;
+            } else {
+                if (nav_gop.found_existing)
+                    dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
+                else
+                    nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
+                type_gop.value_ptr.* = nav_gop.value_ptr.*;
+            }
             wip_nav.entry = nav_gop.value_ptr.*;
             const diw = wip_nav.debug_info.writer(dwarf.gpa);
-            try wip_nav.abbrevCode(.decl_alias);
+            try wip_nav.abbrevCode(.decl_namespace_struct);
             try wip_nav.refType(Type.fromInterned(parent_type));
             assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
             try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
             try uleb128(diw, loc.column + 1);
             try diw.writeByte(accessibility);
             try wip_nav.strp(nav.name.toSlice(ip));
-            try wip_nav.refType(nav_val.toType());
+            try diw.writeByte(@intFromBool(false));
+            break :tag .done;
         },
-        .opaque_type => done: {
-            const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern());
-
-            const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
-                const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
-                break :parent .{
-                    parent_namespace_ptr.owner_type,
-                    if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
-                        DW.ACCESS.public
-                    else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
-                        DW.ACCESS.private
-                    else
-                        unreachable,
-                };
-            } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
-
-            decl_opaque: {
-                const type_inst_info = loaded_opaque.zir_index.resolveFull(ip).?;
-                if (type_inst_info.file != inst_info.file) break :decl_opaque;
-
-                const value_inst = value_inst: {
-                    const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
-                    const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
-                    if (break_inst.tag != .break_inline) break :value_inst null;
-                    assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
-                    var value_inst = break_inst.data.@"break".operand.toIndex();
-                    while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
-                        else => break,
-                        .as_node => value_inst = file.zir.extraData(
-                            Zir.Inst.As,
-                            file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
-                        ).data.operand.toIndex(),
-                    };
-                    break :value_inst value_inst;
-                };
-                if (type_inst_info.inst != value_inst) break :decl_opaque;
+        .undef,
+        .simple_value,
+        .variable,
+        .@"extern",
+        .int,
+        .err,
+        .error_union,
+        .enum_literal,
+        .enum_tag,
+        .empty_enum_value,
+        .float,
+        .ptr,
+        .slice,
+        .opt,
+        .aggregate,
+        .un,
+        => {
+            _ = dwarf.navs.pop();
+            return;
+        },
+        .func => |func| tag: {
+            if (nav_gop.found_existing) {
+                const unit_ptr = dwarf.debug_info.section.getUnit(wip_nav.unit);
+                const entry_ptr = unit_ptr.getEntry(nav_gop.value_ptr.*);
+                if (entry_ptr.len >= AbbrevCode.decl_bytes) {
+                    var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined;
+                    if (try dwarf.getFile().?.preadAll(
+                        &abbrev_code_buf,
+                        dwarf.debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off,
+                    ) != abbrev_code_buf.len) return error.InputOutput;
+                    var abbrev_code_fbs = std.io.fixedBufferStream(&abbrev_code_buf);
+                    const abbrev_code: AbbrevCode = @enumFromInt(
+                        std.leb.readUleb128(@typeInfo(AbbrevCode).@"enum".tag_type, abbrev_code_fbs.reader()) catch unreachable,
+                    );
+                    switch (abbrev_code) {
+                        else => unreachable,
+                        .decl_func, .decl_empty_func => return,
+                        .decl_func_generic, .decl_empty_func_generic => {},
+                    }
+                }
+                entry_ptr.clear();
+            } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
+            wip_nav.entry = nav_gop.value_ptr.*;
 
-                const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
-                if (type_gop.found_existing) {
-                    dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear();
-                    nav_gop.value_ptr.* = type_gop.value_ptr.*;
-                } else {
-                    if (nav_gop.found_existing)
-                        dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
-                    else
-                        nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
-                    type_gop.value_ptr.* = nav_gop.value_ptr.*;
+            const func_type = ip.indexToKey(func.ty).func_type;
+            const diw = wip_nav.debug_info.writer(dwarf.gpa);
+            try wip_nav.abbrevCode(if (func_type.param_types.len > 0 or func_type.is_var_args)
+                .decl_func_generic
+            else
+                .decl_empty_func_generic);
+            try wip_nav.refType(Type.fromInterned(parent_type));
+            assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
+            try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
+            try uleb128(diw, loc.column + 1);
+            try diw.writeByte(accessibility);
+            try wip_nav.strp(nav.name.toSlice(ip));
+            try wip_nav.refType(Type.fromInterned(func_type.return_type));
+            if (func_type.param_types.len > 0 or func_type.is_var_args) {
+                for (0..func_type.param_types.len) |param_index| {
+                    try wip_nav.abbrevCode(.func_type_param);
+                    try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index]));
                 }
-                wip_nav.entry = nav_gop.value_ptr.*;
-                const diw = wip_nav.debug_info.writer(dwarf.gpa);
-                try wip_nav.abbrevCode(.decl_namespace_struct);
-                try wip_nav.refType(Type.fromInterned(parent_type));
-                assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
-                try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
-                try uleb128(diw, loc.column + 1);
-                try diw.writeByte(accessibility);
-                try wip_nav.strp(nav.name.toSlice(ip));
-                try diw.writeByte(@intFromBool(false));
-                break :done;
+                if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
+                try uleb128(diw, @intFromEnum(AbbrevCode.null));
             }
-
+            break :tag .done;
+        },
+        // memoization, not types
+        .memoized_call => unreachable,
+    };
+    switch (tag) {
+        .done => {},
+        .decl_alias => {
             if (nav_gop.found_existing)
                 dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
             else
@@ -3002,10 +2936,6 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
             try wip_nav.strp(nav.name.toSlice(ip));
             try wip_nav.refType(nav_val.toType());
         },
-        else => {
-            _ = dwarf.navs.pop();
-            return;
-        },
     }
     try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
     try wip_nav.flush();
@@ -3734,12 +3664,15 @@ fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) UpdateError!@typeInfo(A
 pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
     const zcu = pt.zcu;
     const ip = &zcu.intern_pool;
-    if (dwarf.types.get(.anyerror_type)) |entry| {
+
+    {
+        const type_gop = try dwarf.types.getOrPut(dwarf.gpa, .anyerror_type);
+        if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(.main);
         var wip_nav: WipNav = .{
             .dwarf = dwarf,
             .pt = pt,
             .unit = .main,
-            .entry = entry,
+            .entry = type_gop.value_ptr.*,
             .any_children = false,
             .func = .none,
             .func_sym_index = undefined,
test/src/Debugger.zig
@@ -411,10 +411,27 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
         },
         \\breakpoint set --file enums.zig --source-pattern-regexp '_ = enums;'
         \\process launch
+        \\expression --show-types -- Enums
         \\frame variable --show-types enums
         \\breakpoint delete --force 1
     ,
         &.{
+            \\(lldb) expression --show-types -- Enums
+            \\(type) Enums = struct {
+            \\  (type) Zero = enum {}
+            \\  (type) One = enum {
+            \\    (root.enums.Enums.One) first = .first
+            \\  }
+            \\  (type) Two = enum {
+            \\    (root.enums.Enums.Two) first = .first
+            \\    (root.enums.Enums.Two) second = .second
+            \\  }
+            \\  (type) Three = enum {
+            \\    (root.enums.Enums.Three) first = .first
+            \\    (root.enums.Enums.Three) second = .second
+            \\    (root.enums.Enums.Three) third = .third
+            \\  }
+            \\}
             \\(lldb) frame variable --show-types enums
             \\(root.enums.Enums) enums = {
             \\  (root.enums.Enums.Zero) zero = @enumFromInt(13)
@@ -434,12 +451,17 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
                 .path = "errors.zig",
                 .source =
                 \\const Errors = struct {
-                \\    one: error{One} = error.One,
-                \\    two: error{One,Two} = error.Two,
-                \\    three: error{One,Two,Three} = error.Three,
+                \\    const Zero = error{};
+                \\    const One = Zero || error{One};
+                \\    const Two = One || error{Two};
+                \\    const Three = Two || error{Three};
+                \\
+                \\    one: One = error.One,
+                \\    two: Two = error.Two,
+                \\    three: Three = error.Three,
                 \\    any: anyerror = error.Any,
                 \\    any_void: anyerror!void = error.NotVoid,
-                \\    any_u32: error{One}!u32 = 42,
+                \\    any_u32: One!u32 = 42,
                 \\};
                 \\fn testErrors(errors: Errors) void {
                 \\    _ = errors;
@@ -453,10 +475,27 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
         },
         \\breakpoint set --file errors.zig --source-pattern-regexp '_ = errors;'
         \\process launch
+        \\expression --show-types -- Errors
         \\frame variable --show-types errors
         \\breakpoint delete --force 1
     ,
         &.{
+            \\(lldb) expression --show-types -- Errors
+            \\(type) Errors = struct {
+            \\  (type) Zero = error {}
+            \\  (type) One = error {
+            \\    (error{One}) One = error.One
+            \\  }
+            \\  (type) Two = error {
+            \\    (error{One,Two}) One = error.One
+            \\    (error{One,Two}) Two = error.Two
+            \\  }
+            \\  (type) Three = error {
+            \\    (error{One,Two,Three}) One = error.One
+            \\    (error{One,Two,Three}) Two = error.Two
+            \\    (error{One,Two,Three}) Three = error.Three
+            \\  }
+            \\}
             \\(lldb) frame variable --show-types errors
             \\(root.errors.Errors) errors = {
             \\  (error{One}) one = error.One
@@ -565,10 +604,30 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
         },
         \\breakpoint set --file unions.zig --source-pattern-regexp '_ = unions;'
         \\process launch
+        \\expression --show-types -- Unions
         \\frame variable --show-types unions
         \\breakpoint delete --force 1
     ,
         &.{
+            \\(lldb) expression --show-types -- Unions
+            \\(type) Unions = struct {
+            \\  (type) Untagged = union {}
+            \\  (type) SafetyTagged = union(enum) {
+            \\    (@typeInfo(unions.Unions.SafetyTagged).@"union".tag_type.?) void = .void
+            \\    (@typeInfo(unions.Unions.SafetyTagged).@"union".tag_type.?) en = .en
+            \\    (@typeInfo(unions.Unions.SafetyTagged).@"union".tag_type.?) eu = .eu
+            \\  }
+            \\  (type) Enum = enum {
+            \\    (root.unions.Unions.Enum) first = .first
+            \\    (root.unions.Unions.Enum) second = .second
+            \\    (root.unions.Unions.Enum) third = .third
+            \\  }
+            \\  (type) Tagged = union(enum) {
+            \\    (@typeInfo(unions.Unions.Tagged).@"union".tag_type.?) void = .void
+            \\    (@typeInfo(unions.Unions.Tagged).@"union".tag_type.?) en = .en
+            \\    (@typeInfo(unions.Unions.Tagged).@"union".tag_type.?) eu = .eu
+            \\  }
+            \\}
             \\(lldb) frame variable --show-types unions
             \\(root.unions.Unions) unions = {
             \\  (root.unions.Unions.Untagged) untagged = {