@@ -40,7 +40,7 @@ pub use global_cache::GlobalCache;
4040pub trait Cx : Copy {
4141 type Input : Debug + Eq + Hash + Copy ;
4242 type Result : Debug + Eq + Hash + Copy ;
43- type AmbiguityInfo : Debug + Eq + Hash + Copy ;
43+ type AmbiguityKind : Debug + Eq + Hash + Copy ;
4444
4545 type DepNodeIndex ;
4646 type Tracked < T : Debug + Clone > : Debug ;
@@ -92,19 +92,16 @@ pub trait Delegate: Sized {
9292 cx : Self :: Cx ,
9393 input : <Self :: Cx as Cx >:: Input ,
9494 ) -> <Self :: Cx as Cx >:: Result ;
95+
96+ const FIXPOINT_OVERFLOW_AMBIGUITY_KIND : <Self :: Cx as Cx >:: AmbiguityKind ;
9597 fn fixpoint_overflow_result (
9698 cx : Self :: Cx ,
9799 input : <Self :: Cx as Cx >:: Input ,
98100 ) -> <Self :: Cx as Cx >:: Result ;
99101
100102 fn is_ambiguous_result (
101103 result : <Self :: Cx as Cx >:: Result ,
102- ) -> Option < <Self :: Cx as Cx >:: AmbiguityInfo > ;
103- fn propagate_ambiguity (
104- cx : Self :: Cx ,
105- for_input : <Self :: Cx as Cx >:: Input ,
106- ambiguity_info : <Self :: Cx as Cx >:: AmbiguityInfo ,
107- ) -> <Self :: Cx as Cx >:: Result ;
104+ ) -> Option < <Self :: Cx as Cx >:: AmbiguityKind > ;
108105
109106 fn compute_goal (
110107 search_graph : & mut SearchGraph < Self > ,
@@ -955,8 +952,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
955952#[ derive_where( Debug ; X : Cx ) ]
956953enum RebaseReason < X : Cx > {
957954 NoCycleUsages ,
958- Ambiguity ( X :: AmbiguityInfo ) ,
959- Overflow ,
955+ Ambiguity ( X :: AmbiguityKind ) ,
960956 /// We've actually reached a fixpoint.
961957 ///
962958 /// This either happens in the first evaluation step for the cycle head.
@@ -987,10 +983,9 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
987983 /// cache entries to also be ambiguous. This causes some undesirable ambiguity for nested
988984 /// goals whose result doesn't actually depend on this cycle head, but that's acceptable
989985 /// to me.
990- #[ instrument( level = "trace" , skip( self , cx ) ) ]
986+ #[ instrument( level = "trace" , skip( self ) ) ]
991987 fn rebase_provisional_cache_entries (
992988 & mut self ,
993- cx : X ,
994989 stack_entry : & StackEntry < X > ,
995990 rebase_reason : RebaseReason < X > ,
996991 ) {
@@ -1065,18 +1060,22 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
10651060 }
10661061
10671062 // The provisional cache entry does depend on the provisional result
1068- // of the popped cycle head. We need to mutate the result of our
1069- // provisional cache entry in case we did not reach a fixpoint .
1063+ // of the popped cycle head. In case we didn't actually reach a fixpoint,
1064+ // we must not keep potentially incorrect provisional cache entries around .
10701065 match rebase_reason {
10711066 // If the cycle head does not actually depend on itself, then
10721067 // the provisional result used by the provisional cache entry
10731068 // is not actually equal to the final provisional result. We
10741069 // need to discard the provisional cache entry in this case.
10751070 RebaseReason :: NoCycleUsages => return false ,
1076- RebaseReason :: Ambiguity ( info) => {
1077- * result = D :: propagate_ambiguity ( cx, input, info) ;
1071+ // If we avoid rerunning a goal due to ambiguity, we only keep provisional
1072+ // results which depend on that cycle head if these are already ambiguous
1073+ // themselves.
1074+ RebaseReason :: Ambiguity ( kind) => {
1075+ if !D :: is_ambiguous_result ( * result) . is_some_and ( |k| k == kind) {
1076+ return false ;
1077+ }
10781078 }
1079- RebaseReason :: Overflow => * result = D :: fixpoint_overflow_result ( cx, input) ,
10801079 RebaseReason :: ReachedFixpoint ( None ) => { }
10811080 RebaseReason :: ReachedFixpoint ( Some ( path_kind) ) => {
10821081 if !popped_head. usages . is_single ( path_kind) {
@@ -1380,17 +1379,12 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
13801379 // final result is equal to the initial response for that case.
13811380 if let Ok ( fixpoint) = self . reached_fixpoint ( & stack_entry, usages, result) {
13821381 self . rebase_provisional_cache_entries (
1383- cx,
13841382 & stack_entry,
13851383 RebaseReason :: ReachedFixpoint ( fixpoint) ,
13861384 ) ;
13871385 return EvaluationResult :: finalize ( stack_entry, encountered_overflow, result) ;
13881386 } else if usages. is_empty ( ) {
1389- self . rebase_provisional_cache_entries (
1390- cx,
1391- & stack_entry,
1392- RebaseReason :: NoCycleUsages ,
1393- ) ;
1387+ self . rebase_provisional_cache_entries ( & stack_entry, RebaseReason :: NoCycleUsages ) ;
13941388 return EvaluationResult :: finalize ( stack_entry, encountered_overflow, result) ;
13951389 }
13961390
@@ -1399,19 +1393,15 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
13991393 // response in the next iteration in this case. These changes would
14001394 // likely either be caused by incompleteness or can change the maybe
14011395 // cause from ambiguity to overflow. Returning ambiguity always
1402- // preserves soundness and completeness even if the goal is be known
1403- // to succeed or fail.
1396+ // preserves soundness and completeness even if the goal could
1397+ // otherwise succeed or fail.
14041398 //
14051399 // This prevents exponential blowup affecting multiple major crates.
14061400 // As we only get to this branch if we haven't yet reached a fixpoint,
14071401 // we also taint all provisional cache entries which depend on the
14081402 // current goal.
1409- if let Some ( info) = D :: is_ambiguous_result ( result) {
1410- self . rebase_provisional_cache_entries (
1411- cx,
1412- & stack_entry,
1413- RebaseReason :: Ambiguity ( info) ,
1414- ) ;
1403+ if let Some ( kind) = D :: is_ambiguous_result ( result) {
1404+ self . rebase_provisional_cache_entries ( & stack_entry, RebaseReason :: Ambiguity ( kind) ) ;
14151405 return EvaluationResult :: finalize ( stack_entry, encountered_overflow, result) ;
14161406 } ;
14171407
@@ -1421,7 +1411,10 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
14211411 if i >= D :: FIXPOINT_STEP_LIMIT {
14221412 debug ! ( "canonical cycle overflow" ) ;
14231413 let result = D :: fixpoint_overflow_result ( cx, input) ;
1424- self . rebase_provisional_cache_entries ( cx, & stack_entry, RebaseReason :: Overflow ) ;
1414+ self . rebase_provisional_cache_entries (
1415+ & stack_entry,
1416+ RebaseReason :: Ambiguity ( D :: FIXPOINT_OVERFLOW_AMBIGUITY_KIND ) ,
1417+ ) ;
14251418 return EvaluationResult :: finalize ( stack_entry, encountered_overflow, result) ;
14261419 }
14271420
0 commit comments