1
1
//! Helper functions for working with def, which don't need to be a separate
2
2
//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
3
3
4
+ use std:: iter;
5
+
4
6
use chalk_ir:: { fold:: Shift , BoundVar , DebruijnIndex } ;
5
7
use hir_def:: {
6
8
db:: DefDatabase ,
@@ -14,8 +16,12 @@ use hir_def::{
14
16
AssocContainerId , GenericDefId , Lookup , TraitId , TypeAliasId , TypeParamId ,
15
17
} ;
16
18
use hir_expand:: name:: { name, Name } ;
19
+ use rustc_hash:: FxHashSet ;
17
20
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
+ } ;
19
25
20
26
fn direct_super_traits ( db : & dyn DefDatabase , trait_ : TraitId ) -> Vec < TraitId > {
21
27
let resolver = trait_. resolver ( db) ;
@@ -102,33 +108,43 @@ pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
102
108
/// `all_super_traits` is that we keep track of type parameters; for example if
103
109
/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
104
110
/// `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
+ }
107
114
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
120
138
}
121
- i += 1 ;
122
139
}
123
- result
124
140
}
125
141
126
142
pub ( super ) fn associated_type_by_name_including_super_traits (
127
143
db : & dyn HirDatabase ,
128
144
trait_ref : TraitRef ,
129
145
name : & Name ,
130
146
) -> 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| {
132
148
let assoc_type = db. trait_data ( t. hir_trait_id ( ) ) . associated_type_by_name ( name) ?;
133
149
Some ( ( t, assoc_type) )
134
150
} )
0 commit comments