1515from mypy .message_registry import INVALID_PARAM_SPEC_LOCATION , INVALID_PARAM_SPEC_LOCATION_NOTE
1616from mypy .messages import format_type
1717from mypy .mixedtraverser import MixedTraverserVisitor
18- from mypy .nodes import Block , ClassDef , Context , FakeInfo , FuncItem , MypyFile
18+ from mypy .nodes import Block , ClassDef , Context , FakeInfo , FuncItem , MypyFile , TypeAlias
1919from mypy .options import Options
2020from mypy .scope import Scope
2121from mypy .subtypes import is_same_type , is_subtype
@@ -58,9 +58,11 @@ def __init__(
5858 self .scope = Scope ()
5959 # Should we also analyze function definitions, or only module top-levels?
6060 self .recurse_into_functions = True
61- # Keep track of the type aliases already visited. This is needed to avoid
62- # infinite recursion on types like A = Union[int, List[A]].
63- self .seen_aliases : set [TypeAliasType ] = set ()
61+ # Keep track of the type alias definitions already visited. This is needed
62+ # to avoid infinite recursion on recursive type aliases. We track by the
63+ # underlying TypeAlias node (not TypeAliasType) so that recursive aliases
64+ # with varying type arguments are still caught.
65+ self .seen_aliases : set [TypeAlias ] = set ()
6466
6567 def visit_mypy_file (self , o : MypyFile ) -> None :
6668 self .errors .set_file (o .path , o .fullname , scope = self .scope , options = self .options )
@@ -84,10 +86,10 @@ def visit_block(self, o: Block) -> None:
8486 def visit_type_alias_type (self , t : TypeAliasType ) -> None :
8587 super ().visit_type_alias_type (t )
8688 if t .is_recursive :
87- if t in self .seen_aliases :
89+ if t . alias in self .seen_aliases :
8890 # Avoid infinite recursion on recursive type aliases.
8991 return
90- self .seen_aliases .add (t )
92+ self .seen_aliases .add (t . alias )
9193 assert t .alias is not None , f"Unfixed type alias { t .type_ref } "
9294 is_error , is_invalid = self .validate_args (
9395 t .alias .name , tuple (t .args ), t .alias .alias_tvars , t
@@ -105,7 +107,7 @@ def visit_type_alias_type(self, t: TypeAliasType) -> None:
105107 # to verify the arguments satisfy the upper bounds of the expansion as well.
106108 get_proper_type (t ).accept (self )
107109 if t .is_recursive :
108- self .seen_aliases .discard (t )
110+ self .seen_aliases .discard (t . alias )
109111
110112 def visit_tuple_type (self , t : TupleType ) -> None :
111113 t .items = flatten_nested_tuples (t .items )
0 commit comments