Skip to content

Commit 5ebd05e

Browse files
Michael0x2ailevkivskyi
authored andcommitted
Make TypeVisitor and SyntheticTypeVisitor (almost) fully abstract (#7312)
This pull request almost resolves #730 -- it makes all TypeVisitor and SyntheticTypeVisitor methods with the exception of TypeAliasType abstract. This thankfully required fairly minimal changes. I ended up needing to make only three non-trivial changes: 1. The visitor for PlaceholderType was moved out of TypeVisitor into SyntheticTypeVisitor. My understanding is that PlaceholderType is a semantic analysis only type, so this ought to be safe. 2. As a consequence of 1, I ended up removing the existing PlaceholderType visitor method from TypeTranslator. (It seems that method was added about 6 months ago when PlaceholderType was first introduced, and was untouched since then). 3. TypeIndirectionVisitor was turned from a SyntheticTypeVisitor into a TypeVisitor. I believe we call this visitor only in the final pass, after the type-checking phase.
1 parent 1e25e05 commit 5ebd05e

File tree

7 files changed

+44
-36
lines changed

7 files changed

+44
-36
lines changed

mypy/fixup.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ def visit_overloaded(self, t: Overloaded) -> None:
185185
for ct in t.items():
186186
ct.accept(self)
187187

188+
def visit_erased_type(self, o: Any) -> None:
189+
# This type should exist only temporarily during type inference
190+
raise RuntimeError("Shouldn't get here", o)
191+
188192
def visit_deleted_type(self, o: Any) -> None:
189193
pass # Nothing to descend into.
190194

mypy/indirection.py

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Dict, Iterable, List, Optional, Set, Union
22

3-
from mypy.types import SyntheticTypeVisitor
3+
from mypy.types import TypeVisitor
44
import mypy.types as types
55
from mypy.util import split_module_names
66

@@ -15,7 +15,7 @@ def extract_module_names(type_name: Optional[str]) -> List[str]:
1515
return []
1616

1717

18-
class TypeIndirectionVisitor(SyntheticTypeVisitor[Set[str]]):
18+
class TypeIndirectionVisitor(TypeVisitor[Set[str]]):
1919
"""Returns all module references within a particular type."""
2020

2121
def __init__(self) -> None:
@@ -39,12 +39,6 @@ def _visit(self, typ_or_typs: Union[types.Type, Iterable[types.Type]]) -> Set[st
3939
def visit_unbound_type(self, t: types.UnboundType) -> Set[str]:
4040
return self._visit(t.args)
4141

42-
def visit_type_list(self, t: types.TypeList) -> Set[str]:
43-
return self._visit(t.items)
44-
45-
def visit_callable_argument(self, t: types.CallableArgument) -> Set[str]:
46-
return self._visit(t.typ)
47-
4842
def visit_any(self, t: types.AnyType) -> Set[str]:
4943
return set()
5044

@@ -90,23 +84,14 @@ def visit_tuple_type(self, t: types.TupleType) -> Set[str]:
9084
def visit_typeddict_type(self, t: types.TypedDictType) -> Set[str]:
9185
return self._visit(t.items.values()) | self._visit(t.fallback)
9286

93-
def visit_raw_expression_type(self, t: types.RawExpressionType) -> Set[str]:
94-
assert False, "Unexpected RawExpressionType after semantic analysis phase"
95-
9687
def visit_literal_type(self, t: types.LiteralType) -> Set[str]:
9788
return self._visit(t.fallback)
9889

99-
def visit_star_type(self, t: types.StarType) -> Set[str]:
100-
return set()
101-
10290
def visit_union_type(self, t: types.UnionType) -> Set[str]:
10391
return self._visit(t.items)
10492

10593
def visit_partial_type(self, t: types.PartialType) -> Set[str]:
10694
return set()
10795

108-
def visit_ellipsis_type(self, t: types.EllipsisType) -> Set[str]:
109-
return set()
110-
11196
def visit_type_type(self, t: types.TypeType) -> Set[str]:
11297
return self._visit(t.item)

mypy/server/astmerge.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@
5656
)
5757
from mypy.traverser import TraverserVisitor
5858
from mypy.types import (
59-
Type, SyntheticTypeVisitor, Instance, AnyType, NoneType, CallableType, DeletedType,
59+
Type, SyntheticTypeVisitor, Instance, AnyType, NoneType, CallableType, ErasedType, DeletedType,
6060
TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType,
6161
Overloaded, TypeVarDef, TypeList, CallableArgument, EllipsisType, StarType, LiteralType,
62-
RawExpressionType, PartialType,
62+
RawExpressionType, PartialType, PlaceholderType,
6363
)
6464
from mypy.util import get_prefix, replace_object_state
6565
from mypy.typestate import TypeState
@@ -373,6 +373,10 @@ def visit_overloaded(self, t: Overloaded) -> None:
373373
if t.fallback is not None:
374374
t.fallback.accept(self)
375375

376+
def visit_erased_type(self, t: ErasedType) -> None:
377+
# This type should exist only temporarily during type inference
378+
raise RuntimeError
379+
376380
def visit_deleted_type(self, typ: DeletedType) -> None:
377381
pass
378382

@@ -429,6 +433,10 @@ def visit_union_type(self, typ: UnionType) -> None:
429433
for item in typ.items:
430434
item.accept(self)
431435

436+
def visit_placeholder_type(self, t: PlaceholderType) -> None:
437+
for item in t.args:
438+
item.accept(self)
439+
432440
# Helpers
433441

434442
def fixup(self, node: SN) -> SN:

mypy/server/deps.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class 'mod.Cls'. This can also refer to an attribute inherited from a
9696
from mypy.types import (
9797
Type, Instance, AnyType, NoneType, TypeVisitor, CallableType, DeletedType, PartialType,
9898
TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType,
99-
FunctionLike, Overloaded, TypeOfAny, LiteralType, get_proper_type, ProperType
99+
FunctionLike, Overloaded, TypeOfAny, LiteralType, ErasedType, get_proper_type, ProperType
100100
)
101101
from mypy.server.trigger import make_trigger, make_wildcard_trigger
102102
from mypy.util import correct_relative_import
@@ -901,6 +901,10 @@ def visit_overloaded(self, typ: Overloaded) -> List[str]:
901901
triggers.extend(self.get_type_triggers(item))
902902
return triggers
903903

904+
def visit_erased_type(self, t: ErasedType) -> List[str]:
905+
# This type should exist only temporarily during type inference
906+
assert False, "Should not see an erased type here"
907+
904908
def visit_deleted_type(self, typ: DeletedType) -> List[str]:
905909
return []
906910

mypy/type_visitor.py

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,6 @@ class TypeVisitor(Generic[T]):
3434
The parameter T is the return type of the visit methods.
3535
"""
3636

37-
def _notimplemented_helper(self, name: str) -> NotImplementedError:
38-
return NotImplementedError("Method {}.visit_{}() not implemented\n"
39-
.format(type(self).__name__, name)
40-
+ "This is a known bug, track development in "
41-
+ "'https://github.com/JukkaL/mypy/issues/730'")
42-
4337
@abstractmethod
4438
def visit_unbound_type(self, t: UnboundType) -> T:
4539
pass
@@ -56,8 +50,9 @@ def visit_none_type(self, t: NoneType) -> T:
5650
def visit_uninhabited_type(self, t: UninhabitedType) -> T:
5751
pass
5852

53+
@abstractmethod
5954
def visit_erased_type(self, t: ErasedType) -> T:
60-
raise self._notimplemented_helper('erased_type')
55+
pass
6156

6257
@abstractmethod
6358
def visit_deleted_type(self, t: DeletedType) -> T:
@@ -75,8 +70,9 @@ def visit_instance(self, t: Instance) -> T:
7570
def visit_callable_type(self, t: CallableType) -> T:
7671
pass
7772

73+
@abstractmethod
7874
def visit_overloaded(self, t: Overloaded) -> T:
79-
raise self._notimplemented_helper('overloaded')
75+
pass
8076

8177
@abstractmethod
8278
def visit_tuple_type(self, t: TupleType) -> T:
@@ -105,9 +101,6 @@ def visit_type_type(self, t: TypeType) -> T:
105101
def visit_type_alias_type(self, t: TypeAliasType) -> T:
106102
raise NotImplementedError('TODO')
107103

108-
def visit_placeholder_type(self, t: PlaceholderType) -> T:
109-
raise RuntimeError('Internal error: unresolved placeholder type {}'.format(t.fullname))
110-
111104

112105
@trait
113106
class SyntheticTypeVisitor(TypeVisitor[T]):
@@ -135,6 +128,10 @@ def visit_ellipsis_type(self, t: EllipsisType) -> T:
135128
def visit_raw_expression_type(self, t: RawExpressionType) -> T:
136129
pass
137130

131+
@abstractmethod
132+
def visit_placeholder_type(self, t: PlaceholderType) -> T:
133+
pass
134+
138135

139136
@trait
140137
class TypeTranslator(TypeVisitor[Type]):
@@ -235,9 +232,6 @@ def visit_overloaded(self, t: Overloaded) -> Type:
235232
def visit_type_type(self, t: TypeType) -> Type:
236233
return TypeType.make_normalized(t.item.accept(self), line=t.line, column=t.column)
237234

238-
def visit_placeholder_type(self, t: PlaceholderType) -> Type:
239-
return PlaceholderType(t.fullname, self.translate_types(t.args), t.line)
240-
241235

242236
@trait
243237
class TypeQuery(SyntheticTypeVisitor[T]):

mypy/typeanal.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
from mypy.options import Options
1414
from mypy.types import (
1515
Type, UnboundType, TypeVarType, TupleType, TypedDictType, UnionType, Instance, AnyType,
16-
CallableType, NoneType, DeletedType, TypeList, TypeVarDef, SyntheticTypeVisitor,
16+
CallableType, NoneType, ErasedType, DeletedType, TypeList, TypeVarDef, SyntheticTypeVisitor,
1717
StarType, PartialType, EllipsisType, UninhabitedType, TypeType, replace_alias_tvars,
1818
CallableArgument, get_type_vars, TypeQuery, union_items, TypeOfAny,
19-
LiteralType, RawExpressionType, PlaceholderType, get_proper_type, ProperType
19+
LiteralType, RawExpressionType, PlaceholderType, Overloaded, get_proper_type, ProperType
2020
)
2121

2222
from mypy.nodes import (
@@ -456,6 +456,10 @@ def visit_none_type(self, t: NoneType) -> Type:
456456
def visit_uninhabited_type(self, t: UninhabitedType) -> Type:
457457
return t
458458

459+
def visit_erased_type(self, t: ErasedType) -> Type:
460+
# This type should exist only temporarily during type inference
461+
assert False, "Internal error: Unexpected erased type"
462+
459463
def visit_deleted_type(self, t: DeletedType) -> Type:
460464
return t
461465

@@ -490,6 +494,14 @@ def visit_callable_type(self, t: CallableType, nested: bool = True) -> Type:
490494
variables=self.anal_var_defs(variables))
491495
return ret
492496

497+
def visit_overloaded(self, t: Overloaded) -> Type:
498+
# Overloaded types are manually constructed in semanal.py by analyzing the
499+
# AST and combining together the Callable types this visitor converts.
500+
#
501+
# So if we're ever asked to reanalyze an Overloaded type, we know it's
502+
# fine to just return it as-is.
503+
return t
504+
493505
def visit_tuple_type(self, t: TupleType) -> Type:
494506
# Types such as (t1, t2, ...) only allowed in assignment statements. They'll
495507
# generate errors elsewhere, and Tuple[t1, t2, ...] must be used instead.

mypy/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1947,6 +1947,7 @@ def __init__(self, fullname: Optional[str], args: List[Type], line: int) -> None
19471947
self.args = args
19481948

19491949
def accept(self, visitor: 'TypeVisitor[T]') -> T:
1950+
assert isinstance(visitor, SyntheticTypeVisitor)
19501951
return visitor.visit_placeholder_type(self)
19511952

19521953
def serialize(self) -> str:

0 commit comments

Comments
 (0)