@@ -220,6 +220,11 @@ impl Usages {
220220 forced_ambiguity : if self . forced_ambiguity == 0 { 0 } else { 1 } ,
221221 }
222222 }
223+
224+ fn is_empty ( self ) -> bool {
225+ let Usages { inductive, unknown, coinductive, forced_ambiguity } = self ;
226+ inductive == 0 && unknown == 0 && coinductive == 0 && forced_ambiguity == 0
227+ }
223228}
224229
225230#[ derive( Debug , Default ) ]
@@ -280,15 +285,19 @@ impl CycleHeads {
280285 self . heads . is_empty ( )
281286 }
282287
283- fn highest_cycle_head ( & self ) -> StackDepth {
284- self . opt_highest_cycle_head ( ) . unwrap ( )
288+ fn highest_cycle_head ( & self ) -> ( StackDepth , CycleHead ) {
289+ self . heads . last_key_value ( ) . map ( |( k, v) | ( * k, * v) ) . unwrap ( )
290+ }
291+
292+ fn highest_cycle_head_index ( & self ) -> StackDepth {
293+ self . opt_highest_cycle_head_index ( ) . unwrap ( )
285294 }
286295
287- fn opt_highest_cycle_head ( & self ) -> Option < StackDepth > {
296+ fn opt_highest_cycle_head_index ( & self ) -> Option < StackDepth > {
288297 self . heads . last_key_value ( ) . map ( |( k, _) | * k)
289298 }
290299
291- fn opt_lowest_cycle_head ( & self ) -> Option < StackDepth > {
300+ fn opt_lowest_cycle_head_index ( & self ) -> Option < StackDepth > {
292301 self . heads . first_key_value ( ) . map ( |( k, _) | * k)
293302 }
294303
@@ -580,7 +589,11 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
580589
581590 for ( head_index, head) in heads {
582591 if let Some ( candidate_usages) = & mut parent. candidate_usages {
583- candidate_usages. 0 . entry ( head_index) . or_default ( ) . add_usages ( head. usages . compressed ( ) ) ;
592+ candidate_usages
593+ . 0
594+ . entry ( head_index)
595+ . or_default ( )
596+ . add_usages ( head. usages . compressed ( ) ) ;
584597 }
585598 match head_index. cmp ( & parent_index) {
586599 Ordering :: Less => parent. heads . insert (
@@ -784,7 +797,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
784797 let path_from_head = Self :: cycle_path_kind (
785798 & self . stack ,
786799 step_kind_from_parent,
787- heads. highest_cycle_head ( ) ,
800+ heads. highest_cycle_head_index ( ) ,
788801 ) ;
789802 let provisional_cache_entry =
790803 ProvisionalCacheEntry { encountered_overflow, heads, path_from_head, result } ;
@@ -822,11 +835,17 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
822835
823836 /// When reevaluating a goal with a changed provisional result, all provisional cache entry
824837 /// which depend on this goal get invalidated.
825- fn clear_dependent_provisional_results ( & mut self ) {
826- let head = self . stack . next_index ( ) ;
838+ ///
839+ /// Note that we keep provisional cache entries which accessed this goal as a cycle head, but
840+ /// don't depend on its value.
841+ fn clear_dependent_provisional_results_for_rerun ( & mut self ) {
842+ let rerun_index = self . stack . next_index ( ) ;
827843 #[ allow( rustc:: potential_query_instability) ]
828844 self . provisional_cache . retain ( |_, entries| {
829- entries. retain ( |entry| entry. heads . highest_cycle_head ( ) != head) ;
845+ entries. retain ( |entry| {
846+ let ( head_index, head) = entry. heads . highest_cycle_head ( ) ;
847+ head_index != rerun_index || head. usages . is_empty ( )
848+ } ) ;
830849 !entries. is_empty ( )
831850 } ) ;
832851 }
@@ -863,7 +882,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
863882 path_from_head,
864883 result,
865884 } = entry;
866- let popped_head = if heads. highest_cycle_head ( ) == popped_head_index {
885+ let popped_head = if heads. highest_cycle_head_index ( ) == popped_head_index {
867886 heads. remove_highest_cycle_head ( )
868887 } else {
869888 return true ;
@@ -907,7 +926,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
907926 heads. insert ( head_index, eph, head. usages . compressed ( ) ) ;
908927 }
909928
910- let Some ( head ) = heads. opt_highest_cycle_head ( ) else {
929+ let Some ( head_index ) = heads. opt_highest_cycle_head_index ( ) else {
911930 return false ;
912931 } ;
913932
@@ -916,7 +935,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
916935 * path_from_head = path_from_head. extend ( Self :: cycle_path_kind (
917936 & self . stack ,
918937 stack_entry. step_kind_from_parent ,
919- head ,
938+ head_index ,
920939 ) ) ;
921940 // Mutate the result of the provisional cache entry in case we did
922941 // not reach a fixpoint.
@@ -940,7 +959,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
940959 for & ProvisionalCacheEntry { encountered_overflow, ref heads, path_from_head, result } in
941960 entries
942961 {
943- let head = heads. highest_cycle_head ( ) ;
962+ let head_index = heads. highest_cycle_head_index ( ) ;
944963 if encountered_overflow {
945964 // This check is overly strict and very subtle. We need to make sure that if
946965 // a global cache entry depends on some goal without adding it to its
@@ -952,14 +971,17 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
952971 // current goal is already part of the same cycle. This check could be
953972 // improved but seems to be good enough for now.
954973 let last = self . stack . last ( ) . unwrap ( ) ;
955- if last. heads . opt_lowest_cycle_head ( ) . is_none_or ( |lowest| lowest > head) {
974+ if last. heads . opt_lowest_cycle_head_index ( ) . is_none_or ( |lowest| lowest > head_index)
975+ {
956976 continue ;
957977 }
958978 }
959979
960980 // A provisional cache entry is only valid if the current path from its
961981 // highest cycle head to the goal is the same.
962- if path_from_head == Self :: cycle_path_kind ( & self . stack , step_kind_from_parent, head) {
982+ if path_from_head
983+ == Self :: cycle_path_kind ( & self . stack , step_kind_from_parent, head_index)
984+ {
963985 Self :: update_parent_goal (
964986 & mut self . stack ,
965987 step_kind_from_parent,
@@ -968,7 +990,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
968990 encountered_overflow,
969991 UpdateParentGoalCtxt :: ProvisionalCacheHit ,
970992 ) ;
971- debug ! ( ?head , ?path_from_head, "provisional cache hit" ) ;
993+ debug ! ( ?head_index , ?path_from_head, "provisional cache hit" ) ;
972994 return Some ( result) ;
973995 }
974996 }
@@ -1026,8 +1048,9 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
10261048 //
10271049 // We check if any of the paths taken while computing the global goal
10281050 // would end up with an applicable provisional cache entry.
1029- let head = heads. highest_cycle_head ( ) ;
1030- let head_to_curr = Self :: cycle_path_kind ( & self . stack , step_kind_from_parent, head) ;
1051+ let head_index = heads. highest_cycle_head_index ( ) ;
1052+ let head_to_curr =
1053+ Self :: cycle_path_kind ( & self . stack , step_kind_from_parent, head_index) ;
10311054 let full_paths = path_from_global_entry. extend_with ( head_to_curr) ;
10321055 if full_paths. contains ( head_to_provisional. into ( ) ) {
10331056 debug ! (
@@ -1239,7 +1262,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
12391262
12401263 // Clear all provisional cache entries which depend on a previous provisional
12411264 // result of this goal and rerun.
1242- self . clear_dependent_provisional_results ( ) ;
1265+ self . clear_dependent_provisional_results_for_rerun ( ) ;
12431266
12441267 debug ! ( ?result, "fixpoint changed provisional results" ) ;
12451268 self . stack . push ( StackEntry {
0 commit comments