The recent stabilization of trait upcasting had me wondering - why does the following not compile?
trait Param {
type Domain: Domain;
}
trait Domain {}
trait Foo {
type Domain: Domain;
fn test(&self, param: &dyn Param<Domain = Self::Domain>);
}
struct TestDomain;
impl Domain for TestDomain {}
struct Test;
impl Foo for Test {
type Domain = TestDomain;
fn test(&self, param: &dyn Param<Domain = Self::Domain>) {
external(param);
}
}
impl<T> Param for T where T: External {
type Domain = TestDomain;
}
trait External {}
fn external(_param: &dyn External) {
unimplemented!()
}
It fails with the error that the call to external expects trait External, but found trait Param<Domain = TestDomain>.
However, shouldn't the existence of this covering implementation:
impl<T> Param for T where T: External {
type Domain = TestDomain;
}
give the compiler enough information to deduce that any T: Param<Domain = TestDomain> also means T: External? And thus, &dyn Param<Domain = TestDomain> should be able to be coerced to &dyn External?
Is this just not implemented as of now? Or maybe I'm missing something?
First, that blanket implementation means that T: External + Sized implies T: Param<Domain = TestDomain, not the other way around.
But changing it to this won't help...
impl<T: ?Sized> External for T where T: Param<Domain = TestDomain> {
}
...because trait upcasting is only for the use case of explicit sub/supertraits (as expressed by the bounds in the trait definition), and is not based on what implementations exist.
And and can't coerce dyn Param<..> itself to dyn External without that relationship[1] because coercions to dyn _ can only happen from another unsized type when you're dropping auto-traits, dropping the principal trait, coercing the dyn lifetime, or -- when the feature lands -- upcasting.