Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Permit coinductive match only for purely OIBIT backtraces.
Better safe than sorry.
  • Loading branch information
nikomatsakis committed Jan 16, 2016
1 parent 3db82d1 commit 4bbe532
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 11 deletions.
49 changes: 38 additions & 11 deletions src/librustc/middle/traits/fulfill.rs
Expand Up @@ -359,17 +359,8 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
let obligation = &pending_obligation.obligation;
match obligation.predicate {
ty::Predicate::Trait(ref data) => {
// For defaulted traits, we use a co-inductive strategy to
// solve, so that recursion is ok.
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![]));
}
}
if coinductive_match(selcx, obligation, data, &backtrace) {
return Ok(Some(vec![]));
}

let trait_obligation = obligation.with(data.clone());
Expand Down Expand Up @@ -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>,
r_b: ty::Region,
cause: ObligationCause<'tcx>,
Expand Down
1 change: 1 addition & 0 deletions src/librustc_data_structures/obligation_forest/mod.rs
Expand Up @@ -379,6 +379,7 @@ impl<O> Node<O> {
}
}

#[derive(Clone)]
pub struct Backtrace<'b, O: 'b> {
nodes: &'b [Node<O>],
pointer: Option<NodeIndex>,
Expand Down

0 comments on commit 4bbe532

Please sign in to comment.