@@ -43,7 +43,7 @@ use crate::hir;
43
43
use rustc_data_structures:: bit_set:: GrowableBitSet ;
44
44
use rustc_data_structures:: sync:: Lock ;
45
45
use rustc_target:: spec:: abi:: Abi ;
46
- use std:: cell:: Cell ;
46
+ use std:: cell:: { Cell , RefCell } ;
47
47
use std:: cmp;
48
48
use std:: fmt:: { self , Display } ;
49
49
use std:: iter;
@@ -151,12 +151,12 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> {
151
151
/// selection-context's freshener. Used to check for recursion.
152
152
fresh_trait_ref : ty:: PolyTraitRef < ' tcx > ,
153
153
154
- /// Starts out as false -- if, during evaluation, we encounter a
155
- /// cycle, then we will set this flag to true for all participants
156
- /// in the cycle (apart from the "head" node) . These participants
157
- /// will then forego caching their results. This is not the most
158
- /// efficient solution, but it addresses #60010. The problem we
159
- /// are trying to prevent:
154
+ /// Starts out equal to `depth` -- if, during evaluation, we
155
+ /// encounter a cycle, then we will set this flag to the minimum
156
+ /// depth of that cycle for all participants in the cycle . These
157
+ /// participants will then forego caching their results. This is
158
+ /// not the most efficient solution, but it addresses #60010. The
159
+ /// problem we are trying to prevent:
160
160
///
161
161
/// - If you have `A: AutoTrait` requires `B: AutoTrait` and `C: NonAutoTrait`
162
162
/// - `B: AutoTrait` requires `A: AutoTrait` (coinductive cycle, ok)
@@ -179,9 +179,16 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> {
179
179
/// evaluate each member of a cycle up to N times, where N is the
180
180
/// length of the cycle. This means the performance impact is
181
181
/// bounded and we shouldn't have any terrible worst-cases.
182
- in_cycle : Cell < bool > ,
182
+ reached_depth : Cell < usize > ,
183
183
184
184
previous : TraitObligationStackList < ' prev , ' tcx > ,
185
+
186
+ /// Number of parent frames plus one -- so the topmost frame has depth 1.
187
+ depth : usize ,
188
+
189
+ /// Depth-first number of this node in the search graph -- a
190
+ /// pre-order index. Basically a freshly incremented counter.
191
+ dfn : usize ,
185
192
}
186
193
187
194
#[ derive( Clone , Default ) ]
@@ -600,7 +607,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
600
607
debug ! ( "select({:?})" , obligation) ;
601
608
debug_assert ! ( !obligation. predicate. has_escaping_bound_vars( ) ) ;
602
609
603
- let stack = self . push_stack ( TraitObligationStackList :: empty ( ) , obligation) ;
610
+ let pec = & ProvisionalEvaluationCache :: default ( ) ;
611
+ let stack = self . push_stack ( TraitObligationStackList :: empty ( pec) , obligation) ;
604
612
605
613
let candidate = match self . candidate_from_obligation ( & stack) {
606
614
Err ( SelectionError :: Overflow ) => {
@@ -646,20 +654,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
646
654
// where we do not expect overflow to be propagated.
647
655
assert ! ( self . query_mode == TraitQueryMode :: Standard ) ;
648
656
649
- self . evaluate_obligation_recursively ( obligation)
657
+ self . evaluate_root_obligation ( obligation)
650
658
. expect ( "Overflow should be caught earlier in standard query mode" )
651
659
. may_apply ( )
652
660
}
653
661
654
- /// Evaluates whether the obligation `obligation` can be satisfied and returns
655
- /// an `EvaluationResult`.
656
- pub fn evaluate_obligation_recursively (
662
+ /// Evaluates whether the obligation `obligation` can be satisfied
663
+ /// and returns an `EvaluationResult`. This is meant for the
664
+ /// *initial* call.
665
+ pub fn evaluate_root_obligation (
657
666
& mut self ,
658
667
obligation : & PredicateObligation < ' tcx > ,
659
668
) -> Result < EvaluationResult , OverflowError > {
660
669
self . evaluation_probe ( |this| {
661
- this. evaluate_predicate_recursively ( TraitObligationStackList :: empty ( ) ,
662
- obligation. clone ( ) )
670
+ this. evaluate_predicate_recursively (
671
+ TraitObligationStackList :: empty ( & ProvisionalEvaluationCache :: default ( ) ) ,
672
+ obligation. clone ( ) ,
673
+ )
663
674
} )
664
675
}
665
676
@@ -865,23 +876,131 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
865
876
return Ok ( result) ;
866
877
}
867
878
879
+ if let Some ( result) = stack. cache ( ) . get_provisional ( fresh_trait_ref) {
880
+ debug ! ( "PROVISIONAL CACHE HIT: EVAL({:?})={:?}" , fresh_trait_ref, result) ;
881
+ stack. update_reached_depth ( stack. cache ( ) . current_reached_depth ( ) ) ;
882
+ return Ok ( result) ;
883
+ }
884
+
885
+ // Check if this is a match for something already on the
886
+ // stack. If so, we don't want to insert the result into the
887
+ // main cache (it is cycle dependent) nor the provisional
888
+ // cache (which is meant for things that have completed but
889
+ // for a "backedge" -- this result *is* the backedge).
890
+ if let Some ( cycle_result) = self . check_evaluation_cycle ( & stack) {
891
+ return Ok ( cycle_result) ;
892
+ }
893
+
868
894
let ( result, dep_node) = self . in_task ( |this| this. evaluate_stack ( & stack) ) ;
869
895
let result = result?;
870
896
871
- if !stack. in_cycle . get ( ) {
897
+ if !result. must_apply_modulo_regions ( ) {
898
+ stack. cache ( ) . on_failure ( stack. dfn ) ;
899
+ }
900
+
901
+ let reached_depth = stack. reached_depth . get ( ) ;
902
+ if reached_depth >= stack. depth {
872
903
debug ! ( "CACHE MISS: EVAL({:?})={:?}" , fresh_trait_ref, result) ;
873
904
self . insert_evaluation_cache ( obligation. param_env , fresh_trait_ref, dep_node, result) ;
905
+
906
+ stack. cache ( ) . on_completion ( stack. depth , |fresh_trait_ref, provisional_result| {
907
+ self . insert_evaluation_cache (
908
+ obligation. param_env ,
909
+ fresh_trait_ref,
910
+ dep_node,
911
+ provisional_result. max ( result) ,
912
+ ) ;
913
+ } ) ;
874
914
} else {
915
+ debug ! ( "PROVISIONAL: {:?}={:?}" , fresh_trait_ref, result) ;
875
916
debug ! (
876
- "evaluate_trait_predicate_recursively: skipping cache because {:?} \
877
- is a cycle participant",
917
+ "evaluate_trait_predicate_recursively: caching provisionally because {:?} \
918
+ is a cycle participant (at depth {}, reached depth {})",
919
+ fresh_trait_ref,
920
+ stack. depth,
921
+ reached_depth,
922
+ ) ;
923
+
924
+ stack. cache ( ) . insert_provisional (
925
+ stack. dfn ,
926
+ reached_depth,
878
927
fresh_trait_ref,
928
+ result,
879
929
) ;
880
930
}
881
931
932
+
882
933
Ok ( result)
883
934
}
884
935
936
+ /// If there is any previous entry on the stack that precisely
937
+ /// matches this obligation, then we can assume that the
938
+ /// obligation is satisfied for now (still all other conditions
939
+ /// must be met of course). One obvious case this comes up is
940
+ /// marker traits like `Send`. Think of a linked list:
941
+ ///
942
+ /// struct List<T> { data: T, next: Option<Box<List<T>>> }
943
+ ///
944
+ /// `Box<List<T>>` will be `Send` if `T` is `Send` and
945
+ /// `Option<Box<List<T>>>` is `Send`, and in turn
946
+ /// `Option<Box<List<T>>>` is `Send` if `Box<List<T>>` is
947
+ /// `Send`.
948
+ ///
949
+ /// Note that we do this comparison using the `fresh_trait_ref`
950
+ /// fields. Because these have all been freshened using
951
+ /// `self.freshener`, we can be sure that (a) this will not
952
+ /// affect the inferencer state and (b) that if we see two
953
+ /// fresh regions with the same index, they refer to the same
954
+ /// unbound type variable.
955
+ fn check_evaluation_cycle (
956
+ & mut self ,
957
+ stack : & TraitObligationStack < ' _ , ' tcx > ,
958
+ ) -> Option < EvaluationResult > {
959
+ if let Some ( cycle_depth) = stack. iter ( )
960
+ . skip ( 1 ) // skip top-most frame
961
+ . find ( |prev| stack. obligation . param_env == prev. obligation . param_env &&
962
+ stack. fresh_trait_ref == prev. fresh_trait_ref )
963
+ . map ( |stack| stack. depth )
964
+ {
965
+ debug ! (
966
+ "evaluate_stack({:?}) --> recursive at depth {}" ,
967
+ stack. fresh_trait_ref,
968
+ cycle_depth,
969
+ ) ;
970
+
971
+ // If we have a stack like `A B C D E A`, where the top of
972
+ // the stack is the final `A`, then this will iterate over
973
+ // `A, E, D, C, B` -- i.e., all the participants apart
974
+ // from the cycle head. We mark them as participating in a
975
+ // cycle. This suppresses caching for those nodes. See
976
+ // `in_cycle` field for more details.
977
+ stack. update_reached_depth ( cycle_depth) ;
978
+
979
+ // Subtle: when checking for a coinductive cycle, we do
980
+ // not compare using the "freshened trait refs" (which
981
+ // have erased regions) but rather the fully explicit
982
+ // trait refs. This is important because it's only a cycle
983
+ // if the regions match exactly.
984
+ let cycle = stack. iter ( ) . skip ( 1 ) . take_while ( |s| s. depth >= cycle_depth) ;
985
+ let cycle = cycle. map ( |stack| ty:: Predicate :: Trait ( stack. obligation . predicate ) ) ;
986
+ if self . coinductive_match ( cycle) {
987
+ debug ! (
988
+ "evaluate_stack({:?}) --> recursive, coinductive" ,
989
+ stack. fresh_trait_ref
990
+ ) ;
991
+ Some ( EvaluatedToOk )
992
+ } else {
993
+ debug ! (
994
+ "evaluate_stack({:?}) --> recursive, inductive" ,
995
+ stack. fresh_trait_ref
996
+ ) ;
997
+ Some ( EvaluatedToRecur )
998
+ }
999
+ } else {
1000
+ None
1001
+ }
1002
+ }
1003
+
885
1004
fn evaluate_stack < ' o > (
886
1005
& mut self ,
887
1006
stack : & TraitObligationStack < ' o , ' tcx > ,
@@ -958,65 +1077,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
958
1077
return Ok ( EvaluatedToUnknown ) ;
959
1078
}
960
1079
961
- // If there is any previous entry on the stack that precisely
962
- // matches this obligation, then we can assume that the
963
- // obligation is satisfied for now (still all other conditions
964
- // must be met of course). One obvious case this comes up is
965
- // marker traits like `Send`. Think of a linked list:
966
- //
967
- // struct List<T> { data: T, next: Option<Box<List<T>>> }
968
- //
969
- // `Box<List<T>>` will be `Send` if `T` is `Send` and
970
- // `Option<Box<List<T>>>` is `Send`, and in turn
971
- // `Option<Box<List<T>>>` is `Send` if `Box<List<T>>` is
972
- // `Send`.
973
- //
974
- // Note that we do this comparison using the `fresh_trait_ref`
975
- // fields. Because these have all been freshened using
976
- // `self.freshener`, we can be sure that (a) this will not
977
- // affect the inferencer state and (b) that if we see two
978
- // fresh regions with the same index, they refer to the same
979
- // unbound type variable.
980
- if let Some ( rec_index) = stack. iter ( )
981
- . skip ( 1 ) // skip top-most frame
982
- . position ( |prev| stack. obligation . param_env == prev. obligation . param_env &&
983
- stack. fresh_trait_ref == prev. fresh_trait_ref )
984
- {
985
- debug ! ( "evaluate_stack({:?}) --> recursive" , stack. fresh_trait_ref) ;
986
-
987
- // If we have a stack like `A B C D E A`, where the top of
988
- // the stack is the final `A`, then this will iterate over
989
- // `A, E, D, C, B` -- i.e., all the participants apart
990
- // from the cycle head. We mark them as participating in a
991
- // cycle. This suppresses caching for those nodes. See
992
- // `in_cycle` field for more details.
993
- for item in stack. iter ( ) . take ( rec_index + 1 ) {
994
- debug ! ( "evaluate_stack: marking {:?} as cycle participant" , item. fresh_trait_ref) ;
995
- item. in_cycle . set ( true ) ;
996
- }
997
-
998
- // Subtle: when checking for a coinductive cycle, we do
999
- // not compare using the "freshened trait refs" (which
1000
- // have erased regions) but rather the fully explicit
1001
- // trait refs. This is important because it's only a cycle
1002
- // if the regions match exactly.
1003
- let cycle = stack. iter ( ) . skip ( 1 ) . take ( rec_index + 1 ) ;
1004
- let cycle = cycle. map ( |stack| ty:: Predicate :: Trait ( stack. obligation . predicate ) ) ;
1005
- if self . coinductive_match ( cycle) {
1006
- debug ! (
1007
- "evaluate_stack({:?}) --> recursive, coinductive" ,
1008
- stack. fresh_trait_ref
1009
- ) ;
1010
- return Ok ( EvaluatedToOk ) ;
1011
- } else {
1012
- debug ! (
1013
- "evaluate_stack({:?}) --> recursive, inductive" ,
1014
- stack. fresh_trait_ref
1015
- ) ;
1016
- return Ok ( EvaluatedToRecur ) ;
1017
- }
1018
- }
1019
-
1020
1080
match self . candidate_from_obligation ( stack) {
1021
1081
Ok ( Some ( c) ) => self . evaluate_candidate ( stack, & c) ,
1022
1082
Ok ( None ) => Ok ( EvaluatedToAmbig ) ,
@@ -1219,6 +1279,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
1219
1279
}
1220
1280
1221
1281
// If no match, compute result and insert into cache.
1282
+ //
1283
+ // FIXME(nikomatsakis) -- this cache is not taking into
1284
+ // account cycles that may have occurred in forming the
1285
+ // candidate. I don't know of any specific problems that
1286
+ // result but it seems awfully suspicious.
1222
1287
let ( candidate, dep_node) =
1223
1288
self . in_task ( |this| this. candidate_from_obligation_no_cache ( stack) ) ;
1224
1289
@@ -3734,11 +3799,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
3734
3799
. to_poly_trait_ref ( )
3735
3800
. fold_with ( & mut self . freshener ) ;
3736
3801
3802
+ let dfn = previous_stack. cache . next_dfn ( ) ;
3803
+ let depth = previous_stack. depth ( ) + 1 ;
3737
3804
TraitObligationStack {
3738
3805
obligation,
3739
3806
fresh_trait_ref,
3740
- in_cycle : Cell :: new ( false ) ,
3807
+ reached_depth : Cell :: new ( depth ) ,
3741
3808
previous : previous_stack,
3809
+ dfn,
3810
+ depth,
3742
3811
}
3743
3812
}
3744
3813
@@ -3931,28 +4000,283 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
3931
4000
TraitObligationStackList :: with ( self )
3932
4001
}
3933
4002
4003
+ fn cache ( & self ) -> & ' o ProvisionalEvaluationCache < ' tcx > {
4004
+ self . previous . cache
4005
+ }
4006
+
3934
4007
fn iter ( & ' o self ) -> TraitObligationStackList < ' o , ' tcx > {
3935
4008
self . list ( )
3936
4009
}
4010
+
4011
+ /// Indicates that attempting to evaluate this stack entry
4012
+ /// required accessing something from the stack at depth `reached_depth`.
4013
+ fn update_reached_depth ( & self , reached_depth : usize ) {
4014
+ assert ! (
4015
+ self . depth > reached_depth,
4016
+ "invoked `update_reached_depth` with something under this stack: \
4017
+ self.depth={} reached_depth={}",
4018
+ self . depth,
4019
+ reached_depth,
4020
+ ) ;
4021
+ debug ! ( "update_reached_depth(reached_depth={})" , reached_depth) ;
4022
+ let mut p = self ;
4023
+ while reached_depth < p. depth {
4024
+ debug ! ( "update_reached_depth: marking {:?} as cycle participant" , p. fresh_trait_ref) ;
4025
+ p. reached_depth . set ( p. reached_depth . get ( ) . min ( reached_depth) ) ;
4026
+ p = p. previous . head . unwrap ( ) ;
4027
+ }
4028
+ }
4029
+ }
4030
+
4031
+ /// The "provisional evaluation cache" is used to store intermediate cache results
4032
+ /// when solving auto traits. Auto traits are unusual in that they can support
4033
+ /// cycles. So, for example, a "proof tree" like this would be ok:
4034
+ ///
4035
+ /// - `Foo<T>: Send` :-
4036
+ /// - `Bar<T>: Send` :-
4037
+ /// - `Foo<T>: Send` -- cycle, but ok
4038
+ /// - `Baz<T>: Send`
4039
+ ///
4040
+ /// Here, to prove `Foo<T>: Send`, we have to prove `Bar<T>: Send` and
4041
+ /// `Baz<T>: Send`. Proving `Bar<T>: Send` in turn required `Foo<T>: Send`.
4042
+ /// For non-auto traits, this cycle would be an error, but for auto traits (because
4043
+ /// they are coinductive) it is considered ok.
4044
+ ///
4045
+ /// However, there is a complication: at the point where we have
4046
+ /// "proven" `Bar<T>: Send`, we have in fact only proven it
4047
+ /// *provisionally*. In particular, we proved that `Bar<T>: Send`
4048
+ /// *under the assumption* that `Foo<T>: Send`. But what if we later
4049
+ /// find out this assumption is wrong? Specifically, we could
4050
+ /// encounter some kind of error proving `Baz<T>: Send`. In that case,
4051
+ /// `Bar<T>: Send` didn't turn out to be true.
4052
+ ///
4053
+ /// In Issue #60010, we found a bug in rustc where it would cache
4054
+ /// these intermediate results. This was fixed in #60444 by disabling
4055
+ /// *all* caching for things involved in a cycle -- in our example,
4056
+ /// that would mean we don't cache that `Bar<T>: Send`. But this led
4057
+ /// to large slowdowns.
4058
+ ///
4059
+ /// Specifically, imagine this scenario, where proving `Baz<T>: Send`
4060
+ /// first requires proving `Bar<T>: Send` (which is true:
4061
+ ///
4062
+ /// - `Foo<T>: Send` :-
4063
+ /// - `Bar<T>: Send` :-
4064
+ /// - `Foo<T>: Send` -- cycle, but ok
4065
+ /// - `Baz<T>: Send`
4066
+ /// - `Bar<T>: Send` -- would be nice for this to be a cache hit!
4067
+ /// - `*const T: Send` -- but what if we later encounter an error?
4068
+ ///
4069
+ /// The *provisional evaluation cache* resolves this issue. It stores
4070
+ /// cache results that we've proven but which were involved in a cycle
4071
+ /// in some way. We track the minimal stack depth (i.e., the
4072
+ /// farthest from the top of the stack) that we are dependent on.
4073
+ /// The idea is that the cache results within are all valid -- so long as
4074
+ /// none of the nodes in between the current node and the node at that minimum
4075
+ /// depth result in an error (in which case the cached results are just thrown away).
4076
+ ///
4077
+ /// During evaluation, we consult this provisional cache and rely on
4078
+ /// it. Accessing a cached value is considered equivalent to accessing
4079
+ /// a result at `reached_depth`, so it marks the *current* solution as
4080
+ /// provisional as well. If an error is encountered, we toss out any
4081
+ /// provisional results added from the subtree that encountered the
4082
+ /// error. When we pop the node at `reached_depth` from the stack, we
4083
+ /// can commit all the things that remain in the provisional cache.
4084
+ struct ProvisionalEvaluationCache < ' tcx > {
4085
+ /// next "depth first number" to issue -- just a counter
4086
+ dfn : Cell < usize > ,
4087
+
4088
+ /// Stores the "coldest" depth (bottom of stack) reached by any of
4089
+ /// the evaluation entries. The idea here is that all things in the provisional
4090
+ /// cache are always dependent on *something* that is colder in the stack:
4091
+ /// therefore, if we add a new entry that is dependent on something *colder still*,
4092
+ /// we have to modify the depth for all entries at once.
4093
+ ///
4094
+ /// Example:
4095
+ ///
4096
+ /// Imagine we have a stack `A B C D E` (with `E` being the top of
4097
+ /// the stack). We cache something with depth 2, which means that
4098
+ /// it was dependent on C. Then we pop E but go on and process a
4099
+ /// new node F: A B C D F. Now F adds something to the cache with
4100
+ /// depth 1, meaning it is dependent on B. Our original cache
4101
+ /// entry is also dependent on B, because there is a path from E
4102
+ /// to C and then from C to F and from F to B.
4103
+ reached_depth : Cell < usize > ,
4104
+
4105
+ /// Map from cache key to the provisionally evaluated thing.
4106
+ /// The cache entries contain the result but also the DFN in which they
4107
+ /// were added. The DFN is used to clear out values on failure.
4108
+ ///
4109
+ /// Imagine we have a stack like:
4110
+ ///
4111
+ /// - `A B C` and we add a cache for the result of C (DFN 2)
4112
+ /// - Then we have a stack `A B D` where `D` has DFN 3
4113
+ /// - We try to solve D by evaluating E: `A B D E` (DFN 4)
4114
+ /// - `E` generates various cache entries which have cyclic dependices on `B`
4115
+ /// - `A B D E F` and so forth
4116
+ /// - the DFN of `F` for example would be 5
4117
+ /// - then we determine that `E` is in error -- we will then clear
4118
+ /// all cache values whose DFN is >= 4 -- in this case, that
4119
+ /// means the cached value for `F`.
4120
+ map : RefCell < FxHashMap < ty:: PolyTraitRef < ' tcx > , ProvisionalEvaluation > > ,
4121
+ }
4122
+
4123
+ /// A cache value for the provisional cache: contains the depth-first
4124
+ /// number (DFN) and result.
4125
+ #[ derive( Copy , Clone , Debug ) ]
4126
+ struct ProvisionalEvaluation {
4127
+ from_dfn : usize ,
4128
+ result : EvaluationResult ,
4129
+ }
4130
+
4131
+ impl < ' tcx > Default for ProvisionalEvaluationCache < ' tcx > {
4132
+ fn default ( ) -> Self {
4133
+ Self {
4134
+ dfn : Cell :: new ( 0 ) ,
4135
+ reached_depth : Cell :: new ( std:: usize:: MAX ) ,
4136
+ map : Default :: default ( ) ,
4137
+ }
4138
+ }
4139
+ }
4140
+
4141
+ impl < ' tcx > ProvisionalEvaluationCache < ' tcx > {
4142
+ /// Get the next DFN in sequence (basically a counter).
4143
+ fn next_dfn ( & self ) -> usize {
4144
+ let result = self . dfn . get ( ) ;
4145
+ self . dfn . set ( result + 1 ) ;
4146
+ result
4147
+ }
4148
+
4149
+ /// Check the provisional cache for any result for
4150
+ /// `fresh_trait_ref`. If there is a hit, then you must consider
4151
+ /// it an access to the stack slots at depth
4152
+ /// `self.current_reached_depth()` and above.
4153
+ fn get_provisional ( & self , fresh_trait_ref : ty:: PolyTraitRef < ' tcx > ) -> Option < EvaluationResult > {
4154
+ debug ! (
4155
+ "get_provisional(fresh_trait_ref={:?}) = {:#?} with reached-depth {}" ,
4156
+ fresh_trait_ref,
4157
+ self . map. borrow( ) . get( & fresh_trait_ref) ,
4158
+ self . reached_depth. get( ) ,
4159
+ ) ;
4160
+ Some ( self . map . borrow ( ) . get ( & fresh_trait_ref) ?. result )
4161
+ }
4162
+
4163
+ /// Current value of the `reached_depth` counter -- all the
4164
+ /// provisional cache entries are dependent on the item at this
4165
+ /// depth.
4166
+ fn current_reached_depth ( & self ) -> usize {
4167
+ self . reached_depth . get ( )
4168
+ }
4169
+
4170
+ /// Insert a provisional result into the cache. The result came
4171
+ /// from the node with the given DFN. It accessed a minimum depth
4172
+ /// of `reached_depth` to compute. It evaluated `fresh_trait_ref`
4173
+ /// and resulted in `result`.
4174
+ fn insert_provisional (
4175
+ & self ,
4176
+ from_dfn : usize ,
4177
+ reached_depth : usize ,
4178
+ fresh_trait_ref : ty:: PolyTraitRef < ' tcx > ,
4179
+ result : EvaluationResult ,
4180
+ ) {
4181
+ debug ! (
4182
+ "insert_provisional(from_dfn={}, reached_depth={}, fresh_trait_ref={:?}, result={:?})" ,
4183
+ from_dfn,
4184
+ reached_depth,
4185
+ fresh_trait_ref,
4186
+ result,
4187
+ ) ;
4188
+ let r_d = self . reached_depth . get ( ) ;
4189
+ self . reached_depth . set ( r_d. min ( reached_depth) ) ;
4190
+
4191
+ debug ! ( "insert_provisional: reached_depth={:?}" , self . reached_depth. get( ) ) ;
4192
+
4193
+ self . map . borrow_mut ( ) . insert ( fresh_trait_ref, ProvisionalEvaluation { from_dfn, result } ) ;
4194
+ }
4195
+
4196
+ /// Invoked when the node with dfn `dfn` does not get a successful
4197
+ /// result. This will clear out any provisional cache entries
4198
+ /// that were added since `dfn` was created. This is because the
4199
+ /// provisional entries are things which must assume that the
4200
+ /// things on the stack at the time of their creation succeeded --
4201
+ /// since the failing node is presently at the top of the stack,
4202
+ /// these provisional entries must either depend on it or some
4203
+ /// ancestor of it.
4204
+ fn on_failure ( & self , dfn : usize ) {
4205
+ debug ! (
4206
+ "on_failure(dfn={:?})" ,
4207
+ dfn,
4208
+ ) ;
4209
+ self . map . borrow_mut ( ) . retain ( |key, eval| {
4210
+ if !eval. from_dfn >= dfn {
4211
+ debug ! ( "on_failure: removing {:?}" , key) ;
4212
+ false
4213
+ } else {
4214
+ true
4215
+ }
4216
+ } ) ;
4217
+ }
4218
+
4219
+ /// Invoked when the node at depth `depth` completed without
4220
+ /// depending on anything higher in the stack (if that completion
4221
+ /// was a failure, then `on_failure` should have been invoked
4222
+ /// already). The callback `op` will be invoked for each
4223
+ /// provisional entry that we can now confirm.
4224
+ fn on_completion (
4225
+ & self ,
4226
+ depth : usize ,
4227
+ mut op : impl FnMut ( ty:: PolyTraitRef < ' tcx > , EvaluationResult ) ,
4228
+ ) {
4229
+ debug ! (
4230
+ "on_completion(depth={}, reached_depth={})" ,
4231
+ depth,
4232
+ self . reached_depth. get( ) ,
4233
+ ) ;
4234
+
4235
+ if self . reached_depth . get ( ) < depth {
4236
+ debug ! ( "on_completion: did not yet reach depth to complete" ) ;
4237
+ return ;
4238
+ }
4239
+
4240
+ for ( fresh_trait_ref, eval) in self . map . borrow_mut ( ) . drain ( ) {
4241
+ debug ! (
4242
+ "on_completion: fresh_trait_ref={:?} eval={:?}" ,
4243
+ fresh_trait_ref,
4244
+ eval,
4245
+ ) ;
4246
+
4247
+ op ( fresh_trait_ref, eval. result ) ;
4248
+ }
4249
+
4250
+ self . reached_depth . set ( std:: usize:: MAX ) ;
4251
+ }
3937
4252
}
3938
4253
3939
4254
#[ derive( Copy , Clone ) ]
3940
4255
struct TraitObligationStackList < ' o , ' tcx : ' o > {
4256
+ cache : & ' o ProvisionalEvaluationCache < ' tcx > ,
3941
4257
head : Option < & ' o TraitObligationStack < ' o , ' tcx > > ,
3942
4258
}
3943
4259
3944
4260
impl < ' o , ' tcx > TraitObligationStackList < ' o , ' tcx > {
3945
- fn empty ( ) -> TraitObligationStackList < ' o , ' tcx > {
3946
- TraitObligationStackList { head : None }
4261
+ fn empty ( cache : & ' o ProvisionalEvaluationCache < ' tcx > ) -> TraitObligationStackList < ' o , ' tcx > {
4262
+ TraitObligationStackList { cache , head : None }
3947
4263
}
3948
4264
3949
4265
fn with ( r : & ' o TraitObligationStack < ' o , ' tcx > ) -> TraitObligationStackList < ' o , ' tcx > {
3950
- TraitObligationStackList { head : Some ( r) }
4266
+ TraitObligationStackList { cache : r . cache ( ) , head : Some ( r) }
3951
4267
}
3952
4268
3953
4269
fn head ( & self ) -> Option < & ' o TraitObligationStack < ' o , ' tcx > > {
3954
4270
self . head
3955
4271
}
4272
+
4273
+ fn depth ( & self ) -> usize {
4274
+ if let Some ( head) = self . head {
4275
+ head. depth
4276
+ } else {
4277
+ 0
4278
+ }
4279
+ }
3956
4280
}
3957
4281
3958
4282
impl < ' o , ' tcx > Iterator for TraitObligationStackList < ' o , ' tcx > {
0 commit comments