Skip to content

Conversation

@sobolevn
Copy link
Member

This PR implements the suggested general case from #10870 (comment)

What we do? When we are stuck with the partial type inside a class definition, we try to fetch types from parent definitions.
If this definition exist, we reuse the type.

This way, we won't have a warning here:

from typing import List

class P:
   x: List[int]

class C(P):
   x = []  # used to be an error here: "Need type annotation for "x" (hint: "x: List[<type>] = ...")"

reveal_type(C.x)  # revealed type is: "List[int]"

Closes #10870

Test Plan

I am going to add more tests after someone from the core team approves this approach 🙂

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@sobolevn
Copy link
Member Author

sobolevn commented Jul 26, 2021

Ok, here's the problematic part:

from typing import List
class P:
    x: List[int]
class M:
    x: List[str]
class C(P, M):
    x = []
reveal_type(C.x)  # N: Revealed type is "builtins.list[builtins.int]"

This code does not raise error: Definition of "x" in base class "P" is incompatible with definition in base class "M" because we forcefully insert x type after the type-checking is already finished.

I have tried to defer this node to the second pass, but we don't have the AssignmentStatement in the enter_partial_types context. It didn't work.

Now, I will try to do something similar in semanal.

The last option is: if we have more than one different type definition in mro, just fallback to old behavior.

@sobolevn
Copy link
Member Author

Solved it using new checker method similar to try_infer_partial_generic_type_from_assignment

@github-actions

This comment has been minimized.

@sobolevn
Copy link
Member Author

sobolevn commented Jul 26, 2021

Oh, this one is hard 😕

Solution with try_infer_partial_generic_type_from_super is too unreliable right now as shown in #10871 (comment)

It is also related to #3208

One more failing case:

from typing import List

class P:
    @property
    def x(self) -> List[int]:
        ...

class C(P):
    x = []

C.x.append(1)  # error: "Callable[[P], List[int]]" has no attribute "append"

It works with explicit x: List[int] = []

@sobolevn
Copy link
Member Author

sobolevn commented Jul 26, 2021

To be fair, current master also does not find subtyping issue here:

from typing import List

class Parent:
    a: List[str]

class A(Parent):
    a = []
    a.append(1)

reveal_type(A.a)  # note: Revealed type is "builtins.list[builtins.int]"

It should give the same result as:

from typing import List

class Parent:
    a: List[str]

class A(Parent):
    a: List[int]  # error: Incompatible types in assignment (expression has type "List[int]", base class "Parent" defined the type as "List[str]")
reveal_type(A.a)  # note: Revealed type is "builtins.list[builtins.int]"

But, I think it is a different task.

@github-actions
Copy link
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

sympy (https://github.com/sympy/sympy.git)
- sympy/core/numbers.py:2514: error: Need type annotation for "free_symbols" (hint: "free_symbols: Set[<type>] = ...")

@sobolevn sobolevn closed this Aug 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mypy complains when [] is used for __slots__ definition

1 participant