Cartesian product using macros

If you're generating sequences of tokens to be given as input to another macro, then you're in for some pain.

The basics

Macro invocations like a!(b!()) are expanded from the outside only; first a! is expanded (receiving the literal tokens b ! ()), and then once that is finished, if any macro invocations are left in the output, those get expanded.

In other words, println!("{}", b!()) works precisely because it does not attempt to "eval" b!().

Getting around this limitation is... fun.

Uh... "fun"?

Here's a place where I used a cartesian product in one of my own macros. It gradually turns something like this...

// (note: in the source linked above this is written as
//  newtype_ops__!{@product::next(...) -> ()}
//  simply to avoid macro namespace pollution)
product_next!{ ({a b c} {A B}) -> () }

...into this...

product_next!{ ({A B}) -> (a) }
product_next!{ ({A B}) -> (b) }
product_next!{ ({A B}) -> (c) }

...into this...

product_next!{ () -> (a A) }
product_next!{ () -> (a B) }
product_next!{ () -> (b A) }
product_next!{ () -> (b B) }
product_next!{ () -> (c A) }
product_next!{ () -> (c B) }

...and then into this...

interpret!{ (a A) }
interpret!{ (a B) }
interpret!{ (b A) }
interpret!{ (b B) }
interpret!{ (c A) }
interpret!{ (c B) }

which then continues on with the next step. Note that for your use case you probably want the expansion to be more like this: (thankfully this is equally possible)

product_next!{ ({a b c} {A B}) -> (()) }
product_next!{         ({A B}) -> ((a) (b) (c)) }
product_next!{              () -> ((a A) (a B) (b A) (b B) (c A) (c B)) }
interpret!{ (a A) (a B) (b A) (b B) (c A) (c B) }

The key thing to notice here is that we never let a macro "finish". The product_next macro directly calls the interpret! macro. At all times, all of our partially built expressions are safely contained inside macro argument lists where they won't be evaluated.

Of course, this technique doesn't scale well. If you have n macros that need a cartesian product, you would need to implement the cartesian product n times! The alternative is to write one cartesian product macro which takes a callback; but I'd be cautious about making it too general, as it can be quite a grueling experience to debug.

One more thing

Comma-separated lists of token trees are just silly (individual token trees need no delimiters). You probably want $($T:ty),* if you're parsing types.