python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.51k stars 2.83k forks source link

Overloading function issues (incompatible with supertype). #3750

Open cynecx opened 7 years ago

cynecx commented 7 years ago
mypy 0.530-dev-417e925b16bcd63ba594f5a85c54b2407bd8831d
KeyTy = TypeVar("KeyTy")
ValTy = TypeVar("ValTy")
TempTy = TypeVar("TempTy")

class CIDict(Dict[KeyTy, ValTy]):
    @overload
    def pop(self, key: KeyTy) -> ValTy:
        pass

    @overload
    def pop(self, key: KeyTy, default: Union[ValTy, TempTy]) \
            -> Union[ValTy, TempTy]:
        pass

    def pop(self, key: KeyTy, default: Optional[Union[ValTy, TempTy]] = None) \
            -> Union[ValTy, TempTy]:
        pass

Running mypy with:

mypy test.py --strict-optional --ignore-missing-imports --disallow-untyped-calls --python-version 3.6

Issues:

CIDict.py:31: error: Signature of "pop" incompatible with supertype "MutableMapping"
CIDict.py:40: error: Overloaded function implementation does not accept all possible arguments of signature 2

Line number differ because the code above is only a snippet.

What am I missing here?

cynecx commented 7 years ago

About that incompatible supertype error. Is it somehow possible to get mypy to print the difference between both types?

ilevkivskyi commented 7 years ago

This actually looks like a bug, the original signature is:

    @overload
    def pop(self, k: _KT) -> _VT: ...
    @overload
    def pop(self, k: _KT, default: Union[_VT, _T] = ...) -> Union[_VT, _T]: ...

Also your idea to print the types seems reasonable, therefore I am also adding a usability label.

ilevkivskyi commented 6 years ago

OK, I have finally found the crux here, mypy considers this unsafe because of arg kinds:

from typing import overload

class A:
    @overload
    def f(self) -> int: ...
    @overload
    def f(self, x: int = ...) -> float: ...

class B(A):
    @overload
    def f(self) -> int: ...
    @overload
    def f(self, x: int) -> float: ...

I am not sure how to convince mypy that it is actually a subtype, this would require a complex overload subtyping algorithm.