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

Type inference problem with overloaded mkdtemp #1541

Closed
JukkaL opened this issue May 17, 2016 · 6 comments
Closed

Type inference problem with overloaded mkdtemp #1541

JukkaL opened this issue May 17, 2016 · 6 comments

Comments

@JukkaL
Copy link
Collaborator

JukkaL commented May 17, 2016

tempfile.mkdtemp returns str (in Python 2) if given no arguments. However, if any of the optional arguments is unicode, the return type should be unicode. We can use an overloaded function to represent this:

@overload
def mkdtemp() -> str: ...
@overload
def mkdtemp(suffix: AnyStr = ..., prefix: AnyStr = ..., dir: AnyStr = ...) -> AnyStr: ...

However, mypy infers type Any for call mkdtemp(), because it thinks that both signatures could match equally well. Instead, mypy should give preference to the first signature.

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

refi64 commented May 17, 2016

As a workaround:

What if the optional arguments were of type Union[AnyStr, str] and the return type AnyStr? The extra Union would ensure that unicode and str can be mixed, but if unicode values are passed in, then the return type will end up as unicode.

Note that this is completely untested...

@gvanrossum
Copy link
Member

gvanrossum commented May 17, 2016 via email

@JukkaL
Copy link
Collaborator Author

JukkaL commented May 17, 2016

Yeah, using the type of the defaults would likely be a better approach. For example:

def mkdtemp(suffix: AnyStr = '', prefix: AnyStr = ..., dir: AnyStr = ...) -> AnyStr: ...

Just one default would be sufficient here. dict.get also has a related issue once we introduce strict optional checking.

@matthiaskramm
Copy link
Contributor

This highlights an interesting difference in how mypy and pytype interpret @overload in pyi.

pytype will pick the first matching signature, mypy (it seems?) all matching signatures.

@JukkaL
Copy link
Collaborator Author

JukkaL commented May 18, 2016

Mypy doesn't just pick all matching signatures, though it's more complex than just picking the first signature. The way the example handled is a bug in mypy.

Originally overloads used runtime dispatch (when used outside stubs) and mypy tried to predict precisely which overload variants could be triggered by the dispatcher. There is longer runtime dispatch, but some of the old logic still persists. One of these days I (or somebody) should clean up the implementation of overloads.

Picking just the first matching signature is not correct if one of the arguments has an Any type, as it can match anything. Also, consider this example (mypy doesn't like the overloaded function definition, actually):

@overload
def f(x: int) -> int: ...
@overload
def f(x: object) -> str: ...

def g(o: object) -> None:
    a = f(o)  # can be int or str?

There may be other tricky cases, but it's been while since I thought about overloads carefully.

@Michael0x2a
Copy link
Collaborator

The original example appears to typecheck as expected now, most likely due to f61c2ba. I think we can close this; feel free to reopen if necessary.

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

No branches or pull requests

7 participants