-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Instantiation of generic return type in Callable[[...], R]
collapse into object
instead of proper union types.
#15968
Comments
Note that as a work-around it seems possible to explicitly overload up to a certain level: from typing import Callable, Sequence, Tuple, TypeVar, overload
R = TypeVar("R")
R1 = TypeVar("R1")
R2 = TypeVar("R2")
R3 = TypeVar("R3")
@overload
def f1(__args1: Callable[[], R1]) -> R1:
...
@overload
def f1(__args1: Callable[[], R1], __args2: Callable[[], R2]) -> R1 | R2:
...
@overload
def f1(__args1: Callable[[], R1], __args2: Callable[[], R2], __args3: Callable[[], R3]) -> R1 | R2 | R3:
...
def f1(*args: Callable[[], R]) -> R:
return args[0]()
def foo() -> int:
return 42
def bar() -> str:
return "..."
reveal_type(f1(foo))
reveal_type(f1(bar))
reveal_type(f1(foo, bar))
reveal_type(f1(foo, bar, lambda: None)) outputs:
If the number of varags is expected to be large, this isn't super practical though. And perhaps the issue here is actually not specific to from typing import TypeVar, Generic
T = TypeVar("T")
class Wrapper(Generic[T]):
def __init__(self, value: T):
self.value = value
def f(*args: Wrapper[T]) -> T:
raise NotImplementedError()
reveal_type(f(Wrapper(42), Wrapper("..."))) So is this just a manifestation of #230? |
Callable[[...], R]
collapse into object
instead of proper union types.Callable[[...], R]
collapse into object
instead of proper union types.
I think most of this is explained by the fact that mypy uses a "join" operator rather than a union operator. For details, refer to this documentation and this documentation. There's a tag called topic-join-v-union that marks all of the issues related to this behavior. That same tag should probably be added to this issue. Your last code sample (with the |
Thanks for pointing that out! It looks like the central tracking issue for "join v union" is #12056. Not sure if the general policy is to keep individual related issues open, but we might as well close this one in favor of the central one. |
@bluenote10 The example with def f(*args: Wrapper[T]) -> T:
if len(args) == 2:
first, second = args
first.value = second.value # Should be totally OK, since both are `T`, right?
... # return whatever
a = Wrapper(1)
b = Wrapper("...")
_ = f(a, b) # <- mypy gives error here
a.value += 1 # Surprise! This is why mypy says it can't infer valid value for You can actually trick mypy by saying that |
@ilevkivskyi, I'm not sure what you mean by " a: Wrapper[int | str] = Wrapper(1)
b: Wrapper[int | str] = Wrapper("...")
c1 = f(a, b) # Mypy doesn't emit an error
reveal_type(c1) # Both mypy and pyright reveal "int | str"
c2 = f(Wrapper(1), Wrapper("...")) # Mypy emits an error, pyright doesn't
reveal_type(c2) # Pyright reveals: "int | str" In the second call to |
Bug Report
(I would have assumed that this has already been reported, but after searching for a while I couldn't find an exact match. Apologies if this is a duplicate.)
It looks like if there is a heterogenic generic instantiation of the return type of a
Callable[[...], R]
, the return typeR
immediately becomesobject
instead of a union type.To Reproduce
Example on mypy playground.
Expected Behavior
I would have hoped that all 4 revealed types become a union type corresponding to the union of the return types of
foo
andbar
, i.e.:Pyright seems to infer the return type as such.
Actual Behavior
mypy instead converts the return type into
object
instead of a union.Your Environment
mypy.ini
(and other config files): none specific (mypy playground default)The text was updated successfully, but these errors were encountered: