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 Dot for Cons { self.head * other.head + self.tail.dot(other.tail) } } -fn test (n:isize, i:isize, first:T, second:T) ->isize { - match n { 0 => {first.dot(second)} //~ ERROR overflow +fn test (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})}