authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-10 20:47:33-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:42:30-07:00
log50bebb9e21c7e131522bec467b477ed7f55feb91
tree91fc8d696f772b909218c6544bc03d9c9f41b448
parent1c7095cb7dfcba3537edf3624a61046c9b772b1f

InternPool: ability to encode enums

This introduces a string table into InternPool as well as a curious new field called `maps` which is an array list of array hash maps with void/void key/value. Some types such as enums, structs, and unions need to store mappings from field names to field index, or value to field index. In such cases, they will store the underlying field names and values directly, relying on one of these maps, stored separately, to provide lookup. This allows the InternPool to be serialized via simple array copies, omitting all the maps, which are only used for optimizing lookup based on field name or field value. When the InternPool is deserialized it can be loaded via simple array copies, and then as a post-processing step the field name maps can be generated as extra metadata that is tacked on. This commit provides two encodings for enums - one when the integer tag type is explicitly provided and one when it is not. This is simpler than the previous setup, which has three encodings. Previous sizes: * EnumSimple: 40 bytes + 16 bytes per field * EnumNumbered: 80 bytes + 24 bytes per field * EnumFull: 184 bytes + 24 bytes per field Sizes after this commit: * type_enum_explicit: 24 bytes + 8 bytes per field * type_enum_auto: 16 bytes + 4 bytes per field

3 files changed, 297 insertions(+), 17 deletions(-)

src/InternPool.zig+282-17
...@@ -13,6 +13,12 @@ extra: std.ArrayListUnmanaged(u32) = .{},...@@ -13,6 +13,12 @@ extra: std.ArrayListUnmanaged(u32) = .{},
13/// Use the helper methods instead of accessing this directly in order to not13/// Use the helper methods instead of accessing this directly in order to not
14/// violate the above mechanism.14/// violate the above mechanism.
15limbs: std.ArrayListUnmanaged(u64) = .{},15limbs: std.ArrayListUnmanaged(u64) = .{},
16/// In order to store references to strings in fewer bytes, we copy all
17/// string bytes into here. String bytes can be null. It is up to whomever
18/// is referencing the data here whether they want to store both index and length,
19/// thus allowing null bytes, or store only index, and use null-termination. The
20/// `string_bytes` array is agnostic to either usage.
21string_bytes: std.ArrayListUnmanaged(u8) = .{},
1622
17/// Struct objects are stored in this data structure because:23/// Struct objects are stored in this data structure because:
18/// * They contain pointers such as the field maps.24/// * They contain pointers such as the field maps.
...@@ -28,6 +34,12 @@ allocated_unions: std.SegmentedList(Module.Union, 0) = .{},...@@ -28,6 +34,12 @@ allocated_unions: std.SegmentedList(Module.Union, 0) = .{},
28/// When a Union object is freed from `allocated_unions`, it is pushed into this stack.34/// When a Union object is freed from `allocated_unions`, it is pushed into this stack.
29unions_free_list: std.ArrayListUnmanaged(Module.Union.Index) = .{},35unions_free_list: std.ArrayListUnmanaged(Module.Union.Index) = .{},
3036
37/// Some types such as enums, structs, and unions need to store mappings from field names
38/// to field index, or value to field index. In such cases, they will store the underlying
39/// field names and values directly, relying on one of these maps, stored separately,
40/// to provide lookup.
41maps: std.ArrayListUnmanaged(std.AutoArrayHashMapUnmanaged(void, void)) = .{},
42
31const std = @import("std");43const std = @import("std");
32const Allocator = std.mem.Allocator;44const Allocator = std.mem.Allocator;
33const assert = std.debug.assert;45const assert = std.debug.assert;
...@@ -52,6 +64,46 @@ const KeyAdapter = struct {...@@ -52,6 +64,46 @@ const KeyAdapter = struct {
52 }64 }
53};65};
5466
67/// An index into `maps` which might be `none`.
68pub const OptionalMapIndex = enum(u32) {
69 none = std.math.maxInt(u32),
70 _,
71};
72
73/// An index into `maps`.
74pub const MapIndex = enum(u32) {
75 _,
76
77 pub fn toOptional(i: MapIndex) OptionalMapIndex {
78 return @intToEnum(OptionalMapIndex, @enumToInt(i));
79 }
80};
81
82/// An index into `string_bytes`.
83pub const NullTerminatedString = enum(u32) {
84 _,
85
86 const Adapter = struct {
87 strings: []const NullTerminatedString,
88
89 pub fn eql(ctx: @This(), a: NullTerminatedString, b_void: void, b_map_index: usize) bool {
90 _ = b_void;
91 return a == ctx.strings[b_map_index];
92 }
93
94 pub fn hash(ctx: @This(), a: NullTerminatedString) u32 {
95 _ = ctx;
96 return std.hash.uint32(@enumToInt(a));
97 }
98 };
99};
100
101/// An index into `string_bytes` which might be `none`.
102pub const OptionalNullTerminatedString = enum(u32) {
103 none = std.math.maxInt(u32),
104 _,
105};
106
55pub const Key = union(enum) {107pub const Key = union(enum) {
56 int_type: IntType,108 int_type: IntType,
57 ptr_type: PtrType,109 ptr_type: PtrType,
...@@ -68,6 +120,7 @@ pub const Key = union(enum) {...@@ -68,6 +120,7 @@ pub const Key = union(enum) {
68 struct_type: StructType,120 struct_type: StructType,
69 union_type: UnionType,121 union_type: UnionType,
70 opaque_type: OpaqueType,122 opaque_type: OpaqueType,
123 enum_type: EnumType,
71124
72 simple_value: SimpleValue,125 simple_value: SimpleValue,
73 extern_func: struct {126 extern_func: struct {
...@@ -174,6 +227,30 @@ pub const Key = union(enum) {...@@ -174,6 +227,30 @@ pub const Key = union(enum) {
174 }227 }
175 };228 };
176229
230 pub const EnumType = struct {
231 /// The Decl that corresponds to the enum itself.
232 decl: Module.Decl.Index,
233 /// Represents the declarations inside this enum.
234 namespace: Module.Namespace.OptionalIndex,
235 /// An integer type which is used for the numerical value of the enum.
236 /// This field is present regardless of whether the enum has an
237 /// explicitly provided tag type or auto-numbered.
238 tag_ty: Index,
239 /// Set of field names in declaration order.
240 names: []const NullTerminatedString,
241 /// Maps integer tag value to field index.
242 /// Entries are in declaration order, same as `fields`.
243 /// If this is empty, it means the enum tags are auto-numbered.
244 values: []const Index,
245 /// true if zig inferred this tag type, false if user specified it
246 tag_ty_inferred: bool,
247 /// This is ignored by `get` but will always be provided by `indexToKey`.
248 names_map: OptionalMapIndex = .none,
249 /// This is ignored by `get` but will be provided by `indexToKey` when
250 /// a value map exists.
251 values_map: OptionalMapIndex = .none,
252 };
253
177 pub const Int = struct {254 pub const Int = struct {
178 ty: Index,255 ty: Index,
179 storage: Storage,256 storage: Storage,
...@@ -263,6 +340,7 @@ pub const Key = union(enum) {...@@ -263,6 +340,7 @@ pub const Key = union(enum) {
263 => |info| std.hash.autoHash(hasher, info),340 => |info| std.hash.autoHash(hasher, info),
264341
265 .opaque_type => |opaque_type| std.hash.autoHash(hasher, opaque_type.decl),342 .opaque_type => |opaque_type| std.hash.autoHash(hasher, opaque_type.decl),
343 .enum_type => |enum_type| std.hash.autoHash(hasher, enum_type.decl),
266344
267 .int => |int| {345 .int => |int| {
268 // Canonicalize all integers by converting them to BigIntConst.346 // Canonicalize all integers by converting them to BigIntConst.
...@@ -410,6 +488,10 @@ pub const Key = union(enum) {...@@ -410,6 +488,10 @@ pub const Key = union(enum) {
410 const b_info = b.opaque_type;488 const b_info = b.opaque_type;
411 return a_info.decl == b_info.decl;489 return a_info.decl == b_info.decl;
412 },490 },
491 .enum_type => |a_info| {
492 const b_info = b.enum_type;
493 return a_info.decl == b_info.decl;
494 },
413 .aggregate => |a_info| {495 .aggregate => |a_info| {
414 const b_info = b.aggregate;496 const b_info = b.aggregate;
415 if (a_info.ty != b_info.ty) return false;497 if (a_info.ty != b_info.ty) return false;
...@@ -430,6 +512,7 @@ pub const Key = union(enum) {...@@ -430,6 +512,7 @@ pub const Key = union(enum) {
430 .struct_type,512 .struct_type,
431 .union_type,513 .union_type,
432 .opaque_type,514 .opaque_type,
515 .enum_type,
433 => return .type_type,516 => return .type_type,
434517
435 inline .ptr,518 inline .ptr,
...@@ -592,6 +675,21 @@ pub const Index = enum(u32) {...@@ -592,6 +675,21 @@ pub const Index = enum(u32) {
592 .legacy = undefined,675 .legacy = undefined,
593 };676 };
594 }677 }
678
679 /// Used for a map of `Index` values to the index within a list of `Index` values.
680 const Adapter = struct {
681 indexes: []const Index,
682
683 pub fn eql(ctx: @This(), a: Index, b_void: void, b_map_index: usize) bool {
684 _ = b_void;
685 return a == ctx.indexes[b_map_index];
686 }
687
688 pub fn hash(ctx: @This(), a: Index) u32 {
689 _ = ctx;
690 return std.hash.uint32(@enumToInt(a));
691 }
692 };
595};693};
596694
597pub const static_keys = [_]Key{695pub const static_keys = [_]Key{
...@@ -848,10 +946,12 @@ pub const Tag = enum(u8) {...@@ -848,10 +946,12 @@ pub const Tag = enum(u8) {
848 /// An error union type.946 /// An error union type.
849 /// data is payload to ErrorUnion.947 /// data is payload to ErrorUnion.
850 type_error_union,948 type_error_union,
851 /// Represents the data that an enum declaration provides, when the fields949 /// An enum type with an explicitly provided integer tag type.
852 /// are auto-numbered, and there are no declarations.950 /// data is payload index to `EnumExplicit`.
853 /// data is payload index to `EnumSimple`.951 type_enum_explicit,
854 type_enum_simple,952 /// An enum type with auto-numbered tag values.
953 /// data is payload index to `EnumAuto`.
954 type_enum_auto,
855 /// A type that can be represented with only an enum tag.955 /// A type that can be represented with only an enum tag.
856 /// data is SimpleType enum value.956 /// data is SimpleType enum value.
857 simple_type,957 simple_type,
...@@ -1087,17 +1187,35 @@ pub const ErrorUnion = struct {...@@ -1087,17 +1187,35 @@ pub const ErrorUnion = struct {
1087};1187};
10881188
1089/// Trailing:1189/// Trailing:
1090/// 0. field name: null-terminated string index for each fields_len; declaration order1190/// 0. field name: NullTerminatedString for each fields_len; declaration order
1091pub const EnumSimple = struct {1191/// 1. tag value: Index for each fields_len; declaration order
1192pub const EnumExplicit = struct {
1193 /// The Decl that corresponds to the enum itself.
1194 decl: Module.Decl.Index,
1195 /// This may be `none` if there are no declarations.
1196 namespace: Module.Namespace.OptionalIndex,
1197 /// An integer type which is used for the numerical value of the enum, which
1198 /// has been explicitly provided by the enum declaration.
1199 int_tag_type: Index,
1200 fields_len: u32,
1201 /// Maps field names to declaration index.
1202 names_map: MapIndex,
1203 /// Maps field values to declaration index.
1204 /// If this is `none`, it means the trailing tag values are absent because
1205 /// they are auto-numbered.
1206 values_map: OptionalMapIndex,
1207};
1208
1209/// Trailing:
1210/// 0. field name: NullTerminatedString for each fields_len; declaration order
1211pub const EnumAuto = struct {
1092 /// The Decl that corresponds to the enum itself.1212 /// The Decl that corresponds to the enum itself.
1093 decl: Module.Decl.Index,1213 decl: Module.Decl.Index,
1094 /// An integer type which is used for the numerical value of the enum. This1214 /// This may be `none` if there are no declarations.
1095 /// is inferred by Zig to be the smallest power of two unsigned int that1215 namespace: Module.Namespace.OptionalIndex,
1096 /// fits the number of fields. It is stored here to avoid unnecessary
1097 /// calculations and possibly allocation failure when querying the tag type
1098 /// of enums.
1099 int_tag_ty: Index,
1100 fields_len: u32,1216 fields_len: u32,
1217 /// Maps field names to declaration index.
1218 names_map: MapIndex,
1101};1219};
11021220
1103pub const PackedU64 = packed struct(u64) {1221pub const PackedU64 = packed struct(u64) {
...@@ -1183,6 +1301,9 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {...@@ -1183,6 +1301,9 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
1183 ip.unions_free_list.deinit(gpa);1301 ip.unions_free_list.deinit(gpa);
1184 ip.allocated_unions.deinit(gpa);1302 ip.allocated_unions.deinit(gpa);
11851303
1304 ip.maps.deinit(gpa);
1305 ip.string_bytes.deinit(gpa);
1306
1186 ip.* = undefined;1307 ip.* = undefined;
1187}1308}
11881309
...@@ -1256,7 +1377,6 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {...@@ -1256,7 +1377,6 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
1256 .type_optional => .{ .opt_type = @intToEnum(Index, data) },1377 .type_optional => .{ .opt_type = @intToEnum(Index, data) },
12571378
1258 .type_error_union => @panic("TODO"),1379 .type_error_union => @panic("TODO"),
1259 .type_enum_simple => @panic("TODO"),
12601380
1261 .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) },1381 .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) },
1262 .type_struct => {1382 .type_struct => {
...@@ -1288,6 +1408,46 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {...@@ -1288,6 +1408,46 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
1288 .runtime_tag = .safety,1408 .runtime_tag = .safety,
1289 } },1409 } },
12901410
1411 .type_enum_auto => {
1412 const enum_auto = ip.extraDataTrail(EnumAuto, data);
1413 const names = @ptrCast(
1414 []const NullTerminatedString,
1415 ip.extra.items[enum_auto.end..][0..enum_auto.data.fields_len],
1416 );
1417 return .{ .enum_type = .{
1418 .decl = enum_auto.data.decl,
1419 .namespace = enum_auto.data.namespace,
1420 .tag_ty = ip.getEnumIntTagType(enum_auto.data.fields_len),
1421 .names = names,
1422 .values = &.{},
1423 .tag_ty_inferred = true,
1424 .names_map = enum_auto.data.names_map.toOptional(),
1425 .values_map = .none,
1426 } };
1427 },
1428 .type_enum_explicit => {
1429 const enum_explicit = ip.extraDataTrail(EnumExplicit, data);
1430 const names = @ptrCast(
1431 []const NullTerminatedString,
1432 ip.extra.items[enum_explicit.end..][0..enum_explicit.data.fields_len],
1433 );
1434 const values = if (enum_explicit.data.values_map != .none) @ptrCast(
1435 []const Index,
1436 ip.extra.items[enum_explicit.end + names.len ..][0..enum_explicit.data.fields_len],
1437 ) else &[0]Index{};
1438
1439 return .{ .enum_type = .{
1440 .decl = enum_explicit.data.decl,
1441 .namespace = enum_explicit.data.namespace,
1442 .tag_ty = enum_explicit.data.int_tag_type,
1443 .names = names,
1444 .values = values,
1445 .tag_ty_inferred = false,
1446 .names_map = enum_explicit.data.names_map.toOptional(),
1447 .values_map = enum_explicit.data.values_map,
1448 } };
1449 },
1450
1291 .opt_null => .{ .opt = .{1451 .opt_null => .{ .opt = .{
1292 .ty = @intToEnum(Index, data),1452 .ty = @intToEnum(Index, data),
1293 .val = .none,1453 .val = .none,
...@@ -1362,6 +1522,14 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {...@@ -1362,6 +1522,14 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
1362 };1522 };
1363}1523}
13641524
1525/// Asserts the integer tag type is already present in the InternPool.
1526fn getEnumIntTagType(ip: InternPool, fields_len: u32) Index {
1527 return ip.getAssumeExists(.{ .int_type = .{
1528 .bits = if (fields_len == 0) 0 else std.math.log2_int_ceil(u32, fields_len),
1529 .signedness = .unsigned,
1530 } });
1531}
1532
1365fn indexToKeyBigInt(ip: InternPool, limb_index: u32, positive: bool) Key {1533fn indexToKeyBigInt(ip: InternPool, limb_index: u32, positive: bool) Key {
1366 const int_info = ip.limbData(Int, limb_index);1534 const int_info = ip.limbData(Int, limb_index);
1367 return .{ .int = .{1535 return .{ .int = .{
...@@ -1522,6 +1690,54 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -1522,6 +1690,54 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
1522 });1690 });
1523 },1691 },
15241692
1693 .enum_type => |enum_type| {
1694 assert(enum_type.tag_ty != .none);
1695 assert(enum_type.names_map == .none);
1696 assert(enum_type.values_map == .none);
1697
1698 const names_map = try ip.addMap(gpa);
1699 try addStringsToMap(ip, gpa, names_map, enum_type.names);
1700
1701 const fields_len = @intCast(u32, enum_type.names.len);
1702
1703 if (enum_type.tag_ty_inferred) {
1704 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
1705 fields_len);
1706 ip.items.appendAssumeCapacity(.{
1707 .tag = .type_enum_auto,
1708 .data = ip.addExtraAssumeCapacity(EnumAuto{
1709 .decl = enum_type.decl,
1710 .namespace = enum_type.namespace,
1711 .names_map = names_map,
1712 .fields_len = fields_len,
1713 }),
1714 });
1715 ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, enum_type.names));
1716 return @intToEnum(Index, ip.items.len - 1);
1717 }
1718
1719 const values_map: OptionalMapIndex = if (enum_type.values.len == 0) .none else m: {
1720 const values_map = try ip.addMap(gpa);
1721 try addIndexesToMap(ip, gpa, values_map, enum_type.values);
1722 break :m values_map.toOptional();
1723 };
1724 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumExplicit).Struct.fields.len +
1725 fields_len);
1726 ip.items.appendAssumeCapacity(.{
1727 .tag = .type_enum_auto,
1728 .data = ip.addExtraAssumeCapacity(EnumExplicit{
1729 .decl = enum_type.decl,
1730 .namespace = enum_type.namespace,
1731 .int_tag_type = enum_type.tag_ty,
1732 .fields_len = fields_len,
1733 .names_map = names_map,
1734 .values_map = values_map,
1735 }),
1736 });
1737 ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, enum_type.names));
1738 ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, enum_type.values));
1739 },
1740
1525 .extern_func => @panic("TODO"),1741 .extern_func => @panic("TODO"),
15261742
1527 .ptr => |ptr| switch (ptr.addr) {1743 .ptr => |ptr| switch (ptr.addr) {
...@@ -1723,6 +1939,40 @@ pub fn getAssumeExists(ip: InternPool, key: Key) Index {...@@ -1723,6 +1939,40 @@ pub fn getAssumeExists(ip: InternPool, key: Key) Index {
1723 return @intToEnum(Index, index);1939 return @intToEnum(Index, index);
1724}1940}
17251941
1942fn addStringsToMap(
1943 ip: *InternPool,
1944 gpa: Allocator,
1945 map_index: MapIndex,
1946 strings: []const NullTerminatedString,
1947) Allocator.Error!void {
1948 const map = &ip.maps.items[@enumToInt(map_index)];
1949 const adapter: NullTerminatedString.Adapter = .{ .strings = strings };
1950 for (strings) |string| {
1951 const gop = try map.getOrPutAdapted(gpa, string, adapter);
1952 assert(!gop.found_existing);
1953 }
1954}
1955
1956fn addIndexesToMap(
1957 ip: *InternPool,
1958 gpa: Allocator,
1959 map_index: MapIndex,
1960 indexes: []const Index,
1961) Allocator.Error!void {
1962 const map = &ip.maps.items[@enumToInt(map_index)];
1963 const adapter: Index.Adapter = .{ .indexes = indexes };
1964 for (indexes) |index| {
1965 const gop = try map.getOrPutAdapted(gpa, index, adapter);
1966 assert(!gop.found_existing);
1967 }
1968}
1969
1970fn addMap(ip: *InternPool, gpa: Allocator) Allocator.Error!MapIndex {
1971 const ptr = try ip.maps.addOne(gpa);
1972 ptr.* = .{};
1973 return @intToEnum(MapIndex, ip.maps.items.len - 1);
1974}
1975
1726/// This operation only happens under compile error conditions.1976/// This operation only happens under compile error conditions.
1727/// Leak the index until the next garbage collection.1977/// Leak the index until the next garbage collection.
1728pub fn remove(ip: *InternPool, index: Index) void {1978pub fn remove(ip: *InternPool, index: Index) void {
...@@ -1758,6 +2008,9 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {...@@ -1758,6 +2008,9 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
1758 Index => @enumToInt(@field(extra, field.name)),2008 Index => @enumToInt(@field(extra, field.name)),
1759 Module.Decl.Index => @enumToInt(@field(extra, field.name)),2009 Module.Decl.Index => @enumToInt(@field(extra, field.name)),
1760 Module.Namespace.Index => @enumToInt(@field(extra, field.name)),2010 Module.Namespace.Index => @enumToInt(@field(extra, field.name)),
2011 Module.Namespace.OptionalIndex => @enumToInt(@field(extra, field.name)),
2012 MapIndex => @enumToInt(@field(extra, field.name)),
2013 OptionalMapIndex => @enumToInt(@field(extra, field.name)),
1761 i32 => @bitCast(u32, @field(extra, field.name)),2014 i32 => @bitCast(u32, @field(extra, field.name)),
1762 Pointer.Flags => @bitCast(u32, @field(extra, field.name)),2015 Pointer.Flags => @bitCast(u32, @field(extra, field.name)),
1763 Pointer.PackedOffset => @bitCast(u32, @field(extra, field.name)),2016 Pointer.PackedOffset => @bitCast(u32, @field(extra, field.name)),
...@@ -1806,15 +2059,19 @@ fn addLimbsAssumeCapacity(ip: *InternPool, limbs: []const Limb) void {...@@ -1806,15 +2059,19 @@ fn addLimbsAssumeCapacity(ip: *InternPool, limbs: []const Limb) void {
1806 }2059 }
1807}2060}
18082061
1809fn extraData(ip: InternPool, comptime T: type, index: usize) T {2062fn extraDataTrail(ip: InternPool, comptime T: type, index: usize) struct { data: T, end: usize } {
1810 var result: T = undefined;2063 var result: T = undefined;
1811 inline for (@typeInfo(T).Struct.fields, 0..) |field, i| {2064 const fields = @typeInfo(T).Struct.fields;
2065 inline for (fields, 0..) |field, i| {
1812 const int32 = ip.extra.items[i + index];2066 const int32 = ip.extra.items[i + index];
1813 @field(result, field.name) = switch (field.type) {2067 @field(result, field.name) = switch (field.type) {
1814 u32 => int32,2068 u32 => int32,
1815 Index => @intToEnum(Index, int32),2069 Index => @intToEnum(Index, int32),
1816 Module.Decl.Index => @intToEnum(Module.Decl.Index, int32),2070 Module.Decl.Index => @intToEnum(Module.Decl.Index, int32),
1817 Module.Namespace.Index => @intToEnum(Module.Namespace.Index, int32),2071 Module.Namespace.Index => @intToEnum(Module.Namespace.Index, int32),
2072 Module.Namespace.OptionalIndex => @intToEnum(Module.Namespace.OptionalIndex, int32),
2073 MapIndex => @intToEnum(MapIndex, int32),
2074 OptionalMapIndex => @intToEnum(OptionalMapIndex, int32),
1818 i32 => @bitCast(i32, int32),2075 i32 => @bitCast(i32, int32),
1819 Pointer.Flags => @bitCast(Pointer.Flags, int32),2076 Pointer.Flags => @bitCast(Pointer.Flags, int32),
1820 Pointer.PackedOffset => @bitCast(Pointer.PackedOffset, int32),2077 Pointer.PackedOffset => @bitCast(Pointer.PackedOffset, int32),
...@@ -1822,7 +2079,14 @@ fn extraData(ip: InternPool, comptime T: type, index: usize) T {...@@ -1822,7 +2079,14 @@ fn extraData(ip: InternPool, comptime T: type, index: usize) T {
1822 else => @compileError("bad field type: " ++ @typeName(field.type)),2079 else => @compileError("bad field type: " ++ @typeName(field.type)),
1823 };2080 };
1824 }2081 }
1825 return result;2082 return .{
2083 .data = result,
2084 .end = index + fields.len,
2085 };
2086}
2087
2088fn extraData(ip: InternPool, comptime T: type, index: usize) T {
2089 return extraDataTrail(ip, T, index).data;
1826}2090}
18272091
1828/// Asserts the struct has 32-bit fields and the number of fields is evenly divisible by 2.2092/// Asserts the struct has 32-bit fields and the number of fields is evenly divisible by 2.
...@@ -2071,7 +2335,8 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {...@@ -2071,7 +2335,8 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
2071 .type_slice => 0,2335 .type_slice => 0,
2072 .type_optional => 0,2336 .type_optional => 0,
2073 .type_error_union => @sizeOf(ErrorUnion),2337 .type_error_union => @sizeOf(ErrorUnion),
2074 .type_enum_simple => @sizeOf(EnumSimple),2338 .type_enum_explicit => @sizeOf(EnumExplicit),
2339 .type_enum_auto => @sizeOf(EnumAuto),
2075 .type_opaque => @sizeOf(Key.OpaqueType),2340 .type_opaque => @sizeOf(Key.OpaqueType),
2076 .type_struct => @sizeOf(Module.Struct) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl),2341 .type_struct => @sizeOf(Module.Struct) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl),
2077 .type_struct_ns => @sizeOf(Module.Namespace),2342 .type_struct_ns => @sizeOf(Module.Namespace),
src/Sema.zig+4
...@@ -31760,6 +31760,8 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -31760,6 +31760,8 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3176031760
31761 .opaque_type => false,31761 .opaque_type => false,
3176231762
31763 .enum_type => @panic("TODO"),
31764
31763 // values, not types31765 // values, not types
31764 .un => unreachable,31766 .un => unreachable,
31765 .simple_value => unreachable,31767 .simple_value => unreachable,
...@@ -33293,6 +33295,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -33293,6 +33295,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
33293 return only.toValue();33295 return only.toValue();
33294 },33296 },
33295 .opaque_type => null,33297 .opaque_type => null,
33298 .enum_type => @panic("TODO"),
3329633299
33297 // values, not types33300 // values, not types
33298 .un => unreachable,33301 .un => unreachable,
...@@ -33862,6 +33865,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -33862,6 +33865,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
33862 },33865 },
3386333866
33864 .opaque_type => false,33867 .opaque_type => false,
33868 .enum_type => @panic("TODO"),
3386533869
33866 // values, not types33870 // values, not types
33867 .un => unreachable,33871 .un => unreachable,
src/type.zig+11
...@@ -79,6 +79,7 @@ pub const Type = struct {...@@ -79,6 +79,7 @@ pub const Type = struct {
79 .struct_type => return .Struct,79 .struct_type => return .Struct,
80 .union_type => return .Union,80 .union_type => return .Union,
81 .opaque_type => return .Opaque,81 .opaque_type => return .Opaque,
82 .enum_type => return .Enum,
82 .simple_type => |s| switch (s) {83 .simple_type => |s| switch (s) {
83 .f16,84 .f16,
84 .f32,85 .f32,
...@@ -1499,6 +1500,7 @@ pub const Type = struct {...@@ -1499,6 +1500,7 @@ pub const Type = struct {
1499 const decl = mod.declPtr(opaque_type.decl);1500 const decl = mod.declPtr(opaque_type.decl);
1500 try decl.renderFullyQualifiedName(mod, writer);1501 try decl.renderFullyQualifiedName(mod, writer);
1501 },1502 },
1503 .enum_type => @panic("TODO"),
15021504
1503 // values, not types1505 // values, not types
1504 .un => unreachable,1506 .un => unreachable,
...@@ -1764,6 +1766,7 @@ pub const Type = struct {...@@ -1764,6 +1766,7 @@ pub const Type = struct {
1764 },1766 },
17651767
1766 .opaque_type => true,1768 .opaque_type => true,
1769 .enum_type => @panic("TODO"),
17671770
1768 // values, not types1771 // values, not types
1769 .un => unreachable,1772 .un => unreachable,
...@@ -1883,6 +1886,7 @@ pub const Type = struct {...@@ -1883,6 +1886,7 @@ pub const Type = struct {
1883 .tagged => false,1886 .tagged => false,
1884 },1887 },
1885 .opaque_type => false,1888 .opaque_type => false,
1889 .enum_type => @panic("TODO"),
18861890
1887 // values, not types1891 // values, not types
1888 .un => unreachable,1892 .un => unreachable,
...@@ -2279,6 +2283,7 @@ pub const Type = struct {...@@ -2279,6 +2283,7 @@ pub const Type = struct {
2279 return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());2283 return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());
2280 },2284 },
2281 .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },2285 .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },
2286 .enum_type => @panic("TODO"),
22822287
2283 // values, not types2288 // values, not types
2284 .un => unreachable,2289 .un => unreachable,
...@@ -2700,6 +2705,7 @@ pub const Type = struct {...@@ -2700,6 +2705,7 @@ pub const Type = struct {
2700 return abiSizeAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());2705 return abiSizeAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());
2701 },2706 },
2702 .opaque_type => unreachable, // no size available2707 .opaque_type => unreachable, // no size available
2708 .enum_type => @panic("TODO"),
27032709
2704 // values, not types2710 // values, not types
2705 .un => unreachable,2711 .un => unreachable,
...@@ -2958,6 +2964,7 @@ pub const Type = struct {...@@ -2958,6 +2964,7 @@ pub const Type = struct {
2958 return size;2964 return size;
2959 },2965 },
2960 .opaque_type => unreachable,2966 .opaque_type => unreachable,
2967 .enum_type => @panic("TODO"),
29612968
2962 // values, not types2969 // values, not types
2963 .un => unreachable,2970 .un => unreachable,
...@@ -3721,6 +3728,7 @@ pub const Type = struct {...@@ -3721,6 +3728,7 @@ pub const Type = struct {
3721 assert(struct_obj.layout == .Packed);3728 assert(struct_obj.layout == .Packed);
3722 ty = struct_obj.backing_int_ty;3729 ty = struct_obj.backing_int_ty;
3723 },3730 },
3731 .enum_type => @panic("TODO"),
37243732
3725 .ptr_type => unreachable,3733 .ptr_type => unreachable,
3726 .array_type => unreachable,3734 .array_type => unreachable,
...@@ -4115,6 +4123,7 @@ pub const Type = struct {...@@ -4115,6 +4123,7 @@ pub const Type = struct {
4115 return only.toValue();4123 return only.toValue();
4116 },4124 },
4117 .opaque_type => return null,4125 .opaque_type => return null,
4126 .enum_type => @panic("TODO"),
41184127
4119 // values, not types4128 // values, not types
4120 .un => unreachable,4129 .un => unreachable,
...@@ -4284,6 +4293,8 @@ pub const Type = struct {...@@ -4284,6 +4293,8 @@ pub const Type = struct {
42844293
4285 .opaque_type => false,4294 .opaque_type => false,
42864295
4296 .enum_type => @panic("TODO"),
4297
4287 // values, not types4298 // values, not types
4288 .un => unreachable,4299 .un => unreachable,
4289 .simple_value => unreachable,4300 .simple_value => unreachable,