Skip to content
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

Errors when using overloaded functions and type variables #4619

Closed
elias6 opened this issue Feb 22, 2018 · 3 comments · Fixed by #5236
Closed

Errors when using overloaded functions and type variables #4619

elias6 opened this issue Feb 22, 2018 · 3 comments · Fixed by #5236
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal topic-overloads topic-type-variables

Comments

@elias6
Copy link
Contributor

elias6 commented Feb 22, 2018

I am using the latest version of mypy from master (mypy 0.570-dev-8f253c2338863c9de5329053890d26a966fc3d7c) and Python 3.6.4. I have a file with the following code:

from typing import overload, List, TypeVar, Union

T = TypeVar('T', bytes, str)

@overload
def make_result(x: T) -> T: ...
@overload
def make_result(x: int) -> List: ...
def make_result(x: Union[bytes, str, int]) -> Union[bytes, str, List]:
    if isinstance(x, int):
        return [x]
    else:
        return x

When I run it through mypy, it gives me the following errors:

overload_test.py:9: error: Overloaded function implementation does not accept all possible arguments of signature 1
overload_test.py:9: error: Overloaded function implementation cannot produce return type of signature 1

What does that mean? I'm guessing that "signature 1" means the first overload, involving the type variable. If I switch around the overloads, I get similar errors about "signature 2".

But what possible arguments does my implementation not accept? The only types that the parameter can have are bytes and str (from the first overload) and int (from the second overload). As far as I know, Union[bytes, str, int] covers all of those.

Likewise with the return type. The overloads have possible return types of bytes, str, and List, and Union[bytes, str, List] covers all of those.

I am aware that the implementation can accept some combinations that none of my overloads can accept (like (int) -> str), but I don't think that should be an error because I'm not actually calling the function with any of those combinations. And if I replace the first signature with two signatures, not involving a generic type ((bytes) -> bytes and (str) -> str), I have a similar situation, where the implementation can accept combinations that the overloads can't accept, but I get no errors.

I thought that this may be caused by my own misunderstanding of type variables and generics, so I changed the type hints in the function to look like def make_result(x: Union[T, int]) -> Union[T, List]: to see what would happen. I got this error:

overload_test.py:9: error: Type variable mismatch between overload signature 2 and implementation

What type variable mismatch is that referring to?

I know that I have filed some bugs that were duplicates of existing bugs, or errors caused by my own incorrect usage of mypy. I am sorry about that. But this time, I really think I found a new bug.

@gvanrossum
Copy link
Member

It looks like mypy doesn't realize that, because of the "value restriction" on the type variable, the implementation actually matches all inputs.

As a workaround you can change the implementation to use Any, but it really does seem to be a bug. Or you can get rid of the type variable and instead use two overloads. Or you can use T = TypeVar('T', bound=Union[str, bytes]).

@elias6
Copy link
Contributor Author

elias6 commented Mar 8, 2018

@gvanrossum thanks for the response. I think I can find a way to deal with it for now.

@Hnasar
Copy link
Contributor

Hnasar commented Mar 21, 2018

Another example, which I think seems to be the same issue? (Using 0.570)

from typing import overload, Union, List, TypeVar

T = TypeVar('T')


@overload
def first_or_only(t):
    # type: (List[T]) -> T
    pass


@overload
def first_or_only(t):
    # type: (T) -> T
    pass


def first_or_only(t):
    # type: (Union[List[T], T]) -> T
    if isinstance(t, list):
        return t[0]

    return t


x = 5
x = first_or_only(x)

y = [5]
y = first_or_only(y)

Which results in

main.py:20: error: Overloaded function implementation does not accept all possible arguments of signature 1
main.py:31: error: Argument 1 to "first_or_only" has incompatible type "List[int]"; expected "List[List[int]]"

For now, changing the parameter in the final definition to Any allows this to typecheck.

Edit: Or upon thinking about it a little more I suppose I don't need to use overload here. But still, the error messages are confusing to me.

@ilevkivskyi ilevkivskyi added false-positive mypy gave an error on correct code topic-overloads labels May 19, 2018
Michael0x2a added a commit to Michael0x2a/mypy that referenced this issue Jun 19, 2018
This pull request fixes python#4619 as
well as an unrelated (and unreported) bug where if the overload
implementation was untyped, we only check to see if there are unsafe
overlaps between the *first* overload alternative and the rest.
Michael0x2a added a commit to Michael0x2a/mypy that referenced this issue Jun 19, 2018
This pull request fixes python#4619 as
well as an unrelated bug where if the overload implementation was untyped,
we only check to see if there are unsafe overlaps between the *first*
overload alternative and the rest.
Michael0x2a added a commit to Michael0x2a/mypy that referenced this issue Jun 21, 2018
This pull request fixes python#4619 as
well as an unrelated bug where if the overload implementation was untyped,
we only check to see if there are unsafe overlaps between the *first*
overload alternative and the rest.
ilevkivskyi pushed a commit that referenced this issue Jun 25, 2018
…#5236)

* Make overload impl checks correctly handle TypeVars and untyped impls

This pull request fixes #4619 as
well as an unrelated bug where if the overload implementation was untyped,
we only check to see if there are unsafe overlaps between the *first*
overload alternative and the rest.

* Remove unify_generics parameter
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal topic-overloads topic-type-variables
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants