Skip to content

Commit a16c414

Browse files
authored
Add TypeVarTupleType type node (#12632)
This adds the TypeVarTupleType type node and basic semanal/glue. Type checking involving it will be added in a subsequent PR to keep each PR smaller. This PR is mostly consisting of modifying all the visitors, but not all of them are implemented.
1 parent c56046c commit a16c414

19 files changed

+193
-21
lines changed

mypy/constraints.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType,
99
UninhabitedType, TypeType, TypeVarId, TypeQuery, is_named_instance, TypeOfAny, LiteralType,
1010
ProperType, ParamSpecType, get_proper_type, TypeAliasType, is_union_with_any,
11-
UnpackType, callable_with_ellipsis, Parameters, TUPLE_LIKE_INSTANCE_NAMES,
11+
UnpackType, callable_with_ellipsis, Parameters, TUPLE_LIKE_INSTANCE_NAMES, TypeVarTupleType,
1212
)
1313
from mypy.maptype import map_instance_to_supertype
1414
import mypy.subtypes
@@ -403,6 +403,9 @@ def visit_param_spec(self, template: ParamSpecType) -> List[Constraint]:
403403
# Can't infer ParamSpecs from component values (only via Callable[P, T]).
404404
return []
405405

406+
def visit_type_var_tuple(self, template: TypeVarTupleType) -> List[Constraint]:
407+
raise NotImplementedError
408+
406409
def visit_unpack_type(self, template: UnpackType) -> List[Constraint]:
407410
raise NotImplementedError
408411

mypy/erasetype.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
Type, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarId, Instance, TypeVarType,
55
CallableType, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType,
66
DeletedType, TypeTranslator, UninhabitedType, TypeType, TypeOfAny, LiteralType, ProperType,
7-
get_proper_type, get_proper_types, TypeAliasType, ParamSpecType, Parameters, UnpackType
7+
get_proper_type, get_proper_types, TypeAliasType, ParamSpecType, Parameters, UnpackType,
8+
TypeVarTupleType
89
)
910
from mypy.nodes import ARG_STAR, ARG_STAR2
1011

@@ -62,8 +63,11 @@ def visit_param_spec(self, t: ParamSpecType) -> ProperType:
6263
def visit_parameters(self, t: Parameters) -> ProperType:
6364
raise RuntimeError("Parameters should have been bound to a class")
6465

66+
def visit_type_var_tuple(self, t: TypeVarTupleType) -> ProperType:
67+
return AnyType(TypeOfAny.special_form)
68+
6569
def visit_unpack_type(self, t: UnpackType) -> ProperType:
66-
raise NotImplementedError
70+
return AnyType(TypeOfAny.special_form)
6771

6872
def visit_callable_type(self, t: CallableType) -> ProperType:
6973
# We must preserve the fallback type for overload resolution to work.

mypy/expandtype.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, TypeVarId,
77
FunctionLike, TypeVarType, LiteralType, get_proper_type, ProperType,
88
TypeAliasType, ParamSpecType, TypeVarLikeType, Parameters, ParamSpecFlavor,
9-
UnpackType
9+
UnpackType, TypeVarTupleType
1010
)
1111

1212

@@ -131,6 +131,9 @@ def visit_param_spec(self, t: ParamSpecType) -> Type:
131131
# TODO: should this branch be removed? better not to fail silently
132132
return repl
133133

134+
def visit_type_var_tuple(self, t: TypeVarTupleType) -> Type:
135+
raise NotImplementedError
136+
134137
def visit_unpack_type(self, t: UnpackType) -> Type:
135138
raise NotImplementedError
136139

mypy/fixup.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
CallableType, Instance, Overloaded, TupleType, TypedDictType,
1212
TypeVarType, UnboundType, UnionType, TypeVisitor, LiteralType,
1313
TypeType, NOT_READY, TypeAliasType, AnyType, TypeOfAny, ParamSpecType,
14-
Parameters, UnpackType,
14+
Parameters, UnpackType, TypeVarTupleType
1515
)
1616
from mypy.visitor import NodeVisitor
1717
from mypy.lookup import lookup_fully_qualified
@@ -252,6 +252,9 @@ def visit_type_var(self, tvt: TypeVarType) -> None:
252252
def visit_param_spec(self, p: ParamSpecType) -> None:
253253
p.upper_bound.accept(self)
254254

255+
def visit_type_var_tuple(self, t: TypeVarTupleType) -> None:
256+
t.upper_bound.accept(self)
257+
255258
def visit_unpack_type(self, u: UnpackType) -> None:
256259
u.type.accept(self)
257260

mypy/indirection.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ def visit_type_var(self, t: types.TypeVarType) -> Set[str]:
6767
def visit_param_spec(self, t: types.ParamSpecType) -> Set[str]:
6868
return set()
6969

70+
def visit_type_var_tuple(self, t: types.TypeVarTupleType) -> Set[str]:
71+
return self._visit(t.upper_bound)
72+
7073
def visit_unpack_type(self, t: types.UnpackType) -> Set[str]:
7174
return t.type.accept(self)
7275

mypy/join.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
TupleType, TypedDictType, ErasedType, UnionType, FunctionLike, Overloaded, LiteralType,
99
PartialType, DeletedType, UninhabitedType, TypeType, TypeOfAny, get_proper_type,
1010
ProperType, get_proper_types, TypeAliasType, PlaceholderType, ParamSpecType, Parameters,
11-
UnpackType
11+
UnpackType, TypeVarTupleType,
1212
)
1313
from mypy.maptype import map_instance_to_supertype
1414
from mypy.subtypes import (
@@ -257,6 +257,11 @@ def visit_param_spec(self, t: ParamSpecType) -> ProperType:
257257
return t
258258
return self.default(self.s)
259259

260+
def visit_type_var_tuple(self, t: TypeVarTupleType) -> ProperType:
261+
if self.s == t:
262+
return t
263+
return self.default(self.s)
264+
260265
def visit_unpack_type(self, t: UnpackType) -> UnpackType:
261266
raise NotImplementedError
262267

mypy/meet.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
TupleType, TypedDictType, ErasedType, UnionType, PartialType, DeletedType,
77
UninhabitedType, TypeType, TypeOfAny, Overloaded, FunctionLike, LiteralType,
88
ProperType, get_proper_type, get_proper_types, TypeAliasType, TypeGuardedType,
9-
ParamSpecType, Parameters, UnpackType,
9+
ParamSpecType, Parameters, UnpackType, TypeVarTupleType,
1010
)
1111
from mypy.subtypes import is_equivalent, is_subtype, is_callable_compatible, is_proper_subtype
1212
from mypy.erasetype import erase_type
@@ -536,6 +536,12 @@ def visit_param_spec(self, t: ParamSpecType) -> ProperType:
536536
else:
537537
return self.default(self.s)
538538

539+
def visit_type_var_tuple(self, t: TypeVarTupleType) -> ProperType:
540+
if self.s == t:
541+
return self.s
542+
else:
543+
return self.default(self.s)
544+
539545
def visit_unpack_type(self, t: UnpackType) -> ProperType:
540546
raise NotImplementedError
541547

mypy/sametypes.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
Type, UnboundType, AnyType, NoneType, TupleType, TypedDictType,
55
UnionType, CallableType, TypeVarType, Instance, TypeVisitor, ErasedType,
66
Overloaded, PartialType, DeletedType, UninhabitedType, TypeType, LiteralType,
7-
ProperType, get_proper_type, TypeAliasType, ParamSpecType, Parameters, UnpackType
7+
ProperType, get_proper_type, TypeAliasType, ParamSpecType, Parameters,
8+
UnpackType, TypeVarTupleType,
89
)
910
from mypy.typeops import tuple_fallback, make_simplified_union, is_simple_literal
1011

@@ -118,6 +119,10 @@ def visit_param_spec(self, left: ParamSpecType) -> bool:
118119
return (isinstance(self.right, ParamSpecType) and
119120
left.id == self.right.id and left.flavor == self.right.flavor)
120121

122+
def visit_type_var_tuple(self, left: TypeVarTupleType) -> bool:
123+
return (isinstance(self.right, TypeVarTupleType) and
124+
left.id == self.right.id)
125+
121126
def visit_unpack_type(self, left: UnpackType) -> bool:
122127
return (isinstance(self.right, UnpackType) and
123128
is_same_type(left.type, self.right.type))

mypy/semanal_typeargs.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from mypy.nodes import TypeInfo, Context, MypyFile, FuncItem, ClassDef, Block, FakeInfo
1111
from mypy.types import (
1212
Type, Instance, TypeVarType, AnyType, get_proper_types, TypeAliasType, ParamSpecType,
13-
UnpackType, TupleType, get_proper_type
13+
UnpackType, TupleType, TypeVarTupleType, TypeOfAny, get_proper_type
1414
)
1515
from mypy.mixedtraverser import MixedTraverserVisitor
1616
from mypy.subtypes import is_subtype
@@ -99,8 +99,15 @@ def visit_unpack_type(self, typ: UnpackType) -> None:
9999
proper_type = get_proper_type(typ.type)
100100
if isinstance(proper_type, TupleType):
101101
return
102+
if isinstance(proper_type, TypeVarTupleType):
103+
return
102104
if isinstance(proper_type, Instance) and proper_type.type.fullname == "builtins.tuple":
103105
return
106+
if isinstance(proper_type, AnyType) and proper_type.type_of_any == TypeOfAny.from_error:
107+
return
108+
109+
# TODO: Infer something when it can't be unpacked to allow rest of
110+
# typechecking to work.
104111
self.fail(message_registry.INVALID_UNPACK.format(proper_type), typ)
105112

106113
def check_type_var_values(self, type: TypeInfo, actuals: List[Type], arg_name: str,

mypy/server/astdiff.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class level -- these are handled at attribute level (say, 'mod.Cls.method'
6060
Type, TypeVisitor, UnboundType, AnyType, NoneType, UninhabitedType,
6161
ErasedType, DeletedType, Instance, TypeVarType, CallableType, TupleType, TypedDictType,
6262
UnionType, Overloaded, PartialType, TypeType, LiteralType, TypeAliasType, ParamSpecType,
63-
Parameters, UnpackType,
63+
Parameters, UnpackType, TypeVarTupleType,
6464
)
6565
from mypy.util import get_prefix
6666

@@ -318,6 +318,12 @@ def visit_param_spec(self, typ: ParamSpecType) -> SnapshotItem:
318318
typ.flavor,
319319
snapshot_type(typ.upper_bound))
320320

321+
def visit_type_var_tuple(self, typ: TypeVarTupleType) -> SnapshotItem:
322+
return ('TypeVarTupleType',
323+
typ.id.raw_id,
324+
typ.id.meta_level,
325+
snapshot_type(typ.upper_bound))
326+
321327
def visit_unpack_type(self, typ: UnpackType) -> SnapshotItem:
322328
return ('UnpackType', snapshot_type(typ.type))
323329

mypy/server/astmerge.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
TupleType, TypeType, TypedDictType, UnboundType, UninhabitedType, UnionType,
6161
Overloaded, TypeVarType, TypeList, CallableArgument, EllipsisType, StarType, LiteralType,
6262
RawExpressionType, PartialType, PlaceholderType, TypeAliasType, ParamSpecType, Parameters,
63-
UnpackType
63+
UnpackType, TypeVarTupleType,
6464
)
6565
from mypy.util import get_prefix, replace_object_state
6666
from mypy.typestate import TypeState
@@ -416,6 +416,9 @@ def visit_type_var(self, typ: TypeVarType) -> None:
416416
def visit_param_spec(self, typ: ParamSpecType) -> None:
417417
pass
418418

419+
def visit_type_var_tuple(self, typ: TypeVarTupleType) -> None:
420+
typ.upper_bound.accept(self)
421+
419422
def visit_unpack_type(self, typ: UnpackType) -> None:
420423
typ.type.accept(self)
421424

mypy/server/deps.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class 'mod.Cls'. This can also refer to an attribute inherited from a
100100
Type, Instance, AnyType, NoneType, TypeVisitor, CallableType, DeletedType, PartialType,
101101
TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType,
102102
FunctionLike, Overloaded, TypeOfAny, LiteralType, ErasedType, get_proper_type, ProperType,
103-
TypeAliasType, ParamSpecType, Parameters, UnpackType
103+
TypeAliasType, ParamSpecType, Parameters, UnpackType, TypeVarTupleType,
104104
)
105105
from mypy.server.trigger import make_trigger, make_wildcard_trigger
106106
from mypy.util import correct_relative_import
@@ -966,6 +966,13 @@ def visit_param_spec(self, typ: ParamSpecType) -> List[str]:
966966
triggers.extend(self.get_type_triggers(typ.upper_bound))
967967
return triggers
968968

969+
def visit_type_var_tuple(self, typ: TypeVarTupleType) -> List[str]:
970+
triggers = []
971+
if typ.fullname:
972+
triggers.append(make_trigger(typ.fullname))
973+
triggers.extend(self.get_type_triggers(typ.upper_bound))
974+
return triggers
975+
969976
def visit_unpack_type(self, typ: UnpackType) -> List[str]:
970977
return typ.type.accept(self)
971978

mypy/subtypes.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
Instance, TypeVarType, CallableType, TupleType, TypedDictType, UnionType, Overloaded,
99
ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, is_named_instance,
1010
FunctionLike, TypeOfAny, LiteralType, get_proper_type, TypeAliasType, ParamSpecType,
11-
Parameters, UnpackType, TUPLE_LIKE_INSTANCE_NAMES,
11+
Parameters, UnpackType, TUPLE_LIKE_INSTANCE_NAMES, TypeVarTupleType,
1212
)
1313
import mypy.applytype
1414
import mypy.constraints
@@ -340,6 +340,15 @@ def visit_param_spec(self, left: ParamSpecType) -> bool:
340340
return True
341341
return self._is_subtype(left.upper_bound, self.right)
342342

343+
def visit_type_var_tuple(self, left: TypeVarTupleType) -> bool:
344+
right = self.right
345+
if (
346+
isinstance(right, TypeVarTupleType)
347+
and right.id == left.id
348+
):
349+
return True
350+
return self._is_subtype(left.upper_bound, self.right)
351+
343352
def visit_unpack_type(self, left: UnpackType) -> bool:
344353
raise NotImplementedError
345354

@@ -1463,6 +1472,15 @@ def visit_param_spec(self, left: ParamSpecType) -> bool:
14631472
return True
14641473
return self._is_proper_subtype(left.upper_bound, self.right)
14651474

1475+
def visit_type_var_tuple(self, left: TypeVarTupleType) -> bool:
1476+
right = self.right
1477+
if (
1478+
isinstance(right, TypeVarTupleType)
1479+
and right.id == left.id
1480+
):
1481+
return True
1482+
return self._is_proper_subtype(left.upper_bound, self.right)
1483+
14661484
def visit_unpack_type(self, left: UnpackType) -> bool:
14671485
raise NotImplementedError
14681486

mypy/tvar_scope.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
from typing import Optional, Dict, Union
2-
from mypy.types import TypeVarLikeType, TypeVarType, ParamSpecType, ParamSpecFlavor, TypeVarId
3-
from mypy.nodes import ParamSpecExpr, TypeVarExpr, TypeVarLikeExpr, SymbolTableNode
2+
from mypy.types import (
3+
TypeVarLikeType, TypeVarType, ParamSpecType, ParamSpecFlavor, TypeVarId, TypeVarTupleType,
4+
)
5+
from mypy.nodes import (
6+
ParamSpecExpr, TypeVarExpr, TypeVarLikeExpr, SymbolTableNode, TypeVarTupleExpr,
7+
)
48

59

610
class TypeVarLikeScope:
@@ -88,6 +92,15 @@ def bind_new(self, name: str, tvar_expr: TypeVarLikeExpr) -> TypeVarLikeType:
8892
line=tvar_expr.line,
8993
column=tvar_expr.column
9094
)
95+
elif isinstance(tvar_expr, TypeVarTupleExpr):
96+
tvar_def = TypeVarTupleType(
97+
name,
98+
tvar_expr.fullname,
99+
i,
100+
upper_bound=tvar_expr.upper_bound,
101+
line=tvar_expr.line,
102+
column=tvar_expr.column
103+
)
91104
else:
92105
assert False
93106
self.scope[tvar_expr.fullname] = tvar_def

mypy/type_visitor.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
Parameters, RawExpressionType, Instance, NoneType, TypeType,
2424
UnionType, TypeVarType, PartialType, DeletedType, UninhabitedType, TypeVarLikeType,
2525
UnboundType, ErasedType, StarType, EllipsisType, TypeList, CallableArgument,
26-
PlaceholderType, TypeAliasType, ParamSpecType, UnpackType, get_proper_type
26+
PlaceholderType, TypeAliasType, ParamSpecType, UnpackType, TypeVarTupleType,
27+
get_proper_type
2728
)
2829

2930

@@ -71,6 +72,10 @@ def visit_param_spec(self, t: ParamSpecType) -> T:
7172
def visit_parameters(self, t: Parameters) -> T:
7273
pass
7374

75+
@abstractmethod
76+
def visit_type_var_tuple(self, t: TypeVarTupleType) -> T:
77+
pass
78+
7479
@abstractmethod
7580
def visit_instance(self, t: Instance) -> T:
7681
pass
@@ -197,6 +202,9 @@ def visit_param_spec(self, t: ParamSpecType) -> Type:
197202
def visit_parameters(self, t: Parameters) -> Type:
198203
return t.copy_modified(arg_types=self.translate_types(t.arg_types))
199204

205+
def visit_type_var_tuple(self, t: TypeVarTupleType) -> Type:
206+
return t
207+
200208
def visit_partial_type(self, t: PartialType) -> Type:
201209
return t
202210

@@ -315,6 +323,9 @@ def visit_type_var(self, t: TypeVarType) -> T:
315323
def visit_param_spec(self, t: ParamSpecType) -> T:
316324
return self.strategy([])
317325

326+
def visit_type_var_tuple(self, t: TypeVarTupleType) -> T:
327+
return self.strategy([])
328+
318329
def visit_unpack_type(self, t: UnpackType) -> T:
319330
return self.query_types([t.type])
320331

0 commit comments

Comments
 (0)