11use crate :: traits:: specialization_graph;
22use crate :: ty:: fast_reject:: { self , SimplifiedType , TreatParams , TreatProjections } ;
33use crate :: ty:: visit:: TypeVisitableExt ;
4- use crate :: ty:: { Ident , Ty , TyCtxt } ;
4+ use crate :: ty:: { Ident , Ty , TyCtxt , TyKind } ;
55use hir:: def_id:: LOCAL_CRATE ;
66use rustc_hir as hir;
77use rustc_hir:: def_id:: DefId ;
@@ -77,6 +77,10 @@ pub struct TraitImpls {
7777 blanket_impls : Vec < DefId > ,
7878 /// Impls indexed by their simplified self type, for fast lookup.
7979 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 > > ,
8084}
8185
8286impl TraitImpls {
@@ -144,14 +148,10 @@ impl<'tcx> TyCtxt<'tcx> {
144148 //
145149 // If we want to be faster, we could have separate queries for
146150 // 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- }
152151
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`).
155155 let treat_params = match treat_projections {
156156 TreatProjections :: NextSolverLookup => TreatParams :: NextSolverLookup ,
157157 TreatProjections :: ForLookup => TreatParams :: ForLookup ,
@@ -161,13 +161,36 @@ impl<'tcx> TyCtxt<'tcx> {
161161 // `T: Clone` this is incredibly useful as we would otherwise look at all the impls
162162 // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
163163 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+
164170 if let Some ( impls) = impls. non_blanket_impls . get ( & simp) {
165171 for & impl_def_id in impls {
166172 f ( impl_def_id) ;
167173 }
168174 }
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+ }
169192 } 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 ) {
171194 f ( impl_def_id) ;
172195 }
173196 }
@@ -193,9 +216,14 @@ impl<'tcx> TyCtxt<'tcx> {
193216 ///
194217 /// `trait_def_id` MUST BE the `DefId` of a trait.
195218 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 ( )
199227 }
200228}
201229
@@ -231,6 +259,17 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
231259 continue ;
232260 }
233261
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+
234273 if let Some ( simplified_self_ty) =
235274 fast_reject:: simplify_type ( tcx, impl_self_ty, TreatParams :: AsCandidateKey )
236275 {
0 commit comments