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 {...@@ -10694,8 +10694,8 @@ fn identAsString(astgen: *AstGen, ident_token: Ast.TokenIndex) !u32 {
10694 const string_bytes = &astgen.string_bytes;10694 const string_bytes = &astgen.string_bytes;
10695 const str_index = @intCast(u32, string_bytes.items.len);10695 const str_index = @intCast(u32, string_bytes.items.len);
10696 try astgen.appendIdentStr(ident_token, string_bytes);10696 try astgen.appendIdentStr(ident_token, string_bytes);
10697 const key = string_bytes.items[str_index..];10697 const key: []const u8 = string_bytes.items[str_index..];
10698 const gop = try astgen.string_table.getOrPutContextAdapted(gpa, @as([]const u8, key), StringIndexAdapter{10698 const gop = try astgen.string_table.getOrPutContextAdapted(gpa, key, StringIndexAdapter{
10699 .bytes = string_bytes,10699 .bytes = string_bytes,
10700 }, StringIndexContext{10700 }, StringIndexContext{
10701 .bytes = string_bytes,10701 .bytes = string_bytes,
src/InternPool.zig+394-71
...@@ -40,6 +40,14 @@ unions_free_list: std.ArrayListUnmanaged(Module.Union.Index) = .{},...@@ -40,6 +40,14 @@ unions_free_list: std.ArrayListUnmanaged(Module.Union.Index) = .{},
40/// to provide lookup.40/// to provide lookup.
41maps: std.ArrayListUnmanaged(std.AutoArrayHashMapUnmanaged(void, void)) = .{},41maps: 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
43const std = @import("std");51const std = @import("std");
44const Allocator = std.mem.Allocator;52const Allocator = std.mem.Allocator;
45const assert = std.debug.assert;53const assert = std.debug.assert;
...@@ -68,6 +76,11 @@ const KeyAdapter = struct {...@@ -68,6 +76,11 @@ const KeyAdapter = struct {
68pub const OptionalMapIndex = enum(u32) {76pub const OptionalMapIndex = enum(u32) {
69 none = std.math.maxInt(u32),77 none = std.math.maxInt(u32),
70 _,78 _,
79
80 pub fn unwrap(oi: OptionalMapIndex) ?MapIndex {
81 if (oi == .none) return null;
82 return @intToEnum(MapIndex, @enumToInt(oi));
83 }
71};84};
7285
73/// An index into `maps`.86/// An index into `maps`.
...@@ -83,6 +96,10 @@ pub const MapIndex = enum(u32) {...@@ -83,6 +96,10 @@ pub const MapIndex = enum(u32) {
83pub const NullTerminatedString = enum(u32) {96pub const NullTerminatedString = enum(u32) {
84 _,97 _,
8598
99 pub fn toOptional(self: NullTerminatedString) OptionalNullTerminatedString {
100 return @intToEnum(OptionalNullTerminatedString, @enumToInt(self));
101 }
102
86 const Adapter = struct {103 const Adapter = struct {
87 strings: []const NullTerminatedString,104 strings: []const NullTerminatedString,
88105
...@@ -102,6 +119,11 @@ pub const NullTerminatedString = enum(u32) {...@@ -102,6 +119,11 @@ pub const NullTerminatedString = enum(u32) {
102pub const OptionalNullTerminatedString = enum(u32) {119pub const OptionalNullTerminatedString = enum(u32) {
103 none = std.math.maxInt(u32),120 none = std.math.maxInt(u32),
104 _,121 _,
122
123 pub fn unwrap(oi: OptionalNullTerminatedString) ?NullTerminatedString {
124 if (oi == .none) return null;
125 return @intToEnum(NullTerminatedString, @enumToInt(oi));
126 }
105};127};
106128
107pub const Key = union(enum) {129pub const Key = union(enum) {
...@@ -242,13 +264,75 @@ pub const Key = union(enum) {...@@ -242,13 +264,75 @@ pub const Key = union(enum) {
242 /// Entries are in declaration order, same as `fields`.264 /// Entries are in declaration order, same as `fields`.
243 /// If this is empty, it means the enum tags are auto-numbered.265 /// If this is empty, it means the enum tags are auto-numbered.
244 values: []const Index,266 values: []const Index,
245 /// true if zig inferred this tag type, false if user specified it267 tag_mode: TagMode,
246 tag_ty_inferred: bool,
247 /// This is ignored by `get` but will always be provided by `indexToKey`.268 /// This is ignored by `get` but will always be provided by `indexToKey`.
248 names_map: OptionalMapIndex = .none,269 names_map: OptionalMapIndex = .none,
249 /// This is ignored by `get` but will be provided by `indexToKey` when270 /// This is ignored by `get` but will be provided by `indexToKey` when
250 /// a value map exists.271 /// a value map exists.
251 values_map: OptionalMapIndex = .none,272 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 }
252 };336 };
253337
254 pub const Int = struct {338 pub const Int = struct {
...@@ -946,12 +1030,18 @@ pub const Tag = enum(u8) {...@@ -946,12 +1030,18 @@ pub const Tag = enum(u8) {
946 /// An error union type.1030 /// An error union type.
947 /// data is payload to ErrorUnion.1031 /// data is payload to ErrorUnion.
948 type_error_union,1032 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,
952 /// An enum type with auto-numbered tag values.1033 /// An enum type with auto-numbered tag values.
1034 /// The enum is exhaustive.
953 /// data is payload index to `EnumAuto`.1035 /// data is payload index to `EnumAuto`.
954 type_enum_auto,1036 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,
955 /// A type that can be represented with only an enum tag.1045 /// A type that can be represented with only an enum tag.
956 /// data is SimpleType enum value.1046 /// data is SimpleType enum value.
957 simple_type,1047 simple_type,
...@@ -1302,9 +1392,11 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {...@@ -1302,9 +1392,11 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
1302 ip.unions_free_list.deinit(gpa);1392 ip.unions_free_list.deinit(gpa);
1303 ip.allocated_unions.deinit(gpa);1393 ip.allocated_unions.deinit(gpa);
13041394
1305 for (ip.maps) |*map| map.deinit(gpa);1395 for (ip.maps.items) |*map| map.deinit(gpa);
1306 ip.maps.deinit(gpa);1396 ip.maps.deinit(gpa);
13071397
1398 ip.string_table.deinit(gpa);
1399
1308 ip.* = undefined;1400 ip.* = undefined;
1309}1401}
13101402
...@@ -1421,33 +1513,13 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {...@@ -1421,33 +1513,13 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
1421 .tag_ty = ip.getEnumIntTagType(enum_auto.data.fields_len),1513 .tag_ty = ip.getEnumIntTagType(enum_auto.data.fields_len),
1422 .names = names,1514 .names = names,
1423 .values = &.{},1515 .values = &.{},
1424 .tag_ty_inferred = true,1516 .tag_mode = .auto,
1425 .names_map = enum_auto.data.names_map.toOptional(),1517 .names_map = enum_auto.data.names_map.toOptional(),
1426 .values_map = .none,1518 .values_map = .none,
1427 } };1519 } };
1428 },1520 },
1429 .type_enum_explicit => {1521 .type_enum_explicit => indexToKeyEnum(ip, data, .explicit),
1430 const enum_explicit = ip.extraDataTrail(EnumExplicit, data);1522 .type_enum_nonexhaustive => indexToKeyEnum(ip, data, .nonexhaustive),
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 },
14511523
1452 .opt_null => .{ .opt = .{1524 .opt_null => .{ .opt = .{
1453 .ty = @intToEnum(Index, data),1525 .ty = @intToEnum(Index, data),
...@@ -1531,6 +1603,29 @@ fn getEnumIntTagType(ip: InternPool, fields_len: u32) Index {...@@ -1531,6 +1603,29 @@ fn getEnumIntTagType(ip: InternPool, fields_len: u32) Index {
1531 } });1603 } });
1532}1604}
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
1534fn indexToKeyBigInt(ip: InternPool, limb_index: u32, positive: bool) Key {1629fn indexToKeyBigInt(ip: InternPool, limb_index: u32, positive: bool) Key {
1535 const int_info = ip.limbData(Int, limb_index);1630 const int_info = ip.limbData(Int, limb_index);
1536 return .{ .int = .{1631 return .{ .int = .{
...@@ -1696,47 +1791,29 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -1696,47 +1791,29 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
1696 assert(enum_type.names_map == .none);1791 assert(enum_type.names_map == .none);
1697 assert(enum_type.values_map == .none);1792 assert(enum_type.values_map == .none);
16981793
1699 const names_map = try ip.addMap(gpa);1794 switch (enum_type.tag_mode) {
1700 try addStringsToMap(ip, gpa, names_map, enum_type.names);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);1799 const fields_len = @intCast(u32, enum_type.names.len);
17031800 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
1704 if (enum_type.tag_ty_inferred) {1801 fields_len);
1705 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +1802 ip.items.appendAssumeCapacity(.{
1706 fields_len);1803 .tag = .type_enum_auto,
1707 ip.items.appendAssumeCapacity(.{1804 .data = ip.addExtraAssumeCapacity(EnumAuto{
1708 .tag = .type_enum_auto,1805 .decl = enum_type.decl,
1709 .data = ip.addExtraAssumeCapacity(EnumAuto{1806 .namespace = enum_type.namespace,
1710 .decl = enum_type.decl,1807 .names_map = names_map,
1711 .namespace = enum_type.namespace,1808 .fields_len = fields_len,
1712 .names_map = names_map,1809 }),
1713 .fields_len = fields_len,1810 });
1714 }),1811 ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, enum_type.names));
1715 });1812 return @intToEnum(Index, ip.items.len - 1);
1716 ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, enum_type.names));1813 },
1717 return @intToEnum(Index, ip.items.len - 1);1814 .explicit => return finishGetEnum(ip, gpa, enum_type, .type_enum_explicit),
1815 .nonexhaustive => return finishGetEnum(ip, gpa, enum_type, .type_enum_nonexhaustive),
1718 }1816 }
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));
1740 },1817 },
17411818
1742 .extern_func => @panic("TODO"),1819 .extern_func => @panic("TODO"),
...@@ -1934,8 +2011,206 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -1934,8 +2011,206 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
1934 return @intToEnum(Index, ip.items.len - 1);2011 return @intToEnum(Index, ip.items.len - 1);
1935}2012}
19362013
1937pub fn getAssumeExists(ip: InternPool, key: Key) Index {2014/// Provides API for completing an enum type after calling `getIncompleteEnum`.
1938 const adapter: KeyAdapter = .{ .intern_pool = &ip };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 };
1939 const index = ip.map.getIndexAdapted(key, adapter).?;2214 const index = ip.map.getIndexAdapted(key, adapter).?;
1940 return @intToEnum(Index, index);2215 return @intToEnum(Index, index);
1941}2216}
...@@ -1979,6 +2254,7 @@ fn addMap(ip: *InternPool, gpa: Allocator) Allocator.Error!MapIndex {...@@ -1979,6 +2254,7 @@ fn addMap(ip: *InternPool, gpa: Allocator) Allocator.Error!MapIndex {
1979pub fn remove(ip: *InternPool, index: Index) void {2254pub fn remove(ip: *InternPool, index: Index) void {
1980 _ = ip;2255 _ = ip;
1981 _ = index;2256 _ = index;
2257 @setCold(true);
1982 @panic("TODO this is a bit problematic to implement, could we maybe just never support a remove() operation on InternPool?");2258 @panic("TODO this is a bit problematic to implement, could we maybe just never support a remove() operation on InternPool?");
1983}2259}
19842260
...@@ -2336,7 +2612,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {...@@ -2336,7 +2612,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
2336 .type_slice => 0,2612 .type_slice => 0,
2337 .type_optional => 0,2613 .type_optional => 0,
2338 .type_error_union => @sizeOf(ErrorUnion),2614 .type_error_union => @sizeOf(ErrorUnion),
2339 .type_enum_explicit => @sizeOf(EnumExplicit),2615 .type_enum_explicit, .type_enum_nonexhaustive => @sizeOf(EnumExplicit),
2340 .type_enum_auto => @sizeOf(EnumAuto),2616 .type_enum_auto => @sizeOf(EnumAuto),
2341 .type_opaque => @sizeOf(Key.OpaqueType),2617 .type_opaque => @sizeOf(Key.OpaqueType),
2342 .type_struct => @sizeOf(Module.Struct) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl),2618 .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)...@@ -2448,3 +2724,50 @@ pub fn destroyUnion(ip: *InternPool, gpa: Allocator, index: Module.Union.Index)
2448 // allocation failures here, instead leaking the Union until garbage collection.2724 // allocation failures here, instead leaking the Union until garbage collection.
2449 };2725 };
2450}2726}
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 {...@@ -886,29 +886,17 @@ pub const Decl = struct {
886 /// Only returns it if the Decl is the owner.886 /// Only returns it if the Decl is the owner.
887 pub fn getInnerNamespaceIndex(decl: *Decl, mod: *Module) Namespace.OptionalIndex {887 pub fn getInnerNamespaceIndex(decl: *Decl, mod: *Module) Namespace.OptionalIndex {
888 if (!decl.owns_tv) return .none;888 if (!decl.owns_tv) return .none;
889 switch (decl.val.ip_index) {889 return switch (decl.val.ip_index) {
890 .empty_struct_type => return .none,890 .empty_struct_type => .none,
891 .none => {891 .none => .none,
892 const ty = (decl.val.castTag(.ty) orelse return .none).data;892 else => switch (mod.intern_pool.indexToKey(decl.val.ip_index)) {
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)) {
903 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),893 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
904 .struct_type => |struct_type| struct_type.namespace,894 .struct_type => |struct_type| struct_type.namespace,
905 .union_type => |union_type| {895 .union_type => |union_type| mod.unionPtr(union_type.index).namespace.toOptional(),
906 const union_obj = mod.unionPtr(union_type.index);896 .enum_type => |enum_type| enum_type.namespace,
907 return union_obj.namespace.toOptional();
908 },
909 else => .none,897 else => .none,
910 },898 },
911 }899 };
912 }900 }
913901
914 /// Same as `getInnerNamespaceIndex` but additionally obtains the pointer.902 /// Same as `getInnerNamespaceIndex` but additionally obtains the pointer.
...@@ -1135,28 +1123,6 @@ pub const Struct = struct {...@@ -1135,28 +1123,6 @@ pub const Struct = struct {
1135 return mod.declPtr(s.owner_decl).srcLoc(mod);1123 return mod.declPtr(s.owner_decl).srcLoc(mod);
1136 }1124 }
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
1160 pub fn haveFieldTypes(s: Struct) bool {1126 pub fn haveFieldTypes(s: Struct) bool {
1161 return switch (s.status) {1127 return switch (s.status) {
1162 .none,1128 .none,
...@@ -1237,110 +1203,6 @@ pub const Struct = struct {...@@ -1237,110 +1203,6 @@ pub const Struct = struct {
1237 }1203 }
1238};1204};
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
1344pub const Union = struct {1206pub const Union = struct {
1345 /// An enum type which is used for the tag of the union.1207 /// An enum type which is used for the tag of the union.
1346 /// This type is created even for untagged unions, even when the memory1208 /// This type is created even for untagged unions, even when the memory
...@@ -1427,28 +1289,6 @@ pub const Union = struct {...@@ -1427,28 +1289,6 @@ pub const Union = struct {
1427 };1289 };
1428 }1290 }
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
1452 pub fn haveFieldTypes(u: Union) bool {1292 pub fn haveFieldTypes(u: Union) bool {
1453 return switch (u.status) {1293 return switch (u.status) {
1454 .none,1294 .none,
...@@ -7313,3 +7153,24 @@ pub fn typeToUnion(mod: *Module, ty: Type) ?*Union {...@@ -7313,3 +7153,24 @@ pub fn typeToUnion(mod: *Module, ty: Type) ?*Union {
7313 const union_index = mod.intern_pool.indexToUnion(ty.ip_index).unwrap() orelse return null;7153 const union_index = mod.intern_pool.indexToUnion(ty.ip_index).unwrap() orelse return null;
7314 return mod.unionPtr(union_index);7154 return mod.unionPtr(union_index);
7315}7155}
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...@@ -2096,7 +2096,7 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS
2096 errdefer msg.destroy(sema.gpa);2096 errdefer msg.destroy(sema.gpa);
20972097
2098 const struct_ty = mod.typeToStruct(container_ty) orelse break :msg msg;2098 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, .{
2100 .index = field_index,2100 .index = field_index,
2101 .range = .value,2101 .range = .value,
2102 });2102 });
...@@ -2875,50 +2875,28 @@ fn zirEnumDecl(...@@ -2875,50 +2875,28 @@ fn zirEnumDecl(
2875 break :blk decls_len;2875 break :blk decls_len;
2876 } else 0;2876 } else 0;
28772877
2878 var done = false;2878 // Because these three things each reference each other, `undefined`
28792879 // placeholders are used before being set after the enum type gains an
2880 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);2880 // InternPool index.
2881 errdefer if (!done) new_decl_arena.deinit();
2882 const new_decl_arena_allocator = new_decl_arena.allocator();
28832881
2884 const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull);2882 var done = false;
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);
2892 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{2883 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
2893 .ty = Type.type,2884 .ty = Type.type,
2894 .val = enum_val,2885 .val = undefined,
2895 }, small.name_strategy, "enum", inst);2886 }, small.name_strategy, "enum", inst);
2896 const new_decl = mod.declPtr(new_decl_index);2887 const new_decl = mod.declPtr(new_decl_index);
2897 new_decl.owns_tv = true;2888 new_decl.owns_tv = true;
2898 errdefer if (!done) mod.abortAnonDecl(new_decl_index);2889 errdefer if (!done) mod.abortAnonDecl(new_decl_index);
28992890
2900 enum_obj.* = .{2891 const new_namespace_index = try mod.createNamespace(.{
2901 .owner_decl = new_decl_index,2892 .parent = block.namespace.toOptional(),
2902 .tag_ty = Type.null,2893 .ty = undefined,
2903 .tag_ty_inferred = true,2894 .file_scope = block.getFileScope(mod),
2904 .fields = .{},2895 });
2905 .values = .{},2896 const new_namespace = mod.namespacePtr(new_namespace_index);
2906 .namespace = try mod.createNamespace(.{2897 errdefer if (!done) mod.destroyNamespace(new_namespace_index);
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);
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
2923 const body = sema.code.extra[extra_index..][0..body_len];2901 const body = sema.code.extra[extra_index..][0..body_len];
2924 extra_index += body.len;2902 extra_index += body.len;
...@@ -2927,7 +2905,31 @@ fn zirEnumDecl(...@@ -2927,7 +2905,31 @@ fn zirEnumDecl(
2927 const body_end = extra_index;2905 const body_end = extra_index;
2928 extra_index += bit_bags_count;2906 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: {
2931 // We create a block for the field type instructions because they2933 // We create a block for the field type instructions because they
2932 // may need to reference Decls from inside the enum namespace.2934 // may need to reference Decls from inside the enum namespace.
2933 // Within the field type, default value, and alignment expressions, the "owner decl"2935 // Within the field type, default value, and alignment expressions, the "owner decl"
...@@ -2957,7 +2959,7 @@ fn zirEnumDecl(...@@ -2957,7 +2959,7 @@ fn zirEnumDecl(
2957 .parent = null,2959 .parent = null,
2958 .sema = sema,2960 .sema = sema,
2959 .src_decl = new_decl_index,2961 .src_decl = new_decl_index,
2960 .namespace = enum_obj.namespace,2962 .namespace = new_namespace_index,
2961 .wip_capture_scope = wip_captures.scope,2963 .wip_capture_scope = wip_captures.scope,
2962 .instructions = .{},2964 .instructions = .{},
2963 .inlining = null,2965 .inlining = null,
...@@ -2976,35 +2978,22 @@ fn zirEnumDecl(...@@ -2976,35 +2978,22 @@ fn zirEnumDecl(
2976 if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) {2978 if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) {
2977 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)});2979 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)});
2978 }2980 }
2979 enum_obj.tag_ty = try ty.copy(decl_arena_allocator);2981 incomplete_enum.setTagType(&mod.intern_pool, ty.ip_index);
2980 enum_obj.tag_ty_inferred = false;2982 break :ty ty;
2981 } else if (fields_len == 0) {2983 } else if (fields_len == 0) {
2982 enum_obj.tag_ty = try mod.intType(.unsigned, 0);2984 break :ty try mod.intType(.unsigned, 0);
2983 enum_obj.tag_ty_inferred = true;
2984 } else {2985 } else {
2985 const bits = std.math.log2_int_ceil(usize, fields_len);2986 const bits = std.math.log2_int_ceil(usize, fields_len);
2986 enum_obj.tag_ty = try mod.intType(.unsigned, bits);2987 break :ty try mod.intType(.unsigned, bits);
2987 enum_obj.tag_ty_inferred = true;
2988 }2988 }
2989 }2989 };
29902990
2991 if (small.nonexhaustive and enum_obj.tag_ty.zigTypeTag(mod) != .ComptimeInt) {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) == enum_obj.tag_ty.bitSize(mod)) {2992 if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(mod)) {
2993 return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});2993 return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
2994 }2994 }
2995 }2995 }
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
3008 var bit_bag_index: usize = body_end;2997 var bit_bag_index: usize = body_end;
3009 var cur_bit_bag: u32 = undefined;2998 var cur_bit_bag: u32 = undefined;
3010 var field_i: u32 = 0;2999 var field_i: u32 = 0;
...@@ -3023,15 +3012,12 @@ fn zirEnumDecl(...@@ -3023,15 +3012,12 @@ fn zirEnumDecl(
3023 // doc comment3012 // doc comment
3024 extra_index += 1;3013 extra_index += 1;
30253014
3026 // This string needs to outlive the ZIR code.3015 const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir);
3027 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);3016 if (try incomplete_enum.addFieldName(&mod.intern_pool, gpa, field_name)) |other_index| {
30283017 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
3029 const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name);3018 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
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;
3033 const msg = msg: {3019 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});
3035 errdefer msg.destroy(gpa);3021 errdefer msg.destroy(gpa);
3036 try sema.errNote(block, other_field_src, msg, "other field here", .{});3022 try sema.errNote(block, other_field_src, msg, "other field here", .{});
3037 break :msg msg;3023 break :msg msg;
...@@ -3045,7 +3031,7 @@ fn zirEnumDecl(...@@ -3045,7 +3031,7 @@ fn zirEnumDecl(
3045 const tag_inst = try sema.resolveInst(tag_val_ref);3031 const tag_inst = try sema.resolveInst(tag_val_ref);
3046 const tag_val = sema.resolveConstValue(block, .unneeded, tag_inst, "") catch |err| switch (err) {3032 const tag_val = sema.resolveConstValue(block, .unneeded, tag_inst, "") catch |err| switch (err) {
3047 error.NeededSourceLocation => {3033 error.NeededSourceLocation => {
3048 const value_src = enum_obj.fieldSrcLoc(sema.mod, .{3034 const value_src = mod.fieldSrcLoc(new_decl_index, .{
3049 .index = field_i,3035 .index = field_i,
3050 .range = .value,3036 .range = .value,
3051 }).lazy;3037 }).lazy;
...@@ -3055,19 +3041,14 @@ fn zirEnumDecl(...@@ -3055,19 +3041,14 @@ fn zirEnumDecl(
3055 else => |e| return e,3041 else => |e| return e,
3056 };3042 };
3057 last_tag_val = tag_val;3043 last_tag_val = tag_val;
3058 const copied_tag_val = try tag_val.copy(decl_arena_allocator);3044 if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, tag_val.ip_index)) |other_index| {
3059 const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{3045 const value_src = mod.fieldSrcLoc(new_decl_index, .{
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, .{
3065 .index = field_i,3046 .index = field_i,
3066 .range = .value,3047 .range = .value,
3067 }).lazy;3048 }).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;
3069 const msg = msg: {3050 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)});
3071 errdefer msg.destroy(gpa);3052 errdefer msg.destroy(gpa);
3072 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});3053 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
3073 break :msg msg;3054 break :msg msg;
...@@ -3076,20 +3057,15 @@ fn zirEnumDecl(...@@ -3076,20 +3057,15 @@ fn zirEnumDecl(
3076 }3057 }
3077 } else if (any_values) {3058 } else if (any_values) {
3078 const tag_val = if (last_tag_val) |val|3059 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)
3080 else3061 else
3081 try mod.intValue(enum_obj.tag_ty, 0);3062 try mod.intValue(int_tag_ty, 0);
3082 last_tag_val = tag_val;3063 last_tag_val = tag_val;
3083 const copied_tag_val = try tag_val.copy(decl_arena_allocator);3064 if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, tag_val.ip_index)) |other_index| {
3084 const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{3065 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
3085 .ty = enum_obj.tag_ty,3066 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
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;
3091 const msg = msg: {3067 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)});
3093 errdefer msg.destroy(gpa);3069 errdefer msg.destroy(gpa);
3094 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});3070 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
3095 break :msg msg;3071 break :msg msg;
...@@ -3097,16 +3073,16 @@ fn zirEnumDecl(...@@ -3097,16 +3073,16 @@ fn zirEnumDecl(
3097 return sema.failWithOwnedErrorMsg(msg);3073 return sema.failWithOwnedErrorMsg(msg);
3098 }3074 }
3099 } else {3075 } 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);
3101 }3077 }
31023078
3103 if (!(try sema.intFitsInType(last_tag_val.?, enum_obj.tag_ty, null))) {3079 if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) {
3104 const value_src = enum_obj.fieldSrcLoc(sema.mod, .{3080 const value_src = mod.fieldSrcLoc(new_decl_index, .{
3105 .index = field_i,3081 .index = field_i,
3106 .range = if (has_tag_value) .value else .name,3082 .range = if (has_tag_value) .value else .name,
3107 }).lazy;3083 }).lazy;
3108 const msg = try sema.errMsg(block, value_src, "enumeration value '{}' too large for type '{}'", .{3084 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),
3110 });3086 });
3111 return sema.failWithOwnedErrorMsg(msg);3087 return sema.failWithOwnedErrorMsg(msg);
3112 }3088 }
...@@ -4356,7 +4332,7 @@ fn validateUnionInit(...@@ -4356,7 +4332,7 @@ fn validateUnionInit(
4356 }4332 }
43574333
4358 const tag_ty = union_ty.unionTagTypeHypothetical(mod);4334 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).?);
4360 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);4336 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
43614337
4362 if (init_val) |val| {4338 if (init_val) |val| {
...@@ -8334,7 +8310,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -8334,7 +8310,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
8334 _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand));8310 _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand));
83358311
8336 if (try sema.resolveMaybeUndefVal(operand)) |int_val| {8312 if (try sema.resolveMaybeUndefVal(operand)) |int_val| {
8337 if (dest_ty.isNonexhaustiveEnum()) {8313 if (dest_ty.isNonexhaustiveEnum(mod)) {
8338 const int_tag_ty = try dest_ty.intTagType(mod);8314 const int_tag_ty = try dest_ty.intTagType(mod);
8339 if (try sema.intFitsInType(int_val, int_tag_ty, null)) {8315 if (try sema.intFitsInType(int_val, int_tag_ty, null)) {
8340 return sema.addConstant(dest_ty, int_val);8316 return sema.addConstant(dest_ty, int_val);
...@@ -8383,7 +8359,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -8383,7 +8359,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
83838359
8384 try sema.requireRuntimeBlock(block, src, operand_src);8360 try sema.requireRuntimeBlock(block, src, operand_src);
8385 const result = try block.addTyOp(.intcast, dest_ty, operand);8361 const result = try block.addTyOp(.intcast, dest_ty, operand);
8386 if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum() and8362 if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum(mod) and
8387 sema.mod.backendSupportsFeature(.is_named_enum_value))8363 sema.mod.backendSupportsFeature(.is_named_enum_value))
8388 {8364 {
8389 const ok = try block.addUnOp(.is_named_enum_value, result);8365 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...@@ -10518,7 +10494,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10518 var else_error_ty: ?Type = null;10494 var else_error_ty: ?Type = null;
1051910495
10520 // Validate usage of '_' prongs.10496 // 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)) {
10522 const msg = msg: {10498 const msg = msg: {
10523 const msg = try sema.errMsg(10499 const msg = try sema.errMsg(
10524 block,10500 block,
...@@ -10543,8 +10519,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10543,8 +10519,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10543 switch (operand_ty.zigTypeTag(mod)) {10519 switch (operand_ty.zigTypeTag(mod)) {
10544 .Union => unreachable, // handled in zirSwitchCond10520 .Union => unreachable, // handled in zirSwitchCond
10545 .Enum => {10521 .Enum => {
10546 seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount());10522 seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount(mod));
10547 empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum();10523 empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(mod);
10548 @memset(seen_enum_fields, null);10524 @memset(seen_enum_fields, null);
10549 // `range_set` is used for non-exhaustive enum values that do not correspond to any tags.10525 // `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...@@ -10599,7 +10575,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10599 } else true;10575 } else true;
1060010576
10601 if (special_prong == .@"else") {10577 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(
10603 block,10579 block,
10604 special_prong_src,10580 special_prong_src,
10605 "unreachable else prong; all cases already handled",10581 "unreachable else prong; all cases already handled",
...@@ -10617,7 +10593,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10617,7 +10593,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10617 for (seen_enum_fields, 0..) |seen_src, i| {10593 for (seen_enum_fields, 0..) |seen_src, i| {
10618 if (seen_src != null) continue;10594 if (seen_src != null) continue;
1061910595
10620 const field_name = operand_ty.enumFieldName(i);10596 const field_name = operand_ty.enumFieldName(i, mod);
10621 try sema.addFieldErrNote(10597 try sema.addFieldErrNote(
10622 operand_ty,10598 operand_ty,
10623 i,10599 i,
...@@ -10635,7 +10611,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10635,7 +10611,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10635 break :msg msg;10611 break :msg msg;
10636 };10612 };
10637 return sema.failWithOwnedErrorMsg(msg);10613 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) {
10639 return sema.fail(10615 return sema.fail(
10640 block,10616 block,
10641 src,10617 src,
...@@ -11159,7 +11135,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11159,7 +11135,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11159 return Air.Inst.Ref.unreachable_value;11135 return Air.Inst.Ref.unreachable_value;
11160 }11136 }
11161 if (mod.backendSupportsFeature(.is_named_enum_value) and block.wantSafety() and operand_ty.zigTypeTag(mod) == .Enum and11137 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))
11163 {11139 {
11164 try sema.zirDbgStmt(block, cond_dbg_node_index);11140 try sema.zirDbgStmt(block, cond_dbg_node_index);
11165 const ok = try block.addUnOp(.is_named_enum_value, operand);11141 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...@@ -11489,7 +11465,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11489 var emit_bb = false;11465 var emit_bb = false;
11490 if (special.is_inline) switch (operand_ty.zigTypeTag(mod)) {11466 if (special.is_inline) switch (operand_ty.zigTypeTag(mod)) {
11491 .Enum => {11467 .Enum => {
11492 if (operand_ty.isNonexhaustiveEnum() and !union_originally) {11468 if (operand_ty.isNonexhaustiveEnum(mod) and !union_originally) {
11493 return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{11469 return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{
11494 operand_ty.fmt(mod),11470 operand_ty.fmt(mod),
11495 });11471 });
...@@ -11629,7 +11605,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11629,7 +11605,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11629 case_block.inline_case_capture = .none;11605 case_block.inline_case_capture = .none;
1163011606
11631 if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and11607 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))
11633 {11609 {
11634 try sema.zirDbgStmt(&case_block, cond_dbg_node_index);11610 try sema.zirDbgStmt(&case_block, cond_dbg_node_index);
11635 const ok = try case_block.addUnOp(.is_named_enum_value, operand);11611 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...@@ -12081,7 +12057,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12081 break :hf switch (ty.zigTypeTag(mod)) {12057 break :hf switch (ty.zigTypeTag(mod)) {
12082 .Struct => ty.structFields(mod).contains(field_name),12058 .Struct => ty.structFields(mod).contains(field_name),
12083 .Union => ty.unionFields(mod).contains(field_name),12059 .Union => ty.unionFields(mod).contains(field_name),
12084 .Enum => ty.enumFields().contains(field_name),12060 .Enum => ty.enumFieldIndex(field_name, mod) != null,
12085 .Array => mem.eql(u8, field_name, "len"),12061 .Array => mem.eql(u8, field_name, "len"),
12086 else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{12062 else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{
12087 ty.fmt(sema.mod),12063 ty.fmt(sema.mod),
...@@ -16300,9 +16276,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16300,9 +16276,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16300 },16276 },
16301 .Enum => {16277 .Enum => {
16302 // TODO: look into memoizing this result.16278 // 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
16307 var fields_anon_decl = try block.startAnonDecl();16283 var fields_anon_decl = try block.startAnonDecl();
16308 defer fields_anon_decl.deinit();16284 defer fields_anon_decl.deinit();
...@@ -16320,25 +16296,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16320,25 +16296,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16320 break :t try enum_field_ty_decl.val.toType().copy(fields_anon_decl.arena());16296 break :t try enum_field_ty_decl.val.toType().copy(fields_anon_decl.arena());
16321 };16297 };
1632216298
16323 const enum_fields = ty.enumFields();16299 const enum_field_vals = try fields_anon_decl.arena().alloc(Value, enum_type.names.len);
16324 const enum_field_vals = try fields_anon_decl.arena().alloc(Value, enum_fields.count());
1632516300
16326 for (enum_field_vals, 0..) |*field_val, i| {16301 for (enum_field_vals, 0..) |*field_val, i| {
16327 var tag_val_payload: Value.Payload.U32 = .{16302 const name_ip = enum_type.names[i];
16328 .base = .{ .tag = .enum_field_index },16303 const name = mod.intern_pool.stringToSlice(name_ip);
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];
16336 const name_val = v: {16304 const name_val = v: {
16337 var anon_decl = try block.startAnonDecl();16305 var anon_decl = try block.startAnonDecl();
16338 defer anon_decl.deinit();16306 defer anon_decl.deinit();
16339 const bytes = try anon_decl.arena().dupeZ(u8, name);16307 const bytes = try anon_decl.arena().dupeZ(u8, name);
16340 const new_decl = try anon_decl.finish(16308 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),
16342 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),16310 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
16343 0, // default alignment16311 0, // default alignment
16344 );16312 );
...@@ -16350,7 +16318,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16350,7 +16318,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16350 // name: []const u8,16318 // name: []const u8,
16351 name_val,16319 name_val,
16352 // value: comptime_int,16320 // value: comptime_int,
16353 int_val,16321 try mod.intValue(Type.comptime_int, i),
16354 };16322 };
16355 field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), enum_field_fields);16323 field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), enum_field_fields);
16356 }16324 }
...@@ -16370,12 +16338,12 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16370,12 +16338,12 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16370 break :v try Value.Tag.decl_ref.create(sema.arena, new_decl);16338 break :v try Value.Tag.decl_ref.create(sema.arena, new_decl);
16371 };16339 };
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
16375 const field_values = try sema.arena.create([4]Value);16343 const field_values = try sema.arena.create([4]Value);
16376 field_values.* = .{16344 field_values.* = .{
16377 // tag_type: type,16345 // tag_type: type,
16378 try Value.Tag.ty.create(sema.arena, int_tag_ty),16346 enum_type.tag_ty.toValue(),
16379 // fields: []const EnumField,16347 // fields: []const EnumField,
16380 fields_val,16348 fields_val,
16381 // decls: []const Declaration,16349 // decls: []const Declaration,
...@@ -16468,7 +16436,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16468,7 +16436,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16468 });16436 });
16469 };16437 };
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
16473 const enum_tag_ty_val = if (union_ty.unionTagType(mod)) |tag_ty| v: {16441 const enum_tag_ty_val = if (union_ty.unionTagType(mod)) |tag_ty| v: {
16474 const ty_val = try Value.Tag.ty.create(sema.arena, tag_ty);16442 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...@@ -16631,7 +16599,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16631 });16599 });
16632 };16600 };
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
16636 const backing_integer_val = blk: {16604 const backing_integer_val = blk: {
16637 if (layout == .Packed) {16605 if (layout == .Packed) {
...@@ -16674,7 +16642,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16674,7 +16642,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16674 // TODO: look into memoizing this result.16642 // TODO: look into memoizing this result.
1667516643
16676 const opaque_ty = try sema.resolveTypeFields(ty);16644 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
16679 const field_values = try sema.arena.create([1]Value);16647 const field_values = try sema.arena.create([1]Value);
16680 field_values.* = .{16648 field_values.* = .{
...@@ -16700,7 +16668,7 @@ fn typeInfoDecls(...@@ -16700,7 +16668,7 @@ fn typeInfoDecls(
16700 block: *Block,16668 block: *Block,
16701 src: LazySrcLoc,16669 src: LazySrcLoc,
16702 type_info_ty: Type,16670 type_info_ty: Type,
16703 opt_namespace: ?*Module.Namespace,16671 opt_namespace: Module.Namespace.OptionalIndex,
16704) CompileError!Value {16672) CompileError!Value {
16705 const mod = sema.mod;16673 const mod = sema.mod;
16706 var decls_anon_decl = try block.startAnonDecl();16674 var decls_anon_decl = try block.startAnonDecl();
...@@ -16726,8 +16694,9 @@ fn typeInfoDecls(...@@ -16726,8 +16694,9 @@ fn typeInfoDecls(
16726 var seen_namespaces = std.AutoHashMap(*Namespace, void).init(sema.gpa);16694 var seen_namespaces = std.AutoHashMap(*Namespace, void).init(sema.gpa);
16727 defer seen_namespaces.deinit();16695 defer seen_namespaces.deinit();
1672816696
16729 if (opt_namespace) |some| {16697 if (opt_namespace.unwrap()) |namespace_index| {
16730 try sema.typeInfoNamespaceDecls(block, decls_anon_decl.arena(), some, &decl_vals, &seen_namespaces);16698 const namespace = mod.namespacePtr(namespace_index);
16699 try sema.typeInfoNamespaceDecls(block, decls_anon_decl.arena(), namespace, &decl_vals, &seen_namespaces);
16731 }16700 }
1673216701
16733 const new_decl = try decls_anon_decl.finish(16702 const new_decl = try decls_anon_decl.finish(
...@@ -17896,7 +17865,7 @@ fn unionInit(...@@ -17896,7 +17865,7 @@ fn unionInit(
1789617865
17897 if (try sema.resolveMaybeUndefVal(init)) |init_val| {17866 if (try sema.resolveMaybeUndefVal(init)) |init_val| {
17898 const tag_ty = union_ty.unionTagTypeHypothetical(mod);17867 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).?);
17900 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);17869 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
17901 return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{17870 return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{
17902 .tag = tag_val,17871 .tag = tag_val,
...@@ -17997,7 +17966,7 @@ fn zirStructInit(...@@ -17997,7 +17966,7 @@ fn zirStructInit(
17997 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);17966 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
17998 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);17967 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
17999 const tag_ty = resolved_ty.unionTagTypeHypothetical(mod);17968 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).?);
18001 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);17970 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
1800217971
18003 const init_inst = try sema.resolveInst(item.data.init);17972 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...@@ -18754,7 +18723,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18754 operand_ty.fmt(mod),18723 operand_ty.fmt(mod),
18755 }),18724 }),
18756 };18725 };
18757 if (enum_ty.enumFieldCount() == 0) {18726 if (enum_ty.enumFieldCount(mod) == 0) {
18758 // TODO I don't think this is the correct way to handle this but18727 // TODO I don't think this is the correct way to handle this but
18759 // it prevents a crash.18728 // it prevents a crash.
18760 return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{}'", .{18729 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...@@ -18776,7 +18745,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18776 };18745 };
18777 return sema.failWithOwnedErrorMsg(msg);18746 return sema.failWithOwnedErrorMsg(msg);
18778 };18747 };
18779 const field_name = enum_ty.enumFieldName(field_index);18748 const field_name = enum_ty.enumFieldName(field_index, mod);
18780 return sema.addStrLit(block, field_name);18749 return sema.addStrLit(block, field_name);
18781 }18750 }
18782 try sema.requireRuntimeBlock(block, src, operand_src);18751 try sema.requireRuntimeBlock(block, src, operand_src);
...@@ -19081,63 +19050,41 @@ fn zirReify(...@@ -19081,63 +19050,41 @@ fn zirReify(
19081 return sema.fail(block, src, "reified enums must have no decls", .{});19050 return sema.fail(block, src, "reified enums must have no decls", .{});
19082 }19051 }
1908319052
19084 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);19053 const int_tag_ty = tag_type_val.toType();
19085 errdefer new_decl_arena.deinit();19054 if (int_tag_ty.zigTypeTag(mod) != .Int) {
19086 const new_decl_arena_allocator = new_decl_arena.allocator();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);
19102 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{19062 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
19103 .ty = Type.type,19063 .ty = Type.type,
19104 .val = enum_val,19064 .val = undefined,
19105 }, name_strategy, "enum", inst);19065 }, name_strategy, "enum", inst);
19106 const new_decl = mod.declPtr(new_decl_index);19066 const new_decl = mod.declPtr(new_decl_index);
19107 new_decl.owns_tv = true;19067 new_decl.owns_tv = true;
19108 errdefer mod.abortAnonDecl(new_decl_index);19068 errdefer mod.abortAnonDecl(new_decl_index);
1910919069
19110 enum_obj.* = .{19070 // Define our empty enum decl
19111 .owner_decl = new_decl_index,19071 const fields_len = @intCast(u32, try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
19112 .tag_ty = Type.null,19072 const incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{
19113 .tag_ty_inferred = false,19073 .decl = new_decl_index,
19114 .fields = .{},19074 .namespace = .none,
19115 .values = .{},19075 .fields_len = fields_len,
19116 .namespace = try mod.createNamespace(.{19076 .has_values = true,
19117 .parent = block.namespace.toOptional(),19077 .tag_mode = if (!is_exhaustive_val.toBool(mod))
19118 .ty = enum_ty,19078 .nonexhaustive
19119 .file_scope = block.getFileScope(mod),19079 else
19120 }),19080 .explicit,
19121 };19081 .tag_ty = int_tag_ty.ip_index,
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,
19137 });19082 });
19083 errdefer mod.intern_pool.remove(incomplete_enum.index);
1913819084
19139 var field_i: usize = 0;19085 new_decl.val = incomplete_enum.index.toValue();
19140 while (field_i < fields_len) : (field_i += 1) {19086
19087 for (0..fields_len) |field_i| {
19141 const elem_val = try fields_val.elemValue(mod, field_i);19088 const elem_val = try fields_val.elemValue(mod, field_i);
19142 const field_struct_val: []const Value = elem_val.castTag(.aggregate).?.data;19089 const field_struct_val: []const Value = elem_val.castTag(.aggregate).?.data;
19143 // TODO use reflection instead of magic numbers here19090 // TODO use reflection instead of magic numbers here
...@@ -19148,39 +19095,36 @@ fn zirReify(...@@ -19148,39 +19095,36 @@ fn zirReify(
1914819095
19149 const field_name = try name_val.toAllocatedBytes(19096 const field_name = try name_val.toAllocatedBytes(
19150 Type.const_slice_u8,19097 Type.const_slice_u8,
19151 new_decl_arena_allocator,19098 sema.arena,
19152 mod,19099 mod,
19153 );19100 );
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)) {
19156 // TODO: better source location19104 // TODO: better source location
19157 return sema.fail(block, src, "field '{s}' with enumeration value '{}' is too large for backing int type '{}'", .{19105 return sema.fail(block, src, "field '{s}' with enumeration value '{}' is too large for backing int type '{}'", .{
19158 field_name,19106 field_name,
19159 value_val.fmtValue(Type.comptime_int, mod),19107 value_val.fmtValue(Type.comptime_int, mod),
19160 enum_obj.tag_ty.fmt(mod),19108 int_tag_ty.fmt(mod),
19161 });19109 });
19162 }19110 }
1916319111
19164 const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name);19112 if (try incomplete_enum.addFieldName(&mod.intern_pool, gpa, field_name_ip)) |other_index| {
19165 if (gop_field.found_existing) {
19166 const msg = msg: {19113 const msg = msg: {
19167 const msg = try sema.errMsg(block, src, "duplicate enum field '{s}'", .{field_name});19114 const msg = try sema.errMsg(block, src, "duplicate enum field '{s}'", .{field_name});
19168 errdefer msg.destroy(gpa);19115 errdefer msg.destroy(gpa);
19116 _ = other_index; // TODO: this note is incorrect
19169 try sema.errNote(block, src, msg, "other field here", .{});19117 try sema.errNote(block, src, msg, "other field here", .{});
19170 break :msg msg;19118 break :msg msg;
19171 };19119 };
19172 return sema.failWithOwnedErrorMsg(msg);19120 return sema.failWithOwnedErrorMsg(msg);
19173 }19121 }
1917419122
19175 const copied_tag_val = try value_val.copy(new_decl_arena_allocator);19123 if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, value_val.ip_index)) |other| {
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) {
19181 const msg = msg: {19124 const msg = msg: {
19182 const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)});19125 const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)});
19183 errdefer msg.destroy(gpa);19126 errdefer msg.destroy(gpa);
19127 _ = other; // TODO: this note is incorrect
19184 try sema.errNote(block, src, msg, "other enum tag value here", .{});19128 try sema.errNote(block, src, msg, "other enum tag value here", .{});
19185 break :msg msg;19129 break :msg msg;
19186 };19130 };
...@@ -19188,7 +19132,6 @@ fn zirReify(...@@ -19188,7 +19132,6 @@ fn zirReify(
19188 }19132 }
19189 }19133 }
1919019134
19191 try new_decl.finalizeNewArena(&new_decl_arena);
19192 return sema.analyzeDeclVal(block, src, new_decl_index);19135 return sema.analyzeDeclVal(block, src, new_decl_index);
19193 },19136 },
19194 .Opaque => {19137 .Opaque => {
...@@ -19307,26 +19250,29 @@ fn zirReify(...@@ -19307,26 +19250,29 @@ fn zirReify(
19307 new_namespace.ty = union_ty.toType();19250 new_namespace.ty = union_ty.toType();
1930819251
19309 // Tag type19252 // Tag type
19310 var tag_ty_field_names: ?Module.EnumFull.NameMap = null;
19311 var enum_field_names: ?*Module.EnumNumbered.NameMap = null;
19312 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));19253 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 = &.{};
19313 if (tag_type_val.optionalValue(mod)) |payload_val| {19257 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) {19260 const enum_type = switch (mod.intern_pool.indexToKey(union_obj.tag_ty.ip_index)) {
19317 return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{});19261 .enum_type => |x| x,
19318 }19262 else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),
19319 tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena);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);
19320 } else {19268 } else {
19321 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, fields_len, null);19269 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
19322 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
19323 }19270 }
1932419271
19325 // Fields19272 // Fields
19326 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);19273 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
1932719274
19328 var i: usize = 0;19275 for (0..fields_len) |i| {
19329 while (i < fields_len) : (i += 1) {
19330 const elem_val = try fields_val.elemValue(mod, i);19276 const elem_val = try fields_val.elemValue(mod, i);
19331 const field_struct_val = elem_val.castTag(.aggregate).?.data;19277 const field_struct_val = elem_val.castTag(.aggregate).?.data;
19332 // TODO use reflection instead of magic numbers here19278 // TODO use reflection instead of magic numbers here
...@@ -19343,13 +19289,14 @@ fn zirReify(...@@ -19343,13 +19289,14 @@ fn zirReify(
19343 mod,19289 mod,
19344 );19290 );
1934519291
19346 if (enum_field_names) |set| {19292 const field_name_ip = try mod.intern_pool.getOrPutString(gpa, field_name);
19347 set.putAssumeCapacity(field_name, {});19293
19294 if (enum_field_names.len != 0) {
19295 enum_field_names[i] = field_name_ip;
19348 }19296 }
1934919297
19350 if (tag_ty_field_names) |*names| {19298 if (explicit_enum_info) |tag_info| {
19351 const enum_has_field = names.orderedRemove(field_name);19299 const enum_index = tag_info.nameIndex(mod.intern_pool, field_name_ip) orelse {
19352 if (!enum_has_field) {
19353 const msg = msg: {19300 const msg = msg: {
19354 const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(mod) });19301 const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(mod) });
19355 errdefer msg.destroy(gpa);19302 errdefer msg.destroy(gpa);
...@@ -19357,7 +19304,11 @@ fn zirReify(...@@ -19357,7 +19304,11 @@ fn zirReify(
19357 break :msg msg;19304 break :msg msg;
19358 };19305 };
19359 return sema.failWithOwnedErrorMsg(msg);19306 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;
19361 }19312 }
1936219313
19363 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);19314 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
...@@ -19409,22 +19360,26 @@ fn zirReify(...@@ -19409,22 +19360,26 @@ fn zirReify(
19409 }19360 }
19410 }19361 }
1941119362
19412 if (tag_ty_field_names) |names| {19363 if (explicit_enum_info) |tag_info| {
19413 if (names.count() > 0) {19364 if (tag_info.names.len > fields_len) {
19414 const msg = msg: {19365 const msg = msg: {
19415 const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{});19366 const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{});
19416 errdefer msg.destroy(gpa);19367 errdefer msg.destroy(gpa);
1941719368
19418 const enum_ty = union_obj.tag_ty;19369 const enum_ty = union_obj.tag_ty;
19419 for (names.keys()) |field_name| {19370 for (tag_info.names, 0..) |field_name, field_index| {
19420 const field_index = enum_ty.enumFieldIndex(field_name).?;19371 if (explicit_tags_seen[field_index]) continue;
19421 try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name});19372 try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{
19373 mod.intern_pool.stringToSlice(field_name),
19374 });
19422 }19375 }
19423 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);19376 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
19424 break :msg msg;19377 break :msg msg;
19425 };19378 };
19426 return sema.failWithOwnedErrorMsg(msg);19379 return sema.failWithOwnedErrorMsg(msg);
19427 }19380 }
19381 } else {
19382 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, enum_field_names, null);
19428 }19383 }
1942919384
19430 try new_decl.finalizeNewArena(&new_decl_arena);19385 try new_decl.finalizeNewArena(&new_decl_arena);
...@@ -23450,7 +23405,7 @@ fn explainWhyTypeIsComptimeInner(...@@ -23450,7 +23405,7 @@ fn explainWhyTypeIsComptimeInner(
2345023405
23451 if (mod.typeToStruct(ty)) |struct_obj| {23406 if (mod.typeToStruct(ty)) |struct_obj| {
23452 for (struct_obj.fields.values(), 0..) |field, i| {23407 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, .{
23454 .index = i,23409 .index = i,
23455 .range = .type,23410 .range = .type,
23456 });23411 });
...@@ -23469,7 +23424,7 @@ fn explainWhyTypeIsComptimeInner(...@@ -23469,7 +23424,7 @@ fn explainWhyTypeIsComptimeInner(
2346923424
23470 if (mod.typeToUnion(ty)) |union_obj| {23425 if (mod.typeToUnion(ty)) |union_obj| {
23471 for (union_obj.fields.values(), 0..) |field, i| {23426 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, .{
23473 .index = i,23428 .index = i,
23474 .range = .type,23429 .range = .type,
23475 });23430 });
...@@ -24168,7 +24123,7 @@ fn fieldVal(...@@ -24168,7 +24123,7 @@ fn fieldVal(
24168 }24123 }
24169 const union_ty = try sema.resolveTypeFields(child_type);24124 const union_ty = try sema.resolveTypeFields(child_type);
24170 if (union_ty.unionTagType(mod)) |enum_ty| {24125 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| {
24172 const field_index = @intCast(u32, field_index_usize);24127 const field_index = @intCast(u32, field_index_usize);
24173 return sema.addConstant(24128 return sema.addConstant(
24174 enum_ty,24129 enum_ty,
...@@ -24184,7 +24139,7 @@ fn fieldVal(...@@ -24184,7 +24139,7 @@ fn fieldVal(
24184 return inst;24139 return inst;
24185 }24140 }
24186 }24141 }
24187 const field_index_usize = child_type.enumFieldIndex(field_name) orelse24142 const field_index_usize = child_type.enumFieldIndex(field_name, mod) orelse
24188 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);24143 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
24189 const field_index = @intCast(u32, field_index_usize);24144 const field_index = @intCast(u32, field_index_usize);
24190 const enum_val = try Value.Tag.enum_field_index.create(arena, field_index);24145 const enum_val = try Value.Tag.enum_field_index.create(arena, field_index);
...@@ -24382,7 +24337,7 @@ fn fieldPtr(...@@ -24382,7 +24337,7 @@ fn fieldPtr(
24382 }24337 }
24383 const union_ty = try sema.resolveTypeFields(child_type);24338 const union_ty = try sema.resolveTypeFields(child_type);
24384 if (union_ty.unionTagType(mod)) |enum_ty| {24339 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| {
24386 const field_index_u32 = @intCast(u32, field_index);24341 const field_index_u32 = @intCast(u32, field_index);
24387 var anon_decl = try block.startAnonDecl();24342 var anon_decl = try block.startAnonDecl();
24388 defer anon_decl.deinit();24343 defer anon_decl.deinit();
...@@ -24401,7 +24356,7 @@ fn fieldPtr(...@@ -24401,7 +24356,7 @@ fn fieldPtr(
24401 return inst;24356 return inst;
24402 }24357 }
24403 }24358 }
24404 const field_index = child_type.enumFieldIndex(field_name) orelse {24359 const field_index = child_type.enumFieldIndex(field_name, mod) orelse {
24405 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);24360 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
24406 };24361 };
24407 const field_index_u32 = @intCast(u32, field_index);24362 const field_index_u32 = @intCast(u32, field_index);
...@@ -24996,7 +24951,7 @@ fn unionFieldPtr(...@@ -24996,7 +24951,7 @@ fn unionFieldPtr(
24996 .@"volatile" = union_ptr_ty.isVolatilePtr(mod),24951 .@"volatile" = union_ptr_ty.isVolatilePtr(mod),
24997 .@"addrspace" = union_ptr_ty.ptrAddressSpace(mod),24952 .@"addrspace" = union_ptr_ty.ptrAddressSpace(mod),
24998 });24953 });
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
25001 if (initializing and field.ty.zigTypeTag(mod) == .NoReturn) {24956 if (initializing and field.ty.zigTypeTag(mod) == .NoReturn) {
25002 const msg = msg: {24957 const msg = msg: {
...@@ -25028,7 +24983,7 @@ fn unionFieldPtr(...@@ -25028,7 +24983,7 @@ fn unionFieldPtr(
25028 if (!tag_matches) {24983 if (!tag_matches) {
25029 const msg = msg: {24984 const msg = msg: {
25030 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;24985 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);
25032 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });24987 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
25033 errdefer msg.destroy(sema.gpa);24988 errdefer msg.destroy(sema.gpa);
25034 try sema.addDeclaredHereNote(msg, union_ty);24989 try sema.addDeclaredHereNote(msg, union_ty);
...@@ -25083,7 +25038,7 @@ fn unionFieldVal(...@@ -25083,7 +25038,7 @@ fn unionFieldVal(
25083 const union_obj = mod.typeToUnion(union_ty).?;25038 const union_obj = mod.typeToUnion(union_ty).?;
25084 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);25039 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
25085 const field = union_obj.fields.values()[field_index];25040 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
25088 if (try sema.resolveMaybeUndefVal(union_byval)) |union_val| {25043 if (try sema.resolveMaybeUndefVal(union_byval)) |union_val| {
25089 if (union_val.isUndef()) return sema.addConstUndef(field.ty);25044 if (union_val.isUndef()) return sema.addConstUndef(field.ty);
...@@ -25102,7 +25057,7 @@ fn unionFieldVal(...@@ -25102,7 +25057,7 @@ fn unionFieldVal(
25102 } else {25057 } else {
25103 const msg = msg: {25058 const msg = msg: {
25104 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;25059 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);
25106 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });25061 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
25107 errdefer msg.destroy(sema.gpa);25062 errdefer msg.destroy(sema.gpa);
25108 try sema.addDeclaredHereNote(msg, union_ty);25063 try sema.addDeclaredHereNote(msg, union_ty);
...@@ -26191,7 +26146,7 @@ fn coerceExtra(...@@ -26191,7 +26146,7 @@ fn coerceExtra(
26191 // enum literal to enum26146 // enum literal to enum
26192 const val = try sema.resolveConstValue(block, .unneeded, inst, "");26147 const val = try sema.resolveConstValue(block, .unneeded, inst, "");
26193 const bytes = val.castTag(.enum_literal).?.data;26148 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 {
26195 const msg = msg: {26150 const msg = msg: {
26196 const msg = try sema.errMsg(26151 const msg = try sema.errMsg(
26197 block,26152 block,
...@@ -28707,7 +28662,7 @@ fn coerceEnumToUnion(...@@ -28707,7 +28662,7 @@ fn coerceEnumToUnion(
2870728662
28708 try sema.requireRuntimeBlock(block, inst_src, null);28663 try sema.requireRuntimeBlock(block, inst_src, null);
2870928664
28710 if (tag_ty.isNonexhaustiveEnum()) {28665 if (tag_ty.isNonexhaustiveEnum(mod)) {
28711 const msg = msg: {28666 const msg = msg: {
28712 const msg = try sema.errMsg(block, inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{28667 const msg = try sema.errMsg(block, inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{
28713 union_ty.fmt(sema.mod),28668 union_ty.fmt(sema.mod),
...@@ -31605,7 +31560,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -31605,7 +31560,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
31605 .error_set_single,31560 .error_set_single,
31606 .error_set_inferred,31561 .error_set_inferred,
31607 .error_set_merged,31562 .error_set_merged,
31608 .enum_simple,
31609 => false,31563 => false,
3161031564
31611 .function => true,31565 .function => true,
...@@ -31646,14 +31600,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -31646,14 +31600,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
31646 const child_ty = ty.castTag(.anyframe_T).?.data;31600 const child_ty = ty.castTag(.anyframe_T).?.data;
31647 return sema.resolveTypeRequiresComptime(child_ty);31601 return sema.resolveTypeRequiresComptime(child_ty);
31648 },31602 },
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 },
31657 },31603 },
31658 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {31604 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
31659 .int_type => false,31605 .int_type => false,
...@@ -31760,7 +31706,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -31760,7 +31706,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3176031706
31761 .opaque_type => false,31707 .opaque_type => false,
3176231708
31763 .enum_type => @panic("TODO"),31709 .enum_type => |enum_type| try sema.resolveTypeRequiresComptime(enum_type.tag_ty.toType()),
3176431710
31765 // values, not types31711 // values, not types
31766 .un => unreachable,31712 .un => unreachable,
...@@ -32284,12 +32230,12 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -32284,12 +32230,12 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
32284 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);32230 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
32285 if (gop.found_existing) {32231 if (gop.found_existing) {
32286 const msg = msg: {32232 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;
32288 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name});32234 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name});
32289 errdefer msg.destroy(gpa);32235 errdefer msg.destroy(gpa);
3229032236
32291 const prev_field_index = struct_obj.fields.getIndex(field_name).?;32237 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 });
32293 try sema.mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{});32239 try sema.mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{});
32294 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});32240 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
32295 break :msg msg;32241 break :msg msg;
...@@ -32325,7 +32271,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -32325,7 +32271,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
32325 if (zir_field.type_ref != .none) {32271 if (zir_field.type_ref != .none) {
32326 break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) {32272 break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) {
32327 error.NeededSourceLocation => {32273 error.NeededSourceLocation => {
32328 const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{32274 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
32329 .index = field_i,32275 .index = field_i,
32330 .range = .type,32276 .range = .type,
32331 }).lazy;32277 }).lazy;
...@@ -32341,7 +32287,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -32341,7 +32287,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
32341 const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);32287 const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
32342 break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) {32288 break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) {
32343 error.NeededSourceLocation => {32289 error.NeededSourceLocation => {
32344 const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{32290 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
32345 .index = field_i,32291 .index = field_i,
32346 .range = .type,32292 .range = .type,
32347 }).lazy;32293 }).lazy;
...@@ -32360,7 +32306,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -32360,7 +32306,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3236032306
32361 if (field_ty.zigTypeTag(mod) == .Opaque) {32307 if (field_ty.zigTypeTag(mod) == .Opaque) {
32362 const msg = msg: {32308 const msg = msg: {
32363 const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{32309 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
32364 .index = field_i,32310 .index = field_i,
32365 .range = .type,32311 .range = .type,
32366 }).lazy;32312 }).lazy;
...@@ -32374,7 +32320,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -32374,7 +32320,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
32374 }32320 }
32375 if (field_ty.zigTypeTag(mod) == .NoReturn) {32321 if (field_ty.zigTypeTag(mod) == .NoReturn) {
32376 const msg = msg: {32322 const msg = msg: {
32377 const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{32323 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
32378 .index = field_i,32324 .index = field_i,
32379 .range = .type,32325 .range = .type,
32380 }).lazy;32326 }).lazy;
...@@ -32388,7 +32334,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -32388,7 +32334,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
32388 }32334 }
32389 if (struct_obj.layout == .Extern and !try sema.validateExternType(field.ty, .struct_field)) {32335 if (struct_obj.layout == .Extern and !try sema.validateExternType(field.ty, .struct_field)) {
32390 const msg = msg: {32336 const msg = msg: {
32391 const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{32337 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
32392 .index = field_i,32338 .index = field_i,
32393 .range = .type,32339 .range = .type,
32394 });32340 });
...@@ -32403,7 +32349,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -32403,7 +32349,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
32403 return sema.failWithOwnedErrorMsg(msg);32349 return sema.failWithOwnedErrorMsg(msg);
32404 } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty, mod))) {32350 } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty, mod))) {
32405 const msg = msg: {32351 const msg = msg: {
32406 const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{32352 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
32407 .index = field_i,32353 .index = field_i,
32408 .range = .type,32354 .range = .type,
32409 });32355 });
...@@ -32424,7 +32370,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -32424,7 +32370,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
32424 const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);32370 const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
32425 field.abi_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {32371 field.abi_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {
32426 error.NeededSourceLocation => {32372 error.NeededSourceLocation => {
32427 const align_src = struct_obj.fieldSrcLoc(sema.mod, .{32373 const align_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
32428 .index = field_i,32374 .index = field_i,
32429 .range = .alignment,32375 .range = .alignment,
32430 }).lazy;32376 }).lazy;
...@@ -32452,7 +32398,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -32452,7 +32398,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
32452 const field = &struct_obj.fields.values()[field_i];32398 const field = &struct_obj.fields.values()[field_i];
32453 const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) {32399 const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) {
32454 error.NeededSourceLocation => {32400 error.NeededSourceLocation => {
32455 const init_src = struct_obj.fieldSrcLoc(sema.mod, .{32401 const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
32456 .index = field_i,32402 .index = field_i,
32457 .range = .value,32403 .range = .value,
32458 }).lazy;32404 }).lazy;
...@@ -32462,7 +32408,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -32462,7 +32408,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
32462 else => |e| return e,32408 else => |e| return e,
32463 };32409 };
32464 const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {32410 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, .{
32466 .index = field_i,32412 .index = field_i,
32467 .range = .value,32413 .range = .value,
32468 }).lazy;32414 }).lazy;
...@@ -32573,9 +32519,11 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -32573,9 +32519,11 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
32573 try union_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);32519 try union_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
3257432520
32575 var int_tag_ty: Type = undefined;32521 var int_tag_ty: Type = undefined;
32576 var enum_field_names: ?*Module.EnumNumbered.NameMap = null;32522 var enum_field_names: []InternPool.NullTerminatedString = &.{};
32577 var enum_value_map: ?*Module.EnumNumbered.ValueMap = null;32523 var enum_field_vals: []InternPool.Index = &.{};
32578 var tag_ty_field_names: ?Module.EnumFull.NameMap = null;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;
32579 if (tag_type_ref != .none) {32527 if (tag_type_ref != .none) {
32580 const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x };32528 const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x };
32581 const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref);32529 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 {...@@ -32601,27 +32549,26 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
32601 return sema.failWithOwnedErrorMsg(msg);32549 return sema.failWithOwnedErrorMsg(msg);
32602 }32550 }
32603 }32551 }
32604 union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, fields_len, provided_ty, union_obj);32552 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
32605 const enum_obj = union_obj.tag_ty.castTag(.enum_numbered).?.data;32553 enum_field_vals = try sema.arena.alloc(InternPool.Index, fields_len);
32606 enum_field_names = &enum_obj.fields;
32607 enum_value_map = &enum_obj.values;
32608 } else {32554 } else {
32609 // The provided type is the enum tag type.32555 // The provided type is the enum tag type.
32610 union_obj.tag_ty = try provided_ty.copy(decl_arena_allocator);32556 union_obj.tag_ty = provided_ty;
32611 if (union_obj.tag_ty.zigTypeTag(mod) != .Enum) {32557 const enum_type = switch (mod.intern_pool.indexToKey(union_obj.tag_ty.ip_index)) {
32612 return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(sema.mod)});32558 .enum_type => |x| x,
32613 }32559 else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(sema.mod)}),
32560 };
32614 // The fields of the union must match the enum exactly.32561 // The fields of the union must match the enum exactly.
32615 // Store a copy of the enum field names so we can check for32562 // A flag per field is used to check for missing and extraneous fields.
32616 // missing or extraneous fields later.32563 explicit_enum_info = enum_type;
32617 tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena);32564 explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
32565 @memset(explicit_tags_seen, false);
32618 }32566 }
32619 } else {32567 } else {
32620 // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis32568 // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis
32621 // purposes, we still auto-generate an enum tag type the same way. That the union is32569 // purposes, we still auto-generate an enum tag type the same way. That the union is
32622 // untagged is represented by the Type tag (union vs union_tagged).32570 // 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);32571 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
32624 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
32625 }32572 }
3262632573
32627 if (fields_len == 0) {32574 if (fields_len == 0) {
...@@ -32675,11 +32622,11 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -32675,11 +32622,11 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
32675 break :blk try sema.resolveInst(tag_ref);32622 break :blk try sema.resolveInst(tag_ref);
32676 } else .none;32623 } else .none;
3267732624
32678 if (enum_value_map) |map| {32625 if (enum_field_vals.len != 0) {
32679 const copied_val = if (tag_ref != .none) blk: {32626 const copied_val = if (tag_ref != .none) blk: {
32680 const val = sema.semaUnionFieldVal(&block_scope, .unneeded, int_tag_ty, tag_ref) catch |err| switch (err) {32627 const val = sema.semaUnionFieldVal(&block_scope, .unneeded, int_tag_ty, tag_ref) catch |err| switch (err) {
32681 error.NeededSourceLocation => {32628 error.NeededSourceLocation => {
32682 const val_src = union_obj.fieldSrcLoc(sema.mod, .{32629 const val_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
32683 .index = field_i,32630 .index = field_i,
32684 .range = .value,32631 .range = .value,
32685 }).lazy;32632 }).lazy;
...@@ -32690,25 +32637,24 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -32690,25 +32637,24 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
32690 };32637 };
32691 last_tag_val = val;32638 last_tag_val = val;
3269232639
32693 // This puts the memory into the union arena, not the enum arena, but32640 break :blk val;
32694 // it is OK since they share the same lifetime.
32695 break :blk try val.copy(decl_arena_allocator);
32696 } else blk: {32641 } else blk: {
32697 const val = if (last_tag_val) |val|32642 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)
32699 else32644 else
32700 try mod.intValue(int_tag_ty, 0);32645 try mod.intValue(int_tag_ty, 0);
32701 last_tag_val = val;32646 last_tag_val = val;
3270232647
32703 break :blk try val.copy(decl_arena_allocator);32648 break :blk val;
32704 };32649 };
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, .{
32706 .ty = int_tag_ty,32652 .ty = int_tag_ty,
32707 .mod = mod,32653 .mod = mod,
32708 });32654 });
32709 if (gop.found_existing) {32655 if (gop.found_existing) {
32710 const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;32656 const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy;
32711 const other_field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = gop.index }).lazy;32657 const other_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = gop.index }).lazy;
32712 const msg = msg: {32658 const msg = msg: {
32713 const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{copied_val.fmtValue(int_tag_ty, sema.mod)});32659 const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{copied_val.fmtValue(int_tag_ty, sema.mod)});
32714 errdefer msg.destroy(gpa);32660 errdefer msg.destroy(gpa);
...@@ -32721,8 +32667,9 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -32721,8 +32667,9 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3272132667
32722 // This string needs to outlive the ZIR code.32668 // This string needs to outlive the ZIR code.
32723 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);32669 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
32724 if (enum_field_names) |set| {32670 const field_name_ip = try mod.intern_pool.getOrPutString(gpa, field_name);
32725 set.putAssumeCapacity(field_name, {});32671 if (enum_field_names.len != 0) {
32672 enum_field_names[field_i] = field_name_ip;
32726 }32673 }
3272732674
32728 const field_ty: Type = if (!has_type)32675 const field_ty: Type = if (!has_type)
...@@ -32732,7 +32679,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -32732,7 +32679,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
32732 else32679 else
32733 sema.resolveType(&block_scope, .unneeded, field_type_ref) catch |err| switch (err) {32680 sema.resolveType(&block_scope, .unneeded, field_type_ref) catch |err| switch (err) {
32734 error.NeededSourceLocation => {32681 error.NeededSourceLocation => {
32735 const ty_src = union_obj.fieldSrcLoc(sema.mod, .{32682 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
32736 .index = field_i,32683 .index = field_i,
32737 .range = .type,32684 .range = .type,
32738 }).lazy;32685 }).lazy;
...@@ -32749,12 +32696,12 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -32749,12 +32696,12 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
32749 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);32696 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
32750 if (gop.found_existing) {32697 if (gop.found_existing) {
32751 const msg = msg: {32698 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;
32753 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name});32700 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name});
32754 errdefer msg.destroy(gpa);32701 errdefer msg.destroy(gpa);
3275532702
32756 const prev_field_index = union_obj.fields.getIndex(field_name).?;32703 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;
32758 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl, mod), msg, "other field here", .{});32705 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl, mod), msg, "other field here", .{});
32759 try sema.errNote(&block_scope, src, msg, "union declared here", .{});32706 try sema.errNote(&block_scope, src, msg, "union declared here", .{});
32760 break :msg msg;32707 break :msg msg;
...@@ -32762,26 +32709,31 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -32762,26 +32709,31 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
32762 return sema.failWithOwnedErrorMsg(msg);32709 return sema.failWithOwnedErrorMsg(msg);
32763 }32710 }
3276432711
32765 if (tag_ty_field_names) |*names| {32712 if (explicit_enum_info) |tag_info| {
32766 const enum_has_field = names.orderedRemove(field_name);32713 const enum_index = tag_info.nameIndex(mod.intern_pool, field_name_ip) orelse {
32767 if (!enum_has_field) {
32768 const msg = msg: {32714 const msg = msg: {
32769 const ty_src = union_obj.fieldSrcLoc(sema.mod, .{32715 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
32770 .index = field_i,32716 .index = field_i,
32771 .range = .type,32717 .range = .type,
32772 }).lazy;32718 }).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 });
32774 errdefer msg.destroy(sema.gpa);32722 errdefer msg.destroy(sema.gpa);
32775 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);32723 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
32776 break :msg msg;32724 break :msg msg;
32777 };32725 };
32778 return sema.failWithOwnedErrorMsg(msg);32726 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;
32780 }32732 }
3278132733
32782 if (field_ty.zigTypeTag(mod) == .Opaque) {32734 if (field_ty.zigTypeTag(mod) == .Opaque) {
32783 const msg = msg: {32735 const msg = msg: {
32784 const ty_src = union_obj.fieldSrcLoc(sema.mod, .{32736 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
32785 .index = field_i,32737 .index = field_i,
32786 .range = .type,32738 .range = .type,
32787 }).lazy;32739 }).lazy;
...@@ -32795,7 +32747,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -32795,7 +32747,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
32795 }32747 }
32796 if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {32748 if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {
32797 const msg = msg: {32749 const msg = msg: {
32798 const ty_src = union_obj.fieldSrcLoc(sema.mod, .{32750 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
32799 .index = field_i,32751 .index = field_i,
32800 .range = .type,32752 .range = .type,
32801 });32753 });
...@@ -32810,7 +32762,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -32810,7 +32762,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
32810 return sema.failWithOwnedErrorMsg(msg);32762 return sema.failWithOwnedErrorMsg(msg);
32811 } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) {32763 } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) {
32812 const msg = msg: {32764 const msg = msg: {
32813 const ty_src = union_obj.fieldSrcLoc(sema.mod, .{32765 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
32814 .index = field_i,32766 .index = field_i,
32815 .range = .type,32767 .range = .type,
32816 });32768 });
...@@ -32833,7 +32785,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -32833,7 +32785,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
32833 if (align_ref != .none) {32785 if (align_ref != .none) {
32834 gop.value_ptr.abi_align = sema.resolveAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {32786 gop.value_ptr.abi_align = sema.resolveAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {
32835 error.NeededSourceLocation => {32787 error.NeededSourceLocation => {
32836 const align_src = union_obj.fieldSrcLoc(sema.mod, .{32788 const align_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
32837 .index = field_i,32789 .index = field_i,
32838 .range = .alignment,32790 .range = .alignment,
32839 }).lazy;32791 }).lazy;
...@@ -32847,22 +32799,28 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -32847,22 +32799,28 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
32847 }32799 }
32848 }32800 }
3284932801
32850 if (tag_ty_field_names) |names| {32802 if (explicit_enum_info) |tag_info| {
32851 if (names.count() > 0) {32803 if (tag_info.names.len > fields_len) {
32852 const msg = msg: {32804 const msg = msg: {
32853 const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{});32805 const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{});
32854 errdefer msg.destroy(sema.gpa);32806 errdefer msg.destroy(sema.gpa);
3285532807
32856 const enum_ty = union_obj.tag_ty;32808 const enum_ty = union_obj.tag_ty;
32857 for (names.keys()) |field_name| {32809 for (tag_info.names, 0..) |field_name, field_index| {
32858 const field_index = enum_ty.enumFieldIndex(field_name).?;32810 if (explicit_tags_seen[field_index]) continue;
32859 try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name});32811 try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{
32812 mod.intern_pool.stringToSlice(field_name),
32813 });
32860 }32814 }
32861 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);32815 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
32862 break :msg msg;32816 break :msg msg;
32863 };32817 };
32864 return sema.failWithOwnedErrorMsg(msg);32818 return sema.failWithOwnedErrorMsg(msg);
32865 }32819 }
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);
32866 }32824 }
32867}32825}
3286832826
...@@ -32874,25 +32832,12 @@ fn semaUnionFieldVal(sema: *Sema, block: *Block, src: LazySrcLoc, int_tag_ty: Ty...@@ -32874,25 +32832,12 @@ fn semaUnionFieldVal(sema: *Sema, block: *Block, src: LazySrcLoc, int_tag_ty: Ty
32874fn generateUnionTagTypeNumbered(32832fn generateUnionTagTypeNumbered(
32875 sema: *Sema,32833 sema: *Sema,
32876 block: *Block,32834 block: *Block,
32877 fields_len: u32,32835 enum_field_names: []const InternPool.NullTerminatedString,
32878 int_ty: Type,32836 enum_field_vals: []const InternPool.Index,
32879 union_obj: *Module.Union,32837 union_obj: *Module.Union,
32880) !Type {32838) !Type {
32881 const mod = sema.mod;32839 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
32896 const src_decl = mod.declPtr(block.src_decl);32841 const src_decl = mod.declPtr(block.src_decl);
32897 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);32842 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
32898 errdefer mod.destroyDecl(new_decl_index);32843 errdefer mod.destroyDecl(new_decl_index);
...@@ -32903,53 +32848,45 @@ fn generateUnionTagTypeNumbered(...@@ -32903,53 +32848,45 @@ fn generateUnionTagTypeNumbered(
32903 };32848 };
32904 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{32849 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{
32905 .ty = Type.type,32850 .ty = Type.type,
32906 .val = enum_val,32851 .val = undefined,
32907 }, name);32852 }, name);
32908 sema.mod.declPtr(new_decl_index).name_fully_qualified = true;
32909
32910 const new_decl = mod.declPtr(new_decl_index);32853 const new_decl = mod.declPtr(new_decl_index);
32854 new_decl.name_fully_qualified = true;
32911 new_decl.owns_tv = true;32855 new_decl.owns_tv = true;
32912 new_decl.name_fully_qualified = true;32856 new_decl.name_fully_qualified = true;
32913 errdefer mod.abortAnonDecl(new_decl_index);32857 errdefer mod.abortAnonDecl(new_decl_index);
3291432858
32915 const copied_int_ty = try int_ty.copy(new_decl_arena_allocator);32859 const enum_ty = try mod.intern(.{ .enum_type = .{
32916 enum_obj.* = .{32860 .decl = new_decl_index,
32917 .owner_decl = new_decl_index,32861 .namespace = .none,
32918 .tag_ty = copied_int_ty,32862 .tag_ty = if (enum_field_vals.len == 0)
32919 .fields = .{},32863 .noreturn_type
32920 .values = .{},32864 else
32921 };32865 mod.intern_pool.typeOf(enum_field_vals[0]),
32922 // Here we pre-allocate the maps using the decl arena.32866 .names = enum_field_names,
32923 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);32867 .values = enum_field_vals,
32924 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{32868 .tag_mode = .explicit,
32925 .ty = copied_int_ty,32869 } });
32926 .mod = mod,32870 errdefer mod.intern_pool.remove(enum_ty);
32927 });
32928 try new_decl.finalizeNewArena(&new_decl_arena);
32929 return enum_ty;
32930}
3293132871
32932fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, maybe_union_obj: ?*Module.Union) !Type {32872 new_decl.val = enum_ty.toValue();
32933 const mod = sema.mod;
3293432873
32935 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);32874 return enum_ty.toType();
32936 errdefer new_decl_arena.deinit();32875}
32937 const new_decl_arena_allocator = new_decl_arena.allocator();
3293832876
32939 const enum_obj = try new_decl_arena_allocator.create(Module.EnumSimple);32877fn generateUnionTagTypeSimple(
32940 const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumSimple);32878 sema: *Sema,
32941 enum_ty_payload.* = .{32879 block: *Block,
32942 .base = .{ .tag = .enum_simple },32880 enum_field_names: []const InternPool.NullTerminatedString,
32943 .data = enum_obj,32881 maybe_union_obj: ?*Module.Union,
32944 };32882) !Type {
32945 const enum_ty = Type.initPayload(&enum_ty_payload.base);32883 const mod = sema.mod;
32946 const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
3294732884
32948 const new_decl_index = new_decl_index: {32885 const new_decl_index = new_decl_index: {
32949 const union_obj = maybe_union_obj orelse {32886 const union_obj = maybe_union_obj orelse {
32950 break :new_decl_index try mod.createAnonymousDecl(block, .{32887 break :new_decl_index try mod.createAnonymousDecl(block, .{
32951 .ty = Type.type,32888 .ty = Type.type,
32952 .val = enum_val,32889 .val = undefined,
32953 });32890 });
32954 };32891 };
32955 const src_decl = mod.declPtr(block.src_decl);32892 const src_decl = mod.declPtr(block.src_decl);
...@@ -32962,24 +32899,31 @@ fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, may...@@ -32962,24 +32899,31 @@ fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, may
32962 };32899 };
32963 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{32900 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{
32964 .ty = Type.type,32901 .ty = Type.type,
32965 .val = enum_val,32902 .val = undefined,
32966 }, name);32903 }, name);
32967 sema.mod.declPtr(new_decl_index).name_fully_qualified = true;32904 mod.declPtr(new_decl_index).name_fully_qualified = true;
32968 break :new_decl_index new_decl_index;32905 break :new_decl_index new_decl_index;
32969 };32906 };
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
32971 const new_decl = mod.declPtr(new_decl_index);32921 const new_decl = mod.declPtr(new_decl_index);
32972 new_decl.owns_tv = true;32922 new_decl.owns_tv = true;
32923 new_decl.val = enum_ty.toValue();
32973 errdefer mod.abortAnonDecl(new_decl_index);32924 errdefer mod.abortAnonDecl(new_decl_index);
3297432925
32975 enum_obj.* = .{32926 return enum_ty.toType();
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;
32983}32927}
3298432928
32985fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {32929fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
...@@ -33098,57 +33042,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -33098,57 +33042,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
33098 return Value.empty_struct;33042 return Value.empty_struct;
33099 },33043 },
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
33152 .array => {33045 .array => {
33153 if (ty.arrayLen(mod) == 0)33046 if (ty.arrayLen(mod) == 0)
33154 return Value.initTag(.empty_array);33047 return Value.initTag(.empty_array);
...@@ -33295,7 +33188,28 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -33295,7 +33188,28 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
33295 return only.toValue();33188 return only.toValue();
33296 },33189 },
33297 .opaque_type => null,33190 .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
33300 // values, not types33214 // values, not types
33301 .un => unreachable,33215 .un => unreachable,
...@@ -33701,7 +33615,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -33701,7 +33615,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
33701 .error_set_single,33615 .error_set_single,
33702 .error_set_inferred,33616 .error_set_inferred,
33703 .error_set_merged,33617 .error_set_merged,
33704 .enum_simple,
33705 => false,33618 => false,
3370633619
33707 .function => true,33620 .function => true,
...@@ -33742,14 +33655,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -33742,14 +33655,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
33742 const child_ty = ty.castTag(.anyframe_T).?.data;33655 const child_ty = ty.castTag(.anyframe_T).?.data;
33743 return sema.typeRequiresComptime(child_ty);33656 return sema.typeRequiresComptime(child_ty);
33744 },33657 },
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 },
33753 },33658 },
33754 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {33659 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
33755 .int_type => return false,33660 .int_type => return false,
...@@ -33865,7 +33770,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -33865,7 +33770,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
33865 },33770 },
3386633771
33867 .opaque_type => false,33772 .opaque_type => false,
33868 .enum_type => @panic("TODO"),33773 .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()),
3386933774
33870 // values, not types33775 // values, not types
33871 .un => unreachable,33776 .un => unreachable,
...@@ -34435,42 +34340,19 @@ fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {...@@ -34435,42 +34340,19 @@ fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {
34435/// Asserts the type is an enum.34340/// Asserts the type is an enum.
34436fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {34341fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {
34437 const mod = sema.mod;34342 const mod = sema.mod;
34438 switch (ty.tag()) {34343 const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
34439 .enum_nonexhaustive => unreachable,34344 assert(enum_type.tag_mode != .nonexhaustive);
34440 .enum_full => {34345 if (enum_type.values.len == 0) {
34441 const enum_full = ty.castTag(.enum_full).?.data;34346 // auto-numbered
34442 const tag_ty = enum_full.tag_ty;34347 return sema.intInRange(enum_type.tag_ty.toType(), int, enum_type.names.len);
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,
34473 }34348 }
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;
34474}34356}
3447534357
34476fn intAddWithOverflow(34358fn intAddWithOverflow(
src/TypedValue.zig+1-1
...@@ -198,7 +198,7 @@ pub fn print(...@@ -198,7 +198,7 @@ pub fn print(
198 .empty_array => return writer.writeAll(".{}"),198 .empty_array => return writer.writeAll(".{}"),
199 .enum_literal => return writer.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}),199 .enum_literal => return writer.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}),
200 .enum_field_index => {200 .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)});
202 },202 },
203 .bytes => return writer.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}),203 .bytes => return writer.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}),
204 .str_lit => {204 .str_lit => {
src/arch/wasm/CodeGen.zig+15-35
...@@ -3101,24 +3101,12 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -3101,24 +3101,12 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3101 },3101 },
3102 .Enum => {3102 .Enum => {
3103 if (val.castTag(.enum_field_index)) |field_index| {3103 if (val.castTag(.enum_field_index)) |field_index| {
3104 switch (ty.tag()) {3104 const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
3105 .enum_simple => return WValue{ .imm32 = field_index.data },3105 if (enum_type.values.len != 0) {
3106 .enum_full, .enum_nonexhaustive => {3106 const tag_val = enum_type.values[field_index.data];
3107 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;3107 return func.lowerConstant(tag_val.toValue(), enum_type.tag_ty.toType());
3108 if (enum_full.values.count() != 0) {3108 } else {
3109 const tag_val = enum_full.values.keys()[field_index.data];3109 return WValue{ .imm32 = 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()}),
3122 }3110 }
3123 } else {3111 } else {
3124 const int_tag_ty = try ty.intTagType(mod);3112 const int_tag_ty = try ty.intTagType(mod);
...@@ -3240,21 +3228,12 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) !i32 {...@@ -3240,21 +3228,12 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) !i32 {
3240 switch (ty.zigTypeTag(mod)) {3228 switch (ty.zigTypeTag(mod)) {
3241 .Enum => {3229 .Enum => {
3242 if (val.castTag(.enum_field_index)) |field_index| {3230 if (val.castTag(.enum_field_index)) |field_index| {
3243 switch (ty.tag()) {3231 const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
3244 .enum_simple => return @bitCast(i32, field_index.data),3232 if (enum_type.values.len != 0) {
3245 .enum_full, .enum_nonexhaustive => {3233 const tag_val = enum_type.values[field_index.data];
3246 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;3234 return func.valueAsI32(tag_val.toValue(), enum_type.tag_ty.toType());
3247 if (enum_full.values.count() != 0) {3235 } else {
3248 const tag_val = enum_full.values.keys()[field_index.data];3236 return @bitCast(i32, 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,
3258 }3237 }
3259 } else {3238 } else {
3260 const int_tag_ty = try ty.intTagType(mod);3239 const int_tag_ty = try ty.intTagType(mod);
...@@ -6836,7 +6815,8 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {...@@ -6836,7 +6815,8 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
68366815
6837 // TODO: Make switch implementation generic so we can use a jump table for this when the tags are not sparse.6816 // TODO: Make switch implementation generic so we can use a jump table for this when the tags are not sparse.
6838 // generate an if-else chain for each tag value as well as constant.6817 // 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);
6840 // for each tag name, create an unnamed const,6820 // for each tag name, create an unnamed const,
6841 // and then get a pointer to its value.6821 // and then get a pointer to its value.
6842 const name_ty = try mod.arrayType(.{6822 const name_ty = try mod.arrayType(.{
...@@ -6846,7 +6826,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {...@@ -6846,7 +6826,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
6846 });6826 });
6847 const string_bytes = &mod.string_literal_bytes;6827 const string_bytes = &mod.string_literal_bytes;
6848 try string_bytes.ensureUnusedCapacity(mod.gpa, tag_name.len);6828 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{
6850 .bytes = string_bytes,6830 .bytes = string_bytes,
6851 }, Module.StringLiteralContext{6831 }, Module.StringLiteralContext{
6852 .bytes = string_bytes,6832 .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 {...@@ -2016,7 +2016,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
2016 const ret_reg = param_regs[0];2016 const ret_reg = param_regs[0];
2017 const enum_mcv = MCValue{ .register = param_regs[1] };2017 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));
2020 defer self.gpa.free(exitlude_jump_relocs);2020 defer self.gpa.free(exitlude_jump_relocs);
20212021
2022 const data_reg = try self.register_manager.allocReg(null, gp);2022 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 {...@@ -2027,9 +2027,10 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
2027 var data_off: i32 = 0;2027 var data_off: i32 = 0;
2028 for (2028 for (
2029 exitlude_jump_relocs,2029 exitlude_jump_relocs,
2030 enum_ty.enumFields().keys(),2030 enum_ty.enumFields(mod),
2031 0..,2031 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);
2033 var tag_pl = Value.Payload.U32{2034 var tag_pl = Value.Payload.U32{
2034 .base = .{ .tag = .enum_field_index },2035 .base = .{ .tag = .enum_field_index },
2035 .data = @intCast(u32, index),2036 .data = @intCast(u32, index),
...@@ -11413,7 +11414,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -11413,7 +11414,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
11413 const union_obj = mod.typeToUnion(union_ty).?;11414 const union_obj = mod.typeToUnion(union_ty).?;
11414 const field_name = union_obj.fields.keys()[extra.field_index];11415 const field_name = union_obj.fields.keys()[extra.field_index];
11415 const tag_ty = union_obj.tag_ty;11416 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).?);
11417 var tag_pl = Value.Payload.U32{ .base = .{ .tag = .enum_field_index }, .data = field_index };11418 var tag_pl = Value.Payload.U32{ .base = .{ .tag = .enum_field_index }, .data = field_index };
11418 const tag_val = Value.initPayload(&tag_pl.base);11419 const tag_val = Value.initPayload(&tag_pl.base);
11419 const tag_int_val = try tag_val.enumToInt(tag_ty, mod);11420 const tag_int_val = try tag_val.enumToInt(tag_ty, mod);
src/codegen.zig+11-21
...@@ -156,7 +156,8 @@ pub fn generateLazySymbol(...@@ -156,7 +156,8 @@ pub fn generateLazySymbol(
156 return Result.ok;156 return Result.ok;
157 } else if (lazy_sym.ty.zigTypeTag(mod) == .Enum) {157 } else if (lazy_sym.ty.zigTypeTag(mod) == .Enum) {
158 alignment.* = 1;158 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);
160 try code.ensureUnusedCapacity(tag_name.len + 1);161 try code.ensureUnusedCapacity(tag_name.len + 1);
161 code.appendSliceAssumeCapacity(tag_name);162 code.appendSliceAssumeCapacity(tag_name);
162 code.appendAssumeCapacity(0);163 code.appendAssumeCapacity(0);
...@@ -1229,26 +1230,15 @@ pub fn genTypedValue(...@@ -1229,26 +1230,15 @@ pub fn genTypedValue(
1229 },1230 },
1230 .Enum => {1231 .Enum => {
1231 if (typed_value.val.castTag(.enum_field_index)) |field_index| {1232 if (typed_value.val.castTag(.enum_field_index)) |field_index| {
1232 switch (typed_value.ty.tag()) {1233 const enum_type = mod.intern_pool.indexToKey(typed_value.ty.ip_index).enum_type;
1233 .enum_simple => {1234 if (enum_type.values.len != 0) {
1234 return GenResult.mcv(.{ .immediate = field_index.data });1235 const tag_val = enum_type.values[field_index.data];
1235 },1236 return genTypedValue(bin_file, src_loc, .{
1236 .enum_numbered, .enum_full, .enum_nonexhaustive => {1237 .ty = enum_type.tag_ty.toType(),
1237 const enum_values = if (typed_value.ty.castTag(.enum_numbered)) |pl|1238 .val = tag_val.toValue(),
1238 pl.data.values1239 }, owner_decl_index);
1239 else1240 } else {
1240 typed_value.ty.cast(Type.Payload.EnumFull).?.data.values;1241 return GenResult.mcv(.{ .immediate = field_index.data });
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,
1252 }1242 }
1253 } else {1243 } else {
1254 const int_tag_ty = try typed_value.ty.intTagType(mod);1244 const int_tag_ty = try typed_value.ty.intTagType(mod);
src/codegen/c.zig+9-23
...@@ -1288,27 +1288,12 @@ pub const DeclGen = struct {...@@ -1288,27 +1288,12 @@ pub const DeclGen = struct {
1288 switch (val.tag()) {1288 switch (val.tag()) {
1289 .enum_field_index => {1289 .enum_field_index => {
1290 const field_index = val.castTag(.enum_field_index).?.data;1290 const field_index = val.castTag(.enum_field_index).?.data;
1291 switch (ty.tag()) {1291 const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
1292 .enum_simple => return writer.print("{d}", .{field_index}),1292 if (enum_type.values.len != 0) {
1293 .enum_full, .enum_nonexhaustive => {1293 const tag_val = enum_type.values[field_index];
1294 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;1294 return dg.renderValue(writer, enum_type.tag_ty.toType(), tag_val.toValue(), location);
1295 if (enum_full.values.count() != 0) {1295 } else {
1296 const tag_val = enum_full.values.keys()[field_index];1296 return writer.print("{d}", .{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,
1312 }1297 }
1313 },1298 },
1314 else => {1299 else => {
...@@ -2539,7 +2524,8 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {...@@ -2539,7 +2524,8 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
2539 try w.writeByte('(');2524 try w.writeByte('(');
2540 try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete);2525 try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete);
2541 try w.writeAll(") {\n switch (tag) {\n");2526 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);
2543 var tag_pl: Value.Payload.U32 = .{2529 var tag_pl: Value.Payload.U32 = .{
2544 .base = .{ .tag = .enum_field_index },2530 .base = .{ .tag = .enum_field_index },
2545 .data = @intCast(u32, index),2531 .data = @intCast(u32, index),
...@@ -6930,7 +6916,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6930,7 +6916,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
6930 const field: CValue = if (union_ty.unionTagTypeSafety(mod)) |tag_ty| field: {6916 const field: CValue = if (union_ty.unionTagTypeSafety(mod)) |tag_ty| field: {
6931 const layout = union_ty.unionGetLayout(mod);6917 const layout = union_ty.unionGetLayout(mod);
6932 if (layout.tag_size != 0) {6918 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
6935 var tag_pl: Value.Payload.U32 = .{6921 var tag_pl: Value.Payload.U32 = .{
6936 .base = .{ .tag = .enum_field_index },6922 .base = .{ .tag = .enum_field_index },
src/codegen/llvm.zig+28-36
...@@ -1516,30 +1516,25 @@ pub const Object = struct {...@@ -1516,30 +1516,25 @@ pub const Object = struct {
1516 return enum_di_ty;1516 return enum_di_ty;
1517 }1517 }
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);
1522 defer gpa.free(enumerators);1523 defer gpa.free(enumerators);
15231524
1524 var buf_field_index: Value.Payload.U32 = .{1525 const int_ty = enum_type.tag_ty.toType();
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);
1531 const int_info = ty.intInfo(mod);1526 const int_info = ty.intInfo(mod);
1532 assert(int_info.bits != 0);1527 assert(int_info.bits != 0);
15331528
1534 for (field_names, 0..) |field_name, i| {1529 for (enum_type.names, 0..) |field_name_ip, i| {
1535 const field_name_z = try gpa.dupeZ(u8, field_name);1530 const field_name_z = ip.stringToSlice(field_name_ip);
1536 defer gpa.free(field_name_z);
15371531
1538 buf_field_index.data = @intCast(u32, i);1532 var bigint_space: InternPool.Key.Int.Storage.BigIntSpace = undefined;
1539 const field_int_val = try field_index_val.enumToInt(ty, mod);1533 const storage = if (enum_type.values.len != 0)
15401534 ip.indexToKey(enum_type.values[i]).int.storage
1541 var bigint_space: Value.BigIntSpace = undefined;1535 else
1542 const bigint = field_int_val.toBigInt(&bigint_space, mod);1536 InternPool.Key.Int.Storage{ .u64 = i };
1537 const bigint = storage.toBigInt(&bigint_space);
15431538
1544 if (bigint.limbs.len == 1) {1539 if (bigint.limbs.len == 1) {
1545 enumerators[i] = dib.createEnumerator(field_name_z, bigint.limbs[0], int_info.signedness == .unsigned);1540 enumerators[i] = dib.createEnumerator(field_name_z, bigint.limbs[0], int_info.signedness == .unsigned);
...@@ -8852,23 +8847,22 @@ pub const FuncGen = struct {...@@ -8852,23 +8847,22 @@ pub const FuncGen = struct {
88528847
8853 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {8848 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {
8854 const mod = self.dg.module;8849 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
8857 // TODO: detect when the type changes and re-emit this function.8852 // 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);
8859 if (gop.found_existing) return gop.value_ptr.*;8854 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
8862 var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);8857 var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);
8863 defer arena_allocator.deinit();8858 defer arena_allocator.deinit();
8864 const arena = arena_allocator.allocator();8859 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);
8867 defer self.gpa.free(fqn);8862 defer self.gpa.free(fqn);
8868 const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_is_named_enum_value_{s}", .{fqn});8863 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);8865 const param_types = [_]*llvm.Type{try self.dg.lowerType(enum_type.tag_ty.toType())};
8871 const param_types = [_]*llvm.Type{try self.dg.lowerType(int_tag_ty)};
88728866
8873 const llvm_ret_ty = try self.dg.lowerType(Type.bool);8867 const llvm_ret_ty = try self.dg.lowerType(Type.bool);
8874 const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);8868 const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);
...@@ -8891,13 +8885,12 @@ pub const FuncGen = struct {...@@ -8891,13 +8885,12 @@ pub const FuncGen = struct {
8891 self.builder.positionBuilderAtEnd(entry_block);8885 self.builder.positionBuilderAtEnd(entry_block);
8892 self.builder.clearCurrentDebugLocation();8886 self.builder.clearCurrentDebugLocation();
88938887
8894 const fields = enum_ty.enumFields();
8895 const named_block = self.context.appendBasicBlock(fn_val, "Named");8888 const named_block = self.context.appendBasicBlock(fn_val, "Named");
8896 const unnamed_block = self.context.appendBasicBlock(fn_val, "Unnamed");8889 const unnamed_block = self.context.appendBasicBlock(fn_val, "Unnamed");
8897 const tag_int_value = fn_val.getParam(0);8890 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| {
8901 const this_tag_int_value = int: {8894 const this_tag_int_value = int: {
8902 var tag_val_payload: Value.Payload.U32 = .{8895 var tag_val_payload: Value.Payload.U32 = .{
8903 .base = .{ .tag = .enum_field_index },8896 .base = .{ .tag = .enum_field_index },
...@@ -8930,18 +8923,18 @@ pub const FuncGen = struct {...@@ -8930,18 +8923,18 @@ pub const FuncGen = struct {
89308923
8931 fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {8924 fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {
8932 const mod = self.dg.module;8925 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
8935 // TODO: detect when the type changes and re-emit this function.8928 // 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);
8937 if (gop.found_existing) return gop.value_ptr.*;8930 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
8940 var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);8933 var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);
8941 defer arena_allocator.deinit();8934 defer arena_allocator.deinit();
8942 const arena = arena_allocator.allocator();8935 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);
8945 defer self.gpa.free(fqn);8938 defer self.gpa.free(fqn);
8946 const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn});8939 const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn});
89478940
...@@ -8950,8 +8943,7 @@ pub const FuncGen = struct {...@@ -8950,8 +8943,7 @@ pub const FuncGen = struct {
8950 const usize_llvm_ty = try self.dg.lowerType(Type.usize);8943 const usize_llvm_ty = try self.dg.lowerType(Type.usize);
8951 const slice_alignment = slice_ty.abiAlignment(mod);8944 const slice_alignment = slice_ty.abiAlignment(mod);
89528945
8953 const int_tag_ty = try enum_ty.intTagType(mod);8946 const param_types = [_]*llvm.Type{try self.dg.lowerType(enum_type.tag_ty.toType())};
8954 const param_types = [_]*llvm.Type{try self.dg.lowerType(int_tag_ty)};
89558947
8956 const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);8948 const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);
8957 const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);8949 const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
...@@ -8973,16 +8965,16 @@ pub const FuncGen = struct {...@@ -8973,16 +8965,16 @@ pub const FuncGen = struct {
8973 self.builder.positionBuilderAtEnd(entry_block);8965 self.builder.positionBuilderAtEnd(entry_block);
8974 self.builder.clearCurrentDebugLocation();8966 self.builder.clearCurrentDebugLocation();
89758967
8976 const fields = enum_ty.enumFields();
8977 const bad_value_block = self.context.appendBasicBlock(fn_val, "BadValue");8968 const bad_value_block = self.context.appendBasicBlock(fn_val, "BadValue");
8978 const tag_int_value = fn_val.getParam(0);8969 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
8981 const array_ptr_indices = [_]*llvm.Value{8972 const array_ptr_indices = [_]*llvm.Value{
8982 usize_llvm_ty.constNull(), usize_llvm_ty.constNull(),8973 usize_llvm_ty.constNull(), usize_llvm_ty.constNull(),
8983 };8974 };
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);
8986 const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False);8978 const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False);
8987 const str_init_llvm_ty = str_init.typeOf();8979 const str_init_llvm_ty = str_init.typeOf();
8988 const str_global = self.dg.object.llvm_module.addGlobal(str_init_llvm_ty, "");8980 const str_global = self.dg.object.llvm_module.addGlobal(str_init_llvm_ty, "");
...@@ -9429,7 +9421,7 @@ pub const FuncGen = struct {...@@ -9429,7 +9421,7 @@ pub const FuncGen = struct {
9429 const tag_int = blk: {9421 const tag_int = blk: {
9430 const tag_ty = union_ty.unionTagTypeHypothetical(mod);9422 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
9431 const union_field_name = union_obj.fields.keys()[extra.field_index];9423 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).?;
9433 var tag_val_payload: Value.Payload.U32 = .{9425 var tag_val_payload: Value.Payload.U32 = .{
9434 .base = .{ .tag = .enum_field_index },9426 .base = .{ .tag = .enum_field_index },
9435 .data = @intCast(u32, enum_field_index),9427 .data = @intCast(u32, enum_field_index),
src/link/Dwarf.zig+8-13
...@@ -401,14 +401,9 @@ pub const DeclState = struct {...@@ -401,14 +401,9 @@ pub const DeclState = struct {
401 dbg_info_buffer.appendSliceAssumeCapacity(enum_name);401 dbg_info_buffer.appendSliceAssumeCapacity(enum_name);
402 dbg_info_buffer.appendAssumeCapacity(0);402 dbg_info_buffer.appendAssumeCapacity(0);
403403
404 const fields = ty.enumFields();404 const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
405 const values: ?Module.EnumFull.ValueMap = switch (ty.tag()) {405 for (enum_type.names, 0..) |field_name_index, field_i| {
406 .enum_full, .enum_nonexhaustive => ty.cast(Type.Payload.EnumFull).?.data.values,406 const field_name = mod.intern_pool.stringToSlice(field_name_index);
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| {
412 // DW.AT.enumerator407 // DW.AT.enumerator
413 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64));408 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64));
414 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.enum_variant));409 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.enum_variant));
...@@ -416,14 +411,14 @@ pub const DeclState = struct {...@@ -416,14 +411,14 @@ pub const DeclState = struct {
416 dbg_info_buffer.appendSliceAssumeCapacity(field_name);411 dbg_info_buffer.appendSliceAssumeCapacity(field_name);
417 dbg_info_buffer.appendAssumeCapacity(0);412 dbg_info_buffer.appendAssumeCapacity(0);
418 // DW.AT.const_value, DW.FORM.data8413 // DW.AT.const_value, DW.FORM.data8
419 const value: u64 = if (values) |vals| value: {414 const value: u64 = value: {
420 if (vals.count() == 0) break :value @intCast(u64, field_i); // auto-numbered415 if (enum_type.values.len == 0) break :value field_i; // auto-numbered
421 const value = vals.keys()[field_i];416 const value = enum_type.values[field_i];
422 // TODO do not assume a 64bit enum value - could be bigger.417 // TODO do not assume a 64bit enum value - could be bigger.
423 // See https://github.com/ziglang/zig/issues/645418 // 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);
425 break :value @bitCast(u64, field_int_val.toSignedInt(mod));420 break :value @bitCast(u64, field_int_val.toSignedInt(mod));
426 } else @intCast(u64, field_i);421 };
427 mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian);422 mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian);
428 }423 }
429424
src/type.zig+89-313
...@@ -62,12 +62,6 @@ pub const Type = struct {...@@ -62,12 +62,6 @@ pub const Type = struct {
62 .tuple,62 .tuple,
63 .anon_struct,63 .anon_struct,
64 => return .Struct,64 => return .Struct,
65
66 .enum_full,
67 .enum_nonexhaustive,
68 .enum_simple,
69 .enum_numbered,
70 => return .Enum,
71 },65 },
72 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {66 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
73 .int_type => return .Int,67 .int_type => return .Int,
...@@ -566,22 +560,6 @@ pub const Type = struct {...@@ -566,22 +560,6 @@ pub const Type = struct {
566560
567 return true;561 return true;
568 },562 },
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 },
585 }563 }
586 }564 }
587565
...@@ -727,22 +705,6 @@ pub const Type = struct {...@@ -727,22 +705,6 @@ pub const Type = struct {
727 field_val.hash(field_ty, hasher, mod);705 field_val.hash(field_ty, hasher, mod);
728 }706 }
729 },707 },
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 },
746 }708 }
747 }709 }
748710
...@@ -920,9 +882,6 @@ pub const Type = struct {...@@ -920,9 +882,6 @@ pub const Type = struct {
920 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),882 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
921 .error_set_inferred => return self.copyPayloadShallow(allocator, Payload.ErrorSetInferred),883 .error_set_inferred => return self.copyPayloadShallow(allocator, Payload.ErrorSetInferred),
922 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),884 .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),
926 }885 }
927 }886 }
928887
...@@ -995,25 +954,6 @@ pub const Type = struct {...@@ -995,25 +954,6 @@ pub const Type = struct {
995 while (true) {954 while (true) {
996 const t = ty.tag();955 const t = ty.tag();
997 switch (t) {956 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
1017 .function => {957 .function => {
1018 const payload = ty.castTag(.function).?.data;958 const payload = ty.castTag(.function).?.data;
1019 try writer.writeAll("fn(");959 try writer.writeAll("fn(");
...@@ -1199,22 +1139,6 @@ pub const Type = struct {...@@ -1199,22 +1139,6 @@ pub const Type = struct {
1199 .inferred_alloc_const => unreachable,1139 .inferred_alloc_const => unreachable,
1200 .inferred_alloc_mut => unreachable,1140 .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
1218 .error_set_inferred => {1142 .error_set_inferred => {
1219 const func = ty.castTag(.error_set_inferred).?.data.func;1143 const func = ty.castTag(.error_set_inferred).?.data.func;
12201144
...@@ -1500,7 +1424,10 @@ pub const Type = struct {...@@ -1500,7 +1424,10 @@ pub const Type = struct {
1500 const decl = mod.declPtr(opaque_type.decl);1424 const decl = mod.declPtr(opaque_type.decl);
1501 try decl.renderFullyQualifiedName(mod, writer);1425 try decl.renderFullyQualifiedName(mod, writer);
1502 },1426 },
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
1505 // values, not types1432 // values, not types
1506 .un => unreachable,1433 .un => unreachable,
...@@ -1593,19 +1520,6 @@ pub const Type = struct {...@@ -1593,19 +1520,6 @@ pub const Type = struct {
1593 }1520 }
1594 },1521 },
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
1609 .array => return ty.arrayLen(mod) != 0 and1523 .array => return ty.arrayLen(mod) != 0 and
1610 try ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),1524 try ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
1611 .array_sentinel => return ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),1525 .array_sentinel => return ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
...@@ -1766,7 +1680,7 @@ pub const Type = struct {...@@ -1766,7 +1680,7 @@ pub const Type = struct {
1766 },1680 },
17671681
1768 .opaque_type => true,1682 .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
1771 // values, not types1685 // values, not types
1772 .un => unreachable,1686 .un => unreachable,
...@@ -1789,9 +1703,7 @@ pub const Type = struct {...@@ -1789,9 +1703,7 @@ pub const Type = struct {
1789 .empty_struct_type => false,1703 .empty_struct_type => false,
17901704
1791 .none => switch (ty.tag()) {1705 .none => switch (ty.tag()) {
1792 .pointer,1706 .pointer => true,
1793 .enum_numbered,
1794 => true,
17951707
1796 .error_set,1708 .error_set,
1797 .error_set_single,1709 .error_set_single,
...@@ -1799,17 +1711,12 @@ pub const Type = struct {...@@ -1799,17 +1711,12 @@ pub const Type = struct {
1799 .error_set_merged,1711 .error_set_merged,
1800 // These are function bodies, not function pointers.1712 // These are function bodies, not function pointers.
1801 .function,1713 .function,
1802 .enum_simple,
1803 .error_union,1714 .error_union,
1804 .anyframe_T,1715 .anyframe_T,
1805 .tuple,1716 .tuple,
1806 .anon_struct,1717 .anon_struct,
1807 => false,1718 => false,
18081719
1809 .enum_full,
1810 .enum_nonexhaustive,
1811 => !ty.cast(Payload.EnumFull).?.data.tag_ty_inferred,
1812
1813 .inferred_alloc_mut => unreachable,1720 .inferred_alloc_mut => unreachable,
1814 .inferred_alloc_const => unreachable,1721 .inferred_alloc_const => unreachable,
18151722
...@@ -1886,7 +1793,10 @@ pub const Type = struct {...@@ -1886,7 +1793,10 @@ pub const Type = struct {
1886 .tagged => false,1793 .tagged => false,
1887 },1794 },
1888 .opaque_type => false,1795 .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
1891 // values, not types1801 // values, not types
1892 .un => unreachable,1802 .un => unreachable,
...@@ -2116,11 +2026,6 @@ pub const Type = struct {...@@ -2116,11 +2026,6 @@ pub const Type = struct {
2116 return AbiAlignmentAdvanced{ .scalar = big_align };2026 return AbiAlignmentAdvanced{ .scalar = big_align };
2117 },2027 },
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
2124 .inferred_alloc_const,2029 .inferred_alloc_const,
2125 .inferred_alloc_mut,2030 .inferred_alloc_mut,
2126 => unreachable,2031 => unreachable,
...@@ -2283,7 +2188,7 @@ pub const Type = struct {...@@ -2283,7 +2188,7 @@ pub const Type = struct {
2283 return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());2188 return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());
2284 },2189 },
2285 .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },2190 .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
2288 // values, not types2193 // values, not types
2289 .un => unreachable,2194 .un => unreachable,
...@@ -2475,11 +2380,6 @@ pub const Type = struct {...@@ -2475,11 +2380,6 @@ pub const Type = struct {
2475 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };2380 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };
2476 },2381 },
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
2483 .array => {2383 .array => {
2484 const payload = ty.castTag(.array).?.data;2384 const payload = ty.castTag(.array).?.data;
2485 switch (try payload.elem_type.abiSizeAdvanced(mod, strat)) {2385 switch (try payload.elem_type.abiSizeAdvanced(mod, strat)) {
...@@ -2705,7 +2605,7 @@ pub const Type = struct {...@@ -2705,7 +2605,7 @@ pub const Type = struct {
2705 return abiSizeAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());2605 return abiSizeAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());
2706 },2606 },
2707 .opaque_type => unreachable, // no size available2607 .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
2710 // values, not types2610 // values, not types
2711 .un => unreachable,2611 .un => unreachable,
...@@ -2823,11 +2723,6 @@ pub const Type = struct {...@@ -2823,11 +2723,6 @@ pub const Type = struct {
2823 return total;2723 return total;
2824 },2724 },
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
2831 .array => {2726 .array => {
2832 const payload = ty.castTag(.array).?.data;2727 const payload = ty.castTag(.array).?.data;
2833 const elem_size = std.math.max(payload.elem_type.abiAlignment(mod), payload.elem_type.abiSize(mod));2728 const elem_size = std.math.max(payload.elem_type.abiAlignment(mod), payload.elem_type.abiSize(mod));
...@@ -2964,7 +2859,7 @@ pub const Type = struct {...@@ -2964,7 +2859,7 @@ pub const Type = struct {
2964 return size;2859 return size;
2965 },2860 },
2966 .opaque_type => unreachable,2861 .opaque_type => unreachable,
2967 .enum_type => @panic("TODO"),2862 .enum_type => |enum_type| return bitSizeAdvanced(enum_type.tag_ty.toType(), mod, opt_sema),
29682863
2969 // values, not types2864 // values, not types
2970 .un => unreachable,2865 .un => unreachable,
...@@ -3433,7 +3328,7 @@ pub const Type = struct {...@@ -3433,7 +3328,7 @@ pub const Type = struct {
3433 pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?usize {3328 pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?usize {
3434 const union_obj = mod.typeToUnion(ty).?;3329 const union_obj = mod.typeToUnion(ty).?;
3435 const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, mod) orelse return null;3330 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);
3437 return union_obj.fields.getIndex(name);3332 return union_obj.fields.getIndex(name);
3438 }3333 }
34393334
...@@ -3690,15 +3585,6 @@ pub const Type = struct {...@@ -3690,15 +3585,6 @@ pub const Type = struct {
36903585
3691 while (true) switch (ty.ip_index) {3586 while (true) switch (ty.ip_index) {
3692 .none => switch (ty.tag()) {3587 .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
3702 .error_set, .error_set_single, .error_set_inferred, .error_set_merged => {3588 .error_set, .error_set_single, .error_set_inferred, .error_set_merged => {
3703 // TODO revisit this when error sets support custom int types3589 // TODO revisit this when error sets support custom int types
3704 return .{ .signedness = .unsigned, .bits = 16 };3590 return .{ .signedness = .unsigned, .bits = 16 };
...@@ -3728,7 +3614,7 @@ pub const Type = struct {...@@ -3728,7 +3614,7 @@ pub const Type = struct {
3728 assert(struct_obj.layout == .Packed);3614 assert(struct_obj.layout == .Packed);
3729 ty = struct_obj.backing_int_ty;3615 ty = struct_obj.backing_int_ty;
3730 },3616 },
3731 .enum_type => @panic("TODO"),3617 .enum_type => |enum_type| ty = enum_type.tag_ty.toType(),
37323618
3733 .ptr_type => unreachable,3619 .ptr_type => unreachable,
3734 .array_type => unreachable,3620 .array_type => unreachable,
...@@ -3964,47 +3850,6 @@ pub const Type = struct {...@@ -3964,47 +3850,6 @@ pub const Type = struct {
3964 return Value.empty_struct;3850 return Value.empty_struct;
3965 },3851 },
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
4008 .array => {3853 .array => {
4009 if (ty.arrayLen(mod) == 0)3854 if (ty.arrayLen(mod) == 0)
4010 return Value.initTag(.empty_array);3855 return Value.initTag(.empty_array);
...@@ -4123,7 +3968,28 @@ pub const Type = struct {...@@ -4123,7 +3968,28 @@ pub const Type = struct {
4123 return only.toValue();3968 return only.toValue();
4124 },3969 },
4125 .opaque_type => return null,3970 .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
4128 // values, not types3994 // values, not types
4129 .un => unreachable,3995 .un => unreachable,
...@@ -4151,7 +4017,6 @@ pub const Type = struct {...@@ -4151,7 +4017,6 @@ pub const Type = struct {
4151 .error_set_single,4017 .error_set_single,
4152 .error_set_inferred,4018 .error_set_inferred,
4153 .error_set_merged,4019 .error_set_merged,
4154 .enum_simple,
4155 => false,4020 => false,
41564021
4157 // These are function bodies, not function pointers.4022 // These are function bodies, not function pointers.
...@@ -4191,14 +4056,6 @@ pub const Type = struct {...@@ -4191,14 +4056,6 @@ pub const Type = struct {
4191 const child_ty = ty.castTag(.anyframe_T).?.data;4056 const child_ty = ty.castTag(.anyframe_T).?.data;
4192 return child_ty.comptimeOnly(mod);4057 return child_ty.comptimeOnly(mod);
4193 },4058 },
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 },
4202 },4059 },
4203 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {4060 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
4204 .int_type => false,4061 .int_type => false,
...@@ -4293,7 +4150,7 @@ pub const Type = struct {...@@ -4293,7 +4150,7 @@ pub const Type = struct {
42934150
4294 .opaque_type => false,4151 .opaque_type => false,
42954152
4296 .enum_type => @panic("TODO"),4153 .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod),
42974154
4298 // values, not types4155 // values, not types
4299 .un => unreachable,4156 .un => unreachable,
...@@ -4346,19 +4203,14 @@ pub const Type = struct {...@@ -4346,19 +4203,14 @@ pub const Type = struct {
43464203
4347 /// Returns null if the type has no namespace.4204 /// Returns null if the type has no namespace.
4348 pub fn getNamespaceIndex(ty: Type, mod: *Module) Module.Namespace.OptionalIndex {4205 pub fn getNamespaceIndex(ty: Type, mod: *Module) Module.Namespace.OptionalIndex {
4349 return switch (ty.ip_index) {4206 if (ty.ip_index == .none) return .none;
4350 .none => switch (ty.tag()) {4207 return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
4351 .enum_full => ty.castTag(.enum_full).?.data.namespace.toOptional(),4208 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
4352 .enum_nonexhaustive => ty.castTag(.enum_nonexhaustive).?.data.namespace.toOptional(),4209 .struct_type => |struct_type| struct_type.namespace,
4353 else => .none,4210 .union_type => |union_type| mod.unionPtr(union_type.index).namespace.toOptional(),
4354 },4211 .enum_type => |enum_type| enum_type.namespace,
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(),
43594212
4360 else => .none,4213 else => .none,
4361 },
4362 };4214 };
4363 }4215 }
43644216
...@@ -4444,29 +4296,23 @@ pub const Type = struct {...@@ -4444,29 +4296,23 @@ pub const Type = struct {
44444296
4445 /// Asserts the type is an enum or a union.4297 /// Asserts the type is an enum or a union.
4446 pub fn intTagType(ty: Type, mod: *Module) !Type {4298 pub fn intTagType(ty: Type, mod: *Module) !Type {
4447 return switch (ty.ip_index) {4299 return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
4448 .none => switch (ty.tag()) {4300 .union_type => |union_type| mod.unionPtr(union_type.index).tag_ty.intTagType(mod),
4449 .enum_full, .enum_nonexhaustive => ty.cast(Payload.EnumFull).?.data.tag_ty,4301 .enum_type => |enum_type| enum_type.tag_ty.toType(),
4450 .enum_numbered => ty.castTag(.enum_numbered).?.data.tag_ty,4302 else => unreachable,
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 },
4463 };4303 };
4464 }4304 }
44654305
4466 pub fn isNonexhaustiveEnum(ty: Type) bool {4306 pub fn isNonexhaustiveEnum(ty: Type, mod: *Module) bool {
4467 return switch (ty.tag()) {4307 return switch (ty.ip_index) {
4468 .enum_nonexhaustive => true,4308 .none => false,
4469 else => 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 },
4470 };4316 };
4471 }4317 }
44724318
...@@ -4510,25 +4356,26 @@ pub const Type = struct {...@@ -4510,25 +4356,26 @@ pub const Type = struct {
4510 return try Tag.error_set_merged.create(arena, names);4356 return try Tag.error_set_merged.create(arena, names);
4511 }4357 }
45124358
4513 pub fn enumFields(ty: Type) Module.EnumFull.NameMap {4359 pub fn enumFields(ty: Type, mod: *Module) []const InternPool.NullTerminatedString {
4514 return switch (ty.tag()) {4360 return mod.intern_pool.indexToKey(ty.ip_index).enum_type.names;
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 };
4520 }4361 }
45214362
4522 pub fn enumFieldCount(ty: Type) usize {4363 pub fn enumFieldCount(ty: Type, mod: *Module) usize {
4523 return ty.enumFields().count();4364 return mod.intern_pool.indexToKey(ty.ip_index).enum_type.names.len;
4524 }4365 }
45254366
4526 pub fn enumFieldName(ty: Type, field_index: usize) []const u8 {4367 pub fn enumFieldName(ty: Type, field_index: usize, mod: *Module) [:0]const u8 {
4527 return ty.enumFields().keys()[field_index];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);
4528 }4371 }
45294372
4530 pub fn enumFieldIndex(ty: Type, field_name: []const u8) ?usize {4373 pub fn enumFieldIndex(ty: Type, field_name: []const u8, mod: *Module) ?usize {
4531 return ty.enumFields().getIndex(field_name);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);
4532 }4379 }
45334380
4534 /// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or4381 /// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or
...@@ -4538,50 +4385,20 @@ pub const Type = struct {...@@ -4538,50 +4385,20 @@ pub const Type = struct {
4538 if (enum_tag.castTag(.enum_field_index)) |payload| {4385 if (enum_tag.castTag(.enum_field_index)) |payload| {
4539 return @as(usize, payload.data);4386 return @as(usize, payload.data);
4540 }4387 }
4541 const S = struct {4388 const ip = &mod.intern_pool;
4542 fn fieldWithRange(int_ty: Type, int_val: Value, end: usize, m: *Module) ?usize {4389 const enum_type = ip.indexToKey(ty.ip_index).enum_type;
4543 if (int_val.compareAllWithZero(.lt, m)) return null;4390 const tag_ty = enum_type.tag_ty.toType();
4544 const end_val = m.intValue(int_ty, end) catch |err| switch (err) {4391 if (enum_type.values.len == 0) {
4545 // TODO: eliminate this failure condition4392 if (enum_tag.compareAllWithZero(.lt, mod)) return null;
4546 error.OutOfMemory => @panic("OOM"),4393 const end_val = mod.intValue(tag_ty, enum_type.names.len) catch |err| switch (err) {
4547 };4394 // TODO: eliminate this failure condition
4548 if (int_val.compareScalar(.gte, end_val, int_ty, m)) return null;4395 error.OutOfMemory => @panic("OOM"),
4549 return @intCast(usize, int_val.toUnsignedInt(m));4396 };
4550 }4397 if (enum_tag.compareScalar(.gte, end_val, tag_ty, mod)) return null;
4551 };4398 return @intCast(usize, enum_tag.toUnsignedInt(mod));
4552 switch (ty.tag()) {4399 } else {
4553 .enum_full, .enum_nonexhaustive => {4400 assert(ip.typeOf(enum_tag.ip_index) == enum_type.tag_ty);
4554 const enum_full = ty.cast(Payload.EnumFull).?.data;4401 return enum_type.tagValueIndex(ip.*, enum_tag.ip_index);
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,
4585 }4402 }
4586 }4403 }
45874404
...@@ -4905,18 +4722,6 @@ pub const Type = struct {...@@ -4905,18 +4722,6 @@ pub const Type = struct {
4905 switch (ty.ip_index) {4722 switch (ty.ip_index) {
4906 .empty_struct_type => return null,4723 .empty_struct_type => return null,
4907 .none => switch (ty.tag()) {4724 .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 },
4920 .error_set => {4725 .error_set => {
4921 const error_set = ty.castTag(.error_set).?.data;4726 const error_set = ty.castTag(.error_set).?.data;
4922 return error_set.srcLoc(mod);4727 return error_set.srcLoc(mod);
...@@ -4934,6 +4739,7 @@ pub const Type = struct {...@@ -4934,6 +4739,7 @@ pub const Type = struct {
4934 return union_obj.srcLoc(mod);4739 return union_obj.srcLoc(mod);
4935 },4740 },
4936 .opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type),4741 .opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type),
4742 .enum_type => |enum_type| mod.declPtr(enum_type.decl).srcLoc(mod),
4937 else => null,4743 else => null,
4938 },4744 },
4939 }4745 }
...@@ -4946,15 +4752,6 @@ pub const Type = struct {...@@ -4946,15 +4752,6 @@ pub const Type = struct {
4946 pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?Module.Decl.Index {4752 pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?Module.Decl.Index {
4947 switch (ty.ip_index) {4753 switch (ty.ip_index) {
4948 .none => switch (ty.tag()) {4754 .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 },
4958 .error_set => {4755 .error_set => {
4959 const error_set = ty.castTag(.error_set).?.data;4756 const error_set = ty.castTag(.error_set).?.data;
4960 return error_set.owner_decl;4757 return error_set.owner_decl;
...@@ -4972,6 +4769,7 @@ pub const Type = struct {...@@ -4972,6 +4769,7 @@ pub const Type = struct {
4972 return union_obj.owner_decl;4769 return union_obj.owner_decl;
4973 },4770 },
4974 .opaque_type => |opaque_type| opaque_type.decl,4771 .opaque_type => |opaque_type| opaque_type.decl,
4772 .enum_type => |enum_type| enum_type.decl,
4975 else => null,4773 else => null,
4976 },4774 },
4977 }4775 }
...@@ -5012,10 +4810,6 @@ pub const Type = struct {...@@ -5012,10 +4810,6 @@ pub const Type = struct {
5012 /// The type is the inferred error set of a specific function.4810 /// The type is the inferred error set of a specific function.
5013 error_set_inferred,4811 error_set_inferred,
5014 error_set_merged,4812 error_set_merged,
5015 enum_simple,
5016 enum_numbered,
5017 enum_full,
5018 enum_nonexhaustive,
50194813
5020 pub const last_no_payload_tag = Tag.inferred_alloc_const;4814 pub const last_no_payload_tag = Tag.inferred_alloc_const;
5021 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;4815 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
...@@ -5040,9 +4834,6 @@ pub const Type = struct {...@@ -5040,9 +4834,6 @@ pub const Type = struct {
5040 .function => Payload.Function,4834 .function => Payload.Function,
5041 .error_union => Payload.ErrorUnion,4835 .error_union => Payload.ErrorUnion,
5042 .error_set_single => Payload.Name,4836 .error_set_single => Payload.Name,
5043 .enum_full, .enum_nonexhaustive => Payload.EnumFull,
5044 .enum_simple => Payload.EnumSimple,
5045 .enum_numbered => Payload.EnumNumbered,
5046 .tuple => Payload.Tuple,4837 .tuple => Payload.Tuple,
5047 .anon_struct => Payload.AnonStruct,4838 .anon_struct => Payload.AnonStruct,
5048 };4839 };
...@@ -5341,21 +5132,6 @@ pub const Type = struct {...@@ -5341,21 +5132,6 @@ pub const Type = struct {
5341 values: []Value,5132 values: []Value,
5342 };5133 };
5343 };5134 };
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 };
5359 };5135 };
53605136
5361 pub const @"u1": Type = .{ .ip_index = .u1_type, .legacy = undefined };5137 pub const @"u1": Type = .{ .ip_index = .u1_type, .legacy = undefined };
src/value.zig+16-46
...@@ -675,80 +675,50 @@ pub const Value = struct {...@@ -675,80 +675,50 @@ pub const Value = struct {
675 const field_index = switch (val.tag()) {675 const field_index = switch (val.tag()) {
676 .enum_field_index => val.castTag(.enum_field_index).?.data,676 .enum_field_index => val.castTag(.enum_field_index).?.data,
677 .the_only_possible_value => blk: {677 .the_only_possible_value => blk: {
678 assert(ty.enumFieldCount() == 1);678 assert(ty.enumFieldCount(mod) == 1);
679 break :blk 0;679 break :blk 0;
680 },680 },
681 .enum_literal => i: {681 .enum_literal => i: {
682 const name = val.castTag(.enum_literal).?.data;682 const name = val.castTag(.enum_literal).?.data;
683 break :i ty.enumFieldIndex(name).?;683 break :i ty.enumFieldIndex(name, mod).?;
684 },684 },
685 // Assume it is already an integer and return it directly.685 // Assume it is already an integer and return it directly.
686 else => return val,686 else => return val,
687 };687 };
688688
689 switch (ty.tag()) {689 const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
690 .enum_full, .enum_nonexhaustive => {690 if (enum_type.values.len != 0) {
691 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;691 return enum_type.values[field_index].toValue();
692 if (enum_full.values.count() != 0) {692 } else {
693 return enum_full.values.keys()[field_index];693 // Field index and integer values are the same.
694 } else {694 return mod.intValue(enum_type.tag_ty.toType(), field_index);
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,
714 }695 }
715 }696 }
716697
717 pub fn tagName(val: Value, ty: Type, mod: *Module) []const u8 {698 pub fn tagName(val: Value, ty: Type, mod: *Module) []const u8 {
718 if (ty.zigTypeTag(mod) == .Union) return val.unionTag().tagName(ty.unionTagTypeHypothetical(mod), mod);699 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
720 const field_index = switch (val.tag()) {703 const field_index = switch (val.tag()) {
721 .enum_field_index => val.castTag(.enum_field_index).?.data,704 .enum_field_index => val.castTag(.enum_field_index).?.data,
722 .the_only_possible_value => blk: {705 .the_only_possible_value => blk: {
723 assert(ty.enumFieldCount() == 1);706 assert(ty.enumFieldCount(mod) == 1);
724 break :blk 0;707 break :blk 0;
725 },708 },
726 .enum_literal => return val.castTag(.enum_literal).?.data,709 .enum_literal => return val.castTag(.enum_literal).?.data,
727 else => field_index: {710 else => field_index: {
728 const values = switch (ty.tag()) {711 if (enum_type.values.len == 0) {
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) {
735 // auto-numbered enum712 // auto-numbered enum
736 break :field_index @intCast(u32, val.toUnsignedInt(mod));713 break :field_index @intCast(u32, val.toUnsignedInt(mod));
737 }714 }
738 const int_tag_ty = ty.intTagType(mod) catch |err| switch (err) {715 const field_index = enum_type.tagValueIndex(mod.intern_pool, val.ip_index).?;
739 error.OutOfMemory => @panic("OOM"), // TODO handle this failure716 break :field_index @intCast(u32, field_index);
740 };
741 break :field_index @intCast(u32, values.getIndexContext(val, .{ .ty = int_tag_ty, .mod = mod }).?);
742 },717 },
743 };718 };
744719
745 const fields = switch (ty.tag()) {720 const field_name = enum_type.names[field_index];
746 .enum_full, .enum_nonexhaustive => ty.cast(Type.Payload.EnumFull).?.data.fields,721 return mod.intern_pool.stringToSlice(field_name);
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];
752 }722 }
753723
754 /// Asserts the value is an integer.724 /// Asserts the value is an integer.