diff --git a/mypy/semanal.py b/mypy/semanal.py index 2a24c129b133..340db6c0c252 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -3292,6 +3292,15 @@ def process_paramspec_declaration(self, s: AssignmentStmt) -> bool: if not self.check_typevarlike_name(call, name, s): return False + # ParamSpec is different from a regular TypeVar: + # arguments are not semantically valid. But, allowed in runtime. + # So, we need to warn users about possible invalid usage. + if len(call.args) > 1: + self.fail( + "Only the first argument to ParamSpec has defined semantics", + s, + ) + # PEP 612 reserves the right to define bound, covariant and contravariant arguments to # ParamSpec in a later PEP. If and when that happens, we should do something # on the lines of process_typevar_parameters diff --git a/test-data/unit/check-parameter-specification.test b/test-data/unit/check-parameter-specification.test index f6123915aada..f2281babb193 100644 --- a/test-data/unit/check-parameter-specification.test +++ b/test-data/unit/check-parameter-specification.test @@ -3,6 +3,16 @@ from typing_extensions import ParamSpec P = ParamSpec('P') [builtins fixtures/tuple.pyi] +[case testInvalidParamSpecDefinitions] +from typing import ParamSpec + +P1 = ParamSpec("P1", covariant=True) # E: Only the first argument to ParamSpec has defined semantics +P2 = ParamSpec("P2", contravariant=True) # E: Only the first argument to ParamSpec has defined semantics +P3 = ParamSpec("P3", bound=int) # E: Only the first argument to ParamSpec has defined semantics +P4 = ParamSpec("P4", int, str) # E: Only the first argument to ParamSpec has defined semantics +P5 = ParamSpec("P5", covariant=True, bound=int) # E: Only the first argument to ParamSpec has defined semantics +[builtins fixtures/tuple.pyi] + [case testParamSpecLocations] from typing import Callable, List from typing_extensions import ParamSpec, Concatenate