@@ -290,7 +290,7 @@ impl CycleHeads {
290
290
}
291
291
292
292
fn contains ( & self , other : & CycleHeads ) -> bool {
293
- other. heads . iter ( ) . all ( |( h, _ ) | self . heads . contains_key ( h ) )
293
+ other. heads . iter ( ) . all ( |( h, & path ) | self . heads . get ( h ) . is_some_and ( |p| p . contains ( path ) ) )
294
294
}
295
295
}
296
296
@@ -785,11 +785,14 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
785
785
fn clear_dependent_provisional_results (
786
786
stack : & Stack < X > ,
787
787
provisional_cache : & mut HashMap < X :: Input , Vec < ProvisionalCacheEntry < X > > > ,
788
+ mut handle_removed_entry : impl FnMut ( X :: Input , ProvisionalCacheEntry < X > ) ,
788
789
) {
789
790
let head = stack. next_index ( ) ;
790
791
#[ allow( rustc:: potential_query_instability) ]
791
- provisional_cache. retain ( |_, entries| {
792
- entries. retain ( |entry| entry. heads . highest_cycle_head ( ) != head) ;
792
+ provisional_cache. retain ( |& input, entries| {
793
+ for e in entries. extract_if ( .., |entry| entry. heads . highest_cycle_head ( ) == head) {
794
+ handle_removed_entry ( input, e)
795
+ }
793
796
!entries. is_empty ( )
794
797
} ) ;
795
798
}
@@ -875,6 +878,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
875
878
// Mutate the result of the provisional cache entry in case we did
876
879
// not reach a fixpoint.
877
880
* result = mutate_result ( input, * result) ;
881
+ debug ! ( ?input, ?entry, "rebased entry" ) ;
878
882
true
879
883
} ) ;
880
884
!entries. is_empty ( )
@@ -1209,10 +1213,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
1209
1213
return EvaluationResult :: finalize ( stack_entry, encountered_overflow, result) ;
1210
1214
}
1211
1215
1212
- // Clear all provisional cache entries which depend on a previous provisional
1213
- // result of this goal and rerun.
1214
- Self :: clear_dependent_provisional_results ( & self . stack , & mut self . provisional_cache ) ;
1215
-
1216
1216
debug ! ( ?i, ?result, "changed provisional results" ) ;
1217
1217
match self . reevaluate_goal_on_stack ( cx, stack_entry, result, inspect) {
1218
1218
( new_stack_entry, new_result) => {
@@ -1247,6 +1247,20 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
1247
1247
) -> ( StackEntry < X > , X :: Result ) {
1248
1248
let node_id = prev_stack_entry. node_id ;
1249
1249
let current_depth = self . stack . next_index ( ) ;
1250
+
1251
+ let mut removed_entries = BTreeMap :: new ( ) ;
1252
+ // Clear all provisional cache entries which depend on a previous provisional
1253
+ // result of this goal and rerun.
1254
+ Self :: clear_dependent_provisional_results (
1255
+ & self . stack ,
1256
+ & mut self . provisional_cache ,
1257
+ |input, entry| {
1258
+ let prev = removed_entries. insert ( entry. entry_node_id , ( input, entry) ) ;
1259
+ if let Some ( prev) = prev {
1260
+ unreachable ! ( "duplicate entries for the same `NodeId`: {prev:?}" ) ;
1261
+ }
1262
+ } ,
1263
+ ) ;
1250
1264
self . stack . push ( StackEntry {
1251
1265
node_id,
1252
1266
input : prev_stack_entry. input ,
@@ -1272,7 +1286,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
1272
1286
// TODO: How can we tell whether this entry was the final revision.
1273
1287
//
1274
1288
// We should be able to rebase provisional entries in most cases.
1275
- Self :: clear_dependent_provisional_results ( stack, provisional_cache) ;
1289
+ Self :: clear_dependent_provisional_results ( stack, provisional_cache, |_ , _| ( ) ) ;
1276
1290
Self :: update_parent_goal (
1277
1291
stack,
1278
1292
reeval_entry. step_kind_from_parent ,
@@ -1286,7 +1300,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
1286
1300
1287
1301
let cycles = self . tree . rerun_get_and_reset_cycles ( prev_stack_entry. node_id ) ;
1288
1302
let current_stack_len = self . stack . len ( ) ;
1289
- let mut first_cycle = true ;
1290
1303
let mut has_changed = HashSet :: default ( ) ;
1291
1304
' outer: for cycle in cycles {
1292
1305
let & tree:: Cycle { node_id : cycle_node_id, ref provisional_results } =
@@ -1328,63 +1341,53 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
1328
1341
let span = tracing:: debug_span!( "reevaluate cycle" , ?rev_stack, ?provisional_result) ;
1329
1342
let _span = span. enter ( ) ;
1330
1343
let mut current_goal = rev_stack. remove ( 0 ) ;
1331
- let mut added_goals = rev_stack
1332
- . into_iter ( )
1333
- . rev ( )
1334
- . enumerate ( )
1335
- . map ( |( idx, ( node_id, info) ) | {
1336
- ( StackDepth :: from ( current_stack_len + idx) , node_id, info)
1337
- } )
1338
- . peekable ( ) ;
1344
+ let mut added_goals = rev_stack. into_iter ( ) . rev ( ) . peekable ( ) ;
1339
1345
// We only pop from the stack when checking whether a result has changed.
1340
1346
// If a later cycle does not have to truncate the stack, we've already reevaluated
1341
1347
// a parent so there's no need to consider that goal.
1342
- if first_cycle {
1343
- first_cycle = false ;
1344
- } else {
1345
- if added_goals. peek ( ) . is_none ( ) {
1346
- if self . stack . len ( ) > current_stack_len {
1347
- truncate_stack (
1348
- & mut self . stack ,
1349
- & mut self . provisional_cache ,
1350
- StackDepth :: from_usize ( current_stack_len) ,
1351
- ) ;
1348
+ for idx in current_stack_len.. {
1349
+ let stack_depth = StackDepth :: from_usize ( idx) ;
1350
+ match ( added_goals. peek ( ) , self . stack . get ( stack_depth) ) {
1351
+ ( Some ( & ( node_id, info) ) , Some ( existing_entry) ) => {
1352
+ let provisional_result = provisional_results. get ( & stack_depth) . copied ( ) ;
1353
+ if existing_entry. node_id == node_id
1354
+ && provisional_result == existing_entry. provisional_result
1355
+ {
1356
+ debug_assert_eq ! ( existing_entry. input, info. input) ;
1357
+ debug_assert_eq ! (
1358
+ existing_entry. step_kind_from_parent,
1359
+ info. step_kind_from_parent
1360
+ ) ;
1361
+ let _ = added_goals. next ( ) . unwrap ( ) ;
1362
+ } else {
1363
+ truncate_stack (
1364
+ & mut self . stack ,
1365
+ & mut self . provisional_cache ,
1366
+ stack_depth,
1367
+ ) ;
1368
+ break ;
1369
+ }
1352
1370
}
1353
- } else {
1354
- while let Some ( & ( stack_depth, node_id, info) ) = added_goals. peek ( ) {
1355
- if let Some ( existing_entry) = self . stack . get ( stack_depth) {
1356
- let provisional_result = provisional_results. get ( & stack_depth) . copied ( ) ;
1357
- if existing_entry. node_id == node_id
1358
- && provisional_result == existing_entry. provisional_result
1359
- {
1360
- debug_assert_eq ! ( existing_entry. input, info. input) ;
1361
- debug_assert_eq ! (
1362
- existing_entry. step_kind_from_parent,
1363
- info. step_kind_from_parent
1364
- ) ;
1365
- let _ = added_goals. next ( ) . unwrap ( ) ;
1366
- } else {
1367
- truncate_stack (
1368
- & mut self . stack ,
1369
- & mut self . provisional_cache ,
1370
- stack_depth,
1371
- ) ;
1372
- break ;
1373
- }
1374
- } else if current_goal. 0 == node_id {
1371
+ ( Some ( & ( node_id, info) ) , None ) => {
1372
+ if current_goal. 0 == node_id {
1375
1373
debug ! ( parent = ?info. input, cycle = ?added_goals. last( ) . unwrap( ) , "reevaluated parent, skip cycle" ) ;
1376
1374
continue ' outer;
1377
1375
} else {
1378
1376
break ;
1379
1377
}
1380
1378
}
1379
+ ( None , Some ( _) ) => {
1380
+ truncate_stack ( & mut self . stack , & mut self . provisional_cache , stack_depth) ;
1381
+ break ;
1382
+ }
1383
+ ( None , None ) => break ,
1381
1384
}
1382
1385
}
1383
1386
1384
- for ( stack_depth , node_id, info) in added_goals {
1387
+ for ( node_id, info) in added_goals {
1385
1388
let tree:: GoalInfo { input, step_kind_from_parent, available_depth } = info;
1389
+ let stack_depth = self . stack . next_index ( ) ;
1386
1390
let provisional_result = provisional_results. get ( & stack_depth) . copied ( ) ;
1387
- debug_assert_eq ! ( self . stack. next_index( ) , stack_depth) ;
1388
1391
self . stack . push ( StackEntry {
1389
1392
node_id,
1390
1393
input,
@@ -1399,10 +1402,22 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
1399
1402
} ) ;
1400
1403
}
1401
1404
1405
+ /*
1406
+ while let Some((&entry_node_id, _)) = removed_entries.first_key_value() {
1407
+ if entry_node_id < current_goal.0
1408
+ && self.stack.iter().all(|e| e.node_id != entry_node_id)
1409
+ {
1410
+ let (entry_node_id, (input, entry)) = removed_entries.pop_first().unwrap();
1411
+ if !self.tree.goal_or_parent_has_changed(node_id, &has_changed, entry_node_id) {
1412
+ self.provisional_cache.entry(input).or_default().push(entry);
1413
+ }
1414
+ }
1415
+ }*/
1416
+
1402
1417
loop {
1403
1418
let span = tracing:: debug_span!(
1404
1419
"reevaluate_canonical_goal" ,
1405
- node = ?current_goal. 1 . input,
1420
+ input = ?current_goal. 1 . input,
1406
1421
step_kind_from_parent = ?current_goal. 1 . step_kind_from_parent
1407
1422
) ;
1408
1423
let _span = span. enter ( ) ;
@@ -1414,6 +1429,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
1414
1429
) ;
1415
1430
if node_id. is_some_and ( |node_id| self . tree . result_matches ( current_goal. 0 , node_id) )
1416
1431
{
1432
+ removed_entries. remove ( & current_goal. 0 ) ;
1417
1433
debug ! ( input = ?current_goal. 1 . input, ?result, "goal did not change" ) ;
1418
1434
continue ' outer;
1419
1435
} else {
@@ -1424,6 +1440,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
1424
1440
Self :: clear_dependent_provisional_results (
1425
1441
& self . stack ,
1426
1442
& mut self . provisional_cache ,
1443
+ |_, _| ( ) ,
1427
1444
) ;
1428
1445
Self :: update_parent_goal (
1429
1446
& mut self . stack ,
@@ -1461,6 +1478,12 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
1461
1478
StackDepth :: from_usize ( current_stack_len) ,
1462
1479
) ;
1463
1480
1481
+ for ( entry_node_id, ( input, entry) ) in removed_entries {
1482
+ if !self . tree . goal_or_parent_has_changed ( node_id, & has_changed, entry_node_id) {
1483
+ self . provisional_cache . entry ( input) . or_default ( ) . push ( entry) ;
1484
+ }
1485
+ }
1486
+
1464
1487
debug_assert_eq ! ( self . stack. len( ) , current_stack_len) ;
1465
1488
let reeval_entry = self . stack . pop ( ) ;
1466
1489
( reeval_entry, provisional_result)
0 commit comments