mypy icon indicating copy to clipboard operation
mypy copied to clipboard

`next(iter(<Tuple[...]>))` should be a `Union` of the `Tuple` element types, rather than their most descended common ancestor

Open finite-state-machine opened this issue 1 year ago • 0 comments

Bug Report

When iterating over a Tuple with mixed types, mypy infers the element type based on the lowest common denominator, rather than a Union of element types. Mypy's behavior is sound, but not as helpful as it could be.

To Reproduce

Gist: mypy-play.net

from __future__ import annotations
from typing import *

A = TypeVar('A')
B = TypeVar('B')
C = TypeVar('C')

def some_func(seq: Tuple[A, B, C]) -> None:
    for element in seq:
        reveal_type(element)  # got: object
                              # expected: Union[A, B, C]

This isn't specific to TypeVars:

Gist: mypy-play.net

from __future__ import annotations
from typing import *

as_us: Union[Sequence[str], Sequence[bytes]]
as_su: Sequence[Union[str, bytes]]
as_tuple: Union[Tuple[str, bytes], Tuple[bytes, str]]

for v1 in as_us:
    reveal_type(v1)     # Union[str, bytes]  (as expected)
for v2 in as_su:
    reveal_type(v2)     # Union[str, bytes]  (as expected)
for v3 in as_tuple:
    reveal_type(v3)     # Sequence[object]   (better: Union[str, bytes])

The behaviour is particularly unhelpful because bytes and str have many interfaces in common, and are accepted interchangeably in many contexts (e.g. re.match(...)), even though they don't share an ancestor class.

Note: mixed tuples (e.g. Tuple[str, bytes]) seem to be essential; this typically won't reproduce if the Tuple only mentions one type (regardless of multiplicity), presumably because it's then handled as a Sequence.

Expected Behavior

Iterating over Tuples with mixed types should be handled as iterating over a Union of those types.

Mypy would ideally identify v3 in the second example as having type Union[str, bytes].

Actual Behavior

Iterating over Tuples with mixed types infers elements to be a common base type of those types.

Mypy identifies v3 has being a Sequence[object]. This is not technically wrong, but it is far less helpful.

Your Environment

  • Mypy version used: 1.8.0, master(2024-02-10)
  • Mypy command-line flags: (none)
  • Mypy configuration options from mypy.ini (and other config files): (none)
  • Python version used: 3.8, 3.12

Other remarks

I've tried to find any existing reports of this issue without success – the keywords are quite general. To assist others in finding this issue, I'll mention Tuple.__iter__().

finite-state-machine avatar Feb 10 '24 22:02 finite-state-machine