From 21755ad77dba7b95138cbf7752c24d1d927085e9 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 25 Sep 2022 16:28:35 -0700 Subject: [PATCH 1/3] test --- test-data/unit/check-python310.test | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test-data/unit/check-python310.test b/test-data/unit/check-python310.test index 22af3ddc0700..cc547fc7c44a 100644 --- a/test-data/unit/check-python310.test +++ b/test-data/unit/check-python310.test @@ -317,6 +317,19 @@ match x: case [str()]: pass +[case testMatchSequencePatternWithInvalidClassPattern] +class Example: + __match_args__ = ("value",) + def __init__(self, value: str) -> None: + self.value = value + +SubClass: type[Example] + +match [SubClass("a"), SubClass("b")]: + case [SubClass(value), *rest]: # E: Expected type in class pattern; found "Type[__main__.Example]" + pass +[builtins fixtures/tuple.pyi] + [case testMatchSequenceUnion-skip] from typing import List, Union m: Union[List[List[str]], str] From 40edd4dceac48839d09d865a45040f0947f249e8 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 25 Sep 2022 16:28:50 -0700 Subject: [PATCH 2/3] fix --- mypy/checkpattern.py | 82 +++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/mypy/checkpattern.py b/mypy/checkpattern.py index 78662b574032..57883c424c85 100644 --- a/mypy/checkpattern.py +++ b/mypy/checkpattern.py @@ -267,51 +267,53 @@ def visit_sequence_pattern(self, o: SequencePattern) -> PatternType: contracted_new_inner_types.append(typ) contracted_rest_inner_types.append(rest) self.update_type_map(captures, type_map) - new_inner_types = self.expand_starred_pattern_types( - contracted_new_inner_types, star_position, len(inner_types) - ) - rest_inner_types = self.expand_starred_pattern_types( - contracted_rest_inner_types, star_position, len(inner_types) - ) - # - # Calculate new type - # new_type: Type rest_type: Type = current_type - if not can_match: - new_type = UninhabitedType() - elif isinstance(current_type, TupleType): - narrowed_inner_types = [] - inner_rest_types = [] - for inner_type, new_inner_type in zip(inner_types, new_inner_types): - ( - narrowed_inner_type, - inner_rest_type, - ) = self.chk.conditional_types_with_intersection( - new_inner_type, [get_type_range(inner_type)], o, default=new_inner_type - ) - narrowed_inner_types.append(narrowed_inner_type) - inner_rest_types.append(inner_rest_type) - if all(not is_uninhabited(typ) for typ in narrowed_inner_types): - new_type = TupleType(narrowed_inner_types, current_type.partial_fallback) - else: - new_type = UninhabitedType() + if can_match: + new_inner_types = self.expand_starred_pattern_types( + contracted_new_inner_types, star_position, len(inner_types) + ) + rest_inner_types = self.expand_starred_pattern_types( + contracted_rest_inner_types, star_position, len(inner_types) + ) - if all(is_uninhabited(typ) for typ in inner_rest_types): - # All subpatterns always match, so we can apply negative narrowing - rest_type = TupleType(rest_inner_types, current_type.partial_fallback) - else: - new_inner_type = UninhabitedType() - for typ in new_inner_types: - new_inner_type = join_types(new_inner_type, typ) - new_type = self.construct_sequence_child(current_type, new_inner_type) - if is_subtype(new_type, current_type): - new_type, _ = self.chk.conditional_types_with_intersection( - current_type, [get_type_range(new_type)], o, default=current_type - ) + # + # Calculate new type + # + if isinstance(current_type, TupleType): + narrowed_inner_types = [] + inner_rest_types = [] + for inner_type, new_inner_type in zip(inner_types, new_inner_types): + ( + narrowed_inner_type, + inner_rest_type, + ) = self.chk.conditional_types_with_intersection( + new_inner_type, [get_type_range(inner_type)], o, default=new_inner_type + ) + narrowed_inner_types.append(narrowed_inner_type) + inner_rest_types.append(inner_rest_type) + if all(not is_uninhabited(typ) for typ in narrowed_inner_types): + new_type = TupleType(narrowed_inner_types, current_type.partial_fallback) + else: + new_type = UninhabitedType() + + if all(is_uninhabited(typ) for typ in inner_rest_types): + # All subpatterns always match, so we can apply negative narrowing + rest_type = TupleType(rest_inner_types, current_type.partial_fallback) else: - new_type = current_type + new_inner_type = UninhabitedType() + for typ in new_inner_types: + new_inner_type = join_types(new_inner_type, typ) + new_type = self.construct_sequence_child(current_type, new_inner_type) + if is_subtype(new_type, current_type): + new_type, _ = self.chk.conditional_types_with_intersection( + current_type, [get_type_range(new_type)], o, default=current_type + ) + else: + new_type = current_type + else: + new_type = UninhabitedType() return PatternType(new_type, rest_type, captures) def get_sequence_type(self, t: Type) -> Type | None: From 079a73d4f4162bff98bcb303a0c90a611843a629 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 25 Sep 2022 16:32:41 -0700 Subject: [PATCH 3/3] okay try this --- mypy/checkpattern.py | 89 +++++++++++++---------------- test-data/unit/check-python310.test | 4 +- 2 files changed, 44 insertions(+), 49 deletions(-) diff --git a/mypy/checkpattern.py b/mypy/checkpattern.py index 57883c424c85..603b392eee29 100644 --- a/mypy/checkpattern.py +++ b/mypy/checkpattern.py @@ -257,63 +257,56 @@ def visit_sequence_pattern(self, o: SequencePattern) -> PatternType: contracted_inner_types = self.contract_starred_pattern_types( inner_types, star_position, required_patterns ) - can_match = True for p, t in zip(o.patterns, contracted_inner_types): pattern_type = self.accept(p, t) typ, rest, type_map = pattern_type - if is_uninhabited(typ): - can_match = False - else: - contracted_new_inner_types.append(typ) - contracted_rest_inner_types.append(rest) + contracted_new_inner_types.append(typ) + contracted_rest_inner_types.append(rest) self.update_type_map(captures, type_map) + new_inner_types = self.expand_starred_pattern_types( + contracted_new_inner_types, star_position, len(inner_types) + ) + rest_inner_types = self.expand_starred_pattern_types( + contracted_rest_inner_types, star_position, len(inner_types) + ) + + # + # Calculate new type + # new_type: Type rest_type: Type = current_type - if can_match: - new_inner_types = self.expand_starred_pattern_types( - contracted_new_inner_types, star_position, len(inner_types) - ) - rest_inner_types = self.expand_starred_pattern_types( - contracted_rest_inner_types, star_position, len(inner_types) - ) - - # - # Calculate new type - # - if isinstance(current_type, TupleType): - narrowed_inner_types = [] - inner_rest_types = [] - for inner_type, new_inner_type in zip(inner_types, new_inner_types): - ( - narrowed_inner_type, - inner_rest_type, - ) = self.chk.conditional_types_with_intersection( - new_inner_type, [get_type_range(inner_type)], o, default=new_inner_type - ) - narrowed_inner_types.append(narrowed_inner_type) - inner_rest_types.append(inner_rest_type) - if all(not is_uninhabited(typ) for typ in narrowed_inner_types): - new_type = TupleType(narrowed_inner_types, current_type.partial_fallback) - else: - new_type = UninhabitedType() - - if all(is_uninhabited(typ) for typ in inner_rest_types): - # All subpatterns always match, so we can apply negative narrowing - rest_type = TupleType(rest_inner_types, current_type.partial_fallback) + if isinstance(current_type, TupleType): + narrowed_inner_types = [] + inner_rest_types = [] + for inner_type, new_inner_type in zip(inner_types, new_inner_types): + ( + narrowed_inner_type, + inner_rest_type, + ) = self.chk.conditional_types_with_intersection( + new_inner_type, [get_type_range(inner_type)], o, default=new_inner_type + ) + narrowed_inner_types.append(narrowed_inner_type) + inner_rest_types.append(inner_rest_type) + if all(not is_uninhabited(typ) for typ in narrowed_inner_types): + new_type = TupleType(narrowed_inner_types, current_type.partial_fallback) else: - new_inner_type = UninhabitedType() - for typ in new_inner_types: - new_inner_type = join_types(new_inner_type, typ) - new_type = self.construct_sequence_child(current_type, new_inner_type) - if is_subtype(new_type, current_type): - new_type, _ = self.chk.conditional_types_with_intersection( - current_type, [get_type_range(new_type)], o, default=current_type - ) - else: - new_type = current_type + new_type = UninhabitedType() + + if all(is_uninhabited(typ) for typ in inner_rest_types): + # All subpatterns always match, so we can apply negative narrowing + rest_type = TupleType(rest_inner_types, current_type.partial_fallback) else: - new_type = UninhabitedType() + new_inner_type = UninhabitedType() + for typ in new_inner_types: + new_inner_type = join_types(new_inner_type, typ) + new_type = self.construct_sequence_child(current_type, new_inner_type) + if is_subtype(new_type, current_type): + new_type, _ = self.chk.conditional_types_with_intersection( + current_type, [get_type_range(new_type)], o, default=current_type + ) + else: + new_type = current_type return PatternType(new_type, rest_type, captures) def get_sequence_type(self, t: Type) -> Type | None: diff --git a/test-data/unit/check-python310.test b/test-data/unit/check-python310.test index cc547fc7c44a..1531ae2e424f 100644 --- a/test-data/unit/check-python310.test +++ b/test-data/unit/check-python310.test @@ -327,7 +327,9 @@ SubClass: type[Example] match [SubClass("a"), SubClass("b")]: case [SubClass(value), *rest]: # E: Expected type in class pattern; found "Type[__main__.Example]" - pass + reveal_type(value) # E: Cannot determine type of "value" \ + # N: Revealed type is "Any" + reveal_type(rest) # N: Revealed type is "builtins.list[__main__.Example]" [builtins fixtures/tuple.pyi] [case testMatchSequenceUnion-skip]