Commit 4f70863a55

Jacob Young <jacobly0@users.noreply.github.com>
2023-05-29 13:30:30
InternPool: fix various pointer issues
1 parent 3269256
src/InternPool.zig
@@ -1374,12 +1374,12 @@ pub const Index = enum(u32) {
         undef: DataIsIndex,
         runtime_value: DataIsIndex,
         simple_value: struct { data: SimpleValue },
-        ptr_mut_decl: struct { data: *PtrMutDecl },
         ptr_decl: struct { data: *PtrDecl },
-        ptr_int: struct { data: *PtrAddr },
-        ptr_eu_payload: DataIsIndex,
-        ptr_opt_payload: DataIsIndex,
+        ptr_mut_decl: struct { data: *PtrMutDecl },
         ptr_comptime_field: struct { data: *PtrComptimeField },
+        ptr_int: struct { data: *PtrBase },
+        ptr_eu_payload: struct { data: *PtrBase },
+        ptr_opt_payload: struct { data: *PtrBase },
         ptr_elem: struct { data: *PtrBaseIndex },
         ptr_field: struct { data: *PtrBaseIndex },
         ptr_slice: struct { data: *PtrSlice },
@@ -1774,29 +1774,25 @@ pub const Tag = enum(u8) {
     /// A value that can be represented with only an enum tag.
     /// data is SimpleValue enum value.
     simple_value,
-    /// A pointer to a decl that can be mutated at comptime.
-    /// data is extra index of PtrMutDecl, which contains the type and address.
-    ptr_mut_decl,
     /// A pointer to a decl.
-    /// data is extra index of PtrDecl, which contains the type and address.
+    /// data is extra index of `PtrDecl`, which contains the type and address.
     ptr_decl,
+    /// A pointer to a decl that can be mutated at comptime.
+    /// data is extra index of `PtrMutDecl`, which contains the type and address.
+    ptr_mut_decl,
+    /// data is extra index of `PtrComptimeField`, which contains the pointer type and field value.
+    ptr_comptime_field,
     /// A pointer with an integer value.
-    /// data is extra index of PtrAddr, which contains the type and address.
+    /// data is extra index of `PtrBase`, which contains the type and address.
     /// Only pointer types are allowed to have this encoding. Optional types must use
     /// `opt_payload` or `opt_null`.
     ptr_int,
     /// A pointer to the payload of an error union.
-    /// data is Index of a pointer value to the error union.
-    /// In order to use this encoding, one must ensure that the `InternPool`
-    /// already contains the payload pointer type corresponding to this payload.
+    /// data is extra index of `PtrBase`, which contains the type and base pointer.
     ptr_eu_payload,
     /// A pointer to the payload of an optional.
-    /// data is Index of a pointer value to the optional.
-    /// In order to use this encoding, one must ensure that the `InternPool`
-    /// already contains the payload pointer type corresponding to this payload.
+    /// data is extra index of `PtrBase`, which contains the type and base pointer.
     ptr_opt_payload,
-    /// data is extra index of PtrComptimeField, which contains the pointer type and field value.
-    ptr_comptime_field,
     /// A pointer to an array element.
     /// data is extra index of PtrBaseIndex, which contains the base array and element index.
     /// In order to use this encoding, one must ensure that the `InternPool`
@@ -2224,14 +2220,14 @@ pub const PtrMutDecl = struct {
     runtime_index: RuntimeIndex,
 };
 
-pub const PtrAddr = struct {
+pub const PtrComptimeField = struct {
     ty: Index,
-    addr: Index,
+    field_val: Index,
 };
 
-pub const PtrComptimeField = struct {
+pub const PtrBase = struct {
     ty: Index,
-    field_val: Index,
+    base: Index,
 };
 
 pub const PtrBaseIndex = struct {
@@ -2598,36 +2594,23 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
                 } },
             } };
         },
-        .ptr_int => {
-            const info = ip.extraData(PtrAddr, data);
+        .ptr_comptime_field => {
+            const info = ip.extraData(PtrComptimeField, data);
             return .{ .ptr = .{
                 .ty = info.ty,
-                .addr = .{ .int = info.addr },
-            } };
-        },
-        .ptr_eu_payload => {
-            const ptr_eu_index = @intToEnum(Index, data);
-            var ptr_type = ip.indexToKey(ip.typeOf(ptr_eu_index)).ptr_type;
-            ptr_type.elem_type = ip.indexToKey(ptr_type.elem_type).error_union_type.payload_type;
-            return .{ .ptr = .{
-                .ty = ip.getAssumeExists(.{ .ptr_type = ptr_type }),
-                .addr = .{ .eu_payload = ptr_eu_index },
+                .addr = .{ .comptime_field = info.field_val },
             } };
         },
-        .ptr_opt_payload => {
-            const ptr_opt_index = @intToEnum(Index, data);
-            var ptr_type = ip.indexToKey(ip.typeOf(ptr_opt_index)).ptr_type;
-            ptr_type.elem_type = ip.indexToKey(ptr_type.elem_type).opt_type;
-            return .{ .ptr = .{
-                .ty = ip.getAssumeExists(.{ .ptr_type = ptr_type }),
-                .addr = .{ .opt_payload = ptr_opt_index },
-            } };
-        },
-        .ptr_comptime_field => {
-            const info = ip.extraData(PtrComptimeField, data);
+        .ptr_int, .ptr_eu_payload, .ptr_opt_payload => {
+            const info = ip.extraData(PtrBase, data);
             return .{ .ptr = .{
                 .ty = info.ty,
-                .addr = .{ .comptime_field = info.field_val },
+                .addr = switch (item.tag) {
+                    .ptr_int => .{ .int = info.base },
+                    .ptr_eu_payload => .{ .eu_payload = info.base },
+                    .ptr_opt_payload => .{ .opt_payload = info.base },
+                    else => unreachable,
+                },
             } };
         },
         .ptr_elem => {
@@ -3248,39 +3231,67 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
                                 .runtime_index = mut_decl.runtime_index,
                             }),
                         }),
-                        .int => |int| {
-                            assert(ip.typeOf(int) == .usize_type);
+                        .comptime_field => |field_val| {
+                            assert(field_val != .none);
                             ip.items.appendAssumeCapacity(.{
-                                .tag = .ptr_int,
-                                .data = try ip.addExtra(gpa, PtrAddr{
+                                .tag = .ptr_comptime_field,
+                                .data = try ip.addExtra(gpa, PtrComptimeField{
                                     .ty = ptr.ty,
-                                    .addr = int,
+                                    .field_val = field_val,
                                 }),
                             });
                         },
-                        .eu_payload, .opt_payload => |data| {
-                            assert(data != .none);
+                        .int, .eu_payload, .opt_payload => |base| {
+                            switch (ptr.addr) {
+                                .int => assert(ip.typeOf(base) == .usize_type),
+                                .eu_payload => assert(ip.indexToKey(
+                                    ip.indexToKey(ip.typeOf(base)).ptr_type.elem_type,
+                                ) == .error_union_type),
+                                .opt_payload => assert(ip.indexToKey(
+                                    ip.indexToKey(ip.typeOf(base)).ptr_type.elem_type,
+                                ) == .opt_type),
+                                else => unreachable,
+                            }
                             ip.items.appendAssumeCapacity(.{
                                 .tag = switch (ptr.addr) {
+                                    .int => .ptr_int,
                                     .eu_payload => .ptr_eu_payload,
                                     .opt_payload => .ptr_opt_payload,
                                     else => unreachable,
                                 },
-                                .data = @enumToInt(data),
-                            });
-                        },
-                        .comptime_field => |field_val| {
-                            assert(field_val != .none);
-                            ip.items.appendAssumeCapacity(.{
-                                .tag = .ptr_comptime_field,
-                                .data = try ip.addExtra(gpa, PtrComptimeField{
+                                .data = try ip.addExtra(gpa, PtrBase{
                                     .ty = ptr.ty,
-                                    .field_val = field_val,
+                                    .base = base,
                                 }),
                             });
                         },
                         .elem, .field => |base_index| {
-                            assert(base_index.base != .none);
+                            const base_ptr_type = ip.indexToKey(ip.typeOf(base_index.base)).ptr_type;
+                            switch (base_ptr_type.size) {
+                                .One => switch (ip.indexToKey(base_ptr_type.elem_type)) {
+                                    .array_type, .vector_type => assert(ptr.addr == .elem),
+                                    .anon_struct_type => |anon_struct_type| {
+                                        assert(ptr.addr == .field);
+                                        assert(base_index.index < anon_struct_type.types.len);
+                                    },
+                                    .struct_type => |struct_type| {
+                                        assert(ptr.addr == .field);
+                                        assert(base_index.index < ip.structPtrUnwrapConst(struct_type.index).?.fields.count());
+                                    },
+                                    .union_type => |union_type| {
+                                        assert(ptr.addr == .field);
+                                        assert(base_index.index < ip.unionPtrConst(union_type.index).fields.count());
+                                    },
+                                    .ptr_type => |slice_type| {
+                                        assert(ptr.addr == .field);
+                                        assert(slice_type.size == .Slice);
+                                        assert(base_index.index < 2);
+                                    },
+                                    else => unreachable,
+                                },
+                                .Many => assert(ptr.addr == .elem),
+                                .Slice, .C => unreachable,
+                            }
                             _ = ip.map.pop();
                             const index_index = try ip.get(gpa, .{ .int = .{
                                 .ty = .usize_type,
@@ -4750,10 +4761,10 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
             .simple_value => 0,
             .ptr_decl => @sizeOf(PtrDecl),
             .ptr_mut_decl => @sizeOf(PtrMutDecl),
-            .ptr_int => @sizeOf(PtrAddr),
-            .ptr_eu_payload => 0,
-            .ptr_opt_payload => 0,
             .ptr_comptime_field => @sizeOf(PtrComptimeField),
+            .ptr_int => @sizeOf(PtrBase),
+            .ptr_eu_payload => @sizeOf(PtrBase),
+            .ptr_opt_payload => @sizeOf(PtrBase),
             .ptr_elem => @sizeOf(PtrBaseIndex),
             .ptr_field => @sizeOf(PtrBaseIndex),
             .ptr_slice => @sizeOf(PtrSlice),
@@ -5281,12 +5292,12 @@ pub fn zigTypeTagOrPoison(ip: InternPool, index: Index) error{GenericPoison}!std
             .undef,
             .runtime_value,
             .simple_value,
-            .ptr_mut_decl,
             .ptr_decl,
+            .ptr_mut_decl,
+            .ptr_comptime_field,
             .ptr_int,
             .ptr_eu_payload,
             .ptr_opt_payload,
-            .ptr_comptime_field,
             .ptr_elem,
             .ptr_field,
             .ptr_slice,
src/Module.zig
@@ -6716,6 +6716,10 @@ pub fn singleConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type {
     return ptrType(mod, .{ .elem_type = child_type.toIntern(), .is_const = true });
 }
 
+pub fn manyConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type {
+    return ptrType(mod, .{ .elem_type = child_type.toIntern(), .size = .Many, .is_const = true });
+}
+
 pub fn adjustPtrTypeChild(mod: *Module, ptr_ty: Type, new_child: Type) Allocator.Error!Type {
     const info = Type.ptrInfoIp(mod.intern_pool, ptr_ty.toIntern());
     return mod.ptrType(.{
src/Sema.zig
@@ -25412,11 +25412,13 @@ fn elemVal(
                     const indexable_val = maybe_indexable_val orelse break :rs indexable_src;
                     const index_val = maybe_index_val orelse break :rs elem_index_src;
                     const index = @intCast(usize, index_val.toUnsignedInt(mod));
-                    const elem_ptr_ty = try sema.elemPtrType(indexable_ty, index);
-                    const elem_ptr_val = try indexable_val.elemPtr(elem_ptr_ty, index, mod);
+                    const elem_ty = indexable_ty.elemType2(mod);
+                    const many_ptr_ty = try mod.manyConstPtrType(elem_ty);
+                    const many_ptr_val = try mod.getCoerced(indexable_val, many_ptr_ty);
+                    const elem_ptr_ty = try mod.singleConstPtrType(elem_ty);
+                    const elem_ptr_val = try many_ptr_val.elemPtr(elem_ptr_ty, index, mod);
                     if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {
-                        const result_ty = indexable_ty.elemType2(mod);
-                        return sema.addConstant(result_ty, try mod.getCoerced(elem_val, result_ty));
+                        return sema.addConstant(elem_ty, try mod.getCoerced(elem_val, elem_ty));
                     }
                     break :rs indexable_src;
                 };
@@ -29906,7 +29908,7 @@ fn analyzeSlice(
     const ptr_ptr_ty = sema.typeOf(ptr_ptr);
     const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag(mod)) {
         .Pointer => ptr_ptr_ty.childType(mod),
-        else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(sema.mod)}),
+        else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(mod)}),
     };
 
     var array_ty = ptr_ptr_child_ty;
@@ -30111,7 +30113,10 @@ fn analyzeSlice(
                 const end_int = end_val.getUnsignedInt(mod).?;
                 const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int);
 
-                const elem_ptr = try ptr_val.elemPtr(try sema.elemPtrType(new_ptr_ty, sentinel_index), sentinel_index, sema.mod);
+                const many_ptr_ty = try mod.manyConstPtrType(elem_ty);
+                const many_ptr_val = try mod.getCoerced(ptr_val, many_ptr_ty);
+                const elem_ptr_ty = try mod.singleConstPtrType(elem_ty);
+                const elem_ptr = try many_ptr_val.elemPtr(elem_ptr_ty, sentinel_index, mod);
                 const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty);
                 const actual_sentinel = switch (res) {
                     .runtime_load => break :sentinel_check,
@@ -30120,23 +30125,23 @@ fn analyzeSlice(
                         block,
                         src,
                         "comptime dereference requires '{}' to have a well-defined layout, but it does not.",
-                        .{ty.fmt(sema.mod)},
+                        .{ty.fmt(mod)},
                     ),
                     .out_of_bounds => |ty| return sema.fail(
                         block,
                         end_src,
                         "slice end index {d} exceeds bounds of containing decl of type '{}'",
-                        .{ end_int, ty.fmt(sema.mod) },
+                        .{ end_int, ty.fmt(mod) },
                     ),
                 };
 
-                if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) {
+                if (!actual_sentinel.eql(expected_sentinel, elem_ty, mod)) {
                     const msg = msg: {
                         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, sema.mod),
-                            actual_sentinel.fmtValue(elem_ty, sema.mod),
+                            expected_sentinel.fmtValue(elem_ty, mod),
+                            actual_sentinel.fmtValue(elem_ty, mod),
                         });
 
                         break :msg msg;
@@ -30310,7 +30315,7 @@ fn cmpNumeric(
 
     const lhs_ty_tag = lhs_ty.zigTypeTag(mod);
     const rhs_ty_tag = rhs_ty.zigTypeTag(mod);
-    const target = sema.mod.getTarget();
+    const target = mod.getTarget();
 
     // One exception to heterogeneous comparison: comptime_float needs to
     // coerce to fixed-width float.
src/value.zig
@@ -1857,7 +1857,8 @@ pub const Value = struct {
                     .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index),
                     .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod))
                         .toValue().elemValue(mod, index),
-                    .int, .eu_payload, .opt_payload => unreachable,
+                    .int, .eu_payload => unreachable,
+                    .opt_payload => |base| base.toValue().elemValue(mod, index),
                     .comptime_field => |field_val| field_val.toValue().elemValue(mod, index),
                     .elem => |elem| elem.base.toValue().elemValue(mod, index + elem.index),
                     .field => |field| if (field.base.toValue().pointerDecl(mod)) |decl_index| {
@@ -1866,6 +1867,7 @@ pub const Value = struct {
                         return field_val.elemValue(mod, index);
                     } else unreachable,
                 },
+                .opt => |opt| opt.val.toValue().elemValue(mod, index),
                 .aggregate => |aggregate| {
                     const len = mod.intern_pool.aggregateTypeLen(aggregate.ty);
                     if (index < len) return switch (aggregate.storage) {