HRTB in trait definition for associated types

Hi, here's a simple scenario:

trait T1 {
    type A: T2;
}

trait T2 {
    type B;
}

Easy enough.

Now, I'd like to constraint T2 such that &B implements Into<Self>.
It is my understanding that, since I can't use a where clause directly in the type directive, I must express the bound in the trait's signature, like this:

trait T2: Sized where for<'a> &'a Self::B: Into<Self> {
    type B;
}

Unfortunately, this results in the following compilation error, which I struggle to understand:

error[E0277]: the trait bound `for<'a> <Self as T1>::A: From<&'a <<Self as T1>::A as T2>::B>` is not satisfied

especially since using an equivalent From bound on T2 doesn't seem to cause any such error; i.e. this is fine:

trait T2: Sized + for<'a> From<&'a Self::B> {
    type B;
}

Obviously, I'd prefer binding to Into rather than From so, how can I do that?

Thanks.

You can create a helper trait to rewrite for<'a> &'a T: Into<U> as a simple bound (Rust Playground):

trait RefInto<T> {}
impl<T: ?Sized, U> RefInto<U> for T where for<'a> &'a T: Into<U> {}

trait T1 {
    type A: T2;
}

trait T2: Sized {
    type B: RefInto<Self>;
}

Thank you!

Somehow I didn't think about this. I'll mark this as solution if nothing else comes up, I'm especially interested in why my attempt was incorrect.
Also not a huge fan of having to export a dedicated trait in my public interface if not absolutely necessary, but oh well

There's currently a (somewhat arbitrary) limitation in Rust that constraints in where clauses of a trait only become "part of the trait" (like supertrait bounds or bounds on associated types usually do) if they use Self or Self::AssociatedType as the Self-type in the constraint. I. e. something like Self: From<T> works, but T: Into<Self> wouldn't and neither would Foo<Self>: From<T>.

Your example is of the last form of you're looking at the associated type, where the Self::B isn't directly the Self-type of the (higher-rank) Into constraint, but it's hidden behind the &…-type; and it's of the second form when looking at the occurrence of Self which appears only as a generic parameter to the Into constraint, not its Self-type either.

As far as I understand, there's technical difficulties with improving the situation [1], but it's pretty likely that these limitations will be lifted eventually and your original code would start working as intended, too. I think, the relevant feature/idea is called "implied bounds", also see e. g. here.


  1. I don't remember where or when exactly I read it, but I remember some remark somewhere that chalk could help make this work eventually edit: ah, here, I found something ↩︎

Ah, I see.
I've been writing Rust for years and yet I'll find nuances like this from time to time that completely throw me off guard.

Thank you for the explaination.

I think the corresponding issue is #20671.

Another option (with Nightly and #![feature(generic_associated_types)]):

#![feature(generic_associated_types)]

trait T1 {
    type A: T2
    where
        for<'a> &'a <<Self as T1>::A as T2>::B: Into<Self::A>;
}

trait T2: Sized where for<'a> &'a Self::B: Into<Self> {
    type B;
}

:face_with_spiral_eyes:

(Playground)

But I think in either case, I would still need to add explicit bounds whereever I want to use the .into() method then. I have been running into that problem several times.