From 8f7d5c7e436795fe0d0ac2cf7b1bf2344fd161e1 Mon Sep 17 00:00:00 2001 From: Naomi Seyfer Date: Wed, 19 Apr 2017 23:26:42 -0700 Subject: [PATCH] Use inheritance to allow most TypeVisitors not to deal with "synthetic" types This is a nearly-complete fix to https://github.com/python/mypy/issues/730 -- the trick is that some types aren't real, they're synthetic AST constructs, and so we shouldn't have to deal with those in every type visitor. Only the type visitors that deal with types before the synthetic constructs are analyzed away. --- mypy/erasetype.py | 4 +--- mypy/expandtype.py | 3 --- mypy/fixup.py | 7 ------- mypy/indirection.py | 4 ++-- mypy/join.py | 3 --- mypy/meet.py | 3 --- mypy/sametypes.py | 3 --- mypy/server/astdiff.py | 3 --- mypy/subtypes.py | 6 ------ mypy/types.py | 39 +++++++++++++++++++++++++++------------ 10 files changed, 30 insertions(+), 45 deletions(-) diff --git a/mypy/erasetype.py b/mypy/erasetype.py index 330df74d9499..49035accf976 100644 --- a/mypy/erasetype.py +++ b/mypy/erasetype.py @@ -26,10 +26,8 @@ def erase_type(typ: Type) -> Type: class EraseTypeVisitor(TypeVisitor[Type]): - def visit_unbound_type(self, t: UnboundType) -> Type: - assert False, 'Not supported' - def visit_type_list(self, t: TypeList) -> Type: + def visit_unbound_type(self, t: UnboundType) -> Type: assert False, 'Not supported' def visit_any(self, t: AnyType) -> Type: diff --git a/mypy/expandtype.py b/mypy/expandtype.py index a526ddd2e020..18301191948b 100644 --- a/mypy/expandtype.py +++ b/mypy/expandtype.py @@ -63,9 +63,6 @@ def __init__(self, variables: Mapping[TypeVarId, Type]) -> None: def visit_unbound_type(self, t: UnboundType) -> Type: return t - def visit_type_list(self, t: TypeList) -> Type: - assert False, 'Not supported' - def visit_any(self, t: AnyType) -> Type: return t diff --git a/mypy/fixup.py b/mypy/fixup.py index 58c1abad5356..0d85feb86ef5 100644 --- a/mypy/fixup.py +++ b/mypy/fixup.py @@ -177,9 +177,6 @@ def visit_callable_type(self, ct: CallableType) -> None: val.accept(self) v.upper_bound.accept(self) - def visit_ellipsis_type(self, e: EllipsisType) -> None: - pass # Nothing to descend into. - def visit_overloaded(self, t: Overloaded) -> None: for ct in t.items(): ct.accept(self) @@ -210,10 +207,6 @@ def visit_typeddict_type(self, tdt: TypedDictType) -> None: if tdt.fallback is not None: tdt.fallback.accept(self) - def visit_type_list(self, tl: TypeList) -> None: - for t in tl.items: - t.accept(self) - def visit_type_var(self, tvt: TypeVarType) -> None: if tvt.values: for vt in tvt.values: diff --git a/mypy/indirection.py b/mypy/indirection.py index cf22648b664b..332eb4357967 100644 --- a/mypy/indirection.py +++ b/mypy/indirection.py @@ -2,7 +2,7 @@ from abc import abstractmethod from mypy.visitor import NodeVisitor -from mypy.types import TypeVisitor +from mypy.types import SyntheticTypeVisitor from mypy.nodes import MODULE_REF import mypy.nodes as nodes import mypy.types as types @@ -19,7 +19,7 @@ def extract_module_names(type_name: Optional[str]) -> List[str]: return [] -class TypeIndirectionVisitor(TypeVisitor[Set[str]]): +class TypeIndirectionVisitor(SyntheticTypeVisitor[Set[str]]): """Returns all module references within a particular type.""" def __init__(self) -> None: diff --git a/mypy/join.py b/mypy/join.py index e0275f0ada0a..b4866bdbc691 100644 --- a/mypy/join.py +++ b/mypy/join.py @@ -107,9 +107,6 @@ def visit_union_type(self, t: UnionType) -> Type: else: return UnionType.make_simplified_union([self.s, t]) - def visit_type_list(self, t: TypeList) -> Type: - assert False, 'Not supported' - def visit_any(self, t: AnyType) -> Type: return t diff --git a/mypy/meet.py b/mypy/meet.py index c644a2291d11..feda9bea1854 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -139,9 +139,6 @@ def visit_unbound_type(self, t: UnboundType) -> Type: else: return AnyType() - def visit_type_list(self, t: TypeList) -> Type: - assert False, 'Not supported' - def visit_any(self, t: AnyType) -> Type: return self.s diff --git a/mypy/sametypes.py b/mypy/sametypes.py index f1a697ced4c9..0531ecc2d474 100644 --- a/mypy/sametypes.py +++ b/mypy/sametypes.py @@ -55,9 +55,6 @@ def __init__(self, right: Type) -> None: def visit_unbound_type(self, left: UnboundType) -> bool: return True - def visit_type_list(self, t: TypeList) -> bool: - assert False, 'Not supported' - def visit_any(self, left: AnyType) -> bool: return isinstance(self.right, AnyType) diff --git a/mypy/server/astdiff.py b/mypy/server/astdiff.py index 8b05928a1e55..9da9056c56b4 100644 --- a/mypy/server/astdiff.py +++ b/mypy/server/astdiff.py @@ -136,9 +136,6 @@ def __init__(self, right: Type) -> None: def visit_unbound_type(self, left: UnboundType) -> bool: return False - def visit_type_list(self, t: TypeList) -> bool: - assert False, 'Not supported' - def visit_any(self, left: AnyType) -> bool: return isinstance(self.right, AnyType) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 2642f603cc96..d122923155bf 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -109,9 +109,6 @@ def __init__(self, right: Type, def visit_unbound_type(self, left: UnboundType) -> bool: return True - def visit_type_list(self, t: TypeList) -> bool: - assert False, 'Not supported' - def visit_any(self, left: AnyType) -> bool: return True @@ -563,9 +560,6 @@ def visit_unbound_type(self, left: UnboundType) -> bool: # from unions, which could filter out some bogus messages. return True - def visit_type_list(self, left: TypeList) -> bool: - assert False, 'Should not happen' - def visit_any(self, left: AnyType) -> bool: return isinstance(self.right, AnyType) diff --git a/mypy/types.py b/mypy/types.py index 598924db5a29..7c6383375fdf 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -975,6 +975,7 @@ def __init__(self, type: Type, line: int = -1, column: int = -1) -> None: super().__init__(line, column) def accept(self, visitor: 'TypeVisitor[T]') -> T: + assert isinstance(visitor, SyntheticTypeVisitor) return visitor.visit_star_type(self) @@ -1116,6 +1117,7 @@ class EllipsisType(Type): """ def accept(self, visitor: 'TypeVisitor[T]') -> T: + assert isinstance(visitor, SyntheticTypeVisitor) return visitor.visit_ellipsis_type(self) def serialize(self) -> JsonDict: @@ -1199,9 +1201,6 @@ def _notimplemented_helper(self, name: str) -> NotImplementedError: def visit_unbound_type(self, t: UnboundType) -> T: pass - def visit_type_list(self, t: TypeList) -> T: - raise self._notimplemented_helper('type_list') - @abstractmethod def visit_any(self, t: AnyType) -> T: pass @@ -1244,9 +1243,6 @@ def visit_tuple_type(self, t: TupleType) -> T: def visit_typeddict_type(self, t: TypedDictType) -> T: pass - def visit_star_type(self, t: StarType) -> T: - raise self._notimplemented_helper('star_type') - @abstractmethod def visit_union_type(self, t: UnionType) -> T: pass @@ -1255,15 +1251,34 @@ def visit_union_type(self, t: UnionType) -> T: def visit_partial_type(self, t: PartialType) -> T: pass - def visit_ellipsis_type(self, t: EllipsisType) -> T: - raise self._notimplemented_helper('ellipsis_type') - @abstractmethod def visit_type_type(self, t: TypeType) -> T: pass -class TypeTranslator(TypeVisitor[Type]): +class SyntheticTypeVisitor(TypeVisitor[T]): + """A TypeVisitor that also knows how to visit synthetic AST constructs. + + Not just real types.""" + + @abstractmethod + def visit_star_type(self, t: StarType) -> T: + pass + + @abstractmethod + def visit_type_list(self, t: TypeList) -> T: + pass + + @abstractmethod + def visit_callable_argument(self, t: CallableArgument) -> T: + pass + + @abstractmethod + def visit_ellipsis_type(self, t: EllipsisType) -> T: + pass + + +class TypeTranslator(SyntheticTypeVisitor[Type]): """Identity type transformation. Subclass this and override some methods to implement a non-trivial @@ -1351,7 +1366,7 @@ def visit_type_type(self, t: TypeType) -> Type: return TypeType(t.item.accept(self), line=t.line, column=t.column) -class TypeStrVisitor(TypeVisitor[str]): +class TypeStrVisitor(SyntheticTypeVisitor[str]): """Visitor for pretty-printing types into strings. This is mostly for debugging/testing. @@ -1510,7 +1525,7 @@ def keywords_str(self, a: Iterable[Tuple[str, Type]]) -> str: ]) -class TypeQuery(Generic[T], TypeVisitor[T]): +class TypeQuery(SyntheticTypeVisitor[T]): """Visitor for performing queries of types. strategy is used to combine results for a series of types