How to implement trait for nested generic type?

I have a conversion trait and I want to implement something like this:

trait To<T> {
    fn to(self) -> T;
}

impl<T, M, U> To<U> for T
where
    T: To<M>,
    M: To<U>,
{
    fn to(self) -> T {
        <M as To<U>>::to(<T as To<M>>::to(self))
    }
}

But I got this error:

error[E0207]: the type parameter `M` is not constrained by the impl trait, self type, or predicates
 --> src/main.rs:5:9
  |
5 | impl<T, M, U> To<U> for T
  |         ^ unconstrained type parameter

For more information about this error, try `rustc --explain E0207`.

And this variant:

trait To {
    type Target;
    fn to(self) -> Self::Target;
}

impl<T> To for T
where
    T: To,
    T::Target: To
{
    type Target = <T::Target as To>::Target;
    fn to(self) -> Self::Target {
    }
}

throws this error:

error[E0275]: overflow evaluating the requirement `<T as To>::Target == _`
  --> src/main.rs:11:19
   |
11 |     type Target = <T::Target as To>::Target;
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0275`.

Is it possible to flatten nested generic trait implementation?

You can mention the type parameter M in self type: Rust Playground

use core::marker::PhantomData;
trait To<Ret> {
    fn to(self) -> Ret;
}

struct Wrapper<T, M>(T, PhantomData<M>);

impl<T, M, U> To<U> for Wrapper<T, M>
where
    T: To<M>,
    M: To<U>
{
    fn to(self) -> U {
        M::to(T::to(self.0))
    }
}

Though the constrain/unconstrain is really a vague and unhelpful terminology in diagnostics IMHO.

1 Like

Your first example isn't possible because transitive traits are ambiguous, e.g if you have A: To<B>, A: To<C>, C: To<D>, B: To<D> the implementations of A: To<D> would overlap.

As to your second example, the To::Target is an associated type, not a type parameter (like T in To<T>), and a trait can only be implemented once per type, regardless of its associated types. The compiler error is a bit strange to be honest.

1 Like