disallow switch case capture discards

Previously Zig allowed you to write something like,
```zig
switch (x) {
    .y => |_| {
```

This seems a bit strange because in other cases, such as when
capturing the tag in a switch case,
```zig
switch (x) {
    .y => |_, _| {
```
this produces an error.

The only usecase I can think of for the previous behaviour is
if you wanted to assert that all union payloads are able
to coerce,
```zig
const X = union(enum) { y: u8, z: f32 };

switch (x) {
    .y, .z => |_| {
```

This will compile-error with the `|_|` and pass without it.

I don't believe this usecase is strong enough to keep the current
behaviour; it was never used in the Zig codebase and I cannot
find a single usage of this behaviour in the real world, searching
through Sourcegraph.
This commit is contained in:
David Rubin 2025-10-04 12:04:42 -07:00 committed by Matthew Lugg
parent c434599134
commit aa2b178029
No known key found for this signature in database
GPG key ID: 3F5B7DCCBF4AF02E
5 changed files with 56 additions and 5 deletions

View file

@ -270,3 +270,30 @@ test "switch loop on non-exhaustive enum" {
try S.doTheTest();
try comptime S.doTheTest();
}
test "switch loop with discarded tag capture" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
const S = struct {
const U = union(enum) {
a: u32,
b: u32,
c: u32,
};
fn doTheTest() void {
const a: U = .{ .a = 10 };
blk: switch (a) {
inline .b => |_, tag| {
_ = tag;
continue :blk .{ .c = 20 };
},
else => {},
}
}
};
S.doTheTest();
comptime S.doTheTest();
}

View file

@ -0,0 +1,16 @@
export fn foo() void {
const S = struct {
fn doTheTest() void {
blk: switch (@as(u8, 'a')) {
'1' => |_| continue :blk '1',
else => {},
}
}
};
S.doTheTest();
comptime S.doTheTest();
}
// error
//
// :5:25: error: discard of capture; omit it instead