Skip to content

Variance bug on TypeVar with value restriction #11379

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
JelleZijlstra opened this issue Oct 24, 2021 · 4 comments
Closed

Variance bug on TypeVar with value restriction #11379

JelleZijlstra opened this issue Oct 24, 2021 · 4 comments
Labels
bug mypy got something wrong topic-type-variables

Comments

@JelleZijlstra
Copy link
Member

from typing import TypeVar, Union, Generic

T1 = TypeVar("T1", int, str, covariant=True)
T2 = TypeVar("T2", int, str)

class X1(Generic[T1]):
    def f(self) -> T1: ...
class X2(Generic[T2]):
    def f(self) -> T2: ...

def f1(x: X1[int]) -> None: ...
def f2(x: X2[int]) -> None: ...

f1(X1[int]())
f1(X1[bool]())

f2(X2[int]())
f2(X2[bool]())

https://mypy-play.net/?mypy=latest&python=3.10&gist=5a4f16dd13bd4b18a7c2323ba464f627

Mypy allows this without errors, but pyright shows an error on the last line and I think it's right: T2 is invariant, so we shouldn't allow bool there:

Argument of type "X2[bool]" cannot be assigned to parameter "x" of type "X2[int]" in function "f2"
  TypeVar "T2@X2" is invariant
    "bool" is incompatible with "int"
@JelleZijlstra JelleZijlstra added the bug mypy got something wrong label Oct 24, 2021
@sobolevn
Copy link
Member

Thanks, @JelleZijlstra! I will take a look 🙂

Related #11378

@sobolevn
Copy link
Member

sobolevn commented Nov 3, 2021

I think the problem is in this line: T1 = TypeVar("T1", int, str, covariant=True)

When defining a type variable with exact values, we want to match these values by type exactly. So, covariant=True should be not allowed in this variable.

Related typing-sig discussion: https://mail.python.org/archives/list/[email protected]/thread/BQYZOF3DSCO3V5HHTWVSPK2PRUQPDIVL/

@erictraut
Copy link

A constrained TypeVar doesn't require an exact match. The following is perfectly legit:

T = TypeVar("T", int, str)

def func(a: T) -> T:
    return a

func(True)

The variance of a TypeVar applies only when it is used as a type parameter in a generic class, such as X1 and X2 in Jelle's example above. In that case, it must be an exact match if it's invariant but can be a subtype (such as bool) if it's covariant. In other words, there are legitimate uses for a covariant constrained TypeVar.

@erictraut
Copy link

I think mypy is doing the right thing here. It shouldn't emit an error. Jelle references an error emitted by pyright, but that was due to a bug that I have since fixed. Pyright now generates no errors for the above code, so it's in sync with mypy. I think this can be closed.

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-type-variables
Projects
None yet
Development

No branches or pull requests

4 participants