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


#1

Hi,

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/other.rs:30:13: 30:26 error: non-pattern macro in pattern position: concat_idents
src/other.rs:30       $(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)?


#2

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.


#3

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.