Trait Solver 4 @BoxyUwU @WaffleLapkin

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

trait A<'a> {
   type Assoc;
}

trait B {}

fn f(_: impl for<'a> A<'a, Assoc = impl B + 'a>) {}

impl<'a> A<'a> for () {
   type Assoc = &'a u8;
}

impl B for &u8 {}

fn main() {
   f(());
}
Solution
error: `impl Trait` can only mention lifetimes from an fn or impl
 --> examples/trait_solver_4.rs:7:45
  |
7 | fn f(_: impl for<'a> A<'a, Assoc = impl B + 'a>) {}
  |                  -- lifetime declared here  ^^

error[E0308]: mismatched types
  --> examples/trait_solver_4.rs:16:5
   |
16 |     f(());
   |     ^^^^^ one type is more general than the other
   |
   = note: expected reference `&'a _`
              found reference `&_`
note: the lifetime requirement is introduced here
  --> examples/trait_solver_4.rs:7:28
   |
7  | fn f(_: impl for<'a> A<'a, Assoc = impl B + 'a>) {}
   |                            ^^^^^^^^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0308`.
error: could not compile `code` (example "trait_solver_4") due to 2 previous errors

The impls are turned into generic parameters on the function (O for the outer impl A, I for the inner impl B).

fn f<O, I>(_: O)
where
    O: for<'a> A<'a, Assoc = I>,
    I: B + 'a,
{}

When looked at like this, it can be seen that the 'a in I: B + 'a doesn't actually exist. It is supposed to come from the O: for<'a> bound, but that's a separate bound. So the I bound cannot name 'a, which is why this does not compile.

This is why nested argument-position-impl-trait can sometimes inhibit confusing behavior.

To make this example compile, you can use newly-stabilized associated type bounds instead of an impl trait. As the Assoc: B + 'a is part of the bound on the generic parameter, it can name the higher-ranked 'a.

fn f(_: impl for<'a> A<'a, Assoc: B + 'a>) {}