From 45fad89885fbc6c5e82cf1e7815e25c1d15b8ffa Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Mon, 19 Jun 2023 21:39:35 +0200 Subject: [PATCH 1/2] Fix @enumToInt and @tagName for auto-numbered enums with signed tag type. --- src/InternPool.zig | 6 +++++- test/behavior/enum.zig | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/InternPool.zig b/src/InternPool.zig index 221b56b88aff..a385702c439d 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -448,7 +448,11 @@ pub const Key = union(enum) { if (x >= self.names.len) return null; return @intCast(u32, x); }, - .i64, .big_int => return null, // out of range + .i64 => |x| { + if (x >= self.names.len or x < 0) return null; + return @intCast(u32, x); + }, + .big_int => return null, // out of range .lazy_align, .lazy_size => unreachable, } } diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index 12926800e307..4280a954dce8 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -812,6 +812,11 @@ 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, From 13ebc6113b2dea669205be4f1ec49a02fe73c837 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Tue, 20 Jun 2023 11:40:14 -0400 Subject: [PATCH 2/2] Sema: fix auto-numbered enums with signed tag types Closes #16095 --- src/InternPool.zig | 16 +++++----------- test/behavior/enum.zig | 20 +++++++++++++++----- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/InternPool.zig b/src/InternPool.zig index a385702c439d..f92711d4f1ba 100644 --- a/src/InternPool.zig +++ b/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; } }; diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index 4280a954dce8..1076f5e3ea34 100644 --- a/test/behavior/enum.zig +++ b/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)); +}