diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 056b2f7bd2c6..c87d1f6cd31c 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4902,7 +4902,7 @@ def tuple_context_matches(self, expr: TupleExpr, ctx: TupleType) -> bool: return len([e for e in expr.items if not isinstance(e, StarExpr)]) <= len(ctx.items) # For variadic context, the only easy case is when structure matches exactly. # TODO: try using tuple type context in more cases. - if len([e for e in expr.items if not isinstance(e, StarExpr)]) != 1: + if len([e for e in expr.items if isinstance(e, StarExpr)]) != 1: return False expr_star_index = next(i for i, lv in enumerate(expr.items) if isinstance(lv, StarExpr)) return len(expr.items) == len(ctx.items) and ctx_unpack_index == expr_star_index @@ -4941,6 +4941,9 @@ def visit_tuple_expr(self, e: TupleExpr) -> Type: if type_context_items is not None: unpack_in_context = find_unpack_in_list(type_context_items) is not None seen_unpack_in_items = False + allow_precise_tuples = ( + unpack_in_context or PRECISE_TUPLE_TYPES in self.chk.options.enable_incomplete_feature + ) # Infer item types. Give up if there's a star expression # that's not a Tuple. @@ -4981,10 +4984,7 @@ def visit_tuple_expr(self, e: TupleExpr) -> Type: # result in an error later, just do something predictable here. j += len(tt.items) else: - if ( - PRECISE_TUPLE_TYPES in self.chk.options.enable_incomplete_feature - and not seen_unpack_in_items - ): + if allow_precise_tuples and not seen_unpack_in_items: # Handle (x, *y, z), where y is e.g. tuple[Y, ...]. if isinstance(tt, Instance) and self.chk.type_is_iterable(tt): item_type = self.chk.iterable_item_type(tt, e) diff --git a/test-data/unit/check-typevar-tuple.test b/test-data/unit/check-typevar-tuple.test index 25babf442d21..487f22699724 100644 --- a/test-data/unit/check-typevar-tuple.test +++ b/test-data/unit/check-typevar-tuple.test @@ -2225,3 +2225,13 @@ bar(*keys, 1) # OK reveal_type(baz(keys, 1)) # N: Revealed type is "builtins.object" reveal_type(baz(*keys, 1)) # N: Revealed type is "builtins.int" [builtins fixtures/tuple.pyi] + +[case testVariadicTupleContextNoCrash] +from typing import Tuple, Unpack + +x: Tuple[int, Unpack[Tuple[int, ...]]] = () # E: Incompatible types in assignment (expression has type "Tuple[()]", variable has type "Tuple[int, Unpack[Tuple[int, ...]]]") +y: Tuple[int, Unpack[Tuple[int, ...]]] = (1, 2) +z: Tuple[int, Unpack[Tuple[int, ...]]] = (1,) +w: Tuple[int, Unpack[Tuple[int, ...]]] = (1, *[2, 3, 4]) +t: Tuple[int, Unpack[Tuple[int, ...]]] = (1, *(2, 3, 4)) +[builtins fixtures/tuple.pyi]