aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-10-16 12:41:03 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-10-16 12:41:03 -0700
commitfdd11f6cee7ef14253cef53729e09d9415b4be7e (patch)
tree6de8143acc2874da3464ddb931370f21c71ce3ee /test
parent4d6d6977b05571e6d164dbf5f26c7a48ee3541a3 (diff)
downloadzig-fdd11f6cee7ef14253cef53729e09d9415b4be7e.tar.gz
zig-fdd11f6cee7ef14253cef53729e09d9415b4be7e.zip
Sema: coercion from error sets to `anyerror`
Diffstat (limited to 'test')
-rw-r--r--test/behavior.zig3
-rw-r--r--test/behavior/error.zig429
-rw-r--r--test/behavior/error_stage1.zig428
3 files changed, 430 insertions, 430 deletions
diff --git a/test/behavior.zig b/test/behavior.zig
index ab4e222832..f94f47c703 100644
--- a/test/behavior.zig
+++ b/test/behavior.zig
@@ -30,6 +30,7 @@ test {
_ = @import("behavior/cast.zig");
_ = @import("behavior/defer.zig");
_ = @import("behavior/enum.zig");
+ _ = @import("behavior/error.zig");
_ = @import("behavior/eval.zig");
_ = @import("behavior/for.zig");
_ = @import("behavior/generics.zig");
@@ -116,7 +117,7 @@ test {
_ = @import("behavior/const_slice_child.zig");
_ = @import("behavior/defer_stage1.zig");
_ = @import("behavior/enum_stage1.zig");
- _ = @import("behavior/error.zig");
+ _ = @import("behavior/error_stage1.zig");
_ = @import("behavior/eval_stage1.zig");
_ = @import("behavior/field_parent_ptr.zig");
_ = @import("behavior/floatop.zig");
diff --git a/test/behavior/error.zig b/test/behavior/error.zig
index 74bf105799..fe647ee7c5 100644
--- a/test/behavior/error.zig
+++ b/test/behavior/error.zig
@@ -4,33 +4,6 @@ const expectError = std.testing.expectError;
const expectEqual = std.testing.expectEqual;
const mem = std.mem;
-pub fn foo() anyerror!i32 {
- const x = try bar();
- return x + 1;
-}
-
-pub fn bar() anyerror!i32 {
- return 13;
-}
-
-pub fn baz() anyerror!i32 {
- const y = foo() catch 1234;
- return y + 1;
-}
-
-test "error wrapping" {
- try expect((baz() catch unreachable) == 15);
-}
-
-fn gimmeItBroke() []const u8 {
- return @errorName(error.ItBroke);
-}
-
-test "@errorName" {
- try expect(mem.eql(u8, @errorName(error.AnError), "AnError"));
- try expect(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
-}
-
test "error values" {
const a = @errorToInt(error.err1);
const b = @errorToInt(error.err2);
@@ -54,409 +27,7 @@ fn errBinaryOperatorG(x: bool) anyerror!isize {
return if (x) error.ItBroke else @as(isize, 10);
}
-test "unwrap simple value from error" {
- const i = unwrapSimpleValueFromErrorDo() catch unreachable;
- try expect(i == 13);
-}
-fn unwrapSimpleValueFromErrorDo() anyerror!isize {
- return 13;
-}
-
-test "error return in assignment" {
- doErrReturnInAssignment() catch unreachable;
-}
-
-fn doErrReturnInAssignment() anyerror!void {
- var x: i32 = undefined;
- x = try makeANonErr();
-}
-
-fn makeANonErr() anyerror!i32 {
- return 1;
-}
-
-test "error union type " {
- try testErrorUnionType();
- comptime try testErrorUnionType();
-}
-
-fn testErrorUnionType() !void {
- const x: anyerror!i32 = 1234;
- if (x) |value| try expect(value == 1234) else |_| unreachable;
- try expect(@typeInfo(@TypeOf(x)) == .ErrorUnion);
- try expect(@typeInfo(@typeInfo(@TypeOf(x)).ErrorUnion.error_set) == .ErrorSet);
- try expect(@typeInfo(@TypeOf(x)).ErrorUnion.error_set == anyerror);
-}
-
-test "error set type" {
- try testErrorSetType();
- comptime try testErrorSetType();
-}
-
-const MyErrSet = error{
- OutOfMemory,
- FileNotFound,
-};
-
-fn testErrorSetType() !void {
- try expect(@typeInfo(MyErrSet).ErrorSet.?.len == 2);
-
- const a: MyErrSet!i32 = 5678;
- const b: MyErrSet!i32 = MyErrSet.OutOfMemory;
- try expect(b catch error.OutOfMemory == error.OutOfMemory);
-
- if (a) |value| try expect(value == 5678) else |err| switch (err) {
- error.OutOfMemory => unreachable,
- error.FileNotFound => unreachable,
- }
-}
-
-test "explicit error set cast" {
- try testExplicitErrorSetCast(Set1.A);
- comptime try testExplicitErrorSetCast(Set1.A);
-}
-
-const Set1 = error{
- A,
- B,
-};
-const Set2 = error{
- A,
- C,
-};
-
-fn testExplicitErrorSetCast(set1: Set1) !void {
- var x = @errSetCast(Set2, set1);
- var y = @errSetCast(Set1, x);
- try expect(y == error.A);
-}
-
-test "comptime test error for empty error set" {
- try testComptimeTestErrorEmptySet(1234);
- comptime try testComptimeTestErrorEmptySet(1234);
-}
-
-const EmptyErrorSet = error{};
-
-fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) !void {
- if (x) |v| try expect(v == 1234) else |err| {
- _ = err;
- @compileError("bad");
- }
-}
-
-test "syntax: optional operator in front of error union operator" {
- comptime {
- try expect(?(anyerror!i32) == ?(anyerror!i32));
- }
-}
-
-test "comptime err to int of error set with only 1 possible value" {
- testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
- comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
-}
-fn testErrToIntWithOnePossibleValue(
- x: error{A},
- comptime value: u32,
-) void {
- if (@errorToInt(x) != value) {
- @compileError("bad");
- }
-}
-
test "empty error union" {
const x = error{} || error{};
_ = x;
}
-
-test "error union peer type resolution" {
- try testErrorUnionPeerTypeResolution(1);
-}
-
-fn testErrorUnionPeerTypeResolution(x: i32) !void {
- const y = switch (x) {
- 1 => bar_1(),
- 2 => baz_1(),
- else => quux_1(),
- };
- if (y) |_| {
- @panic("expected error");
- } else |e| {
- try expect(e == error.A);
- }
-}
-
-fn bar_1() anyerror {
- return error.A;
-}
-
-fn baz_1() !i32 {
- return error.B;
-}
-
-fn quux_1() !i32 {
- return error.C;
-}
-
-test "error: fn returning empty error set can be passed as fn returning any error" {
- entry();
- comptime entry();
-}
-
-fn entry() void {
- foo2(bar2);
-}
-
-fn foo2(f: fn () anyerror!void) void {
- const x = f();
- x catch {};
-}
-
-fn bar2() (error{}!void) {}
-
-test "error: Zero sized error set returned with value payload crash" {
- _ = foo3(0) catch {};
- _ = comptime foo3(0) catch {};
-}
-
-const Error = error{};
-fn foo3(b: usize) Error!usize {
- return b;
-}
-
-test "error: Infer error set from literals" {
- _ = nullLiteral("n") catch |err| handleErrors(err);
- _ = floatLiteral("n") catch |err| handleErrors(err);
- _ = intLiteral("n") catch |err| handleErrors(err);
- _ = comptime nullLiteral("n") catch |err| handleErrors(err);
- _ = comptime floatLiteral("n") catch |err| handleErrors(err);
- _ = comptime intLiteral("n") catch |err| handleErrors(err);
-}
-
-fn handleErrors(err: anytype) noreturn {
- switch (err) {
- error.T => {},
- }
-
- unreachable;
-}
-
-fn nullLiteral(str: []const u8) !?i64 {
- if (str[0] == 'n') return null;
-
- return error.T;
-}
-
-fn floatLiteral(str: []const u8) !?f64 {
- if (str[0] == 'n') return 1.0;
-
- return error.T;
-}
-
-fn intLiteral(str: []const u8) !?i64 {
- if (str[0] == 'n') return 1;
-
- return error.T;
-}
-
-test "nested error union function call in optional unwrap" {
- const S = struct {
- const Foo = struct {
- a: i32,
- };
-
- fn errorable() !i32 {
- var x: Foo = (try getFoo()) orelse return error.Other;
- return x.a;
- }
-
- fn errorable2() !i32 {
- var x: Foo = (try getFoo2()) orelse return error.Other;
- return x.a;
- }
-
- fn errorable3() !i32 {
- var x: Foo = (try getFoo3()) orelse return error.Other;
- return x.a;
- }
-
- fn getFoo() anyerror!?Foo {
- return Foo{ .a = 1234 };
- }
-
- fn getFoo2() anyerror!?Foo {
- return error.Failure;
- }
-
- fn getFoo3() anyerror!?Foo {
- return null;
- }
- };
- try expect((try S.errorable()) == 1234);
- try expectError(error.Failure, S.errorable2());
- try expectError(error.Other, S.errorable3());
- comptime {
- try expect((try S.errorable()) == 1234);
- try expectError(error.Failure, S.errorable2());
- try expectError(error.Other, S.errorable3());
- }
-}
-
-test "widen cast integer payload of error union function call" {
- const S = struct {
- fn errorable() !u64 {
- var x = @as(u64, try number());
- return x;
- }
-
- fn number() anyerror!u32 {
- return 1234;
- }
- };
- try expect((try S.errorable()) == 1234);
-}
-
-test "return function call to error set from error union function" {
- const S = struct {
- fn errorable() anyerror!i32 {
- return fail();
- }
-
- fn fail() anyerror {
- return error.Failure;
- }
- };
- try expectError(error.Failure, S.errorable());
- comptime try expectError(error.Failure, S.errorable());
-}
-
-test "optional error set is the same size as error set" {
- comptime try expect(@sizeOf(?anyerror) == @sizeOf(anyerror));
- const S = struct {
- fn returnsOptErrSet() ?anyerror {
- return null;
- }
- };
- try expect(S.returnsOptErrSet() == null);
- comptime try expect(S.returnsOptErrSet() == null);
-}
-
-test "debug info for optional error set" {
- const SomeError = error{Hello};
- var a_local_variable: ?SomeError = null;
- _ = a_local_variable;
-}
-
-test "nested catch" {
- const S = struct {
- fn entry() !void {
- try expectError(error.Bad, func());
- }
- fn fail() anyerror!Foo {
- return error.Wrong;
- }
- fn func() anyerror!Foo {
- _ = fail() catch
- fail() catch
- return error.Bad;
- unreachable;
- }
- const Foo = struct {
- field: i32,
- };
- };
- try S.entry();
- comptime try S.entry();
-}
-
-test "implicit cast to optional to error union to return result loc" {
- const S = struct {
- fn entry() !void {
- var x: Foo = undefined;
- if (func(&x)) |opt| {
- try expect(opt != null);
- } else |_| @panic("expected non error");
- }
- fn func(f: *Foo) anyerror!?*Foo {
- return f;
- }
- const Foo = struct {
- field: i32,
- };
- };
- try S.entry();
- //comptime S.entry(); TODO
-}
-
-test "function pointer with return type that is error union with payload which is pointer of parent struct" {
- const S = struct {
- const Foo = struct {
- fun: fn (a: i32) (anyerror!*Foo),
- };
-
- const Err = error{UnspecifiedErr};
-
- fn bar(a: i32) anyerror!*Foo {
- _ = a;
- return Err.UnspecifiedErr;
- }
-
- fn doTheTest() !void {
- var x = Foo{ .fun = @This().bar };
- try expectError(error.UnspecifiedErr, x.fun(1));
- }
- };
- try S.doTheTest();
-}
-
-test "return result loc as peer result loc in inferred error set function" {
- const S = struct {
- fn doTheTest() !void {
- if (quux(2)) |x| {
- try expect(x.Two);
- } else |e| switch (e) {
- error.Whatever => @panic("fail"),
- }
- try expectError(error.Whatever, quux(99));
- }
- const FormValue = union(enum) {
- One: void,
- Two: bool,
- };
-
- fn quux(id: u64) !FormValue {
- return switch (id) {
- 2 => FormValue{ .Two = true },
- 1 => FormValue{ .One = {} },
- else => return error.Whatever,
- };
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "error payload type is correctly resolved" {
- const MyIntWrapper = struct {
- const Self = @This();
-
- x: i32,
-
- pub fn create() anyerror!Self {
- return Self{ .x = 42 };
- }
- };
-
- try expectEqual(MyIntWrapper{ .x = 42 }, try MyIntWrapper.create());
-}
-
-test "error union comptime caching" {
- const S = struct {
- fn quux(comptime arg: anytype) void {
- arg catch {};
- }
- };
-
- S.quux(@as(anyerror!void, {}));
- S.quux(@as(anyerror!void, {}));
-}
diff --git a/test/behavior/error_stage1.zig b/test/behavior/error_stage1.zig
new file mode 100644
index 0000000000..03186a0aaa
--- /dev/null
+++ b/test/behavior/error_stage1.zig
@@ -0,0 +1,428 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const expectError = std.testing.expectError;
+const expectEqual = std.testing.expectEqual;
+const mem = std.mem;
+
+pub fn foo() anyerror!i32 {
+ const x = try bar();
+ return x + 1;
+}
+
+pub fn bar() anyerror!i32 {
+ return 13;
+}
+
+pub fn baz() anyerror!i32 {
+ const y = foo() catch 1234;
+ return y + 1;
+}
+
+test "error wrapping" {
+ try expect((baz() catch unreachable) == 15);
+}
+
+fn gimmeItBroke() []const u8 {
+ return @errorName(error.ItBroke);
+}
+
+test "@errorName" {
+ try expect(mem.eql(u8, @errorName(error.AnError), "AnError"));
+ try expect(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
+}
+
+test "unwrap simple value from error" {
+ const i = unwrapSimpleValueFromErrorDo() catch unreachable;
+ try expect(i == 13);
+}
+fn unwrapSimpleValueFromErrorDo() anyerror!isize {
+ return 13;
+}
+
+test "error return in assignment" {
+ doErrReturnInAssignment() catch unreachable;
+}
+
+fn doErrReturnInAssignment() anyerror!void {
+ var x: i32 = undefined;
+ x = try makeANonErr();
+}
+
+fn makeANonErr() anyerror!i32 {
+ return 1;
+}
+
+test "error union type " {
+ try testErrorUnionType();
+ comptime try testErrorUnionType();
+}
+
+fn testErrorUnionType() !void {
+ const x: anyerror!i32 = 1234;
+ if (x) |value| try expect(value == 1234) else |_| unreachable;
+ try expect(@typeInfo(@TypeOf(x)) == .ErrorUnion);
+ try expect(@typeInfo(@typeInfo(@TypeOf(x)).ErrorUnion.error_set) == .ErrorSet);
+ try expect(@typeInfo(@TypeOf(x)).ErrorUnion.error_set == anyerror);
+}
+
+test "error set type" {
+ try testErrorSetType();
+ comptime try testErrorSetType();
+}
+
+const MyErrSet = error{
+ OutOfMemory,
+ FileNotFound,
+};
+
+fn testErrorSetType() !void {
+ try expect(@typeInfo(MyErrSet).ErrorSet.?.len == 2);
+
+ const a: MyErrSet!i32 = 5678;
+ const b: MyErrSet!i32 = MyErrSet.OutOfMemory;
+ try expect(b catch error.OutOfMemory == error.OutOfMemory);
+
+ if (a) |value| try expect(value == 5678) else |err| switch (err) {
+ error.OutOfMemory => unreachable,
+ error.FileNotFound => unreachable,
+ }
+}
+
+test "explicit error set cast" {
+ try testExplicitErrorSetCast(Set1.A);
+ comptime try testExplicitErrorSetCast(Set1.A);
+}
+
+const Set1 = error{ A, B };
+const Set2 = error{ A, C };
+
+fn testExplicitErrorSetCast(set1: Set1) !void {
+ var x = @errSetCast(Set2, set1);
+ var y = @errSetCast(Set1, x);
+ try expect(y == error.A);
+}
+
+test "comptime test error for empty error set" {
+ try testComptimeTestErrorEmptySet(1234);
+ comptime try testComptimeTestErrorEmptySet(1234);
+}
+
+const EmptyErrorSet = error{};
+
+fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) !void {
+ if (x) |v| try expect(v == 1234) else |err| {
+ _ = err;
+ @compileError("bad");
+ }
+}
+
+test "syntax: optional operator in front of error union operator" {
+ comptime {
+ try expect(?(anyerror!i32) == ?(anyerror!i32));
+ }
+}
+
+test "comptime err to int of error set with only 1 possible value" {
+ testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
+ comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
+}
+fn testErrToIntWithOnePossibleValue(
+ x: error{A},
+ comptime value: u32,
+) void {
+ if (@errorToInt(x) != value) {
+ @compileError("bad");
+ }
+}
+
+test "error union peer type resolution" {
+ try testErrorUnionPeerTypeResolution(1);
+}
+
+fn testErrorUnionPeerTypeResolution(x: i32) !void {
+ const y = switch (x) {
+ 1 => bar_1(),
+ 2 => baz_1(),
+ else => quux_1(),
+ };
+ if (y) |_| {
+ @panic("expected error");
+ } else |e| {
+ try expect(e == error.A);
+ }
+}
+
+fn bar_1() anyerror {
+ return error.A;
+}
+
+fn baz_1() !i32 {
+ return error.B;
+}
+
+fn quux_1() !i32 {
+ return error.C;
+}
+
+test "error: fn returning empty error set can be passed as fn returning any error" {
+ entry();
+ comptime entry();
+}
+
+fn entry() void {
+ foo2(bar2);
+}
+
+fn foo2(f: fn () anyerror!void) void {
+ const x = f();
+ x catch {};
+}
+
+fn bar2() (error{}!void) {}
+
+test "error: Zero sized error set returned with value payload crash" {
+ _ = foo3(0) catch {};
+ _ = comptime foo3(0) catch {};
+}
+
+const Error = error{};
+fn foo3(b: usize) Error!usize {
+ return b;
+}
+
+test "error: Infer error set from literals" {
+ _ = nullLiteral("n") catch |err| handleErrors(err);
+ _ = floatLiteral("n") catch |err| handleErrors(err);
+ _ = intLiteral("n") catch |err| handleErrors(err);
+ _ = comptime nullLiteral("n") catch |err| handleErrors(err);
+ _ = comptime floatLiteral("n") catch |err| handleErrors(err);
+ _ = comptime intLiteral("n") catch |err| handleErrors(err);
+}
+
+fn handleErrors(err: anytype) noreturn {
+ switch (err) {
+ error.T => {},
+ }
+
+ unreachable;
+}
+
+fn nullLiteral(str: []const u8) !?i64 {
+ if (str[0] == 'n') return null;
+
+ return error.T;
+}
+
+fn floatLiteral(str: []const u8) !?f64 {
+ if (str[0] == 'n') return 1.0;
+
+ return error.T;
+}
+
+fn intLiteral(str: []const u8) !?i64 {
+ if (str[0] == 'n') return 1;
+
+ return error.T;
+}
+
+test "nested error union function call in optional unwrap" {
+ const S = struct {
+ const Foo = struct {
+ a: i32,
+ };
+
+ fn errorable() !i32 {
+ var x: Foo = (try getFoo()) orelse return error.Other;
+ return x.a;
+ }
+
+ fn errorable2() !i32 {
+ var x: Foo = (try getFoo2()) orelse return error.Other;
+ return x.a;
+ }
+
+ fn errorable3() !i32 {
+ var x: Foo = (try getFoo3()) orelse return error.Other;
+ return x.a;
+ }
+
+ fn getFoo() anyerror!?Foo {
+ return Foo{ .a = 1234 };
+ }
+
+ fn getFoo2() anyerror!?Foo {
+ return error.Failure;
+ }
+
+ fn getFoo3() anyerror!?Foo {
+ return null;
+ }
+ };
+ try expect((try S.errorable()) == 1234);
+ try expectError(error.Failure, S.errorable2());
+ try expectError(error.Other, S.errorable3());
+ comptime {
+ try expect((try S.errorable()) == 1234);
+ try expectError(error.Failure, S.errorable2());
+ try expectError(error.Other, S.errorable3());
+ }
+}
+
+test "widen cast integer payload of error union function call" {
+ const S = struct {
+ fn errorable() !u64 {
+ var x = @as(u64, try number());
+ return x;
+ }
+
+ fn number() anyerror!u32 {
+ return 1234;
+ }
+ };
+ try expect((try S.errorable()) == 1234);
+}
+
+test "return function call to error set from error union function" {
+ const S = struct {
+ fn errorable() anyerror!i32 {
+ return fail();
+ }
+
+ fn fail() anyerror {
+ return error.Failure;
+ }
+ };
+ try expectError(error.Failure, S.errorable());
+ comptime try expectError(error.Failure, S.errorable());
+}
+
+test "optional error set is the same size as error set" {
+ comptime try expect(@sizeOf(?anyerror) == @sizeOf(anyerror));
+ const S = struct {
+ fn returnsOptErrSet() ?anyerror {
+ return null;
+ }
+ };
+ try expect(S.returnsOptErrSet() == null);
+ comptime try expect(S.returnsOptErrSet() == null);
+}
+
+test "debug info for optional error set" {
+ const SomeError = error{Hello};
+ var a_local_variable: ?SomeError = null;
+ _ = a_local_variable;
+}
+
+test "nested catch" {
+ const S = struct {
+ fn entry() !void {
+ try expectError(error.Bad, func());
+ }
+ fn fail() anyerror!Foo {
+ return error.Wrong;
+ }
+ fn func() anyerror!Foo {
+ _ = fail() catch
+ fail() catch
+ return error.Bad;
+ unreachable;
+ }
+ const Foo = struct {
+ field: i32,
+ };
+ };
+ try S.entry();
+ comptime try S.entry();
+}
+
+test "implicit cast to optional to error union to return result loc" {
+ const S = struct {
+ fn entry() !void {
+ var x: Foo = undefined;
+ if (func(&x)) |opt| {
+ try expect(opt != null);
+ } else |_| @panic("expected non error");
+ }
+ fn func(f: *Foo) anyerror!?*Foo {
+ return f;
+ }
+ const Foo = struct {
+ field: i32,
+ };
+ };
+ try S.entry();
+ //comptime S.entry(); TODO
+}
+
+test "function pointer with return type that is error union with payload which is pointer of parent struct" {
+ const S = struct {
+ const Foo = struct {
+ fun: fn (a: i32) (anyerror!*Foo),
+ };
+
+ const Err = error{UnspecifiedErr};
+
+ fn bar(a: i32) anyerror!*Foo {
+ _ = a;
+ return Err.UnspecifiedErr;
+ }
+
+ fn doTheTest() !void {
+ var x = Foo{ .fun = @This().bar };
+ try expectError(error.UnspecifiedErr, x.fun(1));
+ }
+ };
+ try S.doTheTest();
+}
+
+test "return result loc as peer result loc in inferred error set function" {
+ const S = struct {
+ fn doTheTest() !void {
+ if (quux(2)) |x| {
+ try expect(x.Two);
+ } else |e| switch (e) {
+ error.Whatever => @panic("fail"),
+ }
+ try expectError(error.Whatever, quux(99));
+ }
+ const FormValue = union(enum) {
+ One: void,
+ Two: bool,
+ };
+
+ fn quux(id: u64) !FormValue {
+ return switch (id) {
+ 2 => FormValue{ .Two = true },
+ 1 => FormValue{ .One = {} },
+ else => return error.Whatever,
+ };
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "error payload type is correctly resolved" {
+ const MyIntWrapper = struct {
+ const Self = @This();
+
+ x: i32,
+
+ pub fn create() anyerror!Self {
+ return Self{ .x = 42 };
+ }
+ };
+
+ try expectEqual(MyIntWrapper{ .x = 42 }, try MyIntWrapper.create());
+}
+
+test "error union comptime caching" {
+ const S = struct {
+ fn quux(comptime arg: anytype) void {
+ arg catch {};
+ }
+ };
+
+ S.quux(@as(anyerror!void, {}));
+ S.quux(@as(anyerror!void, {}));
+}