From e963793e37f93d84f1e5295d309ebe0c738b663d Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Mon, 1 May 2023 01:03:46 -0400 Subject: [PATCH] Updates std.meta.intToEnum to support non-exhaustive enums (#15491) This was preventing `std.json` from deserializing non-exhaustive enums. --- lib/std/meta.zig | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 97c2ff4fb0..7be3b71347 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -965,18 +965,33 @@ test "intToEnum with error return" { A, B, }; + const E3 = enum(i8) { A, _ }; var zero: u8 = 0; var one: u16 = 1; try testing.expect(intToEnum(E1, zero) catch unreachable == E1.A); try testing.expect(intToEnum(E2, one) catch unreachable == E2.B); + try testing.expect(intToEnum(E3, zero) catch unreachable == E3.A); + try testing.expect(intToEnum(E3, 127) catch unreachable == @intToEnum(E3, 127)); + try testing.expect(intToEnum(E3, -128) catch unreachable == @intToEnum(E3, -128)); try testing.expectError(error.InvalidEnumTag, intToEnum(E1, one)); + try testing.expectError(error.InvalidEnumTag, intToEnum(E3, 128)); + try testing.expectError(error.InvalidEnumTag, intToEnum(E3, -129)); } pub const IntToEnumError = error{InvalidEnumTag}; pub fn intToEnum(comptime EnumTag: type, tag_int: anytype) IntToEnumError!EnumTag { - inline for (@typeInfo(EnumTag).Enum.fields) |f| { + const enum_info = @typeInfo(EnumTag).Enum; + + if (!enum_info.is_exhaustive) { + if (std.math.cast(enum_info.tag_type, tag_int)) |tag| { + return @intToEnum(EnumTag, tag); + } + return error.InvalidEnumTag; + } + + inline for (enum_info.fields) |f| { const this_tag_value = @field(EnumTag, f.name); if (tag_int == @enumToInt(this_tag_value)) { return this_tag_value;