@@ -236,11 +236,24 @@ enum BuiltinBoundConditions<'tcx> {
236236 AmbiguousBuiltin
237237}
238238
239- #[ derive( Debug ) ]
240- enum EvaluationResult < ' tcx > {
239+ #[ derive( Copy , Clone , Debug , PartialOrd , Ord , PartialEq , Eq ) ]
240+ /// The result of trait evaluation. The order is important
241+ /// here as the evaluation of a list is the maximum of the
242+ /// evaluations.
243+ enum EvaluationResult {
244+ /// Evaluation successful
241245 EvaluatedToOk ,
246+ /// Evaluation failed because of recursion - treated as ambiguous
247+ EvaluatedToUnknown ,
248+ /// Evaluation is known to be ambiguous
242249 EvaluatedToAmbig ,
243- EvaluatedToErr ( SelectionError < ' tcx > ) ,
250+ /// Evaluation failed
251+ EvaluatedToErr ,
252+ }
253+
254+ #[ derive( Clone ) ]
255+ pub struct EvaluationCache < ' tcx > {
256+ hashmap : RefCell < FnvHashMap < ty:: PolyTraitRef < ' tcx > , EvaluationResult > >
244257}
245258
246259impl < ' cx , ' tcx > SelectionContext < ' cx , ' tcx > {
@@ -381,6 +394,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
381394 // The result is "true" if the obligation *may* hold and "false" if
382395 // we can be sure it does not.
383396
397+
384398 /// Evaluates whether the obligation `obligation` can be satisfied (by any means).
385399 pub fn evaluate_obligation ( & mut self ,
386400 obligation : & PredicateObligation < ' tcx > )
@@ -393,41 +407,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
393407 . may_apply ( )
394408 }
395409
396- fn evaluate_builtin_bound_recursively < ' o > ( & mut self ,
397- bound : ty:: BuiltinBound ,
398- previous_stack : & TraitObligationStack < ' o , ' tcx > ,
399- ty : Ty < ' tcx > )
400- -> EvaluationResult < ' tcx >
401- {
402- let obligation =
403- util:: predicate_for_builtin_bound (
404- self . tcx ( ) ,
405- previous_stack. obligation . cause . clone ( ) ,
406- bound,
407- previous_stack. obligation . recursion_depth + 1 ,
408- ty) ;
409-
410- match obligation {
411- Ok ( obligation) => {
412- self . evaluate_predicate_recursively ( previous_stack. list ( ) , & obligation)
413- }
414- Err ( ErrorReported ) => {
415- EvaluatedToOk
416- }
417- }
418- }
419-
420410 fn evaluate_predicates_recursively < ' a , ' o , I > ( & mut self ,
421411 stack : TraitObligationStackList < ' o , ' tcx > ,
422412 predicates : I )
423- -> EvaluationResult < ' tcx >
413+ -> EvaluationResult
424414 where I : Iterator < Item =& ' a PredicateObligation < ' tcx > > , ' tcx : ' a
425415 {
426416 let mut result = EvaluatedToOk ;
427417 for obligation in predicates {
428418 match self . evaluate_predicate_recursively ( stack, obligation) {
429- EvaluatedToErr ( e ) => { return EvaluatedToErr ( e ) ; }
419+ EvaluatedToErr => { return EvaluatedToErr ; }
430420 EvaluatedToAmbig => { result = EvaluatedToAmbig ; }
421+ EvaluatedToUnknown => {
422+ if result < EvaluatedToUnknown {
423+ result = EvaluatedToUnknown ;
424+ }
425+ }
431426 EvaluatedToOk => { }
432427 }
433428 }
@@ -437,7 +432,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
437432 fn evaluate_predicate_recursively < ' o > ( & mut self ,
438433 previous_stack : TraitObligationStackList < ' o , ' tcx > ,
439434 obligation : & PredicateObligation < ' tcx > )
440- -> EvaluationResult < ' tcx >
435+ -> EvaluationResult
441436 {
442437 debug ! ( "evaluate_predicate_recursively({:?})" ,
443438 obligation) ;
@@ -464,7 +459,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
464459 } ) ;
465460 match result {
466461 Ok ( ( ) ) => EvaluatedToOk ,
467- Err ( _) => EvaluatedToErr ( Unimplemented ) ,
462+ Err ( _) => EvaluatedToErr
468463 }
469464 }
470465
@@ -489,7 +484,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
489484 if object_safety:: is_object_safe ( self . tcx ( ) , trait_def_id) {
490485 EvaluatedToOk
491486 } else {
492- EvaluatedToErr ( Unimplemented )
487+ EvaluatedToErr
493488 }
494489 }
495490
@@ -505,7 +500,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
505500 EvaluatedToAmbig
506501 }
507502 Err ( _) => {
508- EvaluatedToErr ( Unimplemented )
503+ EvaluatedToErr
509504 }
510505 }
511506 } )
@@ -516,22 +511,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
516511 fn evaluate_obligation_recursively < ' o > ( & mut self ,
517512 previous_stack : TraitObligationStackList < ' o , ' tcx > ,
518513 obligation : & TraitObligation < ' tcx > )
519- -> EvaluationResult < ' tcx >
514+ -> EvaluationResult
520515 {
521516 debug ! ( "evaluate_obligation_recursively({:?})" ,
522517 obligation) ;
523518
524519 let stack = self . push_stack ( previous_stack, obligation) ;
520+ let fresh_trait_ref = stack. fresh_trait_ref ;
521+ if let Some ( result) = self . check_evaluation_cache ( fresh_trait_ref) {
522+ debug ! ( "CACHE HIT: EVAL({:?})={:?}" ,
523+ fresh_trait_ref,
524+ result) ;
525+ return result;
526+ }
525527
526528 let result = self . evaluate_stack ( & stack) ;
527529
528- debug ! ( "result: {:?}" , result) ;
530+ debug ! ( "CACHE MISS: EVAL({:?})={:?}" ,
531+ fresh_trait_ref,
532+ result) ;
533+ self . insert_evaluation_cache ( fresh_trait_ref, result) ;
534+
529535 result
530536 }
531537
532538 fn evaluate_stack < ' o > ( & mut self ,
533539 stack : & TraitObligationStack < ' o , ' tcx > )
534- -> EvaluationResult < ' tcx >
540+ -> EvaluationResult
535541 {
536542 // In intercrate mode, whenever any of the types are unbound,
537543 // there can always be an impl. Even if there are no impls in
@@ -559,16 +565,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
559565 // precise still.
560566 let input_types = stack. fresh_trait_ref . 0 . input_types ( ) ;
561567 let unbound_input_types = input_types. iter ( ) . any ( |ty| ty. is_fresh ( ) ) ;
562- if
563- unbound_input_types &&
564- ( self . intercrate ||
568+ if unbound_input_types && self . intercrate {
569+ debug ! ( "evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous" ,
570+ stack. fresh_trait_ref) ;
571+ return EvaluatedToAmbig ;
572+ }
573+ if unbound_input_types &&
565574 stack. iter ( ) . skip ( 1 ) . any (
566575 |prev| self . match_fresh_trait_refs ( & stack. fresh_trait_ref ,
567- & prev. fresh_trait_ref ) ) )
576+ & prev. fresh_trait_ref ) )
568577 {
569- debug ! ( "evaluate_stack({:?}) --> unbound argument, recursion --> ambiguous " ,
578+ debug ! ( "evaluate_stack({:?}) --> unbound argument, recursive --> giving up " ,
570579 stack. fresh_trait_ref) ;
571- return EvaluatedToAmbig ;
580+ return EvaluatedToUnknown ;
572581 }
573582
574583 // If there is any previous entry on the stack that precisely
@@ -603,7 +612,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
603612 match self . candidate_from_obligation ( stack) {
604613 Ok ( Some ( c) ) => self . winnow_candidate ( stack, & c) ,
605614 Ok ( None ) => EvaluatedToAmbig ,
606- Err ( e ) => EvaluatedToErr ( e ) ,
615+ Err ( .. ) => EvaluatedToErr
607616 }
608617 }
609618
@@ -637,6 +646,34 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
637646 } )
638647 }
639648
649+ fn pick_evaluation_cache ( & self ) -> & EvaluationCache < ' tcx > {
650+ & self . param_env ( ) . evaluation_cache
651+ }
652+
653+ fn check_evaluation_cache ( & self , trait_ref : ty:: PolyTraitRef < ' tcx > )
654+ -> Option < EvaluationResult >
655+ {
656+ let cache = self . pick_evaluation_cache ( ) ;
657+ cache. hashmap . borrow ( ) . get ( & trait_ref) . cloned ( )
658+ }
659+
660+ fn insert_evaluation_cache ( & mut self ,
661+ trait_ref : ty:: PolyTraitRef < ' tcx > ,
662+ result : EvaluationResult )
663+ {
664+ // Avoid caching results that depend on more than just the trait-ref:
665+ // The stack can create EvaluatedToUnknown, and closure signatures
666+ // being yet uninferred can create "spurious" EvaluatedToAmbig.
667+ if result == EvaluatedToUnknown ||
668+ ( result == EvaluatedToAmbig && trait_ref. has_closure_types ( ) )
669+ {
670+ return ;
671+ }
672+
673+ let cache = self . pick_evaluation_cache ( ) ;
674+ cache. hashmap . borrow_mut ( ) . insert ( trait_ref, result) ;
675+ }
676+
640677 ///////////////////////////////////////////////////////////////////////////
641678 // CANDIDATE ASSEMBLY
642679 //
@@ -669,7 +706,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
669706
670707 match self . check_candidate_cache ( & cache_fresh_trait_pred) {
671708 Some ( c) => {
672- debug ! ( "CACHE HIT: cache_fresh_trait_pred= {:?}, candidate ={:?}" ,
709+ debug ! ( "CACHE HIT: SELECT( {:?}) ={:?}" ,
673710 cache_fresh_trait_pred,
674711 c) ;
675712 return c;
@@ -681,7 +718,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
681718 let candidate = self . candidate_from_obligation_no_cache ( stack) ;
682719
683720 if self . should_update_candidate_cache ( & cache_fresh_trait_pred, & candidate) {
684- debug ! ( "CACHE MISS: cache_fresh_trait_pred= {:?}, candidate ={:?}" ,
721+ debug ! ( "CACHE MISS: SELECT( {:?}) ={:?}" ,
685722 cache_fresh_trait_pred, candidate) ;
686723 self . insert_candidate_cache ( cache_fresh_trait_pred, candidate. clone ( ) ) ;
687724 }
@@ -1138,15 +1175,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11381175 fn evaluate_where_clause < ' o > ( & mut self ,
11391176 stack : & TraitObligationStack < ' o , ' tcx > ,
11401177 where_clause_trait_ref : ty:: PolyTraitRef < ' tcx > )
1141- -> EvaluationResult < ' tcx >
1178+ -> EvaluationResult
11421179 {
11431180 self . infcx ( ) . probe ( move |_| {
11441181 match self . match_where_clause_trait_ref ( stack. obligation , where_clause_trait_ref) {
11451182 Ok ( obligations) => {
11461183 self . evaluate_predicates_recursively ( stack. list ( ) , obligations. iter ( ) )
11471184 }
11481185 Err ( ( ) ) => {
1149- EvaluatedToErr ( Unimplemented )
1186+ EvaluatedToErr
11501187 }
11511188 }
11521189 } )
@@ -1492,15 +1529,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
14921529 fn winnow_candidate < ' o > ( & mut self ,
14931530 stack : & TraitObligationStack < ' o , ' tcx > ,
14941531 candidate : & SelectionCandidate < ' tcx > )
1495- -> EvaluationResult < ' tcx >
1532+ -> EvaluationResult
14961533 {
14971534 debug ! ( "winnow_candidate: candidate={:?}" , candidate) ;
14981535 let result = self . infcx . probe ( |_| {
14991536 let candidate = ( * candidate) . clone ( ) ;
15001537 match self . confirm_candidate ( stack. obligation , candidate) {
15011538 Ok ( selection) => self . winnow_selection ( stack. list ( ) ,
15021539 selection) ,
1503- Err ( error ) => EvaluatedToErr ( error ) ,
1540+ Err ( .. ) => EvaluatedToErr
15041541 }
15051542 } ) ;
15061543 debug ! ( "winnow_candidate depth={} result={:?}" ,
@@ -1511,7 +1548,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15111548 fn winnow_selection < ' o > ( & mut self ,
15121549 stack : TraitObligationStackList < ' o , ' tcx > ,
15131550 selection : Selection < ' tcx > )
1514- -> EvaluationResult < ' tcx >
1551+ -> EvaluationResult
15151552 {
15161553 self . evaluate_predicates_recursively ( stack,
15171554 selection. nested_obligations ( ) . iter ( ) )
@@ -2956,6 +2993,14 @@ impl<'tcx> SelectionCache<'tcx> {
29562993 }
29572994}
29582995
2996+ impl < ' tcx > EvaluationCache < ' tcx > {
2997+ pub fn new ( ) -> EvaluationCache < ' tcx > {
2998+ EvaluationCache {
2999+ hashmap : RefCell :: new ( FnvHashMap ( ) )
3000+ }
3001+ }
3002+ }
3003+
29593004impl < ' o , ' tcx > TraitObligationStack < ' o , ' tcx > {
29603005 fn list ( & ' o self ) -> TraitObligationStackList < ' o , ' tcx > {
29613006 TraitObligationStackList :: with ( self )
@@ -3001,17 +3046,14 @@ impl<'o,'tcx> fmt::Debug for TraitObligationStack<'o,'tcx> {
30013046 }
30023047}
30033048
3004- impl < ' tcx > EvaluationResult < ' tcx > {
3049+ impl EvaluationResult {
30053050 fn may_apply ( & self ) -> bool {
30063051 match * self {
30073052 EvaluatedToOk |
30083053 EvaluatedToAmbig |
3009- EvaluatedToErr ( OutputTypeParameterMismatch ( ..) ) |
3010- EvaluatedToErr ( TraitNotObjectSafe ( _) ) =>
3011- true ,
3054+ EvaluatedToUnknown => true ,
30123055
3013- EvaluatedToErr ( Unimplemented ) =>
3014- false ,
3056+ EvaluatedToErr => false
30153057 }
30163058 }
30173059}
0 commit comments