authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2024-06-18 23:07:01+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-06-18 23:07:01+03:00
log7dc52a367ae6bf7d9adbe72f1d3c34103c3c6a4f
tree4c10fee4af96038ac3325f1817dc73847cc92bf6
parent04e08ea883f94d2de7a91daee72ccc9613a18a43
parent0ffeec4b4d3c0321cac618557e829571fa997881
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #20343 from rohlem/std-fix-recursive-union-eql

fix `std.testing.expectEqual`, `std.meta.eql` for `comptime`-only unions

2 files changed, 28 insertions(+), 20 deletions(-)

lib/std/meta.zig+14-8
......@@ -757,16 +757,13 @@ pub fn eql(a: anytype, b: @TypeOf(a)) bool {
757757 },
758758 .Union => |info| {
759759 if (info.tag_type) |UnionTag| {
760 const tag_a = activeTag(a);
761 const tag_b = activeTag(b);
760 const tag_a: UnionTag = a;
761 const tag_b: UnionTag = b;
762762 if (tag_a != tag_b) return false;
763763
764 inline for (info.fields) |field_info| {
765 if (@field(UnionTag, field_info.name) == tag_a) {
766 return eql(@field(a, field_info.name), @field(b, field_info.name));
767 }
768 }
769 return false;
764 return switch (a) {
765 inline else => |val, tag| return eql(val, @field(b, @tagName(tag))),
766 };
770767 }
771768
772769 @compileError("cannot compare untagged union type " ++ @typeName(T));
......@@ -858,6 +855,15 @@ test eql {
858855
859856 try testing.expect(eql(v1, v2));
860857 try testing.expect(!eql(v1, v3));
858
859 const CU = union(enum) {
860 a: void,
861 b: void,
862 c: comptime_int,
863 };
864
865 try testing.expect(eql(CU{ .a = {} }, .a));
866 try testing.expect(!eql(CU{ .a = {} }, .b));
861867}
862868
863869test intToEnum {
lib/std/testing.zig+14-12
......@@ -147,18 +147,10 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void {
147147
148148 try expectEqual(expectedTag, actualTag);
149149
150 // we only reach this loop if the tags are equal
151 inline for (std.meta.fields(@TypeOf(actual))) |fld| {
152 if (std.mem.eql(u8, fld.name, @tagName(actualTag))) {
153 try expectEqual(@field(expected, fld.name), @field(actual, fld.name));
154 return;
155 }
150 // we only reach this switch if the tags are equal
151 switch (expected) {
152 inline else => |val, tag| try expectEqual(val, @field(actual, @tagName(tag))),
156153 }
157
158 // we iterate over *all* union fields
159 // => we should never get here as the loop above is
160 // including all possible values.
161 unreachable;
162154 },
163155
164156 .Optional => {
......@@ -208,6 +200,16 @@ test "expectEqual.union(enum)" {
208200 try expectEqual(a10, a10);
209201}
210202
203test "expectEqual union with comptime-only field" {
204 const U = union(enum) {
205 a: void,
206 b: void,
207 c: comptime_int,
208 };
209
210 try expectEqual(U{ .a = {} }, .a);
211}
212
211213/// This function is intended to be used only in tests. When the formatted result of the template
212214/// and its arguments does not equal the expected text, it prints diagnostics to stderr to show how
213215/// 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
809811
810812 try expectEqual(expectedTag, actualTag);
811813
812 // we only reach this loop if the tags are equal
814 // we only reach this switch if the tags are equal
813815 switch (expected) {
814816 inline else => |val, tag| {
815817 try expectEqualDeep(val, @field(actual, @tagName(tag)));