Skip to content

Non generic enum implementing Generic trait

enum_dispatch works as expected if the enum and trait both are generic, however my requirement is that I will pass concrete types in the enum instead of making it generic over some types.

use enum_dispatch::enum_dispatch;

pub struct Bar<T>(pub T);
pub struct Baz<T>(pub T);

impl<T> FooTrait<T> for Bar<T> {
    fn foo(&self) -> &T {
        &self.0
    }
}


impl<T> FooTrait<T> for Baz<T> {
    fn foo(&self) -> &T {
        &self.0
    }
}

#[enum_dispatch]
pub trait FooTrait<T> {
    fn foo(&self) -> &T;
}

#[enum_dispatch(FooTrait<T>)]
enum Foo { // Foo is not generic
    Bar(Bar<i32>), // Concrete type passed to the variant
    Baz(Baz<i32>),
}

fn main() {
    let bar = Bar(1);
    let baz = Baz(3);

    let x: Foo = Foo::Baz(baz);
    let y: Foo = Foo::Bar(bar);
    println!("print 3: {}", x.foo());
    println!("print 1: {}", y.foo());

}

Compiling above, I get this error


error[E0412]: cannot find type T in this scope
  --> src/main.rs:29:1
   |
29 | #[enum_dispatch(FooTrait<T>)]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
   |

cargo expand reports the following expansion for the above code:

impl FooTrait<T> for Foo {
    #[inline]
    fn foo(&self) -> &T {
        match self {
            Foo::Bar(inner) => FooTrait::<T>::foo(inner),
            Foo::Baz(inner) => FooTrait::<T>::foo(inner),
        }
    }
}

Is there some way to fix this? I expected an expansion like this:

impl<T> FooTrait<T> for Foo
where
    Bar<i32>: FooTrait<T>,
    Baz<i32>: FooTrait<T>,
{
    fn foo(&self) -> &T {
        match self {
            Foo::Bar(e) => FooTrait::<T>::foo(e),
            Foo::Baz(e) => FooTrait::<T>::foo(e),
        }
    }
}