Commit 2a245e3b78

mlugg <mlugg@mlugg.co.uk>
2024-03-26 06:51:34
compiler: eliminate TypedValue
The only logic which remained in this file was the Value printing logic. This has been moved into a new `print_value.zig`.
1 parent a61def1
src/arch/x86_64/CodeGen.zig
@@ -17876,11 +17876,8 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
 
         break :result null;
     }) orelse return self.fail("TODO implement airShuffle from {} and {} to {} with {}", .{
-        lhs_ty.fmt(mod), rhs_ty.fmt(mod), dst_ty.fmt(mod),
-        Value.fromInterned(extra.mask).fmtValue(
-            Type.fromInterned(mod.intern_pool.typeOf(extra.mask)),
-            mod,
-        ),
+        lhs_ty.fmt(mod),                              rhs_ty.fmt(mod), dst_ty.fmt(mod),
+        Value.fromInterned(extra.mask).fmtValue(mod),
     });
     return self.finishAir(inst, result, .{ extra.a, extra.b, .none });
 }
src/codegen/spirv.zig
@@ -860,7 +860,7 @@ const DeclGen = struct {
 
         const val = arg_val;
 
-        log.debug("constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(ty, mod) });
+        log.debug("constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(mod) });
         if (val.isUndefDeep(mod)) {
             return self.spv.constUndef(result_ty_ref);
         }
src/codegen.zig
@@ -185,9 +185,7 @@ pub fn generateSymbol(
     const target = mod.getTarget();
     const endian = target.cpu.arch.endian();
 
-    log.debug("generateSymbol: val = {}", .{
-        val.fmtValue(ty, mod),
-    });
+    log.debug("generateSymbol: val = {}", .{val.fmtValue(mod)});
 
     if (val.isUndefDeep(mod)) {
         const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow;
@@ -862,7 +860,7 @@ fn genDeclRef(
 ) CodeGenError!GenResult {
     const zcu = lf.comp.module.?;
     const ty = val.typeOf(zcu);
-    log.debug("genDeclRef: val = {}", .{val.fmtValue(ty, zcu)});
+    log.debug("genDeclRef: val = {}", .{val.fmtValue(zcu)});
 
     const ptr_decl = zcu.declPtr(ptr_decl_index);
     const namespace = zcu.namespacePtr(ptr_decl.src_namespace);
@@ -976,7 +974,7 @@ fn genUnnamedConst(
 ) CodeGenError!GenResult {
     const zcu = lf.comp.module.?;
     const gpa = lf.comp.gpa;
-    log.debug("genUnnamedConst: val = {}", .{val.fmtValue(val.typeOf(zcu), zcu)});
+    log.debug("genUnnamedConst: val = {}", .{val.fmtValue(zcu)});
 
     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)});
@@ -1016,7 +1014,7 @@ pub fn genTypedValue(
     const zcu = lf.comp.module.?;
     const ty = val.typeOf(zcu);
 
-    log.debug("genTypedValue: val = {}", .{val.fmtValue(ty, zcu)});
+    log.debug("genTypedValue: val = {}", .{val.fmtValue(zcu)});
 
     if (val.isUndef(zcu))
         return GenResult.mcv(.undef);
src/print_air.zig
@@ -951,7 +951,7 @@ const Writer = struct {
             const ty = Type.fromInterned(mod.intern_pool.indexToKey(ip_index).typeOf());
             try s.print("<{}, {}>", .{
                 ty.fmt(mod),
-                Value.fromInterned(ip_index).fmtValue(ty, mod),
+                Value.fromInterned(ip_index).fmtValue(mod),
             });
         } else {
             return w.writeInstIndex(s, operand.toIndex().?, dies);
src/TypedValue.zig → src/print_value.zig
@@ -9,17 +9,13 @@ const Module = Zcu;
 const Sema = @import("Sema.zig");
 const InternPool = @import("InternPool.zig");
 const Allocator = std.mem.Allocator;
-const TypedValue = @This();
 const Target = std.Target;
 
-ty: Type,
-val: Value,
-
 const max_aggregate_items = 100;
 const max_string_len = 256;
 
 const FormatContext = struct {
-    tv: TypedValue,
+    val: Value,
     mod: *Module,
 };
 
@@ -31,7 +27,7 @@ pub fn format(
 ) !void {
     _ = options;
     comptime std.debug.assert(fmt.len == 0);
-    return ctx.tv.print(writer, 3, ctx.mod, null) catch |err| switch (err) {
+    return print(ctx.val, writer, 3, ctx.mod, null) catch |err| switch (err) {
         error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
         error.ComptimeBreak, error.ComptimeReturn => unreachable,
         error.AnalysisFail, error.NeededSourceLocation => unreachable, // TODO: re-evaluate when we actually pass `opt_sema`
@@ -40,7 +36,7 @@ pub fn format(
 }
 
 pub fn print(
-    tv: TypedValue,
+    val: Value,
     writer: anytype,
     level: u8,
     mod: *Module,
@@ -48,7 +44,6 @@ pub fn print(
     opt_sema: ?*Sema,
 ) (@TypeOf(writer).Error || Module.CompileError)!void {
     const ip = &mod.intern_pool;
-    const val = tv.val;
     switch (ip.indexToKey(val.toIntern())) {
         .int_type,
         .ptr_type,
@@ -99,10 +94,7 @@ pub fn print(
             .err_name => |err_name| try writer.print("error.{}", .{
                 err_name.fmt(ip),
             }),
-            .payload => |payload| try print(.{
-                .ty = tv.ty.errorUnionPayload(mod),
-                .val = Value.fromInterned(payload),
-            }, writer, level, mod, opt_sema),
+            .payload => |payload| try print(Value.fromInterned(payload), writer, level, mod, opt_sema),
         },
         .enum_literal => |enum_literal| try writer.print(".{}", .{
             enum_literal.fmt(ip),
@@ -117,10 +109,7 @@ pub fn print(
                 try writer.writeAll("@enumFromInt(...)");
             }
             try writer.writeAll("@enumFromInt(");
-            try print(.{
-                .ty = Type.fromInterned(ip.typeOf(enum_tag.int)),
-                .val = Value.fromInterned(enum_tag.int),
-            }, writer, level - 1, mod, opt_sema);
+            try print(Value.fromInterned(enum_tag.int), writer, level - 1, mod, opt_sema);
             try writer.writeAll(")");
         },
         .empty_enum_value => try writer.writeAll("(empty enum value)"),
@@ -139,10 +128,7 @@ pub fn print(
             }
             try printPtr(slice.ptr, writer, false, false, 0, level, mod, opt_sema);
             try writer.writeAll("[0..");
-            try print(.{
-                .ty = Type.usize,
-                .val = Value.fromInterned(slice.len),
-            }, writer, level - 1, mod, opt_sema);
+            try print(Value.fromInterned(slice.len), writer, level - 1, mod, opt_sema);
             try writer.writeAll("]");
         },
         .ptr => {
@@ -159,10 +145,7 @@ pub fn print(
         },
         .opt => |opt| switch (opt.val) {
             .none => try writer.writeAll("null"),
-            else => |payload| try print(.{
-                .ty = tv.ty.childType(mod),
-                .val = Value.fromInterned(payload),
-            }, writer, level, mod, opt_sema),
+            else => |payload| try print(Value.fromInterned(payload), writer, level, mod, opt_sema),
         },
         .aggregate => |aggregate| try printAggregate(val, aggregate, writer, level, mod, opt_sema),
         .un => |un| {
@@ -171,25 +154,15 @@ pub fn print(
                 return;
             }
             if (un.tag == .none) {
-                const backing_ty = try tv.ty.unionBackingType(mod);
+                const backing_ty = try val.typeOf(mod).unionBackingType(mod);
                 try writer.print("@bitCast(@as({}, ", .{backing_ty.fmt(mod)});
-                try print(.{
-                    .ty = backing_ty,
-                    .val = Value.fromInterned(un.val),
-                }, writer, level - 1, mod, opt_sema);
+                try print(Value.fromInterned(un.val), writer, level - 1, mod, opt_sema);
                 try writer.writeAll("))");
             } else {
                 try writer.writeAll(".{ ");
-                try print(.{
-                    .ty = tv.ty.unionTagTypeHypothetical(mod),
-                    .val = Value.fromInterned(un.tag),
-                }, writer, level - 1, mod, opt_sema);
+                try print(Value.fromInterned(un.tag), writer, level - 1, mod, opt_sema);
                 try writer.writeAll(" = ");
-                const field_ty = tv.ty.unionFieldType(Value.fromInterned(un.tag), mod).?;
-                try print(.{
-                    .ty = field_ty,
-                    .val = Value.fromInterned(un.val),
-                }, writer, level - 1, mod, opt_sema);
+                try print(Value.fromInterned(un.val), writer, level - 1, mod, opt_sema);
                 try writer.writeAll(" }");
             }
         },
@@ -221,10 +194,7 @@ fn printAggregate(
                 if (i != 0) try writer.writeAll(", ");
                 const field_name = ty.structFieldName(@intCast(i), zcu).unwrap().?;
                 try writer.print(".{i} = ", .{field_name.fmt(ip)});
-                try print(.{
-                    .ty = ty.structFieldType(i, zcu),
-                    .val = try val.fieldValue(zcu, i),
-                }, writer, level - 1, zcu, opt_sema);
+                try print(try val.fieldValue(zcu, i), writer, level - 1, zcu, opt_sema);
             }
             try writer.writeAll(" }");
             return;
@@ -240,7 +210,6 @@ fn printAggregate(
         else => unreachable,
     }
 
-    const elem_ty = ty.childType(zcu);
     const len = ty.arrayLen(zcu);
 
     try writer.writeAll(".{ ");
@@ -248,10 +217,7 @@ fn printAggregate(
     const max_len = @min(len, max_aggregate_items);
     for (0..max_len) |i| {
         if (i != 0) try writer.writeAll(", ");
-        try print(.{
-            .ty = elem_ty,
-            .val = try val.fieldValue(zcu, i),
-        }, writer, level - 1, zcu, opt_sema);
+        try print(try val.fieldValue(zcu, i), writer, level - 1, zcu, opt_sema);
     }
     if (len > max_aggregate_items) {
         try writer.writeAll(", ...");
@@ -286,17 +252,11 @@ fn printPtr(
             try writer.writeByteNTimes('(', leading_parens);
             if (force_type) {
                 try writer.print("@as({}, @ptrFromInt(", .{Type.fromInterned(ptr.ty).fmt(zcu)});
-                try print(.{
-                    .ty = Type.usize,
-                    .val = Value.fromInterned(int),
-                }, writer, level - 1, zcu, opt_sema);
+                try print(Value.fromInterned(int), writer, level - 1, zcu, opt_sema);
                 try writer.writeAll("))");
             } else {
                 try writer.writeAll("@ptrFromInt(");
-                try print(.{
-                    .ty = Type.usize,
-                    .val = Value.fromInterned(int),
-                }, writer, level - 1, zcu, opt_sema);
+                try print(Value.fromInterned(int), writer, level - 1, zcu, opt_sema);
                 try writer.writeAll(")");
             }
         },
@@ -308,19 +268,13 @@ fn printPtr(
         .anon_decl => |anon| {
             const ty = Type.fromInterned(ip.typeOf(anon.val));
             try writer.print("&@as({}, ", .{ty.fmt(zcu)});
-            try print(.{
-                .ty = ty,
-                .val = Value.fromInterned(anon.val),
-            }, writer, level - 1, zcu, opt_sema);
+            try print(Value.fromInterned(anon.val), writer, level - 1, zcu, opt_sema);
             try writer.writeAll(")");
         },
         .comptime_field => |val| {
             const ty = Type.fromInterned(ip.typeOf(val));
             try writer.print("&@as({}, ", .{ty.fmt(zcu)});
-            try print(.{
-                .ty = ty,
-                .val = Value.fromInterned(val),
-            }, writer, level - 1, zcu, opt_sema);
+            try print(Value.fromInterned(val), writer, level - 1, zcu, opt_sema);
             try writer.writeAll(")");
         },
         .eu_payload => |base| {
src/Sema.zig
@@ -2272,7 +2272,7 @@ fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty:
     if (int_ty.zigTypeTag(mod) == .Vector) {
         const msg = msg: {
             const msg = try sema.errMsg(block, src, "overflow of vector type '{}' with value '{}'", .{
-                int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod),
+                int_ty.fmt(sema.mod), val.fmtValue(sema.mod),
             });
             errdefer msg.destroy(sema.gpa);
             try sema.errNote(block, src, msg, "when computing vector element at index '{d}'", .{vector_index});
@@ -2281,7 +2281,7 @@ fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty:
         return sema.failWithOwnedErrorMsg(block, msg);
     }
     return sema.fail(block, src, "overflow of integer type '{}' with value '{}'", .{
-        int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod),
+        int_ty.fmt(sema.mod), val.fmtValue(sema.mod),
     });
 }
 
@@ -2914,7 +2914,7 @@ fn createAnonymousDeclTypeNamed(
                         return sema.createAnonymousDeclTypeNamed(block, src, val, .anon, anon_prefix, null);
 
                     if (arg_i != 0) try writer.writeByte(',');
-                    try writer.print("{}", .{arg_val.fmtValue(sema.typeOf(arg), sema.mod)});
+                    try writer.print("{}", .{arg_val.fmtValue(sema.mod)});
 
                     arg_i += 1;
                     continue;
@@ -3186,7 +3186,7 @@ fn zirEnumDecl(
                 }).lazy;
                 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy;
                 const msg = msg: {
-                    const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)});
+                    const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(sema.mod)});
                     errdefer msg.destroy(gpa);
                     try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
                     break :msg msg;
@@ -3206,7 +3206,7 @@ fn zirEnumDecl(
                 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
                 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy;
                 const msg = msg: {
-                    const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)});
+                    const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(sema.mod)});
                     errdefer msg.destroy(gpa);
                     try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
                     break :msg msg;
@@ -3228,7 +3228,7 @@ fn zirEnumDecl(
                 .range = if (has_tag_value) .value else .name,
             }).lazy;
             const msg = try sema.errMsg(block, value_src, "enumeration value '{}' too large for type '{}'", .{
-                last_tag_val.?.fmtValue(int_tag_ty, mod), int_tag_ty.fmt(mod),
+                last_tag_val.?.fmtValue(mod), int_tag_ty.fmt(mod),
             });
             return sema.failWithOwnedErrorMsg(block, msg);
         }
@@ -4381,10 +4381,10 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
                             .input_index = len_idx,
                         } };
                         try sema.errNote(block, a_src, msg, "length {} here", .{
-                            v.fmtValue(Type.usize, sema.mod),
+                            v.fmtValue(sema.mod),
                         });
                         try sema.errNote(block, arg_src, msg, "length {} here", .{
-                            arg_val.fmtValue(Type.usize, sema.mod),
+                            arg_val.fmtValue(sema.mod),
                         });
                         break :msg msg;
                     };
@@ -5794,7 +5794,7 @@ fn zirCompileLog(
         const arg_ty = sema.typeOf(arg);
         if (try sema.resolveValueResolveLazy(arg)) |val| {
             try writer.print("@as({}, {})", .{
-                arg_ty.fmt(mod), val.fmtValue(arg_ty, mod),
+                arg_ty.fmt(mod), val.fmtValue(mod),
             });
         } else {
             try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(mod)});
@@ -8880,7 +8880,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
                 return Air.internedToRef((try mod.getCoerced(int_val, dest_ty)).toIntern());
             }
             return sema.fail(block, src, "int value '{}' out of range of non-exhaustive enum '{}'", .{
-                int_val.fmtValue(sema.typeOf(operand), mod), dest_ty.fmt(mod),
+                int_val.fmtValue(mod), dest_ty.fmt(mod),
             });
         }
         if (int_val.isUndef(mod)) {
@@ -8888,7 +8888,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
         }
         if (!(try sema.enumHasInt(dest_ty, int_val))) {
             return sema.fail(block, src, "enum '{}' has no tag with value '{}'", .{
-                dest_ty.fmt(mod), int_val.fmtValue(sema.typeOf(operand), mod),
+                dest_ty.fmt(mod), int_val.fmtValue(mod),
             });
         }
         return Air.internedToRef((try mod.getCoerced(int_val, dest_ty)).toIntern());
@@ -13934,7 +13934,7 @@ fn zirShl(
                     const rhs_elem = try rhs_val.elemValue(mod, i);
                     if (rhs_elem.compareHetero(.gte, bit_value, mod)) {
                         return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{
-                            rhs_elem.fmtValue(scalar_ty, mod),
+                            rhs_elem.fmtValue(mod),
                             i,
                             scalar_ty.fmt(mod),
                         });
@@ -13942,7 +13942,7 @@ fn zirShl(
                 }
             } else if (rhs_val.compareHetero(.gte, bit_value, mod)) {
                 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{
-                    rhs_val.fmtValue(scalar_ty, mod),
+                    rhs_val.fmtValue(mod),
                     scalar_ty.fmt(mod),
                 });
             }
@@ -13953,14 +13953,14 @@ fn zirShl(
                 const rhs_elem = try rhs_val.elemValue(mod, i);
                 if (rhs_elem.compareHetero(.lt, try mod.intValue(scalar_rhs_ty, 0), mod)) {
                     return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{
-                        rhs_elem.fmtValue(scalar_ty, mod),
+                        rhs_elem.fmtValue(mod),
                         i,
                     });
                 }
             }
         } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) {
             return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{
-                rhs_val.fmtValue(scalar_ty, mod),
+                rhs_val.fmtValue(mod),
             });
         }
     }
@@ -14099,7 +14099,7 @@ fn zirShr(
                     const rhs_elem = try rhs_val.elemValue(mod, i);
                     if (rhs_elem.compareHetero(.gte, bit_value, mod)) {
                         return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{
-                            rhs_elem.fmtValue(scalar_ty, mod),
+                            rhs_elem.fmtValue(mod),
                             i,
                             scalar_ty.fmt(mod),
                         });
@@ -14107,7 +14107,7 @@ fn zirShr(
                 }
             } else if (rhs_val.compareHetero(.gte, bit_value, mod)) {
                 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{
-                    rhs_val.fmtValue(scalar_ty, mod),
+                    rhs_val.fmtValue(mod),
                     scalar_ty.fmt(mod),
                 });
             }
@@ -14118,14 +14118,14 @@ fn zirShr(
                 const rhs_elem = try rhs_val.elemValue(mod, i);
                 if (rhs_elem.compareHetero(.lt, try mod.intValue(rhs_ty.childType(mod), 0), mod)) {
                     return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{
-                        rhs_elem.fmtValue(scalar_ty, mod),
+                        rhs_elem.fmtValue(mod),
                         i,
                     });
                 }
             }
         } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) {
             return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{
-                rhs_val.fmtValue(scalar_ty, mod),
+                rhs_val.fmtValue(mod),
             });
         }
         if (maybe_lhs_val) |lhs_val| {
@@ -15046,7 +15046,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
                 block,
                 src,
                 "ambiguous coercion of division operands '{}' and '{}'; non-zero remainder '{}'",
-                .{ lhs_ty.fmt(mod), rhs_ty.fmt(mod), rem.fmtValue(resolved_type, mod) },
+                .{ lhs_ty.fmt(mod), rhs_ty.fmt(mod), rem.fmtValue(mod) },
             );
         }
     }
@@ -21094,7 +21094,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
             const enum_decl = mod.declPtr(enum_decl_index);
             const msg = msg: {
                 const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{}'", .{
-                    val.fmtValue(enum_ty, sema.mod), enum_decl.name.fmt(ip),
+                    val.fmtValue(sema.mod), enum_decl.name.fmt(ip),
                 });
                 errdefer msg.destroy(sema.gpa);
                 try mod.errNoteNonLazy(enum_decl.srcLoc(mod), msg, "declared here", .{});
@@ -21729,7 +21729,7 @@ fn reifyEnum(
             // TODO: better source location
             return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{
                 field_name.fmt(ip),
-                field_value_val.fmtValue(Type.comptime_int, mod),
+                field_value_val.fmtValue(mod),
                 tag_ty.fmt(mod),
             });
         }
@@ -21745,7 +21745,7 @@ fn reifyEnum(
                     break :msg msg;
                 },
                 .value => msg: {
-                    const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{field_value_val.fmtValue(Type.comptime_int, mod)});
+                    const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{field_value_val.fmtValue(mod)});
                     errdefer msg.destroy(gpa);
                     _ = conflict.prev_field_idx; // TODO: this note is incorrect
                     try sema.errNote(block, src, msg, "other enum tag value here", .{});
@@ -22883,12 +22883,12 @@ fn ptrCastFull(
             return sema.failWithOwnedErrorMsg(block, msg: {
                 const msg = if (src_info.sentinel == .none) blk: {
                     break :blk try sema.errMsg(block, src, "destination pointer requires '{}' sentinel", .{
-                        Value.fromInterned(dest_info.sentinel).fmtValue(Type.fromInterned(dest_info.child), mod),
+                        Value.fromInterned(dest_info.sentinel).fmtValue(mod),
                     });
                 } else blk: {
                     break :blk try sema.errMsg(block, src, "pointer sentinel '{}' cannot coerce into pointer sentinel '{}'", .{
-                        Value.fromInterned(src_info.sentinel).fmtValue(Type.fromInterned(src_info.child), mod),
-                        Value.fromInterned(dest_info.sentinel).fmtValue(Type.fromInterned(dest_info.child), mod),
+                        Value.fromInterned(src_info.sentinel).fmtValue(mod),
+                        Value.fromInterned(dest_info.sentinel).fmtValue(mod),
                     });
                 };
                 errdefer msg.destroy(sema.gpa);
@@ -25285,10 +25285,10 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
                         const msg = try sema.errMsg(block, src, "non-matching @memcpy lengths", .{});
                         errdefer msg.destroy(sema.gpa);
                         try sema.errNote(block, dest_src, msg, "length {} here", .{
-                            dest_len_val.fmtValue(Type.usize, sema.mod),
+                            dest_len_val.fmtValue(sema.mod),
                         });
                         try sema.errNote(block, src_src, msg, "length {} here", .{
-                            src_len_val.fmtValue(Type.usize, sema.mod),
+                            src_len_val.fmtValue(sema.mod),
                         });
                         break :msg msg;
                     };
@@ -29162,7 +29162,7 @@ fn coerceExtra(
                     // comptime-known integer to other number
                     if (!(try sema.intFitsInType(val, dest_ty, null))) {
                         if (!opts.report_err) return error.NotCoercible;
-                        return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) });
+                        return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(mod), val.fmtValue(mod) });
                     }
                     return switch (mod.intern_pool.indexToKey(val.toIntern())) {
                         .undef => try mod.undefRef(dest_ty),
@@ -29207,7 +29207,7 @@ fn coerceExtra(
                             block,
                             inst_src,
                             "type '{}' cannot represent float value '{}'",
-                            .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) },
+                            .{ dest_ty.fmt(mod), val.fmtValue(mod) },
                         );
                     }
                     return Air.internedToRef(result_val.toIntern());
@@ -29578,11 +29578,11 @@ const InMemoryCoercionResult = union(enum) {
             .array_sentinel => |sentinel| {
                 if (sentinel.actual.toIntern() != .unreachable_value) {
                     try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{
-                        sentinel.actual.fmtValue(sentinel.ty, mod), sentinel.wanted.fmtValue(sentinel.ty, mod),
+                        sentinel.actual.fmtValue(mod), sentinel.wanted.fmtValue(mod),
                     });
                 } else {
                     try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{
-                        sentinel.wanted.fmtValue(sentinel.ty, mod),
+                        sentinel.wanted.fmtValue(mod),
                     });
                 }
                 break;
@@ -29704,11 +29704,11 @@ const InMemoryCoercionResult = union(enum) {
             .ptr_sentinel => |sentinel| {
                 if (sentinel.actual.toIntern() != .unreachable_value) {
                     try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{
-                        sentinel.actual.fmtValue(sentinel.ty, mod), sentinel.wanted.fmtValue(sentinel.ty, mod),
+                        sentinel.actual.fmtValue(mod), sentinel.wanted.fmtValue(mod),
                     });
                 } else {
                     try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{
-                        sentinel.wanted.fmtValue(sentinel.ty, mod),
+                        sentinel.wanted.fmtValue(mod),
                     });
                 }
                 break;
@@ -31708,7 +31708,7 @@ fn coerceEnumToUnion(
     if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| {
         const field_index = union_ty.unionTagFieldIndex(val, sema.mod) orelse {
             return sema.fail(block, inst_src, "union '{}' has no tag with value '{}'", .{
-                union_ty.fmt(sema.mod), val.fmtValue(tag_ty, sema.mod),
+                union_ty.fmt(sema.mod), val.fmtValue(sema.mod),
             });
         };
 
@@ -32928,8 +32928,8 @@ fn analyzeSlice(
                                     msg,
                                     "expected '{}', found '{}'",
                                     .{
-                                        Value.zero_comptime_int.fmtValue(Type.comptime_int, mod),
-                                        start_value.fmtValue(Type.comptime_int, mod),
+                                        Value.zero_comptime_int.fmtValue(mod),
+                                        start_value.fmtValue(mod),
                                     },
                                 );
                                 break :msg msg;
@@ -32945,8 +32945,8 @@ fn analyzeSlice(
                                     msg,
                                     "expected '{}', found '{}'",
                                     .{
-                                        Value.one_comptime_int.fmtValue(Type.comptime_int, mod),
-                                        end_value.fmtValue(Type.comptime_int, mod),
+                                        Value.one_comptime_int.fmtValue(mod),
+                                        end_value.fmtValue(mod),
                                     },
                                 );
                                 break :msg msg;
@@ -32959,7 +32959,7 @@ fn analyzeSlice(
                                 block,
                                 end_src,
                                 "end index {} out of bounds for slice of single-item pointer",
-                                .{end_value.fmtValue(Type.comptime_int, mod)},
+                                .{end_value.fmtValue(mod)},
                             );
                         }
                     }
@@ -33054,8 +33054,8 @@ fn analyzeSlice(
                             end_src,
                             "end index {} out of bounds for array of length {}{s}",
                             .{
-                                end_val.fmtValue(Type.usize, mod),
-                                len_val.fmtValue(Type.usize, mod),
+                                end_val.fmtValue(mod),
+                                len_val.fmtValue(mod),
                                 sentinel_label,
                             },
                         );
@@ -33099,7 +33099,7 @@ fn analyzeSlice(
                                 end_src,
                                 "end index {} out of bounds for slice of length {d}{s}",
                                 .{
-                                    end_val.fmtValue(Type.usize, mod),
+                                    end_val.fmtValue(mod),
                                     try slice_val.sliceLen(sema),
                                     sentinel_label,
                                 },
@@ -33159,8 +33159,8 @@ fn analyzeSlice(
                     start_src,
                     "start index {} is larger than end index {}",
                     .{
-                        start_val.fmtValue(Type.usize, mod),
-                        end_val.fmtValue(Type.usize, mod),
+                        start_val.fmtValue(mod),
+                        end_val.fmtValue(mod),
                     },
                 );
             }
@@ -33198,8 +33198,8 @@ fn analyzeSlice(
                         const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{});
                         errdefer msg.destroy(sema.gpa);
                         try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{
-                            expected_sentinel.fmtValue(elem_ty, mod),
-                            actual_sentinel.fmtValue(elem_ty, mod),
+                            expected_sentinel.fmtValue(mod),
+                            actual_sentinel.fmtValue(mod),
                         });
 
                         break :msg msg;
@@ -37213,7 +37213,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
                 const field_src = mod.fieldSrcLoc(union_type.decl, .{ .index = field_i }).lazy;
                 const other_field_src = mod.fieldSrcLoc(union_type.decl, .{ .index = gop.index }).lazy;
                 const msg = msg: {
-                    const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{enum_tag_val.fmtValue(int_tag_ty, mod)});
+                    const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{enum_tag_val.fmtValue(mod)});
                     errdefer msg.destroy(gpa);
                     try sema.errNote(&block_scope, other_field_src, msg, "other occurrence here", .{});
                     break :msg msg;
@@ -38566,18 +38566,17 @@ fn intFromFloat(
 ) CompileError!Value {
     const mod = sema.mod;
     if (float_ty.zigTypeTag(mod) == .Vector) {
-        const elem_ty = float_ty.scalarType(mod);
         const result_data = try sema.arena.alloc(InternPool.Index, float_ty.vectorLen(mod));
         for (result_data, 0..) |*scalar, i| {
             const elem_val = try val.elemValue(sema.mod, i);
-            scalar.* = (try sema.intFromFloatScalar(block, src, elem_val, elem_ty, int_ty.scalarType(mod), mode)).toIntern();
+            scalar.* = (try sema.intFromFloatScalar(block, src, elem_val, int_ty.scalarType(mod), mode)).toIntern();
         }
         return Value.fromInterned((try mod.intern(.{ .aggregate = .{
             .ty = int_ty.toIntern(),
             .storage = .{ .elems = result_data },
         } })));
     }
-    return sema.intFromFloatScalar(block, src, val, float_ty, int_ty, mode);
+    return sema.intFromFloatScalar(block, src, val, int_ty, mode);
 }
 
 // float is expected to be finite and non-NaN
@@ -38610,7 +38609,6 @@ fn intFromFloatScalar(
     block: *Block,
     src: LazySrcLoc,
     val: Value,
-    float_ty: Type,
     int_ty: Type,
     mode: IntFromFloatMode,
 ) CompileError!Value {
@@ -38622,7 +38620,7 @@ fn intFromFloatScalar(
         block,
         src,
         "fractional component prevents float value '{}' from coercion to type '{}'",
-        .{ val.fmtValue(float_ty, mod), int_ty.fmt(mod) },
+        .{ val.fmtValue(mod), int_ty.fmt(mod) },
     );
 
     const float = val.toFloat(f128, mod);
@@ -38644,7 +38642,7 @@ fn intFromFloatScalar(
 
     if (!(try sema.intFitsInType(cti_result, int_ty, null))) {
         return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{
-            val.fmtValue(float_ty, sema.mod), int_ty.fmt(sema.mod),
+            val.fmtValue(sema.mod), int_ty.fmt(sema.mod),
         });
     }
     return mod.getCoerced(cti_result, int_ty);
src/type.zig
@@ -187,8 +187,8 @@ pub const Type = struct {
 
                 if (info.sentinel != .none) switch (info.flags.size) {
                     .One, .C => unreachable,
-                    .Many => try writer.print("[*:{}]", .{Value.fromInterned(info.sentinel).fmtValue(Type.fromInterned(info.child), mod)}),
-                    .Slice => try writer.print("[:{}]", .{Value.fromInterned(info.sentinel).fmtValue(Type.fromInterned(info.child), mod)}),
+                    .Many => try writer.print("[*:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod)}),
+                    .Slice => try writer.print("[:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod)}),
                 } else switch (info.flags.size) {
                     .One => try writer.writeAll("*"),
                     .Many => try writer.writeAll("[*]"),
@@ -234,7 +234,7 @@ pub const Type = struct {
                 } else {
                     try writer.print("[{d}:{}]", .{
                         array_type.len,
-                        Value.fromInterned(array_type.sentinel).fmtValue(Type.fromInterned(array_type.child), mod),
+                        Value.fromInterned(array_type.sentinel).fmtValue(mod),
                     });
                     try print(Type.fromInterned(array_type.child), writer, mod);
                 }
@@ -352,7 +352,7 @@ pub const Type = struct {
                     try print(Type.fromInterned(field_ty), writer, mod);
 
                     if (val != .none) {
-                        try writer.print(" = {}", .{Value.fromInterned(val).fmtValue(Type.fromInterned(field_ty), mod)});
+                        try writer.print(" = {}", .{Value.fromInterned(val).fmtValue(mod)});
                     }
                 }
                 try writer.writeAll("}");
src/Value.zig
@@ -8,9 +8,9 @@ const Target = std.Target;
 const Allocator = std.mem.Allocator;
 const Zcu = @import("Module.zig");
 const Module = Zcu;
-const TypedValue = @import("TypedValue.zig");
 const Sema = @import("Sema.zig");
 const InternPool = @import("InternPool.zig");
+const print_value = @import("print_value.zig");
 const Value = @This();
 
 ip_index: InternPool.Index,
@@ -39,9 +39,9 @@ pub fn fmtDebug(val: Value) std.fmt.Formatter(dump) {
     return .{ .data = val };
 }
 
-pub fn fmtValue(val: Value, ty: Type, mod: *Module) std.fmt.Formatter(TypedValue.format) {
+pub fn fmtValue(val: Value, mod: *Module) std.fmt.Formatter(print_value.format) {
     return .{ .data = .{
-        .tv = .{ .ty = ty, .val = val },
+        .val = val,
         .mod = mod,
     } };
 }
CMakeLists.txt
@@ -526,7 +526,6 @@ set(ZIG_STAGE2_SOURCES
     "${CMAKE_SOURCE_DIR}/src/Package/Fetch.zig"
     "${CMAKE_SOURCE_DIR}/src/RangeSet.zig"
     "${CMAKE_SOURCE_DIR}/src/Sema.zig"
-    "${CMAKE_SOURCE_DIR}/src/TypedValue.zig"
     "${CMAKE_SOURCE_DIR}/src/Value.zig"
     "${CMAKE_SOURCE_DIR}/src/arch/aarch64/CodeGen.zig"
     "${CMAKE_SOURCE_DIR}/src/arch/aarch64/Emit.zig"
@@ -634,9 +633,11 @@ set(ZIG_STAGE2_SOURCES
     "${CMAKE_SOURCE_DIR}/src/main.zig"
     "${CMAKE_SOURCE_DIR}/src/mingw.zig"
     "${CMAKE_SOURCE_DIR}/src/musl.zig"
+    "${CMAKE_SOURCE_DIR}/src/mutable_value.zig"
     "${CMAKE_SOURCE_DIR}/src/print_air.zig"
     "${CMAKE_SOURCE_DIR}/src/print_env.zig"
     "${CMAKE_SOURCE_DIR}/src/print_targets.zig"
+    "${CMAKE_SOURCE_DIR}/src/print_value.zig"
     "${CMAKE_SOURCE_DIR}/src/print_zir.zig"
     "${CMAKE_SOURCE_DIR}/src/register_manager.zig"
     "${CMAKE_SOURCE_DIR}/src/target.zig"