facebook / facebook/pyrefly

Inconsistent scoping of "rescoped" type variables

Open
#1,394 1 comment 0 reactions 0 assignees View on GitHub
scoping-control-flow typechecking
Dominant language
Rust
Stars
7k
Forks
516
PR merge metrics
No merged PRs in 30d

Description

### Describe the Bug

This bug is identical to this bug in Pyright: https://github.com/microsoft/pyright/issues/11016

Code sample:
```py
from collections.abc import Callable

def get_identity[T](name: str) -> Callable[[T], tuple[T, T]]:
tees: list[T] = []

def f(x: T) -> tuple[T, T]:
if tees:
last = tees.pop()
else:
last = x
tees.append(x)
return x, last

f.__name__ = name
return f

identity = get_identity("banana")
a0, b0 = identity(42)
# a0, b0 are both int

a1, b1 = identity("aaa")
# a1, b1 are both str for pyrefly
# but of course b1 is 42 at runtime
```

Using a type variable scoped to `get_identity` to denote that it returns a generic function is called "rescoping" and it's not allowed by the typing spec: [discourse link](https://discuss.python.org/t/rescoping-of-type-variables-into-return-types-agreeing-on-a-specification/60534), instead you're supposed to define a protocol with a generic `__call__` method. It is supported by mypy and pyright for compatibility reasons.

In this case, pyrefly seems to allow the use of the `T` type variable (which is supposed to only exist inside the returned function) inside the enclosing functions, which is not correct. `mypy` correctly complains at the `tees: list[T] = []` line that `T` is not defined.

### Sandbox Link

https://pyrefly.org/sandbox/?project=N4IgZglgNgpgziAXKOBDAdgEwEYHsAeAdAA4CeS4ATrgLYAEAxrlLAwC4S7pyGrYN0INYrkps6AYVQs%2BsADroFmGGDoBzGGwD6EZeg5tSAbQAqAXQAU6VDRiI6cNpQCUdALQA%2BSdKiyYR0zMAGjo2AFdiWFMQ8zNEBTpE0Jh4eygIR0C6AF46IzMFBKTlVTALfHsTV09QiKiTGLiipKSIVTYUuHj0Ft6k30cc5PgSXGILZ2bemCg4Oym%2BxIHxXPwFpI6R1GJiGCxyyZ7Fyk0wyh78EOXCo8SwQi0ta1tHoeeYKZPw87owKYVdHsDKQhhptID9BBDBY5CBsBgEbDDqgAAwhbAooYQ4EWAAsACZDgBiOio9GY1AnOh4NgAC0E%2BhuqAAjOjmVi9DjYageUiFCSWWzSVSafTHJRfqI6GQTmAoKR%2BdSwuJcKomGc5tT2Rk6ATSeJKGFIbYQEEQDKVPLCGxaFAKCSAAqkWXyhwYHAERhcSBqM6oDhcQiKgDKKTotLYbGIXQA9DGLXLSIRRGoY3sY5hcAw4DGmOgfX6A%2BgY5KJagAG6oaB%2BL35iC%2Byj%2Bzg9MZFngKMh0rhucswShwZtDWEAZkIzNxsIUIAAvmbUOwIL2AGLQGAUNBYPBEMgzoA

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.