SOLVED: Creating new variable names in a macro using concat_idents gives error



I’m trying to write a macro that will take in multiple objects, wrap them in RefCells and then later call methods on the wrapped objects using borrow_mut() on the RefCell. The wrapping RefCell would have the name ref_cell_$obj. It looks like this:

macro_rules! method (
  (pub $name:ident<$a:ty,$i:ty,$o:ty>, $self_:ident, [ $( $obj:ident ),* ] , $submac:ident!( $($args:tt)* )) => (
    pub fn $name( $self_: $a, i: $i ) -> nom::IResult<$i, $o> {
      use std::cell::RefCell;
      $(let concat_idents!(ref_cell_, $obj) =  RefCell::new($obj)),*;
      $submac!(i, $($args)*)

Presumably something in the $submac will eventually call a method on one of the $objs. But the error I’m getting with concat_idents is:

src/ 30:26 error: non-pattern macro in pattern position: concat_idents
src/       $(let concat_idents!(ref_cell_, $obj) =  RefCell::new($obj)),*;

Does anybody know what this means and how to get around it? I tried to wrap concat_idents in another macro that made it return a tuple like (concat_idents!(ref_cell_, $obj),) which the Rust Programming Book section on Macros says should count as a pattern, but it still gives the same error.

I even looked at the Rust source code around the error message, and it seems to check to see if the macro expands into a pattern (which is why I tried to make it expand into a tuple), but I clearly I don’t understand what it means by pattern.

Does anybody know how to do something like this (create new variables in a macro based on idents passed to the macro)?


You can’t. You just can’t. There is no work-around other than passing in every identifier you need as part of the macro invocation.

No, really.

Yes, that means concat_idents! is almost totally useless.

No, it’s a limitation of the macro system as a whole, not simply of concat_idents!.

Because concat_idents! expands to an expression, and you can’t have an expression in pattern or ident position (i.e. the name of a function/struct/trait/whatever).

Yes, you could do this with a syntax extension, because that lets you actually generate new identifiers and substitute them wherever you want, but that limits you to nightly compilers.

Yes, it sucks.


Thanks for the reply. That’s a bummer. For now I guess I’m just sticking with the user passing in the name of the struct they want to wrap and also passing in it’s RefCell wrapped name. I guess it’s not that bad.