microsoft / pyright

Static Type Checker for Python
Other
12.7k stars 1.35k forks source link

Type narrowing with `isinstance()` doesn't work correctly for Union types #8302

Closed wch closed 1 week ago

wch commented 1 week ago

Consider this code.

Foo = int | str

def f(x: Foo | list[Foo]) -> None:
    if isinstance(x, Foo):
        x = [x]

    [y for y in x]

With pyright 1.1.370, this results in an error:

❯ pyright test.py
/Users/winston/py-shiny/test.py
  /Users/winston/test.py:6:14 - error: Expression of type "list[Foo | list[Foo]]" is incompatible with declared type "Foo | list[Foo]" (reportAssignmentType)
  /Users/winston/test.py:8:12 - error: Type of "y" is unknown (reportUnknownVariableType)
  /Users/winston/test.py:8:17 - error: "int" is not iterable
    "__iter__" method not defined (reportGeneralTypeIssues)
3 errors, 0 warnings, 0 informations

It looks like inside of the if isinstance(x, Foo): block, it is not narrowing x to Foo; it still thinks it could be Foo | list[Foo].

If I change the definition of Foo so that it's just Foo = int (and not a union type) then no error is reported.

erictraut commented 1 week ago

I'm not seeing any errors for the above code snippet. Did you mean for Foo = int to be Foo = int | str or something like that?

wch commented 1 week ago

Sorry, I did mean Foo = int | str! I have corrected the example.

erictraut commented 1 week ago

This is addressed in pyright 1.1.371.