1
1
use crate :: traits:: specialization_graph;
2
2
use crate :: ty:: fast_reject:: { self , SimplifiedType , TreatParams , TreatProjections } ;
3
3
use crate :: ty:: visit:: TypeVisitableExt ;
4
- use crate :: ty:: { Ident , Ty , TyCtxt } ;
4
+ use crate :: ty:: { Ident , Ty , TyCtxt , TyKind } ;
5
5
use hir:: def_id:: LOCAL_CRATE ;
6
6
use rustc_hir as hir;
7
7
use rustc_hir:: def_id:: DefId ;
@@ -77,6 +77,10 @@ pub struct TraitImpls {
77
77
blanket_impls : Vec < DefId > ,
78
78
/// Impls indexed by their simplified self type, for fast lookup.
79
79
non_blanket_impls : FxIndexMap < SimplifiedType , Vec < DefId > > ,
80
+
81
+ /// Impls for references to simplifiable types, indexed by the referenced simplified type, for
82
+ /// fast lookup.
83
+ impls_for_ref_x : FxIndexMap < SimplifiedType , Vec < DefId > > ,
80
84
}
81
85
82
86
impl TraitImpls {
@@ -144,14 +148,10 @@ impl<'tcx> TyCtxt<'tcx> {
144
148
//
145
149
// If we want to be faster, we could have separate queries for
146
150
// blanket and non-blanket impls, and compare them separately.
147
- let impls = self . trait_impls_of ( trait_def_id) ;
148
-
149
- for & impl_def_id in impls. blanket_impls . iter ( ) {
150
- f ( impl_def_id) ;
151
- }
152
151
153
- // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using
154
- // `TreatParams::AsCandidateKey` while actually adding them.
152
+ // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` and
153
+ // `impls_for_ref_x`, while using `TreatParams::AsCandidateKey` while actually adding them
154
+ // (in `trait_impls_of_provider`).
155
155
let treat_params = match treat_projections {
156
156
TreatProjections :: NextSolverLookup => TreatParams :: NextSolverLookup ,
157
157
TreatProjections :: ForLookup => TreatParams :: ForLookup ,
@@ -161,13 +161,36 @@ impl<'tcx> TyCtxt<'tcx> {
161
161
// `T: Clone` this is incredibly useful as we would otherwise look at all the impls
162
162
// of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
163
163
if let Some ( simp) = fast_reject:: simplify_type ( self , self_ty, treat_params) {
164
+ let impls = self . trait_impls_of ( trait_def_id) ;
165
+
166
+ for & impl_def_id in impls. blanket_impls . iter ( ) {
167
+ f ( impl_def_id) ;
168
+ }
169
+
164
170
if let Some ( impls) = impls. non_blanket_impls . get ( & simp) {
165
171
for & impl_def_id in impls {
166
172
f ( impl_def_id) ;
167
173
}
168
174
}
175
+
176
+ // We separate impls for references to simplifiable types to allow for faster lookups:
177
+ // the set of possibly matching impls is smaller than if we stored them all as
178
+ // `SimplifiedType::RefSimplifiedType`.
179
+ if let TyKind :: Ref ( _, ref_ty, _) = self_ty. kind ( ) {
180
+ if let Some ( ref_simp) = fast_reject:: simplify_type ( self , * ref_ty, treat_params) {
181
+ if let Some ( impls) = impls. impls_for_ref_x . get ( & ref_simp) {
182
+ for & impl_def_id in impls {
183
+ f ( impl_def_id) ;
184
+ }
185
+ }
186
+ } else {
187
+ for & impl_def_id in impls. impls_for_ref_x . values ( ) . flatten ( ) {
188
+ f ( impl_def_id) ;
189
+ }
190
+ }
191
+ }
169
192
} else {
170
- for & impl_def_id in impls . non_blanket_impls . values ( ) . flatten ( ) {
193
+ for impl_def_id in self . all_impls ( trait_def_id ) {
171
194
f ( impl_def_id) ;
172
195
}
173
196
}
@@ -193,9 +216,14 @@ impl<'tcx> TyCtxt<'tcx> {
193
216
///
194
217
/// `trait_def_id` MUST BE the `DefId` of a trait.
195
218
pub fn all_impls ( self , trait_def_id : DefId ) -> impl Iterator < Item = DefId > + ' tcx {
196
- let TraitImpls { blanket_impls, non_blanket_impls } = self . trait_impls_of ( trait_def_id) ;
197
-
198
- blanket_impls. iter ( ) . chain ( non_blanket_impls. iter ( ) . flat_map ( |( _, v) | v) ) . cloned ( )
219
+ let TraitImpls { blanket_impls, non_blanket_impls, impls_for_ref_x } =
220
+ self . trait_impls_of ( trait_def_id) ;
221
+
222
+ blanket_impls
223
+ . iter ( )
224
+ . chain ( non_blanket_impls. iter ( ) . flat_map ( |( _, v) | v) )
225
+ . chain ( impls_for_ref_x. iter ( ) . flat_map ( |( _, v) | v) )
226
+ . copied ( )
199
227
}
200
228
}
201
229
@@ -231,6 +259,17 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
231
259
continue ;
232
260
}
233
261
262
+ // Store impls for references to simplifiable types separately from other impls, for faster
263
+ // lookups.
264
+ if let TyKind :: Ref ( _, ref_ty, _) = impl_self_ty. kind ( ) {
265
+ if let Some ( simplified_ref_ty) =
266
+ fast_reject:: simplify_type ( tcx, * ref_ty, TreatParams :: AsCandidateKey )
267
+ {
268
+ impls. impls_for_ref_x . entry ( simplified_ref_ty) . or_default ( ) . push ( impl_def_id) ;
269
+ continue ;
270
+ }
271
+ }
272
+
234
273
if let Some ( simplified_self_ty) =
235
274
fast_reject:: simplify_type ( tcx, impl_self_ty, TreatParams :: AsCandidateKey )
236
275
{
0 commit comments