[ty] Avoid exponential blow-up in fall-through narrowing (#25278)
## Summary
Prior to this change, narrowing after a large fall-through `match` or
`if`/`elif` sequence could repeatedly evaluate the same projected
narrowing work for each incoming path. For example:
```python
def check(value: Value) -> None:
match value:
case "a":
pass
case "b":
return
case "c":
pass
repr(value)
```
Here, multiple non-terminal branches continue to the statement after the
`match`. In the example above, the "a" and "c" cases both continue to
`repr(value)`. We now reuse the narrowing work shared by those paths
instead of recomputing it for each case.
You can see the impact on the various micro-benchmarks:
```
┌────────────────────────────────────────────────────┬──────────┬───────────┬──────────┐
│ Benchmark │ main │ This PR │ Change │
├────────────────────────────────────────────────────┼──────────┼───────────┼──────────┤
│ ty_micro[literal_match_fallthrough] │ 1.9758 s │ 7.3575 ms │ -99.627% │
│ ty_micro[literal_match_fallthrough_guarded_any] │ 16.967 s │ 27.438 ms │ -99.839% │
│ ty_micro[literal_equality_fallthrough_guarded_any] │ 14.863 s │ 17.969 ms │ -99.879% │
└────────────────────────────────────────────────────┴──────────┴───────────┴──────────┘
```
Closes https://github.com/astral-sh/ty/issues/3504.
Closes https://github.com/astral-sh/ty/issues/3501. C
Charlie Marsh committed
921529b707d5a6a47114d3f2391f5adf0e12ef99
Parent: 539512a
Committed by GitHub <noreply@github.com>
on 5/22/2026, 9:40:14 AM