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

Star operator gets confused when the type has multiple generics #11138

Closed
KotlinIsland opened this issue Sep 18, 2021 · 9 comments · Fixed by #11151
Closed

Star operator gets confused when the type has multiple generics #11138

KotlinIsland opened this issue Sep 18, 2021 · 9 comments · Fixed by #11151
Labels
bug mypy got something wrong

Comments

@KotlinIsland
Copy link
Contributor

Bug Report
When a type has multiple generics and is an iterable, the star operator results in the wrong type

from typing import Iterator, Generic, TypeVar
T = TypeVar("T")
T2 = TypeVar("T2")

class A(Iterator[T2], Generic[T, T2]):
    ...
a: A[int, Iterator[int]]
reveal_type((*a,))
b: list[list[int]] = [*a]

To Reproduce

(Write your steps here:)

  1. Step 1...
  2. Step 2...
  3. Step 3...

Expected Behavior

(Write what you thought would happen.)

Actual Behavior

(Write what happened.)

Your Environment

  • Mypy version used: 0.910
  • Mypy command-line flags: na
  • Mypy configuration options from mypy.ini (and other config files): na
  • Python version used: 3.10
  • Operating system and version: mypy playground
@KotlinIsland KotlinIsland added the bug mypy got something wrong label Sep 18, 2021
@sobolevn
Copy link
Member

@KotlinIsland this line does not seem to be correct: b: list[list[int]] = [*a]. That's exactly what error: List item 0 has incompatible type "A[int, Iterator[int]]"; expected "List[int]" tells you about.
Here b should be list[int]:

from typing import Iterator, Generic, TypeVar
T = TypeVar("T")
T2 = TypeVar("T2")

class A(Iterator[T2], Generic[T, T2]):
    ...
a: A[int, Iterator[int]] = A()
reveal_type((*a,))
reveal_type([*a])
b: list[int] = [*a]

It works: https://mypy-play.net/?mypy=latest&python=3.10&gist=e9ba2aada4295a07d24c5508eadfb5f0
Similar to reveal_type((*a,)) which reveals Revealed type is "builtins.tuple[builtins.int*]"

@KotlinIsland
Copy link
Contributor Author

@sobolevn actually it should be a list[Iterator[int]]

@KotlinIsland
Copy link
Contributor Author

@KotlinIsland
Copy link
Contributor Author

from typing import Generic, TypeVar
T = TypeVar("T")
T2 = TypeVar("T2")

class A(Iterator[T2], Generic[T, T2]):
    ...
    
a: A[str, int]
reveal_type((*a,))  # note: Revealed type is "builtins.tuple[builtins.str*]"
b: list[int] = [*a]  # error: List item 0 has incompatible type "A[str, int]"; expected "int"

@JelleZijlstra
Copy link
Member

@KotlinIsland's latest gist does look pretty buggy. For (*a,) it infers tuple[str, ...], which is wrong because a is an Iterator[Iterator[int]] instead.

@JelleZijlstra
Copy link
Member

JelleZijlstra commented Sep 19, 2021

I like this example of the bug:

from typing import Generic, Iterator, TypeVar
T = TypeVar("T")
U = TypeVar("U")

class X(Iterator[U], Generic[T, U]):
    pass

x: X[str, int]
reveal_type(list(x))  # N: Revealed type is "builtins.list[builtins.int*]"
reveal_type([*x])  # N: Revealed type is "builtins.list[builtins.str*]"

@sobolevn
Copy link
Member

sobolevn commented Sep 20, 2021

Oh, I see. Will try to fix it tomorrow 👍

@sobolevn
Copy link
Member

Yeap, solved using map_instance_to_supertype(actual_type, Iterable) here:

mypy/mypy/argmap.py

Lines 168 to 173 in b3ff2a6

if actual_type.type.fullname == 'builtins.list':
# List *arg.
return actual_type.args[0]
elif actual_type.args:
# TODO: Try to map type arguments to Iterable
return actual_type.args[0]

But, I need changes from #11151 to make it work correctly. Right now it is blocked.
@JelleZijlstra I would appreciate your review to get it merged! 🙏

@JelleZijlstra
Copy link
Member

JelleZijlstra commented Sep 20, 2021

Nice catch! I figured we were assuming somewhere that the first generic arg was for Iterable, but couldn't find the right place in the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants