blob: cc6d4b637d2e2b6f5e3b36baa79346bec155db21 [file] [log] [blame]
from __future__ import annotations
from collections.abc import Iterable
from mypy_extensions import trait
from mypy.types import (
AnyType,
CallableArgument,
CallableType,
DeletedType,
EllipsisType,
ErasedType,
Instance,
LiteralType,
NoneType,
Overloaded,
Parameters,
ParamSpecType,
PartialType,
PlaceholderType,
RawExpressionType,
SyntheticTypeVisitor,
TupleType,
Type,
TypeAliasType,
TypedDictType,
TypeList,
TypeType,
TypeVarTupleType,
TypeVarType,
UnboundType,
UninhabitedType,
UnionType,
UnpackType,
)
@trait
class TypeTraverserVisitor(SyntheticTypeVisitor[None]):
"""Visitor that traverses all components of a type"""
# Atomic types
def visit_any(self, t: AnyType, /) -> None:
pass
def visit_uninhabited_type(self, t: UninhabitedType, /) -> None:
pass
def visit_none_type(self, t: NoneType, /) -> None:
pass
def visit_erased_type(self, t: ErasedType, /) -> None:
pass
def visit_deleted_type(self, t: DeletedType, /) -> None:
pass
def visit_type_var(self, t: TypeVarType, /) -> None:
# Note that type variable values and upper bound aren't treated as
# components, since they are components of the type variable
# definition. We want to traverse everything just once.
t.default.accept(self)
def visit_param_spec(self, t: ParamSpecType, /) -> None:
t.default.accept(self)
def visit_parameters(self, t: Parameters, /) -> None:
self.traverse_types(t.arg_types)
def visit_type_var_tuple(self, t: TypeVarTupleType, /) -> None:
t.default.accept(self)
def visit_literal_type(self, t: LiteralType, /) -> None:
t.fallback.accept(self)
# Composite types
def visit_instance(self, t: Instance, /) -> None:
self.traverse_types(t.args)
def visit_callable_type(self, t: CallableType, /) -> None:
# FIX generics
self.traverse_types(t.arg_types)
t.ret_type.accept(self)
t.fallback.accept(self)
if t.type_guard is not None:
t.type_guard.accept(self)
if t.type_is is not None:
t.type_is.accept(self)
def visit_tuple_type(self, t: TupleType, /) -> None:
self.traverse_types(t.items)
t.partial_fallback.accept(self)
def visit_typeddict_type(self, t: TypedDictType, /) -> None:
self.traverse_types(t.items.values())
t.fallback.accept(self)
def visit_union_type(self, t: UnionType, /) -> None:
self.traverse_types(t.items)
def visit_overloaded(self, t: Overloaded, /) -> None:
self.traverse_types(t.items)
def visit_type_type(self, t: TypeType, /) -> None:
t.item.accept(self)
# Special types (not real types)
def visit_callable_argument(self, t: CallableArgument, /) -> None:
t.typ.accept(self)
def visit_unbound_type(self, t: UnboundType, /) -> None:
self.traverse_types(t.args)
def visit_type_list(self, t: TypeList, /) -> None:
self.traverse_types(t.items)
def visit_ellipsis_type(self, t: EllipsisType, /) -> None:
pass
def visit_placeholder_type(self, t: PlaceholderType, /) -> None:
self.traverse_types(t.args)
def visit_partial_type(self, t: PartialType, /) -> None:
pass
def visit_raw_expression_type(self, t: RawExpressionType, /) -> None:
pass
def visit_type_alias_type(self, t: TypeAliasType, /) -> None:
# TODO: sometimes we want to traverse target as well
# We need to find a way to indicate explicitly the intent,
# maybe make this method abstract (like for TypeTranslator)?
self.traverse_types(t.args)
def visit_unpack_type(self, t: UnpackType, /) -> None:
t.type.accept(self)
# Helpers
def traverse_types(self, types: Iterable[Type], /) -> None:
for typ in types:
typ.accept(self)