Commit a61def10c6

mlugg <mlugg@mlugg.co.uk>
2024-03-26 06:38:32
compiler: eliminate most usages of TypedValue
1 parent b8d114a
src/arch/aarch64/CodeGen.zig
@@ -10,7 +10,6 @@ const Emit = @import("Emit.zig");
 const Liveness = @import("../../Liveness.zig");
 const Type = @import("../../type.zig").Type;
 const Value = @import("../../Value.zig");
-const TypedValue = @import("../../TypedValue.zig");
 const link = @import("../../link.zig");
 const Module = @import("../../Module.zig");
 const InternPool = @import("../../InternPool.zig");
@@ -6143,10 +6142,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
     if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod) and !inst_ty.isError(mod))
         return MCValue{ .none = {} };
 
-    const inst_index = inst.toIndex() orelse return self.genTypedValue(.{
-        .ty = inst_ty,
-        .val = (try self.air.value(inst, mod)).?,
-    });
+    const inst_index = inst.toIndex() orelse return self.genTypedValue((try self.air.value(inst, mod)).?);
 
     return self.getResolvedInstValue(inst_index);
 }
@@ -6163,11 +6159,11 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
     }
 }
 
-fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
+fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
     const mcv: MCValue = switch (try codegen.genTypedValue(
         self.bin_file,
         self.src_loc,
-        arg_tv,
+        val,
         self.owner_decl,
     )) {
         .mcv => |mcv| switch (mcv) {
src/arch/arm/CodeGen.zig
@@ -10,7 +10,6 @@ const Emit = @import("Emit.zig");
 const Liveness = @import("../../Liveness.zig");
 const Type = @import("../../type.zig").Type;
 const Value = @import("../../Value.zig");
-const TypedValue = @import("../../TypedValue.zig");
 const link = @import("../../link.zig");
 const Module = @import("../../Module.zig");
 const InternPool = @import("../../InternPool.zig");
@@ -6097,10 +6096,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
     if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod) and !inst_ty.isError(mod))
         return MCValue{ .none = {} };
 
-    const inst_index = inst.toIndex() orelse return self.genTypedValue(.{
-        .ty = inst_ty,
-        .val = (try self.air.value(inst, mod)).?,
-    });
+    const inst_index = inst.toIndex() orelse return self.genTypedValue((try self.air.value(inst, mod)).?);
 
     return self.getResolvedInstValue(inst_index);
 }
@@ -6117,12 +6113,12 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
     }
 }
 
-fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
+fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
     const mod = self.bin_file.comp.module.?;
     const mcv: MCValue = switch (try codegen.genTypedValue(
         self.bin_file,
         self.src_loc,
-        arg_tv,
+        val,
         mod.funcOwnerDeclIndex(self.func_index),
     )) {
         .mcv => |mcv| switch (mcv) {
src/arch/riscv64/CodeGen.zig
@@ -9,7 +9,6 @@ const Emit = @import("Emit.zig");
 const Liveness = @import("../../Liveness.zig");
 const Type = @import("../../type.zig").Type;
 const Value = @import("../../Value.zig");
-const TypedValue = @import("../../TypedValue.zig");
 const link = @import("../../link.zig");
 const Module = @import("../../Module.zig");
 const InternPool = @import("../../InternPool.zig");
@@ -2552,10 +2551,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
     if (!inst_ty.hasRuntimeBits(mod))
         return MCValue{ .none = {} };
 
-    const inst_index = inst.toIndex() orelse return self.genTypedValue(.{
-        .ty = inst_ty,
-        .val = (try self.air.value(inst, mod)).?,
-    });
+    const inst_index = inst.toIndex() orelse return self.genTypedValue((try self.air.value(inst, mod)).?);
 
     return self.getResolvedInstValue(inst_index);
 }
@@ -2572,12 +2568,12 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
     }
 }
 
-fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
+fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
     const mod = self.bin_file.comp.module.?;
     const mcv: MCValue = switch (try codegen.genTypedValue(
         self.bin_file,
         self.src_loc,
-        typed_value,
+        val,
         mod.funcOwnerDeclIndex(self.func_index),
     )) {
         .mcv => |mcv| switch (mcv) {
src/arch/sparc64/CodeGen.zig
@@ -12,7 +12,7 @@ const builtin = @import("builtin");
 const link = @import("../../link.zig");
 const Module = @import("../../Module.zig");
 const InternPool = @import("../../InternPool.zig");
-const TypedValue = @import("../../TypedValue.zig");
+const Value = @import("../../Value.zig");
 const ErrorMsg = Module.ErrorMsg;
 const codegen = @import("../../codegen.zig");
 const Air = @import("../../Air.zig");
@@ -4118,12 +4118,12 @@ fn genStoreASI(self: *Self, value_reg: Register, addr_reg: Register, off_reg: Re
     }
 }
 
-fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
+fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
     const mod = self.bin_file.comp.module.?;
     const mcv: MCValue = switch (try codegen.genTypedValue(
         self.bin_file,
         self.src_loc,
-        typed_value,
+        val,
         mod.funcOwnerDeclIndex(self.func_index),
     )) {
         .mcv => |mcv| switch (mcv) {
@@ -4546,10 +4546,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
         return self.getResolvedInstValue(inst);
     }
 
-    return self.genTypedValue(.{
-        .ty = ty,
-        .val = (try self.air.value(ref, mod)).?,
-    });
+    return self.genTypedValue((try self.air.value(ref, mod)).?);
 }
 
 fn ret(self: *Self, mcv: MCValue) !void {
src/arch/wasm/CodeGen.zig
@@ -18,7 +18,6 @@ const Value = @import("../../Value.zig");
 const Compilation = @import("../../Compilation.zig");
 const LazySrcLoc = std.zig.LazySrcLoc;
 const link = @import("../../link.zig");
-const TypedValue = @import("../../TypedValue.zig");
 const Air = @import("../../Air.zig");
 const Liveness = @import("../../Liveness.zig");
 const target_util = @import("../../target.zig");
@@ -805,7 +804,7 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
     // In the other cases, we will simply lower the constant to a value that fits
     // into a single local (such as a pointer, integer, bool, etc).
     const result = if (isByRef(ty, mod)) blk: {
-        const sym_index = try func.bin_file.lowerUnnamedConst(.{ .ty = ty, .val = val }, func.decl_index);
+        const sym_index = try func.bin_file.lowerUnnamedConst(val, func.decl_index);
         break :blk WValue{ .memory = sym_index };
     } else try func.lowerConstant(val, ty);
 
@@ -3119,10 +3118,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue
 }
 
 fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: InternPool.DeclIndex, offset: u32) InnerError!WValue {
-    const mod = func.bin_file.base.comp.module.?;
-    const decl = mod.declPtr(decl_index);
-    const ptr_ty = try mod.singleMutPtrType(decl.typeOf(mod));
-    return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset);
+    return func.lowerDeclRefValue(ptr_val, decl_index, offset);
 }
 
 fn lowerAnonDeclRef(
@@ -3157,7 +3153,7 @@ fn lowerAnonDeclRef(
     } else return WValue{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } };
 }
 
-fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: InternPool.DeclIndex, offset: u32) InnerError!WValue {
+fn lowerDeclRefValue(func: *CodeGen, val: Value, decl_index: InternPool.DeclIndex, offset: u32) InnerError!WValue {
     const mod = func.bin_file.base.comp.module.?;
 
     const decl = mod.declPtr(decl_index);
@@ -3165,11 +3161,11 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: InternPool.Decl
     // want to lower the actual decl, rather than the alias itself.
     if (decl.val.getFunction(mod)) |func_val| {
         if (func_val.owner_decl != decl_index) {
-            return func.lowerDeclRefValue(tv, func_val.owner_decl, offset);
+            return func.lowerDeclRefValue(val, func_val.owner_decl, offset);
         }
     } else if (decl.val.getExternFunc(mod)) |func_val| {
         if (func_val.decl != decl_index) {
-            return func.lowerDeclRefValue(tv, func_val.decl, offset);
+            return func.lowerDeclRefValue(val, func_val.decl, offset);
         }
     }
     const decl_ty = decl.typeOf(mod);
@@ -3280,23 +3276,23 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
         },
         .error_union => |error_union| {
             const err_int_ty = try mod.errorIntType();
-            const err_tv: TypedValue = switch (error_union.val) {
+            const err_ty, const err_val = switch (error_union.val) {
                 .err_name => |err_name| .{
-                    .ty = ty.errorUnionSet(mod),
-                    .val = Value.fromInterned((try mod.intern(.{ .err = .{
+                    ty.errorUnionSet(mod),
+                    Value.fromInterned((try mod.intern(.{ .err = .{
                         .ty = ty.errorUnionSet(mod).toIntern(),
                         .name = err_name,
                     } }))),
                 },
                 .payload => .{
-                    .ty = err_int_ty,
-                    .val = try mod.intValue(err_int_ty, 0),
+                    err_int_ty,
+                    try mod.intValue(err_int_ty, 0),
                 },
             };
             const payload_type = ty.errorUnionPayload(mod);
             if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) {
                 // We use the error type directly as the type.
-                return func.lowerConstant(err_tv.val, err_tv.ty);
+                return func.lowerConstant(err_val, err_ty);
             }
 
             return func.fail("Wasm TODO: lowerConstant error union with non-zero-bit payload type", .{});
@@ -3320,10 +3316,10 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
                 .elem, .field => |base_index| ptr = ip.indexToKey(base_index.base).ptr,
                 .comptime_field, .comptime_alloc => unreachable,
             };
-            return .{ .memory = try func.bin_file.lowerUnnamedConst(.{ .ty = ty, .val = val }, owner_decl) };
+            return .{ .memory = try func.bin_file.lowerUnnamedConst(val, owner_decl) };
         },
         .ptr => |ptr| switch (ptr.addr) {
-            .decl => |decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl, 0),
+            .decl => |decl| return func.lowerDeclRefValue(val, decl, 0),
             .int => |int| return func.lowerConstant(Value.fromInterned(int), Type.fromInterned(ip.typeOf(int))),
             .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0),
             .anon_decl => |ad| return func.lowerAnonDeclRef(ad, 0),
@@ -7285,7 +7281,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
             .storage = .{ .bytes = tag_name },
         } });
         const tag_sym_index = try func.bin_file.lowerUnnamedConst(
-            .{ .ty = name_ty, .val = Value.fromInterned(name_val) },
+            Value.fromInterned(name_val),
             enum_decl_index,
         );
 
src/arch/x86_64/CodeGen.zig
@@ -32,7 +32,6 @@ const InternPool = @import("../../InternPool.zig");
 const Alignment = InternPool.Alignment;
 const Target = std.Target;
 const Type = @import("../../type.zig").Type;
-const TypedValue = @import("../../TypedValue.zig");
 const Value = @import("../../Value.zig");
 const Instruction = @import("encoder.zig").Instruction;
 
@@ -2250,7 +2249,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
             for (exitlude_jump_relocs, 0..) |*exitlude_jump_reloc, tag_index| {
                 const tag_name_len = ip.stringToSlice(tag_names.get(ip)[tag_index]).len;
                 const tag_val = try mod.enumValueFieldIndex(enum_ty, @intCast(tag_index));
-                const tag_mcv = try self.genTypedValue(.{ .ty = enum_ty, .val = tag_val });
+                const tag_mcv = try self.genTypedValue(tag_val);
                 try self.genBinOpMir(.{ ._, .cmp }, enum_ty, enum_mcv, tag_mcv);
                 const skip_reloc = try self.asmJccReloc(.ne, undefined);
 
@@ -3323,7 +3322,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
                 .storage = .{ .repeated_elem = mask_val.ip_index },
             } });
 
-            const splat_mcv = try self.genTypedValue(.{ .ty = splat_ty, .val = Value.fromInterned(splat_val) });
+            const splat_mcv = try self.genTypedValue(Value.fromInterned(splat_val));
             const splat_addr_mcv: MCValue = switch (splat_mcv) {
                 .memory, .indirect, .load_frame => splat_mcv.address(),
                 else => .{ .register = try self.copyToTmpRegister(Type.usize, splat_mcv.address()) },
@@ -4992,17 +4991,14 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void {
                         defer self.register_manager.unlockReg(shift_lock);
 
                         const mask_ty = try mod.vectorType(.{ .len = 16, .child = .u8_type });
-                        const mask_mcv = try self.genTypedValue(.{
-                            .ty = mask_ty,
-                            .val = Value.fromInterned((try mod.intern(.{ .aggregate = .{
-                                .ty = mask_ty.toIntern(),
-                                .storage = .{ .elems = &([1]InternPool.Index{
-                                    (try rhs_ty.childType(mod).maxIntScalar(mod, Type.u8)).toIntern(),
-                                } ++ [1]InternPool.Index{
-                                    (try mod.intValue(Type.u8, 0)).toIntern(),
-                                } ** 15) },
-                            } }))),
-                        });
+                        const mask_mcv = try self.genTypedValue(Value.fromInterned(try mod.intern(.{ .aggregate = .{
+                            .ty = mask_ty.toIntern(),
+                            .storage = .{ .elems = &([1]InternPool.Index{
+                                (try rhs_ty.childType(mod).maxIntScalar(mod, Type.u8)).toIntern(),
+                            } ++ [1]InternPool.Index{
+                                (try mod.intValue(Type.u8, 0)).toIntern(),
+                            } ** 15) },
+                        } })));
                         const mask_addr_reg =
                             try self.copyToTmpRegister(Type.usize, mask_mcv.address());
                         const mask_addr_lock = self.register_manager.lockRegAssumeUnused(mask_addr_reg);
@@ -6860,11 +6856,11 @@ fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type)
             .child = (try mod.intType(.signed, scalar_bits)).ip_index,
         });
 
-        const sign_mcv = try self.genTypedValue(.{ .ty = vec_ty, .val = switch (tag) {
+        const sign_mcv = try self.genTypedValue(switch (tag) {
             .neg => try vec_ty.minInt(mod, vec_ty),
             .abs => try vec_ty.maxInt(mod, vec_ty),
             else => unreachable,
-        } });
+        });
         const sign_mem: Memory = if (sign_mcv.isMemory())
             try sign_mcv.mem(self, Memory.Size.fromSize(abi_size))
         else
@@ -11130,10 +11126,7 @@ fn genBinOp(
                     .cmp_neq,
                     => {
                         const unsigned_ty = try lhs_ty.toUnsigned(mod);
-                        const not_mcv = try self.genTypedValue(.{
-                            .ty = lhs_ty,
-                            .val = try unsigned_ty.maxInt(mod, unsigned_ty),
-                        });
+                        const not_mcv = try self.genTypedValue(try unsigned_ty.maxInt(mod, unsigned_ty));
                         const not_mem: Memory = if (not_mcv.isMemory())
                             try not_mcv.mem(self, Memory.Size.fromSize(abi_size))
                         else
@@ -14692,10 +14685,7 @@ fn genSetReg(
                 ),
                 else => unreachable,
             },
-            .segment, .x87, .mmx, .sse => try self.genSetReg(dst_reg, ty, try self.genTypedValue(.{
-                .ty = ty,
-                .val = try mod.undefValue(ty),
-            }), opts),
+            .segment, .x87, .mmx, .sse => try self.genSetReg(dst_reg, ty, try self.genTypedValue(try mod.undefValue(ty)), opts),
         },
         .eflags => |cc| try self.asmSetccRegister(cc, dst_reg.to8()),
         .immediate => |imm| {
@@ -16893,13 +16883,10 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void {
                     .ty = mask_elem_ty.toIntern(),
                     .storage = .{ .u64 = bit / elem_bits },
                 } });
-                const mask_mcv = try self.genTypedValue(.{
-                    .ty = mask_ty,
-                    .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{
-                        .ty = mask_ty.toIntern(),
-                        .storage = .{ .elems = mask_elems[0..vec_len] },
-                    } })),
-                });
+                const mask_mcv = try self.genTypedValue(Value.fromInterned(try mod.intern(.{ .aggregate = .{
+                    .ty = mask_ty.toIntern(),
+                    .storage = .{ .elems = mask_elems[0..vec_len] },
+                } })));
                 const mask_mem: Memory = .{
                     .base = .{ .reg = try self.copyToTmpRegister(Type.usize, mask_mcv.address()) },
                     .mod = .{ .rm = .{ .size = self.memSize(ty) } },
@@ -16921,13 +16908,10 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void {
                     .ty = mask_elem_ty.toIntern(),
                     .storage = .{ .u64 = @as(u32, 1) << @intCast(bit & (elem_bits - 1)) },
                 } });
-                const mask_mcv = try self.genTypedValue(.{
-                    .ty = mask_ty,
-                    .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{
-                        .ty = mask_ty.toIntern(),
-                        .storage = .{ .elems = mask_elems[0..vec_len] },
-                    } })),
-                });
+                const mask_mcv = try self.genTypedValue(Value.fromInterned(try mod.intern(.{ .aggregate = .{
+                    .ty = mask_ty.toIntern(),
+                    .storage = .{ .elems = mask_elems[0..vec_len] },
+                } })));
                 const mask_mem: Memory = .{
                     .base = .{ .reg = try self.copyToTmpRegister(Type.usize, mask_mcv.address()) },
                     .mod = .{ .rm = .{ .size = self.memSize(ty) } },
@@ -17658,13 +17642,10 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
                 else
                     try select_mask_elem_ty.minIntScalar(mod, select_mask_elem_ty)).toIntern();
             }
-            const select_mask_mcv = try self.genTypedValue(.{
-                .ty = select_mask_ty,
-                .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{
-                    .ty = select_mask_ty.toIntern(),
-                    .storage = .{ .elems = select_mask_elems[0..mask_elems.len] },
-                } })),
-            });
+            const select_mask_mcv = try self.genTypedValue(Value.fromInterned(try mod.intern(.{ .aggregate = .{
+                .ty = select_mask_ty.toIntern(),
+                .storage = .{ .elems = select_mask_elems[0..mask_elems.len] },
+            } })));
 
             if (self.hasFeature(.sse4_1)) {
                 const mir_tag: Mir.Inst.FixedTag = .{
@@ -17809,13 +17790,10 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
                 } });
             }
             const lhs_mask_ty = try mod.vectorType(.{ .len = max_abi_size, .child = .u8_type });
-            const lhs_mask_mcv = try self.genTypedValue(.{
-                .ty = lhs_mask_ty,
-                .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{
-                    .ty = lhs_mask_ty.toIntern(),
-                    .storage = .{ .elems = lhs_mask_elems[0..max_abi_size] },
-                } })),
-            });
+            const lhs_mask_mcv = try self.genTypedValue(Value.fromInterned(try mod.intern(.{ .aggregate = .{
+                .ty = lhs_mask_ty.toIntern(),
+                .storage = .{ .elems = lhs_mask_elems[0..max_abi_size] },
+            } })));
             const lhs_mask_mem: Memory = .{
                 .base = .{ .reg = try self.copyToTmpRegister(Type.usize, lhs_mask_mcv.address()) },
                 .mod = .{ .rm = .{ .size = Memory.Size.fromSize(@max(max_abi_size, 16)) } },
@@ -17846,13 +17824,10 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
                 } });
             }
             const rhs_mask_ty = try mod.vectorType(.{ .len = max_abi_size, .child = .u8_type });
-            const rhs_mask_mcv = try self.genTypedValue(.{
-                .ty = rhs_mask_ty,
-                .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{
-                    .ty = rhs_mask_ty.toIntern(),
-                    .storage = .{ .elems = rhs_mask_elems[0..max_abi_size] },
-                } })),
-            });
+            const rhs_mask_mcv = try self.genTypedValue(Value.fromInterned(try mod.intern(.{ .aggregate = .{
+                .ty = rhs_mask_ty.toIntern(),
+                .storage = .{ .elems = rhs_mask_elems[0..max_abi_size] },
+            } })));
             const rhs_mask_mem: Memory = .{
                 .base = .{ .reg = try self.copyToTmpRegister(Type.usize, rhs_mask_mcv.address()) },
                 .mod = .{ .rm = .{ .size = Memory.Size.fromSize(@max(max_abi_size, 16)) } },
@@ -18138,7 +18113,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
                         .{ .frame = frame_index },
                         @intCast(elem_size * elements.len),
                         elem_ty,
-                        try self.genTypedValue(.{ .ty = elem_ty, .val = sentinel }),
+                        try self.genTypedValue(sentinel),
                         .{},
                     );
                     break :result .{ .load_frame = .{ .index = frame_index } };
@@ -18662,7 +18637,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
         const ip_index = ref.toInterned().?;
         const gop = try self.const_tracking.getOrPut(self.gpa, ip_index);
         if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(init: {
-            const const_mcv = try self.genTypedValue(.{ .ty = ty, .val = Value.fromInterned(ip_index) });
+            const const_mcv = try self.genTypedValue(Value.fromInterned(ip_index));
             switch (const_mcv) {
                 .lea_tlv => |tlv_sym| switch (self.bin_file.tag) {
                     .elf, .macho => {
@@ -18727,9 +18702,9 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
     return mcv;
 }
 
-fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
+fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
     const mod = self.bin_file.comp.module.?;
-    return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getDecl(mod))) {
+    return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, val, self.owner.getDecl(mod))) {
         .mcv => |mcv| switch (mcv) {
             .none => .none,
             .undef => .undef,
src/codegen/c.zig
@@ -9,7 +9,6 @@ const Module = @import("../Module.zig");
 const Compilation = @import("../Compilation.zig");
 const Value = @import("../Value.zig");
 const Type = @import("../type.zig").Type;
-const TypedValue = @import("../TypedValue.zig");
 const C = link.File.C;
 const Decl = Module.Decl;
 const trace = @import("../tracy.zig").trace;
@@ -1877,9 +1876,9 @@ pub const DeclGen = struct {
         try renderTypeSuffix(dg.pass, store.*, mod, w, cty_idx, .suffix, .{});
     }
 
-    fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {
+    fn declIsGlobal(dg: *DeclGen, val: Value) bool {
         const mod = dg.module;
-        return switch (mod.intern_pool.indexToKey(tv.val.ip_index)) {
+        return switch (mod.intern_pool.indexToKey(val.ip_index)) {
             .variable => |variable| mod.decl_exports.contains(variable.decl),
             .extern_func => true,
             .func => |func| mod.decl_exports.contains(func.owner_decl),
@@ -1972,7 +1971,7 @@ pub const DeclGen = struct {
     ) !void {
         const decl = dg.module.declPtr(decl_index);
         const fwd = dg.fwdDeclWriter();
-        const is_global = variable.is_extern or dg.declIsGlobal(.{ .ty = decl.typeOf(dg.module), .val = decl.val });
+        const is_global = variable.is_extern or dg.declIsGlobal(decl.val);
         try fwd.writeAll(if (is_global) "zig_extern " else "static ");
         const maybe_exports = dg.module.decl_exports.get(decl_index);
         const export_weak_linkage = if (maybe_exports) |exports|
@@ -2656,13 +2655,12 @@ fn genExports(o: *Object) !void {
         .anon, .flush => return,
     };
     const decl = mod.declPtr(decl_index);
-    const tv: TypedValue = .{ .ty = decl.typeOf(mod), .val = decl.val };
     const fwd = o.dg.fwdDeclWriter();
 
     const exports = mod.decl_exports.get(decl_index) orelse return;
     if (exports.items.len < 2) return;
 
-    const is_variable_const = switch (ip.indexToKey(tv.val.toIntern())) {
+    const is_variable_const = switch (ip.indexToKey(decl.val.toIntern())) {
         .func => return for (exports.items[1..], 1..) |@"export", i| {
             try fwd.writeAll("zig_extern ");
             if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage_fn ");
@@ -2805,15 +2803,11 @@ pub fn genFunc(f: *Function) !void {
     const gpa = o.dg.gpa;
     const decl_index = o.dg.pass.decl;
     const decl = mod.declPtr(decl_index);
-    const tv: TypedValue = .{
-        .ty = decl.typeOf(mod),
-        .val = decl.val,
-    };
 
     o.code_header = std.ArrayList(u8).init(gpa);
     defer o.code_header.deinit();
 
-    const is_global = o.dg.declIsGlobal(tv);
+    const is_global = o.dg.declIsGlobal(decl.val);
     const fwd_decl_writer = o.dg.fwdDeclWriter();
     try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
 
@@ -2893,22 +2887,23 @@ pub fn genDecl(o: *Object) !void {
     const mod = o.dg.module;
     const decl_index = o.dg.pass.decl;
     const decl = mod.declPtr(decl_index);
-    const tv: TypedValue = .{ .ty = decl.typeOf(mod), .val = decl.val };
+    const decl_val = decl.val;
+    const decl_ty = decl_val.typeOf(mod);
 
-    if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return;
-    if (tv.val.getExternFunc(mod)) |_| {
+    if (!decl_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return;
+    if (decl_val.getExternFunc(mod)) |_| {
         const fwd_decl_writer = o.dg.fwdDeclWriter();
         try fwd_decl_writer.writeAll("zig_extern ");
         try o.dg.renderFunctionSignature(fwd_decl_writer, decl_index, .forward, .{ .export_index = 0 });
         try fwd_decl_writer.writeAll(";\n");
         try genExports(o);
-    } else if (tv.val.getVariable(mod)) |variable| {
+    } else if (decl_val.getVariable(mod)) |variable| {
         try o.dg.renderFwdDecl(decl_index, variable, .final);
         try genExports(o);
 
         if (variable.is_extern) return;
 
-        const is_global = variable.is_extern or o.dg.declIsGlobal(tv);
+        const is_global = variable.is_extern or o.dg.declIsGlobal(decl_val);
         const w = o.writer();
         if (!is_global) try w.writeAll("static ");
         if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
@@ -2916,22 +2911,22 @@ pub fn genDecl(o: *Object) !void {
         if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|
             try w.print("zig_linksection(\"{s}\", ", .{s});
         const decl_c_value = .{ .decl = decl_index };
-        try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.alignment, .complete);
+        try o.dg.renderTypeAndName(w, decl_ty, decl_c_value, .{}, decl.alignment, .complete);
         if (decl.@"linksection" != .none) try w.writeAll(", read, write)");
         try w.writeAll(" = ");
-        try o.dg.renderValue(w, tv.ty, Value.fromInterned(variable.init), .StaticInitializer);
+        try o.dg.renderValue(w, decl_ty, Value.fromInterned(variable.init), .StaticInitializer);
         try w.writeByte(';');
         try o.indent_writer.insertNewline();
     } else {
         const is_global = o.dg.module.decl_exports.contains(decl_index);
         const decl_c_value = .{ .decl = decl_index };
-        try genDeclValue(o, tv, is_global, decl_c_value, decl.alignment, decl.@"linksection");
+        try genDeclValue(o, decl_val, is_global, decl_c_value, decl.alignment, decl.@"linksection");
     }
 }
 
 pub fn genDeclValue(
     o: *Object,
-    tv: TypedValue,
+    val: Value,
     is_global: bool,
     decl_c_value: CValue,
     alignment: Alignment,
@@ -2940,8 +2935,10 @@ pub fn genDeclValue(
     const mod = o.dg.module;
     const fwd_decl_writer = o.dg.fwdDeclWriter();
 
+    const ty = val.typeOf(mod);
+
     try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
-    try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, alignment, .complete);
+    try o.dg.renderTypeAndName(fwd_decl_writer, ty, decl_c_value, Const, alignment, .complete);
     switch (o.dg.pass) {
         .decl => |decl_index| {
             if (mod.decl_exports.get(decl_index)) |exports| {
@@ -2964,10 +2961,10 @@ pub fn genDeclValue(
 
     if (mod.intern_pool.stringToSliceUnwrap(link_section)) |s|
         try w.print("zig_linksection(\"{s}\", ", .{s});
-    try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, alignment, .complete);
+    try o.dg.renderTypeAndName(w, ty, decl_c_value, Const, alignment, .complete);
     if (link_section != .none) try w.writeAll(", read)");
     try w.writeAll(" = ");
-    try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);
+    try o.dg.renderValue(w, ty, val, .StaticInitializer);
     try w.writeAll(";\n");
 }
 
@@ -2978,14 +2975,10 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
     const mod = dg.module;
     const decl_index = dg.pass.decl;
     const decl = mod.declPtr(decl_index);
-    const tv: TypedValue = .{
-        .ty = decl.typeOf(mod),
-        .val = decl.val,
-    };
     const writer = dg.fwdDeclWriter();
 
-    switch (tv.ty.zigTypeTag(mod)) {
-        .Fn => if (dg.declIsGlobal(tv)) {
+    switch (decl.val.typeOf(mod).zigTypeTag(mod)) {
+        .Fn => if (dg.declIsGlobal(decl.val)) {
             try writer.writeAll("zig_extern ");
             try dg.renderFunctionSignature(writer, dg.pass.decl, .complete, .{ .export_index = 0 });
             try dg.fwd_decl.appendSlice(";\n");
@@ -5304,25 +5297,25 @@ fn airIsNull(
     const err_int_ty = try mod.errorIntType();
 
     const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod))
-        TypedValue{ .ty = Type.bool, .val = Value.true }
+        Value.true
     else if (optional_ty.isPtrLikeOptional(mod))
         // operand is a regular pointer, test `operand !=/== NULL`
-        TypedValue{ .ty = optional_ty, .val = try mod.getCoerced(Value.null, optional_ty) }
+        try mod.getCoerced(Value.null, optional_ty)
     else if (payload_ty.zigTypeTag(mod) == .ErrorSet)
-        TypedValue{ .ty = err_int_ty, .val = try mod.intValue(err_int_ty, 0) }
+        try mod.intValue(err_int_ty, 0)
     else if (payload_ty.isSlice(mod) and optional_ty.optionalReprIsPayload(mod)) rhs: {
         try writer.writeAll(".ptr");
         const slice_ptr_ty = payload_ty.slicePtrFieldType(mod);
         const opt_slice_ptr_ty = try mod.optionalType(slice_ptr_ty.toIntern());
-        break :rhs TypedValue{ .ty = opt_slice_ptr_ty, .val = try mod.nullValue(opt_slice_ptr_ty) };
+        break :rhs try mod.nullValue(opt_slice_ptr_ty);
     } else rhs: {
         try writer.writeAll(".is_null");
-        break :rhs TypedValue{ .ty = Type.bool, .val = Value.true };
+        break :rhs Value.true;
     };
     try writer.writeByte(' ');
     try writer.writeAll(operator);
     try writer.writeByte(' ');
-    try f.object.dg.renderValue(writer, rhs.ty, rhs.val, .Other);
+    try f.object.dg.renderValue(writer, rhs.typeOf(mod), rhs, .Other);
     try writer.writeAll(";\n");
     return local;
 }
src/codegen/llvm.zig
@@ -18,7 +18,6 @@ const Module = @import("../Module.zig");
 const Zcu = Module;
 const InternPool = @import("../InternPool.zig");
 const Package = @import("../Package.zig");
-const TypedValue = @import("../TypedValue.zig");
 const Air = @import("../Air.zig");
 const Liveness = @import("../Liveness.zig");
 const Value = @import("../Value.zig");
@@ -4823,19 +4822,17 @@ pub const FuncGen = struct {
 
         const o = self.dg.object;
         const mod = o.module;
-        const llvm_val = try self.resolveValue(.{
-            .ty = self.typeOf(inst),
-            .val = (try self.air.value(inst, mod)).?,
-        });
+        const llvm_val = try self.resolveValue((try self.air.value(inst, mod)).?);
         gop.value_ptr.* = llvm_val.toValue();
         return llvm_val.toValue();
     }
 
-    fn resolveValue(self: *FuncGen, tv: TypedValue) Error!Builder.Constant {
+    fn resolveValue(self: *FuncGen, val: Value) Error!Builder.Constant {
         const o = self.dg.object;
         const mod = o.module;
-        const llvm_val = try o.lowerValue(tv.val.toIntern());
-        if (!isByRef(tv.ty, mod)) return llvm_val;
+        const ty = val.typeOf(mod);
+        const llvm_val = try o.lowerValue(val.toIntern());
+        if (!isByRef(ty, mod)) return llvm_val;
 
         // We have an LLVM value but we need to create a global constant and
         // set the value as its initializer, and then return a pointer to the global.
@@ -4849,7 +4846,7 @@ pub const FuncGen = struct {
         variable_index.setLinkage(.private, &o.builder);
         variable_index.setMutability(.constant, &o.builder);
         variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
-        variable_index.setAlignment(tv.ty.abiAlignment(mod).toLlvm(), &o.builder);
+        variable_index.setAlignment(ty.abiAlignment(mod).toLlvm(), &o.builder);
         return o.builder.convConst(
             .unneeded,
             variable_index.toConst(&o.builder),
@@ -4861,11 +4858,10 @@ pub const FuncGen = struct {
         const o = self.dg.object;
         const mod = o.module;
         if (o.null_opt_usize == .no_init) {
-            const ty = try mod.intern(.{ .opt_type = .usize_type });
-            o.null_opt_usize = try self.resolveValue(.{
-                .ty = Type.fromInterned(ty),
-                .val = Value.fromInterned((try mod.intern(.{ .opt = .{ .ty = ty, .val = .none } }))),
-            });
+            o.null_opt_usize = try self.resolveValue(Value.fromInterned(try mod.intern(.{ .opt = .{
+                .ty = try mod.intern(.{ .opt_type = .usize_type }),
+                .val = .none,
+            } })));
         }
         return o.null_opt_usize;
     }
@@ -10061,10 +10057,7 @@ pub const FuncGen = struct {
                     const elem_ptr = try self.wip.gep(.inbounds, llvm_result_ty, alloca_inst, &.{
                         usize_zero, try o.builder.intValue(llvm_usize, array_info.len),
                     }, "");
-                    const llvm_elem = try self.resolveValue(.{
-                        .ty = array_info.elem_type,
-                        .val = sent_val,
-                    });
+                    const llvm_elem = try self.resolveValue(sent_val);
                     try self.store(elem_ptr, elem_ptr_ty, llvm_elem.toValue(), .none);
                 }
 
src/link/Elf/ZigObject.zig
@@ -702,7 +702,6 @@ pub fn lowerAnonDecl(
     }
 
     const val = Value.fromInterned(decl_val);
-    const tv = TypedValue{ .ty = ty, .val = val };
     var name_buf: [32]u8 = undefined;
     const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
         @intFromEnum(decl_val),
@@ -710,7 +709,7 @@ pub fn lowerAnonDecl(
     const res = self.lowerConst(
         elf_file,
         name,
-        tv,
+        val,
         decl_alignment,
         elf_file.zig_data_rel_ro_section_index.?,
         src_loc,
@@ -1157,19 +1156,13 @@ pub fn updateDecl(
     // TODO implement .debug_info for global variables
     const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
     const res = if (decl_state) |*ds|
-        try codegen.generateSymbol(&elf_file.base, decl.srcLoc(mod), .{
-            .ty = decl.typeOf(mod),
-            .val = decl_val,
-        }, &code_buffer, .{
+        try codegen.generateSymbol(&elf_file.base, decl.srcLoc(mod), decl_val, &code_buffer, .{
             .dwarf = ds,
         }, .{
             .parent_atom_index = sym_index,
         })
     else
-        try codegen.generateSymbol(&elf_file.base, decl.srcLoc(mod), .{
-            .ty = decl.typeOf(mod),
-            .val = decl_val,
-        }, &code_buffer, .none, .{
+        try codegen.generateSymbol(&elf_file.base, decl.srcLoc(mod), decl_val, &code_buffer, .none, .{
             .parent_atom_index = sym_index,
         });
 
@@ -1289,7 +1282,7 @@ fn updateLazySymbol(
 pub fn lowerUnnamedConst(
     self: *ZigObject,
     elf_file: *Elf,
-    typed_value: TypedValue,
+    val: Value,
     decl_index: InternPool.DeclIndex,
 ) !u32 {
     const gpa = elf_file.base.comp.gpa;
@@ -1304,11 +1297,12 @@ pub fn lowerUnnamedConst(
     const index = unnamed_consts.items.len;
     const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
     defer gpa.free(name);
+    const ty = val.typeOf(mod);
     const sym_index = switch (try self.lowerConst(
         elf_file,
         name,
-        typed_value,
-        typed_value.ty.abiAlignment(mod),
+        val,
+        ty.abiAlignment(mod),
         elf_file.zig_data_rel_ro_section_index.?,
         decl.srcLoc(mod),
     )) {
@@ -1334,7 +1328,7 @@ fn lowerConst(
     self: *ZigObject,
     elf_file: *Elf,
     name: []const u8,
-    tv: TypedValue,
+    val: Value,
     required_alignment: InternPool.Alignment,
     output_section_index: u32,
     src_loc: Module.SrcLoc,
@@ -1346,7 +1340,7 @@ fn lowerConst(
 
     const sym_index = try self.addAtom(elf_file);
 
-    const res = try codegen.generateSymbol(&elf_file.base, src_loc, tv, &code_buffer, .{
+    const res = try codegen.generateSymbol(&elf_file.base, src_loc, val, &code_buffer, .{
         .none = {},
     }, .{
         .parent_atom_index = sym_index,
@@ -1657,5 +1651,4 @@ const Symbol = @import("Symbol.zig");
 const StringTable = @import("../StringTable.zig");
 const Type = @import("../../type.zig").Type;
 const Value = @import("../../Value.zig");
-const TypedValue = @import("../../TypedValue.zig");
 const ZigObject = @This();
src/link/MachO/ZigObject.zig
@@ -567,8 +567,6 @@ pub fn lowerAnonDecl(
             return .ok;
     }
 
-    const val = Value.fromInterned(decl_val);
-    const tv = TypedValue{ .ty = ty, .val = val };
     var name_buf: [32]u8 = undefined;
     const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
         @intFromEnum(decl_val),
@@ -576,7 +574,7 @@ pub fn lowerAnonDecl(
     const res = self.lowerConst(
         macho_file,
         name,
-        tv,
+        Value.fromInterned(decl_val),
         decl_alignment,
         macho_file.zig_const_sect_index.?,
         src_loc,
@@ -738,11 +736,7 @@ pub fn updateDecl(
 
     const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
     const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none;
-    const res =
-        try codegen.generateSymbol(&macho_file.base, decl.srcLoc(mod), .{
-        .ty = decl.typeOf(mod),
-        .val = decl_val,
-    }, &code_buffer, dio, .{
+    const res = try codegen.generateSymbol(&macho_file.base, decl.srcLoc(mod), decl_val, &code_buffer, dio, .{
         .parent_atom_index = sym_index,
     });
 
@@ -1068,7 +1062,7 @@ fn getDeclOutputSection(
 pub fn lowerUnnamedConst(
     self: *ZigObject,
     macho_file: *MachO,
-    typed_value: TypedValue,
+    val: Value,
     decl_index: InternPool.DeclIndex,
 ) !u32 {
     const gpa = macho_file.base.comp.gpa;
@@ -1086,8 +1080,8 @@ pub fn lowerUnnamedConst(
     const sym_index = switch (try self.lowerConst(
         macho_file,
         name,
-        typed_value,
-        typed_value.ty.abiAlignment(mod),
+        val,
+        val.typeOf(mod).abiAlignment(mod),
         macho_file.zig_const_sect_index.?,
         decl.srcLoc(mod),
     )) {
@@ -1113,7 +1107,7 @@ fn lowerConst(
     self: *ZigObject,
     macho_file: *MachO,
     name: []const u8,
-    tv: TypedValue,
+    val: Value,
     required_alignment: Atom.Alignment,
     output_section_index: u8,
     src_loc: Module.SrcLoc,
@@ -1125,7 +1119,7 @@ fn lowerConst(
 
     const sym_index = try self.addAtom(macho_file);
 
-    const res = try codegen.generateSymbol(&macho_file.base, src_loc, tv, &code_buffer, .{
+    const res = try codegen.generateSymbol(&macho_file.base, src_loc, val, &code_buffer, .{
         .none = {},
     }, .{
         .parent_atom_index = sym_index,
@@ -1580,5 +1574,4 @@ const Symbol = @import("Symbol.zig");
 const StringTable = @import("../StringTable.zig");
 const Type = @import("../../type.zig").Type;
 const Value = @import("../../Value.zig");
-const TypedValue = @import("../../TypedValue.zig");
 const ZigObject = @This();
src/link/Wasm/ZigObject.zig
@@ -270,7 +270,7 @@ pub fn updateDecl(
     const res = try codegen.generateSymbol(
         &wasm_file.base,
         decl.srcLoc(mod),
-        .{ .ty = decl.typeOf(mod), .val = val },
+        val,
         &code_writer,
         .none,
         .{ .parent_atom_index = @intFromEnum(atom.sym_index) },
@@ -444,15 +444,12 @@ pub fn lowerAnonDecl(
     const gpa = wasm_file.base.comp.gpa;
     const gop = try zig_object.anon_decls.getOrPut(gpa, decl_val);
     if (!gop.found_existing) {
-        const mod = wasm_file.base.comp.module.?;
-        const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
-        const tv: TypedValue = .{ .ty = ty, .val = Value.fromInterned(decl_val) };
         var name_buf: [32]u8 = undefined;
         const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
             @intFromEnum(decl_val),
         }) catch unreachable;
 
-        switch (try zig_object.lowerConst(wasm_file, name, tv, src_loc)) {
+        switch (try zig_object.lowerConst(wasm_file, name, Value.fromInterned(decl_val), src_loc)) {
             .ok => |atom_index| zig_object.anon_decls.values()[gop.index] = atom_index,
             .fail => |em| return .{ .fail = em },
         }
@@ -472,10 +469,10 @@ pub fn lowerAnonDecl(
 /// Lowers a constant typed value to a local symbol and atom.
 /// Returns the symbol index of the local
 /// The given `decl` is the parent decl whom owns the constant.
-pub fn lowerUnnamedConst(zig_object: *ZigObject, wasm_file: *Wasm, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 {
+pub fn lowerUnnamedConst(zig_object: *ZigObject, wasm_file: *Wasm, val: Value, decl_index: InternPool.DeclIndex) !u32 {
     const gpa = wasm_file.base.comp.gpa;
     const mod = wasm_file.base.comp.module.?;
-    std.debug.assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions
+    std.debug.assert(val.typeOf(mod).zigTypeTag(mod) != .Fn); // cannot create local symbols for functions
     const decl = mod.declPtr(decl_index);
 
     const parent_atom_index = try zig_object.getOrCreateAtomForDecl(wasm_file, decl_index);
@@ -487,7 +484,7 @@ pub fn lowerUnnamedConst(zig_object: *ZigObject, wasm_file: *Wasm, tv: TypedValu
     });
     defer gpa.free(name);
 
-    switch (try zig_object.lowerConst(wasm_file, name, tv, decl.srcLoc(mod))) {
+    switch (try zig_object.lowerConst(wasm_file, name, val, decl.srcLoc(mod))) {
         .ok => |atom_index| {
             try wasm_file.getAtomPtr(parent_atom_index).locals.append(gpa, atom_index);
             return @intFromEnum(wasm_file.getAtom(atom_index).sym_index);
@@ -505,10 +502,12 @@ const LowerConstResult = union(enum) {
     fail: *Module.ErrorMsg,
 };
 
-fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.SrcLoc) !LowerConstResult {
+fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, val: Value, src_loc: Module.SrcLoc) !LowerConstResult {
     const gpa = wasm_file.base.comp.gpa;
     const mod = wasm_file.base.comp.module.?;
 
+    const ty = val.typeOf(mod);
+
     // Create and initialize a new local symbol and atom
     const sym_index = try zig_object.allocateSymbol(gpa);
     const atom_index = try wasm_file.createAtom(sym_index, zig_object.index);
@@ -517,7 +516,7 @@ fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, tv: Ty
 
     const code = code: {
         const atom = wasm_file.getAtomPtr(atom_index);
-        atom.alignment = tv.ty.abiAlignment(mod);
+        atom.alignment = ty.abiAlignment(mod);
         const segment_name = try std.mem.concat(gpa, u8, &.{ ".rodata.", name });
         errdefer gpa.free(segment_name);
         zig_object.symbol(sym_index).* = .{
@@ -527,7 +526,7 @@ fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, tv: Ty
             .index = try zig_object.createDataSegment(
                 gpa,
                 segment_name,
-                tv.ty.abiAlignment(mod),
+                ty.abiAlignment(mod),
             ),
             .virtual_address = undefined,
         };
@@ -535,7 +534,7 @@ fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, tv: Ty
         const result = try codegen.generateSymbol(
             &wasm_file.base,
             src_loc,
-            tv,
+            val,
             &value_bytes,
             .none,
             .{
@@ -1242,7 +1241,6 @@ const Module = @import("../../Module.zig");
 const StringTable = @import("../StringTable.zig");
 const Symbol = @import("Symbol.zig");
 const Type = @import("../../type.zig").Type;
-const TypedValue = @import("../../TypedValue.zig");
 const Value = @import("../../Value.zig");
 const Wasm = @import("../Wasm.zig");
 const ZigObject = @This();
src/link/C.zig
@@ -283,13 +283,9 @@ fn updateAnonDecl(self: *C, module: *Module, i: usize) !void {
         code.* = object.code.moveToUnmanaged();
     }
 
-    const tv: @import("../TypedValue.zig") = .{
-        .ty = Type.fromInterned(module.intern_pool.typeOf(anon_decl)),
-        .val = Value.fromInterned(anon_decl),
-    };
     const c_value: codegen.CValue = .{ .constant = anon_decl };
     const alignment: Alignment = self.aligned_anon_decls.get(anon_decl) orelse .none;
-    codegen.genDeclValue(&object, tv, false, c_value, alignment, .none) catch |err| switch (err) {
+    codegen.genDeclValue(&object, Value.fromInterned(anon_decl), false, c_value, alignment, .none) catch |err| switch (err) {
         error.AnalysisFail => {
             @panic("TODO: C backend AnalysisFail on anonymous decl");
             //try module.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
src/link/Coff.zig
@@ -1167,7 +1167,7 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air:
     return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
 }
 
-pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 {
+pub fn lowerUnnamedConst(self: *Coff, val: Value, decl_index: InternPool.DeclIndex) !u32 {
     const gpa = self.base.comp.gpa;
     const mod = self.base.comp.module.?;
     const decl = mod.declPtr(decl_index);
@@ -1180,7 +1180,8 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: InternPool.Dec
     const index = unnamed_consts.items.len;
     const sym_name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
     defer gpa.free(sym_name);
-    const atom_index = switch (try self.lowerConst(sym_name, tv, tv.ty.abiAlignment(mod), self.rdata_section_index.?, decl.srcLoc(mod))) {
+    const ty = val.typeOf(mod);
+    const atom_index = switch (try self.lowerConst(sym_name, val, ty.abiAlignment(mod), self.rdata_section_index.?, decl.srcLoc(mod))) {
         .ok => |atom_index| atom_index,
         .fail => |em| {
             decl.analysis = .codegen_failure;
@@ -1198,7 +1199,7 @@ const LowerConstResult = union(enum) {
     fail: *Module.ErrorMsg,
 };
 
-fn lowerConst(self: *Coff, name: []const u8, tv: TypedValue, required_alignment: InternPool.Alignment, sect_id: u16, src_loc: Module.SrcLoc) !LowerConstResult {
+fn lowerConst(self: *Coff, name: []const u8, val: Value, required_alignment: InternPool.Alignment, sect_id: u16, src_loc: Module.SrcLoc) !LowerConstResult {
     const gpa = self.base.comp.gpa;
 
     var code_buffer = std.ArrayList(u8).init(gpa);
@@ -1209,7 +1210,7 @@ fn lowerConst(self: *Coff, name: []const u8, tv: TypedValue, required_alignment:
     try self.setSymbolName(sym, name);
     sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_id + 1));
 
-    const res = try codegen.generateSymbol(&self.base, src_loc, tv, &code_buffer, .none, .{
+    const res = try codegen.generateSymbol(&self.base, src_loc, val, &code_buffer, .none, .{
         .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,
     });
     const code = switch (res) {
@@ -1271,10 +1272,7 @@ pub fn updateDecl(
     defer code_buffer.deinit();
 
     const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
-    const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{
-        .ty = decl.typeOf(mod),
-        .val = decl_val,
-    }, &code_buffer, .none, .{
+    const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), decl_val, &code_buffer, .none, .{
         .parent_atom_index = atom.getSymbolIndex().?,
     });
     const code = switch (res) {
@@ -1887,14 +1885,13 @@ pub fn lowerAnonDecl(
     }
 
     const val = Value.fromInterned(decl_val);
-    const tv = TypedValue{ .ty = ty, .val = val };
     var name_buf: [32]u8 = undefined;
     const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
         @intFromEnum(decl_val),
     }) catch unreachable;
     const res = self.lowerConst(
         name,
-        tv,
+        val,
         decl_alignment,
         self.rdata_section_index.?,
         src_loc,
@@ -2754,7 +2751,6 @@ const TableSection = @import("table_section.zig").TableSection;
 const StringTable = @import("StringTable.zig");
 const Type = @import("../type.zig").Type;
 const Value = @import("../Value.zig");
-const TypedValue = @import("../TypedValue.zig");
 
 pub const base_tag: link.File.Tag = .coff;
 
src/link/Elf.zig
@@ -3039,8 +3039,8 @@ pub fn updateDecl(
     return self.zigObjectPtr().?.updateDecl(self, mod, decl_index);
 }
 
-pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: InternPool.DeclIndex) !u32 {
-    return self.zigObjectPtr().?.lowerUnnamedConst(self, typed_value, decl_index);
+pub fn lowerUnnamedConst(self: *Elf, val: Value, decl_index: InternPool.DeclIndex) !u32 {
+    return self.zigObjectPtr().?.lowerUnnamedConst(self, val, decl_index);
 }
 
 pub fn updateExports(
@@ -6260,7 +6260,7 @@ const SharedObject = @import("Elf/SharedObject.zig");
 const Symbol = @import("Elf/Symbol.zig");
 const StringTable = @import("StringTable.zig");
 const Thunk = thunks.Thunk;
-const TypedValue = @import("../TypedValue.zig");
+const Value = @import("../Value.zig");
 const VerneedSection = synthetic_sections.VerneedSection;
 const ZigGotSection = synthetic_sections.ZigGotSection;
 const ZigObject = @import("Elf/ZigObject.zig");
src/link/MachO.zig
@@ -3127,8 +3127,8 @@ pub fn updateFunc(self: *MachO, mod: *Module, func_index: InternPool.Index, air:
     return self.getZigObject().?.updateFunc(self, mod, func_index, air, liveness);
 }
 
-pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: InternPool.DeclIndex) !u32 {
-    return self.getZigObject().?.lowerUnnamedConst(self, typed_value, decl_index);
+pub fn lowerUnnamedConst(self: *MachO, val: Value, decl_index: InternPool.DeclIndex) !u32 {
+    return self.getZigObject().?.lowerUnnamedConst(self, val, decl_index);
 }
 
 pub fn updateDecl(self: *MachO, mod: *Module, decl_index: InternPool.DeclIndex) !void {
@@ -4689,7 +4689,7 @@ const StubsHelperSection = synthetic.StubsHelperSection;
 const Symbol = @import("MachO/Symbol.zig");
 const Thunk = thunks.Thunk;
 const TlvPtrSection = synthetic.TlvPtrSection;
-const TypedValue = @import("../TypedValue.zig");
+const Value = @import("../Value.zig");
 const UnwindInfo = @import("MachO/UnwindInfo.zig");
 const WeakBindSection = synthetic.WeakBindSection;
 const ZigGotSection = synthetic.ZigGotSection;
src/link/Plan9.zig
@@ -15,7 +15,6 @@ const Air = @import("../Air.zig");
 const Liveness = @import("../Liveness.zig");
 const Type = @import("../type.zig").Type;
 const Value = @import("../Value.zig");
-const TypedValue = @import("../TypedValue.zig");
 
 const std = @import("std");
 const builtin = @import("builtin");
@@ -463,7 +462,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
     return self.updateFinish(decl_index);
 }
 
-pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 {
+pub fn lowerUnnamedConst(self: *Plan9, val: Value, decl_index: InternPool.DeclIndex) !u32 {
     const gpa = self.base.comp.gpa;
     _ = try self.seeDecl(decl_index);
     var code_buffer = std.ArrayList(u8).init(gpa);
@@ -500,7 +499,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.De
     };
     self.syms.items[info.sym_index.?] = sym;
 
-    const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), tv, &code_buffer, .{
+    const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), val, &code_buffer, .{
         .none = {},
     }, .{
         .parent_atom_index = new_atom_idx,
@@ -539,10 +538,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex)
     defer code_buffer.deinit();
     const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
     // TODO we need the symbol index for symbol in the table of locals for the containing atom
-    const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{
-        .ty = decl.typeOf(mod),
-        .val = decl_val,
-    }, &code_buffer, .{ .none = {} }, .{
+    const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), decl_val, &code_buffer, .{ .none = {} }, .{
         .parent_atom_index = @as(Atom.Index, @intCast(atom_idx)),
     });
     const code = switch (res) {
@@ -1545,11 +1541,8 @@ pub fn lowerAnonDecl(
     // ...
     const gpa = self.base.comp.gpa;
     const gop = try self.anon_decls.getOrPut(gpa, decl_val);
-    const mod = self.base.comp.module.?;
     if (!gop.found_existing) {
-        const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
         const val = Value.fromInterned(decl_val);
-        const tv = TypedValue{ .ty = ty, .val = val };
         const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)});
 
         const index = try self.createAtom();
@@ -1557,7 +1550,7 @@ pub fn lowerAnonDecl(
         gop.value_ptr.* = index;
         // we need to free name latex
         var code_buffer = std.ArrayList(u8).init(gpa);
-        const res = try codegen.generateSymbol(&self.base, src_loc, tv, &code_buffer, .{ .none = {} }, .{ .parent_atom_index = index });
+        const res = try codegen.generateSymbol(&self.base, src_loc, val, &code_buffer, .{ .none = {} }, .{ .parent_atom_index = index });
         const code = switch (res) {
             .ok => code_buffer.items,
             .fail => |em| return .{ .fail = em },
src/link/Wasm.zig
@@ -32,7 +32,7 @@ const Module = @import("../Module.zig");
 const Object = @import("Wasm/Object.zig");
 const Symbol = @import("Wasm/Symbol.zig");
 const Type = @import("../type.zig").Type;
-const TypedValue = @import("../TypedValue.zig");
+const Value = @import("../Value.zig");
 const ZigObject = @import("Wasm/ZigObject.zig");
 
 pub const Atom = @import("Wasm/Atom.zig");
@@ -1504,8 +1504,8 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {
 /// Lowers a constant typed value to a local symbol and atom.
 /// Returns the symbol index of the local
 /// The given `decl` is the parent decl whom owns the constant.
-pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 {
-    return wasm.zigObjectPtr().?.lowerUnnamedConst(wasm, tv, decl_index);
+pub fn lowerUnnamedConst(wasm: *Wasm, val: Value, decl_index: InternPool.DeclIndex) !u32 {
+    return wasm.zigObjectPtr().?.lowerUnnamedConst(wasm, val, decl_index);
 }
 
 /// Returns the symbol index from a symbol of which its flag is set global,
src/codegen.zig
@@ -19,7 +19,6 @@ const Liveness = @import("Liveness.zig");
 const Module = @import("Module.zig");
 const Target = std.Target;
 const Type = @import("type.zig").Type;
-const TypedValue = @import("TypedValue.zig");
 const Value = @import("Value.zig");
 const Zir = std.zig.Zir;
 const Alignment = InternPool.Alignment;
@@ -171,7 +170,7 @@ pub fn generateLazySymbol(
 pub fn generateSymbol(
     bin_file: *link.File,
     src_loc: Module.SrcLoc,
-    arg_tv: TypedValue,
+    val: Value,
     code: *std.ArrayList(u8),
     debug_output: DebugInfoOutput,
     reloc_info: RelocInfo,
@@ -181,23 +180,22 @@ pub fn generateSymbol(
 
     const mod = bin_file.comp.module.?;
     const ip = &mod.intern_pool;
-    const typed_value = arg_tv;
+    const ty = val.typeOf(mod);
 
     const target = mod.getTarget();
     const endian = target.cpu.arch.endian();
 
-    log.debug("generateSymbol: ty = {}, val = {}", .{
-        typed_value.ty.fmt(mod),
-        typed_value.val.fmtValue(typed_value.ty, mod),
+    log.debug("generateSymbol: val = {}", .{
+        val.fmtValue(ty, mod),
     });
 
-    if (typed_value.val.isUndefDeep(mod)) {
-        const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow;
+    if (val.isUndefDeep(mod)) {
+        const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow;
         try code.appendNTimes(0xaa, abi_size);
         return .ok;
     }
 
-    switch (ip.indexToKey(typed_value.val.toIntern())) {
+    switch (ip.indexToKey(val.toIntern())) {
         .int_type,
         .ptr_type,
         .array_type,
@@ -238,17 +236,17 @@ pub fn generateSymbol(
         .empty_enum_value,
         => unreachable, // non-runtime values
         .int => {
-            const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow;
+            const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow;
             var space: Value.BigIntSpace = undefined;
-            const val = typed_value.val.toBigInt(&space, mod);
-            val.writeTwosComplement(try code.addManyAsSlice(abi_size), endian);
+            const int_val = val.toBigInt(&space, mod);
+            int_val.writeTwosComplement(try code.addManyAsSlice(abi_size), endian);
         },
         .err => |err| {
             const int = try mod.getErrorValue(err.name);
             try code.writer().writeInt(u16, @as(u16, @intCast(int)), endian);
         },
         .error_union => |error_union| {
-            const payload_ty = typed_value.ty.errorUnionPayload(mod);
+            const payload_ty = ty.errorUnionPayload(mod);
             const err_val = switch (error_union.val) {
                 .err_name => |err_name| @as(u16, @intCast(try mod.getErrorValue(err_name))),
                 .payload => @as(u16, 0),
@@ -261,7 +259,7 @@ pub fn generateSymbol(
 
             const payload_align = payload_ty.abiAlignment(mod);
             const error_align = Type.anyerror.abiAlignment(mod);
-            const abi_align = typed_value.ty.abiAlignment(mod);
+            const abi_align = ty.abiAlignment(mod);
 
             // error value first when its type is larger than the error union's payload
             if (error_align.order(payload_align) == .gt) {
@@ -271,13 +269,10 @@ pub fn generateSymbol(
             // emit payload part of the error union
             {
                 const begin = code.items.len;
-                switch (try generateSymbol(bin_file, src_loc, .{
-                    .ty = payload_ty,
-                    .val = Value.fromInterned(switch (error_union.val) {
-                        .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }),
-                        .payload => |payload| payload,
-                    }),
-                }, code, debug_output, reloc_info)) {
+                switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(switch (error_union.val) {
+                    .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }),
+                    .payload => |payload| payload,
+                }), code, debug_output, reloc_info)) {
                     .ok => {},
                     .fail => |em| return .{ .fail = em },
                 }
@@ -304,11 +299,8 @@ pub fn generateSymbol(
             }
         },
         .enum_tag => |enum_tag| {
-            const int_tag_ty = typed_value.ty.intTagType(mod);
-            switch (try generateSymbol(bin_file, src_loc, .{
-                .ty = int_tag_ty,
-                .val = try mod.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty),
-            }, code, debug_output, reloc_info)) {
+            const int_tag_ty = ty.intTagType(mod);
+            switch (try generateSymbol(bin_file, src_loc, try mod.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, debug_output, reloc_info)) {
                 .ok => {},
                 .fail => |em| return .{ .fail = em },
             }
@@ -319,42 +311,33 @@ pub fn generateSymbol(
             .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(8)),
             .f80 => |f80_val| {
                 writeFloat(f80, f80_val, target, endian, try code.addManyAsArray(10));
-                const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow;
+                const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow;
                 try code.appendNTimes(0, abi_size - 10);
             },
             .f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(16)),
         },
-        .ptr => switch (try lowerParentPtr(bin_file, src_loc, typed_value.val.toIntern(), code, debug_output, reloc_info)) {
+        .ptr => switch (try lowerParentPtr(bin_file, src_loc, val.toIntern(), code, debug_output, reloc_info)) {
             .ok => {},
             .fail => |em| return .{ .fail = em },
         },
         .slice => |slice| {
-            switch (try generateSymbol(bin_file, src_loc, .{
-                .ty = typed_value.ty.slicePtrFieldType(mod),
-                .val = Value.fromInterned(slice.ptr),
-            }, code, debug_output, reloc_info)) {
+            switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(slice.ptr), code, debug_output, reloc_info)) {
                 .ok => {},
                 .fail => |em| return .{ .fail = em },
             }
-            switch (try generateSymbol(bin_file, src_loc, .{
-                .ty = Type.usize,
-                .val = Value.fromInterned(slice.len),
-            }, code, debug_output, reloc_info)) {
+            switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(slice.len), code, debug_output, reloc_info)) {
                 .ok => {},
                 .fail => |em| return .{ .fail = em },
             }
         },
         .opt => {
-            const payload_type = typed_value.ty.optionalChild(mod);
-            const payload_val = typed_value.val.optionalValue(mod);
-            const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow;
+            const payload_type = ty.optionalChild(mod);
+            const payload_val = val.optionalValue(mod);
+            const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow;
 
-            if (typed_value.ty.optionalReprIsPayload(mod)) {
+            if (ty.optionalReprIsPayload(mod)) {
                 if (payload_val) |value| {
-                    switch (try generateSymbol(bin_file, src_loc, .{
-                        .ty = payload_type,
-                        .val = value,
-                    }, code, debug_output, reloc_info)) {
+                    switch (try generateSymbol(bin_file, src_loc, value, code, debug_output, reloc_info)) {
                         .ok => {},
                         .fail => |em| return Result{ .fail = em },
                     }
@@ -365,10 +348,7 @@ pub fn generateSymbol(
                 const padding = abi_size - (math.cast(usize, payload_type.abiSize(mod)) orelse return error.Overflow) - 1;
                 if (payload_type.hasRuntimeBits(mod)) {
                     const value = payload_val orelse Value.fromInterned((try mod.intern(.{ .undef = payload_type.toIntern() })));
-                    switch (try generateSymbol(bin_file, src_loc, .{
-                        .ty = payload_type,
-                        .val = value,
-                    }, code, debug_output, reloc_info)) {
+                    switch (try generateSymbol(bin_file, src_loc, value, code, debug_output, reloc_info)) {
                         .ok => {},
                         .fail => |em| return Result{ .fail = em },
                     }
@@ -377,7 +357,7 @@ pub fn generateSymbol(
                 try code.appendNTimes(0, padding);
             }
         },
-        .aggregate => |aggregate| switch (ip.indexToKey(typed_value.ty.toIntern())) {
+        .aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) {
             .array_type => |array_type| switch (aggregate.storage) {
                 .bytes => |bytes| try code.appendSlice(bytes),
                 .elems, .repeated_elem => {
@@ -385,17 +365,14 @@ pub fn generateSymbol(
                     const len_including_sentinel =
                         array_type.len + @intFromBool(array_type.sentinel != .none);
                     while (index < len_including_sentinel) : (index += 1) {
-                        switch (try generateSymbol(bin_file, src_loc, .{
-                            .ty = Type.fromInterned(array_type.child),
-                            .val = Value.fromInterned(switch (aggregate.storage) {
-                                .bytes => unreachable,
-                                .elems => |elems| elems[@as(usize, @intCast(index))],
-                                .repeated_elem => |elem| if (index < array_type.len)
-                                    elem
-                                else
-                                    array_type.sentinel,
-                            }),
-                        }, code, debug_output, reloc_info)) {
+                        switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(switch (aggregate.storage) {
+                            .bytes => unreachable,
+                            .elems => |elems| elems[@as(usize, @intCast(index))],
+                            .repeated_elem => |elem| if (index < array_type.len)
+                                elem
+                            else
+                                array_type.sentinel,
+                        }), code, debug_output, reloc_info)) {
                             .ok => {},
                             .fail => |em| return .{ .fail = em },
                         }
@@ -403,7 +380,7 @@ pub fn generateSymbol(
                 },
             },
             .vector_type => |vector_type| {
-                const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse
+                const abi_size = math.cast(usize, ty.abiSize(mod)) orelse
                     return error.Overflow;
                 if (vector_type.child == .bool_type) {
                     const bytes = try code.addManyAsSlice(abi_size);
@@ -449,16 +426,13 @@ pub fn generateSymbol(
                         .elems, .repeated_elem => {
                             var index: u64 = 0;
                             while (index < vector_type.len) : (index += 1) {
-                                switch (try generateSymbol(bin_file, src_loc, .{
-                                    .ty = Type.fromInterned(vector_type.child),
-                                    .val = Value.fromInterned(switch (aggregate.storage) {
-                                        .bytes => unreachable,
-                                        .elems => |elems| elems[
-                                            math.cast(usize, index) orelse return error.Overflow
-                                        ],
-                                        .repeated_elem => |elem| elem,
-                                    }),
-                                }, code, debug_output, reloc_info)) {
+                                switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(switch (aggregate.storage) {
+                                    .bytes => unreachable,
+                                    .elems => |elems| elems[
+                                        math.cast(usize, index) orelse return error.Overflow
+                                    ],
+                                    .repeated_elem => |elem| elem,
+                                }), code, debug_output, reloc_info)) {
                                     .ok => {},
                                     .fail => |em| return .{ .fail = em },
                                 }
@@ -491,17 +465,14 @@ pub fn generateSymbol(
                         .repeated_elem => |elem| elem,
                     };
 
-                    switch (try generateSymbol(bin_file, src_loc, .{
-                        .ty = Type.fromInterned(field_ty),
-                        .val = Value.fromInterned(field_val),
-                    }, code, debug_output, reloc_info)) {
+                    switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(field_val), code, debug_output, reloc_info)) {
                         .ok => {},
                         .fail => |em| return Result{ .fail = em },
                     }
                     const unpadded_field_end = code.items.len - struct_begin;
 
                     // Pad struct members if required
-                    const padded_field_end = typed_value.ty.structFieldOffset(index + 1, mod);
+                    const padded_field_end = ty.structFieldOffset(index + 1, mod);
                     const padding = math.cast(usize, padded_field_end - unpadded_field_end) orelse
                         return error.Overflow;
 
@@ -511,10 +482,10 @@ pub fn generateSymbol(
                 }
             },
             .struct_type => {
-                const struct_type = ip.loadStructType(typed_value.ty.toIntern());
+                const struct_type = ip.loadStructType(ty.toIntern());
                 switch (struct_type.layout) {
                     .@"packed" => {
-                        const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse
+                        const abi_size = math.cast(usize, ty.abiSize(mod)) orelse
                             return error.Overflow;
                         const current_pos = code.items.len;
                         try code.resize(current_pos + abi_size);
@@ -537,10 +508,7 @@ pub fn generateSymbol(
                                     return error.Overflow;
                                 var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size);
                                 defer tmp_list.deinit();
-                                switch (try generateSymbol(bin_file, src_loc, .{
-                                    .ty = Type.fromInterned(field_ty),
-                                    .val = Value.fromInterned(field_val),
-                                }, &tmp_list, debug_output, reloc_info)) {
+                                switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(field_val), &tmp_list, debug_output, reloc_info)) {
                                     .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items),
                                     .fail => |em| return Result{ .fail = em },
                                 }
@@ -560,7 +528,7 @@ pub fn generateSymbol(
                             const field_ty = field_types[field_index];
                             if (!Type.fromInterned(field_ty).hasRuntimeBits(mod)) continue;
 
-                            const field_val = switch (ip.indexToKey(typed_value.val.toIntern()).aggregate.storage) {
+                            const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
                                 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
                                     .ty = field_ty,
                                     .storage = .{ .u64 = bytes[field_index] },
@@ -575,10 +543,7 @@ pub fn generateSymbol(
                             ) orelse return error.Overflow;
                             if (padding > 0) try code.appendNTimes(0, padding);
 
-                            switch (try generateSymbol(bin_file, src_loc, .{
-                                .ty = Type.fromInterned(field_ty),
-                                .val = Value.fromInterned(field_val),
-                            }, code, debug_output, reloc_info)) {
+                            switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(field_val), code, debug_output, reloc_info)) {
                                 .ok => {},
                                 .fail => |em| return Result{ .fail = em },
                             }
@@ -599,37 +564,28 @@ pub fn generateSymbol(
             else => unreachable,
         },
         .un => |un| {
-            const layout = typed_value.ty.unionGetLayout(mod);
+            const layout = ty.unionGetLayout(mod);
 
             if (layout.payload_size == 0) {
-                return generateSymbol(bin_file, src_loc, .{
-                    .ty = typed_value.ty.unionTagTypeSafety(mod).?,
-                    .val = Value.fromInterned(un.tag),
-                }, code, debug_output, reloc_info);
+                return generateSymbol(bin_file, src_loc, Value.fromInterned(un.tag), code, debug_output, reloc_info);
             }
 
             // Check if we should store the tag first.
             if (layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)) {
-                switch (try generateSymbol(bin_file, src_loc, .{
-                    .ty = typed_value.ty.unionTagTypeSafety(mod).?,
-                    .val = Value.fromInterned(un.tag),
-                }, code, debug_output, reloc_info)) {
+                switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(un.tag), code, debug_output, reloc_info)) {
                     .ok => {},
                     .fail => |em| return Result{ .fail = em },
                 }
             }
 
-            const union_obj = mod.typeToUnion(typed_value.ty).?;
+            const union_obj = mod.typeToUnion(ty).?;
             if (un.tag != .none) {
-                const field_index = typed_value.ty.unionTagFieldIndex(Value.fromInterned(un.tag), mod).?;
+                const field_index = ty.unionTagFieldIndex(Value.fromInterned(un.tag), mod).?;
                 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
                 if (!field_ty.hasRuntimeBits(mod)) {
                     try code.appendNTimes(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow);
                 } else {
-                    switch (try generateSymbol(bin_file, src_loc, .{
-                        .ty = field_ty,
-                        .val = Value.fromInterned(un.val),
-                    }, code, debug_output, reloc_info)) {
+                    switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(un.val), code, debug_output, reloc_info)) {
                         .ok => {},
                         .fail => |em| return Result{ .fail = em },
                     }
@@ -640,20 +596,14 @@ pub fn generateSymbol(
                     }
                 }
             } else {
-                switch (try generateSymbol(bin_file, src_loc, .{
-                    .ty = Type.fromInterned(ip.typeOf(un.val)),
-                    .val = Value.fromInterned(un.val),
-                }, code, debug_output, reloc_info)) {
+                switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(un.val), code, debug_output, reloc_info)) {
                     .ok => {},
                     .fail => |em| return Result{ .fail = em },
                 }
             }
 
             if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) {
-                switch (try generateSymbol(bin_file, src_loc, .{
-                    .ty = Type.fromInterned(union_obj.enum_tag_ty),
-                    .val = Value.fromInterned(un.tag),
-                }, code, debug_output, reloc_info)) {
+                switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(un.tag), code, debug_output, reloc_info)) {
                     .ok => {},
                     .fail => |em| return Result{ .fail = em },
                 }
@@ -681,10 +631,7 @@ fn lowerParentPtr(
     return switch (ptr.addr) {
         .decl => |decl| try lowerDeclRef(bin_file, src_loc, decl, code, debug_output, reloc_info),
         .anon_decl => |ad| try lowerAnonDeclRef(bin_file, src_loc, ad, code, debug_output, reloc_info),
-        .int => |int| try generateSymbol(bin_file, src_loc, .{
-            .ty = Type.usize,
-            .val = Value.fromInterned(int),
-        }, code, debug_output, reloc_info),
+        .int => |int| try generateSymbol(bin_file, src_loc, Value.fromInterned(int), code, debug_output, reloc_info),
         .eu_payload => |eu_payload| try lowerParentPtr(
             bin_file,
             src_loc,
@@ -910,11 +857,12 @@ pub const GenResult = union(enum) {
 fn genDeclRef(
     lf: *link.File,
     src_loc: Module.SrcLoc,
-    tv: TypedValue,
+    val: Value,
     ptr_decl_index: InternPool.DeclIndex,
 ) CodeGenError!GenResult {
     const zcu = lf.comp.module.?;
-    log.debug("genDeclRef: ty = {}, val = {}", .{ tv.ty.fmt(zcu), tv.val.fmtValue(tv.ty, zcu) });
+    const ty = val.typeOf(zcu);
+    log.debug("genDeclRef: val = {}", .{val.fmtValue(ty, zcu)});
 
     const ptr_decl = zcu.declPtr(ptr_decl_index);
     const namespace = zcu.namespacePtr(ptr_decl.src_namespace);
@@ -945,12 +893,12 @@ fn genDeclRef(
     const gpa = comp.gpa;
 
     // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
-    if (tv.ty.castPtrToFn(zcu)) |fn_ty| {
+    if (ty.castPtrToFn(zcu)) |fn_ty| {
         if (zcu.typeToFunc(fn_ty).?.is_generic) {
             return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(zcu).toByteUnitsOptional().? });
         }
-    } else if (tv.ty.zigTypeTag(zcu) == .Pointer) {
-        const elem_ty = tv.ty.elemType2(zcu);
+    } else if (ty.zigTypeTag(zcu) == .Pointer) {
+        const elem_ty = ty.elemType2(zcu);
         if (!elem_ty.hasRuntimeBits(zcu)) {
             return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(zcu).toByteUnitsOptional().? });
         }
@@ -958,7 +906,7 @@ fn genDeclRef(
 
     const decl_namespace = zcu.namespacePtr(decl.src_namespace);
     const single_threaded = decl_namespace.file_scope.mod.single_threaded;
-    const is_threadlocal = tv.val.isPtrToThreadLocal(zcu) and !single_threaded;
+    const is_threadlocal = val.isPtrToThreadLocal(zcu) and !single_threaded;
     const is_extern = decl.isExtern(zcu);
 
     if (lf.cast(link.File.Elf)) |elf_file| {
@@ -1023,14 +971,14 @@ fn genDeclRef(
 fn genUnnamedConst(
     lf: *link.File,
     src_loc: Module.SrcLoc,
-    tv: TypedValue,
+    val: Value,
     owner_decl_index: InternPool.DeclIndex,
 ) CodeGenError!GenResult {
     const zcu = lf.comp.module.?;
     const gpa = lf.comp.gpa;
-    log.debug("genUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmt(zcu), tv.val.fmtValue(tv.ty, zcu) });
+    log.debug("genUnnamedConst: val = {}", .{val.fmtValue(val.typeOf(zcu), zcu)});
 
-    const local_sym_index = lf.lowerUnnamedConst(tv, owner_decl_index) catch |err| {
+    const local_sym_index = lf.lowerUnnamedConst(val, owner_decl_index) catch |err| {
         return GenResult.fail(gpa, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)});
     };
     switch (lf.tag) {
@@ -1062,18 +1010,15 @@ fn genUnnamedConst(
 pub fn genTypedValue(
     lf: *link.File,
     src_loc: Module.SrcLoc,
-    arg_tv: TypedValue,
+    val: Value,
     owner_decl_index: InternPool.DeclIndex,
 ) CodeGenError!GenResult {
     const zcu = lf.comp.module.?;
-    const typed_value = arg_tv;
+    const ty = val.typeOf(zcu);
 
-    log.debug("genTypedValue: ty = {}, val = {}", .{
-        typed_value.ty.fmt(zcu),
-        typed_value.val.fmtValue(typed_value.ty, zcu),
-    });
+    log.debug("genTypedValue: val = {}", .{val.fmtValue(ty, zcu)});
 
-    if (typed_value.val.isUndef(zcu))
+    if (val.isUndef(zcu))
         return GenResult.mcv(.undef);
 
     const owner_decl = zcu.declPtr(owner_decl_index);
@@ -1081,85 +1026,92 @@ pub fn genTypedValue(
     const target = namespace.file_scope.mod.resolved_target.result;
     const ptr_bits = target.ptrBitWidth();
 
-    if (!typed_value.ty.isSlice(zcu)) switch (zcu.intern_pool.indexToKey(typed_value.val.toIntern())) {
+    if (!ty.isSlice(zcu)) switch (zcu.intern_pool.indexToKey(val.toIntern())) {
         .ptr => |ptr| switch (ptr.addr) {
-            .decl => |decl| return genDeclRef(lf, src_loc, typed_value, decl),
+            .decl => |decl| return genDeclRef(lf, src_loc, val, decl),
             else => {},
         },
         else => {},
     };
 
-    switch (typed_value.ty.zigTypeTag(zcu)) {
+    switch (ty.zigTypeTag(zcu)) {
         .Void => return GenResult.mcv(.none),
-        .Pointer => switch (typed_value.ty.ptrSize(zcu)) {
+        .Pointer => switch (ty.ptrSize(zcu)) {
             .Slice => {},
-            else => switch (typed_value.val.toIntern()) {
+            else => switch (val.toIntern()) {
                 .null_value => {
                     return GenResult.mcv(.{ .immediate = 0 });
                 },
                 .none => {},
-                else => switch (zcu.intern_pool.indexToKey(typed_value.val.toIntern())) {
+                else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
                     .int => {
-                        return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(zcu) });
+                        return GenResult.mcv(.{ .immediate = val.toUnsignedInt(zcu) });
                     },
                     else => {},
                 },
             },
         },
         .Int => {
-            const info = typed_value.ty.intInfo(zcu);
+            const info = ty.intInfo(zcu);
             if (info.bits <= ptr_bits) {
                 const unsigned = switch (info.signedness) {
-                    .signed => @as(u64, @bitCast(typed_value.val.toSignedInt(zcu))),
-                    .unsigned => typed_value.val.toUnsignedInt(zcu),
+                    .signed => @as(u64, @bitCast(val.toSignedInt(zcu))),
+                    .unsigned => val.toUnsignedInt(zcu),
                 };
                 return GenResult.mcv(.{ .immediate = unsigned });
             }
         },
         .Bool => {
-            return GenResult.mcv(.{ .immediate = @intFromBool(typed_value.val.toBool()) });
+            return GenResult.mcv(.{ .immediate = @intFromBool(val.toBool()) });
         },
         .Optional => {
-            if (typed_value.ty.isPtrLikeOptional(zcu)) {
-                return genTypedValue(lf, src_loc, .{
-                    .ty = typed_value.ty.optionalChild(zcu),
-                    .val = typed_value.val.optionalValue(zcu) orelse return GenResult.mcv(.{ .immediate = 0 }),
-                }, owner_decl_index);
-            } else if (typed_value.ty.abiSize(zcu) == 1) {
-                return GenResult.mcv(.{ .immediate = @intFromBool(!typed_value.val.isNull(zcu)) });
+            if (ty.isPtrLikeOptional(zcu)) {
+                return genTypedValue(
+                    lf,
+                    src_loc,
+                    val.optionalValue(zcu) orelse return GenResult.mcv(.{ .immediate = 0 }),
+                    owner_decl_index,
+                );
+            } else if (ty.abiSize(zcu) == 1) {
+                return GenResult.mcv(.{ .immediate = @intFromBool(!val.isNull(zcu)) });
             }
         },
         .Enum => {
-            const enum_tag = zcu.intern_pool.indexToKey(typed_value.val.toIntern()).enum_tag;
-            const int_tag_ty = zcu.intern_pool.typeOf(enum_tag.int);
-            return genTypedValue(lf, src_loc, .{
-                .ty = Type.fromInterned(int_tag_ty),
-                .val = Value.fromInterned(enum_tag.int),
-            }, owner_decl_index);
+            const enum_tag = zcu.intern_pool.indexToKey(val.toIntern()).enum_tag;
+            return genTypedValue(
+                lf,
+                src_loc,
+                Value.fromInterned(enum_tag.int),
+                owner_decl_index,
+            );
         },
         .ErrorSet => {
-            const err_name = zcu.intern_pool.indexToKey(typed_value.val.toIntern()).err.name;
+            const err_name = zcu.intern_pool.indexToKey(val.toIntern()).err.name;
             const error_index = zcu.global_error_set.getIndex(err_name).?;
             return GenResult.mcv(.{ .immediate = error_index });
         },
         .ErrorUnion => {
-            const err_type = typed_value.ty.errorUnionSet(zcu);
-            const payload_type = typed_value.ty.errorUnionPayload(zcu);
+            const err_type = ty.errorUnionSet(zcu);
+            const payload_type = ty.errorUnionPayload(zcu);
             if (!payload_type.hasRuntimeBitsIgnoreComptime(zcu)) {
                 // We use the error type directly as the type.
                 const err_int_ty = try zcu.errorIntType();
-                switch (zcu.intern_pool.indexToKey(typed_value.val.toIntern()).error_union.val) {
-                    .err_name => |err_name| return genTypedValue(lf, src_loc, .{
-                        .ty = err_type,
-                        .val = Value.fromInterned((try zcu.intern(.{ .err = .{
+                switch (zcu.intern_pool.indexToKey(val.toIntern()).error_union.val) {
+                    .err_name => |err_name| return genTypedValue(
+                        lf,
+                        src_loc,
+                        Value.fromInterned(try zcu.intern(.{ .err = .{
                             .ty = err_type.toIntern(),
                             .name = err_name,
-                        } }))),
-                    }, owner_decl_index),
-                    .payload => return genTypedValue(lf, src_loc, .{
-                        .ty = err_int_ty,
-                        .val = try zcu.intValue(err_int_ty, 0),
-                    }, owner_decl_index),
+                        } })),
+                        owner_decl_index,
+                    ),
+                    .payload => return genTypedValue(
+                        lf,
+                        src_loc,
+                        try zcu.intValue(err_int_ty, 0),
+                        owner_decl_index,
+                    ),
                 }
             }
         },
@@ -1176,7 +1128,7 @@ pub fn genTypedValue(
         else => {},
     }
 
-    return genUnnamedConst(lf, src_loc, typed_value, owner_decl_index);
+    return genUnnamedConst(lf, src_loc, val, owner_decl_index);
 }
 
 pub fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u64 {
src/link.zig
@@ -17,7 +17,7 @@ const Liveness = @import("Liveness.zig");
 const Module = @import("Module.zig");
 const InternPool = @import("InternPool.zig");
 const Type = @import("type.zig").Type;
-const TypedValue = @import("TypedValue.zig");
+const Value = @import("Value.zig");
 const LlvmObject = @import("codegen/llvm.zig").Object;
 
 /// When adding a new field, remember to update `hashAddSystemLibs`.
@@ -376,14 +376,14 @@ pub const File = struct {
     /// Called from within the CodeGen to lower a local variable instantion as an unnamed
     /// constant. Returns the symbol index of the lowered constant in the read-only section
     /// of the final binary.
-    pub fn lowerUnnamedConst(base: *File, tv: TypedValue, decl_index: InternPool.DeclIndex) UpdateDeclError!u32 {
+    pub fn lowerUnnamedConst(base: *File, val: Value, decl_index: InternPool.DeclIndex) UpdateDeclError!u32 {
         if (build_options.only_c) @compileError("unreachable");
         switch (base.tag) {
             .spirv => unreachable,
             .c => unreachable,
             .nvptx => unreachable,
             inline else => |t| {
-                return @fieldParentPtr(t.Type(), "base", base).lowerUnnamedConst(tv, decl_index);
+                return @fieldParentPtr(t.Type(), "base", base).lowerUnnamedConst(val, decl_index);
             },
         }
     }
src/Module.zig
@@ -3678,20 +3678,21 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
     const address_space_src: LazySrcLoc = .{ .node_offset_var_decl_addrspace = 0 };
     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 };
     const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 };
-    const decl_tv = try sema.resolveFinalDeclValue(&block_scope, init_src, result_ref);
+    const decl_val = try sema.resolveFinalDeclValue(&block_scope, init_src, result_ref);
+    const decl_ty = decl_val.typeOf(mod);
 
     // Note this resolves the type of the Decl, not the value; if this Decl
     // is a struct, for example, this resolves `type` (which needs no resolution),
     // not the struct itself.
-    try sema.resolveTypeLayout(decl_tv.ty);
+    try sema.resolveTypeLayout(decl_ty);
 
     if (decl.kind == .@"usingnamespace") {
-        if (!decl_tv.ty.eql(Type.type, mod)) {
+        if (!decl_ty.eql(Type.type, mod)) {
             return sema.fail(&block_scope, ty_src, "expected type, found {}", .{
-                decl_tv.ty.fmt(mod),
+                decl_ty.fmt(mod),
             });
         }
-        const ty = decl_tv.val.toType();
+        const ty = decl_val.toType();
         if (ty.getNamespace(mod) == null) {
             return sema.fail(&block_scope, ty_src, "type {} has no namespace", .{ty.fmt(mod)});
         }
@@ -3713,10 +3714,10 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
     var queue_linker_work = true;
     var is_func = false;
     var is_inline = false;
-    switch (decl_tv.val.toIntern()) {
+    switch (decl_val.toIntern()) {
         .generic_poison => unreachable,
         .unreachable_value => unreachable,
-        else => switch (ip.indexToKey(decl_tv.val.toIntern())) {
+        else => switch (ip.indexToKey(decl_val.toIntern())) {
             .variable => |variable| {
                 decl.owns_tv = variable.decl == decl_index;
                 queue_linker_work = decl.owns_tv;
@@ -3731,7 +3732,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
             .func => |func| {
                 decl.owns_tv = func.owner_decl == decl_index;
                 queue_linker_work = false;
-                is_inline = decl.owns_tv and decl_tv.ty.fnCallingConvention(mod) == .Inline;
+                is_inline = decl.owns_tv and decl_ty.fnCallingConvention(mod) == .Inline;
                 is_func = decl.owns_tv;
             },
 
@@ -3739,7 +3740,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
         },
     }
 
-    decl.val = decl_tv.val;
+    decl.val = decl_val;
     // Function linksection, align, and addrspace were already set by Sema
     if (!is_func) {
         decl.alignment = blk: {
@@ -3762,7 +3763,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
             break :blk section.toOptional();
         };
         decl.@"addrspace" = blk: {
-            const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_tv.val.toIntern())) {
+            const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_val.toIntern())) {
                 .variable => .variable,
                 .extern_func, .func => .function,
                 else => .constant,
@@ -3784,10 +3785,10 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
     decl.analysis = .complete;
 
     const result: SemaDeclResult = if (old_has_tv) .{
-        .invalidate_decl_val = !decl_tv.ty.eql(old_ty, mod) or
-            !decl.val.eql(old_val, decl_tv.ty, mod) or
+        .invalidate_decl_val = !decl_ty.eql(old_ty, mod) or
+            !decl.val.eql(old_val, decl_ty, mod) or
             is_inline != old_is_inline,
-        .invalidate_decl_ref = !decl_tv.ty.eql(old_ty, mod) or
+        .invalidate_decl_ref = !decl_ty.eql(old_ty, mod) or
             decl.alignment != old_align or
             decl.@"linksection" != old_linksection or
             decl.@"addrspace" != old_addrspace or
@@ -3797,11 +3798,11 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
         .invalidate_decl_ref = true,
     };
 
-    const has_runtime_bits = queue_linker_work and (is_func or try sema.typeHasRuntimeBits(decl_tv.ty));
+    const has_runtime_bits = queue_linker_work and (is_func or try sema.typeHasRuntimeBits(decl_ty));
     if (has_runtime_bits) {
         // Needed for codegen_decl which will call updateDecl and then the
         // codegen backend wants full access to the Decl Type.
-        try sema.resolveTypeFully(decl_tv.ty);
+        try sema.resolveTypeFully(decl_ty);
 
         try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index });
 
src/Sema.zig
@@ -175,7 +175,6 @@ const Sema = @This();
 const Value = @import("Value.zig");
 const MutableValue = @import("mutable_value.zig").MutableValue;
 const Type = @import("type.zig").Type;
-const TypedValue = @import("TypedValue.zig");
 const Air = @import("Air.zig");
 const Zir = std.zig.Zir;
 const Module = @import("Module.zig");
@@ -1708,7 +1707,7 @@ fn analyzeBodyInner(
                     .needed_comptime_reason = "condition in comptime branch must be comptime-known",
                     .block_comptime_reason = block.comptime_reason,
                 });
-                const inline_body = if (cond.val.toBool()) then_body else else_body;
+                const inline_body = if (cond.toBool()) then_body else else_body;
 
                 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src);
 
@@ -1728,7 +1727,7 @@ fn analyzeBodyInner(
                     .needed_comptime_reason = "condition in comptime branch must be comptime-known",
                     .block_comptime_reason = block.comptime_reason,
                 });
-                const inline_body = if (cond.val.toBool()) then_body else else_body;
+                const inline_body = if (cond.toBool()) then_body else else_body;
 
                 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src);
                 const old_runtime_index = block.runtime_index;
@@ -2179,13 +2178,9 @@ fn resolveInstConst(
     src: LazySrcLoc,
     zir_ref: Zir.Inst.Ref,
     reason: NeededComptimeReason,
-) CompileError!TypedValue {
+) CompileError!Value {
     const air_ref = try sema.resolveInst(zir_ref);
-    const val = try sema.resolveConstDefinedValue(block, src, air_ref, reason);
-    return .{
-        .ty = sema.typeOf(air_ref),
-        .val = val,
-    };
+    return sema.resolveConstDefinedValue(block, src, air_ref, reason);
 }
 
 /// Value Tag may be `undef` or `variable`.
@@ -2194,7 +2189,7 @@ pub fn resolveFinalDeclValue(
     block: *Block,
     src: LazySrcLoc,
     air_ref: Air.Inst.Ref,
-) CompileError!TypedValue {
+) CompileError!Value {
     const val = try sema.resolveValueAllowVariables(air_ref) orelse {
         return sema.failWithNeededComptime(block, src, .{
             .needed_comptime_reason = "global variable initializer must be comptime-known",
@@ -2204,10 +2199,7 @@ pub fn resolveFinalDeclValue(
     if (val.canMutateComptimeVarState(sema.mod)) {
         return sema.fail(block, src, "global variable contains reference to comptime var", .{});
     }
-    return .{
-        .ty = sema.typeOf(air_ref),
-        .val = val,
-    };
+    return val;
 }
 
 fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: NeededComptimeReason) CompileError {
@@ -6414,7 +6406,7 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
     const options = try sema.resolveExportOptions(block, options_src, extra.options);
     if (options.linkage == .internal)
         return;
-    if (operand.val.getFunction(mod)) |function| {
+    if (operand.getFunction(mod)) |function| {
         const decl_index = function.owner_decl;
         return sema.analyzeExport(block, src, options, decl_index);
     }
@@ -6424,7 +6416,7 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
         .src = src,
         .owner_decl = sema.owner_decl_index,
         .src_decl = block.src_decl,
-        .exported = .{ .value = operand.val.toIntern() },
+        .exported = .{ .value = operand.toIntern() },
         .status = .in_progress,
     });
 }
@@ -25831,7 +25823,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
     } else if (extra.data.bits.has_ret_ty_ref) blk: {
         const ret_ty_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
         extra_index += 1;
-        const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref, .{
+        const ret_ty_val = sema.resolveInstConst(block, ret_src, ret_ty_ref, .{
             .needed_comptime_reason = "return type must be comptime-known",
         }) catch |err| switch (err) {
             error.GenericPoison => {
@@ -25839,8 +25831,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
             },
             else => |e| return e,
         };
-        const ty = ret_ty_tv.val.toType();
-        break :blk ty;
+        break :blk ret_ty_val.toType();
     } else Type.void;
 
     const noalias_bits: u32 = if (extra.data.bits.has_any_noalias) blk: {
src/type.zig
@@ -7,7 +7,6 @@ const Module = @import("Module.zig");
 const Zcu = Module;
 const log = std.log.scoped(.Type);
 const target_util = @import("target.zig");
-const TypedValue = @import("TypedValue.zig");
 const Sema = @import("Sema.zig");
 const InternPool = @import("InternPool.zig");
 const Alignment = InternPool.Alignment;
src/TypedValue.zig
@@ -1,3 +1,6 @@
+//! This type exists only for legacy purposes, and will be removed in the future.
+//! It is a thin wrapper around a `Value` which also, redundantly, stores its `Type`.
+
 const std = @import("std");
 const Type = @import("type.zig").Type;
 const Value = @import("Value.zig");
@@ -12,42 +15,6 @@ const Target = std.Target;
 ty: Type,
 val: Value,
 
-/// Memory management for TypedValue. The main purpose of this type
-/// is to be small and have a deinit() function to free associated resources.
-pub const Managed = struct {
-    /// If the tag value is less than Tag.no_payload_count, then no pointer
-    /// dereference is needed.
-    typed_value: TypedValue,
-    /// If this is `null` then there is no memory management needed.
-    arena: ?*std.heap.ArenaAllocator.State = null,
-
-    pub fn deinit(self: *Managed, allocator: Allocator) void {
-        if (self.arena) |a| a.promote(allocator).deinit();
-        self.* = undefined;
-    }
-};
-
-/// Assumes arena allocation. Does a recursive copy.
-pub fn copy(self: TypedValue, arena: Allocator) error{OutOfMemory}!TypedValue {
-    return TypedValue{
-        .ty = self.ty,
-        .val = try self.val.copy(arena),
-    };
-}
-
-pub fn eql(a: TypedValue, b: TypedValue, mod: *Module) bool {
-    if (a.ty.toIntern() != b.ty.toIntern()) return false;
-    return a.val.eql(b.val, a.ty, mod);
-}
-
-pub fn hash(tv: TypedValue, hasher: *std.hash.Wyhash, mod: *Module) void {
-    return tv.val.hash(tv.ty, hasher, mod);
-}
-
-pub fn intFromEnum(tv: TypedValue, mod: *Module) Allocator.Error!Value {
-    return tv.val.intFromEnum(tv.ty, mod);
-}
-
 const max_aggregate_items = 100;
 const max_string_len = 256;
 
@@ -72,7 +39,6 @@ pub fn format(
     };
 }
 
-/// Prints the Value according to the Type, not according to the Value Tag.
 pub fn print(
     tv: TypedValue,
     writer: anytype,
src/Value.zig
@@ -249,12 +249,12 @@ pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64
                 .int => |int| Value.fromInterned(int).getUnsignedIntAdvanced(mod, opt_sema),
                 .elem => |elem| {
                     const base_addr = (try Value.fromInterned(elem.base).getUnsignedIntAdvanced(mod, opt_sema)) orelse return null;
-                    const elem_ty = Type.fromInterned(mod.intern_pool.typeOf(elem.base)).elemType2(mod);
+                    const elem_ty = Value.fromInterned(elem.base).typeOf(mod).elemType2(mod);
                     return base_addr + elem.index * elem_ty.abiSize(mod);
                 },
                 .field => |field| {
                     const base_addr = (try Value.fromInterned(field.base).getUnsignedIntAdvanced(mod, opt_sema)) orelse return null;
-                    const struct_ty = Type.fromInterned(mod.intern_pool.typeOf(field.base)).childType(mod);
+                    const struct_ty = Value.fromInterned(field.base).typeOf(mod).childType(mod);
                     if (opt_sema) |sema| try sema.resolveTypeLayout(struct_ty);
                     return base_addr + struct_ty.structFieldOffset(@as(usize, @intCast(field.index)), mod);
                 },
@@ -1390,7 +1390,7 @@ pub fn elemPtr(
     };
     switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {
         .ptr => |ptr| switch (ptr.addr) {
-            .elem => |elem| if (Type.fromInterned(mod.intern_pool.typeOf(elem.base)).elemType2(mod).eql(elem_ty, mod))
+            .elem => |elem| if (Value.fromInterned(elem.base).typeOf(mod).elemType2(mod).eql(elem_ty, mod))
                 return Value.fromInterned((try mod.intern(.{ .ptr = .{
                     .ty = elem_ptr_ty.toIntern(),
                     .addr = .{ .elem = .{