Open
Description
@overload
def foo(a: Literal[True]) -> int: ...
@overload
def foo(a: Literal[False]) -> str: ...
def foo(a: bool) -> object: ...
a: bool
reveal_type(foo(a)) # error: No overload variant of "foo" matches argument type "bool"
@overload
def foo(a: Literal[True]) -> int: ...
@overload
def foo(a: Literal[False]) -> str: ...
@overload
def foo(a: bool) -> object: ... # no error regarding impossible to match overload
a: bool
reveal_type(foo(a)) # object
@overload
def foo(a: Literal[True, False]) -> int | str: ...
@overload
def foo(a: bool) -> object: ... # error: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader
def foo(a: bool) -> object: ...
a: bool
reveal_type(foo(a)) # int | str
Here mypy incorrectly forces us to implement a completely redundant overload for the non Literal
case when it is already exhaustively covered by both literals. It is only when the literals are in the same overload (useless in practice, but just for demonstration) that mypy correctly handles this case.
Mypy should be doing 'union math' (or what ever it's called) to apply both literal overloads at once.
This also affects all other exhaustible Literal
s such as Enum
s.
This example is pulled directly from the docs, so I think they should be updated as well to an example that doesn't contain this confusing defect.