8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
+ use hir;
11
12
use hir:: def_id:: DefId ;
12
13
use hir:: map:: DefPathHash ;
13
14
use traits:: specialization_graph;
14
15
use ty:: fast_reject;
15
16
use ty:: fold:: TypeFoldable ;
16
17
use ty:: { Ty , TyCtxt } ;
18
+
19
+ use rustc_data_structures:: fx:: FxHashMap ;
20
+
17
21
use std:: rc:: Rc ;
18
- use hir;
19
22
20
23
/// A trait's definition with type information.
21
24
pub struct TraitDef {
@@ -36,60 +39,12 @@ pub struct TraitDef {
36
39
pub def_path_hash : DefPathHash ,
37
40
}
38
41
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 ) ]
44
42
pub 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 > > ,
47
46
}
48
47
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
-
93
48
impl < ' a , ' gcx , ' tcx > TraitDef {
94
49
pub fn new ( def_id : DefId ,
95
50
unsafety : hir:: Unsafety ,
@@ -111,20 +66,36 @@ impl<'a, 'gcx, 'tcx> TraitDef {
111
66
-> specialization_graph:: Ancestors {
112
67
specialization_graph:: ancestors ( tcx, self . def_id , of_impl)
113
68
}
69
+ }
114
70
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 ( ) {
117
76
f ( impl_def_id) ;
118
77
}
78
+
79
+ for v in impls. non_blanket_impls . values ( ) {
80
+ for & impl_def_id in v {
81
+ f ( impl_def_id) ;
82
+ }
83
+ }
119
84
}
120
85
121
86
/// Iterate over every impl that could possibly match the
122
87
/// 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 ,
125
90
self_ty : Ty < ' tcx > ,
126
91
mut f : F )
127
92
{
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
+
128
99
// simplify_type(.., false) basically replaces type parameters and
129
100
// projections with infer-variables. This is, of course, done on
130
101
// the impl trait-ref when it is instantiated, but not on the
@@ -137,23 +108,39 @@ impl<'a, 'gcx, 'tcx> TraitDef {
137
108
// replace `S` with anything - this impl of course can't be
138
109
// selected, and as there are hundreds of similar impls,
139
110
// 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
- } ;
146
111
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
+ }
149
136
}
150
137
}
151
138
}
152
139
153
140
// Query provider for `trait_impls_of`.
154
141
pub ( super ) fn trait_impls_of_provider < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
155
142
trait_id : DefId )
156
- -> TraitImpls {
143
+ -> Rc < TraitImpls > {
157
144
let remote_impls = if trait_id. is_local ( ) {
158
145
// Traits defined in the current crate can't have impls in upstream
159
146
// 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>,
163
150
} ;
164
151
165
152
let mut blanket_impls = Vec :: new ( ) ;
166
- let mut non_blanket_impls = Vec :: new ( ) ;
153
+ let mut non_blanket_impls = FxHashMap ( ) ;
167
154
168
155
let local_impls = tcx. hir
169
156
. trait_impls ( trait_id)
@@ -176,47 +163,20 @@ pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
176
163
continue
177
164
}
178
165
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) ;
181
173
} else {
182
174
blanket_impls. push ( impl_def_id) ;
183
175
}
184
176
}
185
177
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
+ } )
222
182
}
0 commit comments