Description
Bug Report
Functions which optionally take a value of Never
type have impossible requirements placed on usages of that optional value.
To Reproduce
https://gist.github.com/mypy-play/a49d72bdacc179ffda5f69d8b66f41ff
from typing import Never
def blah(s: Never | str) -> None:
print(s + "hi")
Expected Behavior
The code type-checks. Since it is impossible for any variable to take a value of type Never
, the type signature of blah
is equivalent to str -> None
. The function's body is valid when s
is annotated with type str
, so it should be valid when annotated with Never | str
.
Actual Behavior
main.py:5: error: Unsupported left operand type for + ("Never") [operator]
main.py:5: note: Left operand is of type "Never | str"
Found 1 error in 1 file (checked 1 source file)
Your Environment
- Python 3.12
- MyPy 1.15.0, invocation as performed in the Playground
Background
Pyright appears to do the right thing here: it accepts this code.
I ran into this when implementing this pattern, which is me placing types around something I found untyped in the wild:
T = TypeVar("T", contravariant=True)
class _MyProtocol(Protocol[T]):
def _foo(self, arg: T | IO[str]) -> None: ...
try:
import foo
class _MyImpl(_MyProtocol[foo.Foo]):
def _foo(self, arg: foo.Foo | IO[str]) -> None:
# do something here
pass
MyType = _MyImpl
except ImportError:
class _MyImplNone(_MyProtocol[Never]):
def _foo(self, arg: Never | IO[str]) -> None:
# correctly assume arg is an IO[str] here
pass
MyType = _MyImplNone
That way, MyType
has type _MyProtocol[foo.Foo] | _MyProtocol[Never]
, allowing a type-level discrimination of whether the foo
functionality is present or not.