[ty] fix lazy snapshot sweeping in nested scopes (#19908)

## Summary

This PR closes astral-sh/ty#955.

## Test Plan

New test cases in `narrowing/conditionals/nested.md`.
This commit is contained in:
Shunsuke Shibayama 2025-08-15 09:52:52 +09:00 committed by GitHub
parent 957320c0f1
commit 0e5577ab56
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 56 additions and 23 deletions

View file

@ -240,6 +240,21 @@ def f(x: str | None):
# When there is a reassignment, any narrowing constraints on the place are invalidated in lazy scopes.
x = None
def f(x: str | None):
def _():
if x is not None:
def closure():
reveal_type(x) # revealed: str | None
x = None
def f(x: str | None):
class C:
def _():
if x is not None:
def closure():
reveal_type(x) # revealed: str
x = None # This assignment is not visible in the inner lazy scope, so narrowing is still valid.
```
If a variable defined in a private scope is never reassigned, narrowing remains in effect in the
@ -256,6 +271,12 @@ def f(const: str | None):
reveal_type(const) # revealed: str
[reveal_type(const) for _ in range(1)] # revealed: str
def f(const: str | None):
def _():
if const is not None:
def closure():
reveal_type(const) # revealed: str
```
And even if there is an attribute or subscript assignment to the variable, narrowing of the variable