| author | |
| committer | |
| log | 5881a2d63771b070107bdc2325aa1bc455b2d926 |
| tree | 0380faab30356377b721943de57c8b566e9f3744 |
| parent | 404cbc36c52a50975a69e78da716f2258e5b1696 |
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. |
| 41 | maps: std.ArrayListUnmanaged(std.AutoArrayHashMapUnmanaged(void, void)) = .{}, | 41 | maps: std.ArrayListUnmanaged(std.AutoArrayHashMapUnmanaged(void, void)) = .{}, |
| 42 | 42 | ||
| 43 | /// Used for finding the index inside `string_bytes`. | ||
| 44 | string_table: std.HashMapUnmanaged( | ||
| 45 | u32, | ||
| 46 | void, | ||
| 47 | std.hash_map.StringIndexContext, | ||
| 48 | std.hash_map.default_max_load_percentage, | ||
| 49 | ) = .{}, | ||
| 50 | |||
| 43 | const std = @import("std"); | 51 | const std = @import("std"); |
| 44 | const Allocator = std.mem.Allocator; | 52 | const Allocator = std.mem.Allocator; |
| 45 | const assert = std.debug.assert; | 53 | const assert = std.debug.assert; |
| ... | @@ -68,6 +76,11 @@ const KeyAdapter = struct { | ... | @@ -68,6 +76,11 @@ const KeyAdapter = struct { |
| 68 | pub const OptionalMapIndex = enum(u32) { | 76 | pub 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 | }; |
| 72 | 85 | ||
| 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) { |
| 83 | pub const NullTerminatedString = enum(u32) { | 96 | pub const NullTerminatedString = enum(u32) { |
| 84 | _, | 97 | _, |
| 85 | 98 | ||
| 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, |
| 88 | 105 | ||
| ... | @@ -102,6 +119,11 @@ pub const NullTerminatedString = enum(u32) { | ... | @@ -102,6 +119,11 @@ pub const NullTerminatedString = enum(u32) { |
| 102 | pub const OptionalNullTerminatedString = enum(u32) { | 119 | pub 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 | }; |
| 106 | 128 | ||
| 107 | pub const Key = union(enum) { | 129 | pub 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 it | 267 | 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` when | 270 | /// 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 | }; |
| 253 | 337 | ||
| 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); |
| 1304 | 1394 | ||
| 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); |
| 1307 | 1397 | ||
| 1398 | ip.string_table.deinit(gpa); | ||
| 1399 | |||
| 1308 | ip.* = undefined; | 1400 | ip.* = undefined; |
| 1309 | } | 1401 | } |
| 1310 | 1402 | ||
| ... | @@ -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 | }, | ||
| 1451 | 1523 | ||
| 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 | } |
| 1533 | 1605 | ||
| 1606 | fn 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 | |||
| 1534 | fn indexToKeyBigInt(ip: InternPool, limb_index: u32, positive: bool) Key { | 1629 | fn 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); |
| 1698 | 1793 | ||
| 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); | ||
| 1701 | 1798 | ||
| 1702 | const fields_len = @intCast(u32, enum_type.names.len); | 1799 | const fields_len = @intCast(u32, enum_type.names.len); |
| 1703 | 1800 | 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 | }, |
| 1741 | 1818 | ||
| 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 | } |
| 1936 | 2013 | ||
| 1937 | pub 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 }; | 2015 | pub 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. | ||
| 2070 | pub 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 | |||
| 2082 | pub 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 | |||
| 2129 | pub 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 | |||
| 2179 | pub 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 | |||
| 2212 | pub 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 { |
| 1979 | pub fn remove(ip: *InternPool, index: Index) void { | 2254 | pub 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 | } |
| 1984 | 2260 | ||
| ... | @@ -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 | |||
| 2728 | pub 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 | |||
| 2753 | pub 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 | |||
| 2763 | pub 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 | |||
| 2771 | pub 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 | } |
| 913 | 901 | ||
| 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 | } |
| 1137 | 1125 | ||
| 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 | }; |
| 1239 | 1205 | ||
| 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. | ||
| 1244 | pub 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. | ||
| 1265 | pub 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. | ||
| 1293 | pub 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 | |||
| 1344 | pub const Union = struct { | 1206 | pub 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 memory | 1208 | /// 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 | } |
| 1429 | 1291 | ||
| 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 | |||
| 7157 | pub 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); |
| 2097 | 2097 | ||
| 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; |
| 2877 | 2877 | ||
| 2878 | var done = false; | 2878 | // Because these three things each reference each other, `undefined` |
| 2879 | 2879 | // 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(); | ||
| 2883 | 2881 | ||
| 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); |
| 2899 | 2890 | ||
| 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); | ||
| 2920 | 2898 | ||
| 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); |
| 2922 | 2900 | ||
| 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; |
| 2929 | 2907 | ||
| 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 they | 2933 | // 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 | }; |
| 2990 | 2990 | ||
| 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 | } |
| 2996 | 2996 | ||
| 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 comment | 3012 | // doc comment |
| 3024 | extra_index += 1; | 3013 | extra_index += 1; |
| 3025 | 3014 | ||
| 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| { |
| 3028 | 3017 | 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 | else | 3061 | 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 | } |
| 3102 | 3078 | ||
| 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 | } |
| 4357 | 4333 | ||
| 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); |
| 4361 | 4337 | ||
| 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)); |
| 8335 | 8311 | ||
| 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 |
| 8383 | 8359 | ||
| 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() and | 8362 | 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; |
| 10519 | 10495 | ||
| 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 zirSwitchCond | 10520 | .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. |
| 10550 | 10526 | ||
| ... | @@ -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; |
| 10600 | 10576 | ||
| 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; |
| 10619 | 10595 | ||
| 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 and | 11137 | 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; |
| 11630 | 11606 | ||
| 11631 | if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and | 11607 | 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; |
| 16304 | 16280 | ||
| 16305 | const is_exhaustive = Value.makeBool(!ty.isNonexhaustiveEnum()); | 16281 | const is_exhaustive = Value.makeBool(enum_type.tag_mode != .nonexhaustive); |
| 16306 | 16282 | ||
| 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 | }; |
| 16322 | 16298 | ||
| 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()); | ||
| 16325 | 16300 | ||
| 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 alignment | 16311 | 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 | }; |
| 16372 | 16340 | ||
| 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); |
| 16374 | 16342 | ||
| 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 | }; |
| 16470 | 16438 | ||
| 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)); |
| 16472 | 16440 | ||
| 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 | }; |
| 16633 | 16601 | ||
| 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)); |
| 16635 | 16603 | ||
| 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. |
| 16675 | 16643 | ||
| 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)); |
| 16678 | 16646 | ||
| 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(); |
| 16728 | 16696 | ||
| 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 | } |
| 16732 | 16701 | ||
| 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( |
| 17896 | 17865 | ||
| 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); |
| 18002 | 17971 | ||
| 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 but | 18727 | // 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 | } |
| 19083 | 19052 | ||
| 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. | ||
| 19087 | 19061 | ||
| 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); |
| 19109 | 19069 | ||
| 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); | ||
| 19138 | 19084 | ||
| 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 here | 19090 | // TODO use reflection instead of magic numbers here |
| ... | @@ -19148,39 +19095,36 @@ fn zirReify( | ... | @@ -19148,39 +19095,36 @@ fn zirReify( |
| 19148 | 19095 | ||
| 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); | ||
| 19154 | 19102 | ||
| 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 location | 19104 | // 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 | } |
| 19163 | 19111 | ||
| 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 | } |
| 19174 | 19122 | ||
| 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 | } |
| 19190 | 19134 | ||
| 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(); |
| 19308 | 19251 | ||
| 19309 | // Tag type | 19252 | // 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(); |
| 19315 | 19259 | ||
| 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 | } |
| 19324 | 19271 | ||
| 19325 | // Fields | 19272 | // 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); |
| 19327 | 19274 | ||
| 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 here | 19278 | // 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 | ); |
| 19345 | 19291 | ||
| 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 | } |
| 19349 | 19297 | ||
| 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 | } |
| 19362 | 19313 | ||
| 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 | } |
| 19411 | 19362 | ||
| 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); |
| 19417 | 19368 | ||
| 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 | } |
| 19429 | 19384 | ||
| 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( |
| 23450 | 23405 | ||
| 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( |
| 23469 | 23424 | ||
| 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) orelse | 24142 | 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).?); |
| 25000 | 24955 | ||
| 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).?); |
| 25087 | 25042 | ||
| 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 enum | 26146 | // 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( |
| 28707 | 28662 | ||
| 28708 | try sema.requireRuntimeBlock(block, inst_src, null); | 28663 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 28709 | 28664 | ||
| 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, |
| 31610 | 31564 | ||
| 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 { |
| 31760 | 31706 | ||
| 31761 | .opaque_type => false, | 31707 | .opaque_type => false, |
| 31762 | 31708 | ||
| 31763 | .enum_type => @panic("TODO"), | 31709 | .enum_type => |enum_type| try sema.resolveTypeRequiresComptime(enum_type.tag_ty.toType()), |
| 31764 | 31710 | ||
| 31765 | // values, not types | 31711 | // 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); |
| 32290 | 32236 | ||
| 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 |
| 32360 | 32306 | ||
| 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); |
| 32574 | 32520 | ||
| 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 for | 32562 | // 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 analysis | 32568 | // 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 is | 32569 | // 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 | } |
| 32626 | 32573 | ||
| 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; |
| 32677 | 32624 | ||
| 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; |
| 32692 | 32639 | ||
| 32693 | // This puts the memory into the union arena, not the enum arena, but | 32640 | 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 | else | 32644 | 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; |
| 32702 | 32647 | ||
| 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 { |
| 32721 | 32667 | ||
| 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 | } |
| 32727 | 32674 | ||
| 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 | else | 32679 | 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); |
| 32755 | 32702 | ||
| 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 | } |
| 32764 | 32711 | ||
| 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 | } |
| 32781 | 32733 | ||
| 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 | } |
| 32849 | 32801 | ||
| 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); |
| 32855 | 32807 | ||
| 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 | } |
| 32868 | 32826 | ||
| ... | @@ -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 |
| 32874 | fn generateUnionTagTypeNumbered( | 32832 | fn 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; |
| 32882 | 32840 | ||
| 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); |
| 32914 | 32858 | ||
| 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 | } | ||
| 32931 | 32871 | ||
| 32932 | fn 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; | ||
| 32934 | 32873 | ||
| 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(); | ||
| 32938 | 32876 | ||
| 32939 | const enum_obj = try new_decl_arena_allocator.create(Module.EnumSimple); | 32877 | fn 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); | ||
| 32947 | 32884 | ||
| 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 | }; |
| 32970 | 32907 | ||
| 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); |
| 32974 | 32925 | ||
| 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 | } |
| 32984 | 32928 | ||
| 32985 | fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { | 32929 | fn 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 | }, |
| 33100 | 33044 | ||
| 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 | }, | ||
| 33299 | 33213 | ||
| 33300 | // values, not types | 33214 | // 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, |
| 33706 | 33619 | ||
| 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 | }, |
| 33866 | 33771 | ||
| 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()), |
| 33869 | 33774 | ||
| 33870 | // values, not types | 33775 | // 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. |
| 34436 | fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool { | 34341 | fn 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 | } |
| 34475 | 34357 | ||
| 34476 | fn intAddWithOverflow( | 34358 | fn 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 { |
| 6836 | 6815 | ||
| 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] }; |
| 2018 | 2018 | ||
| 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); |
| 2021 | 2021 | ||
| 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.values | 1239 | }, owner_decl_index); |
| 1239 | else | 1240 | } 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).?; |
| 6934 | 6920 | ||
| 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 | } |
| 1518 | 1518 | ||
| 1519 | const field_names = ty.enumFields().keys(); | 1519 | const ip = &mod.intern_pool; |
| 1520 | const enum_type = ip.indexToKey(ty.ip_index).enum_type; | ||
| 1520 | 1521 | ||
| 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); |
| 1523 | 1524 | ||
| 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); |
| 1533 | 1528 | ||
| 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); | ||
| 1537 | 1531 | ||
| 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) |
| 1540 | 1534 | 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); | ||
| 1543 | 1538 | ||
| 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 { |
| 8852 | 8847 | ||
| 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; |
| 8856 | 8851 | ||
| 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)); |
| 8861 | 8856 | ||
| 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(); |
| 8865 | 8860 | ||
| 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}); |
| 8869 | 8864 | ||
| 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)}; | ||
| 8872 | 8866 | ||
| 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(); |
| 8893 | 8887 | ||
| 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)); |
| 8899 | 8892 | ||
| 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 { |
| 8930 | 8923 | ||
| 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; |
| 8934 | 8927 | ||
| 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)); |
| 8939 | 8932 | ||
| 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(); |
| 8943 | 8936 | ||
| 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}); |
| 8947 | 8940 | ||
| ... | @@ -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); |
| 8952 | 8945 | ||
| 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)}; | ||
| 8955 | 8947 | ||
| 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(); |
| 8975 | 8967 | ||
| 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)); |
| 8980 | 8971 | ||
| 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 | }; |
| 8984 | 8975 | ||
| 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); |
| 403 | 403 | ||
| 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.enumerator | 407 | // 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.data8 | 413 | // 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-numbered | 415 | 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/645 | 418 | // 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 | } |
| 429 | 424 |
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 { |
| 566 | 560 | ||
| 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 | } |
| 587 | 565 | ||
| ... | @@ -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 | } |
| 748 | 710 | ||
| ... | @@ -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 | } |
| 928 | 887 | ||
| ... | @@ -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, |
| 1201 | 1141 | ||
| 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; |
| 1220 | 1144 | ||
| ... | @@ -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 | }, | ||
| 1504 | 1431 | ||
| 1505 | // values, not types | 1432 | // 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 | }, |
| 1595 | 1522 | ||
| 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 and | 1523 | .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 | }, |
| 1767 | 1681 | ||
| 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), |
| 1770 | 1684 | ||
| 1771 | // values, not types | 1685 | // 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, |
| 1790 | 1704 | ||
| 1791 | .none => switch (ty.tag()) { | 1705 | .none => switch (ty.tag()) { |
| 1792 | .pointer, | 1706 | .pointer => true, |
| 1793 | .enum_numbered, | ||
| 1794 | => true, | ||
| 1795 | 1707 | ||
| 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, |
| 1808 | 1719 | ||
| 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, |
| 1815 | 1722 | ||
| ... | @@ -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 | }, | ||
| 1890 | 1800 | ||
| 1891 | // values, not types | 1801 | // 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 | }, |
| 2118 | 2028 | ||
| 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) }, |
| 2287 | 2192 | ||
| 2288 | // values, not types | 2193 | // 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 | }, |
| 2477 | 2382 | ||
| 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 available | 2607 | .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) }, |
| 2709 | 2609 | ||
| 2710 | // values, not types | 2610 | // 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 | }, |
| 2825 | 2725 | ||
| 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), |
| 2968 | 2863 | ||
| 2969 | // values, not types | 2864 | // 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 | } |
| 3439 | 3334 | ||
| ... | @@ -3690,15 +3585,6 @@ pub const Type = struct { | ... | @@ -3690,15 +3585,6 @@ pub const Type = struct { |
| 3690 | 3585 | ||
| 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 types | 3589 | // 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(), |
| 3732 | 3618 | ||
| 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 | }, |
| 3966 | 3852 | ||
| 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 | }, | ||
| 4127 | 3993 | ||
| 4128 | // values, not types | 3994 | // 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, |
| 4156 | 4021 | ||
| 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 { |
| 4293 | 4150 | ||
| 4294 | .opaque_type => false, | 4151 | .opaque_type => false, |
| 4295 | 4152 | ||
| 4296 | .enum_type => @panic("TODO"), | 4153 | .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod), |
| 4297 | 4154 | ||
| 4298 | // values, not types | 4155 | // 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 { |
| 4346 | 4203 | ||
| 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(), | ||
| 4359 | 4212 | ||
| 4360 | else => .none, | 4213 | else => .none, |
| 4361 | }, | ||
| 4362 | }; | 4214 | }; |
| 4363 | } | 4215 | } |
| 4364 | 4216 | ||
| ... | @@ -4444,29 +4296,23 @@ pub const Type = struct { | ... | @@ -4444,29 +4296,23 @@ pub const Type = struct { |
| 4444 | 4296 | ||
| 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 | } |
| 4465 | 4305 | ||
| 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 | } |
| 4472 | 4318 | ||
| ... | @@ -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 | } |
| 4512 | 4358 | ||
| 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 | } |
| 4521 | 4362 | ||
| 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 | } |
| 4525 | 4366 | ||
| 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 | } |
| 4529 | 4372 | ||
| 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 | } |
| 4533 | 4380 | ||
| 4534 | /// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or | 4381 | /// 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 condition | 4392 | 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 | } |
| 4587 | 4404 | ||
| ... | @@ -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, | ||
| 5019 | 4813 | ||
| 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 | }; |
| 5360 | 5136 | ||
| 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 | }; |
| 688 | 688 | ||
| 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 | } |
| 716 | 697 | ||
| 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); |
| 719 | 700 | ||
| 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 enum | 712 | // 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 failure | 716 | 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 | }; |
| 744 | 719 | ||
| 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 | } |
| 753 | 723 | ||
| 754 | /// Asserts the value is an integer. | 724 | /// Asserts the value is an integer. |