Allow "+" to follow path fragments in declarative macros

When writing a macro to match a type parameter, I ran into the requirement that paths must not be followed by a + character. Ideally the bound on the type could be matched with : $bound:path $(+ $bounds:path)*, but this is not allowed. It seems like allowing a + to occur here should not make the grammar ambiguous, or open Rust to future ambiguity if paths get changed, because a + is already used to separate bounds in the Rust grammar. Am I missing some compelling reason why + should not be allowed in this position?

1 Like

It might be because something like Fn() -> &dyn Error is also considered a path (yeah, I know, not the most intuitive thing.. but try it out), and terminating that with a + might be confusing.

That's a good idea! However, it looks like there's already a rule keeping it from being ambiguous.

macro_rules! check_if_path {
    { $a:path } => {}
}

check_if_path!{Fn() -> &dyn Error + 'a}

(Playground)

Errors with:

error: ambiguous `+` in a type
 --> src/lib.rs:5:25
  |
5 | check_if_path!{Fn() -> &dyn Error + 'a}
  |                         ^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(dyn Error + 'a)`

At the risk of going off topic...why is that considered a path?

Fn(Args..) -> Ret is syntax sugar for the type path ::core::ops::Fn::<Args=Args.., Result=Ret>. Writing the former would ideally be identical to writing the latter.

2 Likes

Not sure I particularly agree with it, but at least there's a valid reason :sweat_smile:

2 Likes

Paths are used in the grammar to specify trait bounds, which include Fn(Args) -> Ret syntax. See https://doc.rust-lang.org/reference/trait-bounds.html (the nonterminal is called TypePath).