@@ -215,6 +215,27 @@ impl HeadUsages {
215215 let HeadUsages { inductive, unknown, coinductive, forced_ambiguity } = self ;
216216 inductive == 0 && unknown == 0 && coinductive == 0 && forced_ambiguity == 0
217217 }
218+
219+ fn is_single ( self , path_kind : PathKind ) -> bool {
220+ match path_kind {
221+ PathKind :: Inductive => matches ! (
222+ self ,
223+ HeadUsages { inductive: _, unknown: 0 , coinductive: 0 , forced_ambiguity: 0 } ,
224+ ) ,
225+ PathKind :: Unknown => matches ! (
226+ self ,
227+ HeadUsages { inductive: 0 , unknown: _, coinductive: 0 , forced_ambiguity: 0 } ,
228+ ) ,
229+ PathKind :: Coinductive => matches ! (
230+ self ,
231+ HeadUsages { inductive: 0 , unknown: 0 , coinductive: _, forced_ambiguity: 0 } ,
232+ ) ,
233+ PathKind :: ForcedAmbiguity => matches ! (
234+ self ,
235+ HeadUsages { inductive: 0 , unknown: 0 , coinductive: 0 , forced_ambiguity: _ } ,
236+ ) ,
237+ }
238+ }
218239}
219240
220241#[ derive( Debug , Default ) ]
@@ -888,7 +909,20 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
888909 !entries. is_empty ( )
889910 } ) ;
890911 }
912+ }
891913
914+ /// We need to rebase provisional cache entries when popping one of their cycle
915+ /// heads from the stack. This may not necessarily mean that we've actually
916+ /// reached a fixpoint for that cycle head, which impacts the way we rebase
917+ /// provisional cache entries.
918+ enum RebaseReason {
919+ NoCycleUsages ,
920+ Ambiguity ,
921+ Overflow ,
922+ ReachedFixpoint ( Option < PathKind > ) ,
923+ }
924+
925+ impl < D : Delegate < Cx = X > , X : Cx > SearchGraph < D , X > {
892926 /// A necessary optimization to handle complex solver cycles. A provisional cache entry
893927 /// relies on a set of cycle heads and the path towards these heads. When popping a cycle
894928 /// head from the stack after we've finished computing it, we can't be sure that the
@@ -908,8 +942,9 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
908942 /// to me.
909943 fn rebase_provisional_cache_entries (
910944 & mut self ,
945+ cx : X ,
911946 stack_entry : & StackEntry < X > ,
912- mut mutate_result : impl FnMut ( X :: Input , X :: Result ) -> X :: Result ,
947+ rebase_reason : RebaseReason ,
913948 ) {
914949 let popped_head_index = self . stack . next_index ( ) ;
915950 #[ allow( rustc:: potential_query_instability) ]
@@ -927,6 +962,10 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
927962 return true ;
928963 } ;
929964
965+ let Some ( new_highest_head_index) = heads. opt_highest_cycle_head_index ( ) else {
966+ return false ;
967+ } ;
968+
930969 // We're rebasing an entry `e` over a head `p`. This head
931970 // has a number of own heads `h` it depends on.
932971 //
@@ -941,6 +980,22 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
941980 heads. insert ( head_index, PathsToNested :: EMPTY , HeadUsages :: default ( ) ) ;
942981 }
943982 } else {
983+ // We may need to mutate the result of our cycle head in case we did not reach
984+ // a fixpoint.
985+ * result = match rebase_reason {
986+ RebaseReason :: NoCycleUsages => return false ,
987+ RebaseReason :: Ambiguity => D :: propagate_ambiguity ( cx, input, * result) ,
988+ RebaseReason :: Overflow => D :: on_fixpoint_overflow ( cx, input) ,
989+ RebaseReason :: ReachedFixpoint ( None ) => * result,
990+ RebaseReason :: ReachedFixpoint ( Some ( path_kind) ) => {
991+ if popped_head. usages . is_single ( path_kind) {
992+ * result
993+ } else {
994+ return false ;
995+ }
996+ }
997+ } ;
998+
944999 // The entry `e` actually depends on the value of `p`. We need
9451000 // to make sure that the value of `p` wouldn't change even if we
9461001 // were to reevaluate it as a nested goal of `e` instead. For this
@@ -979,20 +1034,14 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
9791034 }
9801035 }
9811036
982- let Some ( head_index) = heads. opt_highest_cycle_head_index ( ) else {
983- return false ;
984- } ;
985-
9861037 // We now care about the path from the next highest cycle head to the
9871038 // provisional cache entry.
9881039 * path_from_head = path_from_head. extend ( Self :: cycle_path_kind (
9891040 & self . stack ,
9901041 stack_entry. step_kind_from_parent ,
991- head_index ,
1042+ new_highest_head_index ,
9921043 ) ) ;
993- // Mutate the result of the provisional cache entry in case we did
994- // not reach a fixpoint.
995- * result = mutate_result ( input, * result) ;
1044+
9961045 true
9971046 } ) ;
9981047 !entries. is_empty ( )
@@ -1213,28 +1262,31 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
12131262 stack_entry : & StackEntry < X > ,
12141263 usages : HeadUsages ,
12151264 result : X :: Result ,
1216- ) -> bool {
1265+ ) -> Result < Option < PathKind > , ( ) > {
12171266 let provisional_result = stack_entry. provisional_result ;
1218- if usages. is_empty ( ) {
1219- true
1220- } else if let Some ( provisional_result) = provisional_result {
1221- provisional_result == result
1267+ if let Some ( provisional_result) = provisional_result {
1268+ if provisional_result == result { Ok ( None ) } else { Err ( ( ) ) }
12221269 } else {
1223- let check = |k| D :: is_initial_provisional_result ( cx, k, stack_entry. input , result) ;
1224- match usages {
1270+ let path_kind = match usages {
12251271 HeadUsages { inductive : _, unknown : 0 , coinductive : 0 , forced_ambiguity : 0 } => {
1226- check ( PathKind :: Inductive )
1272+ PathKind :: Inductive
12271273 }
12281274 HeadUsages { inductive : 0 , unknown : _, coinductive : 0 , forced_ambiguity : 0 } => {
1229- check ( PathKind :: Unknown )
1275+ PathKind :: Unknown
12301276 }
12311277 HeadUsages { inductive : 0 , unknown : 0 , coinductive : _, forced_ambiguity : 0 } => {
1232- check ( PathKind :: Coinductive )
1278+ PathKind :: Coinductive
12331279 }
12341280 HeadUsages { inductive : 0 , unknown : 0 , coinductive : 0 , forced_ambiguity : _ } => {
1235- check ( PathKind :: ForcedAmbiguity )
1281+ PathKind :: ForcedAmbiguity
12361282 }
1237- _ => false ,
1283+ _ => return Err ( ( ) ) ,
1284+ } ;
1285+
1286+ if D :: is_initial_provisional_result ( cx, path_kind, stack_entry. input , result) {
1287+ Ok ( Some ( path_kind) )
1288+ } else {
1289+ Err ( ( ) )
12381290 }
12391291 }
12401292 }
@@ -1280,8 +1332,19 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
12801332 // is equal to the provisional result of the previous iteration, or because
12811333 // this was only the head of either coinductive or inductive cycles, and the
12821334 // final result is equal to the initial response for that case.
1283- if self . reached_fixpoint ( cx, & stack_entry, usages, result) {
1284- self . rebase_provisional_cache_entries ( & stack_entry, |_, result| result) ;
1335+ if let Ok ( fixpoint) = self . reached_fixpoint ( cx, & stack_entry, usages, result) {
1336+ self . rebase_provisional_cache_entries (
1337+ cx,
1338+ & stack_entry,
1339+ RebaseReason :: ReachedFixpoint ( fixpoint) ,
1340+ ) ;
1341+ return EvaluationResult :: finalize ( stack_entry, encountered_overflow, result) ;
1342+ } else if usages. is_empty ( ) {
1343+ self . rebase_provisional_cache_entries (
1344+ cx,
1345+ & stack_entry,
1346+ RebaseReason :: NoCycleUsages ,
1347+ ) ;
12851348 return EvaluationResult :: finalize ( stack_entry, encountered_overflow, result) ;
12861349 }
12871350
@@ -1298,9 +1361,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
12981361 // we also taint all provisional cache entries which depend on the
12991362 // current goal.
13001363 if D :: is_ambiguous_result ( result) {
1301- self . rebase_provisional_cache_entries ( & stack_entry, |input, _| {
1302- D :: propagate_ambiguity ( cx, input, result)
1303- } ) ;
1364+ self . rebase_provisional_cache_entries ( cx, & stack_entry, RebaseReason :: Ambiguity ) ;
13041365 return EvaluationResult :: finalize ( stack_entry, encountered_overflow, result) ;
13051366 } ;
13061367
@@ -1310,9 +1371,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
13101371 if i >= D :: FIXPOINT_STEP_LIMIT {
13111372 debug ! ( "canonical cycle overflow" ) ;
13121373 let result = D :: on_fixpoint_overflow ( cx, input) ;
1313- self . rebase_provisional_cache_entries ( & stack_entry, |input, _| {
1314- D :: on_fixpoint_overflow ( cx, input)
1315- } ) ;
1374+ self . rebase_provisional_cache_entries ( cx, & stack_entry, RebaseReason :: Overflow ) ;
13161375 return EvaluationResult :: finalize ( stack_entry, encountered_overflow, result) ;
13171376 }
13181377
0 commit comments