Skip to content
New issue

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

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

Already on GitHub? # to your account

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

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, ...]")

# for free to join this conversation on GitHub. Already have an account? # 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