Commit 31aee50c1a

Andrew Kelley <andrew@ziglang.org>
2023-05-06 04:13:43
InternPool: add a slice encoding
This uses the data field to reference its pointer field type, which allows for efficient and infallible access of a slice type's pointer type.
1 parent 08e9763
src/arch/aarch64/CodeGen.zig
@@ -3435,7 +3435,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
     const slice_ty = self.typeOf(bin_op.lhs);
     const result: MCValue = if (!slice_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) .dead else result: {
         var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-        const ptr_ty = slice_ty.slicePtrFieldType(&buf);
+        const ptr_ty = slice_ty.slicePtrFieldType(&buf, mod);
 
         const slice_mcv = try self.resolveInst(bin_op.lhs);
         const base_mcv = slicePtr(slice_mcv);
src/arch/arm/CodeGen.zig
@@ -2433,7 +2433,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
     const slice_ty = self.typeOf(bin_op.lhs);
     const result: MCValue = if (!slice_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) .dead else result: {
         var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-        const ptr_ty = slice_ty.slicePtrFieldType(&buf);
+        const ptr_ty = slice_ty.slicePtrFieldType(&buf, mod);
 
         const slice_mcv = try self.resolveInst(bin_op.lhs);
         const base_mcv = slicePtr(slice_mcv);
src/arch/sparc64/CodeGen.zig
@@ -2462,7 +2462,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
         const elem_size = elem_ty.abiSize(mod);
 
         var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-        const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
+        const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf, mod);
 
         const index_lock: ?RegisterLock = if (index_mcv == .register)
             self.register_manager.lockRegAssumeUnused(index_mcv.register)
src/arch/x86_64/CodeGen.zig
@@ -4056,7 +4056,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
     const elem_ty = slice_ty.childType(mod);
     const elem_size = elem_ty.abiSize(mod);
     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-    const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
+    const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf, mod);
 
     const index_ty = self.typeOf(rhs);
     const index_mcv = try self.resolveInst(rhs);
@@ -4081,11 +4081,12 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
 }
 
 fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
+    const mod = self.bin_file.options.module.?;
     const bin_op = self.air.instructions.items(.data)[inst].bin_op;
     const slice_ty = self.typeOf(bin_op.lhs);
 
     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-    const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
+    const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf, mod);
     const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs);
     const dst_mcv = try self.allocRegOrMem(inst, false);
     try self.load(dst_mcv, slice_ptr_field_type, elem_ptr);
@@ -8682,7 +8683,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
 
     var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
     const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload(mod))
-        .{ .off = 0, .ty = if (pl_ty.isSlice(mod)) pl_ty.slicePtrFieldType(&ptr_buf) else pl_ty }
+        .{ .off = 0, .ty = if (pl_ty.isSlice(mod)) pl_ty.slicePtrFieldType(&ptr_buf, mod) else pl_ty }
     else
         .{ .off = @intCast(i32, pl_ty.abiSize(mod)), .ty = Type.bool };
 
@@ -8774,7 +8775,7 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue)
 
     var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
     const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload(mod))
-        .{ .off = 0, .ty = if (pl_ty.isSlice(mod)) pl_ty.slicePtrFieldType(&ptr_buf) else pl_ty }
+        .{ .off = 0, .ty = if (pl_ty.isSlice(mod)) pl_ty.slicePtrFieldType(&ptr_buf, mod) else pl_ty }
     else
         .{ .off = @intCast(i32, pl_ty.abiSize(mod)), .ty = Type.bool };
 
@@ -10813,7 +10814,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
     switch (dst_ptr_ty.ptrSize(mod)) {
         .Slice => {
             var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-            const slice_ptr_ty = dst_ptr_ty.slicePtrFieldType(&buf);
+            const slice_ptr_ty = dst_ptr_ty.slicePtrFieldType(&buf, mod);
 
             // TODO: this only handles slices stored in the stack
             const ptr = dst_ptr;
src/codegen/c/type.zig
@@ -1432,7 +1432,7 @@ pub const CType = extern union {
                                 .payload => unreachable,
                             }) |fwd_idx| {
                                 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-                                const ptr_ty = ty.slicePtrFieldType(&buf);
+                                const ptr_ty = ty.slicePtrFieldType(&buf, mod);
                                 if (try lookup.typeToIndex(ptr_ty, kind)) |ptr_idx| {
                                     self.storage = .{ .anon = undefined };
                                     self.storage.anon.fields[0] = .{
src/codegen/c.zig
@@ -566,7 +566,7 @@ pub const DeclGen = struct {
             }
 
             var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-            try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr(), .Initializer);
+            try dg.renderValue(writer, ty.slicePtrFieldType(&buf, mod), val.slicePtr(), .Initializer);
 
             var len_pl: Value.Payload.U64 = .{
                 .base = .{ .tag = .int_u64 },
@@ -787,7 +787,7 @@ pub const DeclGen = struct {
 
                     try writer.writeAll("{(");
                     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-                    const ptr_ty = ty.slicePtrFieldType(&buf);
+                    const ptr_ty = ty.slicePtrFieldType(&buf, mod);
                     try dg.renderType(writer, ptr_ty);
                     return writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(Type.usize, val, .Other)});
                 } else {
@@ -1088,7 +1088,7 @@ pub const DeclGen = struct {
                         var buf: Type.SlicePtrFieldTypeBuffer = undefined;
 
                         try writer.writeByte('{');
-                        try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, initializer_type);
+                        try dg.renderValue(writer, ty.slicePtrFieldType(&buf, mod), slice.ptr, initializer_type);
                         try writer.writeAll(", ");
                         try dg.renderValue(writer, Type.usize, slice.len, initializer_type);
                         try writer.writeByte('}');
@@ -4107,6 +4107,7 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons
 }
 
 fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
+    const mod = f.object.dg.module;
     const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
     const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
 
@@ -4116,7 +4117,7 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
 
     const inst_ty = f.typeOfIndex(inst);
     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-    const ptr_ty = inst_ty.slicePtrFieldType(&buf);
+    const ptr_ty = inst_ty.slicePtrFieldType(&buf, mod);
 
     const writer = f.object.writer();
     const local = try f.allocLocal(inst, inst_ty);
@@ -5112,7 +5113,7 @@ fn airIsNull(
         TypedValue{ .ty = payload_ty, .val = Value.zero }
     else if (payload_ty.isSlice(mod) and optional_ty.optionalReprIsPayload(mod)) rhs: {
         try writer.writeAll(".ptr");
-        const slice_ptr_ty = payload_ty.slicePtrFieldType(&slice_ptr_buf);
+        const slice_ptr_ty = payload_ty.slicePtrFieldType(&slice_ptr_buf, mod);
         break :rhs TypedValue{ .ty = slice_ptr_ty, .val = Value.null };
     } else rhs: {
         try writer.writeAll(".is_null");
@@ -5845,7 +5846,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
     // &(*(void *)p)[0], although LLVM does via GetElementPtr
     if (operand == .undef) {
         var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-        try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(&buf) }, .Initializer);
+        try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(&buf, mod) }, .Initializer);
     } else if (array_ty.hasRuntimeBitsIgnoreComptime(mod)) {
         try writer.writeAll("&(");
         try f.writeCValueDeref(writer, operand);
src/codegen/llvm.zig
@@ -1638,7 +1638,7 @@ pub const Object = struct {
 
                 if (ty.isSlice(mod)) {
                     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-                    const ptr_ty = ty.slicePtrFieldType(&buf);
+                    const ptr_ty = ty.slicePtrFieldType(&buf, mod);
                     const len_ty = Type.usize;
 
                     const name = try ty.nameAlloc(gpa, o.module);
@@ -2822,7 +2822,7 @@ pub const DeclGen = struct {
             .Pointer => {
                 if (t.isSlice(mod)) {
                     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-                    const ptr_type = t.slicePtrFieldType(&buf);
+                    const ptr_type = t.slicePtrFieldType(&buf, mod);
 
                     const fields: [2]*llvm.Type = .{
                         try dg.lowerType(ptr_type),
@@ -3182,9 +3182,9 @@ pub const DeclGen = struct {
                 const param_ty = fn_info.param_types[it.zig_index - 1];
                 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
                 const ptr_ty = if (param_ty.zigTypeTag(mod) == .Optional)
-                    param_ty.optionalChild(mod).slicePtrFieldType(&buf)
+                    param_ty.optionalChild(mod).slicePtrFieldType(&buf, mod)
                 else
-                    param_ty.slicePtrFieldType(&buf);
+                    param_ty.slicePtrFieldType(&buf, mod);
                 const ptr_llvm_ty = try dg.lowerType(ptr_ty);
                 const len_llvm_ty = try dg.lowerType(Type.usize);
 
@@ -3387,7 +3387,7 @@ pub const DeclGen = struct {
                         var buf: Type.SlicePtrFieldTypeBuffer = undefined;
                         const fields: [2]*llvm.Value = .{
                             try dg.lowerValue(.{
-                                .ty = tv.ty.slicePtrFieldType(&buf),
+                                .ty = tv.ty.slicePtrFieldType(&buf, mod),
                                 .val = slice.ptr,
                             }),
                             try dg.lowerValue(.{
@@ -4169,7 +4169,7 @@ pub const DeclGen = struct {
         const mod = self.module;
         if (tv.ty.isSlice(mod)) {
             var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-            const ptr_ty = tv.ty.slicePtrFieldType(&buf);
+            const ptr_ty = tv.ty.slicePtrFieldType(&buf, mod);
             var slice_len: Value.Payload.U64 = .{
                 .base = .{ .tag = .int_u64 },
                 .data = tv.val.sliceLen(mod),
@@ -6654,7 +6654,7 @@ pub const FuncGen = struct {
             if (payload_ty.isSlice(mod)) {
                 const slice_ptr = self.builder.buildExtractValue(loaded, 0, "");
                 var slice_buf: Type.SlicePtrFieldTypeBuffer = undefined;
-                const ptr_ty = try self.dg.lowerType(payload_ty.slicePtrFieldType(&slice_buf));
+                const ptr_ty = try self.dg.lowerType(payload_ty.slicePtrFieldType(&slice_buf, mod));
                 return self.builder.buildICmp(pred, slice_ptr, ptr_ty.constNull(), "");
             }
             return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), "");
src/codegen/spirv.zig
@@ -669,7 +669,7 @@ pub const DeclGen = struct {
                         const slice = val.castTag(.slice).?.data;
 
                         var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-                        const ptr_ty = ty.slicePtrFieldType(&buf);
+                        const ptr_ty = ty.slicePtrFieldType(&buf, mod);
 
                         try self.lower(ptr_ty, slice.ptr);
                         try self.addInt(Type.usize, slice.len);
@@ -2489,7 +2489,7 @@ pub const DeclGen = struct {
         const index_id = try self.resolve(bin_op.rhs);
 
         var slice_buf: Type.SlicePtrFieldTypeBuffer = undefined;
-        const ptr_ty = slice_ty.slicePtrFieldType(&slice_buf);
+        const ptr_ty = slice_ty.slicePtrFieldType(&slice_buf, mod);
         const ptr_ty_ref = try self.resolveType(ptr_ty, .direct);
 
         const slice_ptr = try self.extractField(ptr_ty, slice_id, 0);
@@ -2987,7 +2987,7 @@ pub const DeclGen = struct {
 
             var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
             const ptr_ty = if (payload_ty.isSlice(mod))
-                payload_ty.slicePtrFieldType(&ptr_buf)
+                payload_ty.slicePtrFieldType(&ptr_buf, mod)
             else
                 payload_ty;
 
src/link/Dwarf.zig
@@ -278,7 +278,7 @@ pub const DeclState = struct {
                     var index = dbg_info_buffer.items.len;
                     try dbg_info_buffer.resize(index + 4);
                     var buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
-                    const ptr_ty = ty.slicePtrFieldType(buf);
+                    const ptr_ty = ty.slicePtrFieldType(buf, mod);
                     try self.addTypeRelocGlobal(atom_index, ptr_ty, @intCast(u32, index));
                     // DW.AT.data_member_location, DW.FORM.udata
                     try dbg_info_buffer.ensureUnusedCapacity(6);
src/codegen.zig
@@ -361,7 +361,7 @@ pub fn generateSymbol(
 
                     // generate ptr
                     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-                    const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf);
+                    const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf, mod);
                     switch (try generateSymbol(bin_file, src_loc, .{
                         .ty = slice_ptr_field_type,
                         .val = slice.ptr,
@@ -851,7 +851,7 @@ fn lowerParentPtr(
                         var buf: Type.SlicePtrFieldTypeBuffer = undefined;
                         break :offset switch (field_ptr.field_index) {
                             0 => 0,
-                            1 => field_ptr.container_ty.slicePtrFieldType(&buf).abiSize(mod),
+                            1 => field_ptr.container_ty.slicePtrFieldType(&buf, mod).abiSize(mod),
                             else => unreachable,
                         };
                     },
@@ -951,7 +951,7 @@ fn lowerDeclRef(
     if (typed_value.ty.isSlice(mod)) {
         // generate ptr
         var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-        const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf);
+        const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf, mod);
         switch (try generateSymbol(bin_file, src_loc, .{
             .ty = slice_ptr_field_type,
             .val = typed_value.val,
src/InternPool.zig
@@ -668,6 +668,9 @@ pub const Tag = enum(u8) {
     /// A fully explicitly specified pointer type.
     /// data is payload to Pointer.
     type_pointer,
+    /// A slice type.
+    /// data is Index of underlying pointer type.
+    type_slice,
     /// An optional type.
     /// data is the child type.
     type_optional,
@@ -984,6 +987,13 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
             } };
         },
 
+        .type_slice => {
+            const ptr_ty_index = @intToEnum(Index, data);
+            var result = indexToKey(ip, ptr_ty_index);
+            result.ptr_type.size = .Slice;
+            return result;
+        },
+
         .type_optional => .{ .opt_type = @intToEnum(Index, data) },
 
         .type_error_union => @panic("TODO"),
@@ -1041,6 +1051,19 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
         },
         .ptr_type => |ptr_type| {
             assert(ptr_type.elem_type != .none);
+
+            if (ptr_type.size == .Slice) {
+                var new_key = key;
+                new_key.ptr_type.size = .Many;
+                const ptr_ty_index = try get(ip, gpa, new_key);
+                try ip.items.ensureUnusedCapacity(gpa, 1);
+                ip.items.appendAssumeCapacity(.{
+                    .tag = .type_slice,
+                    .data = @enumToInt(ptr_ty_index),
+                });
+                return @intToEnum(Index, ip.items.len - 1);
+            }
+
             // TODO introduce more pointer encodings
             ip.items.appendAssumeCapacity(.{
                 .tag = .type_pointer,
@@ -1401,6 +1424,20 @@ pub fn childType(ip: InternPool, i: Index) Index {
     };
 }
 
+/// Given a slice type, returns the type of the pointer field.
+pub fn slicePtrType(ip: InternPool, i: Index) Index {
+    switch (i) {
+        .const_slice_u8_type => return .manyptr_const_u8_type,
+        .const_slice_u8_sentinel_0_type => return .manyptr_const_u8_sentinel_0_type,
+        else => {},
+    }
+    const item = ip.items.get(@enumToInt(i));
+    switch (item.tag) {
+        .type_slice => return @intToEnum(Index, item.data),
+        else => unreachable, // not a slice type
+    }
+}
+
 pub fn dump(ip: InternPool) void {
     dumpFallible(ip, std.heap.page_allocator) catch return;
 }
@@ -1438,6 +1475,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
             .type_array => @sizeOf(Vector),
             .type_vector => @sizeOf(Vector),
             .type_pointer => @sizeOf(Pointer),
+            .type_slice => 0,
             .type_optional => 0,
             .type_error_union => @sizeOf(ErrorUnion),
             .type_enum_simple => @sizeOf(EnumSimple),
src/Module.zig
@@ -6553,7 +6553,7 @@ pub fn populateTestFunctions(
     }
     const decl = mod.declPtr(decl_index);
     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-    const tmp_test_fn_ty = decl.ty.slicePtrFieldType(&buf).childType(mod);
+    const tmp_test_fn_ty = decl.ty.slicePtrFieldType(&buf, mod).childType(mod);
 
     const array_decl_index = d: {
         // Add mod.test_functions to an array decl then make the test_functions
src/Sema.zig
@@ -24201,7 +24201,7 @@ fn fieldPtr(
 
             if (mem.eql(u8, field_name, "ptr")) {
                 const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer);
-                const slice_ptr_ty = inner_ty.slicePtrFieldType(buf);
+                const slice_ptr_ty = inner_ty.slicePtrFieldType(buf, mod);
 
                 const result_ty = try Type.ptr(sema.arena, sema.mod, .{
                     .pointee_type = slice_ptr_ty,
@@ -27804,7 +27804,7 @@ fn beginComptimePtrMutation(
                                         sema,
                                         block,
                                         src,
-                                        parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
+                                        parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer), mod),
                                         &val_ptr.castTag(.slice).?.data.ptr,
                                         ptr_elem_ty,
                                         parent.decl_ref_mut,
@@ -27859,7 +27859,7 @@ fn beginComptimePtrMutation(
                                 sema,
                                 block,
                                 src,
-                                parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
+                                parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer), mod),
                                 &val_ptr.castTag(.slice).?.data.ptr,
                                 ptr_elem_ty,
                                 parent.decl_ref_mut,
@@ -28256,7 +28256,7 @@ fn beginComptimePtrLoad(
                     const slice_val = tv.val.castTag(.slice).?.data;
                     deref.pointee = switch (field_index) {
                         Value.Payload.Slice.ptr_index => TypedValue{
-                            .ty = field_ptr.container_ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
+                            .ty = field_ptr.container_ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer), mod),
                             .val = slice_val.ptr,
                         },
                         Value.Payload.Slice.len_index => TypedValue{
@@ -29339,8 +29339,9 @@ fn analyzeSlicePtr(
     slice: Air.Inst.Ref,
     slice_ty: Type,
 ) CompileError!Air.Inst.Ref {
+    const mod = sema.mod;
     const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer);
-    const result_ty = slice_ty.slicePtrFieldType(buf);
+    const result_ty = slice_ty.slicePtrFieldType(buf, mod);
     if (try sema.resolveMaybeUndefVal(slice)) |val| {
         if (val.isUndef()) return sema.addConstUndef(result_ty);
         return sema.addConstant(result_ty, val.slicePtr());
src/type.zig
@@ -2042,7 +2042,18 @@ pub const Type = struct {
                 else => unreachable,
             },
             else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
-                else => @panic("TODO"),
+                .ptr_type => |ptr_type| {
+                    if (ptr_type.alignment != 0) {
+                        return @intCast(u32, ptr_type.alignment);
+                    } else if (opt_sema) |sema| {
+                        const res = try ptr_type.elem_type.toType().abiAlignmentAdvanced(mod, .{ .sema = sema });
+                        return res.scalar;
+                    } else {
+                        return (ptr_type.elem_type.toType().abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;
+                    }
+                },
+                .opt_type => |child| return child.toType().ptrAlignmentAdvanced(mod, opt_sema),
+                else => unreachable,
             },
         }
     }
@@ -3060,33 +3071,36 @@ pub const Type = struct {
         pointer: Payload.Pointer,
     };
 
-    pub fn slicePtrFieldType(self: Type, buffer: *SlicePtrFieldTypeBuffer) Type {
-        switch (self.tag()) {
-            .pointer => {
-                const payload = self.castTag(.pointer).?.data;
-                assert(payload.size == .Slice);
-
-                buffer.* = .{
-                    .pointer = .{
-                        .data = .{
-                            .pointee_type = payload.pointee_type,
-                            .sentinel = payload.sentinel,
-                            .@"align" = payload.@"align",
-                            .@"addrspace" = payload.@"addrspace",
-                            .bit_offset = payload.bit_offset,
-                            .host_size = payload.host_size,
-                            .vector_index = payload.vector_index,
-                            .@"allowzero" = payload.@"allowzero",
-                            .mutable = payload.mutable,
-                            .@"volatile" = payload.@"volatile",
-                            .size = .Many,
+    pub fn slicePtrFieldType(ty: Type, buffer: *SlicePtrFieldTypeBuffer, mod: *const Module) Type {
+        switch (ty.ip_index) {
+            .none => switch (ty.tag()) {
+                .pointer => {
+                    const payload = ty.castTag(.pointer).?.data;
+                    assert(payload.size == .Slice);
+
+                    buffer.* = .{
+                        .pointer = .{
+                            .data = .{
+                                .pointee_type = payload.pointee_type,
+                                .sentinel = payload.sentinel,
+                                .@"align" = payload.@"align",
+                                .@"addrspace" = payload.@"addrspace",
+                                .bit_offset = payload.bit_offset,
+                                .host_size = payload.host_size,
+                                .vector_index = payload.vector_index,
+                                .@"allowzero" = payload.@"allowzero",
+                                .mutable = payload.mutable,
+                                .@"volatile" = payload.@"volatile",
+                                .size = .Many,
+                            },
                         },
-                    },
-                };
-                return Type.initPayload(&buffer.pointer.base);
-            },
+                    };
+                    return Type.initPayload(&buffer.pointer.base);
+                },
 
-            else => unreachable,
+                else => unreachable,
+            },
+            else => return mod.intern_pool.slicePtrType(ty.ip_index).toType(),
         }
     }
 
src/value.zig
@@ -2078,7 +2078,7 @@ pub const Value = struct {
                 }
 
                 var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
-                const ptr_ty = ty.slicePtrFieldType(&ptr_buf);
+                const ptr_ty = ty.slicePtrFieldType(&ptr_buf, mod);
 
                 return eqlAdvanced(a_payload.ptr, ptr_ty, b_payload.ptr, ptr_ty, mod, opt_sema);
             },
@@ -2237,7 +2237,7 @@ pub const Value = struct {
                     }
 
                     var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
-                    const ptr_ty = ty.slicePtrFieldType(&ptr_buf);
+                    const ptr_ty = ty.slicePtrFieldType(&ptr_buf, mod);
                     const a_ptr = switch (a_ty.ptrSize(mod)) {
                         .Slice => a.slicePtr(),
                         .One => a,
@@ -2376,7 +2376,7 @@ pub const Value = struct {
                 .slice => {
                     const slice = val.castTag(.slice).?.data;
                     var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
-                    const ptr_ty = ty.slicePtrFieldType(&ptr_buf);
+                    const ptr_ty = ty.slicePtrFieldType(&ptr_buf, mod);
                     hash(slice.ptr, ptr_ty, hasher, mod);
                     hash(slice.len, Type.usize, hasher, mod);
                 },
@@ -2499,7 +2499,7 @@ pub const Value = struct {
                 .slice => {
                     const slice = val.castTag(.slice).?.data;
                     var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
-                    const ptr_ty = ty.slicePtrFieldType(&ptr_buf);
+                    const ptr_ty = ty.slicePtrFieldType(&ptr_buf, mod);
                     slice.ptr.hashUncoerced(ptr_ty, hasher, mod);
                 },
                 else => val.hashPtr(hasher, mod),