Skip to content

Commit

Permalink
Add TypeVarTupleType type node (#12632)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jhance committed Apr 21, 2022
1 parent c56046c commit a16c414
Show file tree
Hide file tree
Showing 19 changed files with 193 additions and 21 deletions.
5 changes: 4 additions & 1 deletion mypy/constraints.py
Expand Up @@ -8,7 +8,7 @@
TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType,
UninhabitedType, TypeType, TypeVarId, TypeQuery, is_named_instance, TypeOfAny, LiteralType,
ProperType, ParamSpecType, get_proper_type, TypeAliasType, is_union_with_any,
UnpackType, callable_with_ellipsis, Parameters, TUPLE_LIKE_INSTANCE_NAMES,
UnpackType, callable_with_ellipsis, Parameters, TUPLE_LIKE_INSTANCE_NAMES, TypeVarTupleType,
)
from mypy.maptype import map_instance_to_supertype
import mypy.subtypes
Expand Down Expand Up @@ -403,6 +403,9 @@ def visit_param_spec(self, template: ParamSpecType) -> List[Constraint]:
# Can't infer ParamSpecs from component values (only via Callable[P, T]).
return []

def visit_type_var_tuple(self, template: TypeVarTupleType) -> List[Constraint]:
raise NotImplementedError

def visit_unpack_type(self, template: UnpackType) -> List[Constraint]:
raise NotImplementedError

Expand Down
8 changes: 6 additions & 2 deletions mypy/erasetype.py
Expand Up @@ -4,7 +4,8 @@
Type, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarId, Instance, TypeVarType,
CallableType, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType,
DeletedType, TypeTranslator, UninhabitedType, TypeType, TypeOfAny, LiteralType, ProperType,
get_proper_type, get_proper_types, TypeAliasType, ParamSpecType, Parameters, UnpackType
get_proper_type, get_proper_types, TypeAliasType, ParamSpecType, Parameters, UnpackType,
TypeVarTupleType
)
from mypy.nodes import ARG_STAR, ARG_STAR2

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

def visit_type_var_tuple(self, t: TypeVarTupleType) -> ProperType:
return AnyType(TypeOfAny.special_form)

def visit_unpack_type(self, t: UnpackType) -> ProperType:
raise NotImplementedError
return AnyType(TypeOfAny.special_form)

def visit_callable_type(self, t: CallableType) -> ProperType:
# We must preserve the fallback type for overload resolution to work.
Expand Down
5 changes: 4 additions & 1 deletion mypy/expandtype.py
Expand Up @@ -6,7 +6,7 @@
ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, TypeVarId,
FunctionLike, TypeVarType, LiteralType, get_proper_type, ProperType,
TypeAliasType, ParamSpecType, TypeVarLikeType, Parameters, ParamSpecFlavor,
UnpackType
UnpackType, TypeVarTupleType
)


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

def visit_type_var_tuple(self, t: TypeVarTupleType) -> Type:
raise NotImplementedError

def visit_unpack_type(self, t: UnpackType) -> Type:
raise NotImplementedError

Expand Down
5 changes: 4 additions & 1 deletion mypy/fixup.py
Expand Up @@ -11,7 +11,7 @@
CallableType, Instance, Overloaded, TupleType, TypedDictType,
TypeVarType, UnboundType, UnionType, TypeVisitor, LiteralType,
TypeType, NOT_READY, TypeAliasType, AnyType, TypeOfAny, ParamSpecType,
Parameters, UnpackType,
Parameters, UnpackType, TypeVarTupleType
)
from mypy.visitor import NodeVisitor
from mypy.lookup import lookup_fully_qualified
Expand Down Expand Up @@ -252,6 +252,9 @@ def visit_type_var(self, tvt: TypeVarType) -> None:
def visit_param_spec(self, p: ParamSpecType) -> None:
p.upper_bound.accept(self)

def visit_type_var_tuple(self, t: TypeVarTupleType) -> None:
t.upper_bound.accept(self)

def visit_unpack_type(self, u: UnpackType) -> None:
u.type.accept(self)

Expand Down
3 changes: 3 additions & 0 deletions mypy/indirection.py
Expand Up @@ -67,6 +67,9 @@ def visit_type_var(self, t: types.TypeVarType) -> Set[str]:
def visit_param_spec(self, t: types.ParamSpecType) -> Set[str]:
return set()

def visit_type_var_tuple(self, t: types.TypeVarTupleType) -> Set[str]:
return self._visit(t.upper_bound)

def visit_unpack_type(self, t: types.UnpackType) -> Set[str]:
return t.type.accept(self)

Expand Down
7 changes: 6 additions & 1 deletion mypy/join.py
Expand Up @@ -8,7 +8,7 @@
TupleType, TypedDictType, ErasedType, UnionType, FunctionLike, Overloaded, LiteralType,
PartialType, DeletedType, UninhabitedType, TypeType, TypeOfAny, get_proper_type,
ProperType, get_proper_types, TypeAliasType, PlaceholderType, ParamSpecType, Parameters,
UnpackType
UnpackType, TypeVarTupleType,
)
from mypy.maptype import map_instance_to_supertype
from mypy.subtypes import (
Expand Down Expand Up @@ -257,6 +257,11 @@ def visit_param_spec(self, t: ParamSpecType) -> ProperType:
return t
return self.default(self.s)

def visit_type_var_tuple(self, t: TypeVarTupleType) -> ProperType:
if self.s == t:
return t
return self.default(self.s)

def visit_unpack_type(self, t: UnpackType) -> UnpackType:
raise NotImplementedError

Expand Down
8 changes: 7 additions & 1 deletion mypy/meet.py
Expand Up @@ -6,7 +6,7 @@
TupleType, TypedDictType, ErasedType, UnionType, PartialType, DeletedType,
UninhabitedType, TypeType, TypeOfAny, Overloaded, FunctionLike, LiteralType,
ProperType, get_proper_type, get_proper_types, TypeAliasType, TypeGuardedType,
ParamSpecType, Parameters, UnpackType,
ParamSpecType, Parameters, UnpackType, TypeVarTupleType,
)
from mypy.subtypes import is_equivalent, is_subtype, is_callable_compatible, is_proper_subtype
from mypy.erasetype import erase_type
Expand Down Expand Up @@ -536,6 +536,12 @@ def visit_param_spec(self, t: ParamSpecType) -> ProperType:
else:
return self.default(self.s)

def visit_type_var_tuple(self, t: TypeVarTupleType) -> ProperType:
if self.s == t:
return self.s
else:
return self.default(self.s)

def visit_unpack_type(self, t: UnpackType) -> ProperType:
raise NotImplementedError

Expand Down
7 changes: 6 additions & 1 deletion mypy/sametypes.py
Expand Up @@ -4,7 +4,8 @@
Type, UnboundType, AnyType, NoneType, TupleType, TypedDictType,
UnionType, CallableType, TypeVarType, Instance, TypeVisitor, ErasedType,
Overloaded, PartialType, DeletedType, UninhabitedType, TypeType, LiteralType,
ProperType, get_proper_type, TypeAliasType, ParamSpecType, Parameters, UnpackType
ProperType, get_proper_type, TypeAliasType, ParamSpecType, Parameters,
UnpackType, TypeVarTupleType,
)
from mypy.typeops import tuple_fallback, make_simplified_union, is_simple_literal

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

def visit_type_var_tuple(self, left: TypeVarTupleType) -> bool:
return (isinstance(self.right, TypeVarTupleType) and
left.id == self.right.id)

def visit_unpack_type(self, left: UnpackType) -> bool:
return (isinstance(self.right, UnpackType) and
is_same_type(left.type, self.right.type))
Expand Down
9 changes: 8 additions & 1 deletion mypy/semanal_typeargs.py
Expand Up @@ -10,7 +10,7 @@
from mypy.nodes import TypeInfo, Context, MypyFile, FuncItem, ClassDef, Block, FakeInfo
from mypy.types import (
Type, Instance, TypeVarType, AnyType, get_proper_types, TypeAliasType, ParamSpecType,
UnpackType, TupleType, get_proper_type
UnpackType, TupleType, TypeVarTupleType, TypeOfAny, get_proper_type
)
from mypy.mixedtraverser import MixedTraverserVisitor
from mypy.subtypes import is_subtype
Expand Down Expand Up @@ -99,8 +99,15 @@ def visit_unpack_type(self, typ: UnpackType) -> None:
proper_type = get_proper_type(typ.type)
if isinstance(proper_type, TupleType):
return
if isinstance(proper_type, TypeVarTupleType):
return
if isinstance(proper_type, Instance) and proper_type.type.fullname == "builtins.tuple":
return
if isinstance(proper_type, AnyType) and proper_type.type_of_any == TypeOfAny.from_error:
return

# TODO: Infer something when it can't be unpacked to allow rest of
# typechecking to work.
self.fail(message_registry.INVALID_UNPACK.format(proper_type), typ)

def check_type_var_values(self, type: TypeInfo, actuals: List[Type], arg_name: str,
Expand Down
8 changes: 7 additions & 1 deletion mypy/server/astdiff.py
Expand Up @@ -60,7 +60,7 @@ class level -- these are handled at attribute level (say, 'mod.Cls.method'
Type, TypeVisitor, UnboundType, AnyType, NoneType, UninhabitedType,
ErasedType, DeletedType, Instance, TypeVarType, CallableType, TupleType, TypedDictType,
UnionType, Overloaded, PartialType, TypeType, LiteralType, TypeAliasType, ParamSpecType,
Parameters, UnpackType,
Parameters, UnpackType, TypeVarTupleType,
)
from mypy.util import get_prefix

Expand Down Expand Up @@ -318,6 +318,12 @@ def visit_param_spec(self, typ: ParamSpecType) -> SnapshotItem:
typ.flavor,
snapshot_type(typ.upper_bound))

def visit_type_var_tuple(self, typ: TypeVarTupleType) -> SnapshotItem:
return ('TypeVarTupleType',
typ.id.raw_id,
typ.id.meta_level,
snapshot_type(typ.upper_bound))

def visit_unpack_type(self, typ: UnpackType) -> SnapshotItem:
return ('UnpackType', snapshot_type(typ.type))

Expand Down
5 changes: 4 additions & 1 deletion mypy/server/astmerge.py
Expand Up @@ -60,7 +60,7 @@
TupleType, TypeType, TypedDictType, UnboundType, UninhabitedType, UnionType,
Overloaded, TypeVarType, TypeList, CallableArgument, EllipsisType, StarType, LiteralType,
RawExpressionType, PartialType, PlaceholderType, TypeAliasType, ParamSpecType, Parameters,
UnpackType
UnpackType, TypeVarTupleType,
)
from mypy.util import get_prefix, replace_object_state
from mypy.typestate import TypeState
Expand Down Expand Up @@ -416,6 +416,9 @@ def visit_type_var(self, typ: TypeVarType) -> None:
def visit_param_spec(self, typ: ParamSpecType) -> None:
pass

def visit_type_var_tuple(self, typ: TypeVarTupleType) -> None:
typ.upper_bound.accept(self)

def visit_unpack_type(self, typ: UnpackType) -> None:
typ.type.accept(self)

Expand Down
9 changes: 8 additions & 1 deletion mypy/server/deps.py
Expand Up @@ -100,7 +100,7 @@ class 'mod.Cls'. This can also refer to an attribute inherited from a
Type, Instance, AnyType, NoneType, TypeVisitor, CallableType, DeletedType, PartialType,
TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType,
FunctionLike, Overloaded, TypeOfAny, LiteralType, ErasedType, get_proper_type, ProperType,
TypeAliasType, ParamSpecType, Parameters, UnpackType
TypeAliasType, ParamSpecType, Parameters, UnpackType, TypeVarTupleType,
)
from mypy.server.trigger import make_trigger, make_wildcard_trigger
from mypy.util import correct_relative_import
Expand Down Expand Up @@ -966,6 +966,13 @@ def visit_param_spec(self, typ: ParamSpecType) -> List[str]:
triggers.extend(self.get_type_triggers(typ.upper_bound))
return triggers

def visit_type_var_tuple(self, typ: TypeVarTupleType) -> List[str]:
triggers = []
if typ.fullname:
triggers.append(make_trigger(typ.fullname))
triggers.extend(self.get_type_triggers(typ.upper_bound))
return triggers

def visit_unpack_type(self, typ: UnpackType) -> List[str]:
return typ.type.accept(self)

Expand Down
20 changes: 19 additions & 1 deletion mypy/subtypes.py
Expand Up @@ -8,7 +8,7 @@
Instance, TypeVarType, CallableType, TupleType, TypedDictType, UnionType, Overloaded,
ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, is_named_instance,
FunctionLike, TypeOfAny, LiteralType, get_proper_type, TypeAliasType, ParamSpecType,
Parameters, UnpackType, TUPLE_LIKE_INSTANCE_NAMES,
Parameters, UnpackType, TUPLE_LIKE_INSTANCE_NAMES, TypeVarTupleType,
)
import mypy.applytype
import mypy.constraints
Expand Down Expand Up @@ -340,6 +340,15 @@ def visit_param_spec(self, left: ParamSpecType) -> bool:
return True
return self._is_subtype(left.upper_bound, self.right)

def visit_type_var_tuple(self, left: TypeVarTupleType) -> bool:
right = self.right
if (
isinstance(right, TypeVarTupleType)
and right.id == left.id
):
return True
return self._is_subtype(left.upper_bound, self.right)

def visit_unpack_type(self, left: UnpackType) -> bool:
raise NotImplementedError

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

def visit_type_var_tuple(self, left: TypeVarTupleType) -> bool:
right = self.right
if (
isinstance(right, TypeVarTupleType)
and right.id == left.id
):
return True
return self._is_proper_subtype(left.upper_bound, self.right)

def visit_unpack_type(self, left: UnpackType) -> bool:
raise NotImplementedError

Expand Down
17 changes: 15 additions & 2 deletions mypy/tvar_scope.py
@@ -1,6 +1,10 @@
from typing import Optional, Dict, Union
from mypy.types import TypeVarLikeType, TypeVarType, ParamSpecType, ParamSpecFlavor, TypeVarId
from mypy.nodes import ParamSpecExpr, TypeVarExpr, TypeVarLikeExpr, SymbolTableNode
from mypy.types import (
TypeVarLikeType, TypeVarType, ParamSpecType, ParamSpecFlavor, TypeVarId, TypeVarTupleType,
)
from mypy.nodes import (
ParamSpecExpr, TypeVarExpr, TypeVarLikeExpr, SymbolTableNode, TypeVarTupleExpr,
)


class TypeVarLikeScope:
Expand Down Expand Up @@ -88,6 +92,15 @@ def bind_new(self, name: str, tvar_expr: TypeVarLikeExpr) -> TypeVarLikeType:
line=tvar_expr.line,
column=tvar_expr.column
)
elif isinstance(tvar_expr, TypeVarTupleExpr):
tvar_def = TypeVarTupleType(
name,
tvar_expr.fullname,
i,
upper_bound=tvar_expr.upper_bound,
line=tvar_expr.line,
column=tvar_expr.column
)
else:
assert False
self.scope[tvar_expr.fullname] = tvar_def
Expand Down
13 changes: 12 additions & 1 deletion mypy/type_visitor.py
Expand Up @@ -23,7 +23,8 @@
Parameters, RawExpressionType, Instance, NoneType, TypeType,
UnionType, TypeVarType, PartialType, DeletedType, UninhabitedType, TypeVarLikeType,
UnboundType, ErasedType, StarType, EllipsisType, TypeList, CallableArgument,
PlaceholderType, TypeAliasType, ParamSpecType, UnpackType, get_proper_type
PlaceholderType, TypeAliasType, ParamSpecType, UnpackType, TypeVarTupleType,
get_proper_type
)


Expand Down Expand Up @@ -71,6 +72,10 @@ def visit_param_spec(self, t: ParamSpecType) -> T:
def visit_parameters(self, t: Parameters) -> T:
pass

@abstractmethod
def visit_type_var_tuple(self, t: TypeVarTupleType) -> T:
pass

@abstractmethod
def visit_instance(self, t: Instance) -> T:
pass
Expand Down Expand Up @@ -197,6 +202,9 @@ def visit_param_spec(self, t: ParamSpecType) -> Type:
def visit_parameters(self, t: Parameters) -> Type:
return t.copy_modified(arg_types=self.translate_types(t.arg_types))

def visit_type_var_tuple(self, t: TypeVarTupleType) -> Type:
return t

def visit_partial_type(self, t: PartialType) -> Type:
return t

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

def visit_type_var_tuple(self, t: TypeVarTupleType) -> T:
return self.strategy([])

def visit_unpack_type(self, t: UnpackType) -> T:
return self.query_types([t.type])

Expand Down

0 comments on commit a16c414

Please sign in to comment.