]> git.lizzy.rs Git - rust.git/commitdiff
Permit coinductive match only for purely OIBIT backtraces.
authorNiko Matsakis <niko@alum.mit.edu>
Thu, 7 Jan 2016 09:55:20 +0000 (04:55 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Sat, 16 Jan 2016 10:22:32 +0000 (05:22 -0500)
Better safe than sorry.

src/librustc/middle/traits/fulfill.rs
src/librustc_data_structures/obligation_forest/mod.rs

index 97656ecf6ae8e212c9807bb3030e54801797ffc4..0e1c9c3843bf763444f9a4e3241eb1367681378a 100644 (file)
@@ -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());
@@ -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>,
index 21fa150b01297973427538c85edf19caad5f3258..d23b42790d762f18a9bd3bbe7a831713eb37a8da 100644 (file)
@@ -379,6 +379,7 @@ fn is_popped(&self) -> bool {
     }
 }
 
+#[derive(Clone)]
 pub struct Backtrace<'b, O: 'b> {
     nodes: &'b [Node<O>],
     pointer: Option<NodeIndex>,