Skip to content

Commit 7745c7f

Browse files
authored
Assert that Parameters are not passed to tuples (#20477)
Fixes #20452. I also noticed `TypeVarTuple`s have the same issue, so I fixed that too.
1 parent da4796a commit 7745c7f

File tree

3 files changed

+58
-22
lines changed

3 files changed

+58
-22
lines changed

mypy/semanal_typeargs.py

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ def visit_type_alias_type(self, t: TypeAliasType) -> None:
109109

110110
def visit_tuple_type(self, t: TupleType) -> None:
111111
t.items = flatten_nested_tuples(t.items)
112+
for i, it in enumerate(t.items):
113+
if self.check_non_paramspec(it, "tuple", t):
114+
t.items[i] = AnyType(TypeOfAny.from_error)
115+
112116
# We could also normalize Tuple[*tuple[X, ...]] -> tuple[X, ...] like in
113117
# expand_type() but we can't do this here since it is not a translator visitor,
114118
# and we need to return an Instance instead of TupleType.
@@ -137,6 +141,28 @@ def visit_instance(self, t: Instance) -> None:
137141
assert unpacked.type.fullname == "builtins.tuple"
138142
t.args = unpacked.args
139143

144+
def check_non_paramspec(self, arg: Type, tv_kind: str, context: Context) -> bool:
145+
if isinstance(arg, ParamSpecType):
146+
self.fail(
147+
INVALID_PARAM_SPEC_LOCATION.format(format_type(arg, self.options)),
148+
context,
149+
code=codes.VALID_TYPE,
150+
)
151+
self.note(
152+
INVALID_PARAM_SPEC_LOCATION_NOTE.format(arg.name), context, code=codes.VALID_TYPE
153+
)
154+
return True
155+
if isinstance(arg, Parameters):
156+
self.fail(
157+
f"Cannot use {format_type(arg, self.options)} for {tv_kind},"
158+
" only for ParamSpec",
159+
context,
160+
code=codes.VALID_TYPE,
161+
)
162+
return True
163+
164+
return False
165+
140166
def validate_args(
141167
self, name: str, args: tuple[Type, ...], type_vars: list[TypeVarLikeType], ctx: Context
142168
) -> tuple[bool, bool]:
@@ -154,28 +180,10 @@ def validate_args(
154180
for arg, tvar in zip(args, type_vars):
155181
context = ctx if arg.line < 0 else arg
156182
if isinstance(tvar, TypeVarType):
157-
if isinstance(arg, ParamSpecType):
158-
is_invalid = True
159-
self.fail(
160-
INVALID_PARAM_SPEC_LOCATION.format(format_type(arg, self.options)),
161-
context,
162-
code=codes.VALID_TYPE,
163-
)
164-
self.note(
165-
INVALID_PARAM_SPEC_LOCATION_NOTE.format(arg.name),
166-
context,
167-
code=codes.VALID_TYPE,
168-
)
169-
continue
170-
if isinstance(arg, Parameters):
183+
if self.check_non_paramspec(arg, "regular type variable", context):
171184
is_invalid = True
172-
self.fail(
173-
f"Cannot use {format_type(arg, self.options)} for regular type variable,"
174-
" only for ParamSpec",
175-
context,
176-
code=codes.VALID_TYPE,
177-
)
178185
continue
186+
179187
if self.in_type_alias_expr and isinstance(arg, TypeVarType):
180188
# Type aliases are allowed to use unconstrained type variables
181189
# error will be checked at substitution point.
@@ -226,6 +234,12 @@ def validate_args(
226234
context,
227235
code=codes.VALID_TYPE,
228236
)
237+
elif isinstance(tvar, TypeVarTupleType):
238+
p_arg = get_proper_type(arg)
239+
assert isinstance(p_arg, TupleType)
240+
for it in p_arg.items:
241+
if self.check_non_paramspec(it, "TypeVarTuple", context):
242+
is_invalid = True
229243
if is_invalid:
230244
is_error = True
231245
return is_error, is_invalid

test-data/unit/check-tuples.test

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1824,3 +1824,10 @@ class tuple_aa_subclass(Tuple[A, A]): ...
18241824

18251825
inst_tuple_aa_subclass: tuple_aa_subclass = tuple_aa_subclass((A(), A()))[:] # E: Incompatible types in assignment (expression has type "tuple[A, A]", variable has type "tuple_aa_subclass")
18261826
[builtins fixtures/tuple.pyi]
1827+
1828+
[case testTuplePassedParameters]
1829+
from typing_extensions import Concatenate
1830+
1831+
def c(t: tuple[Concatenate[int, ...]]) -> None: # E: Cannot use "[int, VarArg(Any), KwArg(Any)]" for tuple, only for ParamSpec
1832+
reveal_type(t) # N: Revealed type is "tuple[Any]"
1833+
[builtins fixtures/tuple.pyi]

test-data/unit/check-typevar-tuple.test

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2481,9 +2481,11 @@ reveal_type(a) # N: Revealed type is "__main__.A[[builtins.int, builtins.str],
24812481
b: B[int, str, [int, str]]
24822482
reveal_type(b) # N: Revealed type is "__main__.B[builtins.int, builtins.str, [builtins.int, builtins.str]]"
24832483

2484-
x: A[int, str, [int, str]] # E: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "int"
2484+
x: A[int, str, [int, str]] # E: Cannot use "[int, str]" for TypeVarTuple, only for ParamSpec \
2485+
# E: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "int"
24852486
reveal_type(x) # N: Revealed type is "__main__.A[Any, Unpack[builtins.tuple[Any, ...]]]"
2486-
y: B[[int, str], int, str] # E: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "str"
2487+
y: B[[int, str], int, str] # E: Cannot use "[int, str]" for TypeVarTuple, only for ParamSpec \
2488+
# E: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "str"
24872489
reveal_type(y) # N: Revealed type is "__main__.B[Unpack[builtins.tuple[Any, ...]], Any]"
24882490

24892491
R = TypeVar("R")
@@ -2739,3 +2741,16 @@ def foo() -> str:
27392741
# this is a false positive, but it no longer crashes
27402742
call(run, foo, some_kwarg="a") # E: Argument 1 to "call" has incompatible type "def [Ts`-1, T] run(func: def (*Unpack[Ts]) -> T, *args: Unpack[Ts], some_kwarg: str = ...) -> T"; expected "Callable[[Callable[[], str], str], str]"
27412743
[builtins fixtures/tuple.pyi]
2744+
2745+
[case testTypeVarTuplePassedParameters]
2746+
from typing import TypeVarTuple, Generic, Unpack
2747+
from typing_extensions import Concatenate
2748+
2749+
Ts = TypeVarTuple("Ts")
2750+
2751+
class X(Generic[Unpack[Ts]]):
2752+
...
2753+
2754+
def c(t: X[Concatenate[int, ...]]) -> None: # E: Cannot use "[int, VarArg(Any), KwArg(Any)]" for TypeVarTuple, only for ParamSpec
2755+
reveal_type(t) # N: Revealed type is "__main__.X[Unpack[builtins.tuple[Any, ...]]]"
2756+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)