@@ -636,8 +636,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
636
636
637
637
if let Some ( result) = stack. cache ( ) . get_provisional ( fresh_trait_ref) {
638
638
debug ! ( ?result, "PROVISIONAL CACHE HIT" ) ;
639
- stack. update_reached_depth ( stack . cache ( ) . current_reached_depth ( ) ) ;
640
- return Ok ( result) ;
639
+ stack. update_reached_depth ( result . reached_depth ) ;
640
+ return Ok ( result. result ) ;
641
641
}
642
642
643
643
// Check if this is a match for something already on the
@@ -661,7 +661,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
661
661
debug ! ( ?result, "CACHE MISS" ) ;
662
662
self . insert_evaluation_cache ( obligation. param_env , fresh_trait_ref, dep_node, result) ;
663
663
664
- stack. cache ( ) . on_completion ( stack. depth , |fresh_trait_ref, provisional_result| {
664
+ stack. cache ( ) . on_completion ( stack. dfn , |fresh_trait_ref, provisional_result| {
665
665
self . insert_evaluation_cache (
666
666
obligation. param_env ,
667
667
fresh_trait_ref,
@@ -2235,23 +2235,6 @@ struct ProvisionalEvaluationCache<'tcx> {
2235
2235
/// next "depth first number" to issue -- just a counter
2236
2236
dfn : Cell < usize > ,
2237
2237
2238
- /// Stores the "coldest" depth (bottom of stack) reached by any of
2239
- /// the evaluation entries. The idea here is that all things in the provisional
2240
- /// cache are always dependent on *something* that is colder in the stack:
2241
- /// therefore, if we add a new entry that is dependent on something *colder still*,
2242
- /// we have to modify the depth for all entries at once.
2243
- ///
2244
- /// Example:
2245
- ///
2246
- /// Imagine we have a stack `A B C D E` (with `E` being the top of
2247
- /// the stack). We cache something with depth 2, which means that
2248
- /// it was dependent on C. Then we pop E but go on and process a
2249
- /// new node F: A B C D F. Now F adds something to the cache with
2250
- /// depth 1, meaning it is dependent on B. Our original cache
2251
- /// entry is also dependent on B, because there is a path from E
2252
- /// to C and then from C to F and from F to B.
2253
- reached_depth : Cell < usize > ,
2254
-
2255
2238
/// Map from cache key to the provisionally evaluated thing.
2256
2239
/// The cache entries contain the result but also the DFN in which they
2257
2240
/// were added. The DFN is used to clear out values on failure.
@@ -2275,12 +2258,13 @@ struct ProvisionalEvaluationCache<'tcx> {
2275
2258
#[ derive( Copy , Clone , Debug ) ]
2276
2259
struct ProvisionalEvaluation {
2277
2260
from_dfn : usize ,
2261
+ reached_depth : usize ,
2278
2262
result : EvaluationResult ,
2279
2263
}
2280
2264
2281
2265
impl < ' tcx > Default for ProvisionalEvaluationCache < ' tcx > {
2282
2266
fn default ( ) -> Self {
2283
- Self { dfn : Cell :: new ( 0 ) , reached_depth : Cell :: new ( usize :: MAX ) , map : Default :: default ( ) }
2267
+ Self { dfn : Cell :: new ( 0 ) , map : Default :: default ( ) }
2284
2268
}
2285
2269
}
2286
2270
@@ -2295,22 +2279,17 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
2295
2279
/// Check the provisional cache for any result for
2296
2280
/// `fresh_trait_ref`. If there is a hit, then you must consider
2297
2281
/// it an access to the stack slots at depth
2298
- /// `self.current_reached_depth()` and above.
2299
- fn get_provisional ( & self , fresh_trait_ref : ty:: PolyTraitRef < ' tcx > ) -> Option < EvaluationResult > {
2282
+ /// `reached_depth` (from the returned value).
2283
+ fn get_provisional (
2284
+ & self ,
2285
+ fresh_trait_ref : ty:: PolyTraitRef < ' tcx > ,
2286
+ ) -> Option < ProvisionalEvaluation > {
2300
2287
debug ! (
2301
2288
?fresh_trait_ref,
2302
- reached_depth = ?self . reached_depth. get( ) ,
2303
2289
"get_provisional = {:#?}" ,
2304
2290
self . map. borrow( ) . get( & fresh_trait_ref) ,
2305
2291
) ;
2306
- Some ( self . map . borrow ( ) . get ( & fresh_trait_ref) ?. result )
2307
- }
2308
-
2309
- /// Current value of the `reached_depth` counter -- all the
2310
- /// provisional cache entries are dependent on the item at this
2311
- /// depth.
2312
- fn current_reached_depth ( & self ) -> usize {
2313
- self . reached_depth . get ( )
2292
+ Some ( self . map . borrow ( ) . get ( & fresh_trait_ref) ?. clone ( ) )
2314
2293
}
2315
2294
2316
2295
/// Insert a provisional result into the cache. The result came
@@ -2324,13 +2303,10 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
2324
2303
fresh_trait_ref : ty:: PolyTraitRef < ' tcx > ,
2325
2304
result : EvaluationResult ,
2326
2305
) {
2327
- debug ! ( ?from_dfn, ?reached_depth, ?fresh_trait_ref, ?result, "insert_provisional" ) ;
2328
- let r_d = self . reached_depth . get ( ) ;
2329
- self . reached_depth . set ( r_d. min ( reached_depth) ) ;
2330
-
2331
- debug ! ( reached_depth = self . reached_depth. get( ) ) ;
2332
-
2333
- self . map . borrow_mut ( ) . insert ( fresh_trait_ref, ProvisionalEvaluation { from_dfn, result } ) ;
2306
+ debug ! ( ?from_dfn, ?fresh_trait_ref, ?result, "insert_provisional" ) ;
2307
+ self . map
2308
+ . borrow_mut ( )
2309
+ . insert ( fresh_trait_ref, ProvisionalEvaluation { from_dfn, reached_depth, result } ) ;
2334
2310
}
2335
2311
2336
2312
/// Invoked when the node with dfn `dfn` does not get a successful
@@ -2358,25 +2334,40 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
2358
2334
/// was a failure, then `on_failure` should have been invoked
2359
2335
/// already). The callback `op` will be invoked for each
2360
2336
/// provisional entry that we can now confirm.
2337
+ ///
2338
+ /// Note that we may still have provisional cache items remaining
2339
+ /// in the cache when this is done. For example, if there is a
2340
+ /// cycle:
2341
+ ///
2342
+ /// * A depends on...
2343
+ /// * B depends on A
2344
+ /// * C depends on...
2345
+ /// * D depends on C
2346
+ /// * ...
2347
+ ///
2348
+ /// Then as we complete the C node we will have a provisional cache
2349
+ /// with results for A, B, C, and D. This method would clear out
2350
+ /// the C and D results, but leave A and B provisional.
2351
+ ///
2352
+ /// This is determined based on the DFN: we remove any provisional
2353
+ /// results created since `dfn` started (e.g., in our example, dfn
2354
+ /// would be 2, representing the C node, and hence we would
2355
+ /// remove the result for D, which has DFN 3, but not the results for
2356
+ /// A and B, which have DFNs 0 and 1 respectively).
2361
2357
fn on_completion (
2362
2358
& self ,
2363
- depth : usize ,
2359
+ dfn : usize ,
2364
2360
mut op : impl FnMut ( ty:: PolyTraitRef < ' tcx > , EvaluationResult ) ,
2365
2361
) {
2366
- debug ! ( ?depth , reached_depth = ? self . reached_depth . get ( ) , "on_completion" ) ;
2362
+ debug ! ( ?dfn , "on_completion" ) ;
2367
2363
2368
- if self . reached_depth . get ( ) < depth {
2369
- debug ! ( "on_completion: did not yet reach depth to complete" ) ;
2370
- return ;
2371
- }
2372
-
2373
- for ( fresh_trait_ref, eval) in self . map . borrow_mut ( ) . drain ( ) {
2364
+ for ( fresh_trait_ref, eval) in
2365
+ self . map . borrow_mut ( ) . drain_filter ( |_k, eval| eval. from_dfn >= dfn)
2366
+ {
2374
2367
debug ! ( ?fresh_trait_ref, ?eval, "on_completion" ) ;
2375
2368
2376
2369
op ( fresh_trait_ref, eval. result ) ;
2377
2370
}
2378
-
2379
- self . reached_depth . set ( usize:: MAX ) ;
2380
2371
}
2381
2372
}
2382
2373
0 commit comments