authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-12 00:07:32-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:42:30-07:00
log5881a2d63771b070107bdc2325aa1bc455b2d926
tree0380faab30356377b721943de57c8b566e9f3744
parent404cbc36c52a50975a69e78da716f2258e5b1696

stage2: move enum types into the InternPool

Unlike unions and structs, enums are actually *encoded* into the InternPool directly, rather than using the SegmentedList trick. This results in them being quite compact, and greatly improved the ergonomics of using enum types throughout the compiler. It did however require introducing a new concept to the InternPool which is an "incomplete" item - something that is added to gain a permanent Index, but which is then mutated in place. This was necessary because enum tag values and tag types may reference the namespaces created by the enum itself, which required constructing the namespace, decl, and calling analyzeDecl on the decl, which required the decl value, which required the enum type, which required an InternPool index to be assigned and for it to be meaningful. The API for updating enums in place turned out to be quite slick and efficient - the methods directly populate pre-allocated arrays and return the information necessary to output the same compilation errors as before.

13 files changed, 934 insertions(+), 1178 deletions(-)

src/AstGen.zig+2-2
......@@ -10694,8 +10694,8 @@ fn identAsString(astgen: *AstGen, ident_token: Ast.TokenIndex) !u32 {
1069410694 const string_bytes = &astgen.string_bytes;
1069510695 const str_index = @intCast(u32, string_bytes.items.len);
1069610696 try astgen.appendIdentStr(ident_token, string_bytes);
10697 const key = string_bytes.items[str_index..];
10698 const gop = try astgen.string_table.getOrPutContextAdapted(gpa, @as([]const u8, key), StringIndexAdapter{
10697 const key: []const u8 = string_bytes.items[str_index..];
10698 const gop = try astgen.string_table.getOrPutContextAdapted(gpa, key, StringIndexAdapter{
1069910699 .bytes = string_bytes,
1070010700 }, StringIndexContext{
1070110701 .bytes = string_bytes,
src/InternPool.zig+394-71
......@@ -40,6 +40,14 @@ unions_free_list: std.ArrayListUnmanaged(Module.Union.Index) = .{},
4040/// to provide lookup.
4141maps: std.ArrayListUnmanaged(std.AutoArrayHashMapUnmanaged(void, void)) = .{},
4242
43/// Used for finding the index inside `string_bytes`.
44string_table: std.HashMapUnmanaged(
45 u32,
46 void,
47 std.hash_map.StringIndexContext,
48 std.hash_map.default_max_load_percentage,
49) = .{},
50
4351const std = @import("std");
4452const Allocator = std.mem.Allocator;
4553const assert = std.debug.assert;
......@@ -68,6 +76,11 @@ const KeyAdapter = struct {
6876pub const OptionalMapIndex = enum(u32) {
6977 none = std.math.maxInt(u32),
7078 _,
79
80 pub fn unwrap(oi: OptionalMapIndex) ?MapIndex {
81 if (oi == .none) return null;
82 return @intToEnum(MapIndex, @enumToInt(oi));
83 }
7184};
7285
7386/// An index into `maps`.
......@@ -83,6 +96,10 @@ pub const MapIndex = enum(u32) {
8396pub const NullTerminatedString = enum(u32) {
8497 _,
8598
99 pub fn toOptional(self: NullTerminatedString) OptionalNullTerminatedString {
100 return @intToEnum(OptionalNullTerminatedString, @enumToInt(self));
101 }
102
86103 const Adapter = struct {
87104 strings: []const NullTerminatedString,
88105
......@@ -102,6 +119,11 @@ pub const NullTerminatedString = enum(u32) {
102119pub const OptionalNullTerminatedString = enum(u32) {
103120 none = std.math.maxInt(u32),
104121 _,
122
123 pub fn unwrap(oi: OptionalNullTerminatedString) ?NullTerminatedString {
124 if (oi == .none) return null;
125 return @intToEnum(NullTerminatedString, @enumToInt(oi));
126 }
105127};
106128
107129pub const Key = union(enum) {
......@@ -242,13 +264,75 @@ pub const Key = union(enum) {
242264 /// Entries are in declaration order, same as `fields`.
243265 /// If this is empty, it means the enum tags are auto-numbered.
244266 values: []const Index,
245 /// true if zig inferred this tag type, false if user specified it
246 tag_ty_inferred: bool,
267 tag_mode: TagMode,
247268 /// This is ignored by `get` but will always be provided by `indexToKey`.
248269 names_map: OptionalMapIndex = .none,
249270 /// This is ignored by `get` but will be provided by `indexToKey` when
250271 /// a value map exists.
251272 values_map: OptionalMapIndex = .none,
273
274 pub const TagMode = enum {
275 /// The integer tag type was auto-numbered by zig.
276 auto,
277 /// The integer tag type was provided by the enum declaration, and the enum
278 /// is exhaustive.
279 explicit,
280 /// The integer tag type was provided by the enum declaration, and the enum
281 /// is non-exhaustive.
282 nonexhaustive,
283 };
284
285 /// Look up field index based on field name.
286 pub fn nameIndex(self: EnumType, ip: InternPool, name: NullTerminatedString) ?usize {
287 const map = &ip.maps.items[@enumToInt(self.names_map.unwrap().?)];
288 const adapter: NullTerminatedString.Adapter = .{ .strings = self.names };
289 return map.getIndexAdapted(name, adapter);
290 }
291
292 /// Look up field index based on tag value.
293 /// Asserts that `values_map` is not `none`.
294 /// This function returns `null` when `tag_val` does not have the
295 /// integer tag type of the enum.
296 pub fn tagValueIndex(self: EnumType, ip: InternPool, tag_val: Index) ?usize {
297 assert(tag_val != .none);
298 const map = &ip.maps.items[@enumToInt(self.values_map.unwrap().?)];
299 const adapter: Index.Adapter = .{ .indexes = self.values };
300 return map.getIndexAdapted(tag_val, adapter);
301 }
302 };
303
304 pub const IncompleteEnumType = struct {
305 /// Same as corresponding `EnumType` field.
306 decl: Module.Decl.Index,
307 /// Same as corresponding `EnumType` field.
308 namespace: Module.Namespace.OptionalIndex,
309 /// The field names and field values are not known yet, but
310 /// the number of fields must be known ahead of time.
311 fields_len: u32,
312 /// This information is needed so that the size does not change
313 /// later when populating field values.
314 has_values: bool,
315 /// Same as corresponding `EnumType` field.
316 tag_mode: EnumType.TagMode,
317 /// This may be updated via `setTagType` later.
318 tag_ty: Index = .none,
319
320 pub fn toEnumType(self: @This()) EnumType {
321 return .{
322 .decl = self.decl,
323 .namespace = self.namespace,
324 .tag_ty = self.tag_ty,
325 .tag_mode = self.tag_mode,
326 .names = &.{},
327 .values = &.{},
328 };
329 }
330
331 /// Only the decl is used for hashing and equality, so we can construct
332 /// this minimal key for use with `map`.
333 pub fn toKey(self: @This()) Key {
334 return .{ .enum_type = self.toEnumType() };
335 }
252336 };
253337
254338 pub const Int = struct {
......@@ -946,12 +1030,18 @@ pub const Tag = enum(u8) {
9461030 /// An error union type.
9471031 /// data is payload to ErrorUnion.
9481032 type_error_union,
949 /// An enum type with an explicitly provided integer tag type.
950 /// data is payload index to `EnumExplicit`.
951 type_enum_explicit,
9521033 /// An enum type with auto-numbered tag values.
1034 /// The enum is exhaustive.
9531035 /// data is payload index to `EnumAuto`.
9541036 type_enum_auto,
1037 /// An enum type with an explicitly provided integer tag type.
1038 /// The enum is exhaustive.
1039 /// data is payload index to `EnumExplicit`.
1040 type_enum_explicit,
1041 /// An enum type with an explicitly provided integer tag type.
1042 /// The enum is non-exhaustive.
1043 /// data is payload index to `EnumExplicit`.
1044 type_enum_nonexhaustive,
9551045 /// A type that can be represented with only an enum tag.
9561046 /// data is SimpleType enum value.
9571047 simple_type,
......@@ -1302,9 +1392,11 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
13021392 ip.unions_free_list.deinit(gpa);
13031393 ip.allocated_unions.deinit(gpa);
13041394
1305 for (ip.maps) |*map| map.deinit(gpa);
1395 for (ip.maps.items) |*map| map.deinit(gpa);
13061396 ip.maps.deinit(gpa);
13071397
1398 ip.string_table.deinit(gpa);
1399
13081400 ip.* = undefined;
13091401}
13101402
......@@ -1421,33 +1513,13 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
14211513 .tag_ty = ip.getEnumIntTagType(enum_auto.data.fields_len),
14221514 .names = names,
14231515 .values = &.{},
1424 .tag_ty_inferred = true,
1516 .tag_mode = .auto,
14251517 .names_map = enum_auto.data.names_map.toOptional(),
14261518 .values_map = .none,
14271519 } };
14281520 },
1429 .type_enum_explicit => {
1430 const enum_explicit = ip.extraDataTrail(EnumExplicit, data);
1431 const names = @ptrCast(
1432 []const NullTerminatedString,
1433 ip.extra.items[enum_explicit.end..][0..enum_explicit.data.fields_len],
1434 );
1435 const values = if (enum_explicit.data.values_map != .none) @ptrCast(
1436 []const Index,
1437 ip.extra.items[enum_explicit.end + names.len ..][0..enum_explicit.data.fields_len],
1438 ) else &[0]Index{};
1439
1440 return .{ .enum_type = .{
1441 .decl = enum_explicit.data.decl,
1442 .namespace = enum_explicit.data.namespace,
1443 .tag_ty = enum_explicit.data.int_tag_type,
1444 .names = names,
1445 .values = values,
1446 .tag_ty_inferred = false,
1447 .names_map = enum_explicit.data.names_map.toOptional(),
1448 .values_map = enum_explicit.data.values_map,
1449 } };
1450 },
1521 .type_enum_explicit => indexToKeyEnum(ip, data, .explicit),
1522 .type_enum_nonexhaustive => indexToKeyEnum(ip, data, .nonexhaustive),
14511523
14521524 .opt_null => .{ .opt = .{
14531525 .ty = @intToEnum(Index, data),
......@@ -1531,6 +1603,29 @@ fn getEnumIntTagType(ip: InternPool, fields_len: u32) Index {
15311603 } });
15321604}
15331605
1606fn indexToKeyEnum(ip: InternPool, data: u32, tag_mode: Key.EnumType.TagMode) Key {
1607 const enum_explicit = ip.extraDataTrail(EnumExplicit, data);
1608 const names = @ptrCast(
1609 []const NullTerminatedString,
1610 ip.extra.items[enum_explicit.end..][0..enum_explicit.data.fields_len],
1611 );
1612 const values = if (enum_explicit.data.values_map != .none) @ptrCast(
1613 []const Index,
1614 ip.extra.items[enum_explicit.end + names.len ..][0..enum_explicit.data.fields_len],
1615 ) else &[0]Index{};
1616
1617 return .{ .enum_type = .{
1618 .decl = enum_explicit.data.decl,
1619 .namespace = enum_explicit.data.namespace,
1620 .tag_ty = enum_explicit.data.int_tag_type,
1621 .names = names,
1622 .values = values,
1623 .tag_mode = tag_mode,
1624 .names_map = enum_explicit.data.names_map.toOptional(),
1625 .values_map = enum_explicit.data.values_map,
1626 } };
1627}
1628
15341629fn indexToKeyBigInt(ip: InternPool, limb_index: u32, positive: bool) Key {
15351630 const int_info = ip.limbData(Int, limb_index);
15361631 return .{ .int = .{
......@@ -1696,47 +1791,29 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
16961791 assert(enum_type.names_map == .none);
16971792 assert(enum_type.values_map == .none);
16981793
1699 const names_map = try ip.addMap(gpa);
1700 try addStringsToMap(ip, gpa, names_map, enum_type.names);
1794 switch (enum_type.tag_mode) {
1795 .auto => {
1796 const names_map = try ip.addMap(gpa);
1797 try addStringsToMap(ip, gpa, names_map, enum_type.names);
17011798
1702 const fields_len = @intCast(u32, enum_type.names.len);
1703
1704 if (enum_type.tag_ty_inferred) {
1705 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
1706 fields_len);
1707 ip.items.appendAssumeCapacity(.{
1708 .tag = .type_enum_auto,
1709 .data = ip.addExtraAssumeCapacity(EnumAuto{
1710 .decl = enum_type.decl,
1711 .namespace = enum_type.namespace,
1712 .names_map = names_map,
1713 .fields_len = fields_len,
1714 }),
1715 });
1716 ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, enum_type.names));
1717 return @intToEnum(Index, ip.items.len - 1);
1799 const fields_len = @intCast(u32, enum_type.names.len);
1800 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
1801 fields_len);
1802 ip.items.appendAssumeCapacity(.{
1803 .tag = .type_enum_auto,
1804 .data = ip.addExtraAssumeCapacity(EnumAuto{
1805 .decl = enum_type.decl,
1806 .namespace = enum_type.namespace,
1807 .names_map = names_map,
1808 .fields_len = fields_len,
1809 }),
1810 });
1811 ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, enum_type.names));
1812 return @intToEnum(Index, ip.items.len - 1);
1813 },
1814 .explicit => return finishGetEnum(ip, gpa, enum_type, .type_enum_explicit),
1815 .nonexhaustive => return finishGetEnum(ip, gpa, enum_type, .type_enum_nonexhaustive),
17181816 }
1719
1720 const values_map: OptionalMapIndex = if (enum_type.values.len == 0) .none else m: {
1721 const values_map = try ip.addMap(gpa);
1722 try addIndexesToMap(ip, gpa, values_map, enum_type.values);
1723 break :m values_map.toOptional();
1724 };
1725 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumExplicit).Struct.fields.len +
1726 fields_len);
1727 ip.items.appendAssumeCapacity(.{
1728 .tag = .type_enum_auto,
1729 .data = ip.addExtraAssumeCapacity(EnumExplicit{
1730 .decl = enum_type.decl,
1731 .namespace = enum_type.namespace,
1732 .int_tag_type = enum_type.tag_ty,
1733 .fields_len = fields_len,
1734 .names_map = names_map,
1735 .values_map = values_map,
1736 }),
1737 });
1738 ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, enum_type.names));
1739 ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, enum_type.values));
17401817 },
17411818
17421819 .extern_func => @panic("TODO"),
......@@ -1934,8 +2011,206 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
19342011 return @intToEnum(Index, ip.items.len - 1);
19352012}
19362013
1937pub fn getAssumeExists(ip: InternPool, key: Key) Index {
1938 const adapter: KeyAdapter = .{ .intern_pool = &ip };
2014/// Provides API for completing an enum type after calling `getIncompleteEnum`.
2015pub const IncompleteEnumType = struct {
2016 index: Index,
2017 tag_ty_index: u32,
2018 names_map: MapIndex,
2019 names_start: u32,
2020 values_map: OptionalMapIndex,
2021 values_start: u32,
2022
2023 pub fn setTagType(self: @This(), ip: *InternPool, tag_ty: Index) void {
2024 assert(tag_ty != .none);
2025 ip.extra.items[self.tag_ty_index] = @enumToInt(tag_ty);
2026 }
2027
2028 /// Returns the already-existing field with the same name, if any.
2029 pub fn addFieldName(
2030 self: @This(),
2031 ip: *InternPool,
2032 gpa: Allocator,
2033 name: NullTerminatedString,
2034 ) Allocator.Error!?u32 {
2035 const map = &ip.maps.items[@enumToInt(self.names_map)];
2036 const field_index = map.count();
2037 const strings = ip.extra.items[self.names_start..][0..field_index];
2038 const adapter: NullTerminatedString.Adapter = .{
2039 .strings = @ptrCast([]const NullTerminatedString, strings),
2040 };
2041 const gop = try map.getOrPutAdapted(gpa, name, adapter);
2042 if (gop.found_existing) return @intCast(u32, gop.index);
2043 ip.extra.items[self.names_start + field_index] = @enumToInt(name);
2044 return null;
2045 }
2046
2047 /// Returns the already-existing field with the same value, if any.
2048 /// Make sure the type of the value has the integer tag type of the enum.
2049 pub fn addFieldValue(
2050 self: @This(),
2051 ip: *InternPool,
2052 gpa: Allocator,
2053 value: Index,
2054 ) Allocator.Error!?u32 {
2055 const map = &ip.maps.items[@enumToInt(self.values_map.unwrap().?)];
2056 const field_index = map.count();
2057 const indexes = ip.extra.items[self.values_start..][0..field_index];
2058 const adapter: Index.Adapter = .{
2059 .indexes = @ptrCast([]const Index, indexes),
2060 };
2061 const gop = try map.getOrPutAdapted(gpa, value, adapter);
2062 if (gop.found_existing) return @intCast(u32, gop.index);
2063 ip.extra.items[self.values_start + field_index] = @enumToInt(value);
2064 return null;
2065 }
2066};
2067
2068/// This is used to create an enum type in the `InternPool`, with the ability
2069/// to update the tag type, field names, and field values later.
2070pub fn getIncompleteEnum(
2071 ip: *InternPool,
2072 gpa: Allocator,
2073 enum_type: Key.IncompleteEnumType,
2074) Allocator.Error!InternPool.IncompleteEnumType {
2075 switch (enum_type.tag_mode) {
2076 .auto => return getIncompleteEnumAuto(ip, gpa, enum_type),
2077 .explicit => return getIncompleteEnumExplicit(ip, gpa, enum_type, .type_enum_explicit),
2078 .nonexhaustive => return getIncompleteEnumExplicit(ip, gpa, enum_type, .type_enum_nonexhaustive),
2079 }
2080}
2081
2082pub fn getIncompleteEnumAuto(
2083 ip: *InternPool,
2084 gpa: Allocator,
2085 enum_type: Key.IncompleteEnumType,
2086) Allocator.Error!InternPool.IncompleteEnumType {
2087 // Although the integer tag type will not be stored in the `EnumAuto` struct,
2088 // `InternPool` logic depends on it being present so that `typeOf` can be infallible.
2089 // Ensure it is present here:
2090 _ = try ip.get(gpa, .{ .int_type = .{
2091 .bits = if (enum_type.fields_len == 0) 0 else std.math.log2_int_ceil(u32, enum_type.fields_len),
2092 .signedness = .unsigned,
2093 } });
2094
2095 // We must keep the map in sync with `items`. The hash and equality functions
2096 // for enum types only look at the decl field, which is present even in
2097 // an `IncompleteEnumType`.
2098 const adapter: KeyAdapter = .{ .intern_pool = ip };
2099 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);
2100 assert(!gop.found_existing);
2101
2102 const names_map = try ip.addMap(gpa);
2103
2104 const extra_fields_len: u32 = @typeInfo(EnumAuto).Struct.fields.len;
2105 try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.fields_len);
2106
2107 const extra_index = ip.addExtraAssumeCapacity(EnumAuto{
2108 .decl = enum_type.decl,
2109 .namespace = enum_type.namespace,
2110 .names_map = names_map,
2111 .fields_len = enum_type.fields_len,
2112 });
2113
2114 ip.items.appendAssumeCapacity(.{
2115 .tag = .type_enum_auto,
2116 .data = extra_index,
2117 });
2118 ip.extra.appendNTimesAssumeCapacity(@enumToInt(Index.none), enum_type.fields_len);
2119 return .{
2120 .index = @intToEnum(Index, ip.items.len - 1),
2121 .tag_ty_index = undefined,
2122 .names_map = names_map,
2123 .names_start = extra_index + extra_fields_len,
2124 .values_map = .none,
2125 .values_start = undefined,
2126 };
2127}
2128
2129pub fn getIncompleteEnumExplicit(
2130 ip: *InternPool,
2131 gpa: Allocator,
2132 enum_type: Key.IncompleteEnumType,
2133 tag: Tag,
2134) Allocator.Error!InternPool.IncompleteEnumType {
2135 // We must keep the map in sync with `items`. The hash and equality functions
2136 // for enum types only look at the decl field, which is present even in
2137 // an `IncompleteEnumType`.
2138 const adapter: KeyAdapter = .{ .intern_pool = ip };
2139 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);
2140 assert(!gop.found_existing);
2141
2142 const names_map = try ip.addMap(gpa);
2143 const values_map: OptionalMapIndex = if (!enum_type.has_values) .none else m: {
2144 const values_map = try ip.addMap(gpa);
2145 break :m values_map.toOptional();
2146 };
2147
2148 const reserved_len = enum_type.fields_len +
2149 if (enum_type.has_values) enum_type.fields_len else 0;
2150
2151 const extra_fields_len: u32 = @typeInfo(EnumExplicit).Struct.fields.len;
2152 try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + reserved_len);
2153
2154 const extra_index = ip.addExtraAssumeCapacity(EnumExplicit{
2155 .decl = enum_type.decl,
2156 .namespace = enum_type.namespace,
2157 .int_tag_type = enum_type.tag_ty,
2158 .fields_len = enum_type.fields_len,
2159 .names_map = names_map,
2160 .values_map = values_map,
2161 });
2162
2163 ip.items.appendAssumeCapacity(.{
2164 .tag = tag,
2165 .data = extra_index,
2166 });
2167 // This is both fields and values (if present).
2168 ip.extra.appendNTimesAssumeCapacity(@enumToInt(Index.none), reserved_len);
2169 return .{
2170 .index = @intToEnum(Index, ip.items.len - 1),
2171 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?,
2172 .names_map = names_map,
2173 .names_start = extra_index + extra_fields_len,
2174 .values_map = values_map,
2175 .values_start = extra_index + extra_fields_len + enum_type.fields_len,
2176 };
2177}
2178
2179pub fn finishGetEnum(
2180 ip: *InternPool,
2181 gpa: Allocator,
2182 enum_type: Key.EnumType,
2183 tag: Tag,
2184) Allocator.Error!Index {
2185 const names_map = try ip.addMap(gpa);
2186 try addStringsToMap(ip, gpa, names_map, enum_type.names);
2187
2188 const values_map: OptionalMapIndex = if (enum_type.values.len == 0) .none else m: {
2189 const values_map = try ip.addMap(gpa);
2190 try addIndexesToMap(ip, gpa, values_map, enum_type.values);
2191 break :m values_map.toOptional();
2192 };
2193 const fields_len = @intCast(u32, enum_type.names.len);
2194 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumExplicit).Struct.fields.len +
2195 fields_len);
2196 ip.items.appendAssumeCapacity(.{
2197 .tag = tag,
2198 .data = ip.addExtraAssumeCapacity(EnumExplicit{
2199 .decl = enum_type.decl,
2200 .namespace = enum_type.namespace,
2201 .int_tag_type = enum_type.tag_ty,
2202 .fields_len = fields_len,
2203 .names_map = names_map,
2204 .values_map = values_map,
2205 }),
2206 });
2207 ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, enum_type.names));
2208 ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, enum_type.values));
2209 return @intToEnum(Index, ip.items.len - 1);
2210}
2211
2212pub fn getAssumeExists(ip: *const InternPool, key: Key) Index {
2213 const adapter: KeyAdapter = .{ .intern_pool = ip };
19392214 const index = ip.map.getIndexAdapted(key, adapter).?;
19402215 return @intToEnum(Index, index);
19412216}
......@@ -1979,6 +2254,7 @@ fn addMap(ip: *InternPool, gpa: Allocator) Allocator.Error!MapIndex {
19792254pub fn remove(ip: *InternPool, index: Index) void {
19802255 _ = ip;
19812256 _ = index;
2257 @setCold(true);
19822258 @panic("TODO this is a bit problematic to implement, could we maybe just never support a remove() operation on InternPool?");
19832259}
19842260
......@@ -2336,7 +2612,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
23362612 .type_slice => 0,
23372613 .type_optional => 0,
23382614 .type_error_union => @sizeOf(ErrorUnion),
2339 .type_enum_explicit => @sizeOf(EnumExplicit),
2615 .type_enum_explicit, .type_enum_nonexhaustive => @sizeOf(EnumExplicit),
23402616 .type_enum_auto => @sizeOf(EnumAuto),
23412617 .type_opaque => @sizeOf(Key.OpaqueType),
23422618 .type_struct => @sizeOf(Module.Struct) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl),
......@@ -2448,3 +2724,50 @@ pub fn destroyUnion(ip: *InternPool, gpa: Allocator, index: Module.Union.Index)
24482724 // allocation failures here, instead leaking the Union until garbage collection.
24492725 };
24502726}
2727
2728pub fn getOrPutString(
2729 ip: *InternPool,
2730 gpa: Allocator,
2731 s: []const u8,
2732) Allocator.Error!NullTerminatedString {
2733 const string_bytes = &ip.string_bytes;
2734 const str_index = @intCast(u32, string_bytes.items.len);
2735 try string_bytes.ensureUnusedCapacity(gpa, s.len + 1);
2736 string_bytes.appendSliceAssumeCapacity(s);
2737 const key: []const u8 = string_bytes.items[str_index..];
2738 const gop = try ip.string_table.getOrPutContextAdapted(gpa, key, std.hash_map.StringIndexAdapter{
2739 .bytes = string_bytes,
2740 }, std.hash_map.StringIndexContext{
2741 .bytes = string_bytes,
2742 });
2743 if (gop.found_existing) {
2744 string_bytes.shrinkRetainingCapacity(str_index);
2745 return @intToEnum(NullTerminatedString, gop.key_ptr.*);
2746 } else {
2747 gop.key_ptr.* = str_index;
2748 string_bytes.appendAssumeCapacity(0);
2749 return @intToEnum(NullTerminatedString, str_index);
2750 }
2751}
2752
2753pub fn getString(ip: *InternPool, s: []const u8) OptionalNullTerminatedString {
2754 if (ip.string_table.getKeyAdapted(s, std.hash_map.StringIndexAdapter{
2755 .bytes = &ip.string_bytes,
2756 })) |index| {
2757 return @intToEnum(NullTerminatedString, index).toOptional();
2758 } else {
2759 return .none;
2760 }
2761}
2762
2763pub fn stringToSlice(ip: InternPool, s: NullTerminatedString) [:0]const u8 {
2764 const string_bytes = ip.string_bytes.items;
2765 const start = @enumToInt(s);
2766 var end: usize = start;
2767 while (string_bytes[end] != 0) end += 1;
2768 return string_bytes[start..end :0];
2769}
2770
2771pub fn typeOf(ip: InternPool, index: Index) Index {
2772 return ip.indexToKey(index).typeOf();
2773}
src/Module.zig+28-167
......@@ -886,29 +886,17 @@ pub const Decl = struct {
886886 /// Only returns it if the Decl is the owner.
887887 pub fn getInnerNamespaceIndex(decl: *Decl, mod: *Module) Namespace.OptionalIndex {
888888 if (!decl.owns_tv) return .none;
889 switch (decl.val.ip_index) {
890 .empty_struct_type => return .none,
891 .none => {
892 const ty = (decl.val.castTag(.ty) orelse return .none).data;
893 switch (ty.tag()) {
894 .enum_full, .enum_nonexhaustive => {
895 const enum_obj = ty.cast(Type.Payload.EnumFull).?.data;
896 return enum_obj.namespace.toOptional();
897 },
898
899 else => return .none,
900 }
901 },
902 else => return switch (mod.intern_pool.indexToKey(decl.val.ip_index)) {
889 return switch (decl.val.ip_index) {
890 .empty_struct_type => .none,
891 .none => .none,
892 else => switch (mod.intern_pool.indexToKey(decl.val.ip_index)) {
903893 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
904894 .struct_type => |struct_type| struct_type.namespace,
905 .union_type => |union_type| {
906 const union_obj = mod.unionPtr(union_type.index);
907 return union_obj.namespace.toOptional();
908 },
895 .union_type => |union_type| mod.unionPtr(union_type.index).namespace.toOptional(),
896 .enum_type => |enum_type| enum_type.namespace,
909897 else => .none,
910898 },
911 }
899 };
912900 }
913901
914902 /// Same as `getInnerNamespaceIndex` but additionally obtains the pointer.
......@@ -1135,28 +1123,6 @@ pub const Struct = struct {
11351123 return mod.declPtr(s.owner_decl).srcLoc(mod);
11361124 }
11371125
1138 pub fn fieldSrcLoc(s: Struct, mod: *Module, query: FieldSrcQuery) SrcLoc {
1139 @setCold(true);
1140 const owner_decl = mod.declPtr(s.owner_decl);
1141 const file = owner_decl.getFileScope(mod);
1142 const tree = file.getTree(mod.gpa) catch |err| {
1143 // In this case we emit a warning + a less precise source location.
1144 log.warn("unable to load {s}: {s}", .{
1145 file.sub_file_path, @errorName(err),
1146 });
1147 return s.srcLoc(mod);
1148 };
1149 const node = owner_decl.relativeToNodeIndex(0);
1150
1151 var buf: [2]Ast.Node.Index = undefined;
1152 if (tree.fullContainerDecl(&buf, node)) |container_decl| {
1153 return queryFieldSrc(tree.*, query, file, container_decl);
1154 } else {
1155 // This struct was generated using @Type
1156 return s.srcLoc(mod);
1157 }
1158 }
1159
11601126 pub fn haveFieldTypes(s: Struct) bool {
11611127 return switch (s.status) {
11621128 .none,
......@@ -1237,110 +1203,6 @@ pub const Struct = struct {
12371203 }
12381204};
12391205
1240/// Represents the data that an enum declaration provides, when the fields
1241/// are auto-numbered, and there are no declarations. The integer tag type
1242/// is inferred to be the smallest power of two unsigned int that fits
1243/// the number of fields.
1244pub const EnumSimple = struct {
1245 /// The Decl that corresponds to the enum itself.
1246 owner_decl: Decl.Index,
1247 /// Set of field names in declaration order.
1248 fields: NameMap,
1249
1250 pub const NameMap = EnumFull.NameMap;
1251
1252 pub fn srcLoc(self: EnumSimple, mod: *Module) SrcLoc {
1253 const owner_decl = mod.declPtr(self.owner_decl);
1254 return .{
1255 .file_scope = owner_decl.getFileScope(mod),
1256 .parent_decl_node = owner_decl.src_node,
1257 .lazy = LazySrcLoc.nodeOffset(0),
1258 };
1259 }
1260};
1261
1262/// Represents the data that an enum declaration provides, when there are no
1263/// declarations. However an integer tag type is provided, and the enum tag values
1264/// are explicitly provided.
1265pub const EnumNumbered = struct {
1266 /// The Decl that corresponds to the enum itself.
1267 owner_decl: Decl.Index,
1268 /// An integer type which is used for the numerical value of the enum.
1269 /// Whether zig chooses this type or the user specifies it, it is stored here.
1270 tag_ty: Type,
1271 /// Set of field names in declaration order.
1272 fields: NameMap,
1273 /// Maps integer tag value to field index.
1274 /// Entries are in declaration order, same as `fields`.
1275 /// If this hash map is empty, it means the enum tags are auto-numbered.
1276 values: ValueMap,
1277
1278 pub const NameMap = EnumFull.NameMap;
1279 pub const ValueMap = EnumFull.ValueMap;
1280
1281 pub fn srcLoc(self: EnumNumbered, mod: *Module) SrcLoc {
1282 const owner_decl = mod.declPtr(self.owner_decl);
1283 return .{
1284 .file_scope = owner_decl.getFileScope(mod),
1285 .parent_decl_node = owner_decl.src_node,
1286 .lazy = LazySrcLoc.nodeOffset(0),
1287 };
1288 }
1289};
1290
1291/// Represents the data that an enum declaration provides, when there is
1292/// at least one tag value explicitly specified, or at least one declaration.
1293pub const EnumFull = struct {
1294 /// The Decl that corresponds to the enum itself.
1295 owner_decl: Decl.Index,
1296 /// An integer type which is used for the numerical value of the enum.
1297 /// Whether zig chooses this type or the user specifies it, it is stored here.
1298 tag_ty: Type,
1299 /// Set of field names in declaration order.
1300 fields: NameMap,
1301 /// Maps integer tag value to field index.
1302 /// Entries are in declaration order, same as `fields`.
1303 /// If this hash map is empty, it means the enum tags are auto-numbered.
1304 values: ValueMap,
1305 /// Represents the declarations inside this enum.
1306 namespace: Namespace.Index,
1307 /// true if zig inferred this tag type, false if user specified it
1308 tag_ty_inferred: bool,
1309
1310 pub const NameMap = std.StringArrayHashMapUnmanaged(void);
1311 pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.ArrayHashContext, false);
1312
1313 pub fn srcLoc(self: EnumFull, mod: *Module) SrcLoc {
1314 const owner_decl = mod.declPtr(self.owner_decl);
1315 return .{
1316 .file_scope = owner_decl.getFileScope(mod),
1317 .parent_decl_node = owner_decl.src_node,
1318 .lazy = LazySrcLoc.nodeOffset(0),
1319 };
1320 }
1321
1322 pub fn fieldSrcLoc(e: EnumFull, mod: *Module, query: FieldSrcQuery) SrcLoc {
1323 @setCold(true);
1324 const owner_decl = mod.declPtr(e.owner_decl);
1325 const file = owner_decl.getFileScope(mod);
1326 const tree = file.getTree(mod.gpa) catch |err| {
1327 // In this case we emit a warning + a less precise source location.
1328 log.warn("unable to load {s}: {s}", .{
1329 file.sub_file_path, @errorName(err),
1330 });
1331 return e.srcLoc(mod);
1332 };
1333 const node = owner_decl.relativeToNodeIndex(0);
1334 var buf: [2]Ast.Node.Index = undefined;
1335 if (tree.fullContainerDecl(&buf, node)) |container_decl| {
1336 return queryFieldSrc(tree.*, query, file, container_decl);
1337 } else {
1338 // This enum was generated using @Type
1339 return e.srcLoc(mod);
1340 }
1341 }
1342};
1343
13441206pub const Union = struct {
13451207 /// An enum type which is used for the tag of the union.
13461208 /// This type is created even for untagged unions, even when the memory
......@@ -1427,28 +1289,6 @@ pub const Union = struct {
14271289 };
14281290 }
14291291
1430 pub fn fieldSrcLoc(u: Union, mod: *Module, query: FieldSrcQuery) SrcLoc {
1431 @setCold(true);
1432 const owner_decl = mod.declPtr(u.owner_decl);
1433 const file = owner_decl.getFileScope(mod);
1434 const tree = file.getTree(mod.gpa) catch |err| {
1435 // In this case we emit a warning + a less precise source location.
1436 log.warn("unable to load {s}: {s}", .{
1437 file.sub_file_path, @errorName(err),
1438 });
1439 return u.srcLoc(mod);
1440 };
1441 const node = owner_decl.relativeToNodeIndex(0);
1442
1443 var buf: [2]Ast.Node.Index = undefined;
1444 if (tree.fullContainerDecl(&buf, node)) |container_decl| {
1445 return queryFieldSrc(tree.*, query, file, container_decl);
1446 } else {
1447 // This union was generated using @Type
1448 return u.srcLoc(mod);
1449 }
1450 }
1451
14521292 pub fn haveFieldTypes(u: Union) bool {
14531293 return switch (u.status) {
14541294 .none,
......@@ -7313,3 +7153,24 @@ pub fn typeToUnion(mod: *Module, ty: Type) ?*Union {
73137153 const union_index = mod.intern_pool.indexToUnion(ty.ip_index).unwrap() orelse return null;
73147154 return mod.unionPtr(union_index);
73157155}
7156
7157pub fn fieldSrcLoc(mod: *Module, owner_decl_index: Decl.Index, query: FieldSrcQuery) SrcLoc {
7158 @setCold(true);
7159 const owner_decl = mod.declPtr(owner_decl_index);
7160 const file = owner_decl.getFileScope(mod);
7161 const tree = file.getTree(mod.gpa) catch |err| {
7162 // In this case we emit a warning + a less precise source location.
7163 log.warn("unable to load {s}: {s}", .{
7164 file.sub_file_path, @errorName(err),
7165 });
7166 return owner_decl.srcLoc(mod);
7167 };
7168 const node = owner_decl.relativeToNodeIndex(0);
7169 var buf: [2]Ast.Node.Index = undefined;
7170 if (tree.fullContainerDecl(&buf, node)) |container_decl| {
7171 return queryFieldSrc(tree.*, query, file, container_decl);
7172 } else {
7173 // This type was generated using @Type
7174 return owner_decl.srcLoc(mod);
7175 }
7176}
src/Sema.zig+328-446
......@@ -2096,7 +2096,7 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS
20962096 errdefer msg.destroy(sema.gpa);
20972097
20982098 const struct_ty = mod.typeToStruct(container_ty) orelse break :msg msg;
2099 const default_value_src = struct_ty.fieldSrcLoc(mod, .{
2099 const default_value_src = mod.fieldSrcLoc(struct_ty.owner_decl, .{
21002100 .index = field_index,
21012101 .range = .value,
21022102 });
......@@ -2875,50 +2875,28 @@ fn zirEnumDecl(
28752875 break :blk decls_len;
28762876 } else 0;
28772877
2878 var done = false;
2879
2880 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
2881 errdefer if (!done) new_decl_arena.deinit();
2882 const new_decl_arena_allocator = new_decl_arena.allocator();
2878 // Because these three things each reference each other, `undefined`
2879 // placeholders are used before being set after the enum type gains an
2880 // InternPool index.
28832881
2884 const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull);
2885 const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumFull);
2886 enum_ty_payload.* = .{
2887 .base = .{ .tag = if (small.nonexhaustive) .enum_nonexhaustive else .enum_full },
2888 .data = enum_obj,
2889 };
2890 const enum_ty = Type.initPayload(&enum_ty_payload.base);
2891 const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
2882 var done = false;
28922883 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
28932884 .ty = Type.type,
2894 .val = enum_val,
2885 .val = undefined,
28952886 }, small.name_strategy, "enum", inst);
28962887 const new_decl = mod.declPtr(new_decl_index);
28972888 new_decl.owns_tv = true;
28982889 errdefer if (!done) mod.abortAnonDecl(new_decl_index);
28992890
2900 enum_obj.* = .{
2901 .owner_decl = new_decl_index,
2902 .tag_ty = Type.null,
2903 .tag_ty_inferred = true,
2904 .fields = .{},
2905 .values = .{},
2906 .namespace = try mod.createNamespace(.{
2907 .parent = block.namespace.toOptional(),
2908 .ty = enum_ty,
2909 .file_scope = block.getFileScope(mod),
2910 }),
2911 };
2912
2913 try new_decl.finalizeNewArena(&new_decl_arena);
2914 const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index);
2915 done = true;
2916
2917 var decl_arena: std.heap.ArenaAllocator = undefined;
2918 const decl_arena_allocator = new_decl.value_arena.?.acquire(gpa, &decl_arena);
2919 defer new_decl.value_arena.?.release(&decl_arena);
2891 const new_namespace_index = try mod.createNamespace(.{
2892 .parent = block.namespace.toOptional(),
2893 .ty = undefined,
2894 .file_scope = block.getFileScope(mod),
2895 });
2896 const new_namespace = mod.namespacePtr(new_namespace_index);
2897 errdefer if (!done) mod.destroyNamespace(new_namespace_index);
29202898
2921 extra_index = try mod.scanNamespace(enum_obj.namespace, extra_index, decls_len, new_decl);
2899 extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
29222900
29232901 const body = sema.code.extra[extra_index..][0..body_len];
29242902 extra_index += body.len;
......@@ -2927,7 +2905,31 @@ fn zirEnumDecl(
29272905 const body_end = extra_index;
29282906 extra_index += bit_bags_count;
29292907
2930 {
2908 const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
2909 if (bag != 0) break true;
2910 } else false;
2911
2912 const incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{
2913 .decl = new_decl_index,
2914 .namespace = new_namespace_index.toOptional(),
2915 .fields_len = fields_len,
2916 .has_values = any_values,
2917 .tag_mode = if (small.nonexhaustive)
2918 .nonexhaustive
2919 else if (tag_type_ref == .none)
2920 .auto
2921 else
2922 .explicit,
2923 });
2924 errdefer if (!done) mod.intern_pool.remove(incomplete_enum.index);
2925
2926 new_decl.val = incomplete_enum.index.toValue();
2927 new_namespace.ty = incomplete_enum.index.toType();
2928
2929 const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index);
2930 done = true;
2931
2932 const int_tag_ty = ty: {
29312933 // We create a block for the field type instructions because they
29322934 // may need to reference Decls from inside the enum namespace.
29332935 // Within the field type, default value, and alignment expressions, the "owner decl"
......@@ -2957,7 +2959,7 @@ fn zirEnumDecl(
29572959 .parent = null,
29582960 .sema = sema,
29592961 .src_decl = new_decl_index,
2960 .namespace = enum_obj.namespace,
2962 .namespace = new_namespace_index,
29612963 .wip_capture_scope = wip_captures.scope,
29622964 .instructions = .{},
29632965 .inlining = null,
......@@ -2976,35 +2978,22 @@ fn zirEnumDecl(
29762978 if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) {
29772979 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)});
29782980 }
2979 enum_obj.tag_ty = try ty.copy(decl_arena_allocator);
2980 enum_obj.tag_ty_inferred = false;
2981 incomplete_enum.setTagType(&mod.intern_pool, ty.ip_index);
2982 break :ty ty;
29812983 } else if (fields_len == 0) {
2982 enum_obj.tag_ty = try mod.intType(.unsigned, 0);
2983 enum_obj.tag_ty_inferred = true;
2984 break :ty try mod.intType(.unsigned, 0);
29842985 } else {
29852986 const bits = std.math.log2_int_ceil(usize, fields_len);
2986 enum_obj.tag_ty = try mod.intType(.unsigned, bits);
2987 enum_obj.tag_ty_inferred = true;
2987 break :ty try mod.intType(.unsigned, bits);
29882988 }
2989 }
2989 };
29902990
2991 if (small.nonexhaustive and enum_obj.tag_ty.zigTypeTag(mod) != .ComptimeInt) {
2992 if (fields_len > 1 and std.math.log2_int(u64, fields_len) == enum_obj.tag_ty.bitSize(mod)) {
2991 if (small.nonexhaustive and int_tag_ty.ip_index != .comptime_int_type) {
2992 if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(mod)) {
29932993 return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
29942994 }
29952995 }
29962996
2997 try enum_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
2998 const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
2999 if (bag != 0) break true;
3000 } else false;
3001 if (any_values) {
3002 try enum_obj.values.ensureTotalCapacityContext(decl_arena_allocator, fields_len, .{
3003 .ty = enum_obj.tag_ty,
3004 .mod = mod,
3005 });
3006 }
3007
30082997 var bit_bag_index: usize = body_end;
30092998 var cur_bit_bag: u32 = undefined;
30102999 var field_i: u32 = 0;
......@@ -3023,15 +3012,12 @@ fn zirEnumDecl(
30233012 // doc comment
30243013 extra_index += 1;
30253014
3026 // This string needs to outlive the ZIR code.
3027 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
3028
3029 const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name);
3030 if (gop_field.found_existing) {
3031 const field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
3032 const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_field.index }).lazy;
3015 const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir);
3016 if (try incomplete_enum.addFieldName(&mod.intern_pool, gpa, field_name)) |other_index| {
3017 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
3018 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
30333019 const msg = msg: {
3034 const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name});
3020 const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name_zir});
30353021 errdefer msg.destroy(gpa);
30363022 try sema.errNote(block, other_field_src, msg, "other field here", .{});
30373023 break :msg msg;
......@@ -3045,7 +3031,7 @@ fn zirEnumDecl(
30453031 const tag_inst = try sema.resolveInst(tag_val_ref);
30463032 const tag_val = sema.resolveConstValue(block, .unneeded, tag_inst, "") catch |err| switch (err) {
30473033 error.NeededSourceLocation => {
3048 const value_src = enum_obj.fieldSrcLoc(sema.mod, .{
3034 const value_src = mod.fieldSrcLoc(new_decl_index, .{
30493035 .index = field_i,
30503036 .range = .value,
30513037 }).lazy;
......@@ -3055,19 +3041,14 @@ fn zirEnumDecl(
30553041 else => |e| return e,
30563042 };
30573043 last_tag_val = tag_val;
3058 const copied_tag_val = try tag_val.copy(decl_arena_allocator);
3059 const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{
3060 .ty = enum_obj.tag_ty,
3061 .mod = mod,
3062 });
3063 if (gop_val.found_existing) {
3064 const value_src = enum_obj.fieldSrcLoc(sema.mod, .{
3044 if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, tag_val.ip_index)) |other_index| {
3045 const value_src = mod.fieldSrcLoc(new_decl_index, .{
30653046 .index = field_i,
30663047 .range = .value,
30673048 }).lazy;
3068 const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_val.index }).lazy;
3049 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
30693050 const msg = msg: {
3070 const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)});
3051 const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{tag_val.fmtValue(int_tag_ty, sema.mod)});
30713052 errdefer msg.destroy(gpa);
30723053 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
30733054 break :msg msg;
......@@ -3076,20 +3057,15 @@ fn zirEnumDecl(
30763057 }
30773058 } else if (any_values) {
30783059 const tag_val = if (last_tag_val) |val|
3079 try sema.intAdd(val, try mod.intValue(enum_obj.tag_ty, 1), enum_obj.tag_ty)
3060 try sema.intAdd(val, try mod.intValue(int_tag_ty, 1), int_tag_ty)
30803061 else
3081 try mod.intValue(enum_obj.tag_ty, 0);
3062 try mod.intValue(int_tag_ty, 0);
30823063 last_tag_val = tag_val;
3083 const copied_tag_val = try tag_val.copy(decl_arena_allocator);
3084 const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{
3085 .ty = enum_obj.tag_ty,
3086 .mod = mod,
3087 });
3088 if (gop_val.found_existing) {
3089 const field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
3090 const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_val.index }).lazy;
3064 if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, tag_val.ip_index)) |other_index| {
3065 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
3066 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
30913067 const msg = msg: {
3092 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)});
3068 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(int_tag_ty, sema.mod)});
30933069 errdefer msg.destroy(gpa);
30943070 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
30953071 break :msg msg;
......@@ -3097,16 +3073,16 @@ fn zirEnumDecl(
30973073 return sema.failWithOwnedErrorMsg(msg);
30983074 }
30993075 } else {
3100 last_tag_val = try mod.intValue(enum_obj.tag_ty, field_i);
3076 last_tag_val = try mod.intValue(int_tag_ty, field_i);
31013077 }
31023078
3103 if (!(try sema.intFitsInType(last_tag_val.?, enum_obj.tag_ty, null))) {
3104 const value_src = enum_obj.fieldSrcLoc(sema.mod, .{
3079 if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) {
3080 const value_src = mod.fieldSrcLoc(new_decl_index, .{
31053081 .index = field_i,
31063082 .range = if (has_tag_value) .value else .name,
31073083 }).lazy;
31083084 const msg = try sema.errMsg(block, value_src, "enumeration value '{}' too large for type '{}'", .{
3109 last_tag_val.?.fmtValue(enum_obj.tag_ty, mod), enum_obj.tag_ty.fmt(mod),
3085 last_tag_val.?.fmtValue(int_tag_ty, mod), int_tag_ty.fmt(mod),
31103086 });
31113087 return sema.failWithOwnedErrorMsg(msg);
31123088 }
......@@ -4356,7 +4332,7 @@ fn validateUnionInit(
43564332 }
43574333
43584334 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
4359 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
4335 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?);
43604336 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
43614337
43624338 if (init_val) |val| {
......@@ -8334,7 +8310,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
83348310 _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand));
83358311
83368312 if (try sema.resolveMaybeUndefVal(operand)) |int_val| {
8337 if (dest_ty.isNonexhaustiveEnum()) {
8313 if (dest_ty.isNonexhaustiveEnum(mod)) {
83388314 const int_tag_ty = try dest_ty.intTagType(mod);
83398315 if (try sema.intFitsInType(int_val, int_tag_ty, null)) {
83408316 return sema.addConstant(dest_ty, int_val);
......@@ -8383,7 +8359,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
83838359
83848360 try sema.requireRuntimeBlock(block, src, operand_src);
83858361 const result = try block.addTyOp(.intcast, dest_ty, operand);
8386 if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum() and
8362 if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum(mod) and
83878363 sema.mod.backendSupportsFeature(.is_named_enum_value))
83888364 {
83898365 const ok = try block.addUnOp(.is_named_enum_value, result);
......@@ -10518,7 +10494,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1051810494 var else_error_ty: ?Type = null;
1051910495
1052010496 // Validate usage of '_' prongs.
10521 if (special_prong == .under and (!operand_ty.isNonexhaustiveEnum() or union_originally)) {
10497 if (special_prong == .under and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally)) {
1052210498 const msg = msg: {
1052310499 const msg = try sema.errMsg(
1052410500 block,
......@@ -10543,8 +10519,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1054310519 switch (operand_ty.zigTypeTag(mod)) {
1054410520 .Union => unreachable, // handled in zirSwitchCond
1054510521 .Enum => {
10546 seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount());
10547 empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum();
10522 seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount(mod));
10523 empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(mod);
1054810524 @memset(seen_enum_fields, null);
1054910525 // `range_set` is used for non-exhaustive enum values that do not correspond to any tags.
1055010526
......@@ -10599,7 +10575,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1059910575 } else true;
1060010576
1060110577 if (special_prong == .@"else") {
10602 if (all_tags_handled and !operand_ty.isNonexhaustiveEnum()) return sema.fail(
10578 if (all_tags_handled and !operand_ty.isNonexhaustiveEnum(mod)) return sema.fail(
1060310579 block,
1060410580 special_prong_src,
1060510581 "unreachable else prong; all cases already handled",
......@@ -10617,7 +10593,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1061710593 for (seen_enum_fields, 0..) |seen_src, i| {
1061810594 if (seen_src != null) continue;
1061910595
10620 const field_name = operand_ty.enumFieldName(i);
10596 const field_name = operand_ty.enumFieldName(i, mod);
1062110597 try sema.addFieldErrNote(
1062210598 operand_ty,
1062310599 i,
......@@ -10635,7 +10611,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1063510611 break :msg msg;
1063610612 };
1063710613 return sema.failWithOwnedErrorMsg(msg);
10638 } else if (special_prong == .none and operand_ty.isNonexhaustiveEnum() and !union_originally) {
10614 } else if (special_prong == .none and operand_ty.isNonexhaustiveEnum(mod) and !union_originally) {
1063910615 return sema.fail(
1064010616 block,
1064110617 src,
......@@ -11159,7 +11135,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1115911135 return Air.Inst.Ref.unreachable_value;
1116011136 }
1116111137 if (mod.backendSupportsFeature(.is_named_enum_value) and block.wantSafety() and operand_ty.zigTypeTag(mod) == .Enum and
11162 (!operand_ty.isNonexhaustiveEnum() or union_originally))
11138 (!operand_ty.isNonexhaustiveEnum(mod) or union_originally))
1116311139 {
1116411140 try sema.zirDbgStmt(block, cond_dbg_node_index);
1116511141 const ok = try block.addUnOp(.is_named_enum_value, operand);
......@@ -11489,7 +11465,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1148911465 var emit_bb = false;
1149011466 if (special.is_inline) switch (operand_ty.zigTypeTag(mod)) {
1149111467 .Enum => {
11492 if (operand_ty.isNonexhaustiveEnum() and !union_originally) {
11468 if (operand_ty.isNonexhaustiveEnum(mod) and !union_originally) {
1149311469 return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{
1149411470 operand_ty.fmt(mod),
1149511471 });
......@@ -11629,7 +11605,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1162911605 case_block.inline_case_capture = .none;
1163011606
1163111607 if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and
11632 operand_ty.zigTypeTag(mod) == .Enum and (!operand_ty.isNonexhaustiveEnum() or union_originally))
11608 operand_ty.zigTypeTag(mod) == .Enum and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally))
1163311609 {
1163411610 try sema.zirDbgStmt(&case_block, cond_dbg_node_index);
1163511611 const ok = try case_block.addUnOp(.is_named_enum_value, operand);
......@@ -12081,7 +12057,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1208112057 break :hf switch (ty.zigTypeTag(mod)) {
1208212058 .Struct => ty.structFields(mod).contains(field_name),
1208312059 .Union => ty.unionFields(mod).contains(field_name),
12084 .Enum => ty.enumFields().contains(field_name),
12060 .Enum => ty.enumFieldIndex(field_name, mod) != null,
1208512061 .Array => mem.eql(u8, field_name, "len"),
1208612062 else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{
1208712063 ty.fmt(sema.mod),
......@@ -16300,9 +16276,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1630016276 },
1630116277 .Enum => {
1630216278 // TODO: look into memoizing this result.
16303 const int_tag_ty = try ty.intTagType(mod);
16279 const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
1630416280
16305 const is_exhaustive = Value.makeBool(!ty.isNonexhaustiveEnum());
16281 const is_exhaustive = Value.makeBool(enum_type.tag_mode != .nonexhaustive);
1630616282
1630716283 var fields_anon_decl = try block.startAnonDecl();
1630816284 defer fields_anon_decl.deinit();
......@@ -16320,25 +16296,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1632016296 break :t try enum_field_ty_decl.val.toType().copy(fields_anon_decl.arena());
1632116297 };
1632216298
16323 const enum_fields = ty.enumFields();
16324 const enum_field_vals = try fields_anon_decl.arena().alloc(Value, enum_fields.count());
16299 const enum_field_vals = try fields_anon_decl.arena().alloc(Value, enum_type.names.len);
1632516300
1632616301 for (enum_field_vals, 0..) |*field_val, i| {
16327 var tag_val_payload: Value.Payload.U32 = .{
16328 .base = .{ .tag = .enum_field_index },
16329 .data = @intCast(u32, i),
16330 };
16331 const tag_val = Value.initPayload(&tag_val_payload.base);
16332
16333 const int_val = try tag_val.enumToInt(ty, mod);
16334
16335 const name = enum_fields.keys()[i];
16302 const name_ip = enum_type.names[i];
16303 const name = mod.intern_pool.stringToSlice(name_ip);
1633616304 const name_val = v: {
1633716305 var anon_decl = try block.startAnonDecl();
1633816306 defer anon_decl.deinit();
1633916307 const bytes = try anon_decl.arena().dupeZ(u8, name);
1634016308 const new_decl = try anon_decl.finish(
16341 try Type.array(anon_decl.arena(), bytes.len, try mod.intValue(Type.u8, 0), Type.u8, mod),
16309 try Type.array(anon_decl.arena(), bytes.len, Value.zero_u8, Type.u8, mod),
1634216310 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
1634316311 0, // default alignment
1634416312 );
......@@ -16350,7 +16318,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1635016318 // name: []const u8,
1635116319 name_val,
1635216320 // value: comptime_int,
16353 int_val,
16321 try mod.intValue(Type.comptime_int, i),
1635416322 };
1635516323 field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), enum_field_fields);
1635616324 }
......@@ -16370,12 +16338,12 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1637016338 break :v try Value.Tag.decl_ref.create(sema.arena, new_decl);
1637116339 };
1637216340
16373 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespace(mod));
16341 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, enum_type.namespace);
1637416342
1637516343 const field_values = try sema.arena.create([4]Value);
1637616344 field_values.* = .{
1637716345 // tag_type: type,
16378 try Value.Tag.ty.create(sema.arena, int_tag_ty),
16346 enum_type.tag_ty.toValue(),
1637916347 // fields: []const EnumField,
1638016348 fields_val,
1638116349 // decls: []const Declaration,
......@@ -16468,7 +16436,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1646816436 });
1646916437 };
1647016438
16471 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespace(mod));
16439 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespaceIndex(mod));
1647216440
1647316441 const enum_tag_ty_val = if (union_ty.unionTagType(mod)) |tag_ty| v: {
1647416442 const ty_val = try Value.Tag.ty.create(sema.arena, tag_ty);
......@@ -16631,7 +16599,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1663116599 });
1663216600 };
1663316601
16634 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespace(mod));
16602 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespaceIndex(mod));
1663516603
1663616604 const backing_integer_val = blk: {
1663716605 if (layout == .Packed) {
......@@ -16674,7 +16642,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1667416642 // TODO: look into memoizing this result.
1667516643
1667616644 const opaque_ty = try sema.resolveTypeFields(ty);
16677 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespace(mod));
16645 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespaceIndex(mod));
1667816646
1667916647 const field_values = try sema.arena.create([1]Value);
1668016648 field_values.* = .{
......@@ -16700,7 +16668,7 @@ fn typeInfoDecls(
1670016668 block: *Block,
1670116669 src: LazySrcLoc,
1670216670 type_info_ty: Type,
16703 opt_namespace: ?*Module.Namespace,
16671 opt_namespace: Module.Namespace.OptionalIndex,
1670416672) CompileError!Value {
1670516673 const mod = sema.mod;
1670616674 var decls_anon_decl = try block.startAnonDecl();
......@@ -16726,8 +16694,9 @@ fn typeInfoDecls(
1672616694 var seen_namespaces = std.AutoHashMap(*Namespace, void).init(sema.gpa);
1672716695 defer seen_namespaces.deinit();
1672816696
16729 if (opt_namespace) |some| {
16730 try sema.typeInfoNamespaceDecls(block, decls_anon_decl.arena(), some, &decl_vals, &seen_namespaces);
16697 if (opt_namespace.unwrap()) |namespace_index| {
16698 const namespace = mod.namespacePtr(namespace_index);
16699 try sema.typeInfoNamespaceDecls(block, decls_anon_decl.arena(), namespace, &decl_vals, &seen_namespaces);
1673116700 }
1673216701
1673316702 const new_decl = try decls_anon_decl.finish(
......@@ -17896,7 +17865,7 @@ fn unionInit(
1789617865
1789717866 if (try sema.resolveMaybeUndefVal(init)) |init_val| {
1789817867 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
17899 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
17868 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?);
1790017869 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
1790117870 return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{
1790217871 .tag = tag_val,
......@@ -17997,7 +17966,7 @@ fn zirStructInit(
1799717966 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
1799817967 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
1799917968 const tag_ty = resolved_ty.unionTagTypeHypothetical(mod);
18000 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
17969 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?);
1800117970 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
1800217971
1800317972 const init_inst = try sema.resolveInst(item.data.init);
......@@ -18754,7 +18723,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1875418723 operand_ty.fmt(mod),
1875518724 }),
1875618725 };
18757 if (enum_ty.enumFieldCount() == 0) {
18726 if (enum_ty.enumFieldCount(mod) == 0) {
1875818727 // TODO I don't think this is the correct way to handle this but
1875918728 // it prevents a crash.
1876018729 return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{}'", .{
......@@ -18776,7 +18745,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1877618745 };
1877718746 return sema.failWithOwnedErrorMsg(msg);
1877818747 };
18779 const field_name = enum_ty.enumFieldName(field_index);
18748 const field_name = enum_ty.enumFieldName(field_index, mod);
1878018749 return sema.addStrLit(block, field_name);
1878118750 }
1878218751 try sema.requireRuntimeBlock(block, src, operand_src);
......@@ -19081,63 +19050,41 @@ fn zirReify(
1908119050 return sema.fail(block, src, "reified enums must have no decls", .{});
1908219051 }
1908319052
19084 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
19085 errdefer new_decl_arena.deinit();
19086 const new_decl_arena_allocator = new_decl_arena.allocator();
19053 const int_tag_ty = tag_type_val.toType();
19054 if (int_tag_ty.zigTypeTag(mod) != .Int) {
19055 return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{});
19056 }
19057
19058 // Because these things each reference each other, `undefined`
19059 // placeholders are used before being set after the enum type gains
19060 // an InternPool index.
1908719061
19088 // Define our empty enum decl
19089 const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull);
19090 const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumFull);
19091 enum_ty_payload.* = .{
19092 .base = .{
19093 .tag = if (!is_exhaustive_val.toBool(mod))
19094 .enum_nonexhaustive
19095 else
19096 .enum_full,
19097 },
19098 .data = enum_obj,
19099 };
19100 const enum_ty = Type.initPayload(&enum_ty_payload.base);
19101 const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
1910219062 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
1910319063 .ty = Type.type,
19104 .val = enum_val,
19064 .val = undefined,
1910519065 }, name_strategy, "enum", inst);
1910619066 const new_decl = mod.declPtr(new_decl_index);
1910719067 new_decl.owns_tv = true;
1910819068 errdefer mod.abortAnonDecl(new_decl_index);
1910919069
19110 enum_obj.* = .{
19111 .owner_decl = new_decl_index,
19112 .tag_ty = Type.null,
19113 .tag_ty_inferred = false,
19114 .fields = .{},
19115 .values = .{},
19116 .namespace = try mod.createNamespace(.{
19117 .parent = block.namespace.toOptional(),
19118 .ty = enum_ty,
19119 .file_scope = block.getFileScope(mod),
19120 }),
19121 };
19122
19123 // Enum tag type
19124 const int_tag_ty = try tag_type_val.toType().copy(new_decl_arena_allocator);
19125
19126 if (int_tag_ty.zigTypeTag(mod) != .Int) {
19127 return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{});
19128 }
19129 enum_obj.tag_ty = int_tag_ty;
19130
19131 // Fields
19132 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
19133 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
19134 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
19135 .ty = enum_obj.tag_ty,
19136 .mod = mod,
19070 // Define our empty enum decl
19071 const fields_len = @intCast(u32, try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
19072 const incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{
19073 .decl = new_decl_index,
19074 .namespace = .none,
19075 .fields_len = fields_len,
19076 .has_values = true,
19077 .tag_mode = if (!is_exhaustive_val.toBool(mod))
19078 .nonexhaustive
19079 else
19080 .explicit,
19081 .tag_ty = int_tag_ty.ip_index,
1913719082 });
19083 errdefer mod.intern_pool.remove(incomplete_enum.index);
1913819084
19139 var field_i: usize = 0;
19140 while (field_i < fields_len) : (field_i += 1) {
19085 new_decl.val = incomplete_enum.index.toValue();
19086
19087 for (0..fields_len) |field_i| {
1914119088 const elem_val = try fields_val.elemValue(mod, field_i);
1914219089 const field_struct_val: []const Value = elem_val.castTag(.aggregate).?.data;
1914319090 // TODO use reflection instead of magic numbers here
......@@ -19148,39 +19095,36 @@ fn zirReify(
1914819095
1914919096 const field_name = try name_val.toAllocatedBytes(
1915019097 Type.const_slice_u8,
19151 new_decl_arena_allocator,
19098 sema.arena,
1915219099 mod,
1915319100 );
19101 const field_name_ip = try mod.intern_pool.getOrPutString(gpa, field_name);
1915419102
19155 if (!try sema.intFitsInType(value_val, enum_obj.tag_ty, null)) {
19103 if (!try sema.intFitsInType(value_val, int_tag_ty, null)) {
1915619104 // TODO: better source location
1915719105 return sema.fail(block, src, "field '{s}' with enumeration value '{}' is too large for backing int type '{}'", .{
1915819106 field_name,
1915919107 value_val.fmtValue(Type.comptime_int, mod),
19160 enum_obj.tag_ty.fmt(mod),
19108 int_tag_ty.fmt(mod),
1916119109 });
1916219110 }
1916319111
19164 const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name);
19165 if (gop_field.found_existing) {
19112 if (try incomplete_enum.addFieldName(&mod.intern_pool, gpa, field_name_ip)) |other_index| {
1916619113 const msg = msg: {
1916719114 const msg = try sema.errMsg(block, src, "duplicate enum field '{s}'", .{field_name});
1916819115 errdefer msg.destroy(gpa);
19116 _ = other_index; // TODO: this note is incorrect
1916919117 try sema.errNote(block, src, msg, "other field here", .{});
1917019118 break :msg msg;
1917119119 };
1917219120 return sema.failWithOwnedErrorMsg(msg);
1917319121 }
1917419122
19175 const copied_tag_val = try value_val.copy(new_decl_arena_allocator);
19176 const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{
19177 .ty = enum_obj.tag_ty,
19178 .mod = mod,
19179 });
19180 if (gop_val.found_existing) {
19123 if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, value_val.ip_index)) |other| {
1918119124 const msg = msg: {
1918219125 const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)});
1918319126 errdefer msg.destroy(gpa);
19127 _ = other; // TODO: this note is incorrect
1918419128 try sema.errNote(block, src, msg, "other enum tag value here", .{});
1918519129 break :msg msg;
1918619130 };
......@@ -19188,7 +19132,6 @@ fn zirReify(
1918819132 }
1918919133 }
1919019134
19191 try new_decl.finalizeNewArena(&new_decl_arena);
1919219135 return sema.analyzeDeclVal(block, src, new_decl_index);
1919319136 },
1919419137 .Opaque => {
......@@ -19307,26 +19250,29 @@ fn zirReify(
1930719250 new_namespace.ty = union_ty.toType();
1930819251
1930919252 // Tag type
19310 var tag_ty_field_names: ?Module.EnumFull.NameMap = null;
19311 var enum_field_names: ?*Module.EnumNumbered.NameMap = null;
1931219253 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
19254 var explicit_tags_seen: []bool = &.{};
19255 var explicit_enum_info: ?InternPool.Key.EnumType = null;
19256 var enum_field_names: []InternPool.NullTerminatedString = &.{};
1931319257 if (tag_type_val.optionalValue(mod)) |payload_val| {
19314 union_obj.tag_ty = try payload_val.toType().copy(new_decl_arena_allocator);
19258 union_obj.tag_ty = payload_val.toType();
1931519259
19316 if (union_obj.tag_ty.zigTypeTag(mod) != .Enum) {
19317 return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{});
19318 }
19319 tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena);
19260 const enum_type = switch (mod.intern_pool.indexToKey(union_obj.tag_ty.ip_index)) {
19261 .enum_type => |x| x,
19262 else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),
19263 };
19264
19265 explicit_enum_info = enum_type;
19266 explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
19267 @memset(explicit_tags_seen, false);
1932019268 } else {
19321 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, fields_len, null);
19322 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
19269 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
1932319270 }
1932419271
1932519272 // Fields
1932619273 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
1932719274
19328 var i: usize = 0;
19329 while (i < fields_len) : (i += 1) {
19275 for (0..fields_len) |i| {
1933019276 const elem_val = try fields_val.elemValue(mod, i);
1933119277 const field_struct_val = elem_val.castTag(.aggregate).?.data;
1933219278 // TODO use reflection instead of magic numbers here
......@@ -19343,13 +19289,14 @@ fn zirReify(
1934319289 mod,
1934419290 );
1934519291
19346 if (enum_field_names) |set| {
19347 set.putAssumeCapacity(field_name, {});
19292 const field_name_ip = try mod.intern_pool.getOrPutString(gpa, field_name);
19293
19294 if (enum_field_names.len != 0) {
19295 enum_field_names[i] = field_name_ip;
1934819296 }
1934919297
19350 if (tag_ty_field_names) |*names| {
19351 const enum_has_field = names.orderedRemove(field_name);
19352 if (!enum_has_field) {
19298 if (explicit_enum_info) |tag_info| {
19299 const enum_index = tag_info.nameIndex(mod.intern_pool, field_name_ip) orelse {
1935319300 const msg = msg: {
1935419301 const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(mod) });
1935519302 errdefer msg.destroy(gpa);
......@@ -19357,7 +19304,11 @@ fn zirReify(
1935719304 break :msg msg;
1935819305 };
1935919306 return sema.failWithOwnedErrorMsg(msg);
19360 }
19307 };
19308 // No check for duplicate because the check already happened in order
19309 // to create the enum type in the first place.
19310 assert(!explicit_tags_seen[enum_index]);
19311 explicit_tags_seen[enum_index] = true;
1936119312 }
1936219313
1936319314 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
......@@ -19409,22 +19360,26 @@ fn zirReify(
1940919360 }
1941019361 }
1941119362
19412 if (tag_ty_field_names) |names| {
19413 if (names.count() > 0) {
19363 if (explicit_enum_info) |tag_info| {
19364 if (tag_info.names.len > fields_len) {
1941419365 const msg = msg: {
1941519366 const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{});
1941619367 errdefer msg.destroy(gpa);
1941719368
1941819369 const enum_ty = union_obj.tag_ty;
19419 for (names.keys()) |field_name| {
19420 const field_index = enum_ty.enumFieldIndex(field_name).?;
19421 try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name});
19370 for (tag_info.names, 0..) |field_name, field_index| {
19371 if (explicit_tags_seen[field_index]) continue;
19372 try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{
19373 mod.intern_pool.stringToSlice(field_name),
19374 });
1942219375 }
1942319376 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
1942419377 break :msg msg;
1942519378 };
1942619379 return sema.failWithOwnedErrorMsg(msg);
1942719380 }
19381 } else {
19382 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, enum_field_names, null);
1942819383 }
1942919384
1943019385 try new_decl.finalizeNewArena(&new_decl_arena);
......@@ -23450,7 +23405,7 @@ fn explainWhyTypeIsComptimeInner(
2345023405
2345123406 if (mod.typeToStruct(ty)) |struct_obj| {
2345223407 for (struct_obj.fields.values(), 0..) |field, i| {
23453 const field_src_loc = struct_obj.fieldSrcLoc(sema.mod, .{
23408 const field_src_loc = mod.fieldSrcLoc(struct_obj.owner_decl, .{
2345423409 .index = i,
2345523410 .range = .type,
2345623411 });
......@@ -23469,7 +23424,7 @@ fn explainWhyTypeIsComptimeInner(
2346923424
2347023425 if (mod.typeToUnion(ty)) |union_obj| {
2347123426 for (union_obj.fields.values(), 0..) |field, i| {
23472 const field_src_loc = union_obj.fieldSrcLoc(sema.mod, .{
23427 const field_src_loc = mod.fieldSrcLoc(union_obj.owner_decl, .{
2347323428 .index = i,
2347423429 .range = .type,
2347523430 });
......@@ -24168,7 +24123,7 @@ fn fieldVal(
2416824123 }
2416924124 const union_ty = try sema.resolveTypeFields(child_type);
2417024125 if (union_ty.unionTagType(mod)) |enum_ty| {
24171 if (enum_ty.enumFieldIndex(field_name)) |field_index_usize| {
24126 if (enum_ty.enumFieldIndex(field_name, mod)) |field_index_usize| {
2417224127 const field_index = @intCast(u32, field_index_usize);
2417324128 return sema.addConstant(
2417424129 enum_ty,
......@@ -24184,7 +24139,7 @@ fn fieldVal(
2418424139 return inst;
2418524140 }
2418624141 }
24187 const field_index_usize = child_type.enumFieldIndex(field_name) orelse
24142 const field_index_usize = child_type.enumFieldIndex(field_name, mod) orelse
2418824143 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
2418924144 const field_index = @intCast(u32, field_index_usize);
2419024145 const enum_val = try Value.Tag.enum_field_index.create(arena, field_index);
......@@ -24382,7 +24337,7 @@ fn fieldPtr(
2438224337 }
2438324338 const union_ty = try sema.resolveTypeFields(child_type);
2438424339 if (union_ty.unionTagType(mod)) |enum_ty| {
24385 if (enum_ty.enumFieldIndex(field_name)) |field_index| {
24340 if (enum_ty.enumFieldIndex(field_name, mod)) |field_index| {
2438624341 const field_index_u32 = @intCast(u32, field_index);
2438724342 var anon_decl = try block.startAnonDecl();
2438824343 defer anon_decl.deinit();
......@@ -24401,7 +24356,7 @@ fn fieldPtr(
2440124356 return inst;
2440224357 }
2440324358 }
24404 const field_index = child_type.enumFieldIndex(field_name) orelse {
24359 const field_index = child_type.enumFieldIndex(field_name, mod) orelse {
2440524360 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
2440624361 };
2440724362 const field_index_u32 = @intCast(u32, field_index);
......@@ -24996,7 +24951,7 @@ fn unionFieldPtr(
2499624951 .@"volatile" = union_ptr_ty.isVolatilePtr(mod),
2499724952 .@"addrspace" = union_ptr_ty.ptrAddressSpace(mod),
2499824953 });
24999 const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);
24954 const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name, mod).?);
2500024955
2500124956 if (initializing and field.ty.zigTypeTag(mod) == .NoReturn) {
2500224957 const msg = msg: {
......@@ -25028,7 +24983,7 @@ fn unionFieldPtr(
2502824983 if (!tag_matches) {
2502924984 const msg = msg: {
2503024985 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;
25031 const active_field_name = union_obj.tag_ty.enumFieldName(active_index);
24986 const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod);
2503224987 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
2503324988 errdefer msg.destroy(sema.gpa);
2503424989 try sema.addDeclaredHereNote(msg, union_ty);
......@@ -25083,7 +25038,7 @@ fn unionFieldVal(
2508325038 const union_obj = mod.typeToUnion(union_ty).?;
2508425039 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
2508525040 const field = union_obj.fields.values()[field_index];
25086 const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);
25041 const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name, mod).?);
2508725042
2508825043 if (try sema.resolveMaybeUndefVal(union_byval)) |union_val| {
2508925044 if (union_val.isUndef()) return sema.addConstUndef(field.ty);
......@@ -25102,7 +25057,7 @@ fn unionFieldVal(
2510225057 } else {
2510325058 const msg = msg: {
2510425059 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;
25105 const active_field_name = union_obj.tag_ty.enumFieldName(active_index);
25060 const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod);
2510625061 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
2510725062 errdefer msg.destroy(sema.gpa);
2510825063 try sema.addDeclaredHereNote(msg, union_ty);
......@@ -26191,7 +26146,7 @@ fn coerceExtra(
2619126146 // enum literal to enum
2619226147 const val = try sema.resolveConstValue(block, .unneeded, inst, "");
2619326148 const bytes = val.castTag(.enum_literal).?.data;
26194 const field_index = dest_ty.enumFieldIndex(bytes) orelse {
26149 const field_index = dest_ty.enumFieldIndex(bytes, mod) orelse {
2619526150 const msg = msg: {
2619626151 const msg = try sema.errMsg(
2619726152 block,
......@@ -28707,7 +28662,7 @@ fn coerceEnumToUnion(
2870728662
2870828663 try sema.requireRuntimeBlock(block, inst_src, null);
2870928664
28710 if (tag_ty.isNonexhaustiveEnum()) {
28665 if (tag_ty.isNonexhaustiveEnum(mod)) {
2871128666 const msg = msg: {
2871228667 const msg = try sema.errMsg(block, inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{
2871328668 union_ty.fmt(sema.mod),
......@@ -31605,7 +31560,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3160531560 .error_set_single,
3160631561 .error_set_inferred,
3160731562 .error_set_merged,
31608 .enum_simple,
3160931563 => false,
3161031564
3161131565 .function => true,
......@@ -31646,14 +31600,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3164631600 const child_ty = ty.castTag(.anyframe_T).?.data;
3164731601 return sema.resolveTypeRequiresComptime(child_ty);
3164831602 },
31649 .enum_numbered => {
31650 const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty;
31651 return sema.resolveTypeRequiresComptime(tag_ty);
31652 },
31653 .enum_full, .enum_nonexhaustive => {
31654 const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty;
31655 return sema.resolveTypeRequiresComptime(tag_ty);
31656 },
3165731603 },
3165831604 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
3165931605 .int_type => false,
......@@ -31760,7 +31706,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3176031706
3176131707 .opaque_type => false,
3176231708
31763 .enum_type => @panic("TODO"),
31709 .enum_type => |enum_type| try sema.resolveTypeRequiresComptime(enum_type.tag_ty.toType()),
3176431710
3176531711 // values, not types
3176631712 .un => unreachable,
......@@ -32284,12 +32230,12 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3228432230 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
3228532231 if (gop.found_existing) {
3228632232 const msg = msg: {
32287 const field_src = struct_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
32233 const field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = field_i }).lazy;
3228832234 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name});
3228932235 errdefer msg.destroy(gpa);
3229032236
3229132237 const prev_field_index = struct_obj.fields.getIndex(field_name).?;
32292 const prev_field_src = struct_obj.fieldSrcLoc(sema.mod, .{ .index = prev_field_index });
32238 const prev_field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = prev_field_index });
3229332239 try sema.mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{});
3229432240 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
3229532241 break :msg msg;
......@@ -32325,7 +32271,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3232532271 if (zir_field.type_ref != .none) {
3232632272 break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) {
3232732273 error.NeededSourceLocation => {
32328 const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{
32274 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
3232932275 .index = field_i,
3233032276 .range = .type,
3233132277 }).lazy;
......@@ -32341,7 +32287,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3234132287 const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
3234232288 break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) {
3234332289 error.NeededSourceLocation => {
32344 const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{
32290 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
3234532291 .index = field_i,
3234632292 .range = .type,
3234732293 }).lazy;
......@@ -32360,7 +32306,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3236032306
3236132307 if (field_ty.zigTypeTag(mod) == .Opaque) {
3236232308 const msg = msg: {
32363 const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{
32309 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
3236432310 .index = field_i,
3236532311 .range = .type,
3236632312 }).lazy;
......@@ -32374,7 +32320,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3237432320 }
3237532321 if (field_ty.zigTypeTag(mod) == .NoReturn) {
3237632322 const msg = msg: {
32377 const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{
32323 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
3237832324 .index = field_i,
3237932325 .range = .type,
3238032326 }).lazy;
......@@ -32388,7 +32334,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3238832334 }
3238932335 if (struct_obj.layout == .Extern and !try sema.validateExternType(field.ty, .struct_field)) {
3239032336 const msg = msg: {
32391 const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{
32337 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
3239232338 .index = field_i,
3239332339 .range = .type,
3239432340 });
......@@ -32403,7 +32349,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3240332349 return sema.failWithOwnedErrorMsg(msg);
3240432350 } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty, mod))) {
3240532351 const msg = msg: {
32406 const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{
32352 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
3240732353 .index = field_i,
3240832354 .range = .type,
3240932355 });
......@@ -32424,7 +32370,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3242432370 const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
3242532371 field.abi_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {
3242632372 error.NeededSourceLocation => {
32427 const align_src = struct_obj.fieldSrcLoc(sema.mod, .{
32373 const align_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
3242832374 .index = field_i,
3242932375 .range = .alignment,
3243032376 }).lazy;
......@@ -32452,7 +32398,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3245232398 const field = &struct_obj.fields.values()[field_i];
3245332399 const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) {
3245432400 error.NeededSourceLocation => {
32455 const init_src = struct_obj.fieldSrcLoc(sema.mod, .{
32401 const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
3245632402 .index = field_i,
3245732403 .range = .value,
3245832404 }).lazy;
......@@ -32462,7 +32408,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3246232408 else => |e| return e,
3246332409 };
3246432410 const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
32465 const init_src = struct_obj.fieldSrcLoc(sema.mod, .{
32411 const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
3246632412 .index = field_i,
3246732413 .range = .value,
3246832414 }).lazy;
......@@ -32573,9 +32519,11 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3257332519 try union_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
3257432520
3257532521 var int_tag_ty: Type = undefined;
32576 var enum_field_names: ?*Module.EnumNumbered.NameMap = null;
32577 var enum_value_map: ?*Module.EnumNumbered.ValueMap = null;
32578 var tag_ty_field_names: ?Module.EnumFull.NameMap = null;
32522 var enum_field_names: []InternPool.NullTerminatedString = &.{};
32523 var enum_field_vals: []InternPool.Index = &.{};
32524 var enum_field_vals_map: std.ArrayHashMapUnmanaged(Value, void, Value.ArrayHashContext, false) = .{};
32525 var explicit_tags_seen: []bool = &.{};
32526 var explicit_enum_info: ?InternPool.Key.EnumType = null;
3257932527 if (tag_type_ref != .none) {
3258032528 const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x };
3258132529 const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref);
......@@ -32601,27 +32549,26 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3260132549 return sema.failWithOwnedErrorMsg(msg);
3260232550 }
3260332551 }
32604 union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, fields_len, provided_ty, union_obj);
32605 const enum_obj = union_obj.tag_ty.castTag(.enum_numbered).?.data;
32606 enum_field_names = &enum_obj.fields;
32607 enum_value_map = &enum_obj.values;
32552 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
32553 enum_field_vals = try sema.arena.alloc(InternPool.Index, fields_len);
3260832554 } else {
3260932555 // The provided type is the enum tag type.
32610 union_obj.tag_ty = try provided_ty.copy(decl_arena_allocator);
32611 if (union_obj.tag_ty.zigTypeTag(mod) != .Enum) {
32612 return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(sema.mod)});
32613 }
32556 union_obj.tag_ty = provided_ty;
32557 const enum_type = switch (mod.intern_pool.indexToKey(union_obj.tag_ty.ip_index)) {
32558 .enum_type => |x| x,
32559 else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(sema.mod)}),
32560 };
3261432561 // The fields of the union must match the enum exactly.
32615 // Store a copy of the enum field names so we can check for
32616 // missing or extraneous fields later.
32617 tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena);
32562 // A flag per field is used to check for missing and extraneous fields.
32563 explicit_enum_info = enum_type;
32564 explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
32565 @memset(explicit_tags_seen, false);
3261832566 }
3261932567 } else {
3262032568 // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis
3262132569 // purposes, we still auto-generate an enum tag type the same way. That the union is
3262232570 // untagged is represented by the Type tag (union vs union_tagged).
32623 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, fields_len, union_obj);
32624 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
32571 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
3262532572 }
3262632573
3262732574 if (fields_len == 0) {
......@@ -32675,11 +32622,11 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3267532622 break :blk try sema.resolveInst(tag_ref);
3267632623 } else .none;
3267732624
32678 if (enum_value_map) |map| {
32625 if (enum_field_vals.len != 0) {
3267932626 const copied_val = if (tag_ref != .none) blk: {
3268032627 const val = sema.semaUnionFieldVal(&block_scope, .unneeded, int_tag_ty, tag_ref) catch |err| switch (err) {
3268132628 error.NeededSourceLocation => {
32682 const val_src = union_obj.fieldSrcLoc(sema.mod, .{
32629 const val_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
3268332630 .index = field_i,
3268432631 .range = .value,
3268532632 }).lazy;
......@@ -32690,25 +32637,24 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3269032637 };
3269132638 last_tag_val = val;
3269232639
32693 // This puts the memory into the union arena, not the enum arena, but
32694 // it is OK since they share the same lifetime.
32695 break :blk try val.copy(decl_arena_allocator);
32640 break :blk val;
3269632641 } else blk: {
3269732642 const val = if (last_tag_val) |val|
32698 try sema.intAdd(val, try mod.intValue(int_tag_ty, 1), int_tag_ty)
32643 try sema.intAdd(val, Value.one_comptime_int, int_tag_ty)
3269932644 else
3270032645 try mod.intValue(int_tag_ty, 0);
3270132646 last_tag_val = val;
3270232647
32703 break :blk try val.copy(decl_arena_allocator);
32648 break :blk val;
3270432649 };
32705 const gop = map.getOrPutAssumeCapacityContext(copied_val, .{
32650 enum_field_vals[field_i] = copied_val.ip_index;
32651 const gop = enum_field_vals_map.getOrPutAssumeCapacityContext(copied_val, .{
3270632652 .ty = int_tag_ty,
3270732653 .mod = mod,
3270832654 });
3270932655 if (gop.found_existing) {
32710 const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
32711 const other_field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = gop.index }).lazy;
32656 const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy;
32657 const other_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = gop.index }).lazy;
3271232658 const msg = msg: {
3271332659 const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{copied_val.fmtValue(int_tag_ty, sema.mod)});
3271432660 errdefer msg.destroy(gpa);
......@@ -32721,8 +32667,9 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3272132667
3272232668 // This string needs to outlive the ZIR code.
3272332669 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
32724 if (enum_field_names) |set| {
32725 set.putAssumeCapacity(field_name, {});
32670 const field_name_ip = try mod.intern_pool.getOrPutString(gpa, field_name);
32671 if (enum_field_names.len != 0) {
32672 enum_field_names[field_i] = field_name_ip;
3272632673 }
3272732674
3272832675 const field_ty: Type = if (!has_type)
......@@ -32732,7 +32679,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3273232679 else
3273332680 sema.resolveType(&block_scope, .unneeded, field_type_ref) catch |err| switch (err) {
3273432681 error.NeededSourceLocation => {
32735 const ty_src = union_obj.fieldSrcLoc(sema.mod, .{
32682 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
3273632683 .index = field_i,
3273732684 .range = .type,
3273832685 }).lazy;
......@@ -32749,12 +32696,12 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3274932696 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
3275032697 if (gop.found_existing) {
3275132698 const msg = msg: {
32752 const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
32699 const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy;
3275332700 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name});
3275432701 errdefer msg.destroy(gpa);
3275532702
3275632703 const prev_field_index = union_obj.fields.getIndex(field_name).?;
32757 const prev_field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = prev_field_index }).lazy;
32704 const prev_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = prev_field_index }).lazy;
3275832705 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl, mod), msg, "other field here", .{});
3275932706 try sema.errNote(&block_scope, src, msg, "union declared here", .{});
3276032707 break :msg msg;
......@@ -32762,26 +32709,31 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3276232709 return sema.failWithOwnedErrorMsg(msg);
3276332710 }
3276432711
32765 if (tag_ty_field_names) |*names| {
32766 const enum_has_field = names.orderedRemove(field_name);
32767 if (!enum_has_field) {
32712 if (explicit_enum_info) |tag_info| {
32713 const enum_index = tag_info.nameIndex(mod.intern_pool, field_name_ip) orelse {
3276832714 const msg = msg: {
32769 const ty_src = union_obj.fieldSrcLoc(sema.mod, .{
32715 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
3277032716 .index = field_i,
3277132717 .range = .type,
3277232718 }).lazy;
32773 const msg = try sema.errMsg(&block_scope, ty_src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
32719 const msg = try sema.errMsg(&block_scope, ty_src, "no field named '{s}' in enum '{}'", .{
32720 field_name, union_obj.tag_ty.fmt(sema.mod),
32721 });
3277432722 errdefer msg.destroy(sema.gpa);
3277532723 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
3277632724 break :msg msg;
3277732725 };
3277832726 return sema.failWithOwnedErrorMsg(msg);
32779 }
32727 };
32728 // No check for duplicate because the check already happened in order
32729 // to create the enum type in the first place.
32730 assert(!explicit_tags_seen[enum_index]);
32731 explicit_tags_seen[enum_index] = true;
3278032732 }
3278132733
3278232734 if (field_ty.zigTypeTag(mod) == .Opaque) {
3278332735 const msg = msg: {
32784 const ty_src = union_obj.fieldSrcLoc(sema.mod, .{
32736 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
3278532737 .index = field_i,
3278632738 .range = .type,
3278732739 }).lazy;
......@@ -32795,7 +32747,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3279532747 }
3279632748 if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {
3279732749 const msg = msg: {
32798 const ty_src = union_obj.fieldSrcLoc(sema.mod, .{
32750 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
3279932751 .index = field_i,
3280032752 .range = .type,
3280132753 });
......@@ -32810,7 +32762,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3281032762 return sema.failWithOwnedErrorMsg(msg);
3281132763 } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) {
3281232764 const msg = msg: {
32813 const ty_src = union_obj.fieldSrcLoc(sema.mod, .{
32765 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
3281432766 .index = field_i,
3281532767 .range = .type,
3281632768 });
......@@ -32833,7 +32785,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3283332785 if (align_ref != .none) {
3283432786 gop.value_ptr.abi_align = sema.resolveAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {
3283532787 error.NeededSourceLocation => {
32836 const align_src = union_obj.fieldSrcLoc(sema.mod, .{
32788 const align_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
3283732789 .index = field_i,
3283832790 .range = .alignment,
3283932791 }).lazy;
......@@ -32847,22 +32799,28 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3284732799 }
3284832800 }
3284932801
32850 if (tag_ty_field_names) |names| {
32851 if (names.count() > 0) {
32802 if (explicit_enum_info) |tag_info| {
32803 if (tag_info.names.len > fields_len) {
3285232804 const msg = msg: {
3285332805 const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{});
3285432806 errdefer msg.destroy(sema.gpa);
3285532807
3285632808 const enum_ty = union_obj.tag_ty;
32857 for (names.keys()) |field_name| {
32858 const field_index = enum_ty.enumFieldIndex(field_name).?;
32859 try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name});
32809 for (tag_info.names, 0..) |field_name, field_index| {
32810 if (explicit_tags_seen[field_index]) continue;
32811 try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{
32812 mod.intern_pool.stringToSlice(field_name),
32813 });
3286032814 }
3286132815 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
3286232816 break :msg msg;
3286332817 };
3286432818 return sema.failWithOwnedErrorMsg(msg);
3286532819 }
32820 } else if (enum_field_vals.len != 0) {
32821 union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals, union_obj);
32822 } else {
32823 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_obj);
3286632824 }
3286732825}
3286832826
......@@ -32874,25 +32832,12 @@ fn semaUnionFieldVal(sema: *Sema, block: *Block, src: LazySrcLoc, int_tag_ty: Ty
3287432832fn generateUnionTagTypeNumbered(
3287532833 sema: *Sema,
3287632834 block: *Block,
32877 fields_len: u32,
32878 int_ty: Type,
32835 enum_field_names: []const InternPool.NullTerminatedString,
32836 enum_field_vals: []const InternPool.Index,
3287932837 union_obj: *Module.Union,
3288032838) !Type {
3288132839 const mod = sema.mod;
3288232840
32883 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
32884 errdefer new_decl_arena.deinit();
32885 const new_decl_arena_allocator = new_decl_arena.allocator();
32886
32887 const enum_obj = try new_decl_arena_allocator.create(Module.EnumNumbered);
32888 const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumNumbered);
32889 enum_ty_payload.* = .{
32890 .base = .{ .tag = .enum_numbered },
32891 .data = enum_obj,
32892 };
32893 const enum_ty = Type.initPayload(&enum_ty_payload.base);
32894 const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
32895
3289632841 const src_decl = mod.declPtr(block.src_decl);
3289732842 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
3289832843 errdefer mod.destroyDecl(new_decl_index);
......@@ -32903,53 +32848,45 @@ fn generateUnionTagTypeNumbered(
3290332848 };
3290432849 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{
3290532850 .ty = Type.type,
32906 .val = enum_val,
32851 .val = undefined,
3290732852 }, name);
32908 sema.mod.declPtr(new_decl_index).name_fully_qualified = true;
32909
3291032853 const new_decl = mod.declPtr(new_decl_index);
32854 new_decl.name_fully_qualified = true;
3291132855 new_decl.owns_tv = true;
3291232856 new_decl.name_fully_qualified = true;
3291332857 errdefer mod.abortAnonDecl(new_decl_index);
3291432858
32915 const copied_int_ty = try int_ty.copy(new_decl_arena_allocator);
32916 enum_obj.* = .{
32917 .owner_decl = new_decl_index,
32918 .tag_ty = copied_int_ty,
32919 .fields = .{},
32920 .values = .{},
32921 };
32922 // Here we pre-allocate the maps using the decl arena.
32923 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
32924 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
32925 .ty = copied_int_ty,
32926 .mod = mod,
32927 });
32928 try new_decl.finalizeNewArena(&new_decl_arena);
32929 return enum_ty;
32930}
32859 const enum_ty = try mod.intern(.{ .enum_type = .{
32860 .decl = new_decl_index,
32861 .namespace = .none,
32862 .tag_ty = if (enum_field_vals.len == 0)
32863 .noreturn_type
32864 else
32865 mod.intern_pool.typeOf(enum_field_vals[0]),
32866 .names = enum_field_names,
32867 .values = enum_field_vals,
32868 .tag_mode = .explicit,
32869 } });
32870 errdefer mod.intern_pool.remove(enum_ty);
3293132871
32932fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, maybe_union_obj: ?*Module.Union) !Type {
32933 const mod = sema.mod;
32872 new_decl.val = enum_ty.toValue();
3293432873
32935 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
32936 errdefer new_decl_arena.deinit();
32937 const new_decl_arena_allocator = new_decl_arena.allocator();
32874 return enum_ty.toType();
32875}
3293832876
32939 const enum_obj = try new_decl_arena_allocator.create(Module.EnumSimple);
32940 const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumSimple);
32941 enum_ty_payload.* = .{
32942 .base = .{ .tag = .enum_simple },
32943 .data = enum_obj,
32944 };
32945 const enum_ty = Type.initPayload(&enum_ty_payload.base);
32946 const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
32877fn generateUnionTagTypeSimple(
32878 sema: *Sema,
32879 block: *Block,
32880 enum_field_names: []const InternPool.NullTerminatedString,
32881 maybe_union_obj: ?*Module.Union,
32882) !Type {
32883 const mod = sema.mod;
3294732884
3294832885 const new_decl_index = new_decl_index: {
3294932886 const union_obj = maybe_union_obj orelse {
3295032887 break :new_decl_index try mod.createAnonymousDecl(block, .{
3295132888 .ty = Type.type,
32952 .val = enum_val,
32889 .val = undefined,
3295332890 });
3295432891 };
3295532892 const src_decl = mod.declPtr(block.src_decl);
......@@ -32962,24 +32899,31 @@ fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, may
3296232899 };
3296332900 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{
3296432901 .ty = Type.type,
32965 .val = enum_val,
32902 .val = undefined,
3296632903 }, name);
32967 sema.mod.declPtr(new_decl_index).name_fully_qualified = true;
32904 mod.declPtr(new_decl_index).name_fully_qualified = true;
3296832905 break :new_decl_index new_decl_index;
3296932906 };
3297032907
32908 const enum_ty = try mod.intern(.{ .enum_type = .{
32909 .decl = new_decl_index,
32910 .namespace = .none,
32911 .tag_ty = if (enum_field_names.len == 0)
32912 .noreturn_type
32913 else
32914 (try mod.smallestUnsignedInt(enum_field_names.len - 1)).ip_index,
32915 .names = enum_field_names,
32916 .values = &.{},
32917 .tag_mode = .auto,
32918 } });
32919 errdefer mod.intern_pool.remove(enum_ty);
32920
3297132921 const new_decl = mod.declPtr(new_decl_index);
3297232922 new_decl.owns_tv = true;
32923 new_decl.val = enum_ty.toValue();
3297332924 errdefer mod.abortAnonDecl(new_decl_index);
3297432925
32975 enum_obj.* = .{
32976 .owner_decl = new_decl_index,
32977 .fields = .{},
32978 };
32979 // Here we pre-allocate the maps using the decl arena.
32980 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
32981 try new_decl.finalizeNewArena(&new_decl_arena);
32982 return enum_ty;
32926 return enum_ty.toType();
3298332927}
3298432928
3298532929fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
......@@ -33098,57 +33042,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3309833042 return Value.empty_struct;
3309933043 },
3310033044
33101 .enum_numbered => {
33102 const resolved_ty = try sema.resolveTypeFields(ty);
33103 const enum_obj = resolved_ty.castTag(.enum_numbered).?.data;
33104 // An explicit tag type is always provided for enum_numbered.
33105 if (!(try sema.typeHasRuntimeBits(enum_obj.tag_ty))) {
33106 return null;
33107 }
33108 if (enum_obj.fields.count() == 1) {
33109 if (enum_obj.values.count() == 0) {
33110 return Value.enum_field_0; // auto-numbered
33111 } else {
33112 return enum_obj.values.keys()[0];
33113 }
33114 } else {
33115 return null;
33116 }
33117 },
33118 .enum_full => {
33119 const resolved_ty = try sema.resolveTypeFields(ty);
33120 const enum_obj = resolved_ty.castTag(.enum_full).?.data;
33121 if (!(try sema.typeHasRuntimeBits(enum_obj.tag_ty))) {
33122 return null;
33123 }
33124 switch (enum_obj.fields.count()) {
33125 0 => return Value.@"unreachable",
33126 1 => if (enum_obj.values.count() == 0) {
33127 return Value.enum_field_0; // auto-numbered
33128 } else {
33129 return enum_obj.values.keys()[0];
33130 },
33131 else => return null,
33132 }
33133 },
33134 .enum_simple => {
33135 const resolved_ty = try sema.resolveTypeFields(ty);
33136 const enum_simple = resolved_ty.castTag(.enum_simple).?.data;
33137 switch (enum_simple.fields.count()) {
33138 0 => return Value.@"unreachable",
33139 1 => return Value.enum_field_0,
33140 else => return null,
33141 }
33142 },
33143 .enum_nonexhaustive => {
33144 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
33145 if (tag_ty.zigTypeTag(mod) != .ComptimeInt and !(try sema.typeHasRuntimeBits(tag_ty))) {
33146 return Value.enum_field_0;
33147 } else {
33148 return null;
33149 }
33150 },
33151
3315233045 .array => {
3315333046 if (ty.arrayLen(mod) == 0)
3315433047 return Value.initTag(.empty_array);
......@@ -33295,7 +33188,28 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3329533188 return only.toValue();
3329633189 },
3329733190 .opaque_type => null,
33298 .enum_type => @panic("TODO"),
33191 .enum_type => |enum_type| switch (enum_type.tag_mode) {
33192 .nonexhaustive => {
33193 if (enum_type.tag_ty != .comptime_int_type and
33194 !(try sema.typeHasRuntimeBits(enum_type.tag_ty.toType())))
33195 {
33196 return Value.enum_field_0;
33197 } else {
33198 return null;
33199 }
33200 },
33201 .auto, .explicit => switch (enum_type.names.len) {
33202 0 => return Value.@"unreachable",
33203 1 => {
33204 if (enum_type.values.len == 0) {
33205 return Value.enum_field_0; // auto-numbered
33206 } else {
33207 return enum_type.values[0].toValue();
33208 }
33209 },
33210 else => return null,
33211 },
33212 },
3329933213
3330033214 // values, not types
3330133215 .un => unreachable,
......@@ -33701,7 +33615,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3370133615 .error_set_single,
3370233616 .error_set_inferred,
3370333617 .error_set_merged,
33704 .enum_simple,
3370533618 => false,
3370633619
3370733620 .function => true,
......@@ -33742,14 +33655,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3374233655 const child_ty = ty.castTag(.anyframe_T).?.data;
3374333656 return sema.typeRequiresComptime(child_ty);
3374433657 },
33745 .enum_numbered => {
33746 const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty;
33747 return sema.typeRequiresComptime(tag_ty);
33748 },
33749 .enum_full, .enum_nonexhaustive => {
33750 const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty;
33751 return sema.typeRequiresComptime(tag_ty);
33752 },
3375333658 },
3375433659 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
3375533660 .int_type => return false,
......@@ -33865,7 +33770,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3386533770 },
3386633771
3386733772 .opaque_type => false,
33868 .enum_type => @panic("TODO"),
33773 .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()),
3386933774
3387033775 // values, not types
3387133776 .un => unreachable,
......@@ -34435,42 +34340,19 @@ fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {
3443534340/// Asserts the type is an enum.
3443634341fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {
3443734342 const mod = sema.mod;
34438 switch (ty.tag()) {
34439 .enum_nonexhaustive => unreachable,
34440 .enum_full => {
34441 const enum_full = ty.castTag(.enum_full).?.data;
34442 const tag_ty = enum_full.tag_ty;
34443 if (enum_full.values.count() == 0) {
34444 return sema.intInRange(tag_ty, int, enum_full.fields.count());
34445 } else {
34446 return enum_full.values.containsContext(int, .{
34447 .ty = tag_ty,
34448 .mod = sema.mod,
34449 });
34450 }
34451 },
34452 .enum_numbered => {
34453 const enum_obj = ty.castTag(.enum_numbered).?.data;
34454 const tag_ty = enum_obj.tag_ty;
34455 if (enum_obj.values.count() == 0) {
34456 return sema.intInRange(tag_ty, int, enum_obj.fields.count());
34457 } else {
34458 return enum_obj.values.containsContext(int, .{
34459 .ty = tag_ty,
34460 .mod = sema.mod,
34461 });
34462 }
34463 },
34464 .enum_simple => {
34465 const enum_simple = ty.castTag(.enum_simple).?.data;
34466 const fields_len = enum_simple.fields.count();
34467 const bits = std.math.log2_int_ceil(usize, fields_len);
34468 const tag_ty = try mod.intType(.unsigned, bits);
34469 return sema.intInRange(tag_ty, int, fields_len);
34470 },
34471
34472 else => unreachable,
34343 const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
34344 assert(enum_type.tag_mode != .nonexhaustive);
34345 if (enum_type.values.len == 0) {
34346 // auto-numbered
34347 return sema.intInRange(enum_type.tag_ty.toType(), int, enum_type.names.len);
3447334348 }
34349
34350 // The `tagValueIndex` function call below relies on the type being the integer tag type.
34351 // `getCoerced` assumes the value will fit the new type.
34352 if (!(try sema.intFitsInType(int, enum_type.tag_ty.toType(), null))) return false;
34353 const int_coerced = try mod.intern_pool.getCoerced(sema.gpa, int.ip_index, enum_type.tag_ty);
34354
34355 return enum_type.tagValueIndex(mod.intern_pool, int_coerced) != null;
3447434356}
3447534357
3447634358fn intAddWithOverflow(
src/TypedValue.zig+1-1
......@@ -198,7 +198,7 @@ pub fn print(
198198 .empty_array => return writer.writeAll(".{}"),
199199 .enum_literal => return writer.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}),
200200 .enum_field_index => {
201 return writer.print(".{s}", .{ty.enumFieldName(val.castTag(.enum_field_index).?.data)});
201 return writer.print(".{s}", .{ty.enumFieldName(val.castTag(.enum_field_index).?.data, mod)});
202202 },
203203 .bytes => return writer.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}),
204204 .str_lit => {
src/arch/wasm/CodeGen.zig+15-35
......@@ -3101,24 +3101,12 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
31013101 },
31023102 .Enum => {
31033103 if (val.castTag(.enum_field_index)) |field_index| {
3104 switch (ty.tag()) {
3105 .enum_simple => return WValue{ .imm32 = field_index.data },
3106 .enum_full, .enum_nonexhaustive => {
3107 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
3108 if (enum_full.values.count() != 0) {
3109 const tag_val = enum_full.values.keys()[field_index.data];
3110 return func.lowerConstant(tag_val, enum_full.tag_ty);
3111 } else {
3112 return WValue{ .imm32 = field_index.data };
3113 }
3114 },
3115 .enum_numbered => {
3116 const index = field_index.data;
3117 const enum_data = ty.castTag(.enum_numbered).?.data;
3118 const enum_val = enum_data.values.keys()[index];
3119 return func.lowerConstant(enum_val, enum_data.tag_ty);
3120 },
3121 else => return func.fail("TODO: lowerConstant for enum tag: {}", .{ty.tag()}),
3104 const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
3105 if (enum_type.values.len != 0) {
3106 const tag_val = enum_type.values[field_index.data];
3107 return func.lowerConstant(tag_val.toValue(), enum_type.tag_ty.toType());
3108 } else {
3109 return WValue{ .imm32 = field_index.data };
31223110 }
31233111 } else {
31243112 const int_tag_ty = try ty.intTagType(mod);
......@@ -3240,21 +3228,12 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) !i32 {
32403228 switch (ty.zigTypeTag(mod)) {
32413229 .Enum => {
32423230 if (val.castTag(.enum_field_index)) |field_index| {
3243 switch (ty.tag()) {
3244 .enum_simple => return @bitCast(i32, field_index.data),
3245 .enum_full, .enum_nonexhaustive => {
3246 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
3247 if (enum_full.values.count() != 0) {
3248 const tag_val = enum_full.values.keys()[field_index.data];
3249 return func.valueAsI32(tag_val, enum_full.tag_ty);
3250 } else return @bitCast(i32, field_index.data);
3251 },
3252 .enum_numbered => {
3253 const index = field_index.data;
3254 const enum_data = ty.castTag(.enum_numbered).?.data;
3255 return func.valueAsI32(enum_data.values.keys()[index], enum_data.tag_ty);
3256 },
3257 else => unreachable,
3231 const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
3232 if (enum_type.values.len != 0) {
3233 const tag_val = enum_type.values[field_index.data];
3234 return func.valueAsI32(tag_val.toValue(), enum_type.tag_ty.toType());
3235 } else {
3236 return @bitCast(i32, field_index.data);
32583237 }
32593238 } else {
32603239 const int_tag_ty = try ty.intTagType(mod);
......@@ -6836,7 +6815,8 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
68366815
68376816 // TODO: Make switch implementation generic so we can use a jump table for this when the tags are not sparse.
68386817 // generate an if-else chain for each tag value as well as constant.
6839 for (enum_ty.enumFields().keys(), 0..) |tag_name, field_index| {
6818 for (enum_ty.enumFields(mod), 0..) |tag_name_ip, field_index| {
6819 const tag_name = mod.intern_pool.stringToSlice(tag_name_ip);
68406820 // for each tag name, create an unnamed const,
68416821 // and then get a pointer to its value.
68426822 const name_ty = try mod.arrayType(.{
......@@ -6846,7 +6826,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
68466826 });
68476827 const string_bytes = &mod.string_literal_bytes;
68486828 try string_bytes.ensureUnusedCapacity(mod.gpa, tag_name.len);
6849 const gop = try mod.string_literal_table.getOrPutContextAdapted(mod.gpa, tag_name, Module.StringLiteralAdapter{
6829 const gop = try mod.string_literal_table.getOrPutContextAdapted(mod.gpa, @as([]const u8, tag_name), Module.StringLiteralAdapter{
68506830 .bytes = string_bytes,
68516831 }, Module.StringLiteralContext{
68526832 .bytes = string_bytes,
src/arch/x86_64/CodeGen.zig+5-4
......@@ -2016,7 +2016,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
20162016 const ret_reg = param_regs[0];
20172017 const enum_mcv = MCValue{ .register = param_regs[1] };
20182018
2019 var exitlude_jump_relocs = try self.gpa.alloc(u32, enum_ty.enumFieldCount());
2019 var exitlude_jump_relocs = try self.gpa.alloc(u32, enum_ty.enumFieldCount(mod));
20202020 defer self.gpa.free(exitlude_jump_relocs);
20212021
20222022 const data_reg = try self.register_manager.allocReg(null, gp);
......@@ -2027,9 +2027,10 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
20272027 var data_off: i32 = 0;
20282028 for (
20292029 exitlude_jump_relocs,
2030 enum_ty.enumFields().keys(),
2030 enum_ty.enumFields(mod),
20312031 0..,
2032 ) |*exitlude_jump_reloc, tag_name, index| {
2032 ) |*exitlude_jump_reloc, tag_name_ip, index| {
2033 const tag_name = mod.intern_pool.stringToSlice(tag_name_ip);
20332034 var tag_pl = Value.Payload.U32{
20342035 .base = .{ .tag = .enum_field_index },
20352036 .data = @intCast(u32, index),
......@@ -11413,7 +11414,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
1141311414 const union_obj = mod.typeToUnion(union_ty).?;
1141411415 const field_name = union_obj.fields.keys()[extra.field_index];
1141511416 const tag_ty = union_obj.tag_ty;
11416 const field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
11417 const field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?);
1141711418 var tag_pl = Value.Payload.U32{ .base = .{ .tag = .enum_field_index }, .data = field_index };
1141811419 const tag_val = Value.initPayload(&tag_pl.base);
1141911420 const tag_int_val = try tag_val.enumToInt(tag_ty, mod);
src/codegen.zig+11-21
......@@ -156,7 +156,8 @@ pub fn generateLazySymbol(
156156 return Result.ok;
157157 } else if (lazy_sym.ty.zigTypeTag(mod) == .Enum) {
158158 alignment.* = 1;
159 for (lazy_sym.ty.enumFields().keys()) |tag_name| {
159 for (lazy_sym.ty.enumFields(mod)) |tag_name_ip| {
160 const tag_name = mod.intern_pool.stringToSlice(tag_name_ip);
160161 try code.ensureUnusedCapacity(tag_name.len + 1);
161162 code.appendSliceAssumeCapacity(tag_name);
162163 code.appendAssumeCapacity(0);
......@@ -1229,26 +1230,15 @@ pub fn genTypedValue(
12291230 },
12301231 .Enum => {
12311232 if (typed_value.val.castTag(.enum_field_index)) |field_index| {
1232 switch (typed_value.ty.tag()) {
1233 .enum_simple => {
1234 return GenResult.mcv(.{ .immediate = field_index.data });
1235 },
1236 .enum_numbered, .enum_full, .enum_nonexhaustive => {
1237 const enum_values = if (typed_value.ty.castTag(.enum_numbered)) |pl|
1238 pl.data.values
1239 else
1240 typed_value.ty.cast(Type.Payload.EnumFull).?.data.values;
1241 if (enum_values.count() != 0) {
1242 const tag_val = enum_values.keys()[field_index.data];
1243 return genTypedValue(bin_file, src_loc, .{
1244 .ty = try typed_value.ty.intTagType(mod),
1245 .val = tag_val,
1246 }, owner_decl_index);
1247 } else {
1248 return GenResult.mcv(.{ .immediate = field_index.data });
1249 }
1250 },
1251 else => unreachable,
1233 const enum_type = mod.intern_pool.indexToKey(typed_value.ty.ip_index).enum_type;
1234 if (enum_type.values.len != 0) {
1235 const tag_val = enum_type.values[field_index.data];
1236 return genTypedValue(bin_file, src_loc, .{
1237 .ty = enum_type.tag_ty.toType(),
1238 .val = tag_val.toValue(),
1239 }, owner_decl_index);
1240 } else {
1241 return GenResult.mcv(.{ .immediate = field_index.data });
12521242 }
12531243 } else {
12541244 const int_tag_ty = try typed_value.ty.intTagType(mod);
src/codegen/c.zig+9-23
......@@ -1288,27 +1288,12 @@ pub const DeclGen = struct {
12881288 switch (val.tag()) {
12891289 .enum_field_index => {
12901290 const field_index = val.castTag(.enum_field_index).?.data;
1291 switch (ty.tag()) {
1292 .enum_simple => return writer.print("{d}", .{field_index}),
1293 .enum_full, .enum_nonexhaustive => {
1294 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
1295 if (enum_full.values.count() != 0) {
1296 const tag_val = enum_full.values.keys()[field_index];
1297 return dg.renderValue(writer, enum_full.tag_ty, tag_val, location);
1298 } else {
1299 return writer.print("{d}", .{field_index});
1300 }
1301 },
1302 .enum_numbered => {
1303 const enum_obj = ty.castTag(.enum_numbered).?.data;
1304 if (enum_obj.values.count() != 0) {
1305 const tag_val = enum_obj.values.keys()[field_index];
1306 return dg.renderValue(writer, enum_obj.tag_ty, tag_val, location);
1307 } else {
1308 return writer.print("{d}", .{field_index});
1309 }
1310 },
1311 else => unreachable,
1291 const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
1292 if (enum_type.values.len != 0) {
1293 const tag_val = enum_type.values[field_index];
1294 return dg.renderValue(writer, enum_type.tag_ty.toType(), tag_val.toValue(), location);
1295 } else {
1296 return writer.print("{d}", .{field_index});
13121297 }
13131298 },
13141299 else => {
......@@ -2539,7 +2524,8 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
25392524 try w.writeByte('(');
25402525 try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete);
25412526 try w.writeAll(") {\n switch (tag) {\n");
2542 for (enum_ty.enumFields().keys(), 0..) |name, index| {
2527 for (enum_ty.enumFields(mod), 0..) |name_ip, index| {
2528 const name = mod.intern_pool.stringToSlice(name_ip);
25432529 var tag_pl: Value.Payload.U32 = .{
25442530 .base = .{ .tag = .enum_field_index },
25452531 .data = @intCast(u32, index),
......@@ -6930,7 +6916,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
69306916 const field: CValue = if (union_ty.unionTagTypeSafety(mod)) |tag_ty| field: {
69316917 const layout = union_ty.unionGetLayout(mod);
69326918 if (layout.tag_size != 0) {
6933 const field_index = tag_ty.enumFieldIndex(field_name).?;
6919 const field_index = tag_ty.enumFieldIndex(field_name, mod).?;
69346920
69356921 var tag_pl: Value.Payload.U32 = .{
69366922 .base = .{ .tag = .enum_field_index },
src/codegen/llvm.zig+28-36
......@@ -1516,30 +1516,25 @@ pub const Object = struct {
15161516 return enum_di_ty;
15171517 }
15181518
1519 const field_names = ty.enumFields().keys();
1519 const ip = &mod.intern_pool;
1520 const enum_type = ip.indexToKey(ty.ip_index).enum_type;
15201521
1521 const enumerators = try gpa.alloc(*llvm.DIEnumerator, field_names.len);
1522 const enumerators = try gpa.alloc(*llvm.DIEnumerator, enum_type.names.len);
15221523 defer gpa.free(enumerators);
15231524
1524 var buf_field_index: Value.Payload.U32 = .{
1525 .base = .{ .tag = .enum_field_index },
1526 .data = undefined,
1527 };
1528 const field_index_val = Value.initPayload(&buf_field_index.base);
1529
1530 const int_ty = try ty.intTagType(mod);
1525 const int_ty = enum_type.tag_ty.toType();
15311526 const int_info = ty.intInfo(mod);
15321527 assert(int_info.bits != 0);
15331528
1534 for (field_names, 0..) |field_name, i| {
1535 const field_name_z = try gpa.dupeZ(u8, field_name);
1536 defer gpa.free(field_name_z);
1529 for (enum_type.names, 0..) |field_name_ip, i| {
1530 const field_name_z = ip.stringToSlice(field_name_ip);
15371531
1538 buf_field_index.data = @intCast(u32, i);
1539 const field_int_val = try field_index_val.enumToInt(ty, mod);
1540
1541 var bigint_space: Value.BigIntSpace = undefined;
1542 const bigint = field_int_val.toBigInt(&bigint_space, mod);
1532 var bigint_space: InternPool.Key.Int.Storage.BigIntSpace = undefined;
1533 const storage = if (enum_type.values.len != 0)
1534 ip.indexToKey(enum_type.values[i]).int.storage
1535 else
1536 InternPool.Key.Int.Storage{ .u64 = i };
1537 const bigint = storage.toBigInt(&bigint_space);
15431538
15441539 if (bigint.limbs.len == 1) {
15451540 enumerators[i] = dib.createEnumerator(field_name_z, bigint.limbs[0], int_info.signedness == .unsigned);
......@@ -8852,23 +8847,22 @@ pub const FuncGen = struct {
88528847
88538848 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {
88548849 const mod = self.dg.module;
8855 const enum_decl = enum_ty.getOwnerDecl(mod);
8850 const enum_type = mod.intern_pool.indexToKey(enum_ty.ip_index).enum_type;
88568851
88578852 // TODO: detect when the type changes and re-emit this function.
8858 const gop = try self.dg.object.named_enum_map.getOrPut(self.dg.gpa, enum_decl);
8853 const gop = try self.dg.object.named_enum_map.getOrPut(self.dg.gpa, enum_type.decl);
88598854 if (gop.found_existing) return gop.value_ptr.*;
8860 errdefer assert(self.dg.object.named_enum_map.remove(enum_decl));
8855 errdefer assert(self.dg.object.named_enum_map.remove(enum_type.decl));
88618856
88628857 var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);
88638858 defer arena_allocator.deinit();
88648859 const arena = arena_allocator.allocator();
88658860
8866 const fqn = try mod.declPtr(enum_decl).getFullyQualifiedName(mod);
8861 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
88678862 defer self.gpa.free(fqn);
88688863 const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_is_named_enum_value_{s}", .{fqn});
88698864
8870 const int_tag_ty = try enum_ty.intTagType(mod);
8871 const param_types = [_]*llvm.Type{try self.dg.lowerType(int_tag_ty)};
8865 const param_types = [_]*llvm.Type{try self.dg.lowerType(enum_type.tag_ty.toType())};
88728866
88738867 const llvm_ret_ty = try self.dg.lowerType(Type.bool);
88748868 const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);
......@@ -8891,13 +8885,12 @@ pub const FuncGen = struct {
88918885 self.builder.positionBuilderAtEnd(entry_block);
88928886 self.builder.clearCurrentDebugLocation();
88938887
8894 const fields = enum_ty.enumFields();
88958888 const named_block = self.context.appendBasicBlock(fn_val, "Named");
88968889 const unnamed_block = self.context.appendBasicBlock(fn_val, "Unnamed");
88978890 const tag_int_value = fn_val.getParam(0);
8898 const switch_instr = self.builder.buildSwitch(tag_int_value, unnamed_block, @intCast(c_uint, fields.count()));
8891 const switch_instr = self.builder.buildSwitch(tag_int_value, unnamed_block, @intCast(c_uint, enum_type.names.len));
88998892
8900 for (fields.keys(), 0..) |_, field_index| {
8893 for (enum_type.names, 0..) |_, field_index| {
89018894 const this_tag_int_value = int: {
89028895 var tag_val_payload: Value.Payload.U32 = .{
89038896 .base = .{ .tag = .enum_field_index },
......@@ -8930,18 +8923,18 @@ pub const FuncGen = struct {
89308923
89318924 fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {
89328925 const mod = self.dg.module;
8933 const enum_decl = enum_ty.getOwnerDecl(mod);
8926 const enum_type = mod.intern_pool.indexToKey(enum_ty.ip_index).enum_type;
89348927
89358928 // TODO: detect when the type changes and re-emit this function.
8936 const gop = try self.dg.object.decl_map.getOrPut(self.dg.gpa, enum_decl);
8929 const gop = try self.dg.object.decl_map.getOrPut(self.dg.gpa, enum_type.decl);
89378930 if (gop.found_existing) return gop.value_ptr.*;
8938 errdefer assert(self.dg.object.decl_map.remove(enum_decl));
8931 errdefer assert(self.dg.object.decl_map.remove(enum_type.decl));
89398932
89408933 var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);
89418934 defer arena_allocator.deinit();
89428935 const arena = arena_allocator.allocator();
89438936
8944 const fqn = try mod.declPtr(enum_decl).getFullyQualifiedName(mod);
8937 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
89458938 defer self.gpa.free(fqn);
89468939 const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn});
89478940
......@@ -8950,8 +8943,7 @@ pub const FuncGen = struct {
89508943 const usize_llvm_ty = try self.dg.lowerType(Type.usize);
89518944 const slice_alignment = slice_ty.abiAlignment(mod);
89528945
8953 const int_tag_ty = try enum_ty.intTagType(mod);
8954 const param_types = [_]*llvm.Type{try self.dg.lowerType(int_tag_ty)};
8946 const param_types = [_]*llvm.Type{try self.dg.lowerType(enum_type.tag_ty.toType())};
89558947
89568948 const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);
89578949 const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
......@@ -8973,16 +8965,16 @@ pub const FuncGen = struct {
89738965 self.builder.positionBuilderAtEnd(entry_block);
89748966 self.builder.clearCurrentDebugLocation();
89758967
8976 const fields = enum_ty.enumFields();
89778968 const bad_value_block = self.context.appendBasicBlock(fn_val, "BadValue");
89788969 const tag_int_value = fn_val.getParam(0);
8979 const switch_instr = self.builder.buildSwitch(tag_int_value, bad_value_block, @intCast(c_uint, fields.count()));
8970 const switch_instr = self.builder.buildSwitch(tag_int_value, bad_value_block, @intCast(c_uint, enum_type.names.len));
89808971
89818972 const array_ptr_indices = [_]*llvm.Value{
89828973 usize_llvm_ty.constNull(), usize_llvm_ty.constNull(),
89838974 };
89848975
8985 for (fields.keys(), 0..) |name, field_index| {
8976 for (enum_type.names, 0..) |name_ip, field_index| {
8977 const name = mod.intern_pool.stringToSlice(name_ip);
89868978 const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False);
89878979 const str_init_llvm_ty = str_init.typeOf();
89888980 const str_global = self.dg.object.llvm_module.addGlobal(str_init_llvm_ty, "");
......@@ -9429,7 +9421,7 @@ pub const FuncGen = struct {
94299421 const tag_int = blk: {
94309422 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
94319423 const union_field_name = union_obj.fields.keys()[extra.field_index];
9432 const enum_field_index = tag_ty.enumFieldIndex(union_field_name).?;
9424 const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;
94339425 var tag_val_payload: Value.Payload.U32 = .{
94349426 .base = .{ .tag = .enum_field_index },
94359427 .data = @intCast(u32, enum_field_index),
src/link/Dwarf.zig+8-13
......@@ -401,14 +401,9 @@ pub const DeclState = struct {
401401 dbg_info_buffer.appendSliceAssumeCapacity(enum_name);
402402 dbg_info_buffer.appendAssumeCapacity(0);
403403
404 const fields = ty.enumFields();
405 const values: ?Module.EnumFull.ValueMap = switch (ty.tag()) {
406 .enum_full, .enum_nonexhaustive => ty.cast(Type.Payload.EnumFull).?.data.values,
407 .enum_simple => null,
408 .enum_numbered => ty.castTag(.enum_numbered).?.data.values,
409 else => unreachable,
410 };
411 for (fields.keys(), 0..) |field_name, field_i| {
404 const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
405 for (enum_type.names, 0..) |field_name_index, field_i| {
406 const field_name = mod.intern_pool.stringToSlice(field_name_index);
412407 // DW.AT.enumerator
413408 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64));
414409 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.enum_variant));
......@@ -416,14 +411,14 @@ pub const DeclState = struct {
416411 dbg_info_buffer.appendSliceAssumeCapacity(field_name);
417412 dbg_info_buffer.appendAssumeCapacity(0);
418413 // DW.AT.const_value, DW.FORM.data8
419 const value: u64 = if (values) |vals| value: {
420 if (vals.count() == 0) break :value @intCast(u64, field_i); // auto-numbered
421 const value = vals.keys()[field_i];
414 const value: u64 = value: {
415 if (enum_type.values.len == 0) break :value field_i; // auto-numbered
416 const value = enum_type.values[field_i];
422417 // TODO do not assume a 64bit enum value - could be bigger.
423418 // See https://github.com/ziglang/zig/issues/645
424 const field_int_val = try value.enumToInt(ty, mod);
419 const field_int_val = try value.toValue().enumToInt(ty, mod);
425420 break :value @bitCast(u64, field_int_val.toSignedInt(mod));
426 } else @intCast(u64, field_i);
421 };
427422 mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian);
428423 }
429424
src/type.zig+89-313
......@@ -62,12 +62,6 @@ pub const Type = struct {
6262 .tuple,
6363 .anon_struct,
6464 => return .Struct,
65
66 .enum_full,
67 .enum_nonexhaustive,
68 .enum_simple,
69 .enum_numbered,
70 => return .Enum,
7165 },
7266 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
7367 .int_type => return .Int,
......@@ -566,22 +560,6 @@ pub const Type = struct {
566560
567561 return true;
568562 },
569
570 .enum_full, .enum_nonexhaustive => {
571 const a_enum_obj = a.cast(Payload.EnumFull).?.data;
572 const b_enum_obj = (b.cast(Payload.EnumFull) orelse return false).data;
573 return a_enum_obj == b_enum_obj;
574 },
575 .enum_simple => {
576 const a_enum_obj = a.cast(Payload.EnumSimple).?.data;
577 const b_enum_obj = (b.cast(Payload.EnumSimple) orelse return false).data;
578 return a_enum_obj == b_enum_obj;
579 },
580 .enum_numbered => {
581 const a_enum_obj = a.cast(Payload.EnumNumbered).?.data;
582 const b_enum_obj = (b.cast(Payload.EnumNumbered) orelse return false).data;
583 return a_enum_obj == b_enum_obj;
584 },
585563 }
586564 }
587565
......@@ -727,22 +705,6 @@ pub const Type = struct {
727705 field_val.hash(field_ty, hasher, mod);
728706 }
729707 },
730
731 .enum_full, .enum_nonexhaustive => {
732 const enum_obj: *const Module.EnumFull = ty.cast(Payload.EnumFull).?.data;
733 std.hash.autoHash(hasher, std.builtin.TypeId.Enum);
734 std.hash.autoHash(hasher, enum_obj);
735 },
736 .enum_simple => {
737 const enum_obj: *const Module.EnumSimple = ty.cast(Payload.EnumSimple).?.data;
738 std.hash.autoHash(hasher, std.builtin.TypeId.Enum);
739 std.hash.autoHash(hasher, enum_obj);
740 },
741 .enum_numbered => {
742 const enum_obj: *const Module.EnumNumbered = ty.cast(Payload.EnumNumbered).?.data;
743 std.hash.autoHash(hasher, std.builtin.TypeId.Enum);
744 std.hash.autoHash(hasher, enum_obj);
745 },
746708 }
747709 }
748710
......@@ -920,9 +882,6 @@ pub const Type = struct {
920882 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
921883 .error_set_inferred => return self.copyPayloadShallow(allocator, Payload.ErrorSetInferred),
922884 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
923 .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple),
924 .enum_numbered => return self.copyPayloadShallow(allocator, Payload.EnumNumbered),
925 .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull),
926885 }
927886 }
928887
......@@ -995,25 +954,6 @@ pub const Type = struct {
995954 while (true) {
996955 const t = ty.tag();
997956 switch (t) {
998 .enum_full, .enum_nonexhaustive => {
999 const enum_full = ty.cast(Payload.EnumFull).?.data;
1000 return writer.print("({s} decl={d})", .{
1001 @tagName(t), enum_full.owner_decl,
1002 });
1003 },
1004 .enum_simple => {
1005 const enum_simple = ty.castTag(.enum_simple).?.data;
1006 return writer.print("({s} decl={d})", .{
1007 @tagName(t), enum_simple.owner_decl,
1008 });
1009 },
1010 .enum_numbered => {
1011 const enum_numbered = ty.castTag(.enum_numbered).?.data;
1012 return writer.print("({s} decl={d})", .{
1013 @tagName(t), enum_numbered.owner_decl,
1014 });
1015 },
1016
1017957 .function => {
1018958 const payload = ty.castTag(.function).?.data;
1019959 try writer.writeAll("fn(");
......@@ -1199,22 +1139,6 @@ pub const Type = struct {
11991139 .inferred_alloc_const => unreachable,
12001140 .inferred_alloc_mut => unreachable,
12011141
1202 .enum_full, .enum_nonexhaustive => {
1203 const enum_full = ty.cast(Payload.EnumFull).?.data;
1204 const decl = mod.declPtr(enum_full.owner_decl);
1205 try decl.renderFullyQualifiedName(mod, writer);
1206 },
1207 .enum_simple => {
1208 const enum_simple = ty.castTag(.enum_simple).?.data;
1209 const decl = mod.declPtr(enum_simple.owner_decl);
1210 try decl.renderFullyQualifiedName(mod, writer);
1211 },
1212 .enum_numbered => {
1213 const enum_numbered = ty.castTag(.enum_numbered).?.data;
1214 const decl = mod.declPtr(enum_numbered.owner_decl);
1215 try decl.renderFullyQualifiedName(mod, writer);
1216 },
1217
12181142 .error_set_inferred => {
12191143 const func = ty.castTag(.error_set_inferred).?.data.func;
12201144
......@@ -1500,7 +1424,10 @@ pub const Type = struct {
15001424 const decl = mod.declPtr(opaque_type.decl);
15011425 try decl.renderFullyQualifiedName(mod, writer);
15021426 },
1503 .enum_type => @panic("TODO"),
1427 .enum_type => |enum_type| {
1428 const decl = mod.declPtr(enum_type.decl);
1429 try decl.renderFullyQualifiedName(mod, writer);
1430 },
15041431
15051432 // values, not types
15061433 .un => unreachable,
......@@ -1593,19 +1520,6 @@ pub const Type = struct {
15931520 }
15941521 },
15951522
1596 .enum_full => {
1597 const enum_full = ty.castTag(.enum_full).?.data;
1598 return enum_full.tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat);
1599 },
1600 .enum_simple => {
1601 const enum_simple = ty.castTag(.enum_simple).?.data;
1602 return enum_simple.fields.count() >= 2;
1603 },
1604 .enum_numbered, .enum_nonexhaustive => {
1605 const int_tag_ty = try ty.intTagType(mod);
1606 return int_tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat);
1607 },
1608
16091523 .array => return ty.arrayLen(mod) != 0 and
16101524 try ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
16111525 .array_sentinel => return ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
......@@ -1766,7 +1680,7 @@ pub const Type = struct {
17661680 },
17671681
17681682 .opaque_type => true,
1769 .enum_type => @panic("TODO"),
1683 .enum_type => |enum_type| enum_type.tag_ty.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
17701684
17711685 // values, not types
17721686 .un => unreachable,
......@@ -1789,9 +1703,7 @@ pub const Type = struct {
17891703 .empty_struct_type => false,
17901704
17911705 .none => switch (ty.tag()) {
1792 .pointer,
1793 .enum_numbered,
1794 => true,
1706 .pointer => true,
17951707
17961708 .error_set,
17971709 .error_set_single,
......@@ -1799,17 +1711,12 @@ pub const Type = struct {
17991711 .error_set_merged,
18001712 // These are function bodies, not function pointers.
18011713 .function,
1802 .enum_simple,
18031714 .error_union,
18041715 .anyframe_T,
18051716 .tuple,
18061717 .anon_struct,
18071718 => false,
18081719
1809 .enum_full,
1810 .enum_nonexhaustive,
1811 => !ty.cast(Payload.EnumFull).?.data.tag_ty_inferred,
1812
18131720 .inferred_alloc_mut => unreachable,
18141721 .inferred_alloc_const => unreachable,
18151722
......@@ -1886,7 +1793,10 @@ pub const Type = struct {
18861793 .tagged => false,
18871794 },
18881795 .opaque_type => false,
1889 .enum_type => @panic("TODO"),
1796 .enum_type => |enum_type| switch (enum_type.tag_mode) {
1797 .auto => false,
1798 .explicit, .nonexhaustive => true,
1799 },
18901800
18911801 // values, not types
18921802 .un => unreachable,
......@@ -2116,11 +2026,6 @@ pub const Type = struct {
21162026 return AbiAlignmentAdvanced{ .scalar = big_align };
21172027 },
21182028
2119 .enum_full, .enum_nonexhaustive, .enum_simple, .enum_numbered => {
2120 const int_tag_ty = try ty.intTagType(mod);
2121 return AbiAlignmentAdvanced{ .scalar = int_tag_ty.abiAlignment(mod) };
2122 },
2123
21242029 .inferred_alloc_const,
21252030 .inferred_alloc_mut,
21262031 => unreachable,
......@@ -2283,7 +2188,7 @@ pub const Type = struct {
22832188 return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());
22842189 },
22852190 .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },
2286 .enum_type => @panic("TODO"),
2191 .enum_type => |enum_type| return AbiAlignmentAdvanced{ .scalar = enum_type.tag_ty.toType().abiAlignment(mod) },
22872192
22882193 // values, not types
22892194 .un => unreachable,
......@@ -2475,11 +2380,6 @@ pub const Type = struct {
24752380 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };
24762381 },
24772382
2478 .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => {
2479 const int_tag_ty = try ty.intTagType(mod);
2480 return AbiSizeAdvanced{ .scalar = int_tag_ty.abiSize(mod) };
2481 },
2482
24832383 .array => {
24842384 const payload = ty.castTag(.array).?.data;
24852385 switch (try payload.elem_type.abiSizeAdvanced(mod, strat)) {
......@@ -2705,7 +2605,7 @@ pub const Type = struct {
27052605 return abiSizeAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());
27062606 },
27072607 .opaque_type => unreachable, // no size available
2708 .enum_type => @panic("TODO"),
2608 .enum_type => |enum_type| return AbiSizeAdvanced{ .scalar = enum_type.tag_ty.toType().abiSize(mod) },
27092609
27102610 // values, not types
27112611 .un => unreachable,
......@@ -2823,11 +2723,6 @@ pub const Type = struct {
28232723 return total;
28242724 },
28252725
2826 .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => {
2827 const int_tag_ty = try ty.intTagType(mod);
2828 return try bitSizeAdvanced(int_tag_ty, mod, opt_sema);
2829 },
2830
28312726 .array => {
28322727 const payload = ty.castTag(.array).?.data;
28332728 const elem_size = std.math.max(payload.elem_type.abiAlignment(mod), payload.elem_type.abiSize(mod));
......@@ -2964,7 +2859,7 @@ pub const Type = struct {
29642859 return size;
29652860 },
29662861 .opaque_type => unreachable,
2967 .enum_type => @panic("TODO"),
2862 .enum_type => |enum_type| return bitSizeAdvanced(enum_type.tag_ty.toType(), mod, opt_sema),
29682863
29692864 // values, not types
29702865 .un => unreachable,
......@@ -3433,7 +3328,7 @@ pub const Type = struct {
34333328 pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?usize {
34343329 const union_obj = mod.typeToUnion(ty).?;
34353330 const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, mod) orelse return null;
3436 const name = union_obj.tag_ty.enumFieldName(index);
3331 const name = union_obj.tag_ty.enumFieldName(index, mod);
34373332 return union_obj.fields.getIndex(name);
34383333 }
34393334
......@@ -3690,15 +3585,6 @@ pub const Type = struct {
36903585
36913586 while (true) switch (ty.ip_index) {
36923587 .none => switch (ty.tag()) {
3693 .enum_full, .enum_nonexhaustive => ty = ty.cast(Payload.EnumFull).?.data.tag_ty,
3694 .enum_numbered => ty = ty.castTag(.enum_numbered).?.data.tag_ty,
3695 .enum_simple => {
3696 const enum_obj = ty.castTag(.enum_simple).?.data;
3697 const field_count = enum_obj.fields.count();
3698 if (field_count == 0) return .{ .signedness = .unsigned, .bits = 0 };
3699 return .{ .signedness = .unsigned, .bits = smallestUnsignedBits(field_count - 1) };
3700 },
3701
37023588 .error_set, .error_set_single, .error_set_inferred, .error_set_merged => {
37033589 // TODO revisit this when error sets support custom int types
37043590 return .{ .signedness = .unsigned, .bits = 16 };
......@@ -3728,7 +3614,7 @@ pub const Type = struct {
37283614 assert(struct_obj.layout == .Packed);
37293615 ty = struct_obj.backing_int_ty;
37303616 },
3731 .enum_type => @panic("TODO"),
3617 .enum_type => |enum_type| ty = enum_type.tag_ty.toType(),
37323618
37333619 .ptr_type => unreachable,
37343620 .array_type => unreachable,
......@@ -3964,47 +3850,6 @@ pub const Type = struct {
39643850 return Value.empty_struct;
39653851 },
39663852
3967 .enum_numbered => {
3968 const enum_numbered = ty.castTag(.enum_numbered).?.data;
3969 // An explicit tag type is always provided for enum_numbered.
3970 if (enum_numbered.tag_ty.hasRuntimeBits(mod)) {
3971 return null;
3972 }
3973 assert(enum_numbered.fields.count() == 1);
3974 return enum_numbered.values.keys()[0];
3975 },
3976 .enum_full => {
3977 const enum_full = ty.castTag(.enum_full).?.data;
3978 if (enum_full.tag_ty.hasRuntimeBits(mod)) {
3979 return null;
3980 }
3981 switch (enum_full.fields.count()) {
3982 0 => return Value.@"unreachable",
3983 1 => if (enum_full.values.count() == 0) {
3984 return Value.enum_field_0; // auto-numbered
3985 } else {
3986 return enum_full.values.keys()[0];
3987 },
3988 else => return null,
3989 }
3990 },
3991 .enum_simple => {
3992 const enum_simple = ty.castTag(.enum_simple).?.data;
3993 switch (enum_simple.fields.count()) {
3994 0 => return Value.@"unreachable",
3995 1 => return Value.enum_field_0,
3996 else => return null,
3997 }
3998 },
3999 .enum_nonexhaustive => {
4000 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
4001 if (!tag_ty.hasRuntimeBits(mod)) {
4002 return Value.enum_field_0;
4003 } else {
4004 return null;
4005 }
4006 },
4007
40083853 .array => {
40093854 if (ty.arrayLen(mod) == 0)
40103855 return Value.initTag(.empty_array);
......@@ -4123,7 +3968,28 @@ pub const Type = struct {
41233968 return only.toValue();
41243969 },
41253970 .opaque_type => return null,
4126 .enum_type => @panic("TODO"),
3971 .enum_type => |enum_type| switch (enum_type.tag_mode) {
3972 .nonexhaustive => {
3973 if (enum_type.tag_ty != .comptime_int_type and
3974 !enum_type.tag_ty.toType().hasRuntimeBits(mod))
3975 {
3976 return Value.enum_field_0;
3977 } else {
3978 return null;
3979 }
3980 },
3981 .auto, .explicit => switch (enum_type.names.len) {
3982 0 => return Value.@"unreachable",
3983 1 => {
3984 if (enum_type.values.len == 0) {
3985 return Value.enum_field_0; // auto-numbered
3986 } else {
3987 return enum_type.values[0].toValue();
3988 }
3989 },
3990 else => return null,
3991 },
3992 },
41273993
41283994 // values, not types
41293995 .un => unreachable,
......@@ -4151,7 +4017,6 @@ pub const Type = struct {
41514017 .error_set_single,
41524018 .error_set_inferred,
41534019 .error_set_merged,
4154 .enum_simple,
41554020 => false,
41564021
41574022 // These are function bodies, not function pointers.
......@@ -4191,14 +4056,6 @@ pub const Type = struct {
41914056 const child_ty = ty.castTag(.anyframe_T).?.data;
41924057 return child_ty.comptimeOnly(mod);
41934058 },
4194 .enum_numbered => {
4195 const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty;
4196 return tag_ty.comptimeOnly(mod);
4197 },
4198 .enum_full, .enum_nonexhaustive => {
4199 const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty;
4200 return tag_ty.comptimeOnly(mod);
4201 },
42024059 },
42034060 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
42044061 .int_type => false,
......@@ -4293,7 +4150,7 @@ pub const Type = struct {
42934150
42944151 .opaque_type => false,
42954152
4296 .enum_type => @panic("TODO"),
4153 .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod),
42974154
42984155 // values, not types
42994156 .un => unreachable,
......@@ -4346,19 +4203,14 @@ pub const Type = struct {
43464203
43474204 /// Returns null if the type has no namespace.
43484205 pub fn getNamespaceIndex(ty: Type, mod: *Module) Module.Namespace.OptionalIndex {
4349 return switch (ty.ip_index) {
4350 .none => switch (ty.tag()) {
4351 .enum_full => ty.castTag(.enum_full).?.data.namespace.toOptional(),
4352 .enum_nonexhaustive => ty.castTag(.enum_nonexhaustive).?.data.namespace.toOptional(),
4353 else => .none,
4354 },
4355 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
4356 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
4357 .struct_type => |struct_type| struct_type.namespace,
4358 .union_type => |union_type| mod.unionPtr(union_type.index).namespace.toOptional(),
4206 if (ty.ip_index == .none) return .none;
4207 return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
4208 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
4209 .struct_type => |struct_type| struct_type.namespace,
4210 .union_type => |union_type| mod.unionPtr(union_type.index).namespace.toOptional(),
4211 .enum_type => |enum_type| enum_type.namespace,
43594212
4360 else => .none,
4361 },
4213 else => .none,
43624214 };
43634215 }
43644216
......@@ -4444,29 +4296,23 @@ pub const Type = struct {
44444296
44454297 /// Asserts the type is an enum or a union.
44464298 pub fn intTagType(ty: Type, mod: *Module) !Type {
4447 return switch (ty.ip_index) {
4448 .none => switch (ty.tag()) {
4449 .enum_full, .enum_nonexhaustive => ty.cast(Payload.EnumFull).?.data.tag_ty,
4450 .enum_numbered => ty.castTag(.enum_numbered).?.data.tag_ty,
4451 .enum_simple => {
4452 const enum_simple = ty.castTag(.enum_simple).?.data;
4453 const field_count = enum_simple.fields.count();
4454 const bits: u16 = if (field_count == 0) 0 else std.math.log2_int_ceil(usize, field_count);
4455 return mod.intType(.unsigned, bits);
4456 },
4457 else => unreachable,
4458 },
4459 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
4460 .union_type => |union_type| mod.unionPtr(union_type.index).tag_ty.intTagType(mod),
4461 else => unreachable,
4462 },
4299 return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
4300 .union_type => |union_type| mod.unionPtr(union_type.index).tag_ty.intTagType(mod),
4301 .enum_type => |enum_type| enum_type.tag_ty.toType(),
4302 else => unreachable,
44634303 };
44644304 }
44654305
4466 pub fn isNonexhaustiveEnum(ty: Type) bool {
4467 return switch (ty.tag()) {
4468 .enum_nonexhaustive => true,
4469 else => false,
4306 pub fn isNonexhaustiveEnum(ty: Type, mod: *Module) bool {
4307 return switch (ty.ip_index) {
4308 .none => false,
4309 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
4310 .enum_type => |enum_type| switch (enum_type.tag_mode) {
4311 .nonexhaustive => true,
4312 .auto, .explicit => false,
4313 },
4314 else => false,
4315 },
44704316 };
44714317 }
44724318
......@@ -4510,25 +4356,26 @@ pub const Type = struct {
45104356 return try Tag.error_set_merged.create(arena, names);
45114357 }
45124358
4513 pub fn enumFields(ty: Type) Module.EnumFull.NameMap {
4514 return switch (ty.tag()) {
4515 .enum_full, .enum_nonexhaustive => ty.cast(Payload.EnumFull).?.data.fields,
4516 .enum_simple => ty.castTag(.enum_simple).?.data.fields,
4517 .enum_numbered => ty.castTag(.enum_numbered).?.data.fields,
4518 else => unreachable,
4519 };
4359 pub fn enumFields(ty: Type, mod: *Module) []const InternPool.NullTerminatedString {
4360 return mod.intern_pool.indexToKey(ty.ip_index).enum_type.names;
45204361 }
45214362
4522 pub fn enumFieldCount(ty: Type) usize {
4523 return ty.enumFields().count();
4363 pub fn enumFieldCount(ty: Type, mod: *Module) usize {
4364 return mod.intern_pool.indexToKey(ty.ip_index).enum_type.names.len;
45244365 }
45254366
4526 pub fn enumFieldName(ty: Type, field_index: usize) []const u8 {
4527 return ty.enumFields().keys()[field_index];
4367 pub fn enumFieldName(ty: Type, field_index: usize, mod: *Module) [:0]const u8 {
4368 const ip = &mod.intern_pool;
4369 const field_name = ip.indexToKey(ty.ip_index).enum_type.names[field_index];
4370 return ip.stringToSlice(field_name);
45284371 }
45294372
4530 pub fn enumFieldIndex(ty: Type, field_name: []const u8) ?usize {
4531 return ty.enumFields().getIndex(field_name);
4373 pub fn enumFieldIndex(ty: Type, field_name: []const u8, mod: *Module) ?usize {
4374 const ip = &mod.intern_pool;
4375 const enum_type = ip.indexToKey(ty.ip_index).enum_type;
4376 // If the string is not interned, then the field certainly is not present.
4377 const field_name_interned = ip.getString(field_name).unwrap() orelse return null;
4378 return enum_type.nameIndex(ip.*, field_name_interned);
45324379 }
45334380
45344381 /// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or
......@@ -4538,50 +4385,20 @@ pub const Type = struct {
45384385 if (enum_tag.castTag(.enum_field_index)) |payload| {
45394386 return @as(usize, payload.data);
45404387 }
4541 const S = struct {
4542 fn fieldWithRange(int_ty: Type, int_val: Value, end: usize, m: *Module) ?usize {
4543 if (int_val.compareAllWithZero(.lt, m)) return null;
4544 const end_val = m.intValue(int_ty, end) catch |err| switch (err) {
4545 // TODO: eliminate this failure condition
4546 error.OutOfMemory => @panic("OOM"),
4547 };
4548 if (int_val.compareScalar(.gte, end_val, int_ty, m)) return null;
4549 return @intCast(usize, int_val.toUnsignedInt(m));
4550 }
4551 };
4552 switch (ty.tag()) {
4553 .enum_full, .enum_nonexhaustive => {
4554 const enum_full = ty.cast(Payload.EnumFull).?.data;
4555 const tag_ty = enum_full.tag_ty;
4556 if (enum_full.values.count() == 0) {
4557 return S.fieldWithRange(tag_ty, enum_tag, enum_full.fields.count(), mod);
4558 } else {
4559 return enum_full.values.getIndexContext(enum_tag, .{
4560 .ty = tag_ty,
4561 .mod = mod,
4562 });
4563 }
4564 },
4565 .enum_numbered => {
4566 const enum_obj = ty.castTag(.enum_numbered).?.data;
4567 const tag_ty = enum_obj.tag_ty;
4568 if (enum_obj.values.count() == 0) {
4569 return S.fieldWithRange(tag_ty, enum_tag, enum_obj.fields.count(), mod);
4570 } else {
4571 return enum_obj.values.getIndexContext(enum_tag, .{
4572 .ty = tag_ty,
4573 .mod = mod,
4574 });
4575 }
4576 },
4577 .enum_simple => {
4578 const enum_simple = ty.castTag(.enum_simple).?.data;
4579 const fields_len = enum_simple.fields.count();
4580 const bits = std.math.log2_int_ceil(usize, fields_len);
4581 const tag_ty = mod.intType(.unsigned, bits) catch @panic("TODO: handle OOM here");
4582 return S.fieldWithRange(tag_ty, enum_tag, fields_len, mod);
4583 },
4584 else => unreachable,
4388 const ip = &mod.intern_pool;
4389 const enum_type = ip.indexToKey(ty.ip_index).enum_type;
4390 const tag_ty = enum_type.tag_ty.toType();
4391 if (enum_type.values.len == 0) {
4392 if (enum_tag.compareAllWithZero(.lt, mod)) return null;
4393 const end_val = mod.intValue(tag_ty, enum_type.names.len) catch |err| switch (err) {
4394 // TODO: eliminate this failure condition
4395 error.OutOfMemory => @panic("OOM"),
4396 };
4397 if (enum_tag.compareScalar(.gte, end_val, tag_ty, mod)) return null;
4398 return @intCast(usize, enum_tag.toUnsignedInt(mod));
4399 } else {
4400 assert(ip.typeOf(enum_tag.ip_index) == enum_type.tag_ty);
4401 return enum_type.tagValueIndex(ip.*, enum_tag.ip_index);
45854402 }
45864403 }
45874404
......@@ -4905,18 +4722,6 @@ pub const Type = struct {
49054722 switch (ty.ip_index) {
49064723 .empty_struct_type => return null,
49074724 .none => switch (ty.tag()) {
4908 .enum_full, .enum_nonexhaustive => {
4909 const enum_full = ty.cast(Payload.EnumFull).?.data;
4910 return enum_full.srcLoc(mod);
4911 },
4912 .enum_numbered => {
4913 const enum_numbered = ty.castTag(.enum_numbered).?.data;
4914 return enum_numbered.srcLoc(mod);
4915 },
4916 .enum_simple => {
4917 const enum_simple = ty.castTag(.enum_simple).?.data;
4918 return enum_simple.srcLoc(mod);
4919 },
49204725 .error_set => {
49214726 const error_set = ty.castTag(.error_set).?.data;
49224727 return error_set.srcLoc(mod);
......@@ -4934,6 +4739,7 @@ pub const Type = struct {
49344739 return union_obj.srcLoc(mod);
49354740 },
49364741 .opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type),
4742 .enum_type => |enum_type| mod.declPtr(enum_type.decl).srcLoc(mod),
49374743 else => null,
49384744 },
49394745 }
......@@ -4946,15 +4752,6 @@ pub const Type = struct {
49464752 pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?Module.Decl.Index {
49474753 switch (ty.ip_index) {
49484754 .none => switch (ty.tag()) {
4949 .enum_full, .enum_nonexhaustive => {
4950 const enum_full = ty.cast(Payload.EnumFull).?.data;
4951 return enum_full.owner_decl;
4952 },
4953 .enum_numbered => return ty.castTag(.enum_numbered).?.data.owner_decl,
4954 .enum_simple => {
4955 const enum_simple = ty.castTag(.enum_simple).?.data;
4956 return enum_simple.owner_decl;
4957 },
49584755 .error_set => {
49594756 const error_set = ty.castTag(.error_set).?.data;
49604757 return error_set.owner_decl;
......@@ -4972,6 +4769,7 @@ pub const Type = struct {
49724769 return union_obj.owner_decl;
49734770 },
49744771 .opaque_type => |opaque_type| opaque_type.decl,
4772 .enum_type => |enum_type| enum_type.decl,
49754773 else => null,
49764774 },
49774775 }
......@@ -5012,10 +4810,6 @@ pub const Type = struct {
50124810 /// The type is the inferred error set of a specific function.
50134811 error_set_inferred,
50144812 error_set_merged,
5015 enum_simple,
5016 enum_numbered,
5017 enum_full,
5018 enum_nonexhaustive,
50194813
50204814 pub const last_no_payload_tag = Tag.inferred_alloc_const;
50214815 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
......@@ -5040,9 +4834,6 @@ pub const Type = struct {
50404834 .function => Payload.Function,
50414835 .error_union => Payload.ErrorUnion,
50424836 .error_set_single => Payload.Name,
5043 .enum_full, .enum_nonexhaustive => Payload.EnumFull,
5044 .enum_simple => Payload.EnumSimple,
5045 .enum_numbered => Payload.EnumNumbered,
50464837 .tuple => Payload.Tuple,
50474838 .anon_struct => Payload.AnonStruct,
50484839 };
......@@ -5341,21 +5132,6 @@ pub const Type = struct {
53415132 values: []Value,
53425133 };
53435134 };
5344
5345 pub const EnumFull = struct {
5346 base: Payload,
5347 data: *Module.EnumFull,
5348 };
5349
5350 pub const EnumSimple = struct {
5351 base: Payload = .{ .tag = .enum_simple },
5352 data: *Module.EnumSimple,
5353 };
5354
5355 pub const EnumNumbered = struct {
5356 base: Payload = .{ .tag = .enum_numbered },
5357 data: *Module.EnumNumbered,
5358 };
53595135 };
53605136
53615137 pub const @"u1": Type = .{ .ip_index = .u1_type, .legacy = undefined };
src/value.zig+16-46
......@@ -675,80 +675,50 @@ pub const Value = struct {
675675 const field_index = switch (val.tag()) {
676676 .enum_field_index => val.castTag(.enum_field_index).?.data,
677677 .the_only_possible_value => blk: {
678 assert(ty.enumFieldCount() == 1);
678 assert(ty.enumFieldCount(mod) == 1);
679679 break :blk 0;
680680 },
681681 .enum_literal => i: {
682682 const name = val.castTag(.enum_literal).?.data;
683 break :i ty.enumFieldIndex(name).?;
683 break :i ty.enumFieldIndex(name, mod).?;
684684 },
685685 // Assume it is already an integer and return it directly.
686686 else => return val,
687687 };
688688
689 switch (ty.tag()) {
690 .enum_full, .enum_nonexhaustive => {
691 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
692 if (enum_full.values.count() != 0) {
693 return enum_full.values.keys()[field_index];
694 } else {
695 // Field index and integer values are the same.
696 return mod.intValue(enum_full.tag_ty, field_index);
697 }
698 },
699 .enum_numbered => {
700 const enum_obj = ty.castTag(.enum_numbered).?.data;
701 if (enum_obj.values.count() != 0) {
702 return enum_obj.values.keys()[field_index];
703 } else {
704 // Field index and integer values are the same.
705 return mod.intValue(enum_obj.tag_ty, field_index);
706 }
707 },
708 .enum_simple => {
709 // Field index and integer values are the same.
710 const tag_ty = try ty.intTagType(mod);
711 return mod.intValue(tag_ty, field_index);
712 },
713 else => unreachable,
689 const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
690 if (enum_type.values.len != 0) {
691 return enum_type.values[field_index].toValue();
692 } else {
693 // Field index and integer values are the same.
694 return mod.intValue(enum_type.tag_ty.toType(), field_index);
714695 }
715696 }
716697
717698 pub fn tagName(val: Value, ty: Type, mod: *Module) []const u8 {
718699 if (ty.zigTypeTag(mod) == .Union) return val.unionTag().tagName(ty.unionTagTypeHypothetical(mod), mod);
719700
701 const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
702
720703 const field_index = switch (val.tag()) {
721704 .enum_field_index => val.castTag(.enum_field_index).?.data,
722705 .the_only_possible_value => blk: {
723 assert(ty.enumFieldCount() == 1);
706 assert(ty.enumFieldCount(mod) == 1);
724707 break :blk 0;
725708 },
726709 .enum_literal => return val.castTag(.enum_literal).?.data,
727710 else => field_index: {
728 const values = switch (ty.tag()) {
729 .enum_full, .enum_nonexhaustive => ty.cast(Type.Payload.EnumFull).?.data.values,
730 .enum_numbered => ty.castTag(.enum_numbered).?.data.values,
731 .enum_simple => Module.EnumFull.ValueMap{},
732 else => unreachable,
733 };
734 if (values.entries.len == 0) {
711 if (enum_type.values.len == 0) {
735712 // auto-numbered enum
736713 break :field_index @intCast(u32, val.toUnsignedInt(mod));
737714 }
738 const int_tag_ty = ty.intTagType(mod) catch |err| switch (err) {
739 error.OutOfMemory => @panic("OOM"), // TODO handle this failure
740 };
741 break :field_index @intCast(u32, values.getIndexContext(val, .{ .ty = int_tag_ty, .mod = mod }).?);
715 const field_index = enum_type.tagValueIndex(mod.intern_pool, val.ip_index).?;
716 break :field_index @intCast(u32, field_index);
742717 },
743718 };
744719
745 const fields = switch (ty.tag()) {
746 .enum_full, .enum_nonexhaustive => ty.cast(Type.Payload.EnumFull).?.data.fields,
747 .enum_numbered => ty.castTag(.enum_numbered).?.data.fields,
748 .enum_simple => ty.castTag(.enum_simple).?.data.fields,
749 else => unreachable,
750 };
751 return fields.keys()[field_index];
720 const field_name = enum_type.names[field_index];
721 return mod.intern_pool.stringToSlice(field_name);
752722 }
753723
754724 /// Asserts the value is an integer.