Skip to content

Incorrect value type inferred for min/max in some contexts #6692

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mthuurne opened this issue Apr 18, 2019 · 1 comment
Closed

Incorrect value type inferred for min/max in some contexts #6692

mthuurne opened this issue Apr 18, 2019 · 1 comment

Comments

@mthuurne
Copy link
Contributor

I'm using mypy 0.701 on Python 3.7.2, no flags.

When run on the following code:

from typing import Iterable, Optional

def longest(values: Iterable[str]) -> Optional[str]:
    return max(values, key=len, default=None)

print(longest(['badger', 'mushroom', 'snake']))
print(longest([]))

mypy reports:

4: error: Argument "key" to "max" has incompatible type "Callable[[Sized], int]"; expected "Callable[[Optional[str]], Any]"

While this looks similar to #6460, the root cause is not the same: mypy 0.701 contains the updated typeshed with a signature that uses a Union for the return type of max. Also the test case from that issue passes now. The difference with my test case seems to be in the expected return type.

To make absolutely certain that the built-in signature is not the problem, I created this test case that uses a custom mox function with the same signature as max:

from typing import Any, Callable, Iterable, Optional, TypeVar, Union

_T = TypeVar('_T')
_VT = TypeVar('_VT')

def mox(iterable: Iterable[_T],
        key: Callable[[_T], Any],
        default: _VT
        ) -> Union[_T, _VT]: ...

def moxest(values: Iterable[str]) -> Optional[str]:
    return mox(values, key=len, default=None)

def has_mox(values: Iterable[str]) -> bool:
    return bool(mox(values, key=len, default=None))

mypy reports:

12: error: Argument "key" to "mox" has incompatible type "Callable[[Sized], int]"; expected "Callable[[Optional[str]], Any]"
15: error: Argument "key" to "mox" has incompatible type "Callable[[Sized], int]"; expected "Callable[[object], Any]"

So the expected value type seems to be influenced by the expected return type of the expression, instead of being determined solely by the argument types.

I guess there could be situations in which picking a weaker value type is useful, but in this case the weaker type causes a false positive.

@ilevkivskyi
Copy link
Member

So the expected value type seems to be influenced by the expected return type of the expression, instead of being determined solely by the argument types.

Yes, this is how mypy is designed to work. Empirically, this approach leads to fewer false positives and better error messages.

I guess there could be situations in which picking a weaker value type is useful, but in this case the weaker type causes a false positive.

Yes, contravariant generics (like callables) is a known exception. Essentially, this is a duplicate of #6482 which is an (important) special case of #5874.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants