-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Bug: overloads not matched when using TypeVar
with default
(where Pyright matches correctly)
#19182
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
Comments
I'm not sure this is even a bug. This: T = TypeVar("T", bound=Union[str, int], default=Any) means " Here's a minimal reproducer without overloads: from typing import Any, Callable, Generic
from typing_extensions import TypeVar
T = TypeVar("T", bound=str | int, default=Any)
class Foo(Generic[T]):
def __init__(self, t: T) -> None:
self.t = t
class Bar:
def apply(self, f: Callable[..., T | None]) -> Foo[T]: ...
def func() -> Foo:
return Foo(3)
def main(b: Bar) -> None:
reveal_type(b.apply(func)) # N: Revealed type is "__main__.Foo[Any]" Could you elaborate on your use case where As a result, both overloads are matched, and since they have nothing in common we reduce the final result to I don't know whether this should or will be fixed, but a simple workaround exists: do not use from typing import Any, Callable, Generic, Protocol, Self, overload, reveal_type
from typing_extensions import TypeVar
T = TypeVar("T", bound=str | int, default=Any)
U = TypeVar("U", bound=str | int)
class Foo(Generic[T]):
def __init__(self, t: T) -> None:
self.t = t
class Bar(Protocol):
@overload
def apply(self, f: Callable[..., Foo]) -> Self: ...
@overload
def apply(self, f: Callable[..., U | None]) -> Foo[U]: ...
def func() -> Foo:
return Foo(3)
def main(b: Bar) -> None:
reveal_type(b.apply(func)) |
In the minimal producer without overloads, mypy doesn't detect a type error for the call expression The argument If I remove the default from the type parameter |
@erictraut While I probably agree that using default only when there were no constraints at all would be more reasonable, |
Argument assignability must be satisfied before attempting to solve type variables. The type Consider this code sample: T = TypeVar("T", bound=int, default=bool)
def func(x: T | list[str]) -> T: ...
reveal_type(func(1)) # int
reveal_type(func([""])) # bool
func("") # Error, even though a solution of T=Any would satisfy it I agree that Interestingly, mypy works as I would expect in other cases that involve T = TypeVar("T", bound=Sequence[int], default="list[Any]")
def func(x: T) -> T: ...
func([1]) # OK
func([""]) # Error |
From the spec:
I think mypy is conformant here: there's no solution for Your last example is convincing, though: it produces a diagnostic even if T = TypeVar("T", bound=Sequence[int], default=Any)
def func(x: T) -> T: ...
func([1]) # OK
func([""]) # E: Value of type variable "T" of "func" cannot be "list[str]" [type-var] So our approach is indeed at least inconsistent. |
I can understand why you might find the current wording in the spec to be confusing or ambiguous. As I mentioned above, assignability of arguments is a prerequisite. If the type of an argument isn't assignable to the corresponding parameter type, it should be considered a type violation. Only in cases where the arguments are assignable does it make sense to solve type variables. As I point out above, there are situations where arguments are assignable to parameters but there is still no solution for the type variable because of insufficient constraints. That's what the spec is referring to here where it says "when the type parameter cannot be solved to anything". If I remember correctly, I suggested the current wording in PEP 696 when I reviewed an early draft, so you can probably blame me for its lack of clarity, but I can confirm that was the intended meaning of this phrase. In any case, it's important for type checkers to be consistent here because, as the OP points out, this affects overload resolution. We've been working hard to pin down the overload resolution specification to improve type checker consistency and make it easier for library and stub maintainers. |
Thanks all for responses
In pandas, |
In NumPy this is used quite a lot, for example
There are also some examples of this in the typeshed stdlib stubs, e.g. |
Uh oh!
There was an error while loading. Please reload this page.
Bug Report
In the example below, mypy reveals the type to be
Any
, whereas Pyright correctly detectsBar
Note that replacing
T | None
withT
makes Mypy also infer the type correctlyNoticed while working on pandas-stubs
To Reproduce
https://mypy-play.net/?mypy=latest&python=3.12&gist=6df33ff32887ddfab4c1ae43edd62b2d
Expected Behavior
that
reveal_type
would showBar
(for reference, this is what Pyright does)Actual Behavior
Your Environment
mypy.ini
(and other config files):The text was updated successfully, but these errors were encountered: