Skip to content

Commit 575f772

Browse files
committed
Require ListExpr for ParamSpec defaults
1 parent 5c29737 commit 575f772

File tree

6 files changed

+40
-62
lines changed

6 files changed

+40
-62
lines changed

mypy/exprtotype.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
Type,
3434
TypeList,
3535
TypeOfAny,
36-
TypeOfTypeList,
3736
UnboundType,
3837
UnionType,
3938
)
@@ -162,12 +161,9 @@ def expr_to_unanalyzed_type(
162161
else:
163162
raise TypeTranslationError()
164163
return CallableArgument(typ, name, arg_const, expr.line, expr.column)
165-
elif isinstance(expr, (ListExpr, TupleExpr)):
164+
elif isinstance(expr, ListExpr):
166165
return TypeList(
167166
[expr_to_unanalyzed_type(t, options, allow_new_syntax, expr) for t in expr.items],
168-
TypeOfTypeList.callable_args
169-
if isinstance(expr, ListExpr)
170-
else TypeOfTypeList.param_spec_defaults,
171167
line=expr.line,
172168
column=expr.column,
173169
)

mypy/semanal.py

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4114,9 +4114,7 @@ def process_typevar_parameters(
41144114
tv_arg = self.get_typevarlike_argument(
41154115
"TypeVar", param_name, param_value, context, allow_unbound_tvars=True
41164116
)
4117-
if tv_arg is None:
4118-
return None
4119-
default = tv_arg
4117+
default = tv_arg or AnyType(TypeOfAny.from_error)
41204118
elif param_name == "values":
41214119
# Probably using obsolete syntax with values=(...). Explain the current syntax.
41224120
self.fail('TypeVar "values" argument not supported', context)
@@ -4153,6 +4151,7 @@ def get_typevarlike_argument(
41534151
*,
41544152
allow_unbound_tvars: bool = False,
41554153
allow_param_spec_literals: bool = False,
4154+
report_invalid_typevar_arg: bool = True,
41564155
) -> ProperType | None:
41574156
try:
41584157
# We want to use our custom error message below, so we suppress
@@ -4173,7 +4172,7 @@ def get_typevarlike_argument(
41734172
# ...
41744173
analyzed = PlaceholderType(None, [], context.line)
41754174
typ = get_proper_type(analyzed)
4176-
if isinstance(typ, AnyType) and typ.is_from_error:
4175+
if report_invalid_typevar_arg and isinstance(typ, AnyType) and typ.is_from_error:
41774176
self.fail(
41784177
message_registry.TYPEVAR_ARG_MUST_BE_TYPE.format(typevarlike_name, param_name),
41794178
param_value,
@@ -4182,10 +4181,11 @@ def get_typevarlike_argument(
41824181
# using the AnyType as the upper bound.
41834182
return typ
41844183
except TypeTranslationError:
4185-
self.fail(
4186-
message_registry.TYPEVAR_ARG_MUST_BE_TYPE.format(typevarlike_name, param_name),
4187-
param_value,
4188-
)
4184+
if report_invalid_typevar_arg:
4185+
self.fail(
4186+
message_registry.TYPEVAR_ARG_MUST_BE_TYPE.format(typevarlike_name, param_name),
4187+
param_value,
4188+
)
41894189
return None
41904190

41914191
def extract_typevarlike_name(self, s: AssignmentStmt, call: CallExpr) -> str | None:
@@ -4236,20 +4236,23 @@ def process_paramspec_declaration(self, s: AssignmentStmt) -> bool:
42364236
s,
42374237
allow_unbound_tvars=True,
42384238
allow_param_spec_literals=True,
4239+
report_invalid_typevar_arg=False,
42394240
)
4240-
if tv_arg is None:
4241-
return False
4242-
default = tv_arg
4241+
default = tv_arg or AnyType(TypeOfAny.from_error)
42434242
if isinstance(tv_arg, Parameters):
42444243
for i, arg_type in enumerate(tv_arg.arg_types):
42454244
typ = get_proper_type(arg_type)
42464245
if isinstance(typ, AnyType) and typ.is_from_error:
42474246
self.fail(
42484247
f"Argument {i} of ParamSpec default must be a type", param_value
42494248
)
4250-
elif not isinstance(default, (AnyType, UnboundType)):
4249+
elif (
4250+
isinstance(default, AnyType)
4251+
and default.is_from_error
4252+
or not isinstance(default, (AnyType, UnboundType))
4253+
):
42514254
self.fail(
4252-
"The default argument to ParamSpec must be a tuple expression, ellipsis, or a ParamSpec",
4255+
"The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec",
42534256
param_value,
42544257
)
42554258
default = AnyType(TypeOfAny.from_error)
@@ -4306,11 +4309,14 @@ def process_typevartuple_declaration(self, s: AssignmentStmt) -> bool:
43064309
):
43074310
if param_name == "default":
43084311
tv_arg = self.get_typevarlike_argument(
4309-
"TypeVarTuple", param_name, param_value, s, allow_unbound_tvars=True
4312+
"TypeVarTuple",
4313+
param_name,
4314+
param_value,
4315+
s,
4316+
allow_unbound_tvars=True,
4317+
report_invalid_typevar_arg=False,
43104318
)
4311-
if tv_arg is None:
4312-
return False
4313-
default = tv_arg
4319+
default = tv_arg or AnyType(TypeOfAny.from_error)
43144320
if not isinstance(default, UnpackType):
43154321
self.fail(
43164322
"The default argument to TypeVarTuple must be an Unpacked tuple",

mypy/typeanal.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@
7272
TypedDictType,
7373
TypeList,
7474
TypeOfAny,
75-
TypeOfTypeList,
7675
TypeQuery,
7776
TypeType,
7877
TypeVarLikeType,
@@ -897,12 +896,10 @@ def visit_type_list(self, t: TypeList) -> Type:
897896
else:
898897
return AnyType(TypeOfAny.from_error)
899898
else:
900-
s = "[...]" if t.list_type == TypeOfTypeList.callable_args else "(...)"
901899
self.fail(
902-
f'Bracketed expression "{s}" is not valid as a type', t, code=codes.VALID_TYPE
900+
'Bracketed expression "[...]" is not valid as a type', t, code=codes.VALID_TYPE
903901
)
904-
if t.list_type == TypeOfTypeList.callable_args:
905-
self.note('Did you mean "List[...]"?', t)
902+
self.note('Did you mean "List[...]"?', t)
906903
return AnyType(TypeOfAny.from_error)
907904

908905
def visit_callable_argument(self, t: CallableArgument) -> Type:

mypy/types.py

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -197,17 +197,6 @@ class TypeOfAny:
197197
suggestion_engine: Final = 9
198198

199199

200-
class TypeOfTypeList:
201-
"""This class describes the different types of TypeList."""
202-
203-
__slots__ = ()
204-
205-
# List expressions for callable args
206-
callable_args: Final = 1
207-
# Tuple expressions for ParamSpec defaults
208-
param_spec_defaults: Final = 2
209-
210-
211200
def deserialize_type(data: JsonDict | str) -> Type:
212201
if isinstance(data, str):
213202
return Instance.deserialize(data)
@@ -1005,20 +994,13 @@ class TypeList(ProperType):
1005994
types before they are processed into Callable types.
1006995
"""
1007996

1008-
__slots__ = ("items", "list_type")
997+
__slots__ = ("items",)
1009998

1010999
items: list[Type]
10111000

1012-
def __init__(
1013-
self,
1014-
items: list[Type],
1015-
list_type: int = TypeOfTypeList.callable_args,
1016-
line: int = -1,
1017-
column: int = -1,
1018-
) -> None:
1001+
def __init__(self, items: list[Type], line: int = -1, column: int = -1) -> None:
10191002
super().__init__(line, column)
10201003
self.items = items
1021-
self.list_type = list_type
10221004

10231005
def accept(self, visitor: TypeVisitor[T]) -> T:
10241006
assert isinstance(visitor, SyntheticTypeVisitor)
@@ -1032,11 +1014,7 @@ def __hash__(self) -> int:
10321014
return hash(tuple(self.items))
10331015

10341016
def __eq__(self, other: object) -> bool:
1035-
return (
1036-
isinstance(other, TypeList)
1037-
and self.items == other.items
1038-
and self.list_type == other.list_type
1039-
)
1017+
return isinstance(other, TypeList) and self.items == other.items
10401018

10411019

10421020
class UnpackType(ProperType):

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ from typing import Generic, TypeVar, ParamSpec, Callable, Tuple, List
44
from typing_extensions import TypeVarTuple, Unpack
55

66
T1 = TypeVar("T1", default=int)
7-
P1 = ParamSpec("P1", default=(int, str))
7+
P1 = ParamSpec("P1", default=[int, str])
88
Ts1 = TypeVarTuple("Ts1", default=Unpack[Tuple[int, str]])
99

1010
def f1(a: T1) -> List[T1]: ...
@@ -44,9 +44,9 @@ T5 = TypeVar("T5", default=S0)
4444
T6 = TypeVar("T6", bound=float, default=S1)
4545
# T7 = TypeVar("T7", bound=List[Any], default=List[S0]) # TODO
4646

47-
P1 = ParamSpec("P1", default=())
47+
P1 = ParamSpec("P1", default=[])
4848
P2 = ParamSpec("P2", default=...)
49-
P3 = ParamSpec("P3", default=(int, str))
49+
P3 = ParamSpec("P3", default=[int, str])
5050
P4 = ParamSpec("P4", default=P0)
5151

5252
Ts1 = TypeVarTuple("Ts1", default=Unpack[Tuple[int]])
@@ -59,15 +59,16 @@ from typing import TypeVar, ParamSpec, Tuple
5959
from typing_extensions import TypeVarTuple, Unpack
6060

6161
T1 = TypeVar("T1", default=2) # E: TypeVar "default" must be a type
62-
T2 = TypeVar("T2", default=(int, str)) # E: Bracketed expression "(...)" is not valid as a type \
62+
T2 = TypeVar("T2", default=[int, str]) # E: Bracketed expression "[...]" is not valid as a type \
63+
# N: Did you mean "List[...]"? \
6364
# E: TypeVar "default" must be a type
6465

65-
P1 = ParamSpec("P1", default=int) # E: The default argument to ParamSpec must be a tuple expression, ellipsis, or a ParamSpec
66-
P2 = ParamSpec("P2", default=2) # E: ParamSpec "default" must be a type
67-
P3 = ParamSpec("P3", default=(2, int)) # E: Argument 0 of ParamSpec default must be a type
66+
P1 = ParamSpec("P1", default=int) # E: The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec
67+
P2 = ParamSpec("P2", default=2) # E: The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec
68+
P3 = ParamSpec("P3", default=(2, int)) # E: The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec
69+
P4 = ParamSpec("P4", default=[2, int]) # E: Argument 0 of ParamSpec default must be a type
6870

69-
Ts1 = TypeVarTuple("Ts1", default=2) # E: TypeVarTuple "default" must be a type \
70-
# E: The default argument to TypeVarTuple must be an Unpacked tuple
71+
Ts1 = TypeVarTuple("Ts1", default=2) # E: The default argument to TypeVarTuple must be an Unpacked tuple
7172
Ts2 = TypeVarTuple("Ts2", default=int) # E: The default argument to TypeVarTuple must be an Unpacked tuple
7273
Ts3 = TypeVarTuple("Ts3", default=Tuple[int]) # E: The default argument to TypeVarTuple must be an Unpacked tuple
7374
[builtins fixtures/tuple.pyi]

test-data/unit/semanal-errors.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1045,7 +1045,7 @@ c = TypeVar(1) # E: TypeVar() expects a string literal as first argument
10451045
T = TypeVar(b'T') # E: TypeVar() expects a string literal as first argument
10461046
d = TypeVar('D') # E: String argument 1 "D" to TypeVar(...) does not match variable name "d"
10471047
e = TypeVar('e', int, str, x=1) # E: Unexpected argument to "TypeVar()": "x"
1048-
f = TypeVar('f', (int, str), int) # E: Bracketed expression "(...)" is not valid as a type
1048+
f = TypeVar('f', (int, str), int) # E: Type expected
10491049
g = TypeVar('g', int) # E: TypeVar cannot have only a single constraint
10501050
h = TypeVar('h', x=(int, str)) # E: Unexpected argument to "TypeVar()": "x"
10511051
i = TypeVar('i', bound=1) # E: TypeVar "bound" must be a type

0 commit comments

Comments
 (0)