Permit coinductive match only for purely OIBIT backtraces.

Better safe than sorry.
This commit is contained in:
Niko Matsakis 2016-01-07 04:55:20 -05:00
parent 3db82d1a4e
commit 4bbe532737
2 changed files with 39 additions and 11 deletions

View File

@ -359,17 +359,8 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
let obligation = &pending_obligation.obligation; let obligation = &pending_obligation.obligation;
match obligation.predicate { match obligation.predicate {
ty::Predicate::Trait(ref data) => { ty::Predicate::Trait(ref data) => {
// For defaulted traits, we use a co-inductive strategy to if coinductive_match(selcx, obligation, data, &backtrace) {
// solve, so that recursion is ok. return Ok(Some(vec![]));
if selcx.tcx().trait_has_default_impl(data.def_id()) {
debug!("process_predicate: trait has default impl");
for bt_obligation in backtrace {
debug!("process_predicate: bt_obligation = {:?}", bt_obligation.obligation);
if bt_obligation.obligation.predicate == obligation.predicate {
debug!("process_predicate: found a match!");
return Ok(Some(vec![]));
}
}
} }
let trait_obligation = obligation.with(data.clone()); let trait_obligation = obligation.with(data.clone());
@ -483,6 +474,42 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
} }
} }
/// For defaulted traits, we use a co-inductive strategy to solve, so
/// that recursion is ok. This routine returns true if the top of the
/// stack (`top_obligation` and `top_data`):
/// - is a defaulted trait, and
/// - it also appears in the backtrace at some position `X`; and,
/// - all the predicates at positions `X..` between `X` an the top are
/// also defaulted traits.
fn coinductive_match<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
top_obligation: &PredicateObligation<'tcx>,
top_data: &ty::PolyTraitPredicate<'tcx>,
backtrace: &Backtrace<PendingPredicateObligation<'tcx>>)
-> bool
{
if selcx.tcx().trait_has_default_impl(top_data.def_id()) {
for bt_obligation in backtrace.clone() {
// *Everything* in the backtrace must be a defaulted trait.
match bt_obligation.obligation.predicate {
ty::Predicate::Trait(ref data) => {
if !selcx.tcx().trait_has_default_impl(data.def_id()) {
break;
}
}
_ => { break; }
}
// And we must find a recursive match.
if bt_obligation.obligation.predicate == top_obligation.predicate {
debug!("process_predicate: found a match in the backtrace");
return true;
}
}
}
false
}
fn register_region_obligation<'tcx>(t_a: Ty<'tcx>, fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
r_b: ty::Region, r_b: ty::Region,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,

View File

@ -379,6 +379,7 @@ impl<O> Node<O> {
} }
} }
#[derive(Clone)]
pub struct Backtrace<'b, O: 'b> { pub struct Backtrace<'b, O: 'b> {
nodes: &'b [Node<O>], nodes: &'b [Node<O>],
pointer: Option<NodeIndex>, pointer: Option<NodeIndex>,