@@ -86,9 +86,13 @@ mod graphviz;
8686mod tests;
8787
8888pub trait ForestObligation : Clone + Debug {
89- type Predicate : Clone + hash:: Hash + Eq + Debug ;
89+ type CacheKey : Clone + hash:: Hash + Eq + Debug ;
9090
91- fn as_predicate ( & self ) -> & Self :: Predicate ;
91+ /// Converts this `ForestObligation` suitable for use as a cache key.
92+ /// If two distinct `ForestObligations`s return the same cache key,
93+ /// then it must be sound to use the result of processing one obligation
94+ /// (e.g. success for error) for the other obligation
95+ fn as_cache_key ( & self ) -> Self :: CacheKey ;
9296}
9397
9498pub trait ObligationProcessor {
@@ -138,12 +142,12 @@ pub struct ObligationForest<O: ForestObligation> {
138142 nodes : Vec < Node < O > > ,
139143
140144 /// A cache of predicates that have been successfully completed.
141- done_cache : FxHashSet < O :: Predicate > ,
145+ done_cache : FxHashSet < O :: CacheKey > ,
142146
143147 /// A cache of the nodes in `nodes`, indexed by predicate. Unfortunately,
144148 /// its contents are not guaranteed to match those of `nodes`. See the
145149 /// comments in `process_obligation` for details.
146- active_cache : FxHashMap < O :: Predicate , usize > ,
150+ active_cache : FxHashMap < O :: CacheKey , usize > ,
147151
148152 /// A vector reused in compress(), to avoid allocating new vectors.
149153 node_rewrites : Vec < usize > ,
@@ -157,7 +161,7 @@ pub struct ObligationForest<O: ForestObligation> {
157161 /// See [this][details] for details.
158162 ///
159163 /// [details]: https://github.com/rust-lang/rust/pull/53255#issuecomment-421184780
160- error_cache : FxHashMap < ObligationTreeId , FxHashSet < O :: Predicate > > ,
164+ error_cache : FxHashMap < ObligationTreeId , FxHashSet < O :: CacheKey > > ,
161165}
162166
163167#[ derive( Debug ) ]
@@ -305,11 +309,12 @@ impl<O: ForestObligation> ObligationForest<O> {
305309
306310 // Returns Err(()) if we already know this obligation failed.
307311 fn register_obligation_at ( & mut self , obligation : O , parent : Option < usize > ) -> Result < ( ) , ( ) > {
308- if self . done_cache . contains ( obligation. as_predicate ( ) ) {
312+ if self . done_cache . contains ( & obligation. as_cache_key ( ) ) {
313+ debug ! ( "register_obligation_at: ignoring already done obligation: {:?}" , obligation) ;
309314 return Ok ( ( ) ) ;
310315 }
311316
312- match self . active_cache . entry ( obligation. as_predicate ( ) . clone ( ) ) {
317+ match self . active_cache . entry ( obligation. as_cache_key ( ) . clone ( ) ) {
313318 Entry :: Occupied ( o) => {
314319 let node = & mut self . nodes [ * o. get ( ) ] ;
315320 if let Some ( parent_index) = parent {
@@ -333,7 +338,7 @@ impl<O: ForestObligation> ObligationForest<O> {
333338 && self
334339 . error_cache
335340 . get ( & obligation_tree_id)
336- . map ( |errors| errors. contains ( obligation. as_predicate ( ) ) )
341+ . map ( |errors| errors. contains ( & obligation. as_cache_key ( ) ) )
337342 . unwrap_or ( false ) ;
338343
339344 if already_failed {
@@ -380,7 +385,7 @@ impl<O: ForestObligation> ObligationForest<O> {
380385 self . error_cache
381386 . entry ( node. obligation_tree_id )
382387 . or_default ( )
383- . insert ( node. obligation . as_predicate ( ) . clone ( ) ) ;
388+ . insert ( node. obligation . as_cache_key ( ) . clone ( ) ) ;
384389 }
385390
386391 /// Performs a pass through the obligation list. This must
@@ -618,11 +623,11 @@ impl<O: ForestObligation> ObligationForest<O> {
618623 // `self.nodes`. See the comment in `process_obligation`
619624 // for more details.
620625 if let Some ( ( predicate, _) ) =
621- self . active_cache . remove_entry ( node. obligation . as_predicate ( ) )
626+ self . active_cache . remove_entry ( & node. obligation . as_cache_key ( ) )
622627 {
623628 self . done_cache . insert ( predicate) ;
624629 } else {
625- self . done_cache . insert ( node. obligation . as_predicate ( ) . clone ( ) ) ;
630+ self . done_cache . insert ( node. obligation . as_cache_key ( ) . clone ( ) ) ;
626631 }
627632 if do_completed == DoCompleted :: Yes {
628633 // Extract the success stories.
@@ -635,7 +640,7 @@ impl<O: ForestObligation> ObligationForest<O> {
635640 // We *intentionally* remove the node from the cache at this point. Otherwise
636641 // tests must come up with a different type on every type error they
637642 // check against.
638- self . active_cache . remove ( node. obligation . as_predicate ( ) ) ;
643+ self . active_cache . remove ( & node. obligation . as_cache_key ( ) ) ;
639644 self . insert_into_error_cache ( index) ;
640645 node_rewrites[ index] = orig_nodes_len;
641646 dead_nodes += 1 ;
0 commit comments