@@ -32,11 +32,29 @@ def find_modules(self, typs: Iterable[types.Type]) -> set[str]:
3232 self .modules = set ()
3333 self .seen_fullnames = set ()
3434 self .seen_aliases = set ()
35- self ._visit (typs )
35+ for typ in typs :
36+ self ._visit (typ )
3637 return self .modules
3738
38- def _visit (self , typ_or_typs : types .Type | Iterable [types .Type ]) -> None :
39- typs = [typ_or_typs ] if isinstance (typ_or_typs , types .Type ) else typ_or_typs
39+ def _visit (self , typ : types .Type ) -> None :
40+ if isinstance (typ , types .TypeAliasType ):
41+ # Avoid infinite recursion for recursive type aliases.
42+ if typ not in self .seen_aliases :
43+ self .seen_aliases .add (typ )
44+ typ .accept (self )
45+
46+ def _visit_type_tuple (self , typs : tuple [types .Type , ...]) -> None :
47+ # Micro-optimization: Specialized version of _visit for lists
48+ for typ in typs :
49+ if isinstance (typ , types .TypeAliasType ):
50+ # Avoid infinite recursion for recursive type aliases.
51+ if typ in self .seen_aliases :
52+ continue
53+ self .seen_aliases .add (typ )
54+ typ .accept (self )
55+
56+ def _visit_type_list (self , typs : list [types .Type ]) -> None :
57+ # Micro-optimization: Specialized version of _visit for tuples
4058 for typ in typs :
4159 if isinstance (typ , types .TypeAliasType ):
4260 # Avoid infinite recursion for recursive type aliases.
@@ -50,7 +68,7 @@ def _visit_module_name(self, module_name: str) -> None:
5068 self .modules .update (split_module_names (module_name ))
5169
5270 def visit_unbound_type (self , t : types .UnboundType ) -> None :
53- self ._visit (t .args )
71+ self ._visit_type_tuple (t .args )
5472
5573 def visit_any (self , t : types .AnyType ) -> None :
5674 pass
@@ -68,7 +86,7 @@ def visit_deleted_type(self, t: types.DeletedType) -> None:
6886 pass
6987
7088 def visit_type_var (self , t : types .TypeVarType ) -> None :
71- self ._visit (t .values )
89+ self ._visit_type_list (t .values )
7290 self ._visit (t .upper_bound )
7391 self ._visit (t .default )
7492
@@ -84,10 +102,10 @@ def visit_unpack_type(self, t: types.UnpackType) -> None:
84102 t .type .accept (self )
85103
86104 def visit_parameters (self , t : types .Parameters ) -> None :
87- self ._visit (t .arg_types )
105+ self ._visit_type_list (t .arg_types )
88106
89107 def visit_instance (self , t : types .Instance ) -> None :
90- self ._visit (t .args )
108+ self ._visit_type_tuple (t .args )
91109 if t .type :
92110 # Uses of a class depend on everything in the MRO,
93111 # as changes to classes in the MRO can add types to methods,
@@ -98,7 +116,7 @@ def visit_instance(self, t: types.Instance) -> None:
98116 self ._visit_module_name (t .type .metaclass_type .type .module_name )
99117
100118 def visit_callable_type (self , t : types .CallableType ) -> None :
101- self ._visit (t .arg_types )
119+ self ._visit_type_list (t .arg_types )
102120 self ._visit (t .ret_type )
103121 if t .definition is not None :
104122 fullname = t .definition .fullname
@@ -107,22 +125,22 @@ def visit_callable_type(self, t: types.CallableType) -> None:
107125 self .seen_fullnames .add (fullname )
108126
109127 def visit_overloaded (self , t : types .Overloaded ) -> None :
110- self ._visit ( t .items )
128+ self ._visit_type_list ( list ( t .items ) )
111129 self ._visit (t .fallback )
112130
113131 def visit_tuple_type (self , t : types .TupleType ) -> None :
114- self ._visit (t .items )
132+ self ._visit_type_list (t .items )
115133 self ._visit (t .partial_fallback )
116134
117135 def visit_typeddict_type (self , t : types .TypedDictType ) -> None :
118- self ._visit ( t .items .values ())
136+ self ._visit_type_list ( list ( t .items .values () ))
119137 self ._visit (t .fallback )
120138
121139 def visit_literal_type (self , t : types .LiteralType ) -> None :
122140 self ._visit (t .fallback )
123141
124142 def visit_union_type (self , t : types .UnionType ) -> None :
125- self ._visit (t .items )
143+ self ._visit_type_list (t .items )
126144
127145 def visit_partial_type (self , t : types .PartialType ) -> None :
128146 pass
0 commit comments