@@ -252,6 +252,10 @@ struct Node<O: ForestObligation> {
252252 obligation : O ,
253253 state : Cell < NodeState > ,
254254
255+ /// A predicate (and its key) can change during processing. If it does we need to register the
256+ /// old predicate so that we can remove or mark it as done if this node errors or is done.
257+ alternative_predicates : Vec < O :: CacheKey > ,
258+
255259 /// Obligations that depend on this obligation for their completion. They
256260 /// must all be in a non-pending state.
257261 dependents : Vec < NodeIndex > ,
@@ -287,6 +291,7 @@ where
287291 Node {
288292 obligation,
289293 state : Cell :: new ( NodeState :: Pending ) ,
294+ alternative_predicates : vec ! [ ] ,
290295 dependents : if let Some ( parent_index) = parent { vec ! [ parent_index] } else { vec ! [ ] } ,
291296 reverse_dependents : vec ! [ ] ,
292297 has_parent : parent. is_some ( ) ,
@@ -311,6 +316,7 @@ where
311316 self . state
312317 ) ;
313318 self . state . set ( NodeState :: Pending ) ;
319+ self . alternative_predicates . clear ( ) ;
314320 self . dependents . clear ( ) ;
315321 self . reverse_dependents . clear ( ) ;
316322 if let Some ( parent_index) = parent {
@@ -660,7 +666,12 @@ impl<O: ForestObligation> ObligationForest<O> {
660666 // `self.active_cache`. This means that `self.active_cache` can get
661667 // out of sync with `nodes`. It's not very common, but it does
662668 // happen, and code in `compress` has to allow for it.
669+ let before = node. obligation . as_cache_key ( ) ;
663670 let result = processor. process_obligation ( & mut node. obligation ) ;
671+ let after = node. obligation . as_cache_key ( ) ;
672+ if before != after {
673+ node. alternative_predicates . push ( before) ;
674+ }
664675
665676 self . unblock_nodes ( processor) ;
666677 let node = & mut self . nodes [ index] ;
@@ -934,6 +945,12 @@ impl<O: ForestObligation> ObligationForest<O> {
934945 . active_cache
935946 . entry ( node. obligation . as_cache_key ( ) )
936947 . or_insert ( CacheState :: Done ) = CacheState :: Done ;
948+ // If the node's predicate changed at some point we mark all its alternate
949+ // predicates as done as well
950+ for alt in node. alternative_predicates . drain ( ..) {
951+ * self . active_cache . entry ( alt) . or_insert ( CacheState :: Done ) =
952+ CacheState :: Done ;
953+ }
937954
938955 if do_completed == DoCompleted :: Yes {
939956 // Extract the success stories.
@@ -949,6 +966,11 @@ impl<O: ForestObligation> ObligationForest<O> {
949966 // tests must come up with a different type on every type error they
950967 // check against.
951968 self . active_cache . remove ( & node. obligation . as_cache_key ( ) ) ;
969+ // If the node's predicate changed at some point we remove all its alternate
970+ // predicates as well
971+ for alt in & node. alternative_predicates {
972+ self . active_cache . remove ( alt) ;
973+ }
952974 self . insert_into_error_cache ( index) ;
953975 self . dead_nodes . push ( index) ;
954976 }
0 commit comments