Open jan-spurny opened 5 months ago
This is not a stub bug as I expected initially when got bitten by this. min
is defined correctly with two different typevars. This is a strange failure of inference.
The following snippet demonstrates the weird inconsistency:
from __future__ import annotations
def foo(x: list[list[int]]) -> list[int] | None:
reveal_type(min(x, key=len, default=None)) # N: Revealed type is "Union[builtins.list[builtins.int], None]"
return min(x, key=len, default=None) # E: Argument "key" to "min" has incompatible type "Callable[[Sized], int]"; expected "Callable[[list[int] | None], SupportsDunderLT[Any] | SupportsDunderGT[Any]]" [arg-type]
foos: list[list[int]]
reveal_type(min(foos, key=len, default=None)) # N: Revealed type is "Union[builtins.list[builtins.int], None]"
min_foo: list[int] | None = min(foos, key=len, default=None) # E: Argument "key" to "min" has incompatible type "Callable[[Sized], int]"; expected "Callable[[list[int] | None], SupportsDunderLT[Any] | SupportsDunderGT[Any]]" [arg-type]
Note that return
line produces an arg-type
error, but the same expression (!) on the previous line has type assignable to return type. The same happens outside of the function with and without output types.
min
is defined in typeshed as
@overload
def min(
arg1: SupportsRichComparisonT, arg2: SupportsRichComparisonT, /, *_args: SupportsRichComparisonT, key: None = None
) -> SupportsRichComparisonT: ...
@overload
def min(arg1: _T, arg2: _T, /, *_args: _T, key: Callable[[_T], SupportsRichComparison]) -> _T: ...
@overload
def min(iterable: Iterable[SupportsRichComparisonT], /, *, key: None = None) -> SupportsRichComparisonT: ...
@overload
def min(iterable: Iterable[_T], /, *, key: Callable[[_T], SupportsRichComparison]) -> _T: ...
@overload
def min(iterable: Iterable[SupportsRichComparisonT], /, *, key: None = None, default: _T) -> SupportsRichComparisonT | _T: ...
@overload
def min(iterable: Iterable[_T1], /, *, key: Callable[[_T1], SupportsRichComparison], default: _T2) -> _T1 | _T2: ...
The relevant overload is the last one.
Here's a playground link: https://mypy-play.net/?mypy=master&python=3.11&flags=strict&gist=8b209a7e7c9ddf0c03f3f6dfb0153316
Bug Report
When using
key
function inmin
builtin function, default None value and returning it from a function which has anOptional
type, mypy reports a problem where I believe there is none.To Reproduce
Expected Behavior
No errors reported.
Actual Behavior
The error goes away if I remove the
default=None
or when themin
is not in a function withX | None
return type:Here, mypy complains only about
get_min_1
:Your Environment
mypy.ini
(and other config files): (no config)