Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds attribute type inference from super-types for partial types #10871

Closed
wants to merge 5 commits into from
Closed

Adds attribute type inference from super-types for partial types #10871

wants to merge 5 commits into from

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