Skip to content

Commit e3175c3

Browse files
committedJun 16, 2019
Auto merge of #61754 - nikomatsakis:trait-caching-perf-3, r=pnkfelix
create a "provisional cache" to restore performance in the case of cycles Introduce a "provisional cache" that caches the results of auto trait resolutions but keeps them from entering the *main* cache until everything is ready. This turned out a bit more complex than I hoped, but I don't see another short term fix -- happy to take suggestions! In the meantime, it's very clear we need to rework the trait solver. This resolves the extreme performance slowdown experienced in #60846 -- I plan to add a perf.rust-lang.org regression test to track this. Caveat: I've not run `x.py test` in full yet. r? @pnkfelix cc @arielb1 Fixes #60846
2 parents 37b6a5e + 0baa925 commit e3175c3

File tree

4 files changed

+409
-85
lines changed

4 files changed

+409
-85
lines changed
 

‎src/librustc/traits/query/evaluate_obligation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
6464
Err(OverflowError) => {
6565
let mut selcx =
6666
SelectionContext::with_query_mode(&self, TraitQueryMode::Standard);
67-
selcx.evaluate_obligation_recursively(obligation)
67+
selcx.evaluate_root_obligation(obligation)
6868
.unwrap_or_else(|r| {
6969
span_bug!(
7070
obligation.cause.span,

‎src/librustc/traits/select.rs

+405-81
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use crate::hir;
4343
use rustc_data_structures::bit_set::GrowableBitSet;
4444
use rustc_data_structures::sync::Lock;
4545
use rustc_target::spec::abi::Abi;
46-
use std::cell::Cell;
46+
use std::cell::{Cell, RefCell};
4747
use std::cmp;
4848
use std::fmt::{self, Display};
4949
use std::iter;
@@ -151,12 +151,12 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> {
151151
/// selection-context's freshener. Used to check for recursion.
152152
fresh_trait_ref: ty::PolyTraitRef<'tcx>,
153153

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:
160160
///
161161
/// - If you have `A: AutoTrait` requires `B: AutoTrait` and `C: NonAutoTrait`
162162
/// - `B: AutoTrait` requires `A: AutoTrait` (coinductive cycle, ok)
@@ -179,9 +179,16 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> {
179179
/// evaluate each member of a cycle up to N times, where N is the
180180
/// length of the cycle. This means the performance impact is
181181
/// bounded and we shouldn't have any terrible worst-cases.
182-
in_cycle: Cell<bool>,
182+
reached_depth: Cell<usize>,
183183

184184
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,
185192
}
186193

187194
#[derive(Clone, Default)]
@@ -600,7 +607,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
600607
debug!("select({:?})", obligation);
601608
debug_assert!(!obligation.predicate.has_escaping_bound_vars());
602609

603-
let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
610+
let pec = &ProvisionalEvaluationCache::default();
611+
let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
604612

605613
let candidate = match self.candidate_from_obligation(&stack) {
606614
Err(SelectionError::Overflow) => {
@@ -646,20 +654,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
646654
// where we do not expect overflow to be propagated.
647655
assert!(self.query_mode == TraitQueryMode::Standard);
648656

649-
self.evaluate_obligation_recursively(obligation)
657+
self.evaluate_root_obligation(obligation)
650658
.expect("Overflow should be caught earlier in standard query mode")
651659
.may_apply()
652660
}
653661

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(
657666
&mut self,
658667
obligation: &PredicateObligation<'tcx>,
659668
) -> Result<EvaluationResult, OverflowError> {
660669
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+
)
663674
})
664675
}
665676

@@ -865,23 +876,131 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
865876
return Ok(result);
866877
}
867878

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+
868894
let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack));
869895
let result = result?;
870896

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 {
872903
debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result);
873904
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+
});
874914
} else {
915+
debug!("PROVISIONAL: {:?}={:?}", fresh_trait_ref, result);
875916
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,
878927
fresh_trait_ref,
928+
result,
879929
);
880930
}
881931

932+
882933
Ok(result)
883934
}
884935

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+
8851004
fn evaluate_stack<'o>(
8861005
&mut self,
8871006
stack: &TraitObligationStack<'o, 'tcx>,
@@ -958,65 +1077,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
9581077
return Ok(EvaluatedToUnknown);
9591078
}
9601079

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-
10201080
match self.candidate_from_obligation(stack) {
10211081
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
10221082
Ok(None) => Ok(EvaluatedToAmbig),
@@ -1219,6 +1279,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12191279
}
12201280

12211281
// 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.
12221287
let (candidate, dep_node) =
12231288
self.in_task(|this| this.candidate_from_obligation_no_cache(stack));
12241289

@@ -3734,11 +3799,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
37343799
.to_poly_trait_ref()
37353800
.fold_with(&mut self.freshener);
37363801

3802+
let dfn = previous_stack.cache.next_dfn();
3803+
let depth = previous_stack.depth() + 1;
37373804
TraitObligationStack {
37383805
obligation,
37393806
fresh_trait_ref,
3740-
in_cycle: Cell::new(false),
3807+
reached_depth: Cell::new(depth),
37413808
previous: previous_stack,
3809+
dfn,
3810+
depth,
37423811
}
37433812
}
37443813

@@ -3931,28 +4000,283 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
39314000
TraitObligationStackList::with(self)
39324001
}
39334002

4003+
fn cache(&self) -> &'o ProvisionalEvaluationCache<'tcx> {
4004+
self.previous.cache
4005+
}
4006+
39344007
fn iter(&'o self) -> TraitObligationStackList<'o, 'tcx> {
39354008
self.list()
39364009
}
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+
}
39374252
}
39384253

39394254
#[derive(Copy, Clone)]
39404255
struct TraitObligationStackList<'o, 'tcx: 'o> {
4256+
cache: &'o ProvisionalEvaluationCache<'tcx>,
39414257
head: Option<&'o TraitObligationStack<'o, 'tcx>>,
39424258
}
39434259

39444260
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 }
39474263
}
39484264

39494265
fn with(r: &'o TraitObligationStack<'o, 'tcx>) -> TraitObligationStackList<'o, 'tcx> {
3950-
TraitObligationStackList { head: Some(r) }
4266+
TraitObligationStackList { cache: r.cache(), head: Some(r) }
39514267
}
39524268

39534269
fn head(&self) -> Option<&'o TraitObligationStack<'o, 'tcx>> {
39544270
self.head
39554271
}
4272+
4273+
fn depth(&self) -> usize {
4274+
if let Some(head) = self.head {
4275+
head.depth
4276+
} else {
4277+
0
4278+
}
4279+
}
39564280
}
39574281

39584282
impl<'o, 'tcx> Iterator for TraitObligationStackList<'o, 'tcx> {

‎src/librustc_traits/evaluate_obligation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fn evaluate_obligation<'tcx>(
2929
let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical);
3030
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
3131

32-
selcx.evaluate_obligation_recursively(&obligation)
32+
selcx.evaluate_root_obligation(&obligation)
3333
},
3434
)
3535
}

‎src/libsyntax/tokenstream.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ where
6565
// bounds without them.
6666
// FIXME: Remove these impls when the compiler can compute the bounds quickly again.
6767
// See https://github.com/rust-lang/rust/issues/60846
68-
#[cfg(parallel_compiler)]
68+
#[cfg(all(bootstrap, parallel_compiler))]
6969
unsafe impl Send for TokenTree {}
70-
#[cfg(parallel_compiler)]
70+
#[cfg(all(bootstrap, parallel_compiler))]
7171
unsafe impl Sync for TokenTree {}
7272

7373
impl TokenTree {

0 commit comments

Comments
 (0)
Please sign in to comment.