Skip to content

Commit f9b1db6

Browse files
Fix crash on invalid type variable with ParamSpec (#15953)
Fixes #15948 The fix is straightforward: invalid type variable resulted in applying type arguments packing/simplification when we shouldn't. Making the latter more strict fixes the issue. --------- Co-authored-by: Jelle Zijlstra <[email protected]>
1 parent 9e1f4df commit f9b1db6

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

mypy/typeanal.py

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -458,11 +458,30 @@ def pack_paramspec_args(self, an_args: Sequence[Type]) -> list[Type]:
458458
# These do not support mypy_extensions VarArgs, etc. as they were already analyzed
459459
# TODO: should these be re-analyzed to get rid of this inconsistency?
460460
count = len(an_args)
461-
if count > 0:
462-
first_arg = get_proper_type(an_args[0])
463-
if not (count == 1 and isinstance(first_arg, (Parameters, ParamSpecType, AnyType))):
464-
return [Parameters(an_args, [ARG_POS] * count, [None] * count)]
465-
return list(an_args)
461+
if count == 0:
462+
return []
463+
if count == 1 and isinstance(get_proper_type(an_args[0]), AnyType):
464+
# Single Any is interpreted as ..., rather that a single argument with Any type.
465+
# I didn't find this in the PEP, but it sounds reasonable.
466+
return list(an_args)
467+
if any(isinstance(a, (Parameters, ParamSpecType)) for a in an_args):
468+
if len(an_args) > 1:
469+
first_wrong = next(
470+
arg for arg in an_args if isinstance(arg, (Parameters, ParamSpecType))
471+
)
472+
self.fail(
473+
"Nested parameter specifications are not allowed",
474+
first_wrong,
475+
code=codes.VALID_TYPE,
476+
)
477+
return [AnyType(TypeOfAny.from_error)]
478+
return list(an_args)
479+
first = an_args[0]
480+
return [
481+
Parameters(
482+
an_args, [ARG_POS] * count, [None] * count, line=first.line, column=first.column
483+
)
484+
]
466485

467486
def cannot_resolve_type(self, t: UnboundType) -> None:
468487
# TODO: Move error message generation to messages.py. We'd first
@@ -503,7 +522,11 @@ def apply_concatenate_operator(self, t: UnboundType) -> Type:
503522
names: list[str | None] = [None] * len(args)
504523

505524
pre = Parameters(
506-
args + pre.arg_types, [ARG_POS] * len(args) + pre.arg_kinds, names + pre.arg_names
525+
args + pre.arg_types,
526+
[ARG_POS] * len(args) + pre.arg_kinds,
527+
names + pre.arg_names,
528+
line=t.line,
529+
column=t.column,
507530
)
508531
return ps.copy_modified(prefix=pre) if isinstance(ps, ParamSpecType) else pre
509532

@@ -913,7 +936,7 @@ def visit_type_list(self, t: TypeList) -> Type:
913936
if params:
914937
ts, kinds, names = params
915938
# bind these types
916-
return Parameters(self.anal_array(ts), kinds, names)
939+
return Parameters(self.anal_array(ts), kinds, names, line=t.line, column=t.column)
917940
else:
918941
return AnyType(TypeOfAny.from_error)
919942
else:

test-data/unit/check-parameter-specification.test

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,3 +1741,26 @@ def bar(x): ...
17411741

17421742
reveal_type(bar) # N: Revealed type is "Overload(def (x: builtins.int) -> builtins.float, def (x: builtins.str) -> builtins.str)"
17431743
[builtins fixtures/paramspec.pyi]
1744+
1745+
[case testParamSpecDecoratorOverloadNoCrashOnInvalidTypeVar]
1746+
from typing import Any, Callable, List
1747+
from typing_extensions import ParamSpec
1748+
1749+
P = ParamSpec("P")
1750+
T = 1
1751+
1752+
Alias = Callable[P, List[T]] # type: ignore
1753+
def dec(fn: Callable[P, T]) -> Alias[P, T]: ... # type: ignore
1754+
f: Any
1755+
dec(f) # No crash
1756+
[builtins fixtures/paramspec.pyi]
1757+
1758+
[case testParamSpecErrorNestedParams]
1759+
from typing import Generic
1760+
from typing_extensions import ParamSpec
1761+
1762+
P = ParamSpec("P")
1763+
class C(Generic[P]): ...
1764+
c: C[int, [int, str], str] # E: Nested parameter specifications are not allowed
1765+
reveal_type(c) # N: Revealed type is "__main__.C[Any]"
1766+
[builtins fixtures/paramspec.pyi]

0 commit comments

Comments
 (0)