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

Use Union for tuple fallback? #7616

Open
mthuurne opened this issue Oct 3, 2019 · 1 comment
Open

Use Union for tuple fallback? #7616

mthuurne opened this issue Oct 3, 2019 · 1 comment
Labels
needs discussion topic-join-v-union Using join vs. using unions

Comments

@mthuurne
Copy link
Contributor

mthuurne commented Oct 3, 2019

  • Please insert below the code you are checking with mypy,
from typing import Iterable, Iterator, Union
from typing_extensions import Protocol

class MixedIter(Protocol):
    def __iter__(self) -> Iterator[Union[int, str]]: ...

def f(xs: Iterable[Union[int, str]]) -> str:
    return ''.join(str(x) for x in xs)

def g(xs: MixedIter) -> str:
    return ''.join(str(x) for x in xs)

mixedTuple = (56, 'A')
reveal_type(mixedTuple)
reveal_type(mixedTuple.__iter__)
print(f(mixedTuple))
print(g(mixedTuple))
  • What is the actual behavior/output?
mixedtuple.py:14: note: Revealed type is 'Tuple[builtins.int, builtins.str]'
mixedtuple.py:15: note: Revealed type is 'def () -> typing.Iterator[builtins.object*]'
mixedtuple.py:17: error: Argument 1 to "g" has incompatible type "Tuple[int, str]"; expected "MixedIter"  [arg-type]
  • What is the behavior/output you expect?

I'd expect both f(mixedTuple) and g(mixedTuple) to be accepted without errors.

  • What are the versions of mypy and Python you are using?

mypy 0.730 on Python 3.7.2.

@msullivan msullivan changed the title Use Union return type for Tuple.__iter__ for mixed-type tuples Use Union for tuple fallback? Oct 4, 2019
@msullivan
Copy link
Collaborator

The situation here is that the use of it as an Iterable is enabled as part of a bevy of unfortunate special cases in our subtype checker: https://github.com/python/mypy/blob/master/mypy/subtypes.py#L277-L286.

The type used to figure out things like the type of mixedTuple.__iter__ is the tuple's "fallback type", which is computed using a join: https://github.com/python/mypy/blob/master/mypy/typeops.py#L34

It seems possible that we could switch to using a union for tuple fallbacks instead of a join and drop those special cases subtyping special cases. The normal worry about switching from using a join to using a union--that it will break calls functions with invariant type constructors--seems less pronounced here since tuples are immutable.

I think the main concern would be when lists are created from tuples with list(mixedTuple). But constraints also has its own batch of special casing (https://github.com/python/mypy/blob/master/mypy/constraints.py#L366-L370) that seems to mitigate that...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs discussion topic-join-v-union Using join vs. using unions
Projects
None yet
Development

No branches or pull requests

3 participants