const std = @import("std"); const assert = std.debug.assert; const expect = std.testing.expect; const expectError = std.testing.expectError; const expectEqual = std.testing.expectEqual; const builtin = @import("builtin"); test "switch on error union catch capture" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Error = error{ A, B, C }; fn doTheTest() !void { try testScalar(); try testMulti(); try testElse(); try testCapture(); try testInline(); try testEmptyErrSet(); try testAddressOf(); } 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); } } fn testAddressOf() !void { { const a: anyerror!usize = 0; const ptr = &(a catch |e| switch (e) { else => 3, }); comptime assert(@TypeOf(ptr) == *const usize); try expectEqual(ptr, &(a catch unreachable)); } { const a: anyerror!usize = error.A; const ptr = &(a catch |e| switch (e) { else => 3, }); comptime assert(@TypeOf(ptr) == *const comptime_int); try expectEqual(3, ptr.*); } { var a: anyerror!usize = 0; _ = &a; const ptr = &(a catch |e| switch (e) { else => return, }); comptime assert(@TypeOf(ptr) == *usize); ptr.* += 1; try expectEqual(@as(usize, 1), a catch unreachable); } { var a: anyerror!usize = error.A; _ = &a; const ptr = &(a catch |e| switch (e) { else => return, }); comptime assert(@TypeOf(ptr) == *usize); unreachable; } } }; try comptime S.doTheTest(); try S.doTheTest(); } test "switch on error union if else capture" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; 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(); try testAddressOf(); } 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); } } fn testAddressOf() !void { { const a: anyerror!usize = 0; const ptr = &(if (a) |*v| v.* else |e| switch (e) { else => 3, }); comptime assert(@TypeOf(ptr) == *const usize); try expectEqual(ptr, &(a catch unreachable)); } { const a: anyerror!usize = error.A; const ptr = &(if (a) |*v| v.* else |e| switch (e) { else => 3, }); comptime assert(@TypeOf(ptr) == *const comptime_int); try expectEqual(3, ptr.*); } { var a: anyerror!usize = 0; _ = &a; const ptr = &(if (a) |*v| v.* else |e| switch (e) { else => return, }); comptime assert(@TypeOf(ptr) == *usize); ptr.* += 1; try expectEqual(@as(usize, 1), a catch unreachable); } { var a: anyerror!usize = error.A; _ = &a; const ptr = &(if (a) |*v| v.* else |e| switch (e) { else => return, }); comptime assert(@TypeOf(ptr) == *usize); unreachable; } } }; try comptime S.doTheTest(); try S.doTheTest(); }