From 499aba9ca6eb3febfb16261b507145a39598c0b4 Mon Sep 17 00:00:00 2001 From: Justus Klausecker Date: Thu, 12 Mar 2026 11:47:45 +0100 Subject: [PATCH] Sema: require else prong for `comptime_int` This fixes a bug introduced a couple of commits ago. --- src/Sema.zig | 5 +- .../switch_validate_else_prong.zig | 166 ++++++++++++++++++ 2 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 test/cases/compile_errors/switch_validate_else_prong.zig diff --git a/src/Sema.zig b/src/Sema.zig index 78f80b31e2..a6507865b7 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -11665,10 +11665,9 @@ fn validateSwitchBlock( }, }; }, - .int, .comptime_int, .@"union", .@"struct" => |type_tag| { + .int, .@"union", .@"struct" => |type_tag| { check_range: { const int_ty = switch (type_tag) { - .comptime_int => break :check_range, // comptime_int has 'infinite' range .int => item_ty, .@"union", .@"struct" => item_ty.bitpackBackingInt(zcu), else => unreachable, @@ -11696,7 +11695,7 @@ fn validateSwitchBlock( } } }, - .enum_literal, .@"fn", .pointer, .type => { + .comptime_int, .enum_literal, .@"fn", .pointer, .type => { if (!has_else) { return sema.fail( block, diff --git a/test/cases/compile_errors/switch_validate_else_prong.zig b/test/cases/compile_errors/switch_validate_else_prong.zig new file mode 100644 index 0000000000..4a1b3887b9 --- /dev/null +++ b/test/cases/compile_errors/switch_validate_else_prong.zig @@ -0,0 +1,166 @@ +const E = enum { a, b }; +export fn entry1() void { + switch (E.a) { + .a => {}, + } +} +export fn entry2() void { + switch (E.a) { + .a, .b => {}, + else => {}, + } +} + +const T = union(E) { a: u32, b }; +export fn entry3() void { + switch (T{ .a = 0 }) { + .a => {}, + } +} +export fn entry4() void { + switch (T{ .a = 0 }) { + .a, .b => {}, + else => {}, + } +} + +const Error = error{ MyError, MyOtherError }; +export fn entry5() void { + switch (Error.MyError) { + error.MyError => {}, + } +} +export fn entry6() void { + switch (Error.MyError) { + error.MyError, error.MyOtherError => {}, + else => {}, + } +} + +const U = packed union { a: u1, b: i1 }; +export fn entry7() void { + switch (U{ .a = 0 }) { + .{ .a = 0 } => {}, + } +} +export fn entry8() void { + switch (U{ .a = 0 }) { + .{ .a = 0 }, .{ .a = 1 } => {}, + else => {}, + } +} + +const S = packed struct { a: u1 }; +export fn entry9() void { + switch (S{ .a = 0 }) { + .{ .a = 0 } => {}, + } +} +export fn entry10() void { + switch (S{ .a = 0 }) { + .{ .a = 0 }, .{ .a = 1 } => {}, + else => {}, + } +} + +export fn entry11() void { + switch (@as(u1, 0)) { + 0 => {}, + } +} +export fn entry12() void { + switch (@as(u1, 0)) { + 0, 1 => {}, + else => {}, + } +} + +export fn entry13() void { + switch (true) { + true => {}, + } +} +export fn entry14() void { + switch (true) { + true, false => {}, + else => {}, + } +} + +export fn entry15() void { + switch ({}) {} +} +export fn entry16() void { + switch ({}) { + {} => {}, + else => {}, + } +} + +export fn entry17() void { + switch (123) { + 123 => {}, + } +} + +export fn entry18() void { + switch (.foo) { + .foo => {}, + } +} + +fn bar() void {} +export fn entry19() void { + switch (bar) { + bar => {}, + } +} + +const baz: *u8 = @ptrFromInt(123); +export fn entry20() void { + switch (baz) { + baz => {}, + } +} + +export fn entry21() void { + switch (u32) { + u32 => {}, + } +} + +export fn entry22() void { + switch (@as(anyerror, error.MyError)) { + error.MyError => {}, + } +} + +// error +// +// :3:5: error: switch must handle all possibilities +// :1:21: note: unhandled enumeration value: 'b' +// :1:11: note: enum 'tmp.E' declared here +// :10:14: error: unreachable else prong; all cases already handled +// :16:5: error: switch must handle all possibilities +// :1:21: note: unhandled enumeration value: 'b' +// :1:11: note: enum 'tmp.E' declared here +// :23:14: error: unreachable else prong; all cases already handled +// :29:5: error: switch must handle all possibilities +// :29:5: note: unhandled error value: 'error.MyOtherError' +// :36:14: error: unreachable else prong; all cases already handled +// :42:5: error: switch must handle all possibilities +// :49:14: error: unreachable else prong; all cases already handled +// :55:5: error: switch must handle all possibilities +// :62:14: error: unreachable else prong; all cases already handled +// :67:5: error: switch must handle all possibilities +// :74:14: error: unreachable else prong; all cases already handled +// :79:5: error: switch must handle all possibilities +// :86:14: error: unreachable else prong; all cases already handled +// :91:5: error: switch must handle all possibilities +// :96:14: error: unreachable else prong; all cases already handled +// :101:5: error: else prong required when switching on type 'comptime_int' +// :107:5: error: else prong required when switching on type '@EnumLiteral()' +// :114:5: error: else prong required when switching on type 'fn () void' +// :121:5: error: else prong required when switching on type '*u8' +// :127:5: error: else prong required when switching on type 'type' +// :133:5: error: else prong required when switching on type 'anyerror'