Skip to content

Can't pass a value of type Union[str, bytes] to a generic function typed with AnyStr #1533

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

Open
gvanrossum opened this issue May 15, 2016 · 2 comments
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal topic-union-types

Comments

@gvanrossum
Copy link
Member

gvanrossum commented May 15, 2016

Repro:

from typing import AnyStr, Union
def g(a: AnyStr) -> AnyStr:
    pass
def f(a: Union[str, bytes]):
    g(a)

We get an error on the last line:

c.py:5: error: Type argument 1 of "g" has incompatible value "Union[str, bytes]"

I would have expected that it would just deduce that y is also a Union[str, bytes].

(UPDATE: shortened the repro.)

@JukkaL
Copy link
Collaborator

JukkaL commented May 16, 2016

Yeah, it would be nice if the example would work. Generally substituting Union[str, bytes] for AnyStr would be wrong, though. Instead, the union could be decomposed into the components and these could be checked separately.

The reason why can't substitute a union is a little subtle. First, consider this example:

from typing import AnyStr, Union, Sequence

def g(a: Sequence[AnyStr]) -> Sequence[AnyStr]:
    if isinstance(a[0], str):
        for s in a:
            print(s + 'x')

def f(a: Sequence[Union[str, bytes]]):
    g(a)   # should be rejected

Now the call should be rejected, since g expects a uniform sequence and can fail on a mixed sequence.

Here is another example:

from typing import AnyStr, Union, List

def g(a: AnyStr, b: AnyStr) -> None:
    if isinstance(a, str):
        print(a + b)

def f(a: Union[str, bytes], b: Union[str, bytes]):
    g(a, b)  # should be rejected 

The latter example is similar but doesn't use generics. Here we could type check the call g(a, b) with all 4 possible argument type combinations.

Substituting a union type might be safe if AnyStr is only used once in an argument type and it's used as a bare type (not within a generic or a composite type). Not 100% about this, though.

@JukkaL JukkaL added the bug mypy got something wrong label May 16, 2016
@rwbarton
Copy link
Contributor

We do already perform this kind of separate type checking of each case when type checking a method call on a union, so it does seem natural to extend that to function calls as @JukkaL described. Another place this would come up is in calls to overloaded functions.

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-union-types
Projects
None yet
Development

No branches or pull requests

5 participants