Macro path uses novel syntax


I think this is an oddity, that this compiles:

macro_rules! foo {
    ($x:path) => { $x() }

fn main() {
    let mut v = foo!(Vec<i32>::new);

playground link

It is odd because Vec<i32>::new is not valid syntax anywhere else. It’s either <Vec<i32>>::new (<Type>::method) or Vec::<i32>::new (path-like).


There are 3 kinds of path styles:

  • Module, generic parameters disallowed i.e. Result::Err. These styles of paths are used in:
    • Attributes #[path::attribute]
    • Macro invocations path::macro!()
    • Module reference (pub(restricted) and use)
  • Type, double-colons prohibited before generic parameters i.e. Result<T, U>::Err. These styles of paths are used in:
    • Type and trait references
    • Macros 1.0 :path
  • Expression, double-colons required before generic parameters i.e. Result::<T,U>::Err
    • Expressions
    • Patterns

(In a qualified path <P as Trait>::Q, if the whole path uses style X, the inner path P is also parsed using style X.)

The oddity is $x:path is parsed where a type is expected (i.e. Vec<i32>::new is parsed like an inner type called new inside the struct Vec<i32>). After a path is parsed the style information is thrown out, so it can be used like an expression $x(). This causes the strange syntax mismatch here.

I’m not sure if this is something Macros 2.0 (#![feature(decl_macro)]) is going to improve or worsen here, as I heard that $x there will eventually just mean the token stream Vec<i32>::new without any special meaning, so it will become a syntax error.


I think this can be “fixed” in the same way as

I.e. instead of three “styles” of paths described by @kennytm, there will be two styles of paths - “usual” paths with optional :: before <...> usable everywhere except for expressions, and “sorry but we need a disambiguator” paths with mandatory :: before <...> used in expressions.
Generic arguments in import/visibility/etc paths will be rejected by a semantic check and not by parser (this is already necessary, see

This way you will be able to pass any kinds of paths to macros and choose the variant that looks better / more natural, e.g. Vec::<i32>::new for methods (even if Vec<i32>::new will still be accepted).


I’ve found an interesting example while implementing this:


is parsed like a path segment with generic argument, similar to Fn(ArgType)!
So, it seems like an equivalent of PathStyle::Mod is still needed.