From 80eb33feb08aa249a8e2b5cf1b265ca1491de768 Mon Sep 17 00:00:00 2001 From: A5rocks Date: Wed, 29 Jan 2025 18:47:44 +0900 Subject: [PATCH 1/3] Update the overlapping check for tuples to account for NamedTuples --- mypy/meet.py | 14 +++++++++++++- test-data/unit/check-namedtuple.test | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/mypy/meet.py b/mypy/meet.py index cbe3e99cdcd8..8b2ef07494ea 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -50,6 +50,7 @@ find_unpack_in_list, get_proper_type, get_proper_types, + is_named_instance, split_with_prefix_and_suffix, ) @@ -645,7 +646,18 @@ def are_tuples_overlapping( if len(left.items) != len(right.items): return False - return all(is_overlapping(l, r) for l, r in zip(left.items, right.items)) + if not all(is_overlapping(l, r) for l, r in zip(left.items, right.items)): + return False + + # Check that the tuples aren't from e.g. different NamedTuples. + if is_named_instance(right.partial_fallback, "builtins.tuple") or is_named_instance( + left.partial_fallback, "builtins.tuple" + ): + return True + else: + return is_subtype(left.partial_fallback, right.partial_fallback) or is_subtype( + right.partial_fallback, left.partial_fallback + ) def expand_tuple_if_possible(tup: TupleType, target: int) -> TupleType: diff --git a/test-data/unit/check-namedtuple.test b/test-data/unit/check-namedtuple.test index 172228820add..055081a8feff 100644 --- a/test-data/unit/check-namedtuple.test +++ b/test-data/unit/check-namedtuple.test @@ -1474,3 +1474,19 @@ def main(n: NT[T]) -> None: [builtins fixtures/tuple.pyi] [typing fixtures/typing-namedtuple.pyi] + +[case testNamedTupleOverlappingCheck] +from typing import overload, NamedTuple, Union + +class A(NamedTuple): ... + +class B(NamedTuple): ... + +@overload +def f(arg: A) -> A: ... +@overload +def f(arg: B) -> B: ... +def f(arg: Union[A, B]) -> Union[A, B]: ... + +# no errors should be raised above. +[builtins fixtures/tuple.pyi] From db7473e7267f1c894742c2092e151480424650f9 Mon Sep 17 00:00:00 2001 From: A5rocks Date: Wed, 29 Jan 2025 18:58:15 +0900 Subject: [PATCH 2/3] Switch from `is_subtype` to `is_overlapping` --- mypy/meet.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mypy/meet.py b/mypy/meet.py index 8b2ef07494ea..ea2411b8ccc9 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -655,9 +655,7 @@ def are_tuples_overlapping( ): return True else: - return is_subtype(left.partial_fallback, right.partial_fallback) or is_subtype( - right.partial_fallback, left.partial_fallback - ) + return is_overlapping(left.partial_fallback, right.partial_fallback) def expand_tuple_if_possible(tup: TupleType, target: int) -> TupleType: From 9233143ef1c70d6d532902473e45576f09129d71 Mon Sep 17 00:00:00 2001 From: A5rocks Date: Wed, 29 Jan 2025 23:47:40 +0900 Subject: [PATCH 3/3] Add a test case for https://github.com/python/mypy/issues/18520. --- test-data/unit/check-namedtuple.test | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/test-data/unit/check-namedtuple.test b/test-data/unit/check-namedtuple.test index 055081a8feff..a65a99cc25d0 100644 --- a/test-data/unit/check-namedtuple.test +++ b/test-data/unit/check-namedtuple.test @@ -1478,9 +1478,18 @@ def main(n: NT[T]) -> None: [case testNamedTupleOverlappingCheck] from typing import overload, NamedTuple, Union -class A(NamedTuple): ... +class AKey(NamedTuple): + k: str -class B(NamedTuple): ... +class A(NamedTuple): + key: AKey + + +class BKey(NamedTuple): + k: str + +class B(NamedTuple): + key: BKey @overload def f(arg: A) -> A: ... @@ -1488,5 +1497,12 @@ def f(arg: A) -> A: ... def f(arg: B) -> B: ... def f(arg: Union[A, B]) -> Union[A, B]: ... +def g(x: Union[A, B, str]) -> Union[A, B, str]: + if isinstance(x, str): + return x + else: + 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]]" + return x._replace() + # no errors should be raised above. [builtins fixtures/tuple.pyi]