Describe the issue:
The commonly used @overload pattern with _ArrayLike{}_co parameter types can lead to unexpected type inferences if the return types are incompatible with one another other.
An example of this is the numpy.dtype constructor:
It correctly infers dtype(bool) and dtype(int) as dtype[np.bool] and dtype[signedinteger[Any]], respectively.
But in the case that either bool or int can be passed, e.g as dtype(int_co) with int_co: type[bool] | tuple[int], the resulting type is inferred as dtype[signedinteger[Any]], which is incompatible with dtype[bool].
The correct type in this case would be dtype[bool | signedinteger[Any]].
Reproduce the code example:
# overlapping_overload_issue.pyi
import numpy as np
x: type[bool]
y: type[int]
z: type[bool] | type[int]
reveal_type(np.dtype(x)) # OK: dtype[bool]
reveal_type(np.dtype(y)) # OK: dtype[signedinteger[Any]]
reveal_type(np.dtype(z)) # WRONG: dtype[signedinteger[Any]]
But the last revealed type doesn't include bool, i.e. it should have been dtype[bool | signedinteger[Any]].
This isn't limited to only bool and int; all possible non-trivial unions of bool, int, float or complex have this problem, see https://typing.readthedocs.io/en/latest/spec/special-types.html#special-cases-for-float-and-complex
And this also isn't limited to dtype.__new__:
The same issue can be observed with the arithmetic operator methods (e.g. __add__) of numpy.ndarray, numpy.bool, and all subclasses of numpy.number, just to name a few.
Error message:
With Pyright / Pylance, enabling the reportOverlappingOverload setting will in such cases result in an error message (unless there's a # type: ignore comment), e.g. for numpy.dtype.__new__ Pylance reports:
Overload 1 for "__new__" overlaps overload 51 and returns an incompatible type
Overload 2 for "__new__" overlaps overload 3 and returns an incompatible type
Overload 2 for "__new__" overlaps overload 4 and returns an incompatible type
Overload 2 for "__new__" overlaps overload 5 and returns an incompatible type
Python and NumPy Versions:
2.1.0.dev0+git20240724.3df4283
3.10.12 (main, Mar 22 2024, 16:50:05) [GCC 11.4.0]
Type-checker version and settings:
basedpyright 1.15.0 (pyright 1.1.373)
Additional typing packages.
typing-extensions 4.12.2
Describe the issue:
The commonly used
@overloadpattern with_ArrayLike{}_coparameter types can lead to unexpected type inferences if the return types are incompatible with one another other.An example of this is the
numpy.dtypeconstructor:It correctly infers
dtype(bool)anddtype(int)asdtype[np.bool]anddtype[signedinteger[Any]], respectively.But in the case that either
boolorintcan be passed, e.g asdtype(int_co)withint_co: type[bool] | tuple[int], the resulting type is inferred asdtype[signedinteger[Any]], which is incompatible withdtype[bool].The correct type in this case would be
dtype[bool | signedinteger[Any]].Reproduce the code example:
But the last revealed type doesn't include
bool, i.e. it should have beendtype[bool | signedinteger[Any]].This isn't limited to only
boolandint; all possible non-trivial unions ofbool,int,floatorcomplexhave this problem, see https://typing.readthedocs.io/en/latest/spec/special-types.html#special-cases-for-float-and-complexAnd this also isn't limited to
dtype.__new__:The same issue can be observed with the arithmetic operator methods (e.g.
__add__) ofnumpy.ndarray,numpy.bool, and all subclasses ofnumpy.number, just to name a few.Error message:
With Pyright / Pylance, enabling the
reportOverlappingOverloadsetting will in such cases result in an error message (unless there's a# type: ignorecomment), e.g. fornumpy.dtype.__new__Pylance reports:Python and NumPy Versions:
2.1.0.dev0+git20240724.3df4283
3.10.12 (main, Mar 22 2024, 16:50:05) [GCC 11.4.0]
Type-checker version and settings:
basedpyright 1.15.0 (pyright 1.1.373)
Additional typing packages.
typing-extensions 4.12.2