Is there a way to define `match` labels using macros?

Viewed 92

I mean, see code

macro_rules! impls {
    () => {
        let a = "Hello, world!";
        println!("{}", match 7 {
            impls!{ 3 + 4, a }
            _ => unimplemented!()
        })
    };

    ($x:expr, $name:ident) => {
        ($x) => $name,
    }
}

fn main() {
    impls!{ }
}

As I think, impls!{ 3 + 4, a } should be (3 + 4) => a, but it's not. What's wrong? Compiler error:

error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
  --> src/main.rs:6:13
   |
5  |             impls!{ 3 + 4, a }
   |                               - expected one of `=>`, `if`, or `|`
6  |             _ => unimplemented!()
   |             ^ unexpected token
...
16 |     impls!{ }
   |     --------- in this macro invocation
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
2 Answers

That is not possible with declarative macros (it might be with procedural macros, I've very little experience with those so I do not know): per the documentation

Macros can expand to expressions, statements, items (including traits, impls, and foreign items), types, or patterns.

A match arm is not in and of itself a "Rust construct", it's a sub-item of a match expression (composed of a pattern, an optional guard expression and a body expression).

As a result, it can not be produced by a declarative macro.

While macros cannot expand to match arm, as said, it is still possible to use them for patterns:(playground)

struct A(usize);
struct B(f32);
macro_rules! impls {
    () => {
        let x =  A(3 + 4);
        println!("{}", match x {
            impls!{ A -> 7 } => "Hello,",
            _ => unimplemented!(),
        })
    };
    ($e:expr) => {
        let x =  B(4.0);
        println!("{}", match x {
            impls!{ B -> x } => if x==$e { "world!" } else {"None"},
        })
    };
    
    ($a:tt -> $x:tt) => { $a($x) };
}

fn main() {
    impls!{ }
    impls!{ 16f32.sqrt() }
    impls!{ }
    impls!{ 1.0 }
}
Related