1
votes

Why does the following not compile?

trait A<'a> {
    type Typ;
}

trait B {}

struct C<T> {
    _ph: std::marker::PhantomData<T>,
}

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

playground

The previous gives the error "the type parameter V is not constrained by the impl trait, self type, or predicates". Changing the associated type to a generic type also does not compile, giving the same error. However, the following compiles when the lifetimes are removed.

trait A {
    type Typ;
}

trait B {}

struct C<T> {
    _ph: std::marker::PhantomData<T>,
}

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

playground

Removing the associated type compiles as well.

trait A<'a> {}

trait B {}

struct C<T> {
    _ph: std::marker::PhantomData<T>,
}

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

playground

Seeing how just removing the lifetime causes the code to compile (not changing V in any way), I'm guessing the error message is not the real underlying error. I have no clue what the real reason for not compiling would be.

The original situation this arose isn't really relevant - this question's more about the strange behaviour and error message, but you can look at it here if you want.

1
I think it's because the generic opens up a (possibly infinite) number of 'a and V pairs that satisfy T: A<'a, Typ=V>, which means that just given the type C<T>, Rust cannot decide what generic impl parameters to use. With no lifetime and only a constraint on the associated type, there can only be one A impl and thus only one valid V.Aplet123

1 Answers

0
votes

It complains because you are not constraining that generic.

It is like writing:

impl<A> SomeTrait for MyType {}
// We aren't using A

This will work just fine because it is already generic over what Typ is:

impl<'a, T> B for C<T> where
    T: A<'a>,
{
    // you can refer to your V type as <T as A>::Typ
}

If you do want to constrain it you can:

use std::default::Default;

impl<'a, T> B for C<T> where
    T: A<'a>,
    <T as A<'a>>::Typ: Default,
{
    // now here you can call <T as A<'a>>::Typ::default()
}