aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2024-06-18 23:07:01 +0300
committerGitHub <noreply@github.com>2024-06-18 23:07:01 +0300
commit7dc52a367ae6bf7d9adbe72f1d3c34103c3c6a4f (patch)
tree4c10fee4af96038ac3325f1817dc73847cc92bf6 /lib/std
parent04e08ea883f94d2de7a91daee72ccc9613a18a43 (diff)
parent0ffeec4b4d3c0321cac618557e829571fa997881 (diff)
downloadzig-7dc52a367ae6bf7d9adbe72f1d3c34103c3c6a4f.tar.gz
zig-7dc52a367ae6bf7d9adbe72f1d3c34103c3c6a4f.zip
Merge pull request #20343 from rohlem/std-fix-recursive-union-eql
fix `std.testing.expectEqual`, `std.meta.eql` for `comptime`-only unions
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/meta.zig22
-rw-r--r--lib/std/testing.zig26
2 files changed, 28 insertions, 20 deletions
diff --git a/lib/std/meta.zig b/lib/std/meta.zig
index 0fff0aed3c..85eb6cd4d3 100644
--- a/lib/std/meta.zig
+++ b/lib/std/meta.zig
@@ -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 {
diff --git a/lib/std/testing.zig b/lib/std/testing.zig
index 051b6becee..341161a64b 100644
--- a/lib/std/testing.zig
+++ b/lib/std/testing.zig
@@ -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)));