Skip to content

Commit 0ea018e

Browse files
committed
Require ListExpr for ParamSpec defaults
1 parent 409e676 commit 0ea018e

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
@@ -4132,9 +4132,7 @@ def process_typevar_parameters(
41324132
tv_arg = self.get_typevarlike_argument(
41334133
"TypeVar", param_name, param_value, context, allow_unbound_tvars=True
41344134
)
4135-
if tv_arg is None:
4136-
return None
4137-
default = tv_arg
4135+
default = tv_arg or AnyType(TypeOfAny.from_error)
41384136
elif param_name == "values":
41394137
# Probably using obsolete syntax with values=(...). Explain the current syntax.
41404138
self.fail('TypeVar "values" argument not supported', context)
@@ -4171,6 +4169,7 @@ def get_typevarlike_argument(
41714169
*,
41724170
allow_unbound_tvars: bool = False,
41734171
allow_param_spec_literals: bool = False,
4172+
report_invalid_typevar_arg: bool = True,
41744173
) -> ProperType | None:
41754174
try:
41764175
# We want to use our custom error message below, so we suppress
@@ -4191,7 +4190,7 @@ def get_typevarlike_argument(
41914190
# ...
41924191
analyzed = PlaceholderType(None, [], context.line)
41934192
typ = get_proper_type(analyzed)
4194-
if isinstance(typ, AnyType) and typ.is_from_error:
4193+
if report_invalid_typevar_arg and isinstance(typ, AnyType) and typ.is_from_error:
41954194
self.fail(
41964195
message_registry.TYPEVAR_ARG_MUST_BE_TYPE.format(typevarlike_name, param_name),
41974196
param_value,
@@ -4200,10 +4199,11 @@ def get_typevarlike_argument(
42004199
# using the AnyType as the upper bound.
42014200
return typ
42024201
except TypeTranslationError:
4203-
self.fail(
4204-
message_registry.TYPEVAR_ARG_MUST_BE_TYPE.format(typevarlike_name, param_name),
4205-
param_value,
4206-
)
4202+
if report_invalid_typevar_arg:
4203+
self.fail(
4204+
message_registry.TYPEVAR_ARG_MUST_BE_TYPE.format(typevarlike_name, param_name),
4205+
param_value,
4206+
)
42074207
return None
42084208

42094209
def extract_typevarlike_name(self, s: AssignmentStmt, call: CallExpr) -> str | None:
@@ -4254,20 +4254,23 @@ def process_paramspec_declaration(self, s: AssignmentStmt) -> bool:
42544254
s,
42554255
allow_unbound_tvars=True,
42564256
allow_param_spec_literals=True,
4257+
report_invalid_typevar_arg=False,
42574258
)
4258-
if tv_arg is None:
4259-
return False
4260-
default = tv_arg
4259+
default = tv_arg or AnyType(TypeOfAny.from_error)
42614260
if isinstance(tv_arg, Parameters):
42624261
for i, arg_type in enumerate(tv_arg.arg_types):
42634262
typ = get_proper_type(arg_type)
42644263
if isinstance(typ, AnyType) and typ.is_from_error:
42654264
self.fail(
42664265
f"Argument {i} of ParamSpec default must be a type", param_value
42674266
)
4268-
elif not isinstance(default, (AnyType, UnboundType)):
4267+
elif (
4268+
isinstance(default, AnyType)
4269+
and default.is_from_error
4270+
or not isinstance(default, (AnyType, UnboundType))
4271+
):
42694272
self.fail(
4270-
"The default argument to ParamSpec must be a tuple expression, ellipsis, or a ParamSpec",
4273+
"The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec",
42714274
param_value,
42724275
)
42734276
default = AnyType(TypeOfAny.from_error)
@@ -4324,11 +4327,14 @@ def process_typevartuple_declaration(self, s: AssignmentStmt) -> bool:
43244327
):
43254328
if param_name == "default":
43264329
tv_arg = self.get_typevarlike_argument(
4327-
"TypeVarTuple", param_name, param_value, s, allow_unbound_tvars=True
4330+
"TypeVarTuple",
4331+
param_name,
4332+
param_value,
4333+
s,
4334+
allow_unbound_tvars=True,
4335+
report_invalid_typevar_arg=False,
43284336
)
4329-
if tv_arg is None:
4330-
return False
4331-
default = tv_arg
4337+
default = tv_arg or AnyType(TypeOfAny.from_error)
43324338
if not isinstance(default, UnpackType):
43334339
self.fail(
43344340
"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,
@@ -891,12 +890,10 @@ def visit_type_list(self, t: TypeList) -> Type:
891890
else:
892891
return AnyType(TypeOfAny.from_error)
893892
else:
894-
s = "[...]" if t.list_type == TypeOfTypeList.callable_args else "(...)"
895893
self.fail(
896-
f'Bracketed expression "{s}" is not valid as a type', t, code=codes.VALID_TYPE
894+
'Bracketed expression "[...]" is not valid as a type', t, code=codes.VALID_TYPE
897895
)
898-
if t.list_type == TypeOfTypeList.callable_args:
899-
self.note('Did you mean "List[...]"?', t)
896+
self.note('Did you mean "List[...]"?', t)
900897
return AnyType(TypeOfAny.from_error)
901898

902899
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)
@@ -1022,20 +1011,13 @@ class TypeList(ProperType):
10221011
types before they are processed into Callable types.
10231012
"""
10241013

1025-
__slots__ = ("items", "list_type")
1014+
__slots__ = ("items",)
10261015

10271016
items: list[Type]
10281017

1029-
def __init__(
1030-
self,
1031-
items: list[Type],
1032-
list_type: int = TypeOfTypeList.callable_args,
1033-
line: int = -1,
1034-
column: int = -1,
1035-
) -> None:
1018+
def __init__(self, items: list[Type], line: int = -1, column: int = -1) -> None:
10361019
super().__init__(line, column)
10371020
self.items = items
1038-
self.list_type = list_type
10391021

10401022
def accept(self, visitor: TypeVisitor[T]) -> T:
10411023
assert isinstance(visitor, SyntheticTypeVisitor)
@@ -1049,11 +1031,7 @@ def __hash__(self) -> int:
10491031
return hash(tuple(self.items))
10501032

10511033
def __eq__(self, other: object) -> bool:
1052-
return (
1053-
isinstance(other, TypeList)
1054-
and self.items == other.items
1055-
and self.list_type == other.list_type
1056-
)
1034+
return isinstance(other, TypeList) and self.items == other.items
10571035

10581036

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