authorgravatar for justus@klausecker.deJustus Klausecker <justus@klausecker.de> 2026-06-16 18:23:12+02:00
committergravatar for justusk@noreply.codeberg.orgJustus Klausecker <justusk@noreply.codeberg.org> 2026-06-16 23:28:03+02:00
loge6be5cfe3e280656339d81fdd0cc7451941eba09
tree788afa5fb643570b771a4bf9c7d491edf9e471c4
parentb23404af3d3141037f83257379743c9cdb0de473

Sema: allow overwriting previous analysis results when using switch inst to store temporary information

Essentially `inst_map.putAssumeCapacityNoClobber` is always wrong here because we *want* to clobber previous results when analyzing the same switch expression multiple times.

2 files changed, 38 insertions(+), 1 deletions(-)

src/Sema.zig+1-1
......@@ -9843,7 +9843,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
98439843
98449844 const maybe_switch_ref: ?Air.Inst.Ref = ref: {
98459845 // make err capture (i.e. switch operand) available to switch prong bodies
9846 sema.inst_map.putAssumeCapacityNoClobber(inst, raw_switch_operand);
9846 sema.inst_map.putAssumeCapacity(inst, raw_switch_operand);
98479847 defer assert(sema.inst_map.remove(inst));
98489848 break :ref try sema.analyzeSwitchBlock(block, &switch_block, raw_switch_operand, false, merges, inst, &zir_switch, &validated_switch);
98499849 };
test/behavior/switch.zig+37
......@@ -1542,3 +1542,40 @@ test "error captures narrow error sets" {
15421542 try comptime S.doTheTest(error.B);
15431543 try comptime S.doTheTest(error.C);
15441544}
1545
1546test "repeated switch analysis overrides previous analysis results" {
1547 // This tests an implementation detail where semantic analysis of switch
1548 // statements uses the switch inst itself to store capture values and result
1549 // type information while analyzing (parts of) that switch inst.
1550 // If that inst has already been assigned a result by a previous analysis
1551 // that result needs to be overwritten.
1552
1553 comptime {
1554 const x: u32 = 123;
1555 for (0..2) |_| _ = switch (x) {
1556 123 => |capture| capture,
1557 else => unreachable,
1558 };
1559 }
1560 comptime {
1561 const x: union(enum) { a, b, c } = .a;
1562 for (0..2) |_| _ = switch (x) {
1563 .a => |_, tag| tag,
1564 else => unreachable,
1565 };
1566 }
1567 comptime {
1568 const x: enum { a, b, c } = .a;
1569 for (0..2) |_| _ = label: switch (x) {
1570 .a => continue :label .b,
1571 else => 123,
1572 };
1573 }
1574 comptime {
1575 const x: anyerror!void = error.MyError;
1576 for (0..2) |_| _ = x catch |err| switch (err) {
1577 error.MyError => {},
1578 else => unreachable,
1579 };
1580 }
1581}