From 7ef1eb1c27754cb0349fdc10db1f02ff2dddd99b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 17 Aug 2023 14:25:18 -0700 Subject: [PATCH] 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`. --- src/InternPool.zig | 247 ++++++++++++++++++++++++------------------- src/Module.zig | 2 +- src/Sema.zig | 31 +++--- src/TypedValue.zig | 2 +- src/codegen/llvm.zig | 13 +-- src/link/Dwarf.zig | 9 +- src/type.zig | 12 ++- src/value.zig | 2 +- 8 files changed, 176 insertions(+), 142 deletions(-) diff --git a/src/InternPool.zig b/src/InternPool.zig index bde6c11256..92acf10bd5 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -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, diff --git a/src/Module.zig b/src/Module.zig index c19b742b54..2c78ddd881 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -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(); } diff --git a/src/Sema.zig b/src/Sema.zig index 396ef9a786..d62cf3ef0c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -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, } }, diff --git a/src/TypedValue.zig b/src/TypedValue.zig index 78fefbe442..415d54d7e1 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -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("); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 3db6321119..e36f411a01 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -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); diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 6b7744644e..b2ca85467c 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -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); diff --git a/src/type.zig b/src/type.zig index df39192a63..b82d3723d0 100644 --- a/src/type.zig +++ b/src/type.zig @@ -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 { diff --git a/src/value.zig b/src/value.zig index 1a2e85bb1e..fdf061c680 100644 --- a/src/value.zig +++ b/src/value.zig @@ -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,