rust-lang/project-const-traits

Making it possible to call super trait methods with bound on the subtrait

Closed this issue · 2 comments

We'll start with the sugar version:

#[const_trait]
trait Foo {
    fn a(&self);
}

#[const_trait]
trait Bar: ~const Foo {}

const fn foo<T: ~const Bar>(t: &T) {
    t.a();
}

This currently fails compilation, and making a desugaring that makes this work is apparently hard. I'll illustrate this issue by first desugaring it.

Note that this desugaring uses some types from a PR that has not yet landed. See this diff for more info.

trait Foo {
    type Fx;
    fn a<const RUNTIME: bool>(&self) where Param<RUNTIME>: Sub<Self::Fx>;
}

trait Bar: Foo {
    type Fx: Sub<<Self as Foo>::Fx>;
}

fn foo<const RUNTIME: bool, T: Bar>(t: &T) where Param<RUNTIME>: Sub<<T as Bar>::Fx> {
    t.a();
}

This errors because the bound on Foo::a isn't satisfied (specifically Param<RUNTIME>: Sub<Self::Fx>) Now one way to do this is maybe make the compiler know that Sub is a transitive trait, such that A: Sub<B>, B: Sub<C> would together imply A: Sub<C>. But that could be very complicated.

I'm not entirely sure how else to approach it. There might be other desugarings that would make this work, but none was able to escape this transitive implication thing I think.

I'm not entirely sure how else to approach it. There might be other desugarings that would make this work, but none was able to escape this transitive implication thing I think.

Stop me if I'm being naive, but how hard would it be to just hardcode the list of supertraits in the desugared bounds? (Now that's a tongue-twister.)

So your example could desugar to this:

fn foo<const RUNTIME: bool, T: Bar>(t: &T)
where
    Param<RUNTIME>: Sub<<T as Bar>::Fx>,
    Param<RUNTIME>: Sub<<T as Foo>::Fx>,
{
    t.a();
}

It's not super efficient, but I'm pretty sure 99.9% of trait hierarchies in any Rust codebase have under five traits in them, so this solution doesn't add huge amounts of extra work.

EDIT - Oh, this is basically rust-lang/rust#129499

This should be finished ✨