Merge pull request #20343 from rohlem/std-fix-recursive-union-eql
fix `std.testing.expectEqual`, `std.meta.eql` for `comptime`-only unions
This commit is contained in:
@@ -757,16 +757,13 @@ pub fn eql(a: anytype, b: @TypeOf(a)) bool {
|
||||
},
|
||||
.Union => |info| {
|
||||
if (info.tag_type) |UnionTag| {
|
||||
const tag_a = activeTag(a);
|
||||
const tag_b = activeTag(b);
|
||||
const tag_a: UnionTag = a;
|
||||
const tag_b: UnionTag = b;
|
||||
if (tag_a != tag_b) return false;
|
||||
|
||||
inline for (info.fields) |field_info| {
|
||||
if (@field(UnionTag, field_info.name) == tag_a) {
|
||||
return eql(@field(a, field_info.name), @field(b, field_info.name));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return switch (a) {
|
||||
inline else => |val, tag| return eql(val, @field(b, @tagName(tag))),
|
||||
};
|
||||
}
|
||||
|
||||
@compileError("cannot compare untagged union type " ++ @typeName(T));
|
||||
@@ -858,6 +855,15 @@ test eql {
|
||||
|
||||
try testing.expect(eql(v1, v2));
|
||||
try testing.expect(!eql(v1, v3));
|
||||
|
||||
const CU = union(enum) {
|
||||
a: void,
|
||||
b: void,
|
||||
c: comptime_int,
|
||||
};
|
||||
|
||||
try testing.expect(eql(CU{ .a = {} }, .a));
|
||||
try testing.expect(!eql(CU{ .a = {} }, .b));
|
||||
}
|
||||
|
||||
test intToEnum {
|
||||
|
||||
@@ -147,18 +147,10 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void {
|
||||
|
||||
try expectEqual(expectedTag, actualTag);
|
||||
|
||||
// we only reach this loop if the tags are equal
|
||||
inline for (std.meta.fields(@TypeOf(actual))) |fld| {
|
||||
if (std.mem.eql(u8, fld.name, @tagName(actualTag))) {
|
||||
try expectEqual(@field(expected, fld.name), @field(actual, fld.name));
|
||||
return;
|
||||
}
|
||||
// we only reach this switch if the tags are equal
|
||||
switch (expected) {
|
||||
inline else => |val, tag| try expectEqual(val, @field(actual, @tagName(tag))),
|
||||
}
|
||||
|
||||
// we iterate over *all* union fields
|
||||
// => we should never get here as the loop above is
|
||||
// including all possible values.
|
||||
unreachable;
|
||||
},
|
||||
|
||||
.Optional => {
|
||||
@@ -208,6 +200,16 @@ test "expectEqual.union(enum)" {
|
||||
try expectEqual(a10, a10);
|
||||
}
|
||||
|
||||
test "expectEqual union with comptime-only field" {
|
||||
const U = union(enum) {
|
||||
a: void,
|
||||
b: void,
|
||||
c: comptime_int,
|
||||
};
|
||||
|
||||
try expectEqual(U{ .a = {} }, .a);
|
||||
}
|
||||
|
||||
/// This function is intended to be used only in tests. When the formatted result of the template
|
||||
/// and its arguments does not equal the expected text, it prints diagnostics to stderr to show how
|
||||
/// they are not equal, then returns an error. It depends on `expectEqualStrings()` for printing
|
||||
@@ -809,7 +811,7 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe
|
||||
|
||||
try expectEqual(expectedTag, actualTag);
|
||||
|
||||
// we only reach this loop if the tags are equal
|
||||
// we only reach this switch if the tags are equal
|
||||
switch (expected) {
|
||||
inline else => |val, tag| {
|
||||
try expectEqualDeep(val, @field(actual, @tagName(tag)));
|
||||
|
||||
Reference in New Issue
Block a user