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:
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.
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↩︎
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;
}
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.