Macros help with weird error


#1

So I wanted to write a macro for faster and cleaner implementations of certain traits, however on the internet as I read about macros I still don’t understand what is wrong with mine and the compiler is not helping. So here is the macro:

macro_rules! auto_impl {
    ($trait_name:item , $method_name:item, $sym: ty , $int: ty) => {
        impl<'a> $trait_name<&'a $sym> for $int{
            type Output = $sym;
            fn $method_name(self, rhs: &'a $sym) -> Self::Output {
                rhs.add(self)
            }
        }
    }
}

And the compiler responds with:

Compiling symints v0.1.0 (file:///media/hdd/work/metadiff/symints)
error: expected one of `!` or `::`, found `,`
   --> src/lib.rs:966:15
    |
966 | auto_impl!(Add,add,SymMonomial,i64);
    |               ^

I’m invokcing it with:

auto_impl!(Add,add,SymMonomial,i64);

Could someone explain me what is going wrong and potentially ho to fix this?


#2

Your rule ($trait_name:item , $method_name:item, $sym: ty , $int: ty) requires an item in the first and second positions. So, the parser tries to parse an item starting with Add. The following things are items:

  • extern crate declarations
  • use declarations
  • modules
  • functions
  • type definitions
  • structs
  • enumerations
  • constant items
  • static items
  • traits
  • implementations
  • macros that expand into an item

Of those, the only thing that could possibly start with “Add” is a macro invocation, so that why it’s possibly expecting “!”. It’s possibly expecting “::” because (I think) you used to be able to specify macros by their full path, but that’s no longer the case.

You probably want to use “ident” instead of “item”. See the Macros chapter of the book for a list of possible fragment specifiers.


#3

Thanks, that sorted it out, but Add is a trait and as you said an item is suppose to match traits as well. Is there something I’m misunderstanding?


#4

The tokens are syntactic, not semantic. In this specific case, Add is an Ident and

trait Add {
  // impl here
}

is an Item


#5

Ah, I meant trait definiton.


#6

Ahh sorry, but that is slightly confusing in terms of how would the expression matcher match a whole definition. Could you give an example of a macro which would take this and how would the expression match it (just semantically feel free to write something that doesn’t compile I just want to understand, because clearly my understanding of the macro matcher is plainly wrong)


#7

Are you asking for an example of a macro that takes an item? Something like this?

macro_rules! put_item_in_mod (
    ($i:item) => (mod private { $i })
);

put_item_in_mod! {
    put_item_in_mod! {
        trait MyTrait {
            fn my_fn(&self);
        }
    }
}

use private::private::MyTrait;

#8

How about all the macros in newtype_derive and enum_derive?