InternPool: safer enum API

The key changes in this commit are:

```diff
-        names: []const NullTerminatedString,
+        names: NullTerminatedString.Slice,
-        values: []const Index,
+        values: Index.Slice,
```

Which eliminates the slices from `InternPool.Key.EnumType` and replaces
them with structs that contain `start` and `len` indexes. This makes the
lifetime of `EnumType` change from expiring with updates to InternPool,
to expiring when the InternPool is garbage-collected, which is currently
never.

This is gearing up for a larger change I started working on locally
which moves union types into InternPool.

As a bonus, I fixed some unnecessary instances of `@as`.
This commit is contained in:
Andrew Kelley 2023-08-17 14:25:18 -07:00
parent 8c1329b222
commit 7ef1eb1c27
8 changed files with 176 additions and 142 deletions

View File

@ -105,7 +105,7 @@ pub const OptionalMapIndex = enum(u32) {
pub fn unwrap(oi: OptionalMapIndex) ?MapIndex {
if (oi == .none) return null;
return @as(MapIndex, @enumFromInt(@intFromEnum(oi)));
return @enumFromInt(@intFromEnum(oi));
}
};
@ -114,7 +114,7 @@ pub const MapIndex = enum(u32) {
_,
pub fn toOptional(i: MapIndex) OptionalMapIndex {
return @as(OptionalMapIndex, @enumFromInt(@intFromEnum(i)));
return @enumFromInt(@intFromEnum(i));
}
};
@ -218,7 +218,7 @@ pub const OptionalNullTerminatedString = enum(u32) {
pub fn unwrap(oi: OptionalNullTerminatedString) ?NullTerminatedString {
if (oi == .none) return null;
return @as(NullTerminatedString, @enumFromInt(@intFromEnum(oi)));
return @enumFromInt(@intFromEnum(oi));
}
};
@ -415,11 +415,11 @@ pub const Key = union(enum) {
/// explicitly provided tag type or auto-numbered.
tag_ty: Index,
/// Set of field names in declaration order.
names: []const NullTerminatedString,
names: NullTerminatedString.Slice,
/// Maps integer tag value to field index.
/// Entries are in declaration order, same as `fields`.
/// If this is empty, it means the enum tags are auto-numbered.
values: []const Index,
values: Index.Slice,
tag_mode: TagMode,
/// This is ignored by `get` but will always be provided by `indexToKey`.
names_map: OptionalMapIndex = .none,
@ -441,9 +441,9 @@ pub const Key = union(enum) {
/// Look up field index based on field name.
pub fn nameIndex(self: EnumType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
const map = &ip.maps.items[@intFromEnum(self.names_map.unwrap().?)];
const adapter: NullTerminatedString.Adapter = .{ .strings = self.names };
const adapter: NullTerminatedString.Adapter = .{ .strings = self.names.get(ip) };
const field_index = map.getIndexAdapted(name, adapter) orelse return null;
return @as(u32, @intCast(field_index));
return @intCast(field_index);
}
/// Look up field index based on tag value.
@ -461,9 +461,9 @@ pub const Key = union(enum) {
};
if (self.values_map.unwrap()) |values_map| {
const map = &ip.maps.items[@intFromEnum(values_map)];
const adapter: Index.Adapter = .{ .indexes = self.values };
const adapter: Index.Adapter = .{ .indexes = self.values.get(ip) };
const field_index = map.getIndexAdapted(int_tag_val, adapter) orelse return null;
return @as(u32, @intCast(field_index));
return @intCast(field_index);
}
// Auto-numbered enum. Convert `int_tag_val` to field index.
const field_index = switch (ip.indexToKey(int_tag_val).int.storage) {
@ -497,8 +497,8 @@ pub const Key = union(enum) {
.namespace = self.namespace,
.tag_ty = self.tag_ty,
.tag_mode = self.tag_mode,
.names = &.{},
.values = &.{},
.names = .{ .start = 0, .len = 0 },
.values = .{ .start = 0, .len = 0 },
};
}
@ -2570,7 +2570,7 @@ pub const Alignment = enum(u6) {
pub fn fromByteUnits(n: u64) Alignment {
if (n == 0) return .none;
assert(std.math.isPowerOfTwo(n));
return @as(Alignment, @enumFromInt(@ctz(n)));
return @enumFromInt(@ctz(n));
}
pub fn fromNonzeroByteUnits(n: u64) Alignment {
@ -2647,11 +2647,11 @@ pub const PackedU64 = packed struct(u64) {
b: u32,
pub fn get(x: PackedU64) u64 {
return @as(u64, @bitCast(x));
return @bitCast(x);
}
pub fn init(x: u64) PackedU64 {
return @as(PackedU64, @bitCast(x));
return @bitCast(x);
}
};
@ -2714,7 +2714,7 @@ pub const Float64 = struct {
pub fn get(self: Float64) f64 {
const int_bits = @as(u64, self.piece0) | (@as(u64, self.piece1) << 32);
return @as(f64, @bitCast(int_bits));
return @bitCast(int_bits);
}
fn pack(val: f64) Float64 {
@ -2736,7 +2736,7 @@ pub const Float80 = struct {
const int_bits = @as(u80, self.piece0) |
(@as(u80, self.piece1) << 32) |
(@as(u80, self.piece2) << 64);
return @as(f80, @bitCast(int_bits));
return @bitCast(int_bits);
}
fn pack(val: f80) Float80 {
@ -2761,7 +2761,7 @@ pub const Float128 = struct {
(@as(u128, self.piece1) << 32) |
(@as(u128, self.piece2) << 64) |
(@as(u128, self.piece3) << 96);
return @as(f128, @bitCast(int_bits));
return @bitCast(int_bits);
}
fn pack(val: f128) Float128 {
@ -2968,16 +2968,18 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
.type_enum_auto => {
const enum_auto = ip.extraDataTrail(EnumAuto, data);
const names = @as(
[]const NullTerminatedString,
@ptrCast(ip.extra.items[enum_auto.end..][0..enum_auto.data.fields_len]),
);
return .{ .enum_type = .{
.decl = enum_auto.data.decl,
.namespace = enum_auto.data.namespace,
.tag_ty = enum_auto.data.int_tag_type,
.names = names,
.values = &.{},
.names = .{
.start = @intCast(enum_auto.end),
.len = enum_auto.data.fields_len,
},
.values = .{
.start = 0,
.len = 0,
},
.tag_mode = .auto,
.names_map = enum_auto.data.names_map.toOptional(),
.values_map = .none,
@ -3443,21 +3445,19 @@ fn extraFuncCoerced(ip: *const InternPool, extra_index: u32) Key.Func {
fn indexToKeyEnum(ip: *const InternPool, data: u32, tag_mode: Key.EnumType.TagMode) Key {
const enum_explicit = ip.extraDataTrail(EnumExplicit, data);
const names = @as(
[]const NullTerminatedString,
@ptrCast(ip.extra.items[enum_explicit.end..][0..enum_explicit.data.fields_len]),
);
const values = if (enum_explicit.data.values_map != .none) @as(
[]const Index,
@ptrCast(ip.extra.items[enum_explicit.end + names.len ..][0..enum_explicit.data.fields_len]),
) else &[0]Index{};
const fields_len = enum_explicit.data.fields_len;
return .{ .enum_type = .{
.decl = enum_explicit.data.decl,
.namespace = enum_explicit.data.namespace,
.tag_ty = enum_explicit.data.int_tag_type,
.names = names,
.values = values,
.names = .{
.start = @intCast(enum_explicit.end),
.len = fields_len,
},
.values = .{
.start = @intCast(enum_explicit.end + fields_len),
.len = if (enum_explicit.data.values_map != .none) fields_len else 0,
},
.tag_mode = tag_mode,
.names_map = enum_explicit.data.names_map.toOptional(),
.values_map = enum_explicit.data.values_map,
@ -3506,7 +3506,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.tag = .type_slice,
.data = @intFromEnum(ptr_type_index),
});
return @as(Index, @enumFromInt(ip.items.len - 1));
return @enumFromInt(ip.items.len - 1);
}
var ptr_type_adjusted = ptr_type;
@ -3530,7 +3530,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.child = array_type.child,
}),
});
return @as(Index, @enumFromInt(ip.items.len - 1));
return @enumFromInt(ip.items.len - 1);
}
}
@ -3643,7 +3643,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
assert(anon_struct_type.types.len == anon_struct_type.values.len);
for (anon_struct_type.types) |elem| assert(elem != .none);
const fields_len = @as(u32, @intCast(anon_struct_type.types.len));
const fields_len: u32 = @intCast(anon_struct_type.types.len);
if (anon_struct_type.names.len == 0) {
try ip.extra.ensureUnusedCapacity(
gpa,
@ -3655,9 +3655,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.fields_len = fields_len,
}),
});
ip.extra.appendSliceAssumeCapacity(@as([]const u32, @ptrCast(anon_struct_type.types)));
ip.extra.appendSliceAssumeCapacity(@as([]const u32, @ptrCast(anon_struct_type.values)));
return @as(Index, @enumFromInt(ip.items.len - 1));
ip.extra.appendSliceAssumeCapacity(@ptrCast(anon_struct_type.types));
ip.extra.appendSliceAssumeCapacity(@ptrCast(anon_struct_type.values));
return @enumFromInt(ip.items.len - 1);
}
assert(anon_struct_type.names.len == anon_struct_type.types.len);
@ -3672,10 +3672,10 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.fields_len = fields_len,
}),
});
ip.extra.appendSliceAssumeCapacity(@as([]const u32, @ptrCast(anon_struct_type.types)));
ip.extra.appendSliceAssumeCapacity(@as([]const u32, @ptrCast(anon_struct_type.values)));
ip.extra.appendSliceAssumeCapacity(@as([]const u32, @ptrCast(anon_struct_type.names)));
return @as(Index, @enumFromInt(ip.items.len - 1));
ip.extra.appendSliceAssumeCapacity(@ptrCast(anon_struct_type.types));
ip.extra.appendSliceAssumeCapacity(@ptrCast(anon_struct_type.values));
ip.extra.appendSliceAssumeCapacity(@ptrCast(anon_struct_type.names));
return @enumFromInt(ip.items.len - 1);
},
.union_type => |union_type| {
@ -3696,38 +3696,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
});
},
.enum_type => |enum_type| {
assert(enum_type.tag_ty == .noreturn_type or ip.isIntegerType(enum_type.tag_ty));
for (enum_type.values) |value| assert(ip.typeOf(value) == enum_type.tag_ty);
assert(enum_type.names_map == .none);
assert(enum_type.values_map == .none);
switch (enum_type.tag_mode) {
.auto => {
const names_map = try ip.addMap(gpa);
try addStringsToMap(ip, gpa, names_map, enum_type.names);
const fields_len = @as(u32, @intCast(enum_type.names.len));
try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
fields_len);
ip.items.appendAssumeCapacity(.{
.tag = .type_enum_auto,
.data = ip.addExtraAssumeCapacity(EnumAuto{
.decl = enum_type.decl,
.namespace = enum_type.namespace,
.int_tag_type = enum_type.tag_ty,
.names_map = names_map,
.fields_len = fields_len,
}),
});
ip.extra.appendSliceAssumeCapacity(@as([]const u32, @ptrCast(enum_type.names)));
return @as(Index, @enumFromInt(ip.items.len - 1));
},
.explicit => return finishGetEnum(ip, gpa, enum_type, .type_enum_explicit),
.nonexhaustive => return finishGetEnum(ip, gpa, enum_type, .type_enum_nonexhaustive),
}
},
.enum_type => unreachable, // use getEnum() or getIncompleteEnum() instead
.func_type => unreachable, // use getFuncType() instead
.extern_func => unreachable, // use getExternFunc() instead
.func => unreachable, // use getFuncInstance() or getFuncDecl() instead
@ -3915,7 +3884,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.lazy_ty = lazy_ty,
}),
});
return @as(Index, @enumFromInt(ip.items.len - 1));
return @enumFromInt(ip.items.len - 1);
},
}
switch (int.ty) {
@ -4056,7 +4025,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.value = casted,
}),
});
return @as(Index, @enumFromInt(ip.items.len - 1));
return @enumFromInt(ip.items.len - 1);
} else |_| {}
const tag: Tag = if (big_int.positive) .int_positive else .int_negative;
@ -4071,7 +4040,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.value = casted,
}),
});
return @as(Index, @enumFromInt(ip.items.len - 1));
return @enumFromInt(ip.items.len - 1);
}
var buf: [2]Limb = undefined;
@ -4234,7 +4203,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.tag = .only_possible_value,
.data = @intFromEnum(aggregate.ty),
});
return @as(Index, @enumFromInt(ip.items.len - 1));
return @enumFromInt(ip.items.len - 1);
}
switch (ty_key) {
@ -4262,7 +4231,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.tag = .only_possible_value,
.data = @intFromEnum(aggregate.ty),
});
return @as(Index, @enumFromInt(ip.items.len - 1));
return @enumFromInt(ip.items.len - 1);
},
else => {},
}
@ -4301,7 +4270,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.elem_val = elem,
}),
});
return @as(Index, @enumFromInt(ip.items.len - 1));
return @enumFromInt(ip.items.len - 1);
}
if (child == .u8_type) bytes: {
@ -4345,7 +4314,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.bytes = string,
}),
});
return @as(Index, @enumFromInt(ip.items.len - 1));
return @enumFromInt(ip.items.len - 1);
}
try ip.extra.ensureUnusedCapacity(
@ -4358,7 +4327,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.ty = aggregate.ty,
}),
});
ip.extra.appendSliceAssumeCapacity(@as([]const u32, @ptrCast(aggregate.storage.elems)));
ip.extra.appendSliceAssumeCapacity(@ptrCast(aggregate.storage.elems));
if (sentinel != .none) ip.extra.appendAssumeCapacity(@intFromEnum(sentinel));
},
@ -4384,7 +4353,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.result = memoized_call.result,
}),
});
ip.extra.appendSliceAssumeCapacity(@as([]const u32, @ptrCast(memoized_call.arg_values)));
ip.extra.appendSliceAssumeCapacity(@ptrCast(memoized_call.arg_values));
},
}
return @enumFromInt(ip.items.len - 1);
@ -5017,7 +4986,7 @@ pub const IncompleteEnumType = struct {
.strings = @as([]const NullTerminatedString, @ptrCast(strings)),
};
const gop = try map.getOrPutAdapted(gpa, name, adapter);
if (gop.found_existing) return @as(u32, @intCast(gop.index));
if (gop.found_existing) return @intCast(gop.index);
ip.extra.items[self.names_start + field_index] = @intFromEnum(name);
return null;
}
@ -5038,7 +5007,7 @@ pub const IncompleteEnumType = struct {
.indexes = @as([]const Index, @ptrCast(indexes)),
};
const gop = try map.getOrPutAdapted(gpa, value, adapter);
if (gop.found_existing) return @as(u32, @intCast(gop.index));
if (gop.found_existing) return @intCast(gop.index);
ip.extra.items[self.values_start + field_index] = @intFromEnum(value);
return null;
}
@ -5158,36 +5127,94 @@ fn getIncompleteEnumExplicit(
};
}
pub const GetEnumInit = struct {
decl: Module.Decl.Index,
namespace: Module.Namespace.OptionalIndex,
tag_ty: Index,
names: []const NullTerminatedString,
values: []const Index,
tag_mode: Key.EnumType.TagMode,
};
pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Error!Index {
const adapter: KeyAdapter = .{ .intern_pool = ip };
const gop = try ip.map.getOrPutAdapted(gpa, Key{
.enum_type = .{
// Only the decl is used for hashing and equality.
.decl = ini.decl,
.namespace = undefined,
.tag_ty = undefined,
.names = undefined,
.values = undefined,
.tag_mode = undefined,
.names_map = undefined,
.values_map = undefined,
},
}, adapter);
if (gop.found_existing) return @enumFromInt(gop.index);
errdefer _ = ip.map.pop();
try ip.items.ensureUnusedCapacity(gpa, 1);
assert(ini.tag_ty == .noreturn_type or ip.isIntegerType(ini.tag_ty));
for (ini.values) |value| assert(ip.typeOf(value) == ini.tag_ty);
switch (ini.tag_mode) {
.auto => {
const names_map = try ip.addMap(gpa);
try addStringsToMap(ip, gpa, names_map, ini.names);
const fields_len: u32 = @intCast(ini.names.len);
try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
fields_len);
ip.items.appendAssumeCapacity(.{
.tag = .type_enum_auto,
.data = ip.addExtraAssumeCapacity(EnumAuto{
.decl = ini.decl,
.namespace = ini.namespace,
.int_tag_type = ini.tag_ty,
.names_map = names_map,
.fields_len = fields_len,
}),
});
ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
return @enumFromInt(ip.items.len - 1);
},
.explicit => return finishGetEnum(ip, gpa, ini, .type_enum_explicit),
.nonexhaustive => return finishGetEnum(ip, gpa, ini, .type_enum_nonexhaustive),
}
}
pub fn finishGetEnum(
ip: *InternPool,
gpa: Allocator,
enum_type: Key.EnumType,
ini: GetEnumInit,
tag: Tag,
) Allocator.Error!Index {
const names_map = try ip.addMap(gpa);
try addStringsToMap(ip, gpa, names_map, enum_type.names);
try addStringsToMap(ip, gpa, names_map, ini.names);
const values_map: OptionalMapIndex = if (enum_type.values.len == 0) .none else m: {
const values_map: OptionalMapIndex = if (ini.values.len == 0) .none else m: {
const values_map = try ip.addMap(gpa);
try addIndexesToMap(ip, gpa, values_map, enum_type.values);
try addIndexesToMap(ip, gpa, values_map, ini.values);
break :m values_map.toOptional();
};
const fields_len = @as(u32, @intCast(enum_type.names.len));
const fields_len: u32 = @intCast(ini.names.len);
try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumExplicit).Struct.fields.len +
fields_len);
ip.items.appendAssumeCapacity(.{
.tag = tag,
.data = ip.addExtraAssumeCapacity(EnumExplicit{
.decl = enum_type.decl,
.namespace = enum_type.namespace,
.int_tag_type = enum_type.tag_ty,
.decl = ini.decl,
.namespace = ini.namespace,
.int_tag_type = ini.tag_ty,
.fields_len = fields_len,
.names_map = names_map,
.values_map = values_map,
}),
});
ip.extra.appendSliceAssumeCapacity(@ptrCast(enum_type.names));
ip.extra.appendSliceAssumeCapacity(@ptrCast(enum_type.values));
ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.values));
return @enumFromInt(ip.items.len - 1);
}
@ -5486,7 +5513,7 @@ pub fn slicePtrType(ip: *const InternPool, i: Index) Index {
}
const item = ip.items.get(@intFromEnum(i));
switch (item.tag) {
.type_slice => return @as(Index, @enumFromInt(item.data)),
.type_slice => return @enumFromInt(item.data),
else => unreachable, // not a slice type
}
}
@ -5618,7 +5645,7 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
return ip.get(gpa, .{ .enum_tag = .{
.ty = new_ty,
.int = if (enum_type.values.len != 0)
enum_type.values[index]
enum_type.values.get(ip)[index]
else
try ip.get(gpa, .{ .int = .{
.ty = enum_type.tag_ty,
@ -6362,7 +6389,7 @@ pub fn createStruct(
}
const ptr = try ip.allocated_structs.addOne(gpa);
ptr.* = initialization;
return @as(Module.Struct.Index, @enumFromInt(ip.allocated_structs.len - 1));
return @enumFromInt(ip.allocated_structs.len - 1);
}
pub fn destroyStruct(ip: *InternPool, gpa: Allocator, index: Module.Struct.Index) void {
@ -6384,7 +6411,7 @@ pub fn createUnion(
}
const ptr = try ip.allocated_unions.addOne(gpa);
ptr.* = initialization;
return @as(Module.Union.Index, @enumFromInt(ip.allocated_unions.len - 1));
return @enumFromInt(ip.allocated_unions.len - 1);
}
pub fn destroyUnion(ip: *InternPool, gpa: Allocator, index: Module.Union.Index) void {
@ -6406,7 +6433,7 @@ pub fn createDecl(
}
const ptr = try ip.allocated_decls.addOne(gpa);
ptr.* = initialization;
return @as(Module.Decl.Index, @enumFromInt(ip.allocated_decls.len - 1));
return @enumFromInt(ip.allocated_decls.len - 1);
}
pub fn destroyDecl(ip: *InternPool, gpa: Allocator, index: Module.Decl.Index) void {
@ -6428,7 +6455,7 @@ pub fn createNamespace(
}
const ptr = try ip.allocated_namespaces.addOne(gpa);
ptr.* = initialization;
return @as(Module.Namespace.Index, @enumFromInt(ip.allocated_namespaces.len - 1));
return @enumFromInt(ip.allocated_namespaces.len - 1);
}
pub fn destroyNamespace(ip: *InternPool, gpa: Allocator, index: Module.Namespace.Index) void {
@ -6495,11 +6522,11 @@ pub fn getOrPutTrailingString(
});
if (gop.found_existing) {
string_bytes.shrinkRetainingCapacity(str_index);
return @as(NullTerminatedString, @enumFromInt(gop.key_ptr.*));
return @enumFromInt(gop.key_ptr.*);
} else {
gop.key_ptr.* = str_index;
string_bytes.appendAssumeCapacity(0);
return @as(NullTerminatedString, @enumFromInt(str_index));
return @enumFromInt(str_index);
}
}
@ -6725,7 +6752,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
/// Assumes that the enum's field indexes equal its value tags.
pub fn toEnum(ip: *const InternPool, comptime E: type, i: Index) E {
const int = ip.indexToKey(i).enum_tag.int;
return @as(E, @enumFromInt(ip.indexToKey(int).int.storage.u64));
return @enumFromInt(ip.indexToKey(int).int.storage.u64);
}
pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {
@ -6758,9 +6785,9 @@ pub fn funcTypeReturnType(ip: *const InternPool, ty: Index) Index {
else => unreachable,
};
assert(child_item.tag == .type_function);
return @as(Index, @enumFromInt(ip.extra.items[
return @enumFromInt(ip.extra.items[
child_item.data + std.meta.fieldIndex(Tag.TypeFunction, "return_type").?
]));
]);
}
pub fn isNoReturn(ip: *const InternPool, ty: Index) bool {
@ -6791,9 +6818,9 @@ pub fn getBackingDecl(ip: *const InternPool, val: Index) Module.Decl.OptionalInd
switch (ip.items.items(.tag)[base]) {
inline .ptr_decl,
.ptr_mut_decl,
=> |tag| return @as(Module.Decl.OptionalIndex, @enumFromInt(ip.extra.items[
=> |tag| return @enumFromInt(ip.extra.items[
ip.items.items(.data)[base] + std.meta.fieldIndex(tag.Payload(), "decl").?
])),
]),
inline .ptr_eu_payload,
.ptr_opt_payload,
.ptr_elem,

View File

@ -6655,7 +6655,7 @@ pub fn enumValueFieldIndex(mod: *Module, ty: Type, field_index: u32) Allocator.E
return (try ip.get(gpa, .{ .enum_tag = .{
.ty = ty.toIntern(),
.int = enum_type.values[field_index],
.int = enum_type.values.get(ip)[field_index],
} })).toValue();
}

View File

@ -17170,14 +17170,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
for (enum_field_vals, 0..) |*field_val, i| {
const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
const value_val = if (enum_type.values.len > 0)
try mod.intern_pool.getCoerced(gpa, enum_type.values[i], .comptime_int_type)
try mod.intern_pool.getCoerced(gpa, enum_type.values.get(ip)[i], .comptime_int_type)
else
try mod.intern(.{ .int = .{
.ty = .comptime_int_type,
.storage = .{ .u64 = @as(u64, @intCast(i)) },
} });
// TODO: write something like getCoercedInts to avoid needing to dupe
const name = try sema.arena.dupe(u8, ip.stringToSlice(enum_type.names[i]));
const name = try sema.arena.dupe(u8, ip.stringToSlice(enum_type.names.get(ip)[i]));
const name_val = v: {
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
@ -20601,7 +20601,7 @@ fn zirReify(
errdefer msg.destroy(gpa);
const enum_ty = union_obj.tag_ty;
for (tag_info.names, 0..) |field_name, field_index| {
for (tag_info.names.get(ip), 0..) |field_name, field_index| {
if (explicit_tags_seen[field_index]) continue;
try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{}' missing, declared here", .{
field_name.fmt(ip),
@ -35420,7 +35420,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
errdefer msg.destroy(sema.gpa);
const enum_ty = union_obj.tag_ty;
for (tag_info.names, 0..) |field_name, field_index| {
for (tag_info.names.get(ip), 0..) |field_name, field_index| {
if (explicit_tags_seen[field_index]) continue;
try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{}' missing, declared here", .{
field_name.fmt(ip),
@ -35452,12 +35452,13 @@ fn generateUnionTagTypeNumbered(
) !Type {
const mod = sema.mod;
const gpa = sema.gpa;
const ip = &mod.intern_pool;
const src_decl = mod.declPtr(block.src_decl);
const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
errdefer mod.destroyDecl(new_decl_index);
const fqn = try union_obj.getFullyQualifiedName(mod);
const name = try mod.intern_pool.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(&mod.intern_pool)});
const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{
.ty = Type.noreturn,
.val = Value.@"unreachable",
@ -35469,17 +35470,17 @@ fn generateUnionTagTypeNumbered(
new_decl.owns_tv = true;
new_decl.name_fully_qualified = true;
const enum_ty = try mod.intern(.{ .enum_type = .{
const enum_ty = try ip.getEnum(gpa, .{
.decl = new_decl_index,
.namespace = .none,
.tag_ty = if (enum_field_vals.len == 0)
(try mod.intType(.unsigned, 0)).toIntern()
else
mod.intern_pool.typeOf(enum_field_vals[0]),
ip.typeOf(enum_field_vals[0]),
.names = enum_field_names,
.values = enum_field_vals,
.tag_mode = .explicit,
} });
});
new_decl.ty = Type.type;
new_decl.val = enum_ty.toValue();
@ -35495,6 +35496,7 @@ fn generateUnionTagTypeSimple(
maybe_union_obj: ?*Module.Union,
) !Type {
const mod = sema.mod;
const ip = &mod.intern_pool;
const gpa = sema.gpa;
const new_decl_index = new_decl_index: {
@ -35508,7 +35510,7 @@ fn generateUnionTagTypeSimple(
const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
errdefer mod.destroyDecl(new_decl_index);
const fqn = try union_obj.getFullyQualifiedName(mod);
const name = try mod.intern_pool.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(&mod.intern_pool)});
const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{
.ty = Type.noreturn,
.val = Value.@"unreachable",
@ -35518,7 +35520,7 @@ fn generateUnionTagTypeSimple(
};
errdefer mod.abortAnonDecl(new_decl_index);
const enum_ty = try mod.intern(.{ .enum_type = .{
const enum_ty = try ip.getEnum(gpa, .{
.decl = new_decl_index,
.namespace = .none,
.tag_ty = if (enum_field_names.len == 0)
@ -35528,7 +35530,7 @@ fn generateUnionTagTypeSimple(
.names = enum_field_names,
.values = &.{},
.tag_mode = .auto,
} });
});
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
@ -35625,6 +35627,7 @@ fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
/// TODO assert the return value matches `ty.onePossibleValue`
pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
const mod = sema.mod;
const ip = &mod.intern_pool;
return switch (ty.toIntern()) {
.u0_type,
.i0_type,
@ -35718,7 +35721,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
.none,
=> unreachable,
_ => switch (mod.intern_pool.items.items(.tag)[@intFromEnum(ty.toIntern())]) {
_ => switch (ip.items.items(.tag)[@intFromEnum(ty.toIntern())]) {
.type_int_signed, // i0 handled above
.type_int_unsigned, // u0 handled above
.type_pointer,
@ -35801,7 +35804,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
.type_union_tagged,
.type_union_untagged,
.type_union_safety,
=> switch (mod.intern_pool.indexToKey(ty.toIntern())) {
=> switch (ip.indexToKey(ty.toIntern())) {
inline .array_type, .vector_type => |seq_type, seq_tag| {
const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none;
if (seq_type.len + @intFromBool(has_sentinel) == 0) return (try mod.intern(.{ .aggregate = .{
@ -35930,7 +35933,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
.storage = .{ .u64 = 0 },
} })
else
enum_type.values[0]).toValue(), ty),
enum_type.values.get(ip)[0]).toValue(), ty),
else => return null,
}
},

View File

@ -238,7 +238,7 @@ pub fn print(
}
const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| {
try writer.print(".{i}", .{enum_type.names[tag_index].fmt(ip)});
try writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)});
return;
}
try writer.writeAll("@enumFromInt(");

View File

@ -1909,12 +1909,12 @@ pub const Object = struct {
const int_info = ty.intInfo(mod);
assert(int_info.bits != 0);
for (enum_type.names, 0..) |field_name_ip, i| {
for (enum_type.names.get(ip), 0..) |field_name_ip, i| {
const field_name_z = ip.stringToSlice(field_name_ip);
var bigint_space: Value.BigIntSpace = undefined;
const bigint = if (enum_type.values.len != 0)
enum_type.values[i].toValue().toBigInt(&bigint_space, mod)
enum_type.values.get(ip)[i].toValue().toBigInt(&bigint_space, mod)
else
std.math.big.int.Mutable.init(&bigint_space.limbs, i).toConst();
@ -9206,7 +9206,8 @@ pub const FuncGen = struct {
fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
const o = self.dg.object;
const mod = o.module;
const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;
const ip = &mod.intern_pool;
const enum_type = ip.indexToKey(enum_ty.toIntern()).enum_type;
// TODO: detect when the type changes and re-emit this function.
const gop = try o.decl_map.getOrPut(o.gpa, enum_type.decl);
@ -9218,7 +9219,7 @@ pub const FuncGen = struct {
const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
const function_index = try o.builder.addFunction(
try o.builder.fnType(ret_ty, &.{try o.lowerType(enum_type.tag_ty.toType())}, .normal),
try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(&mod.intern_pool)}),
try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(ip)}),
toLlvmAddressSpace(.generic, mod.getTarget()),
);
@ -9241,8 +9242,8 @@ pub const FuncGen = struct {
try wip.@"switch"(tag_int_value, bad_value_block, @intCast(enum_type.names.len));
defer wip_switch.finish(&wip);
for (enum_type.names, 0..) |name, field_index| {
const name_string = try o.builder.string(mod.intern_pool.stringToSlice(name));
for (enum_type.names.get(ip), 0..) |name, field_index| {
const name_string = try o.builder.string(ip.stringToSlice(name));
const name_init = try o.builder.stringNullConst(name_string);
const name_variable_index =
try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);

View File

@ -388,9 +388,10 @@ pub const DeclState = struct {
try ty.print(dbg_info_buffer.writer(), mod);
try dbg_info_buffer.append(0);
const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
for (enum_type.names, 0..) |field_name_index, field_i| {
const field_name = mod.intern_pool.stringToSlice(field_name_index);
const ip = &mod.intern_pool;
const enum_type = ip.indexToKey(ty.ip_index).enum_type;
for (enum_type.names.get(ip), 0..) |field_name_index, field_i| {
const field_name = ip.stringToSlice(field_name_index);
// DW.AT.enumerator
try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64));
dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevKind.enum_variant));
@ -400,7 +401,7 @@ pub const DeclState = struct {
// DW.AT.const_value, DW.FORM.data8
const value: u64 = value: {
if (enum_type.values.len == 0) break :value field_i; // auto-numbered
const value = enum_type.values[field_i];
const value = enum_type.values.get(ip)[field_i];
// TODO do not assume a 64bit enum value - could be bigger.
// See https://github.com/ziglang/zig/issues/645
const field_int_val = try value.toValue().intFromEnum(ty, mod);

View File

@ -2434,11 +2434,11 @@ pub const Type = struct {
/// resolves field types rather than asserting they are already resolved.
pub fn onePossibleValue(starting_type: Type, mod: *Module) !?Value {
var ty = starting_type;
const ip = &mod.intern_pool;
while (true) switch (ty.toIntern()) {
.empty_struct_type => return Value.empty_struct,
else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
else => switch (ip.indexToKey(ty.toIntern())) {
.int_type => |int_type| {
if (int_type.bits == 0) {
return try mod.intValue(ty, 0);
@ -2619,7 +2619,7 @@ pub const Type = struct {
} });
return only.toValue();
} else {
return enum_type.values[0].toValue();
return enum_type.values.get(ip)[0].toValue();
}
},
else => return null,
@ -2967,7 +2967,8 @@ pub const Type = struct {
}
pub fn enumFields(ty: Type, mod: *Module) []const InternPool.NullTerminatedString {
return mod.intern_pool.indexToKey(ty.toIntern()).enum_type.names;
const ip = &mod.intern_pool;
return ip.indexToKey(ty.toIntern()).enum_type.names.get(ip);
}
pub fn enumFieldCount(ty: Type, mod: *Module) usize {
@ -2975,7 +2976,8 @@ pub const Type = struct {
}
pub fn enumFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString {
return mod.intern_pool.indexToKey(ty.toIntern()).enum_type.names[field_index];
const ip = &mod.intern_pool;
return ip.indexToKey(ty.toIntern()).enum_type.names.get(ip)[field_index];
}
pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, mod: *Module) ?u32 {

View File

@ -426,7 +426,7 @@ pub const Value = struct {
// Assume it is already an integer and return it directly.
.simple_type, .int_type => val,
.enum_type => |enum_type| if (enum_type.values.len != 0)
enum_type.values[field_index].toValue()
enum_type.values.get(ip)[field_index].toValue()
else // Field index and integer values are the same.
mod.intValue(enum_type.tag_ty.toType(), field_index),
else => unreachable,