@@ -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+ } 
913+ 
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+ } 
891924
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) ]  
@@ -983,16 +1018,30 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
9831018                    return  false ; 
9841019                } ; 
9851020
1021+                 // We may need to mutate the result of our cycle head in case we did not reach 
1022+                 // a fixpoint. 
1023+                 * result = match  rebase_reason { 
1024+                     RebaseReason :: NoCycleUsages  => return  false , 
1025+                     RebaseReason :: Ambiguity  => D :: propagate_ambiguity ( cx,  input,  * result) , 
1026+                     RebaseReason :: Overflow  => D :: on_fixpoint_overflow ( cx,  input) , 
1027+                     RebaseReason :: ReachedFixpoint ( None )  => * result, 
1028+                     RebaseReason :: ReachedFixpoint ( Some ( path_kind) )  => { 
1029+                         if  popped_head. usages . is_single ( path_kind)  { 
1030+                             * result
1031+                         }  else  { 
1032+                             return  false ; 
1033+                         } 
1034+                     } 
1035+                 } ; 
1036+ 
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 , 
9911042                    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