Commit 69ab687156

dweiller <4678790+dweiller@users.noreply.github.com>
2023-11-30 09:12:47
test: add tests for switch_block_err_union
1 parent fc6dc79
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();
+}
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
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
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'
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
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
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
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'