Commit 9afa974183

Jacob Young <jacobly0@users.noreply.github.com>
2023-05-26 05:48:39
InternPool: fix enough crashes to run `build-obj` on a simple program
1 parent 9a738c0
src/codegen/llvm.zig
@@ -3267,21 +3267,28 @@ pub const DeclGen = struct {
                 return llvm_ty.constInt(kv.value, .False);
             },
             .error_union => |error_union| {
+                const err_tv: TypedValue = switch (error_union.val) {
+                    .err_name => |err_name| .{
+                        .ty = tv.ty.errorUnionSet(mod),
+                        .val = (try mod.intern(.{ .err = .{
+                            .ty = tv.ty.errorUnionSet(mod).toIntern(),
+                            .name = err_name,
+                        } })).toValue(),
+                    },
+                    .payload => .{
+                        .ty = Type.err_int,
+                        .val = try mod.intValue(Type.err_int, 0),
+                    },
+                };
                 const payload_type = tv.ty.errorUnionPayload(mod);
-                const is_pl = tv.val.errorUnionIsPayload(mod);
-
                 if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) {
                     // We use the error type directly as the type.
-                    const err_val = if (!is_pl) tv.val else try mod.intValue(Type.err_int, 0);
-                    return dg.lowerValue(.{ .ty = Type.anyerror, .val = err_val });
+                    return dg.lowerValue(err_tv);
                 }
 
                 const payload_align = payload_type.abiAlignment(mod);
-                const error_align = Type.anyerror.abiAlignment(mod);
-                const llvm_error_value = try dg.lowerValue(.{
-                    .ty = Type.anyerror,
-                    .val = if (is_pl) try mod.intValue(Type.err_int, 0) else tv.val,
-                });
+                const error_align = err_tv.ty.abiAlignment(mod);
+                const llvm_error_value = try dg.lowerValue(err_tv);
                 const llvm_payload_value = try dg.lowerValue(.{
                     .ty = payload_type,
                     .val = switch (error_union.val) {
src/Liveness/Verify.zig
@@ -61,10 +61,10 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
             .work_item_id,
             .work_group_size,
             .work_group_id,
-            => try self.verifyInst(inst, .{ .none, .none, .none }),
+            => try self.verifyInstOperands(inst, .{ .none, .none, .none }),
 
             .trap, .unreach => {
-                try self.verifyInst(inst, .{ .none, .none, .none });
+                try self.verifyInstOperands(inst, .{ .none, .none, .none });
                 // This instruction terminates the function, so everything should be dead
                 if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst});
             },
@@ -113,7 +113,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
             .c_va_copy,
             => {
                 const ty_op = data[inst].ty_op;
-                try self.verifyInst(inst, .{ ty_op.operand, .none, .none });
+                try self.verifyInstOperands(inst, .{ ty_op.operand, .none, .none });
             },
             .is_null,
             .is_non_null,
@@ -149,13 +149,13 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
             .c_va_end,
             => {
                 const un_op = data[inst].un_op;
-                try self.verifyInst(inst, .{ un_op, .none, .none });
+                try self.verifyInstOperands(inst, .{ un_op, .none, .none });
             },
             .ret,
             .ret_load,
             => {
                 const un_op = data[inst].un_op;
-                try self.verifyInst(inst, .{ un_op, .none, .none });
+                try self.verifyInstOperands(inst, .{ un_op, .none, .none });
                 // This instruction terminates the function, so everything should be dead
                 if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst});
             },
@@ -164,36 +164,36 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
             .wasm_memory_grow,
             => {
                 const pl_op = data[inst].pl_op;
-                try self.verifyInst(inst, .{ pl_op.operand, .none, .none });
+                try self.verifyInstOperands(inst, .{ pl_op.operand, .none, .none });
             },
             .prefetch => {
                 const prefetch = data[inst].prefetch;
-                try self.verifyInst(inst, .{ prefetch.ptr, .none, .none });
+                try self.verifyInstOperands(inst, .{ prefetch.ptr, .none, .none });
             },
             .reduce,
             .reduce_optimized,
             => {
                 const reduce = data[inst].reduce;
-                try self.verifyInst(inst, .{ reduce.operand, .none, .none });
+                try self.verifyInstOperands(inst, .{ reduce.operand, .none, .none });
             },
             .union_init => {
                 const ty_pl = data[inst].ty_pl;
                 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
-                try self.verifyInst(inst, .{ extra.init, .none, .none });
+                try self.verifyInstOperands(inst, .{ extra.init, .none, .none });
             },
             .struct_field_ptr, .struct_field_val => {
                 const ty_pl = data[inst].ty_pl;
                 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
-                try self.verifyInst(inst, .{ extra.struct_operand, .none, .none });
+                try self.verifyInstOperands(inst, .{ extra.struct_operand, .none, .none });
             },
             .field_parent_ptr => {
                 const ty_pl = data[inst].ty_pl;
                 const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
-                try self.verifyInst(inst, .{ extra.field_ptr, .none, .none });
+                try self.verifyInstOperands(inst, .{ extra.field_ptr, .none, .none });
             },
             .atomic_load => {
                 const atomic_load = data[inst].atomic_load;
-                try self.verifyInst(inst, .{ atomic_load.ptr, .none, .none });
+                try self.verifyInstOperands(inst, .{ atomic_load.ptr, .none, .none });
             },
 
             // binary
@@ -263,7 +263,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
             .memcpy,
             => {
                 const bin_op = data[inst].bin_op;
-                try self.verifyInst(inst, .{ bin_op.lhs, bin_op.rhs, .none });
+                try self.verifyInstOperands(inst, .{ bin_op.lhs, bin_op.rhs, .none });
             },
             .add_with_overflow,
             .sub_with_overflow,
@@ -277,48 +277,48 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
             => {
                 const ty_pl = data[inst].ty_pl;
                 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
-                try self.verifyInst(inst, .{ extra.lhs, extra.rhs, .none });
+                try self.verifyInstOperands(inst, .{ extra.lhs, extra.rhs, .none });
             },
             .shuffle => {
                 const ty_pl = data[inst].ty_pl;
                 const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data;
-                try self.verifyInst(inst, .{ extra.a, extra.b, .none });
+                try self.verifyInstOperands(inst, .{ extra.a, extra.b, .none });
             },
             .cmp_vector,
             .cmp_vector_optimized,
             => {
                 const ty_pl = data[inst].ty_pl;
                 const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;
-                try self.verifyInst(inst, .{ extra.lhs, extra.rhs, .none });
+                try self.verifyInstOperands(inst, .{ extra.lhs, extra.rhs, .none });
             },
             .atomic_rmw => {
                 const pl_op = data[inst].pl_op;
                 const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data;
-                try self.verifyInst(inst, .{ pl_op.operand, extra.operand, .none });
+                try self.verifyInstOperands(inst, .{ pl_op.operand, extra.operand, .none });
             },
 
             // ternary
             .select => {
                 const pl_op = data[inst].pl_op;
                 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
-                try self.verifyInst(inst, .{ pl_op.operand, extra.lhs, extra.rhs });
+                try self.verifyInstOperands(inst, .{ pl_op.operand, extra.lhs, extra.rhs });
             },
             .mul_add => {
                 const pl_op = data[inst].pl_op;
                 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
-                try self.verifyInst(inst, .{ extra.lhs, extra.rhs, pl_op.operand });
+                try self.verifyInstOperands(inst, .{ extra.lhs, extra.rhs, pl_op.operand });
             },
             .vector_store_elem => {
                 const vector_store_elem = data[inst].vector_store_elem;
                 const extra = self.air.extraData(Air.Bin, vector_store_elem.payload).data;
-                try self.verifyInst(inst, .{ vector_store_elem.vector_ptr, extra.lhs, extra.rhs });
+                try self.verifyInstOperands(inst, .{ vector_store_elem.vector_ptr, extra.lhs, extra.rhs });
             },
             .cmpxchg_strong,
             .cmpxchg_weak,
             => {
                 const ty_pl = data[inst].ty_pl;
                 const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
-                try self.verifyInst(inst, .{ extra.ptr, extra.expected_value, extra.new_value });
+                try self.verifyInstOperands(inst, .{ extra.ptr, extra.expected_value, extra.new_value });
             },
 
             // big tombs
@@ -332,7 +332,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
                 for (elements) |element| {
                     try self.verifyOperand(inst, element, bt.feed());
                 }
-                try self.verifyInst(inst, .{ .none, .none, .none });
+                try self.verifyInst(inst);
             },
             .call, .call_always_tail, .call_never_tail, .call_never_inline => {
                 const pl_op = data[inst].pl_op;
@@ -347,7 +347,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
                 for (args) |arg| {
                     try self.verifyOperand(inst, arg, bt.feed());
                 }
-                try self.verifyInst(inst, .{ .none, .none, .none });
+                try self.verifyInst(inst);
             },
             .assembly => {
                 const ty_pl = data[inst].ty_pl;
@@ -373,7 +373,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
                 for (inputs) |input| {
                     try self.verifyOperand(inst, input, bt.feed());
                 }
-                try self.verifyInst(inst, .{ .none, .none, .none });
+                try self.verifyInst(inst);
             },
 
             // control flow
@@ -397,7 +397,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
 
                 for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death);
 
-                try self.verifyInst(inst, .{ .none, .none, .none });
+                try self.verifyInst(inst);
             },
             .try_ptr => {
                 const ty_pl = data[inst].ty_pl;
@@ -419,7 +419,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
 
                 for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death);
 
-                try self.verifyInst(inst, .{ .none, .none, .none });
+                try self.verifyInst(inst);
             },
             .br => {
                 const br = data[inst].br;
@@ -431,7 +431,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
                 } else {
                     gop.value_ptr.* = try self.live.clone(self.gpa);
                 }
-                try self.verifyInst(inst, .{ .none, .none, .none });
+                try self.verifyInst(inst);
             },
             .block => {
                 const ty_pl = data[inst].ty_pl;
@@ -462,7 +462,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
                     try self.verifyMatchingLiveness(inst, live);
                 }
 
-                try self.verifyInst(inst, .{ .none, .none, .none });
+                try self.verifyInstOperands(inst, .{ .none, .none, .none });
             },
             .loop => {
                 const ty_pl = data[inst].ty_pl;
@@ -477,7 +477,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
                 // The same stuff should be alive after the loop as before it
                 try self.verifyMatchingLiveness(inst, live);
 
-                try self.verifyInst(inst, .{ .none, .none, .none });
+                try self.verifyInstOperands(inst, .{ .none, .none, .none });
             },
             .cond_br => {
                 const pl_op = data[inst].pl_op;
@@ -500,7 +500,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
                 for (cond_br_liveness.else_deaths) |death| try self.verifyDeath(inst, death);
                 try self.verifyBody(else_body);
 
-                try self.verifyInst(inst, .{ .none, .none, .none });
+                try self.verifyInst(inst);
             },
             .switch_br => {
                 const pl_op = data[inst].pl_op;
@@ -544,7 +544,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
                     try self.verifyBody(else_body);
                 }
 
-                try self.verifyInst(inst, .{ .none, .none, .none });
+                try self.verifyInst(inst);
             },
         }
     }
@@ -570,7 +570,7 @@ fn verifyOperand(self: *Verify, inst: Air.Inst.Index, op_ref: Air.Inst.Ref, dies
     }
 }
 
-fn verifyInst(
+fn verifyInstOperands(
     self: *Verify,
     inst: Air.Inst.Index,
     operands: [Liveness.bpi - 1]Air.Inst.Ref,
@@ -579,6 +579,10 @@ fn verifyInst(
         const dies = self.liveness.operandDies(inst, @intCast(Liveness.OperandInt, operand_index));
         try self.verifyOperand(inst, operand, dies);
     }
+    try self.verifyInst(inst);
+}
+
+fn verifyInst(self: *Verify, inst: Air.Inst.Index) Error!void {
     if (self.air.instructions.items(.tag)[inst] == .interned) return;
     if (self.liveness.isUnused(inst)) {
         assert(!self.live.contains(inst));
src/InternPool.zig
@@ -2298,7 +2298,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
     ip.* = undefined;
 }
 
-pub fn indexToKey(ip: InternPool, index: Index) Key {
+pub fn indexToKey(ip: *const InternPool, index: Index) Key {
     assert(index != .none);
     const item = ip.items.get(@enumToInt(index));
     const data = item.data;
@@ -2361,7 +2361,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
 
         .type_slice => {
             const ptr_type_index = @intToEnum(Index, data);
-            var result = indexToKey(ip, ptr_type_index).ptr_type;
+            var result = ip.indexToKey(ptr_type_index).ptr_type;
             result.size = .Slice;
             return .{ .ptr_type = result };
         },
@@ -2454,9 +2454,9 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
                 .values_map = .none,
             } };
         },
-        .type_enum_explicit => indexToKeyEnum(ip, data, .explicit),
-        .type_enum_nonexhaustive => indexToKeyEnum(ip, data, .nonexhaustive),
-        .type_function => .{ .func_type = indexToKeyFuncType(ip, data) },
+        .type_enum_explicit => ip.indexToKeyEnum(data, .explicit),
+        .type_enum_nonexhaustive => ip.indexToKeyEnum(data, .nonexhaustive),
+        .type_function => .{ .func_type = ip.indexToKeyFuncType(data) },
 
         .undef => .{ .undef = @intToEnum(Index, data) },
         .runtime_value => {
@@ -2591,8 +2591,8 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
             .ty = .comptime_int_type,
             .storage = .{ .i64 = @bitCast(i32, data) },
         } },
-        .int_positive => indexToKeyBigInt(ip, data, true),
-        .int_negative => indexToKeyBigInt(ip, data, false),
+        .int_positive => ip.indexToKeyBigInt(data, true),
+        .int_negative => ip.indexToKeyBigInt(data, false),
         .int_small => {
             const info = ip.extraData(IntSmall, data);
             return .{ .int = .{
@@ -3430,22 +3430,25 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
             .data = try ip.addExtra(gpa, err),
         }),
 
-        .error_union => |error_union| ip.items.appendAssumeCapacity(switch (error_union.val) {
-            .err_name => |err_name| .{
-                .tag = .error_union_error,
-                .data = try ip.addExtra(gpa, Key.Error{
-                    .ty = error_union.ty,
-                    .name = err_name,
-                }),
-            },
-            .payload => |payload| .{
-                .tag = .error_union_payload,
-                .data = try ip.addExtra(gpa, TypeValue{
-                    .ty = error_union.ty,
-                    .val = payload,
-                }),
-            },
-        }),
+        .error_union => |error_union| {
+            assert(ip.indexToKey(error_union.ty) == .error_union_type);
+            ip.items.appendAssumeCapacity(switch (error_union.val) {
+                .err_name => |err_name| .{
+                    .tag = .error_union_error,
+                    .data = try ip.addExtra(gpa, Key.Error{
+                        .ty = error_union.ty,
+                        .name = err_name,
+                    }),
+                },
+                .payload => |payload| .{
+                    .tag = .error_union_payload,
+                    .data = try ip.addExtra(gpa, TypeValue{
+                        .ty = error_union.ty,
+                        .val = payload,
+                    }),
+                },
+            });
+        },
 
         .enum_literal => |enum_literal| ip.items.appendAssumeCapacity(.{
             .tag = .enum_literal,
@@ -4191,6 +4194,7 @@ pub fn sliceLen(ip: InternPool, i: Index) Index {
 /// * ptr <=> ptr
 /// * null_value => opt
 /// * payload => opt
+/// * error set <=> error set
 pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
     const old_ty = ip.typeOf(val);
     if (old_ty == new_ty) return val;
@@ -4230,6 +4234,13 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
             } }),
             else => {},
         },
+        .err => |err| switch (ip.indexToKey(new_ty)) {
+            .error_set_type, .inferred_error_set_type => return ip.get(gpa, .{ .err = .{
+                .ty = new_ty,
+                .name = err.name,
+            } }),
+            else => {},
+        },
         else => {},
     }
     switch (ip.indexToKey(new_ty)) {
src/print_air.zig
@@ -703,7 +703,7 @@ const Writer = struct {
         const pl_op = w.air.instructions.items(.data)[inst].pl_op;
         try w.writeOperand(s, inst, 0, pl_op.operand);
         const name = w.air.nullTerminatedString(pl_op.payload);
-        try s.print(", {s}", .{name});
+        try s.print(", \"{}\"", .{std.zig.fmtEscapes(name)});
     }
 
     fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
src/Sema.zig
@@ -16687,7 +16687,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
                                 const new_decl_ty = try mod.arrayType(.{
                                     .len = bytes.len,
                                     .child = .u8_type,
-                                    .sentinel = .zero_u8,
                                 });
                                 const new_decl = try anon_decl.finish(
                                     new_decl_ty,
@@ -16698,7 +16697,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
                                     0, // default alignment
                                 );
                                 break :v try mod.intern(.{ .ptr = .{
-                                    .ty = .slice_const_u8_sentinel_0_type,
+                                    .ty = .slice_const_u8_type,
                                     .addr = .{ .decl = new_decl },
                                     .len = (try mod.intValue(Type.usize, bytes.len)).toIntern(),
                                 } });
@@ -23991,7 +23990,6 @@ fn panicWithMsg(
     msg_inst: Air.Inst.Ref,
 ) !void {
     const mod = sema.mod;
-    const arena = sema.arena;
 
     if (!mod.backendSupportsFeature(.panic_fn)) {
         _ = try block.addNoOp(.trap);
@@ -24001,16 +23999,22 @@ fn panicWithMsg(
     const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
     const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
     const target = mod.getTarget();
-    const ptr_stack_trace_ty = try Type.ptr(arena, mod, .{
-        .pointee_type = stack_trace_ty,
-        .@"addrspace" = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic
+    const ptr_stack_trace_ty = try mod.ptrType(.{
+        .elem_type = stack_trace_ty.toIntern(),
+        .address_space = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic
     });
-    const null_stack_trace = try sema.addConstant(
-        try Type.optional(arena, ptr_stack_trace_ty, mod),
-        Value.null,
-    );
-    const args: [3]Air.Inst.Ref = .{ msg_inst, null_stack_trace, .null_value };
-    try sema.callBuiltin(block, panic_fn, .auto, &args);
+    const opt_ptr_stack_trace_ty = try mod.optionalType(ptr_stack_trace_ty.toIntern());
+    const null_stack_trace = try sema.addConstant(opt_ptr_stack_trace_ty, (try mod.intern(.{ .opt = .{
+        .ty = opt_ptr_stack_trace_ty.toIntern(),
+        .val = .none,
+    } })).toValue());
+
+    const opt_usize_ty = try mod.optionalType(.usize_type);
+    const null_ret_addr = try sema.addConstant(opt_usize_ty, (try mod.intern(.{ .opt = .{
+        .ty = opt_usize_ty.toIntern(),
+        .val = .none,
+    } })).toValue());
+    try sema.callBuiltin(block, panic_fn, .auto, &.{ msg_inst, null_stack_trace, null_ret_addr });
 }
 
 fn panicUnwrapError(
@@ -29395,13 +29399,10 @@ fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value {
 
 fn optRefValue(sema: *Sema, block: *Block, ty: Type, opt_val: ?Value) !Value {
     const mod = sema.mod;
-    const val = opt_val orelse return Value.null;
-    const ptr_val = try sema.refValue(block, ty, val);
-    const result = try mod.intern(.{ .opt = .{
-        .ty = (try mod.optionalType((try mod.singleConstPtrType(ty)).toIntern())).toIntern(),
-        .val = ptr_val.toIntern(),
-    } });
-    return result.toValue();
+    return (try mod.intern(.{ .opt = .{
+        .ty = (try mod.optionalType((try mod.singleConstPtrType(Type.anyopaque)).toIntern())).toIntern(),
+        .val = if (opt_val) |val| (try sema.refValue(block, ty, val)).toIntern() else .none,
+    } })).toValue();
 }
 
 fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref {
@@ -30603,7 +30604,7 @@ fn wrapErrorUnionPayload(
     if (try sema.resolveMaybeUndefVal(coerced)) |val| {
         return sema.addConstant(dest_ty, (try mod.intern(.{ .error_union = .{
             .ty = dest_ty.toIntern(),
-            .val = .{ .payload = val.toIntern() },
+            .val = .{ .payload = try val.intern(dest_payload_ty, mod) },
         } })).toValue());
     }
     try sema.requireRuntimeBlock(block, inst_src, null);
@@ -30647,7 +30648,12 @@ fn wrapErrorUnionSet(
                 else => unreachable,
             },
         }
-        return sema.addConstant(dest_ty, val);
+        return sema.addConstant(dest_ty, (try mod.intern(.{ .error_union = .{
+            .ty = dest_ty.toIntern(),
+            .val = .{
+                .err_name = mod.intern_pool.indexToKey(try val.intern(dest_err_set_ty, mod)).err.name,
+            },
+        } })).toValue());
     }
 
     try sema.requireRuntimeBlock(block, inst_src, null);
@@ -33325,7 +33331,7 @@ fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref {
 }
 
 fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {
-    return sema.addConstant(ty, Value.undef);
+    return sema.addConstant(ty, (try sema.mod.intern(.{ .undef = ty.toIntern() })).toValue());
 }
 
 pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref {
src/value.zig
@@ -347,6 +347,43 @@ pub const Value = struct {
     pub fn intern(val: Value, ty: Type, mod: *Module) Allocator.Error!InternPool.Index {
         if (val.ip_index != .none) return mod.intern_pool.getCoerced(mod.gpa, val.toIntern(), ty.toIntern());
         switch (val.tag()) {
+            .eu_payload => {
+                const pl = val.castTag(.eu_payload).?.data;
+                return mod.intern(.{ .error_union = .{
+                    .ty = ty.toIntern(),
+                    .val = .{ .payload = try pl.intern(ty.errorUnionPayload(mod), mod) },
+                } });
+            },
+            .opt_payload => {
+                const pl = val.castTag(.opt_payload).?.data;
+                return mod.intern(.{ .opt = .{
+                    .ty = ty.toIntern(),
+                    .val = try pl.intern(ty.optionalChild(mod), mod),
+                } });
+            },
+            .slice => {
+                const pl = val.castTag(.slice).?.data;
+                const ptr = try pl.ptr.intern(ty.optionalChild(mod), mod);
+                var ptr_key = mod.intern_pool.indexToKey(ptr).ptr;
+                assert(ptr_key.len == .none);
+                ptr_key.ty = ty.toIntern();
+                ptr_key.len = try pl.len.intern(Type.usize, mod);
+                return mod.intern(.{ .ptr = ptr_key });
+            },
+            .bytes => {
+                const pl = val.castTag(.bytes).?.data;
+                return mod.intern(.{ .aggregate = .{
+                    .ty = ty.toIntern(),
+                    .storage = .{ .bytes = pl },
+                } });
+            },
+            .repeated => {
+                const pl = val.castTag(.repeated).?.data;
+                return mod.intern(.{ .aggregate = .{
+                    .ty = ty.toIntern(),
+                    .storage = .{ .repeated_elem = try pl.intern(ty.childType(mod), mod) },
+                } });
+            },
             .aggregate => {
                 const old_elems = val.castTag(.aggregate).?.data;
                 const new_elems = try mod.gpa.alloc(InternPool.Index, old_elems.len);
@@ -372,24 +409,74 @@ pub const Value = struct {
                     .val = try pl.val.intern(ty.unionFieldType(pl.tag, mod), mod),
                 } });
             },
-            else => unreachable,
         }
     }
 
     pub fn unintern(val: Value, arena: Allocator, mod: *Module) Allocator.Error!Value {
-        if (val.ip_index == .none) return val;
-        switch (mod.intern_pool.indexToKey(val.toIntern())) {
+        return if (val.ip_index == .none) val else switch (mod.intern_pool.indexToKey(val.toIntern())) {
+            .int_type,
+            .ptr_type,
+            .array_type,
+            .vector_type,
+            .opt_type,
+            .anyframe_type,
+            .error_union_type,
+            .simple_type,
+            .struct_type,
+            .anon_struct_type,
+            .union_type,
+            .opaque_type,
+            .enum_type,
+            .func_type,
+            .error_set_type,
+            .inferred_error_set_type,
+
+            .undef,
+            .runtime_value,
+            .simple_value,
+            .variable,
+            .extern_func,
+            .func,
+            .int,
+            .err,
+            .enum_literal,
+            .enum_tag,
+            .float,
+            => val,
+
+            .error_union => |error_union| switch (error_union.val) {
+                .err_name => val,
+                .payload => |payload| Tag.eu_payload.create(arena, payload.toValue()),
+            },
+
+            .ptr => |ptr| switch (ptr.len) {
+                .none => val,
+                else => |len| Tag.slice.create(arena, .{
+                    .ptr = val.slicePtr(mod),
+                    .len = len.toValue(),
+                }),
+            },
+
+            .opt => |opt| switch (opt.val) {
+                .none => val,
+                else => |payload| Tag.opt_payload.create(arena, payload.toValue()),
+            },
+
             .aggregate => |aggregate| switch (aggregate.storage) {
-                .bytes => |bytes| return Tag.bytes.create(arena, try arena.dupe(u8, bytes)),
+                .bytes => |bytes| Tag.bytes.create(arena, try arena.dupe(u8, bytes)),
                 .elems => |old_elems| {
                     const new_elems = try arena.alloc(Value, old_elems.len);
                     for (new_elems, old_elems) |*new_elem, old_elem| new_elem.* = old_elem.toValue();
                     return Tag.aggregate.create(arena, new_elems);
                 },
-                .repeated_elem => |elem| return Tag.repeated.create(arena, elem.toValue()),
+                .repeated_elem => |elem| Tag.repeated.create(arena, elem.toValue()),
             },
-            else => return val,
-        }
+
+            .un => |un| Tag.@"union".create(arena, .{
+                .tag = un.tag.toValue(),
+                .val = un.val.toValue(),
+            }),
+        };
     }
 
     pub fn toIntern(val: Value) InternPool.Index {
@@ -1896,7 +1983,7 @@ pub const Value = struct {
 
     /// Returns true if a Value is backed by a variable
     pub fn isVariable(val: Value, mod: *Module) bool {
-        return switch (mod.intern_pool.indexToKey(val.toIntern())) {
+        return val.ip_index != .none and switch (mod.intern_pool.indexToKey(val.toIntern())) {
             .variable => true,
             .ptr => |ptr| switch (ptr.addr) {
                 .decl => |decl_index| {
@@ -1919,28 +2006,25 @@ pub const Value = struct {
     }
 
     pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool {
-        return switch (val.ip_index) {
-            .none => false,
-            else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
-                .variable => |variable| variable.is_threadlocal,
-                .ptr => |ptr| switch (ptr.addr) {
-                    .decl => |decl_index| {
-                        const decl = mod.declPtr(decl_index);
-                        assert(decl.has_tv);
-                        return decl.val.isPtrToThreadLocal(mod);
-                    },
-                    .mut_decl => |mut_decl| {
-                        const decl = mod.declPtr(mut_decl.decl);
-                        assert(decl.has_tv);
-                        return decl.val.isPtrToThreadLocal(mod);
-                    },
-                    .int => false,
-                    .eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isPtrToThreadLocal(mod),
-                    .comptime_field => |comptime_field| comptime_field.toValue().isPtrToThreadLocal(mod),
-                    .elem, .field => |base_index| base_index.base.toValue().isPtrToThreadLocal(mod),
+        return val.ip_index != .none and switch (mod.intern_pool.indexToKey(val.toIntern())) {
+            .variable => |variable| variable.is_threadlocal,
+            .ptr => |ptr| switch (ptr.addr) {
+                .decl => |decl_index| {
+                    const decl = mod.declPtr(decl_index);
+                    assert(decl.has_tv);
+                    return decl.val.isPtrToThreadLocal(mod);
                 },
-                else => false,
+                .mut_decl => |mut_decl| {
+                    const decl = mod.declPtr(mut_decl.decl);
+                    assert(decl.has_tv);
+                    return decl.val.isPtrToThreadLocal(mod);
+                },
+                .int => false,
+                .eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isPtrToThreadLocal(mod),
+                .comptime_field => |comptime_field| comptime_field.toValue().isPtrToThreadLocal(mod),
+                .elem, .field => |base_index| base_index.base.toValue().isPtrToThreadLocal(mod),
             },
+            else => false,
         };
     }
 
tools/lldb_pretty_printers.py
@@ -681,6 +681,7 @@ def __lldb_init_module(debugger, _=None):
     add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Air\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True)
     add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True)
     add(debugger, category='zig.stage2', type='Module.Decl::Module.Decl.Index', synth=True)
+    add(debugger, category='zig.stage2', type='Module.LazySrcLoc', identifier='zig_TaggedUnion', synth=True)
     add(debugger, category='zig.stage2', type='InternPool.Index', synth=True)
     add(debugger, category='zig.stage2', type='InternPool.Key', identifier='zig_TaggedUnion', synth=True)
     add(debugger, category='zig.stage2', type='InternPool.Key.Int.Storage', identifier='zig_TaggedUnion', synth=True)