@@ -6,6 +6,7 @@ pub(super) use crate::solve::search_graph::overflow::OverflowHandler;
66use cache:: ProvisionalCache ;
77use overflow:: OverflowData ;
88use rustc_index:: vec:: IndexVec ;
9+ use rustc_middle:: dep_graph:: DepKind ;
910use rustc_middle:: traits:: solve:: { CanonicalGoal , Certainty , MaybeCause , QueryResult } ;
1011use rustc_middle:: ty:: TyCtxt ;
1112use std:: { collections:: hash_map:: Entry , mem} ;
@@ -139,10 +140,9 @@ impl<'tcx> SearchGraph<'tcx> {
139140 /// updated the provisional cache and we have to recompute the current goal.
140141 ///
141142 /// FIXME: Refer to the rustc-dev-guide entry once it exists.
142- #[ instrument( level = "debug" , skip( self , tcx , actual_goal) , ret) ]
143+ #[ instrument( level = "debug" , skip( self , actual_goal) , ret) ]
143144 fn try_finalize_goal (
144145 & mut self ,
145- tcx : TyCtxt < ' tcx > ,
146146 actual_goal : CanonicalGoal < ' tcx > ,
147147 response : QueryResult < ' tcx > ,
148148 ) -> bool {
@@ -176,72 +176,87 @@ impl<'tcx> SearchGraph<'tcx> {
176176 self . stack . push ( StackElem { goal, has_been_used : false } ) ;
177177 false
178178 } else {
179- self . try_move_finished_goal_to_global_cache ( tcx, stack_elem) ;
180179 true
181180 }
182181 }
183182
184- fn try_move_finished_goal_to_global_cache (
183+ pub ( super ) fn with_new_goal (
185184 & mut self ,
186185 tcx : TyCtxt < ' tcx > ,
187- stack_elem : StackElem < ' tcx > ,
188- ) {
189- let StackElem { goal, .. } = stack_elem;
186+ canonical_goal : CanonicalGoal < ' tcx > ,
187+ mut loop_body : impl FnMut ( & mut Self ) -> QueryResult < ' tcx > ,
188+ ) -> QueryResult < ' tcx > {
189+ if let Some ( result) = tcx. new_solver_evaluation_cache . get ( & canonical_goal, tcx) {
190+ return result;
191+ }
192+
193+ match self . try_push_stack ( tcx, canonical_goal) {
194+ Ok ( ( ) ) => { }
195+ // Our goal is already on the stack, eager return.
196+ Err ( response) => return response,
197+ }
198+
199+ // This is for global caching, so we properly track query dependencies.
200+ // Everything that affects the `Result` should be performed within this
201+ // `with_anon_task` closure.
202+ let ( result, dep_node) = tcx. dep_graph . with_anon_task ( tcx, DepKind :: TraitSelect , || {
203+ self . repeat_while_none (
204+ |this| {
205+ let result = this. deal_with_overflow ( tcx, canonical_goal) ;
206+ let _ = this. stack . pop ( ) . unwrap ( ) ;
207+ result
208+ } ,
209+ |this| {
210+ let result = loop_body ( this) ;
211+ this. try_finalize_goal ( canonical_goal, result) . then ( || result)
212+ } ,
213+ )
214+ } ) ;
215+
190216 let cache = & mut self . provisional_cache ;
191- let provisional_entry_index = * cache. lookup_table . get ( & goal ) . unwrap ( ) ;
217+ let provisional_entry_index = * cache. lookup_table . get ( & canonical_goal ) . unwrap ( ) ;
192218 let provisional_entry = & mut cache. entries [ provisional_entry_index] ;
193219 let depth = provisional_entry. depth ;
194220
195221 // If not, we're done with this goal.
196222 //
197223 // Check whether that this goal doesn't depend on a goal deeper on the stack
198- // and if so, move it and all nested goals to the global cache.
224+ // and if so, move it to the global cache.
199225 //
200226 // Note that if any nested goal were to depend on something deeper on the stack,
201227 // this would have also updated the depth of the current goal.
202228 if depth == self . stack . next_index ( ) {
203- for ( i, entry) in cache. entries . drain_enumerated ( provisional_entry_index. index ( ) ..) {
229+ // If the current goal is the head of a cycle, we drop all other
230+ // cycle participants without moving them to the global cache.
231+ let other_cycle_participants = provisional_entry_index. index ( ) + 1 ;
232+ for ( i, entry) in cache. entries . drain_enumerated ( other_cycle_participants..) {
204233 let actual_index = cache. lookup_table . remove ( & entry. goal ) ;
205234 debug_assert_eq ! ( Some ( i) , actual_index) ;
206235 debug_assert ! ( entry. depth == depth) ;
207- cache:: try_move_finished_goal_to_global_cache (
208- tcx,
209- & mut self . overflow_data ,
210- & self . stack ,
211- entry. goal ,
212- entry. response ,
213- ) ;
214236 }
215- }
216- }
217237
218- pub ( super ) fn with_new_goal (
219- & mut self ,
220- tcx : TyCtxt < ' tcx > ,
221- canonical_goal : CanonicalGoal < ' tcx > ,
222- mut loop_body : impl FnMut ( & mut Self ) -> QueryResult < ' tcx > ,
223- ) -> QueryResult < ' tcx > {
224- match self . try_push_stack ( tcx, canonical_goal) {
225- Ok ( ( ) ) => { }
226- // Our goal is already on the stack, eager return.
227- Err ( response) => return response,
238+ let current_goal = cache. entries . pop ( ) . unwrap ( ) ;
239+ let actual_index = cache. lookup_table . remove ( & current_goal. goal ) ;
240+ debug_assert_eq ! ( Some ( provisional_entry_index) , actual_index) ;
241+ debug_assert ! ( current_goal. depth == depth) ;
242+
243+ // We move the root goal to the global cache if we either did not hit an overflow or if it's
244+ // the root goal as that will now always hit the same overflow limit.
245+ //
246+ // NOTE: We cannot move any non-root goals to the global cache. When replaying the root goal's
247+ // dependencies, our non-root goal may no longer appear as child of the root goal.
248+ //
249+ // See https://github.com/rust-lang/rust/pull/108071 for some additional context.
250+ let should_cache_globally = !self . overflow_data . did_overflow ( ) || self . stack . is_empty ( ) ;
251+ if should_cache_globally {
252+ tcx. new_solver_evaluation_cache . insert (
253+ current_goal. goal ,
254+ dep_node,
255+ current_goal. response ,
256+ ) ;
257+ }
228258 }
229259
230- self . repeat_while_none (
231- |this| {
232- let result = this. deal_with_overflow ( tcx, canonical_goal) ;
233- let stack_elem = this. stack . pop ( ) . unwrap ( ) ;
234- this. try_move_finished_goal_to_global_cache ( tcx, stack_elem) ;
235- result
236- } ,
237- |this| {
238- let result = loop_body ( this) ;
239- if this. try_finalize_goal ( tcx, canonical_goal, result) {
240- Some ( result)
241- } else {
242- None
243- }
244- } ,
245- )
260+ result
246261 }
247262}
0 commit comments