Implement a hacky version of the DAG support we ultimately want, leaving

a FIXME for later.
This commit is contained in:
Niko Matsakis 2016-01-11 15:49:30 -05:00
parent 3046ac217f
commit 57c31b2849
3 changed files with 54 additions and 9 deletions
src
librustc/middle/traits
test/compile-fail

@ -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)
}

@ -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

@ -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})}