diff --git a/mypy/checker.py b/mypy/checker.py index 0387ffce8549..76fa7c33ab27 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -4027,7 +4027,9 @@ def check_subtype(self, subtype = get_proper_type(subtype) supertype = get_proper_type(supertype) - + if self.msg.try_report_long_tuple_assignment_error(subtype, supertype, context, msg, + subtype_label, supertype_label, code=code): + return False if self.should_suppress_optional_error([subtype]): return False extra_info = [] # type: List[str] diff --git a/mypy/messages.py b/mypy/messages.py index a8c6882ad43f..52eb8aa1e5be 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -1387,6 +1387,77 @@ def print_more(self, .format(len(conflicts) - max_items), context, offset=offset, code=code) + def try_report_long_tuple_assignment_error(self, + subtype: ProperType, + supertype: ProperType, + context: Context, + msg: str = message_registry.INCOMPATIBLE_TYPES, + subtype_label: Optional[str] = None, + supertype_label: Optional[str] = None, + code: Optional[ErrorCode] = None) -> bool: + """Try to generate meaningful error message for very long tuple assignment + + Returns a bool: True when generating long tuple assignment error, + False when no such error reported + """ + if isinstance(subtype, TupleType): + if (len(subtype.items) > 10 and + isinstance(supertype, Instance) and + supertype.type.fullname == 'builtins.tuple'): + lhs_type = supertype.args[0] + lhs_types = [lhs_type] * len(subtype.items) + self.generate_incompatible_tuple_error(lhs_types, + subtype.items, context, msg, code) + return True + elif (isinstance(supertype, TupleType) and + (len(subtype.items) > 10 or len(supertype.items) > 10)): + if len(subtype.items) != len(supertype.items): + if supertype_label is not None and subtype_label is not None: + error_msg = "{} ({} {}, {} {})".format(msg, subtype_label, + self.format_long_tuple_type(subtype), supertype_label, + self.format_long_tuple_type(supertype)) + self.fail(error_msg, context, code=code) + return True + self.generate_incompatible_tuple_error(supertype.items, + subtype.items, context, msg, code) + return True + return False + + def format_long_tuple_type(self, typ: TupleType) -> str: + """Format very long tuple type using an ellipsis notation""" + item_cnt = len(typ.items) + if item_cnt > 10: + return 'Tuple[{}, {}, ... <{} more items>]'\ + .format(format_type_bare(typ.items[0]), + format_type_bare(typ.items[1]), str(item_cnt - 2)) + else: + return format_type_bare(typ) + + def generate_incompatible_tuple_error(self, + lhs_types: List[Type], + rhs_types: List[Type], + context: Context, + msg: str = message_registry.INCOMPATIBLE_TYPES, + code: Optional[ErrorCode] = None) -> None: + """Generate error message for individual incompatible tuple pairs""" + error_cnt = 0 + notes = [] # List[str] + for i, (lhs_t, rhs_t) in enumerate(zip(lhs_types, rhs_types)): + if not is_subtype(lhs_t, rhs_t): + if error_cnt < 3: + notes.append('Expression tuple item {} has type "{}"; "{}" expected; ' + .format(str(i), format_type_bare(rhs_t), format_type_bare(lhs_t))) + error_cnt += 1 + + error_msg = msg + ' ({} tuple items are incompatible'.format(str(error_cnt)) + if error_cnt - 3 > 0: + error_msg += '; {} items are omitted)'.format(str(error_cnt - 3)) + else: + error_msg += ')' + self.fail(error_msg, context, code=code) + for note in notes: + self.note(note, context, code=code) + def quote_type_string(type_string: str) -> str: """Quotes a type representation for use in messages.""" diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index 73c1c9ac6236..4058bd509535 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -1241,3 +1241,46 @@ b = ("bar", 7) reveal_type(a + b) # N: Revealed type is 'Tuple[builtins.int, builtins.str, builtins.int, builtins.str, builtins.int]' [builtins fixtures/tuple.pyi] + +[case testAssigningWithLongTupleInitializer] +from typing import Tuple + +# long initializer assignment with few mismatches +t: Tuple[int, ...] = (1, 2, 3, 4, 5, 6, 7, 8, "str", "str", "str", 11) \ + # E: Incompatible types in assignment (3 tuple items are incompatible) \ + # N: Expression tuple item 8 has type "str"; "int" expected; \ + # N: Expression tuple item 9 has type "str"; "int" expected; \ + # N: Expression tuple item 10 has type "str"; "int" expected; + +# long initializer assignment with more mismatches +t1: Tuple[int, ...] = (1, 2, 3, 4, 5, 6, 7, 8, "str", "str", "str", "str") \ + # E: Incompatible types in assignment (4 tuple items are incompatible; 1 items are omitted) \ + # N: Expression tuple item 8 has type "str"; "int" expected; \ + # N: Expression tuple item 9 has type "str"; "int" expected; \ + # N: Expression tuple item 10 has type "str"; "int" expected; + +# short tuple initializer assignment +t2: Tuple[int, ...] = (1, 2, "s", 4) \ + # E: Incompatible types in assignment (expression has type "Tuple[int, int, str, int]", variable has type "Tuple[int, ...]") + +# long initializer assignment with few mismatches, no ellipsis +t3: Tuple[int, int, int, int, int, int, int, int, int, int, int, int] = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "str", "str") \ + # E: Incompatible types in assignment (2 tuple items are incompatible) \ + # N: Expression tuple item 10 has type "str"; "int" expected; \ + # N: Expression tuple item 11 has type "str"; "int" expected; + +# long initializer assignment with more mismatches, no ellipsis +t4: Tuple[int, int, int, int, int, int, int, int, int, int, int, int] = (1, 2, 3, 4, 5, 6, 7, 8, "str", "str", "str", "str") \ + # E: Incompatible types in assignment (4 tuple items are incompatible; 1 items are omitted) \ + # N: Expression tuple item 8 has type "str"; "int" expected; \ + # N: Expression tuple item 9 has type "str"; "int" expected; \ + # N: Expression tuple item 10 has type "str"; "int" expected; + +# short tuple initializer assignment, no ellipsis +t5: Tuple[int, int] = (1, 2, "s", 4) # E: Incompatible types in assignment (expression has type "Tuple[int, int, str, int]", variable has type "Tuple[int, int]") + +# long initializer assignment with mismatched pairs +t6: Tuple[int, int, int, int, int, int, int, int, int, int, int, int] = (1, 2, 3, 4, 5, 6, 7, 8, "str", "str", "str", "str", 1, 1, 1, 1, 1) \ + # E: Incompatible types in assignment (expression has type Tuple[int, int, ... <15 more items>], variable has type Tuple[int, int, ... <10 more items>]) + +[builtins fixtures/tuple.pyi]
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: