11//! Helper functions for working with def, which don't need to be a separate
22//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
33
4+ use std:: iter;
5+
46use chalk_ir:: { fold:: Shift , BoundVar , DebruijnIndex } ;
57use hir_def:: {
68 db:: DefDatabase ,
@@ -14,8 +16,12 @@ use hir_def::{
1416 AssocContainerId , GenericDefId , Lookup , TraitId , TypeAliasId , TypeParamId ,
1517} ;
1618use hir_expand:: name:: { name, Name } ;
19+ use rustc_hash:: FxHashSet ;
1720
18- use crate :: { db:: HirDatabase , Interner , Substitution , TraitRef , TraitRefExt , TyKind , WhereClause } ;
21+ use crate :: {
22+ db:: HirDatabase , ChalkTraitId , Interner , Substitution , TraitRef , TraitRefExt , TyKind ,
23+ WhereClause ,
24+ } ;
1925
2026fn direct_super_traits ( db : & dyn DefDatabase , trait_ : TraitId ) -> Vec < TraitId > {
2127 let resolver = trait_. resolver ( db) ;
@@ -102,33 +108,43 @@ pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
102108/// `all_super_traits` is that we keep track of type parameters; for example if
103109/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
104110/// `Self: OtherTrait<i32>`.
105- pub ( super ) fn all_super_trait_refs ( db : & dyn HirDatabase , trait_ref : TraitRef ) -> Vec < TraitRef > {
106- // FIXME: replace by Chalk's `super_traits`, maybe make this a query
111+ pub ( super ) fn all_super_trait_refs ( db : & dyn HirDatabase , trait_ref : TraitRef ) -> SuperTraits {
112+ SuperTraits { db, seen : iter:: once ( trait_ref. trait_id ) . collect ( ) , stack : vec ! [ trait_ref] }
113+ }
107114
108- // we need to take care a bit here to avoid infinite loops in case of cycles
109- // (i.e. if we have `trait A: B; trait B: A;`)
110- let mut result = vec ! [ trait_ref] ;
111- let mut i = 0 ;
112- while i < result. len ( ) {
113- let t = & result[ i] ;
114- // yeah this is quadratic, but trait hierarchies should be flat
115- // enough that this doesn't matter
116- for tt in direct_super_trait_refs ( db, t) {
117- if !result. iter ( ) . any ( |tr| tr. trait_id == tt. trait_id ) {
118- result. push ( tt) ;
119- }
115+ pub ( super ) struct SuperTraits < ' a > {
116+ db : & ' a dyn HirDatabase ,
117+ stack : Vec < TraitRef > ,
118+ seen : FxHashSet < ChalkTraitId > ,
119+ }
120+
121+ impl < ' a > SuperTraits < ' a > {
122+ fn elaborate ( & mut self , trait_ref : & TraitRef ) {
123+ let mut trait_refs = direct_super_trait_refs ( self . db , trait_ref) ;
124+ trait_refs. retain ( |tr| !self . seen . contains ( & tr. trait_id ) ) ;
125+ self . stack . extend ( trait_refs) ;
126+ }
127+ }
128+
129+ impl < ' a > Iterator for SuperTraits < ' a > {
130+ type Item = TraitRef ;
131+
132+ fn next ( & mut self ) -> Option < Self :: Item > {
133+ if let Some ( next) = self . stack . pop ( ) {
134+ self . elaborate ( & next) ;
135+ Some ( next)
136+ } else {
137+ None
120138 }
121- i += 1 ;
122139 }
123- result
124140}
125141
126142pub ( super ) fn associated_type_by_name_including_super_traits (
127143 db : & dyn HirDatabase ,
128144 trait_ref : TraitRef ,
129145 name : & Name ,
130146) -> Option < ( TraitRef , TypeAliasId ) > {
131- all_super_trait_refs ( db, trait_ref) . into_iter ( ) . find_map ( |t| {
147+ all_super_trait_refs ( db, trait_ref) . find_map ( |t| {
132148 let assoc_type = db. trait_data ( t. hir_trait_id ( ) ) . associated_type_by_name ( name) ?;
133149 Some ( ( t, assoc_type) )
134150 } )
0 commit comments