| author | |
| committer | |
| log | e6be5cfe3e280656339d81fdd0cc7451941eba09 |
| tree | 788afa5fb643570b771a4bf9c7d491edf9e471c4 |
| parent | b23404af3d3141037f83257379743c9cdb0de473 |
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 | ... | @@ -9843,7 +9843,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 9843 | 9843 | ||
| 9844 | const maybe_switch_ref: ?Air.Inst.Ref = ref: { | 9844 | const maybe_switch_ref: ?Air.Inst.Ref = ref: { |
| 9845 | // make err capture (i.e. switch operand) available to switch prong bodies | 9845 | // 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); |
| 9847 | defer assert(sema.inst_map.remove(inst)); | 9847 | defer assert(sema.inst_map.remove(inst)); |
| 9848 | break :ref try sema.analyzeSwitchBlock(block, &switch_block, raw_switch_operand, false, merges, inst, &zir_switch, &validated_switch); | 9848 | break :ref try sema.analyzeSwitchBlock(block, &switch_block, raw_switch_operand, false, merges, inst, &zir_switch, &validated_switch); |
| 9849 | }; | 9849 | }; |
test/behavior/switch.zig+37| ... | @@ -1542,3 +1542,40 @@ test "error captures narrow error sets" { | ... | @@ -1542,3 +1542,40 @@ test "error captures narrow error sets" { |
| 1542 | try comptime S.doTheTest(error.B); | 1542 | try comptime S.doTheTest(error.B); |
| 1543 | try comptime S.doTheTest(error.C); | 1543 | try comptime S.doTheTest(error.C); |
| 1544 | } | 1544 | } |
| 1545 | |||
| 1546 | test "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 | } |