88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11+ use hir;
1112use hir:: def_id:: DefId ;
1213use hir:: map:: DefPathHash ;
1314use traits:: specialization_graph;
1415use ty:: fast_reject;
1516use ty:: fold:: TypeFoldable ;
1617use ty:: { Ty , TyCtxt } ;
18+
19+ use rustc_data_structures:: fx:: FxHashMap ;
20+
1721use std:: rc:: Rc ;
18- use hir;
1922
2023/// A trait's definition with type information.
2124pub struct TraitDef {
@@ -36,60 +39,12 @@ pub struct TraitDef {
3639 pub def_path_hash : DefPathHash ,
3740}
3841
39- // We don't store the list of impls in a flat list because each cached list of
40- // `relevant_impls_for` we would then duplicate all blanket impls. By keeping
41- // blanket and non-blanket impls separate, we can share the list of blanket
42- // impls.
43- #[ derive( Clone ) ]
4442pub struct TraitImpls {
45- blanket_impls : Rc < Vec < DefId > > ,
46- non_blanket_impls : Rc < Vec < DefId > > ,
43+ blanket_impls : Vec < DefId > ,
44+ /// Impls indexed by their simplified self-type, for fast lookup.
45+ non_blanket_impls : FxHashMap < fast_reject:: SimplifiedType , Vec < DefId > > ,
4746}
4847
49- impl TraitImpls {
50- pub fn iter ( & self ) -> TraitImplsIter {
51- TraitImplsIter {
52- blanket_impls : self . blanket_impls . clone ( ) ,
53- non_blanket_impls : self . non_blanket_impls . clone ( ) ,
54- index : 0
55- }
56- }
57- }
58-
59- #[ derive( Clone ) ]
60- pub struct TraitImplsIter {
61- blanket_impls : Rc < Vec < DefId > > ,
62- non_blanket_impls : Rc < Vec < DefId > > ,
63- index : usize ,
64- }
65-
66- impl Iterator for TraitImplsIter {
67- type Item = DefId ;
68-
69- fn next ( & mut self ) -> Option < DefId > {
70- if self . index < self . blanket_impls . len ( ) {
71- let bi_index = self . index ;
72- self . index += 1 ;
73- Some ( self . blanket_impls [ bi_index] )
74- } else {
75- let nbi_index = self . index - self . blanket_impls . len ( ) ;
76- if nbi_index < self . non_blanket_impls . len ( ) {
77- self . index += 1 ;
78- Some ( self . non_blanket_impls [ nbi_index] )
79- } else {
80- None
81- }
82- }
83- }
84-
85- fn size_hint ( & self ) -> ( usize , Option < usize > ) {
86- let items_left = ( self . blanket_impls . len ( ) + self . non_blanket_impls . len ( ) ) - self . index ;
87- ( items_left, Some ( items_left) )
88- }
89- }
90-
91- impl ExactSizeIterator for TraitImplsIter { }
92-
9348impl < ' a , ' gcx , ' tcx > TraitDef {
9449 pub fn new ( def_id : DefId ,
9550 unsafety : hir:: Unsafety ,
@@ -111,20 +66,36 @@ impl<'a, 'gcx, 'tcx> TraitDef {
11166 -> specialization_graph:: Ancestors {
11267 specialization_graph:: ancestors ( tcx, self . def_id , of_impl)
11368 }
69+ }
11470
115- pub fn for_each_impl < F : FnMut ( DefId ) > ( & self , tcx : TyCtxt < ' a , ' gcx , ' tcx > , mut f : F ) {
116- for impl_def_id in tcx. trait_impls_of ( self . def_id ) . iter ( ) {
71+ impl < ' a , ' gcx , ' tcx > TyCtxt < ' a , ' gcx , ' tcx > {
72+ pub fn for_each_impl < F : FnMut ( DefId ) > ( self , def_id : DefId , mut f : F ) {
73+ let impls = self . trait_impls_of ( def_id) ;
74+
75+ for & impl_def_id in impls. blanket_impls . iter ( ) {
11776 f ( impl_def_id) ;
11877 }
78+
79+ for v in impls. non_blanket_impls . values ( ) {
80+ for & impl_def_id in v {
81+ f ( impl_def_id) ;
82+ }
83+ }
11984 }
12085
12186 /// Iterate over every impl that could possibly match the
12287 /// self-type `self_ty`.
123- pub fn for_each_relevant_impl < F : FnMut ( DefId ) > ( & self ,
124- tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
88+ pub fn for_each_relevant_impl < F : FnMut ( DefId ) > ( self ,
89+ def_id : DefId ,
12590 self_ty : Ty < ' tcx > ,
12691 mut f : F )
12792 {
93+ let impls = self . trait_impls_of ( def_id) ;
94+
95+ for & impl_def_id in impls. blanket_impls . iter ( ) {
96+ f ( impl_def_id) ;
97+ }
98+
12899 // simplify_type(.., false) basically replaces type parameters and
129100 // projections with infer-variables. This is, of course, done on
130101 // the impl trait-ref when it is instantiated, but not on the
@@ -137,23 +108,39 @@ impl<'a, 'gcx, 'tcx> TraitDef {
137108 // replace `S` with anything - this impl of course can't be
138109 // selected, and as there are hundreds of similar impls,
139110 // considering them would significantly harm performance.
140- let relevant_impls = if let Some ( simplified_self_ty) =
141- fast_reject:: simplify_type ( tcx, self_ty, true ) {
142- tcx. relevant_trait_impls_for ( ( self . def_id , simplified_self_ty) )
143- } else {
144- tcx. trait_impls_of ( self . def_id )
145- } ;
146111
147- for impl_def_id in relevant_impls. iter ( ) {
148- f ( impl_def_id) ;
112+ // This depends on the set of all impls for the trait. That is
113+ // unfortunate. When we get red-green recompilation, we would like
114+ // to have a way of knowing whether the set of relevant impls
115+ // changed. The most naive
116+ // way would be to compute the Vec of relevant impls and see whether
117+ // it differs between compilations. That shouldn't be too slow by
118+ // itself - we do quite a bit of work for each relevant impl anyway.
119+ //
120+ // If we want to be faster, we could have separate queries for
121+ // blanket and non-blanket impls, and compare them separately.
122+ //
123+ // I think we'll cross that bridge when we get to it.
124+ if let Some ( simp) = fast_reject:: simplify_type ( self , self_ty, true ) {
125+ if let Some ( impls) = impls. non_blanket_impls . get ( & simp) {
126+ for & impl_def_id in impls {
127+ f ( impl_def_id) ;
128+ }
129+ }
130+ } else {
131+ for v in impls. non_blanket_impls . values ( ) {
132+ for & impl_def_id in v {
133+ f ( impl_def_id) ;
134+ }
135+ }
149136 }
150137 }
151138}
152139
153140// Query provider for `trait_impls_of`.
154141pub ( super ) fn trait_impls_of_provider < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
155142 trait_id : DefId )
156- -> TraitImpls {
143+ -> Rc < TraitImpls > {
157144 let remote_impls = if trait_id. is_local ( ) {
158145 // Traits defined in the current crate can't have impls in upstream
159146 // crates, so we don't bother querying the cstore.
@@ -163,7 +150,7 @@ pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
163150 } ;
164151
165152 let mut blanket_impls = Vec :: new ( ) ;
166- let mut non_blanket_impls = Vec :: new ( ) ;
153+ let mut non_blanket_impls = FxHashMap ( ) ;
167154
168155 let local_impls = tcx. hir
169156 . trait_impls ( trait_id)
@@ -176,47 +163,20 @@ pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
176163 continue
177164 }
178165
179- if fast_reject:: simplify_type ( tcx, impl_self_ty, false ) . is_some ( ) {
180- non_blanket_impls. push ( impl_def_id) ;
166+ if let Some ( simplified_self_ty) =
167+ fast_reject:: simplify_type ( tcx, impl_self_ty, false )
168+ {
169+ non_blanket_impls
170+ . entry ( simplified_self_ty)
171+ . or_insert ( vec ! [ ] )
172+ . push ( impl_def_id) ;
181173 } else {
182174 blanket_impls. push ( impl_def_id) ;
183175 }
184176 }
185177
186- TraitImpls {
187- blanket_impls : Rc :: new ( blanket_impls) ,
188- non_blanket_impls : Rc :: new ( non_blanket_impls) ,
189- }
190- }
191-
192- // Query provider for `relevant_trait_impls_for`.
193- pub ( super ) fn relevant_trait_impls_provider < ' a , ' tcx > (
194- tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
195- ( trait_id, self_ty) : ( DefId , fast_reject:: SimplifiedType ) )
196- -> TraitImpls
197- {
198- let all_trait_impls = tcx. trait_impls_of ( trait_id) ;
199-
200- let relevant: Vec < DefId > = all_trait_impls
201- . non_blanket_impls
202- . iter ( )
203- . cloned ( )
204- . filter ( |& impl_def_id| {
205- let impl_self_ty = tcx. type_of ( impl_def_id) ;
206- let impl_simple_self_ty = fast_reject:: simplify_type ( tcx,
207- impl_self_ty,
208- false ) . unwrap ( ) ;
209- impl_simple_self_ty == self_ty
210- } )
211- . collect ( ) ;
212-
213- if all_trait_impls. non_blanket_impls . len ( ) == relevant. len ( ) {
214- // If we didn't filter anything out, re-use the existing vec.
215- all_trait_impls
216- } else {
217- TraitImpls {
218- blanket_impls : all_trait_impls. blanket_impls . clone ( ) ,
219- non_blanket_impls : Rc :: new ( relevant) ,
220- }
221- }
178+ Rc :: new ( TraitImpls {
179+ blanket_impls : blanket_impls,
180+ non_blanket_impls : non_blanket_impls,
181+ } )
222182}
0 commit comments