Skip to content

Inconsistent scoping of "rescoped" type variables #1394

@decorator-factory

Description

@decorator-factory

Describe the Bug

This bug is identical to this bug in Pyright: microsoft/pyright#11016

Code sample:

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, 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    scoping-control-flowissues related to scoping and control flow

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions