Description
Specialization is fundamentally reentrant: to determine that one impl specializes another, we end up needing to call back into the full trait system machinery (selection, projection, normalization), which in turn depends on the result of specialization (for associated types in particular).
The initial implementation institutes a strict "phase split", where any attempt to perform a projection that would require walking the specialization graph while we are constructing the specialization graph simply ICEs the compiler. The need to walk the graph for a projection arises whenever you are trying to project an inherited associated type. That means examples like the following will ICE:
trait Assoc {
type Output;
}
impl<T> Assoc for T {
type Output = bool;
}
impl Assoc for u8 {} // <- inherits the non-default type from above
trait Foo {}
impl Foo for <u8 as Assoc>::Output {} // <- this projection will fail with an ICE
To fix this problem, we will need to allow the specialization graph to be consulted while it's being constructed.