Add `|` to allowed macro separators

Since matches use the vertical bar as pattern separation it would be incredible if we could use it as a separator in macro.

expected one of: `*`, `+`, or `?`

For match arms in particular $( ... )|*(repetition with vertical bar as separator) this would be useful without using other macros only for repetition.

macro_rules! foo {
    ($($a:literal)|+) => {$($a)|+}
}

const a: u8 = foo!(0|0);

works just fine for me: Rust Playground

5 Likes

That's weird, I clearly tried that but it did not work

I though that you might just have outdated rustc version, but this seems to work even with rustc 1.0.0. I had to modify code a bit as :literal was not an option then, but $()|+ is fine:

macro_rules! foo {
    ($(($a:expr))|+) => {$($a)|+}
}

pub const A: u8 = foo!((0)|(0));

(Also changed constant name to A and made it pub so that there are zero warnings.)

You might have tried it with a :pat matcher, which doesn’t work because | is part of the pattern syntax.

It doesn’t really have anything to do with matches! or match; | is a pattern operator to combine multiple options into a single pattern, and parses in all positions that expect a pattern (though some disallow it later in the compilation process). For example:

use either::Either;

fn main() {
    let (Either::Left(x) | Either::Right(x)) = Either::Left(42);
    dbg!(x);
}
2 Likes

Yep, and they can probably use the :pat_param matcher instead.

5 Likes

Yes, :pat_param has been designed not to include | at its top-level, thereby making macros allow usage of | after it.

However, the problem does remain with :. Neither :pat, nor even :pat_param, allow for a : after it. This means that parsing fn or closure args/params using a more general pattern (rather than hard-coding $:tt or $($:ident)+) followed by type ascriptions, as mandated for fns, and allowed for closures, is outright not possible, even when using the matcher whose name hints at patterns-in-params...

There is specific reason for this, though: there's been discussion on making : Type part of the pattern syntax, to e.g. allow writing Wrapping(x: usize) in some positions instead of the more verbose Wrapping(x): Wrapping<usize>.

I don't recall what the temperature was the last time it was brought up (I think it was colder than when the "generalized type ascription" was first posted), but it hasn't been ruled out as a legitimate possibility.

It could probably be a reasonable minor addition to add a :param matcher for $pat_param: $ty…

1 Like

But x: usize there is a :pat, not a :pat_param, right?

I admit my "neither" phrasing was a poor choice, since I agree the door remains open for :pat. But having :pat_param in that same category does feel wrong, future-wise, and quite limiting, present-time :smile:

2 Likes

IIRC type ascription support is removed from compiler.

Type ascription was removed in expression contexts. What @CAD97 was talking about is im pattern context.

2 Likes