about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/traits/fulfill.rs58
-rw-r--r--src/test/compile-fail/issue-20831-debruijn.rs1
-rw-r--r--src/test/compile-fail/recursion.rs4
3 files changed, 54 insertions, 9 deletions
diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs
index 2fdf93e6e35..7d1af8ca83a 100644
--- a/src/librustc/middle/traits/fulfill.rs
+++ b/src/librustc/middle/traits/fulfill.rs
@@ -319,12 +319,58 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
                                         FulfillmentErrorCode<'tcx>>
 {
     match process_predicate1(selcx, pending_obligation, backtrace, region_obligations) {
-        Ok(Some(v)) => Ok(Some(v.into_iter()
-                                .map(|o| PendingPredicateObligation {
-                                    obligation: o,
-                                    stalled_on: vec![]
-                                })
-                               .collect())),
+        Ok(Some(v)) => {
+            // FIXME the right thing to do here, I think, is to permit
+            // DAGs. That is, we should detect whenever this predicate
+            // has appeared somewhere in the current tree./ If it's a
+            // parent, that's a cycle, and we should either error out
+            // or consider it ok. But if it's NOT a parent, we can
+            // ignore it, since it will be proven (or not) separately.
+            // However, this is a touch tricky, so I'm doing something
+            // a bit hackier for now so that the `huge-struct.rs` passes.
+
+            let retain_vec: Vec<_> = {
+                let mut dedup = FnvHashSet();
+                v.iter()
+                 .map(|o| {
+                     // Screen out obligations that we know globally
+                     // are true. This should really be the DAG check
+                     // mentioned above.
+                     if
+                         o.predicate.is_global() &&
+                         selcx.tcx().fulfilled_predicates.borrow().is_duplicate(&o.predicate)
+                     {
+                         return false;
+                     }
+
+                     // If we see two siblings that are exactly the
+                     // same, no need to add them twice.
+                     if !dedup.insert(&o.predicate) {
+                         return false;
+                     }
+
+                     true
+                 })
+                 .collect()
+            };
+
+            let pending_predicate_obligations =
+                v.into_iter()
+                 .zip(retain_vec)
+                 .flat_map(|(o, retain)| {
+                     if retain {
+                         Some(PendingPredicateObligation {
+                             obligation: o,
+                             stalled_on: vec![]
+                         })
+                     } else {
+                         None
+                     }
+                 })
+                .collect();
+
+            Ok(Some(pending_predicate_obligations))
+        }
         Ok(None) => Ok(None),
         Err(e) => Err(e)
     }
diff --git a/src/test/compile-fail/issue-20831-debruijn.rs b/src/test/compile-fail/issue-20831-debruijn.rs
index 48ea344c7c2..3f96a9c3422 100644
--- a/src/test/compile-fail/issue-20831-debruijn.rs
+++ b/src/test/compile-fail/issue-20831-debruijn.rs
@@ -40,7 +40,6 @@ impl<'a> Publisher<'a> for MyStruct<'a> {
         //~^^ ERROR cannot infer
         //~|  ERROR cannot infer
         //~|  ERROR cannot infer
-        //~|  ERROR cannot infer
         //
         // The fact that `Publisher` is using an implicit lifetime is
         // what was causing the debruijn accounting to be off, so
diff --git a/src/test/compile-fail/recursion.rs b/src/test/compile-fail/recursion.rs
index b1d45a82276..3221ae46296 100644
--- a/src/test/compile-fail/recursion.rs
+++ b/src/test/compile-fail/recursion.rs
@@ -19,8 +19,8 @@ impl<T:Dot> Dot for Cons<T> {
     self.head * other.head + self.tail.dot(other.tail)
   }
 }
-fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
-  match n {    0 => {first.dot(second)} //~ ERROR overflow
+fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize { //~ ERROR recursion limit
+  match n {    0 => {first.dot(second)}
       // FIXME(#4287) Error message should be here. It should be
       // a type error to instantiate `test` at a type other than T.
     _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}