Skip to content

Commit 03cd934

Browse files
committed
Ensure that we properly increment obligation depth
1 parent 54fd8ca commit 03cd934

File tree

1 file changed

+24
-21
lines changed

1 file changed

+24
-21
lines changed

src/librustc/traits/select.rs

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use rustc_data_structures::bit_set::GrowableBitSet;
4242
use rustc_data_structures::sync::Lock;
4343
use rustc_target::spec::abi::Abi;
4444
use std::cmp;
45-
use std::fmt;
45+
use std::fmt::{self, Display};
4646
use std::iter;
4747
use std::rc::Rc;
4848
use util::nodemap::{FxHashMap, FxHashSet};
@@ -660,7 +660,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
660660
{
661661
let mut result = EvaluatedToOk;
662662
for obligation in predicates {
663-
let eval = self.evaluate_predicate_recursively(stack, obligation)?;
663+
let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
664664
debug!(
665665
"evaluate_predicate_recursively({:?}) = {:?}",
666666
obligation, eval
@@ -682,13 +682,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
682682
obligation: PredicateObligation<'tcx>,
683683
) -> Result<EvaluationResult, OverflowError> {
684684
debug!("evaluate_predicate_recursively({:?})", obligation);
685-
self.check_recursion_limit(obligation)?;
685+
self.check_recursion_limit(&obligation)?;
686686

687687
match obligation.predicate {
688688
ty::Predicate::Trait(ref t) => {
689689
debug_assert!(!t.has_escaping_bound_vars());
690690
let mut obligation = obligation.with(t.clone());
691-
obligation.recursion_depth += 1
691+
obligation.recursion_depth += 1;
692692
self.evaluate_trait_predicate_recursively(previous_stack, obligation)
693693
}
694694

@@ -697,11 +697,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
697697
match self.infcx
698698
.subtype_predicate(&obligation.cause, obligation.param_env, p)
699699
{
700-
Some(Ok(InferOk { obligations, .. })) => {
701-
for o in obligations.iter_mut() {
702-
o.recursion_depth += 1
703-
}
704-
self.evaluate_predicates_recursively(previous_stack, obligation.into_iter())
700+
Some(Ok(InferOk { mut obligations, .. })) => {
701+
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
702+
self.evaluate_predicates_recursively(previous_stack, obligations.into_iter())
705703
}
706704
Some(Err(_)) => Ok(EvaluatedToErr),
707705
None => Ok(EvaluatedToAmbig),
@@ -715,11 +713,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
715713
ty,
716714
obligation.cause.span,
717715
) {
718-
Some(obligations) => {
719-
for o in obligations.iter_mut() {
720-
o.recursion_depth += 1
721-
}
722-
self.evaluate_predicates_recursively(previous_stack, obligations.iter())
716+
Some(mut obligations) => {
717+
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
718+
self.evaluate_predicates_recursively(previous_stack, obligations.into_iter())
723719
}
724720
None => Ok(EvaluatedToAmbig),
725721
},
@@ -741,10 +737,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
741737
ty::Predicate::Projection(ref data) => {
742738
let project_obligation = obligation.with(data.clone());
743739
match project::poly_project_and_unify_type(self, &project_obligation) {
744-
Ok(Some(subobligations)) => {
745-
for o in subobligations.iter_mut() {
746-
o.recursion_depth += 1
747-
}
740+
Ok(Some(mut subobligations)) => {
741+
self.add_depth(subobligations.iter_mut(), obligation.recursion_depth);
748742
let result = self.evaluate_predicates_recursively(
749743
previous_stack,
750744
subobligations.into_iter(),
@@ -1016,7 +1010,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
10161010
match this.confirm_candidate(stack.obligation, candidate) {
10171011
Ok(selection) => this.evaluate_predicates_recursively(
10181012
stack.list(),
1019-
selection.nested_obligations().iter(),
1013+
selection.nested_obligations().into_iter(),
10201014
),
10211015
Err(..) => Ok(EvaluatedToErr),
10221016
}
@@ -1091,14 +1085,23 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
10911085
.insert(trait_ref, WithDepNode::new(dep_node, result));
10921086
}
10931087

1088+
// Due to caching of projection results, it's possible for a subobligation
1089+
// to have a *lower* recursion_depth than the obligation used to create it.
1090+
// To ensure that obligation_depth never decreasees, we force all subobligations
1091+
// to have at least the depth of the original obligation.
1092+
fn add_depth<T: 'cx, I: Iterator<Item = &'cx mut Obligation<'tcx, T>>>(&self, it: I,
1093+
min_depth: usize) {
1094+
it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
1095+
}
1096+
10941097
// Check that the recursion limit has not been exceeded.
10951098
//
10961099
// The weird return type of this function allows it to be used with the 'try' (?)
10971100
// operator within certain functions
10981101
fn check_recursion_limit<T: Display + TypeFoldable<'tcx>>(&self, obligation: &Obligation<'tcx, T>,
10991102
) -> Result<(), OverflowError> {
11001103
let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get();
1101-
if obligaton.recursion_depth >= recursion_limit {
1104+
if obligation.recursion_depth >= recursion_limit {
11021105
match self.query_mode {
11031106
TraitQueryMode::Standard => {
11041107
self.infcx().report_overflow_error(obligation, true);
@@ -1796,7 +1799,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
17961799
self.evaluation_probe(|this| {
17971800
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
17981801
Ok(obligations) => {
1799-
this.evaluate_predicates_recursively(stack.list(), obligations.iter())
1802+
this.evaluate_predicates_recursively(stack.list(), obligations.into_iter())
18001803
}
18011804
Err(()) => Ok(EvaluatedToErr),
18021805
}

0 commit comments

Comments
 (0)