Skip to content

Commit 2e7882f

Browse files
ilevkivskyix612skm
authored andcommitted
Fix handling of named tuples in class match pattern (python#18663)
Fixes python#15299 The fix is straightforward, named tuples should be properly represented as tuples with fallback, not as instances.
1 parent ac18748 commit 2e7882f

File tree

2 files changed

+34
-11
lines changed

2 files changed

+34
-11
lines changed

Diff for: mypy/checkpattern.py

+4-11
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
get_proper_type,
5555
split_with_prefix_and_suffix,
5656
)
57-
from mypy.typevars import fill_typevars
57+
from mypy.typevars import fill_typevars, fill_typevars_with_any
5858
from mypy.visitor import PatternVisitor
5959

6060
self_match_type_names: Final = [
@@ -544,16 +544,7 @@ def visit_class_pattern(self, o: ClassPattern) -> PatternType:
544544
self.msg.fail(message_registry.CLASS_PATTERN_GENERIC_TYPE_ALIAS, o)
545545
return self.early_non_match()
546546
if isinstance(type_info, TypeInfo):
547-
any_type = AnyType(TypeOfAny.implementation_artifact)
548-
args: list[Type] = []
549-
for tv in type_info.defn.type_vars:
550-
if isinstance(tv, TypeVarTupleType):
551-
args.append(
552-
UnpackType(self.chk.named_generic_type("builtins.tuple", [any_type]))
553-
)
554-
else:
555-
args.append(any_type)
556-
typ: Type = Instance(type_info, args)
547+
typ: Type = fill_typevars_with_any(type_info)
557548
elif isinstance(type_info, TypeAlias):
558549
typ = type_info.target
559550
elif (
@@ -703,6 +694,8 @@ def visit_class_pattern(self, o: ClassPattern) -> PatternType:
703694

704695
def should_self_match(self, typ: Type) -> bool:
705696
typ = get_proper_type(typ)
697+
if isinstance(typ, TupleType):
698+
typ = typ.partial_fallback
706699
if isinstance(typ, Instance) and typ.type.get("__match_args__") is not None:
707700
# Named tuples and other subtypes of builtins that define __match_args__
708701
# should not self match.

Diff for: test-data/unit/check-python310.test

+30
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,21 @@ match m:
770770
reveal_type(j) # N: Revealed type is "builtins.int"
771771
[builtins fixtures/tuple.pyi]
772772

773+
[case testMatchSequencePatternCaptureNamedTuple]
774+
from typing import NamedTuple
775+
776+
class N(NamedTuple):
777+
x: int
778+
y: str
779+
780+
a = N(1, "a")
781+
782+
match a:
783+
case [x, y]:
784+
reveal_type(x) # N: Revealed type is "builtins.int"
785+
reveal_type(y) # N: Revealed type is "builtins.str"
786+
[builtins fixtures/tuple.pyi]
787+
773788
[case testMatchClassPatternCaptureGeneric]
774789
from typing import Generic, TypeVar
775790

@@ -2522,3 +2537,18 @@ def fn2(x: Some | int | str) -> None:
25222537
case Some(value): # E: Incompatible types in capture pattern (pattern captures type "Union[int, str]", variable has type "Callable[[], str]")
25232538
pass
25242539
[builtins fixtures/dict.pyi]
2540+
2541+
[case testMatchNamedTupleSequence]
2542+
from typing import Any, NamedTuple
2543+
2544+
class T(NamedTuple):
2545+
t: list[Any]
2546+
2547+
class K(NamedTuple):
2548+
k: int
2549+
2550+
def f(t: T) -> None:
2551+
match t:
2552+
case T([K() as k]):
2553+
reveal_type(k) # N: Revealed type is "Tuple[builtins.int, fallback=__main__.K]"
2554+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)