Skip to content

Add TypeVarTupleType type node #12632

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion mypy/constraints.py
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Loading