@@ -6,6 +6,7 @@ pub(super) use crate::solve::search_graph::overflow::OverflowHandler;
6
6
use cache:: ProvisionalCache ;
7
7
use overflow:: OverflowData ;
8
8
use rustc_index:: vec:: IndexVec ;
9
+ use rustc_middle:: dep_graph:: DepKind ;
9
10
use rustc_middle:: traits:: solve:: { CanonicalGoal , Certainty , MaybeCause , QueryResult } ;
10
11
use rustc_middle:: ty:: TyCtxt ;
11
12
use std:: { collections:: hash_map:: Entry , mem} ;
@@ -139,10 +140,9 @@ impl<'tcx> SearchGraph<'tcx> {
139
140
/// updated the provisional cache and we have to recompute the current goal.
140
141
///
141
142
/// 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) ]
143
144
fn try_finalize_goal (
144
145
& mut self ,
145
- tcx : TyCtxt < ' tcx > ,
146
146
actual_goal : CanonicalGoal < ' tcx > ,
147
147
response : QueryResult < ' tcx > ,
148
148
) -> bool {
@@ -176,72 +176,87 @@ impl<'tcx> SearchGraph<'tcx> {
176
176
self . stack . push ( StackElem { goal, has_been_used : false } ) ;
177
177
false
178
178
} else {
179
- self . try_move_finished_goal_to_global_cache ( tcx, stack_elem) ;
180
179
true
181
180
}
182
181
}
183
182
184
- fn try_move_finished_goal_to_global_cache (
183
+ pub ( super ) fn with_new_goal (
185
184
& mut self ,
186
185
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
+
190
216
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 ( ) ;
192
218
let provisional_entry = & mut cache. entries [ provisional_entry_index] ;
193
219
let depth = provisional_entry. depth ;
194
220
195
221
// If not, we're done with this goal.
196
222
//
197
223
// 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.
199
225
//
200
226
// Note that if any nested goal were to depend on something deeper on the stack,
201
227
// this would have also updated the depth of the current goal.
202
228
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..) {
204
233
let actual_index = cache. lookup_table . remove ( & entry. goal ) ;
205
234
debug_assert_eq ! ( Some ( i) , actual_index) ;
206
235
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
- ) ;
214
236
}
215
- }
216
- }
217
237
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
+ }
228
258
}
229
259
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
246
261
}
247
262
}
0 commit comments