diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-01-09 13:54:27 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-09 13:54:27 -0800 |
| commit | acca16c8cee4529bcb11c150c2c99b7de32ce21f (patch) | |
| tree | 78900c056830d99f6dfaa849faf23df8d4e53032 /test | |
| parent | dbdee2d53cf22be8bcc9031c1c15a58ce530b131 (diff) | |
| parent | 67d7d7b5a79cd709749f7435e1c3e4ef2e9150be (diff) | |
| download | zig-acca16c8cee4529bcb11c150c2c99b7de32ce21f.tar.gz zig-acca16c8cee4529bcb11c150c2c99b7de32ce21f.zip | |
Merge pull request #18173 from dweiller/switch-err-union
Special-case switching on error union capture
Diffstat (limited to 'test')
9 files changed, 942 insertions, 0 deletions
diff --git a/test/behavior/switch_on_captured_error.zig b/test/behavior/switch_on_captured_error.zig new file mode 100644 index 0000000000..b6b422ba93 --- /dev/null +++ b/test/behavior/switch_on_captured_error.zig @@ -0,0 +1,750 @@ +const std = @import("std"); +const assert = std.debug.assert; +const expect = std.testing.expect; +const expectError = std.testing.expectError; +const expectEqual = std.testing.expectEqual; + +test "switch on error union catch capture" { + const S = struct { + const Error = error{ A, B, C }; + fn doTheTest() !void { + try testScalar(); + try testMulti(); + try testElse(); + try testCapture(); + try testInline(); + try testEmptyErrSet(); + } + + fn testScalar() !void { + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + error.B => 1, + error.C => 2, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + error.B => @intFromError(err) + 4, + error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + error.B => @intFromError(err) + 4, + error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 0), b); + } + } + + fn testMulti() !void { + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A, error.B => 0, + error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + error.B, error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A, error.B => 0, + error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 0), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + error.B, error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 0), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + error.B, error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + } + + fn testElse() !void { + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + else => 1, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 1, + else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 1), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + else => 1, + }; + try expectEqual(@as(u64, 1), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + } + + fn testCapture() !void { + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => |e| @intFromError(e) + 4, + else => 0, + }; + try expectEqual(@as(u64, @intFromError(error.A) + 4), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + else => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, 0), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + else => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => |e| @intFromError(e) + 4, + else => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + error.B, error.C => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + } + + fn testInline() !void { + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + inline else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => |e| @intFromError(e) + 4, + inline else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = a catch |err| switch (err) { + inline else => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.A => 0, + inline error.B, error.C => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + } + + fn testEmptyErrSet() !void { + { + var a: error{}!u64 = 0; + _ = &a; + const b: u64 = a catch |err| switch (err) { + else => |e| return e, + }; + try expectEqual(@as(u64, 0), b); + } + { + var a: error{}!u64 = 0; + _ = &a; + const b: u64 = a catch |err| switch (err) { + error.UnknownError => return error.Fail, + else => |e| return e, + }; + try expectEqual(@as(u64, 0), b); + } + } + }; + + try comptime S.doTheTest(); + try S.doTheTest(); +} + +test "switch on error union if else capture" { + const S = struct { + const Error = error{ A, B, C }; + fn doTheTest() !void { + try testScalar(); + try testScalarPtr(); + try testMulti(); + try testMultiPtr(); + try testElse(); + try testElsePtr(); + try testCapture(); + try testCapturePtr(); + try testInline(); + try testInlinePtr(); + try testEmptyErrSet(); + try testEmptyErrSetPtr(); + } + + fn testScalar() !void { + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + error.B => 1, + error.C => 2, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + error.B => @intFromError(err) + 4, + error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + error.B => @intFromError(err) + 4, + error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 0), b); + } + } + + fn testScalarPtr() !void { + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + error.B => 1, + error.C => 2, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + error.B => @intFromError(err) + 4, + error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + error.B => @intFromError(err) + 4, + error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 0), b); + } + } + + fn testMulti() !void { + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A, error.B => 0, + error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + error.B, error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A, error.B => 0, + error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 0), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + error.B, error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 0), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + error.B, error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + } + + fn testMultiPtr() !void { + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A, error.B => 0, + error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + error.B, error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A, error.B => 0, + error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 0), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + error.B, error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 0), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + error.B, error.C => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + } + + fn testElse() !void { + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + else => 1, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 1, + else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 1), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + else => 1, + }; + try expectEqual(@as(u64, 1), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + } + + fn testElsePtr() !void { + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + else => 1, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = 3; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 3), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 1, + else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, 1), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + else => 1, + }; + try expectEqual(@as(u64, 1), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + } + + fn testCapture() !void { + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => |e| @intFromError(e) + 4, + else => 0, + }; + try expectEqual(@as(u64, @intFromError(error.A) + 4), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + else => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, 0), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + else => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => |e| @intFromError(e) + 4, + else => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + error.B, error.C => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + } + + fn testCapturePtr() !void { + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => |e| @intFromError(e) + 4, + else => 0, + }; + try expectEqual(@as(u64, @intFromError(error.A) + 4), b); + } + { + var a: Error!u64 = error.A; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + else => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, 0), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + else => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => |e| @intFromError(e) + 4, + else => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + error.B, error.C => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + } + + fn testInline() !void { + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + inline else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => |e| @intFromError(e) + 4, + inline else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + inline else => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.A => 0, + inline error.B, error.C => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + } + + fn testInlinePtr() !void { + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + inline else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => |e| @intFromError(e) + 4, + inline else => @intFromError(err) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + inline else => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + { + var a: Error!u64 = error.B; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.A => 0, + inline error.B, error.C => |e| @intFromError(e) + 4, + }; + try expectEqual(@as(u64, @intFromError(error.B) + 4), b); + } + } + + fn testEmptyErrSet() !void { + { + var a: error{}!u64 = 0; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + else => |e| return e, + }; + try expectEqual(@as(u64, 0), b); + } + { + var a: error{}!u64 = 0; + _ = &a; + const b: u64 = if (a) |x| x else |err| switch (err) { + error.UnknownError => return error.Fail, + else => |e| return e, + }; + try expectEqual(@as(u64, 0), b); + } + } + + fn testEmptyErrSetPtr() !void { + { + var a: error{}!u64 = 0; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + else => |e| return e, + }; + try expectEqual(@as(u64, 0), b); + } + { + var a: error{}!u64 = 0; + _ = &a; + const b: u64 = if (a) |*x| x.* else |err| switch (err) { + error.UnknownError => return error.Fail, + else => |e| return e, + }; + try expectEqual(@as(u64, 0), b); + } + } + }; + + try comptime S.doTheTest(); + try S.doTheTest(); +} diff --git a/test/cases/compile_errors/switch_expression-duplicate_error_prong.zig b/test/cases/compile_errors/switch_expression-duplicate_error_prong.zig new file mode 100644 index 0000000000..bcebd25a58 --- /dev/null +++ b/test/cases/compile_errors/switch_expression-duplicate_error_prong.zig @@ -0,0 +1,33 @@ +fn f(n: Error!i32) i32 { + if (n) |x| + _ = x + else |e| switch (e) { + error.Foo => 1, + error.Bar => 2, + error.Baz => 3, + error.Foo => 2, + } +} +fn g(n: Error!i32) i32 { + n catch |e| switch (e) { + error.Foo => 1, + error.Bar => 2, + error.Baz => 3, + error.Foo => 2, + }; +} + +const Error = error{ Foo, Bar, Baz }; + +export fn entry() usize { + return @sizeOf(@TypeOf(&f)) + @sizeOf(@TypeOf(&g)); +} + +// error +// backend=stage2 +// target=native +// +// :8:9: error: duplicate switch value +// :5:9: note: previous value here +// :16:9: error: duplicate switch value +// :13:9: note: previous value here diff --git a/test/cases/compile_errors/switch_expression-duplicate_error_prong_when_else_present.zig b/test/cases/compile_errors/switch_expression-duplicate_error_prong_when_else_present.zig new file mode 100644 index 0000000000..ca156183e0 --- /dev/null +++ b/test/cases/compile_errors/switch_expression-duplicate_error_prong_when_else_present.zig @@ -0,0 +1,35 @@ +fn f(n: Error!i32) i32 { + if (n) |x| + _ = x + else |e| switch (e) { + error.Foo => 1, + error.Bar => 2, + error.Baz => 3, + error.Foo => 2, + else => 10, + } +} +fn g(n: Error!i32) i32 { + n catch |e| switch (e) { + error.Foo => 1, + error.Bar => 2, + error.Baz => 3, + error.Foo => 2, + else => 10, + }; +} + +const Error = error{ Foo, Bar, Baz }; + +export fn entry() usize { + return @sizeOf(@TypeOf(&f)) + @sizeOf(@TypeOf(&g)); +} + +// error +// backend=stage2 +// target=native +// +// :8:9: error: duplicate switch value +// :5:9: note: previous value here +// :17:9: error: duplicate switch value +// :14:9: note: previous value here diff --git a/test/cases/compile_errors/switch_expression-missing_error_prong.zig b/test/cases/compile_errors/switch_expression-missing_error_prong.zig new file mode 100644 index 0000000000..ee28057c43 --- /dev/null +++ b/test/cases/compile_errors/switch_expression-missing_error_prong.zig @@ -0,0 +1,33 @@ +const Error = error { + One, + Two, + Three, + Four, +}; +fn f(n: Error!i32) i32 { + if (n) |x| x else |e| switch (e) { + error.One => 1, + error.Two => 2, + error.Three => 3, + } +} +fn h(n: Error!i32) i32 { + n catch |e| switch (e) { + error.One => 1, + error.Two => 2, + error.Three => 3, + }; +} + +export fn entry() usize { + return @sizeOf(@TypeOf(&f)) + @sizeOf(@TypeOf(&h)); +} + +// error +// backend=stage2 +// target=native +// +// :8:27: error: switch must handle all possibilities +// :8:27: note: unhandled error value: 'error.Four' +// :15:17: error: switch must handle all possibilities +// :15:17: note: unhandled error value: 'error.Four' diff --git a/test/cases/compile_errors/switch_expression-multiple_else_prongs.zig b/test/cases/compile_errors/switch_expression-multiple_else_prongs.zig index f4cdb3b125..a6bb48db17 100644 --- a/test/cases/compile_errors/switch_expression-multiple_else_prongs.zig +++ b/test/cases/compile_errors/switch_expression-multiple_else_prongs.zig @@ -5,8 +5,24 @@ fn f(x: u32) void { else => true, }; } +fn g(x: error{Foo, Bar, Baz}!u32) void { + const value: bool = if (x) |_| true else |e| switch (e) { + error.Foo => false, + else => true, + else => true, + }; +} +fn h(x: error{Foo, Bar, Baz}!u32) void { + const value: u32 = x catch |e| switch (e) { + error.Foo => 1, + else => 2, + else => 3, + }; +} export fn entry() void { f(1234); + g(1234); + h(1234); } // error @@ -15,3 +31,7 @@ export fn entry() void { // // :5:9: error: multiple else prongs in switch expression // :4:9: note: previous else prong here +// :12:9: error: multiple else prongs in switch expression +// :11:9: note: previous else prong here +// :19:9: error: multiple else prongs in switch expression +// :18:9: note: previous else prong here diff --git a/test/cases/compile_errors/switch_expression-unreachable_else_prong_error.zig b/test/cases/compile_errors/switch_expression-unreachable_else_prong_error.zig new file mode 100644 index 0000000000..520723d927 --- /dev/null +++ b/test/cases/compile_errors/switch_expression-unreachable_else_prong_error.zig @@ -0,0 +1,32 @@ +fn foo(x: u2) void { + const y: Error!u2 = x; + if (y) |_| {} else |e| switch (e) { + error.Foo => {}, + error.Bar => {}, + error.Baz => {}, + else => {}, + } +} + +fn bar(x: u2) void { + const y: Error!u2 = x; + y catch |e| switch (e) { + error.Foo => {}, + error.Bar => {}, + error.Baz => {}, + else => {}, + }; +} + +const Error = error{ Foo, Bar, Baz }; + +export fn entry() usize { + return @sizeOf(@TypeOf(&foo)) + @sizeOf(@TypeOf(&bar)); +} + +// error +// backend=stage2 +// target=native +// +// :7:14: error: unreachable else prong; all cases already handled +// :17:14: error: unreachable else prong; all cases already handled diff --git a/test/cases/compile_errors/switch_on_error_union_discard.zig b/test/cases/compile_errors/switch_on_error_union_discard.zig new file mode 100644 index 0000000000..34a607cfef --- /dev/null +++ b/test/cases/compile_errors/switch_on_error_union_discard.zig @@ -0,0 +1,12 @@ +export fn entry() void { + const x: error{}!u32 = 0; + if (x) |v| v else |_| switch (_) { + } +} + + +// error +// backend=stage2 +// target=native +// +// :3:24: error: discard of error capture; omit it instead diff --git a/test/cases/compile_errors/switch_on_error_with_1_field_with_no_prongs.zig b/test/cases/compile_errors/switch_on_error_with_1_field_with_no_prongs.zig new file mode 100644 index 0000000000..504df0374f --- /dev/null +++ b/test/cases/compile_errors/switch_on_error_with_1_field_with_no_prongs.zig @@ -0,0 +1,20 @@ +const Error = error{M}; + +export fn entry() void { + const f: Error!void = void{}; + if (f) {} else |e| switch (e) {} +} + +export fn entry2() void { + const f: Error!void = void{}; + f catch |e| switch (e) {}; +} + +// error +// backend=stage2 +// target=native +// +// :5:24: error: switch must handle all possibilities +// :5:24: note: unhandled error value: 'error.M' +// :10:17: error: switch must handle all possibilities +// :10:17: note: unhandled error value: 'error.M' diff --git a/test/cases/inherit_want_safety.zig b/test/cases/inherit_want_safety.zig index 6a70e603a6..a0c79952b8 100644 --- a/test/cases/inherit_want_safety.zig +++ b/test/cases/inherit_want_safety.zig @@ -23,6 +23,13 @@ pub export fn entry() usize { u += 1; }, } + if (@as(error{}!usize, u)) |_| { + u += 1; + } else |e| switch (e) { + else => { + u += 1; + } + } return u; } |
