@@ -636,8 +636,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
636636
637637 if let Some ( result) = stack. cache ( ) . get_provisional ( fresh_trait_ref) {
638638 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 ) ;
641641 }
642642
643643 // Check if this is a match for something already on the
@@ -661,7 +661,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
661661 debug ! ( ?result, "CACHE MISS" ) ;
662662 self . insert_evaluation_cache ( obligation. param_env , fresh_trait_ref, dep_node, result) ;
663663
664- stack. cache ( ) . on_completion ( stack. depth , |fresh_trait_ref, provisional_result| {
664+ stack. cache ( ) . on_completion ( stack. dfn , |fresh_trait_ref, provisional_result| {
665665 self . insert_evaluation_cache (
666666 obligation. param_env ,
667667 fresh_trait_ref,
@@ -2162,7 +2162,7 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
21622162 /// required accessing something from the stack at depth `reached_depth`.
21632163 fn update_reached_depth ( & self , reached_depth : usize ) {
21642164 assert ! (
2165- self . depth > reached_depth,
2165+ self . depth >= reached_depth,
21662166 "invoked `update_reached_depth` with something under this stack: \
21672167 self.depth={} reached_depth={}",
21682168 self . depth,
@@ -2235,23 +2235,6 @@ struct ProvisionalEvaluationCache<'tcx> {
22352235 /// next "depth first number" to issue -- just a counter
22362236 dfn : Cell < usize > ,
22372237
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-
22552238 /// Map from cache key to the provisionally evaluated thing.
22562239 /// The cache entries contain the result but also the DFN in which they
22572240 /// were added. The DFN is used to clear out values on failure.
@@ -2275,12 +2258,13 @@ struct ProvisionalEvaluationCache<'tcx> {
22752258#[ derive( Copy , Clone , Debug ) ]
22762259struct ProvisionalEvaluation {
22772260 from_dfn : usize ,
2261+ reached_depth : usize ,
22782262 result : EvaluationResult ,
22792263}
22802264
22812265impl < ' tcx > Default for ProvisionalEvaluationCache < ' tcx > {
22822266 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 ( ) }
22842268 }
22852269}
22862270
@@ -2295,22 +2279,17 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
22952279 /// Check the provisional cache for any result for
22962280 /// `fresh_trait_ref`. If there is a hit, then you must consider
22972281 /// 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 > {
23002287 debug ! (
23012288 ?fresh_trait_ref,
2302- reached_depth = ?self . reached_depth. get( ) ,
23032289 "get_provisional = {:#?}" ,
23042290 self . map. borrow( ) . get( & fresh_trait_ref) ,
23052291 ) ;
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 ( ) )
23142293 }
23152294
23162295 /// Insert a provisional result into the cache. The result came
@@ -2324,13 +2303,31 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
23242303 fresh_trait_ref : ty:: PolyTraitRef < ' tcx > ,
23252304 result : EvaluationResult ,
23262305 ) {
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) ) ;
2306+ debug ! ( ?from_dfn, ?fresh_trait_ref, ?result, "insert_provisional" ) ;
23302307
2331- debug ! ( reached_depth = self . reached_depth. get( ) ) ;
2308+ let mut map = self . map . borrow_mut ( ) ;
2309+
2310+ // Subtle: when we complete working on the DFN `from_dfn`, anything
2311+ // that remains in the provisional cache must be dependent on some older
2312+ // stack entry than `from_dfn`. We have to update their depth with our transitive
2313+ // depth in that case or else it would be referring to some popped note.
2314+ //
2315+ // Example:
2316+ // A (reached depth 0)
2317+ // ...
2318+ // B // depth 1 -- reached depth = 0
2319+ // C // depth 2 -- reached depth = 1 (should be 0)
2320+ // B
2321+ // A // depth 0
2322+ // D (reached depth 1)
2323+ // C (cache -- reached depth = 2)
2324+ for ( _k, v) in & mut * map {
2325+ if v. from_dfn >= from_dfn {
2326+ v. reached_depth = reached_depth. min ( v. reached_depth ) ;
2327+ }
2328+ }
23322329
2333- self . map . borrow_mut ( ) . insert ( fresh_trait_ref, ProvisionalEvaluation { from_dfn, result } ) ;
2330+ map. insert ( fresh_trait_ref, ProvisionalEvaluation { from_dfn, reached_depth , result } ) ;
23342331 }
23352332
23362333 /// Invoked when the node with dfn `dfn` does not get a successful
@@ -2358,25 +2355,40 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
23582355 /// was a failure, then `on_failure` should have been invoked
23592356 /// already). The callback `op` will be invoked for each
23602357 /// provisional entry that we can now confirm.
2358+ ///
2359+ /// Note that we may still have provisional cache items remaining
2360+ /// in the cache when this is done. For example, if there is a
2361+ /// cycle:
2362+ ///
2363+ /// * A depends on...
2364+ /// * B depends on A
2365+ /// * C depends on...
2366+ /// * D depends on C
2367+ /// * ...
2368+ ///
2369+ /// Then as we complete the C node we will have a provisional cache
2370+ /// with results for A, B, C, and D. This method would clear out
2371+ /// the C and D results, but leave A and B provisional.
2372+ ///
2373+ /// This is determined based on the DFN: we remove any provisional
2374+ /// results created since `dfn` started (e.g., in our example, dfn
2375+ /// would be 2, representing the C node, and hence we would
2376+ /// remove the result for D, which has DFN 3, but not the results for
2377+ /// A and B, which have DFNs 0 and 1 respectively).
23612378 fn on_completion (
23622379 & self ,
2363- depth : usize ,
2380+ dfn : usize ,
23642381 mut op : impl FnMut ( ty:: PolyTraitRef < ' tcx > , EvaluationResult ) ,
23652382 ) {
2366- debug ! ( ?depth , reached_depth = ? self . reached_depth . get ( ) , "on_completion" ) ;
2383+ debug ! ( ?dfn , "on_completion" ) ;
23672384
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 ( ) {
2385+ for ( fresh_trait_ref, eval) in
2386+ self . map . borrow_mut ( ) . drain_filter ( |_k, eval| eval. from_dfn >= dfn)
2387+ {
23742388 debug ! ( ?fresh_trait_ref, ?eval, "on_completion" ) ;
23752389
23762390 op ( fresh_trait_ref, eval. result ) ;
23772391 }
2378-
2379- self . reached_depth . set ( usize:: MAX ) ;
23802392 }
23812393}
23822394
0 commit comments