pub trait A<T> {
}
pub trait B {
type X;
type Y: A<Self::X>;
}
pub trait C {
type X;
type Y: B<X = Self::X>;
// ^^^ This complains that <Self:Y as B>::Y does not implement A<Self::X>
// although Self::Y wouldn't be implementing B otherwise, now would it,
// given that Self::X == <Self::Y as B>::X.
}
I suspect it has to do with the type equality Self::X == <Self::Y as B>::X. However, I wish Rust evaluated these requirements on impl rather than on trait declaration, since there it would be more obvious what the types are.
This is an interesting case. I suspect what's happening is since B: Y references B: X the compiler wants to ensure that B: Y's bounds have been satisfied eagerly. This is in contrast to, say, something like:
trait B {
type X;
type Y: std::fmt::Debug;
type Z: A<Self::Y>
}
Here there's no relationship between X and Y/Z, although Y and Z have bounds. Compiler is happy with this formulation when you define trait C referencing B: X because you've said nothing about Y and Z in the process.
So I guess the question is whether the seeming inconsistency in when trait bounds are checked is an impl artifact or some principled design.
I think a github issue might be worthwhile to get someone from the language team to explain.