J. Dunne
J. Dunne

Reputation: 157

Do Rust macros work inside trait definitions?

I can build structs and enums using macros but not traits. Is this a bug or something about how traits work that I am missing? Here is a simple example that fails to build:

macro_rules! fun{
  () => { fn hello(); }
}

macro_rules! full_fun{
  () => { fn hello(){} }
}

// Fails with:
// <anon>:13:8: 13:11 error: expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `fun`
// <anon>:13        fun!();
macro_rules! trait_macro{
  ($name:ident) => {
     pub trait $name {
       fun!();
     }
 }; 
}

macro_rules! struct_macro{
  ($name:ident) => {
     pub struct $name;

     impl $name {
       full_fun!();
     }
 };
}

// I can add functions to a Impl
struct_macro!{Monster}
// But I cannot add functions to a trait
trait_macro!{Monster}


fn main() {

}

Upvotes: 0

Views: 1252

Answers (2)

Chris Emerson
Chris Emerson

Reputation: 14021

According to the Rust documentation on macros, a macro can be expanded as:

  • zero or more items
  • zero or more methods,
  • an expression,
  • a statement, or
  • a pattern.

Your full_fun becomes a method, but I think a declaration inside a trait doesn't count. (I haven't found an exact reference, though).

Even if it were, it wouldn't help: due to the macro hygiene rules, the hello defined couldn't be referenced elsewhere, as it would effectively be a unique identifier different from any other - ie your fun!() macro would not be declaring the same function as is implemented by full_fun!().

Upvotes: 1

J. Dunne
J. Dunne

Reputation: 157

Macro inside trait expansion is currently not supported. The relevant AST code:

pub enum TraitItemKind {
    Const(P<Ty>, Option<P<Expr>>),
    Method(MethodSig, Option<P<Block>>),
    Type(TyParamBounds, Option<P<Ty>>),
}

As the error message states only one of const, extern, fn, type, or unsafe are expected as next token in a Trait.

Upvotes: 0

Related Questions