error: macro expansion ignores token `{` and any following
--> src/main.rs:2:24
|
2 | ($e: path) => { $e { v: 42 } }
| ^
...
6 | let s = create_instance!(E::I32);
| ------------------------ caused by the macro expansion here
|
= note: the usage of `create_instance!` is likely invalid in expression context
error[E0533]: expected value, found struct variant `E::I32`
--> src/main.rs:2:21
|
2 | ($e: path) => { $e { v: 42 } }
| ^^ not a value
...
6 | let s = create_instance!(E::I32);
| ------------------------ in this macro invocation
|
= note: this error originates in the macro `create_instance` (in Nightly builds, run with -Z macro-backtrace for more info)
Why is this happening? Maybe it's a hygiene thing? Is there a way to overcome this in a declarative macro?
No, it's purely syntactic. (You could argue that hygiene is a purely syntactic concept, too – in which case my answer is "this is lower-level than hygiene".)
An expression-position macro must expand to something that looks like a complete, atomic expression in order to avoid ambiguities, so placing arbitrary trailing braces (that could denote a block, the body of a trait, etc.) at the end is not allowed.
When in doubt, use more indirection: you can always work around this by wrapping the thing into a block or parentheses, either of which will cause it to become a single token tree that yields the inner value.
However, if you do that (slightly modified Playground), you'll get an error about a "struct literal body without a path".
(Now I think that may actually be hygiene kicking in: the identifier for the path comes from the call site, while its fields come from the macro expansion.) No it's still not hygiene; if you send the field name from the caller too, it still doesn't work.
I don't know how to fix this; I'd probably scrap the current approach and write a proc-macro or do it with a function/trait, at runtime.