Skip to content

variable annotated as tuple[SomeProtocol, ...] loses protocol information on assignment #12360

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

Closed
asottile opened this issue Mar 15, 2022 · 4 comments
Labels
bug mypy got something wrong topic-join-v-union Using join vs. using unions

Comments

@asottile
Copy link
Contributor

Bug Report

re-assigning of a variable which is annotated with tuple[P, ...] loses its typing (it becomes Tuple[The, Concrete, Classes]) which breaks accessing of protocol members

To Reproduce

from __future__ import annotations

from typing import Protocol

class P(Protocol):
    def f(self) -> int: ...

class C:
    def f(self) -> int:
        return 5

class D:
    def f(self) -> int:
        return 6

x: tuple[P, ...] = ()
reveal_type(x)

x = (C(), D())
reveal_type(x)

for thing in x:
    print(thing.f())

Expected Behavior

I expect both of the reveal_types to be the same and there to be no error on access of thing.f()

Actual Behavior

$ mypy t.py
t.py:17: note: Revealed type is "builtins.tuple[t.P, ...]"
t.py:20: note: Revealed type is "Tuple[t.C, t.D]"
t.py:23: error: "object" has no attribute "f"
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 0.941
  • Mypy command-line flags: N/A
  • Mypy configuration options from mypy.ini (and other config files): N/A
  • Python version used: python 3.8.10
  • Operating system and version: ubuntu 20.04
@asottile asottile added the bug mypy got something wrong label Mar 15, 2022
@erictraut
Copy link

This is another case where mypy's use of join instead of union results in a false positive. See #12009.

@AlexWaygood AlexWaygood added the topic-join-v-union Using join vs. using unions label Mar 24, 2022
@brianschubert
Copy link
Collaborator

Fixed in #17408, released with v1.11.0

@asottile
Copy link
Contributor Author

it seems maybe only part of this was fixed (the unions in the for loop) -- the typing of the tuple is still discarded:

$ mypy t.py 
t.py:17: note: Revealed type is "builtins.tuple[t.P, ...]"
t.py:20: note: Revealed type is "tuple[t.C, t.D]"
Success: no issues found in 1 source file

@brianschubert
Copy link
Collaborator

That looks correct to me. Mypy will locally narrow types on assignment, which is what reveal_type is showing. The declared type is still tuple[P, ...]. This example might help clarify what's going on:

x: tuple[P, ...] = ()
reveal_type(x)  # N: Revealed type is "builtins.tuple[SCRATCH.P, ...]"

x = (C(), D())
reveal_type(x)  # N: Revealed type is "tuple[SCRATCH.C, SCRATCH.D]"

x = (D(), C())
reveal_type(x)  # N: Revealed type is "tuple[SCRATCH.D, SCRATCH.C]"

x = "foo"  # E: Incompatible types in assignment (expression has type "str", variable has type "tuple[P, ...]")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-join-v-union Using join vs. using unions
Projects
None yet
Development

No branches or pull requests

4 participants