Skip to content

Commit a484f16

Browse files
committed
avoid recursion errors
1 parent 8547b2e commit a484f16

File tree

2 files changed

+29
-13
lines changed

2 files changed

+29
-13
lines changed

mypy/checker.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -296,14 +296,22 @@ class InstanceDeprecatedVisitor(TypeVisitor[None]):
296296
def __init__(self, typechecker: TypeChecker, context: Context) -> None:
297297
self.typechecker = typechecker
298298
self.context = context
299+
self.visited: set[Type] = set()
300+
301+
def _already_visited(self, t: Type, /) -> bool:
302+
if t in self.visited:
303+
return True
304+
self.visited.add(t)
305+
return False
299306

300307
def visit_any(self, t: AnyType) -> None:
301308
pass
302309

303310
def visit_callable_type(self, t: CallableType) -> None:
304-
for arg_type in t.arg_types:
305-
arg_type.accept(self)
306-
t.ret_type.accept(self)
311+
if not self._already_visited(t):
312+
for arg_type in t.arg_types:
313+
arg_type.accept(self)
314+
t.ret_type.accept(self)
307315

308316
def visit_deleted_type(self, t: DeletedType) -> None:
309317
pass
@@ -312,9 +320,10 @@ def visit_erased_type(self, t: ErasedType) -> None:
312320
pass
313321

314322
def visit_instance(self, t: Instance) -> None:
315-
self.typechecker.check_deprecated(t.type, self.context)
316-
for arg in t.args:
317-
arg.accept(self)
323+
if not self._already_visited(t):
324+
self.typechecker.check_deprecated(t.type, self.context)
325+
for arg in t.args:
326+
arg.accept(self)
318327

319328
def visit_literal_type(self, t: LiteralType) -> None:
320329
pass
@@ -335,11 +344,14 @@ def visit_partial_type(self, t: PartialType) -> None:
335344
pass
336345

337346
def visit_tuple_type(self, t: TupleType) -> None:
338-
for item in t.items:
339-
item.accept(self)
347+
if not self._already_visited(t):
348+
for item in t.items:
349+
item.accept(self)
340350

341351
def visit_type_alias_type(self, t: TypeAliasType) -> None:
342-
t.alias.target.accept(self)
352+
if not self._already_visited(t):
353+
if ((alias := t.alias) is not None) and ((target := alias.target) is not None):
354+
target.accept(self)
343355

344356
def visit_type_type(self, t: TypeType) -> None:
345357
pass
@@ -360,8 +372,9 @@ def visit_uninhabited_type(self, t: UninhabitedType) -> None:
360372
pass
361373

362374
def visit_union_type(self, t: UnionType) -> None:
363-
for item in t.items:
364-
item.accept(self)
375+
if not self._already_visited(t):
376+
for item in t.items:
377+
item.accept(self)
365378

366379
def visit_unpack_type(self, t: UnpackType) -> None:
367380
pass

test-data/unit/check-deprecated.test

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,11 @@ x8: List[Optional[Tuple[Union[List[C], int]]]] # N: class __main__.C is depreca
141141
x9: Callable[[int], C] # N: class __main__.C is deprecated: use C2 instead
142142
x10: Callable[[int, C, int], int] # N: class __main__.C is deprecated: use C2 instead
143143

144-
A: TypeAlias = Optional[C] # ToDo
145-
x11: A # N: class __main__.C is deprecated: use C2 instead
144+
A1: TypeAlias = Optional[C] # ToDo
145+
x11: A1 # N: class __main__.C is deprecated: use C2 instead
146+
147+
A2: TypeAlias = List[Union[A2, C]] # ToDo
148+
x12: A2 # N: class __main__.C is deprecated: use C2 instead
146149

147150
[builtins fixtures/tuple.pyi]
148151

0 commit comments

Comments
 (0)