@@ -295,3 +295,91 @@ pub(super) fn any_over_type<'db>(
295295 visitor. visit_type ( db, ty) ;
296296 visitor. found_matching_type . get ( )
297297}
298+
299+ /// Returns the number of layers of generic specializations for a given type.
300+ ///
301+ /// For example, `int` has a depth of `0`, `list[int]` has a depth of `1`, and
302+ /// `list[set[int]]` has a depth of `2`.
303+ pub ( super ) fn specialization_depth ( db : & dyn Db , ty : Type < ' _ > ) -> usize {
304+ struct SpecializationDepthVisitor < ' db > {
305+ seen_types : RefCell < FxIndexSet < NonAtomicType < ' db > > > ,
306+ max_depth : Cell < usize > ,
307+ }
308+
309+ impl < ' db > TypeVisitor < ' db > for SpecializationDepthVisitor < ' db > {
310+ fn should_visit_lazy_type_attributes ( & self ) -> bool {
311+ false
312+ }
313+
314+ fn visit_type ( & self , db : & ' db dyn Db , ty : Type < ' db > ) {
315+ match TypeKind :: from ( ty) {
316+ TypeKind :: Atomic => {
317+ if ty. is_divergent ( ) {
318+ self . max_depth . set ( usize:: MAX ) ;
319+ }
320+ }
321+ TypeKind :: NonAtomic ( non_atomic_type) => {
322+ if !self . seen_types . borrow_mut ( ) . insert ( non_atomic_type) {
323+ return ;
324+ }
325+
326+ walk_non_atomic_type ( db, non_atomic_type, self ) ;
327+ let child_max_depth = self . max_depth . get ( ) ;
328+
329+ let self_depth: usize =
330+ matches ! ( non_atomic_type, NonAtomicType :: GenericAlias ( _) ) . into ( ) ;
331+
332+ self . max_depth . set (
333+ self . max_depth
334+ . get ( )
335+ . max ( child_max_depth. saturating_add ( self_depth) ) ,
336+ ) ;
337+ }
338+ }
339+ }
340+ }
341+
342+ let visitor = SpecializationDepthVisitor {
343+ seen_types : RefCell :: new ( FxIndexSet :: default ( ) ) ,
344+ max_depth : Cell :: new ( 0 ) ,
345+ } ;
346+ visitor. visit_type ( db, ty) ;
347+ visitor. max_depth . get ( )
348+ }
349+
350+ #[ cfg( test) ]
351+ mod tests {
352+ use super :: * ;
353+ use crate :: { db:: tests:: setup_db, types:: KnownClass } ;
354+
355+ #[ test]
356+ fn test_generics_layering_depth ( ) {
357+ let db = setup_db ( ) ;
358+
359+ let list_of_int =
360+ KnownClass :: List . to_specialized_instance ( & db, [ KnownClass :: Int . to_instance ( & db) ] ) ;
361+ assert_eq ! ( specialization_depth( & db, list_of_int) , 1 ) ;
362+
363+ let list_of_list_of_int = KnownClass :: List . to_specialized_instance ( & db, [ list_of_int] ) ;
364+ assert_eq ! ( specialization_depth( & db, list_of_list_of_int) , 2 ) ;
365+
366+ let list_of_list_of_list_of_int =
367+ KnownClass :: List . to_specialized_instance ( & db, [ list_of_list_of_int] ) ;
368+ assert_eq ! ( specialization_depth( & db, list_of_list_of_list_of_int) , 3 ) ;
369+
370+ let set_of_dict_of_str_and_list_of_int = KnownClass :: Set . to_specialized_instance (
371+ & db,
372+ [ KnownClass :: Dict
373+ . to_specialized_instance ( & db, [ KnownClass :: Str . to_instance ( & db) , list_of_int] ) ] ,
374+ ) ;
375+ assert_eq ! (
376+ specialization_depth( & db, set_of_dict_of_str_and_list_of_int) ,
377+ 3
378+ ) ;
379+
380+ // list[list[int]] | list[list[list[int]]]
381+ let union_type =
382+ UnionType :: from_elements ( & db, [ list_of_list_of_int, list_of_list_of_list_of_int] ) ;
383+ assert_eq ! ( specialization_depth( & db, union_type) , 3 ) ;
384+ }
385+ }
0 commit comments