microsoft / pyright

Static Type Checker for Python
Other
13.32k stars 1.45k forks source link

List of subclass with a typing error inside is erroring the list. #8715

Closed T4rk1n closed 2 months ago

T4rk1n commented 2 months ago

Consider the following classes:

class S:
    pass

class A(S):
    def __init__(self, a: str):
        pass

class B:
    def __init__(self, b: list[S]):
        pass

class C:
    def __init__(self, c: int):
        pass

if you then have an invalid type as a in b, the whole list will be highlighted as error, making finding the actual error difficult: image

$ pyright typeerror.py 
/home/philippe/repos/dash/typeerror.py
  /home/philippe/repos/dash/typeerror.py:19:7 - error: Argument of type "list[A]" cannot be assigned to parameter "b" of type "list[S]" in function "__init__" (reportArgumentType)
  /home/philippe/repos/dash/typeerror.py:21:7 - error: Argument of type "Literal[1]" cannot be assigned to parameter "a" of type "str" in function "__init__"
    "Literal[1]" is incompatible with "str" (reportArgumentType)
2 errors, 0 warnings, 0 informations ****

If you add an invalid type to the list, only the actual errors are highlighted, which is the desired behavior: image

$ pyright typeerror.py
/home/philippe/newrepos/dash/typeerror.py
  /home/philippe/newrepos/dash/typeerror.py:21:7 - error: Argument of type "Literal[1]" cannot be assigned to parameter "a" of type "str" in function "__init__"
    "Literal[1]" is incompatible with "str" (reportArgumentType)
  /home/philippe/newrepos/dash/typeerror.py:23:5 - error: Argument of type "list[A | C]" cannot be assigned to parameter "b" of type "list[S]" in function "__init__"
    "C" is incompatible with "S" (reportArgumentType)
2 errors, 0 warnings, 0 informations
erictraut commented 2 months ago

Yes, a type error can cause downstream type errors. If you fix the initial type error, any errors that result from the first one will also go away.

In this particular case, the reason you're seeing the secondary error is that the bidirectional type inference logic sees that there is an error attempting to coerce the expression A(a=1) to type S, so it falls back on regular inference rules, which evaluate the type A. That results in the list being evaluated as type list[S | A] (which is equivalent to list[A]), and this type is not assignable to list[S] because of invariance.

T4rk1n commented 2 months ago

In this particular case, the reason you're seeing the secondary error is that the bidirectional type inference logic sees that there is an error attempting to coerce the expression A(a=1) to type S, so it falls back on regular inference rules, which evaluate the type A. That results in the list being evaluated as type list[S | A] (which is equivalent to list[A]), and this type is not assignable to list[S] because of invariance.

But then why all instances of A that don't have an error also get flagged?

The second screenshot shows inconsistent behavior with the above statement, as now only the C is flagged.