Skip to content

Commit a6ee900

Browse files
committed
Require ListExpr for ParamSpec defaults
1 parent e8bbe5c commit a6ee900

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
@@ -4110,9 +4110,7 @@ def process_typevar_parameters(
41104110
tv_arg = self.get_typevarlike_argument(
41114111
"TypeVar", param_name, param_value, context, allow_unbound_tvars=True
41124112
)
4113-
if tv_arg is None:
4114-
return None
4115-
default = tv_arg
4113+
default = tv_arg or AnyType(TypeOfAny.from_error)
41164114
elif param_name == "values":
41174115
# Probably using obsolete syntax with values=(...). Explain the current syntax.
41184116
self.fail('TypeVar "values" argument not supported', context)
@@ -4149,6 +4147,7 @@ def get_typevarlike_argument(
41494147
*,
41504148
allow_unbound_tvars: bool = False,
41514149
allow_param_spec_literals: bool = False,
4150+
report_invalid_typevar_arg: bool = True,
41524151
) -> ProperType | None:
41534152
try:
41544153
# We want to use our custom error message below, so we suppress
@@ -4169,7 +4168,7 @@ def get_typevarlike_argument(
41694168
# ...
41704169
analyzed = PlaceholderType(None, [], context.line)
41714170
typ = get_proper_type(analyzed)
4172-
if isinstance(typ, AnyType) and typ.is_from_error:
4171+
if report_invalid_typevar_arg and isinstance(typ, AnyType) and typ.is_from_error:
41734172
self.fail(
41744173
message_registry.TYPEVAR_ARG_MUST_BE_TYPE.format(typevarlike_name, param_name),
41754174
param_value,
@@ -4178,10 +4177,11 @@ def get_typevarlike_argument(
41784177
# using the AnyType as the upper bound.
41794178
return typ
41804179
except TypeTranslationError:
4181-
self.fail(
4182-
message_registry.TYPEVAR_ARG_MUST_BE_TYPE.format(typevarlike_name, param_name),
4183-
param_value,
4184-
)
4180+
if report_invalid_typevar_arg:
4181+
self.fail(
4182+
message_registry.TYPEVAR_ARG_MUST_BE_TYPE.format(typevarlike_name, param_name),
4183+
param_value,
4184+
)
41854185
return None
41864186

41874187
def extract_typevarlike_name(self, s: AssignmentStmt, call: CallExpr) -> str | None:
@@ -4232,20 +4232,23 @@ def process_paramspec_declaration(self, s: AssignmentStmt) -> bool:
42324232
s,
42334233
allow_unbound_tvars=True,
42344234
allow_param_spec_literals=True,
4235+
report_invalid_typevar_arg=False,
42354236
)
4236-
if tv_arg is None:
4237-
return False
4238-
default = tv_arg
4237+
default = tv_arg or AnyType(TypeOfAny.from_error)
42394238
if isinstance(tv_arg, Parameters):
42404239
for i, arg_type in enumerate(tv_arg.arg_types):
42414240
typ = get_proper_type(arg_type)
42424241
if isinstance(typ, AnyType) and typ.is_from_error:
42434242
self.fail(
42444243
f"Argument {i} of ParamSpec default must be a type", param_value
42454244
)
4246-
elif not isinstance(default, (AnyType, UnboundType)):
4245+
elif (
4246+
isinstance(default, AnyType)
4247+
and default.is_from_error
4248+
or not isinstance(default, (AnyType, UnboundType))
4249+
):
42474250
self.fail(
4248-
"The default argument to ParamSpec must be a tuple expression, ellipsis, or a ParamSpec",
4251+
"The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec",
42494252
param_value,
42504253
)
42514254
default = AnyType(TypeOfAny.from_error)
@@ -4296,11 +4299,14 @@ def process_typevartuple_declaration(self, s: AssignmentStmt) -> bool:
42964299
):
42974300
if param_name == "default":
42984301
tv_arg = self.get_typevarlike_argument(
4299-
"TypeVarTuple", param_name, param_value, s, allow_unbound_tvars=True
4302+
"TypeVarTuple",
4303+
param_name,
4304+
param_value,
4305+
s,
4306+
allow_unbound_tvars=True,
4307+
report_invalid_typevar_arg=False,
43004308
)
4301-
if tv_arg is None:
4302-
return False
4303-
default = tv_arg
4309+
default = tv_arg or AnyType(TypeOfAny.from_error)
43044310
if not isinstance(default, UnpackType):
43054311
self.fail(
43064312
"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,
@@ -892,12 +891,10 @@ def visit_type_list(self, t: TypeList) -> Type:
892891
else:
893892
return AnyType(TypeOfAny.from_error)
894893
else:
895-
s = "[...]" if t.list_type == TypeOfTypeList.callable_args else "(...)"
896894
self.fail(
897-
f'Bracketed expression "{s}" is not valid as a type', t, code=codes.VALID_TYPE
895+
'Bracketed expression "[...]" is not valid as a type', t, code=codes.VALID_TYPE
898896
)
899-
if t.list_type == TypeOfTypeList.callable_args:
900-
self.note('Did you mean "List[...]"?', t)
897+
self.note('Did you mean "List[...]"?', t)
901898
return AnyType(TypeOfAny.from_error)
902899

903900
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)