Commit e963793e37

Mason Remaley <MasonRemaley@users.noreply.github.com>
2023-05-01 07:03:46
Updates std.meta.intToEnum to support non-exhaustive enums (#15491)
This was preventing `std.json` from deserializing non-exhaustive enums.
1 parent 6ae19fa
Changed files (1)
lib
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;