Without lifetimes - compiles fine; with them - "unconstrainted type parameter"

I have the following code (simplified):

trait A<'a> {
    type C;
}

trait B {}

impl<'a, T: A<'a, C = C>, C> B for T {}

The compile fails to compile:

error[E0207]: the type parameter `C` is not constrained by the impl trait, self type, or predicates
 --> src/lib.rs:7:27
  |
7 | impl<'a, T: A<'a, C = C>, C> B for T {}
  |                           ^ unconstrained type parameter

I don't understand why.

But the really strange thing happens when I remove the lifetime:

trait A {
    type C;
}

trait B {}

impl<T: A<C = C>, C> B for T {}

Now the code compiles fine.

I would expect the opposite, if already; the lifetime introduces space for ambiguation, doesn't it?

struct Q {}

impl<'a> A<'a> for Q {
    type C = i32;
}

The above impl will implement the all traits A<'a>, A<'b>, A<'c> and so on for every possible lifetime. Now which one applies in the impl of B for Q?

But if I remove the associated type this compiles:

trait A<'a> {}

trait B {}

impl<'a, T: A<'a>> B for T {}

Interesting. I don't have the answer to that, anyway, you can use this:

trait A<'a> {
    type C;
}

trait B {}

impl<T: for<'a> A<'a, C = C>, C> B for T {}

This syntax allows you to say "T must implement A<'a, C = C> for every lifetime 'a" rather than yours, which says "T must implement A<'a, C = C> for some lifetime 'a".

I suspect that it’s a situation like this that the compiler’s worried about, but it feels fully-specified to me. I’ve run into similar errors where I can’t name an associated type as a parameter.

Edit: I found the bug report I filed. It’s not exactly the same as this, but similar.

struct Q {}

impl<'a> A<'a> for Q {
    type C = &'a i32;
}
1 Like

The one you just posted compiles for me.

1 Like

I meant to say that the possibility of C being dependent on 'a might explain the error message for the original problematic statement:

impl<'a, T: A<'a, C = C>, C> B for T {}

Ahh, yes. What if the A<'a> impl had C = i32 but the A<'b> impl had C = u32. Then the type C would not be sufficiently constrained.

I guess it just doesn't care about unconstrained lifetimes.