rust/tests/ui/traits/next-solver/overflow-plus-ambiguity-nor...

57 lines
1.8 KiB
Rust

//@ check-pass
//@ compile-flags: -Znext-solver
// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/201>.
// See comment below on `fn main`.
trait Intersect<U> {
type Output;
}
impl<T, U> Intersect<Vec<U>> for T
where
T: Intersect<U>,
{
type Output = T;
}
impl Intersect<Cuboid> for Cuboid {
type Output = Cuboid;
}
fn intersect<T, U>(_: &T, _: &U) -> T::Output
where
T: Intersect<U>,
{
todo!()
}
struct Cuboid;
impl Cuboid {
fn method(&self) {}
}
fn main() {
let x = vec![];
// Here we end up trying to normalize `<Cuboid as Intersect<Vec<?0>>>::Output`
// for the return type of the function, to constrain `y`. The impl then requires
// `Cuboid: Intersect<?0>`, which has two candidates. One that constrains
// `?0 = Vec<?1>`, which itself has the same two candidates and ends up leading
// to a recursion depth overflow. In the second impl, we constrain `?0 = Cuboid`.
//
// Floundering leads to us combining the overflow candidate and yes candidate to
// overflow. Because the response was overflow, we used to bubble it up to the
// parent normalizes-to goal, which caused us to drop its constraint that would
// guide us to normalize the associated type mentioned before.
//
// After this PR, we implement a new floundering "algebra" such that `Overflow OR Maybe`
// returns anew `Overflow { keep_constraints: true }`, which means that we don't
// need to drop constraints in the parent normalizes-to goal. This allows us to
// normalize `y` to `Cuboid`, and allows us to call the method successfully. We
// then constrain the `?0` in `let x: Vec<Cuboid> = x` below, so that we don't have
// a left over ambiguous goal.
let y = intersect(&Cuboid, &x);
y.method();
let x: Vec<Cuboid> = x;
}