Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -5348,8 +5348,20 @@ 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
# A variadic tuple context justifies inferring a precise tuple type even when
# tuple_context_matches() rejected the context because the structure doesn't
# line up exactly (e.g. (*a, "last") against tuple[str, *tuple[str, ...]]).
# Without this, such an expression collapses to tuple[str, ...], which is not
# assignable back to the variadic context. Note this deliberately does not feed
# unpack_in_context, whose index bookkeeping below relies on a full match.
variadic_context = (
isinstance(type_context, TupleType)
and find_unpack_in_list(type_context.items) is not None
)
allow_precise_tuples = (
unpack_in_context or PRECISE_TUPLE_TYPES in self.chk.options.enable_incomplete_feature
unpack_in_context
or variadic_context
or PRECISE_TUPLE_TYPES in self.chk.options.enable_incomplete_feature
)

# Infer item types. Give up if there's a star expression
Expand Down
21 changes: 21 additions & 0 deletions test-data/unit/check-typevar-tuple.test
Original file line number Diff line number Diff line change
Expand Up @@ -1738,6 +1738,27 @@ vt = 1, *test(), 2 # OK, type context is used
vt2 = 1, *test(), 2 # E: Need type annotation for "vt2"
[builtins fixtures/tuple.pyi]

[case testVariadicTupleContextStarPositionMismatch]
from typing import Tuple
from typing_extensions import Unpack

a: Tuple[str, ...]
b: Tuple[str, Unpack[Tuple[str, ...]]]

# The star lines up with the context unpack.
b = ("first", *a)
# The star does not line up, but the context is still variadic, so the
# precise tuple type is inferred rather than collapsing to tuple[str, ...].
b = (*a, "last")

# A variadic context must not paper over genuinely incompatible item types.
c: Tuple[int, Unpack[Tuple[int, ...]]]
c = (*a, "last") # E: Incompatible types in assignment (expression has type "tuple[Unpack[tuple[str, ...]], str]", variable has type "tuple[int, Unpack[tuple[int, ...]]]")
# A fixed-length context still requires enough items.
d: Tuple[str, str, Unpack[Tuple[str, ...]]]
d = ("only",) # E: Incompatible types in assignment (expression has type "tuple[str]", variable has type "tuple[str, str, Unpack[tuple[str, ...]]]")
[builtins fixtures/tuple.pyi]

[case testVariadicTupleConcatenation]
# flags: --enable-incomplete-feature=PreciseTupleTypes
from typing import Tuple
Expand Down
Loading