-
Notifications
You must be signed in to change notification settings - Fork 281
Labels
Description
Describe the Bug
I encountered this issue when trying to improve numpy's annotations for np.datetime64 ops. (None is used to indicate the special "Not A Time" marker)
from typing import Any, overload, assert_type
class A[T]: # covariant
def get(self) -> T: ...
@overload
def op(l: A[None], r: A[None]) -> A[None]: ...
@overload
def op(l: A[None], r: A[Any]) -> A[None]: ...
@overload
def op(l: A[Any], r: A[None]) -> A[None]: ...
@overload
def op(l: A[Any], r: A[Any]) -> A[Any]: ...
def op(l, r):
# dummy implementation:
if l.get() is None or r.get() is None:
return A[None]()
return A[Any]()
def test(x: A[None], y: A[Any]) -> None:
assert_type(op(x, x), A[None])
assert_type(op(x, y), A[None]) # ❌️: (mypy, zuban)
assert_type(op(y, x), A[None]) # ❌️: (mypy, zuban)
assert_type(op(y, y), Any) # ❌️: (pyright, ty, pyrefly)According to the typing spec for overloads, in particular step 5 and 6, op(y,y) should be inferred to as Any, because:
l=A[Any],r=A[Any]can be assigned to all signatures- The return types are not equivalent, because not all materializations of
A[Any]can be assigned toA[None].
Side note
To be honest I think the specification could be improved: instead of Any, it would also be fair, in my opinion, to return the union of all the return type of all overloads that could be caught by different materializations of Any, so in this case this would mean that op(y,y) is A[None] | A[Any], because if the first or second Any were materialized to None, we would get A[None] and if neither materialized to None, we would get A[Any]. (python/typing#2196)
Sandbox Link
(Only applicable for extension issues) IDE Information
No response
Reactions are currently unavailable