zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit e6be5cfe3e280656339d81fdd0cc7451941eba09 (tree)
parent b23404af3d3141037f83257379743c9cdb0de473
Author: Justus Klausecker <justus@klausecker.de>
Date:   Tue, 16 Jun 2026 18:23:12 +0200

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.

Diffstat:
Msrc/Sema.zig | 2+-
Mtest/behavior/switch.zig | 37+++++++++++++++++++++++++++++++++++++
2 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/src/Sema.zig b/src/Sema.zig @@ -9843,7 +9843,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp const maybe_switch_ref: ?Air.Inst.Ref = ref: { // make err capture (i.e. switch operand) available to switch prong bodies - sema.inst_map.putAssumeCapacityNoClobber(inst, raw_switch_operand); + sema.inst_map.putAssumeCapacity(inst, raw_switch_operand); defer assert(sema.inst_map.remove(inst)); break :ref try sema.analyzeSwitchBlock(block, &switch_block, raw_switch_operand, false, merges, inst, &zir_switch, &validated_switch); }; diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig @@ -1542,3 +1542,40 @@ test "error captures narrow error sets" { try comptime S.doTheTest(error.B); try comptime S.doTheTest(error.C); } + +test "repeated switch analysis overrides previous analysis results" { + // This tests an implementation detail where semantic analysis of switch + // statements uses the switch inst itself to store capture values and result + // type information while analyzing (parts of) that switch inst. + // If that inst has already been assigned a result by a previous analysis + // that result needs to be overwritten. + + comptime { + const x: u32 = 123; + for (0..2) |_| _ = switch (x) { + 123 => |capture| capture, + else => unreachable, + }; + } + comptime { + const x: union(enum) { a, b, c } = .a; + for (0..2) |_| _ = switch (x) { + .a => |_, tag| tag, + else => unreachable, + }; + } + comptime { + const x: enum { a, b, c } = .a; + for (0..2) |_| _ = label: switch (x) { + .a => continue :label .b, + else => 123, + }; + } + comptime { + const x: anyerror!void = error.MyError; + for (0..2) |_| _ = x catch |err| switch (err) { + error.MyError => {}, + else => unreachable, + }; + } +}