Ensure that we properly increment obligation depth
This commit is contained in:
parent
54fd8caddc
commit
03cd934ba9
1 changed files with 24 additions and 21 deletions
|
@ -42,7 +42,7 @@ use rustc_data_structures::bit_set::GrowableBitSet;
|
||||||
use rustc_data_structures::sync::Lock;
|
use rustc_data_structures::sync::Lock;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::fmt;
|
use std::fmt::{self, Display};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use util::nodemap::{FxHashMap, FxHashSet};
|
use util::nodemap::{FxHashMap, FxHashSet};
|
||||||
|
@ -660,7 +660,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
{
|
{
|
||||||
let mut result = EvaluatedToOk;
|
let mut result = EvaluatedToOk;
|
||||||
for obligation in predicates {
|
for obligation in predicates {
|
||||||
let eval = self.evaluate_predicate_recursively(stack, obligation)?;
|
let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
|
||||||
debug!(
|
debug!(
|
||||||
"evaluate_predicate_recursively({:?}) = {:?}",
|
"evaluate_predicate_recursively({:?}) = {:?}",
|
||||||
obligation, eval
|
obligation, eval
|
||||||
|
@ -682,13 +682,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
obligation: PredicateObligation<'tcx>,
|
obligation: PredicateObligation<'tcx>,
|
||||||
) -> Result<EvaluationResult, OverflowError> {
|
) -> Result<EvaluationResult, OverflowError> {
|
||||||
debug!("evaluate_predicate_recursively({:?})", obligation);
|
debug!("evaluate_predicate_recursively({:?})", obligation);
|
||||||
self.check_recursion_limit(obligation)?;
|
self.check_recursion_limit(&obligation)?;
|
||||||
|
|
||||||
match obligation.predicate {
|
match obligation.predicate {
|
||||||
ty::Predicate::Trait(ref t) => {
|
ty::Predicate::Trait(ref t) => {
|
||||||
debug_assert!(!t.has_escaping_bound_vars());
|
debug_assert!(!t.has_escaping_bound_vars());
|
||||||
let mut obligation = obligation.with(t.clone());
|
let mut obligation = obligation.with(t.clone());
|
||||||
obligation.recursion_depth += 1
|
obligation.recursion_depth += 1;
|
||||||
self.evaluate_trait_predicate_recursively(previous_stack, obligation)
|
self.evaluate_trait_predicate_recursively(previous_stack, obligation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,11 +697,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
match self.infcx
|
match self.infcx
|
||||||
.subtype_predicate(&obligation.cause, obligation.param_env, p)
|
.subtype_predicate(&obligation.cause, obligation.param_env, p)
|
||||||
{
|
{
|
||||||
Some(Ok(InferOk { obligations, .. })) => {
|
Some(Ok(InferOk { mut obligations, .. })) => {
|
||||||
for o in obligations.iter_mut() {
|
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
|
||||||
o.recursion_depth += 1
|
self.evaluate_predicates_recursively(previous_stack, obligations.into_iter())
|
||||||
}
|
|
||||||
self.evaluate_predicates_recursively(previous_stack, obligation.into_iter())
|
|
||||||
}
|
}
|
||||||
Some(Err(_)) => Ok(EvaluatedToErr),
|
Some(Err(_)) => Ok(EvaluatedToErr),
|
||||||
None => Ok(EvaluatedToAmbig),
|
None => Ok(EvaluatedToAmbig),
|
||||||
|
@ -715,11 +713,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
ty,
|
ty,
|
||||||
obligation.cause.span,
|
obligation.cause.span,
|
||||||
) {
|
) {
|
||||||
Some(obligations) => {
|
Some(mut obligations) => {
|
||||||
for o in obligations.iter_mut() {
|
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
|
||||||
o.recursion_depth += 1
|
self.evaluate_predicates_recursively(previous_stack, obligations.into_iter())
|
||||||
}
|
|
||||||
self.evaluate_predicates_recursively(previous_stack, obligations.iter())
|
|
||||||
}
|
}
|
||||||
None => Ok(EvaluatedToAmbig),
|
None => Ok(EvaluatedToAmbig),
|
||||||
},
|
},
|
||||||
|
@ -741,10 +737,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
ty::Predicate::Projection(ref data) => {
|
ty::Predicate::Projection(ref data) => {
|
||||||
let project_obligation = obligation.with(data.clone());
|
let project_obligation = obligation.with(data.clone());
|
||||||
match project::poly_project_and_unify_type(self, &project_obligation) {
|
match project::poly_project_and_unify_type(self, &project_obligation) {
|
||||||
Ok(Some(subobligations)) => {
|
Ok(Some(mut subobligations)) => {
|
||||||
for o in subobligations.iter_mut() {
|
self.add_depth(subobligations.iter_mut(), obligation.recursion_depth);
|
||||||
o.recursion_depth += 1
|
|
||||||
}
|
|
||||||
let result = self.evaluate_predicates_recursively(
|
let result = self.evaluate_predicates_recursively(
|
||||||
previous_stack,
|
previous_stack,
|
||||||
subobligations.into_iter(),
|
subobligations.into_iter(),
|
||||||
|
@ -1016,7 +1010,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
match this.confirm_candidate(stack.obligation, candidate) {
|
match this.confirm_candidate(stack.obligation, candidate) {
|
||||||
Ok(selection) => this.evaluate_predicates_recursively(
|
Ok(selection) => this.evaluate_predicates_recursively(
|
||||||
stack.list(),
|
stack.list(),
|
||||||
selection.nested_obligations().iter(),
|
selection.nested_obligations().into_iter(),
|
||||||
),
|
),
|
||||||
Err(..) => Ok(EvaluatedToErr),
|
Err(..) => Ok(EvaluatedToErr),
|
||||||
}
|
}
|
||||||
|
@ -1091,6 +1085,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
.insert(trait_ref, WithDepNode::new(dep_node, result));
|
.insert(trait_ref, WithDepNode::new(dep_node, result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Due to caching of projection results, it's possible for a subobligation
|
||||||
|
// to have a *lower* recursion_depth than the obligation used to create it.
|
||||||
|
// To ensure that obligation_depth never decreasees, we force all subobligations
|
||||||
|
// to have at least the depth of the original obligation.
|
||||||
|
fn add_depth<T: 'cx, I: Iterator<Item = &'cx mut Obligation<'tcx, T>>>(&self, it: I,
|
||||||
|
min_depth: usize) {
|
||||||
|
it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
// Check that the recursion limit has not been exceeded.
|
// Check that the recursion limit has not been exceeded.
|
||||||
//
|
//
|
||||||
// The weird return type of this function allows it to be used with the 'try' (?)
|
// The weird return type of this function allows it to be used with the 'try' (?)
|
||||||
|
@ -1098,7 +1101,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
fn check_recursion_limit<T: Display + TypeFoldable<'tcx>>(&self, obligation: &Obligation<'tcx, T>,
|
fn check_recursion_limit<T: Display + TypeFoldable<'tcx>>(&self, obligation: &Obligation<'tcx, T>,
|
||||||
) -> Result<(), OverflowError> {
|
) -> Result<(), OverflowError> {
|
||||||
let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get();
|
let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get();
|
||||||
if obligaton.recursion_depth >= recursion_limit {
|
if obligation.recursion_depth >= recursion_limit {
|
||||||
match self.query_mode {
|
match self.query_mode {
|
||||||
TraitQueryMode::Standard => {
|
TraitQueryMode::Standard => {
|
||||||
self.infcx().report_overflow_error(obligation, true);
|
self.infcx().report_overflow_error(obligation, true);
|
||||||
|
@ -1796,7 +1799,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
self.evaluation_probe(|this| {
|
self.evaluation_probe(|this| {
|
||||||
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
|
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
|
||||||
Ok(obligations) => {
|
Ok(obligations) => {
|
||||||
this.evaluate_predicates_recursively(stack.list(), obligations.iter())
|
this.evaluate_predicates_recursively(stack.list(), obligations.into_iter())
|
||||||
}
|
}
|
||||||
Err(()) => Ok(EvaluatedToErr),
|
Err(()) => Ok(EvaluatedToErr),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue