Skip to content

Commit e2b821b

Browse files
authored
Update the overlapping check for tuples to account for NamedTuples (#18564)
Fixes #18562. Fixes #6623. Fixes #18520. (Only incidentally and I'm not exactly sure why.) I was investigating what input mypy thought satisfied both overloads and I found that mypy is missing a check on the fallback type.
1 parent 7d084e9 commit e2b821b

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed

mypy/meet.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
find_unpack_in_list,
5151
get_proper_type,
5252
get_proper_types,
53+
is_named_instance,
5354
split_with_prefix_and_suffix,
5455
)
5556

@@ -645,7 +646,16 @@ def are_tuples_overlapping(
645646

646647
if len(left.items) != len(right.items):
647648
return False
648-
return all(is_overlapping(l, r) for l, r in zip(left.items, right.items))
649+
if not all(is_overlapping(l, r) for l, r in zip(left.items, right.items)):
650+
return False
651+
652+
# Check that the tuples aren't from e.g. different NamedTuples.
653+
if is_named_instance(right.partial_fallback, "builtins.tuple") or is_named_instance(
654+
left.partial_fallback, "builtins.tuple"
655+
):
656+
return True
657+
else:
658+
return is_overlapping(left.partial_fallback, right.partial_fallback)
649659

650660

651661
def expand_tuple_if_possible(tup: TupleType, target: int) -> TupleType:

test-data/unit/check-namedtuple.test

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,3 +1474,35 @@ def main(n: NT[T]) -> None:
14741474

14751475
[builtins fixtures/tuple.pyi]
14761476
[typing fixtures/typing-namedtuple.pyi]
1477+
1478+
[case testNamedTupleOverlappingCheck]
1479+
from typing import overload, NamedTuple, Union
1480+
1481+
class AKey(NamedTuple):
1482+
k: str
1483+
1484+
class A(NamedTuple):
1485+
key: AKey
1486+
1487+
1488+
class BKey(NamedTuple):
1489+
k: str
1490+
1491+
class B(NamedTuple):
1492+
key: BKey
1493+
1494+
@overload
1495+
def f(arg: A) -> A: ...
1496+
@overload
1497+
def f(arg: B) -> B: ...
1498+
def f(arg: Union[A, B]) -> Union[A, B]: ...
1499+
1500+
def g(x: Union[A, B, str]) -> Union[A, B, str]:
1501+
if isinstance(x, str):
1502+
return x
1503+
else:
1504+
reveal_type(x) # N: Revealed type is "Union[Tuple[Tuple[builtins.str, fallback=__main__.AKey], fallback=__main__.A], Tuple[Tuple[builtins.str, fallback=__main__.BKey], fallback=__main__.B]]"
1505+
return x._replace()
1506+
1507+
# no errors should be raised above.
1508+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)