aboutsummaryrefslogtreecommitdiff
path: root/test/behavior/error.zig
diff options
context:
space:
mode:
Diffstat (limited to 'test/behavior/error.zig')
-rw-r--r--test/behavior/error.zig300
1 files changed, 273 insertions, 27 deletions
diff --git a/test/behavior/error.zig b/test/behavior/error.zig
index d58ad6ccb5..0e3767a4ca 100644
--- a/test/behavior/error.zig
+++ b/test/behavior/error.zig
@@ -1,10 +1,20 @@
const builtin = @import("builtin");
const std = @import("std");
const expect = std.testing.expect;
-const expectError = std.testing.expectError;
const expectEqual = std.testing.expectEqual;
const mem = std.mem;
+/// A more basic implementation of std.testing.expectError which
+/// does not require formatter/printing support
+fn expectError(expected_err: anyerror, observed_err_union: anytype) !void {
+ if (observed_err_union) {
+ return error.TestExpectedError;
+ } else |err| if (err == expected_err) {
+ return; // Success
+ }
+ return error.TestExpectedError;
+}
+
test "error values" {
const a = @errorToInt(error.err1);
const b = @errorToInt(error.err2);
@@ -19,6 +29,8 @@ fn shouldBeNotEqual(a: anyerror, b: anyerror) void {
}
test "error binary operator" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+
const a = errBinaryOperatorG(true) catch 3;
const b = errBinaryOperatorG(false) catch 3;
try expect(a == 3);
@@ -48,10 +60,14 @@ pub fn baz() anyerror!i32 {
}
test "error wrapping" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+
try expect((baz() catch unreachable) == 15);
}
test "unwrap simple value from error" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+
const i = unwrapSimpleValueFromErrorDo() catch unreachable;
try expect(i == 13);
}
@@ -60,6 +76,8 @@ fn unwrapSimpleValueFromErrorDo() anyerror!isize {
}
test "error return in assignment" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+
doErrReturnInAssignment() catch unreachable;
}
@@ -79,6 +97,9 @@ test "syntax: optional operator in front of error union operator" {
}
test "widen cast integer payload of error union function call" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+
const S = struct {
fn errorable() !u64 {
var x = @as(u64, try number());
@@ -93,12 +114,16 @@ test "widen cast integer payload of error union function call" {
}
test "debug info for optional error set" {
- const SomeError = error{Hello};
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
+
+ const SomeError = error{ Hello, Hello2 };
var a_local_variable: ?SomeError = null;
_ = a_local_variable;
}
test "implicit cast to optional to error union to return result loc" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+
const S = struct {
fn entry() !void {
var x: Foo = undefined;
@@ -117,25 +142,49 @@ test "implicit cast to optional to error union to return result loc" {
//comptime S.entry(); TODO
}
-test "error: fn returning empty error set can be passed as fn returning any error" {
+test "fn returning empty error set can be passed as fn returning any error" {
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+
entry();
comptime entry();
}
+test "fn returning empty error set can be passed as fn returning any error - pointer" {
+ if (builtin.zig_backend == .stage1) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+
+ entryPtr();
+ comptime entryPtr();
+}
+
fn entry() void {
foo2(bar2);
}
+fn entryPtr() void {
+ var ptr = &bar2;
+ fooPtr(ptr);
+}
+
fn foo2(f: fn () anyerror!void) void {
const x = f();
- x catch {};
+ x catch {
+ @panic("fail");
+ };
+}
+
+fn fooPtr(f: *const fn () anyerror!void) void {
+ const x = f();
+ x catch {
+ @panic("fail");
+ };
}
fn bar2() (error{}!void) {}
test "error union type " {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
-
try testErrorUnionType();
comptime try testErrorUnionType();
}
@@ -149,8 +198,6 @@ fn testErrorUnionType() !void {
}
test "error set type" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
-
try testErrorSetType();
comptime try testErrorSetType();
}
@@ -174,7 +221,9 @@ fn testErrorSetType() !void {
}
test "explicit error set cast" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
try testExplicitErrorSetCast(Set1.A);
comptime try testExplicitErrorSetCast(Set1.A);
@@ -185,12 +234,15 @@ const Set2 = error{ A, C };
fn testExplicitErrorSetCast(set1: Set1) !void {
var x = @errSetCast(Set2, set1);
+ try expect(@TypeOf(x) == Set2);
var y = @errSetCast(Set1, x);
+ try expect(@TypeOf(y) == Set1);
try expect(y == error.A);
}
test "comptime test error for empty error set" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
try testComptimeTestErrorEmptySet(1234);
comptime try testComptimeTestErrorEmptySet(1234);
@@ -206,7 +258,9 @@ fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) !void {
}
test "comptime err to int of error set with only 1 possible value" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
@@ -220,8 +274,16 @@ fn testErrToIntWithOnePossibleValue(
}
}
+test "inferred empty error set comptime catch" {
+ const S = struct {
+ fn foo() !void {}
+ };
+ S.foo() catch @compileError("fail");
+}
+
test "error union peer type resolution" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
try testErrorUnionPeerTypeResolution(1);
}
@@ -252,10 +314,10 @@ fn quux_1() !i32 {
}
test "error: Zero sized error set returned with value payload crash" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- _ = foo3(0) catch {};
- _ = comptime foo3(0) catch {};
+ _ = try foo3(0);
+ _ = comptime try foo3(0);
}
const Error = error{};
@@ -264,7 +326,8 @@ fn foo3(b: usize) Error!usize {
}
test "error: Infer error set from literals" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
_ = nullLiteral("n") catch |err| handleErrors(err);
_ = floatLiteral("n") catch |err| handleErrors(err);
@@ -301,7 +364,9 @@ fn intLiteral(str: []const u8) !?i64 {
}
test "nested error union function call in optional unwrap" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const S = struct {
const Foo = struct {
@@ -346,7 +411,8 @@ test "nested error union function call in optional unwrap" {
}
test "return function call to error set from error union function" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const S = struct {
fn errorable() anyerror!i32 {
@@ -362,9 +428,11 @@ test "return function call to error set from error union function" {
}
test "optional error set is the same size as error set" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
comptime try expect(@sizeOf(?anyerror) == @sizeOf(anyerror));
+ comptime try expect(@alignOf(?anyerror) == @alignOf(anyerror));
const S = struct {
fn returnsOptErrSet() ?anyerror {
return null;
@@ -375,7 +443,8 @@ test "optional error set is the same size as error set" {
}
test "nested catch" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const S = struct {
fn entry() !void {
@@ -399,11 +468,18 @@ test "nested catch" {
}
test "function pointer with return type that is error union with payload which is pointer of parent struct" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage1) {
+ // stage1 has wrong function pointer semantics
+ return error.SkipZigTest;
+ }
+
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const S = struct {
const Foo = struct {
- fun: fn (a: i32) (anyerror!*Foo),
+ fun: *const fn (a: i32) (anyerror!*Foo),
};
const Err = error{UnspecifiedErr};
@@ -422,7 +498,9 @@ test "function pointer with return type that is error union with payload which i
}
test "return result loc as peer result loc in inferred error set function" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
const S = struct {
fn doTheTest() !void {
@@ -451,7 +529,9 @@ test "return result loc as peer result loc in inferred error set function" {
}
test "error payload type is correctly resolved" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const MyIntWrapper = struct {
const Self = @This();
@@ -463,12 +543,10 @@ test "error payload type is correctly resolved" {
}
};
- try expectEqual(MyIntWrapper{ .x = 42 }, try MyIntWrapper.create());
+ try expect(std.meta.eql(MyIntWrapper{ .x = 42 }, try MyIntWrapper.create()));
}
test "error union comptime caching" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
-
const S = struct {
fn quux(comptime arg: anytype) void {
arg catch {};
@@ -478,3 +556,171 @@ test "error union comptime caching" {
S.quux(@as(anyerror!void, {}));
S.quux(@as(anyerror!void, {}));
}
+
+test "@errorName" {
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+
+ try expect(mem.eql(u8, @errorName(error.AnError), "AnError"));
+ try expect(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
+ try expect(mem.eql(u8, @errorName(gimmeItBroke()), "ItBroke"));
+}
+fn gimmeItBroke() anyerror {
+ return error.ItBroke;
+}
+
+test "@errorName sentinel length matches slice length" {
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+
+ const name = testBuiltinErrorName(error.FooBar);
+ const length: usize = 6;
+ try expect(length == std.mem.indexOfSentinel(u8, 0, name.ptr));
+ try expect(length == name.len);
+}
+
+pub fn testBuiltinErrorName(err: anyerror) [:0]const u8 {
+ return @errorName(err);
+}
+
+test "error set equality" {
+ // This tests using stage2 logic (#11022)
+ if (builtin.zig_backend == .stage1) return error.SkipZigTest;
+
+ const a = error{One};
+ const b = error{One};
+
+ try expect(a == a);
+ try expect(a == b);
+ try expect(a == error{One});
+
+ // should treat as a set
+ const c = error{ One, Two };
+ const d = error{ Two, One };
+
+ try expect(c == d);
+}
+
+test "inferred error set equality" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn foo() !void {
+ return @This().bar();
+ }
+
+ fn bar() !void {
+ return error.Bad;
+ }
+
+ fn baz() !void {
+ return quux();
+ }
+
+ fn quux() anyerror!void {}
+ };
+
+ const FooError = @typeInfo(@typeInfo(@TypeOf(S.foo)).Fn.return_type.?).ErrorUnion.error_set;
+ const BarError = @typeInfo(@typeInfo(@TypeOf(S.bar)).Fn.return_type.?).ErrorUnion.error_set;
+ const BazError = @typeInfo(@typeInfo(@TypeOf(S.baz)).Fn.return_type.?).ErrorUnion.error_set;
+
+ try expect(BarError != error{Bad});
+
+ try expect(FooError != anyerror);
+ try expect(BarError != anyerror);
+ try expect(BazError != anyerror);
+
+ try expect(FooError != BarError);
+ try expect(FooError != BazError);
+ try expect(BarError != BazError);
+
+ try expect(FooError == FooError);
+ try expect(BarError == BarError);
+ try expect(BazError == BazError);
+}
+
+test "peer type resolution of two different error unions" {
+ const a: error{B}!void = {};
+ const b: error{A}!void = {};
+ var cond = true;
+ const err = if (cond) a else b;
+ try err;
+}
+
+test "coerce error set to the current inferred error set" {
+ const S = struct {
+ fn foo() !void {
+ var a = false;
+ if (a) {
+ const b: error{A}!void = error.A;
+ return b;
+ }
+ const b = error.A;
+ return b;
+ }
+ };
+ S.foo() catch {};
+}
+
+test "error union payload is properly aligned" {
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ a: u128,
+ b: u128,
+ c: u128,
+ fn foo() error{}!@This() {
+ return @This(){ .a = 1, .b = 2, .c = 3 };
+ }
+ };
+ const blk = S.foo() catch unreachable;
+ if (blk.a != 1) unreachable;
+}
+
+test "ret_ptr doesn't cause own inferred error set to be resolved" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn foo() !void {}
+
+ fn doTheTest() !void {
+ errdefer @compileError("bad");
+
+ return try @This().foo();
+ }
+ };
+ try S.doTheTest();
+}
+
+test "simple else prong allowed even when all errors handled" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn foo() !u8 {
+ return error.Foo;
+ }
+ };
+ var value = S.foo() catch |err| switch (err) {
+ error.Foo => @as(u8, 255),
+ else => |e| return e,
+ };
+ try expect(value == 255);
+ value = S.foo() catch |err| switch (err) {
+ error.Foo => 255,
+ else => unreachable,
+ };
+ try expect(value == 255);
+ value = S.foo() catch |err| switch (err) {
+ error.Foo => 255,
+ else => return,
+ };
+ try expect(value == 255);
+}