2020use super :: { SelectionContext , FulfillmentContext } ;
2121use super :: util:: { fresh_type_vars_for_impl, impl_trait_ref_and_oblig} ;
2222
23+ use rustc_data_structures:: fnv:: FnvHashMap ;
2324use hir:: def_id:: DefId ;
2425use infer:: { InferCtxt , TypeOrigin } ;
2526use middle:: region;
@@ -111,6 +112,10 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
111112pub fn specializes < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
112113 impl1_def_id : DefId ,
113114 impl2_def_id : DefId ) -> bool {
115+ if let Some ( r) = tcx. specializes_cache . borrow ( ) . check ( impl1_def_id, impl2_def_id) {
116+ return r;
117+ }
118+
114119 // The feature gate should prevent introducing new specializations, but not
115120 // taking advantage of upstream ones.
116121 if !tcx. sess . features . borrow ( ) . specialization &&
@@ -146,7 +151,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
146151 . unwrap ( )
147152 . subst ( tcx, & penv. free_substs ) ;
148153
149- tcx. normalizing_infer_ctxt ( ProjectionMode :: Topmost ) . enter ( |mut infcx| {
154+ let result = tcx. normalizing_infer_ctxt ( ProjectionMode :: Topmost ) . enter ( |mut infcx| {
150155 // Normalize the trait reference, adding any obligations
151156 // that arise into the impl1 assumptions.
152157 let Normalized { value : impl1_trait_ref, obligations : normalization_obligations } = {
@@ -167,7 +172,10 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
167172
168173 // Attempt to prove that impl2 applies, given all of the above.
169174 fulfill_implication ( & infcx, impl1_trait_ref, impl2_def_id) . is_ok ( )
170- } )
175+ } ) ;
176+
177+ tcx. specializes_cache . borrow_mut ( ) . insert ( impl1_def_id, impl2_def_id, result) ;
178+ result
171179}
172180
173181/// Attempt to fulfill all obligations of `target_impl` after unification with
@@ -225,3 +233,23 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
225233 }
226234 } )
227235}
236+
237+ pub struct SpecializesCache {
238+ map : FnvHashMap < ( DefId , DefId ) , bool >
239+ }
240+
241+ impl SpecializesCache {
242+ pub fn new ( ) -> Self {
243+ SpecializesCache {
244+ map : FnvHashMap ( )
245+ }
246+ }
247+
248+ pub fn check ( & self , a : DefId , b : DefId ) -> Option < bool > {
249+ self . map . get ( & ( a, b) ) . cloned ( )
250+ }
251+
252+ pub fn insert ( & mut self , a : DefId , b : DefId , result : bool ) {
253+ self . map . insert ( ( a, b) , result) ;
254+ }
255+ }
0 commit comments