8

I'm trying to write a macro that generates a From impl for an enum by wrapping the type in a certain variant.

I've come up with this:

macro_rules! variant_derive_from {
    ($enum:ty:$variant:ident($from:ty)) => {
        impl From<$from> for $enum {
            fn from(thing: $from) -> $enum { return $enum::$variant(thing) }
        }
    };
}

However, whenever I try to actually use this macro I get the following error:

error: expected expression, found `B`
|             fn from(thing: $from) -> $enum { $enum::$variant(thing) }
|                                               ^^^^

I couldn't figure out why this might be happening, so I ran a build with macro tracing on, and the macro apparently expands to the following (dummy types, of course):

impl From < A > for B { fn from ( thing : A ) -> B { B :: AVariant ( thing ) } }

When pasting this directly into the code, it compiles successfully. What gives??

Here's a full example of the error.

AlphaModder
  • 3,266
  • 2
  • 28
  • 44

2 Answers2

4

A ty placeholder only works as type, not as a namespace. Using ident instead should work just fine in your example.

ident doesn't accept paths ("foo::Bar") though (and using path also doesn't seem to work in this case); you should be able to workaround it by manually constructing paths like matching this: $enum:ident $(:: $enum_path:ident)* (use it like this: $enum $(:: $enum_path)*).

Stefan
  • 5,304
  • 2
  • 25
  • 44
0

You can simply use <_>:: to disambiguate that you want to use $enum as a type:

<$enum>::$variant(thing)

The macro works perfectly after that change (playground).

kmdreko
  • 42,554
  • 6
  • 57
  • 106