@@ -27,23 +27,84 @@ use crate::{
2727 db:: HirDatabase , ChalkTraitId , Interner , Substitution , TraitRef , TraitRefExt , WhereClause ,
2828} ;
2929
30- pub ( crate ) fn fn_traits ( db : & dyn DefDatabase , krate : CrateId ) -> impl Iterator < Item = TraitId > {
31- [
32- db. lang_item ( krate, LangItem :: Fn ) ,
33- db. lang_item ( krate, LangItem :: FnMut ) ,
34- db. lang_item ( krate, LangItem :: FnOnce ) ,
35- ]
36- . into_iter ( )
37- . flatten ( )
38- . flat_map ( |it| it. as_trait ( ) )
30+ pub ( crate ) fn fn_traits (
31+ db : & dyn DefDatabase ,
32+ krate : CrateId ,
33+ ) -> impl Iterator < Item = TraitId > + ' _ {
34+ [ LangItem :: Fn , LangItem :: FnMut , LangItem :: FnOnce ]
35+ . into_iter ( )
36+ . filter_map ( move |lang| db. lang_item ( krate, lang) )
37+ . flat_map ( |it| it. as_trait ( ) )
3938}
4039
41- fn direct_super_traits ( db : & dyn DefDatabase , trait_ : TraitId ) -> SmallVec < [ TraitId ; 4 ] > {
40+ /// Returns an iterator over the whole super trait hierarchy (including the
41+ /// trait itself).
42+ pub fn all_super_traits ( db : & dyn DefDatabase , trait_ : TraitId ) -> SmallVec < [ TraitId ; 4 ] > {
43+ // we need to take care a bit here to avoid infinite loops in case of cycles
44+ // (i.e. if we have `trait A: B; trait B: A;`)
45+
46+ let mut result = smallvec ! [ trait_] ;
47+ let mut i = 0 ;
48+ while let Some ( & t) = result. get ( i) {
49+ // yeah this is quadratic, but trait hierarchies should be flat
50+ // enough that this doesn't matter
51+ direct_super_traits ( db, t, |tt| {
52+ if !result. contains ( & tt) {
53+ result. push ( tt) ;
54+ }
55+ } ) ;
56+ i += 1 ;
57+ }
58+ result
59+ }
60+
61+ /// Given a trait ref (`Self: Trait`), builds all the implied trait refs for
62+ /// super traits. The original trait ref will be included. So the difference to
63+ /// `all_super_traits` is that we keep track of type parameters; for example if
64+ /// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
65+ /// `Self: OtherTrait<i32>`.
66+ pub ( super ) fn all_super_trait_refs < T > (
67+ db : & dyn HirDatabase ,
68+ trait_ref : TraitRef ,
69+ cb : impl FnMut ( TraitRef ) -> Option < T > ,
70+ ) -> Option < T > {
71+ let seen = iter:: once ( trait_ref. trait_id ) . collect ( ) ;
72+ let mut stack = Vec :: new ( ) ;
73+ stack. push ( trait_ref) ;
74+ SuperTraits { db, seen, stack } . find_map ( cb)
75+ }
76+
77+ struct SuperTraits < ' a > {
78+ db : & ' a dyn HirDatabase ,
79+ stack : Vec < TraitRef > ,
80+ seen : FxHashSet < ChalkTraitId > ,
81+ }
82+
83+ impl < ' a > SuperTraits < ' a > {
84+ fn elaborate ( & mut self , trait_ref : & TraitRef ) {
85+ direct_super_trait_refs ( self . db , trait_ref, |trait_ref| {
86+ if !self . seen . contains ( & trait_ref. trait_id ) {
87+ self . stack . push ( trait_ref) ;
88+ }
89+ } ) ;
90+ }
91+ }
92+
93+ impl < ' a > Iterator for SuperTraits < ' a > {
94+ type Item = TraitRef ;
95+
96+ fn next ( & mut self ) -> Option < Self :: Item > {
97+ if let Some ( next) = self . stack . pop ( ) {
98+ self . elaborate ( & next) ;
99+ Some ( next)
100+ } else {
101+ None
102+ }
103+ }
104+ }
105+
106+ fn direct_super_traits ( db : & dyn DefDatabase , trait_ : TraitId , cb : impl FnMut ( TraitId ) ) {
42107 let resolver = trait_. resolver ( db) ;
43- // returning the iterator directly doesn't easily work because of
44- // lifetime problems, but since there usually shouldn't be more than a
45- // few direct traits this should be fine (we could even use some kind of
46- // SmallVec if performance is a concern)
47108 let generic_params = db. generic_params ( trait_. into ( ) ) ;
48109 let trait_self = generic_params. find_trait_self_param ( ) ;
49110 generic_params
@@ -73,18 +134,14 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[Trait
73134 Some ( TypeNs :: TraitId ( t) ) => Some ( t) ,
74135 _ => None ,
75136 } )
76- . collect ( )
137+ . for_each ( cb ) ;
77138}
78139
79- fn direct_super_trait_refs ( db : & dyn HirDatabase , trait_ref : & TraitRef ) -> Vec < TraitRef > {
80- // returning the iterator directly doesn't easily work because of
81- // lifetime problems, but since there usually shouldn't be more than a
82- // few direct traits this should be fine (we could even use some kind of
83- // SmallVec if performance is a concern)
140+ fn direct_super_trait_refs ( db : & dyn HirDatabase , trait_ref : & TraitRef , cb : impl FnMut ( TraitRef ) ) {
84141 let generic_params = db. generic_params ( trait_ref. hir_trait_id ( ) . into ( ) ) ;
85142 let trait_self = match generic_params. find_trait_self_param ( ) {
86143 Some ( p) => TypeOrConstParamId { parent : trait_ref. hir_trait_id ( ) . into ( ) , local_id : p } ,
87- None => return Vec :: new ( ) ,
144+ None => return ,
88145 } ;
89146 db. generic_predicates_for_param ( trait_self. parent , trait_self, None )
90147 . iter ( )
@@ -100,72 +157,15 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
100157 } )
101158 } )
102159 . map ( |pred| pred. substitute ( Interner , & trait_ref. substitution ) )
103- . collect ( )
104- }
105-
106- /// Returns an iterator over the whole super trait hierarchy (including the
107- /// trait itself).
108- pub fn all_super_traits ( db : & dyn DefDatabase , trait_ : TraitId ) -> SmallVec < [ TraitId ; 4 ] > {
109- // we need to take care a bit here to avoid infinite loops in case of cycles
110- // (i.e. if we have `trait A: B; trait B: A;`)
111-
112- let mut result = smallvec ! [ trait_] ;
113- let mut i = 0 ;
114- while let Some ( & t) = result. get ( i) {
115- // yeah this is quadratic, but trait hierarchies should be flat
116- // enough that this doesn't matter
117- for tt in direct_super_traits ( db, t) {
118- if !result. contains ( & tt) {
119- result. push ( tt) ;
120- }
121- }
122- i += 1 ;
123- }
124- result
125- }
126-
127- /// Given a trait ref (`Self: Trait`), builds all the implied trait refs for
128- /// super traits. The original trait ref will be included. So the difference to
129- /// `all_super_traits` is that we keep track of type parameters; for example if
130- /// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
131- /// `Self: OtherTrait<i32>`.
132- pub ( super ) fn all_super_trait_refs ( db : & dyn HirDatabase , trait_ref : TraitRef ) -> SuperTraits < ' _ > {
133- SuperTraits { db, seen : iter:: once ( trait_ref. trait_id ) . collect ( ) , stack : vec ! [ trait_ref] }
134- }
135-
136- pub ( super ) struct SuperTraits < ' a > {
137- db : & ' a dyn HirDatabase ,
138- stack : Vec < TraitRef > ,
139- seen : FxHashSet < ChalkTraitId > ,
140- }
141-
142- impl < ' a > SuperTraits < ' a > {
143- fn elaborate ( & mut self , trait_ref : & TraitRef ) {
144- let mut trait_refs = direct_super_trait_refs ( self . db , trait_ref) ;
145- trait_refs. retain ( |tr| !self . seen . contains ( & tr. trait_id ) ) ;
146- self . stack . extend ( trait_refs) ;
147- }
148- }
149-
150- impl < ' a > Iterator for SuperTraits < ' a > {
151- type Item = TraitRef ;
152-
153- fn next ( & mut self ) -> Option < Self :: Item > {
154- if let Some ( next) = self . stack . pop ( ) {
155- self . elaborate ( & next) ;
156- Some ( next)
157- } else {
158- None
159- }
160- }
160+ . for_each ( cb) ;
161161}
162162
163163pub ( super ) fn associated_type_by_name_including_super_traits (
164164 db : & dyn HirDatabase ,
165165 trait_ref : TraitRef ,
166166 name : & Name ,
167167) -> Option < ( TraitRef , TypeAliasId ) > {
168- all_super_trait_refs ( db, trait_ref) . find_map ( |t| {
168+ all_super_trait_refs ( db, trait_ref, |t| {
169169 let assoc_type = db. trait_data ( t. hir_trait_id ( ) ) . associated_type_by_name ( name) ?;
170170 Some ( ( t, assoc_type) )
171171 } )
@@ -238,15 +238,18 @@ impl Generics {
238238
239239 /// (parent total, self param, type param list, const param list, impl trait)
240240 pub ( crate ) fn provenance_split ( & self ) -> ( usize , usize , usize , usize , usize ) {
241- let ty_iter = || self . params . iter ( ) . filter_map ( |x| x. 1 . type_param ( ) ) ;
242-
243- let self_params =
244- ty_iter ( ) . filter ( |p| p. provenance == TypeParamProvenance :: TraitSelf ) . count ( ) ;
245- let type_params =
246- ty_iter ( ) . filter ( |p| p. provenance == TypeParamProvenance :: TypeParamList ) . count ( ) ;
247- let impl_trait_params =
248- ty_iter ( ) . filter ( |p| p. provenance == TypeParamProvenance :: ArgumentImplTrait ) . count ( ) ;
249- let const_params = self . params . iter ( ) . filter_map ( |x| x. 1 . const_param ( ) ) . count ( ) ;
241+ let mut self_params = 0 ;
242+ let mut type_params = 0 ;
243+ let mut impl_trait_params = 0 ;
244+ let mut const_params = 0 ;
245+ self . params . iter ( ) . for_each ( |( _, data) | match data {
246+ TypeOrConstParamData :: TypeParamData ( p) => match p. provenance {
247+ TypeParamProvenance :: TypeParamList => type_params += 1 ,
248+ TypeParamProvenance :: TraitSelf => self_params += 1 ,
249+ TypeParamProvenance :: ArgumentImplTrait => impl_trait_params += 1 ,
250+ } ,
251+ TypeOrConstParamData :: ConstParamData ( _) => const_params += 1 ,
252+ } ) ;
250253
251254 let parent_len = self . parent_generics ( ) . map_or ( 0 , Generics :: len) ;
252255 ( parent_len, self_params, type_params, const_params, impl_trait_params)
0 commit comments