rust/tests/ui/traits/next-solver/normalize/indirectly-constrained-term.rs

46 lines
1.7 KiB
Rust

//@ revisions: current next
//@[next] compile-flags: -Znext-solver=coherence
//@ ignore-compare-mode-next-solver (explicit revisions)
//@ check-pass
// A regression test for `paperclip-core`. This previously failed to compile
// in the new solver.
//
// Behavior in old solver:
// We prove `Projection(<W<?0> as Unconstrained>::Assoc, ())`. This
// normalizes `<W<?0> as Unconstrained>::Assoc` to `?1` with nested goals
// `[Projection(<?0 as Unconstrained>::Assoc, ?1), Trait(?1: NoImpl)]`.
// We then unify `?1` with `()`. At this point `?1: NoImpl` does not hold,
// and we get an error.
//
// Previous behavior of the new solver:
// We prove `Projection(<W<?0> as Unconstrained>::Assoc, ())`. This normalizes
// `<W<?0> as Unconstrained>::Assoc` to `?1` and eagerly computes the nested
// goals `[Projection(<?0 as Unconstrained>::Assoc, ?1), Trait(?1: NoImpl)]`.
// These goals are both ambiguous. `NormalizesTo`` then returns `?1` as the
// normalized-to type. It discards the nested goals, forcing the certainty of
// the normalization to `Maybe`. Unifying `?1` with `()` succeeds¹. However,
// this is never propagated to the `?1: NoImpl` goal, as it only exists inside
// of the `NormalizesTo` goal. The normalized-to term always starts out as
// unconstrained.
//
// We fix this regression by returning the nested goals of `NormalizesTo` goals
// to the `AliasRelate`. This results in us checking `(): NoImpl`, same as the
// old solver.
struct W<T: ?Sized>(T);
trait NoImpl {}
trait Unconstrained {
type Assoc;
}
impl<T: Unconstrained<Assoc = U>, U: NoImpl> Unconstrained for W<T> {
type Assoc = U;
}
trait Overlap {}
impl<T: Unconstrained<Assoc = ()>> Overlap for T {}
impl<U> Overlap for W<U> {}
fn main() {}