Commit 8875efe548

Jacob Young <jacobly0@users.noreply.github.com>
2023-06-20 17:40:14
Sema: fix auto-numbered enums with signed tag types
Closes #16095
1 parent 3267eb3
Changed files (2)
src
test
behavior
src/InternPool.zig
@@ -443,18 +443,12 @@ pub const Key = union(enum) {
                 return @intCast(u32, field_index);
             }
             // Auto-numbered enum. Convert `int_tag_val` to field index.
-            switch (ip.indexToKey(int_tag_val).int.storage) {
-                .u64 => |x| {
-                    if (x >= self.names.len) return null;
-                    return @intCast(u32, x);
-                },
-                .i64 => |x| {
-                    if (x >= self.names.len or x < 0) return null;
-                    return @intCast(u32, x);
-                },
-                .big_int => return null, // out of range
+            const field_index = switch (ip.indexToKey(int_tag_val).int.storage) {
+                inline .u64, .i64 => |x| std.math.cast(u32, x) orelse return null,
+                .big_int => |x| x.to(u32) catch return null,
                 .lazy_align, .lazy_size => unreachable,
-            }
+            };
+            return if (field_index < self.names.len) field_index else null;
         }
     };
 
test/behavior/enum.zig
@@ -812,11 +812,6 @@ test "signed integer as enum tag" {
     try expect(@intFromEnum(SignedEnum.A2) == 1);
 }
 
-test "int to enum with signed tag type" {
-    const E = enum(i32) { a, b, c };
-    try expect(@intToEnum(E, 0) == .a);
-}
-
 test "enum with one member and custom tag type" {
     const E = enum(u2) {
         One,
@@ -1202,3 +1197,18 @@ test "enum tag from a local variable" {
     const i = @enumFromInt(S.Int(u32), 0);
     try std.testing.expect(@intFromEnum(i) == 0);
 }
+
+test "auto-numbered enum with signed tag type" {
+    const E = enum(i32) { a, b };
+
+    try std.testing.expectEqual(@as(i32, 0), @intFromEnum(E.a));
+    try std.testing.expectEqual(@as(i32, 1), @intFromEnum(E.b));
+    try std.testing.expectEqual(E.a, @enumFromInt(E, 0));
+    try std.testing.expectEqual(E.b, @enumFromInt(E, 1));
+    try std.testing.expectEqual(E.a, @enumFromInt(E, @as(i32, 0)));
+    try std.testing.expectEqual(E.b, @enumFromInt(E, @as(i32, 1)));
+    try std.testing.expectEqual(E.a, @enumFromInt(E, @as(u32, 0)));
+    try std.testing.expectEqual(E.b, @enumFromInt(E, @as(u32, 1)));
+    try std.testing.expectEqualStrings("a", @tagName(E.a));
+    try std.testing.expectEqualStrings("b", @tagName(E.b));
+}