Why do I need angle brackets in <$a> when implementing macro based on type?

Viewed 689

I can implement a macro taking a type like this:

trait Boundable<A> {
    fn max_value() -> A;
}

impl Boundable<u8> for u8 {
    fn max_value() -> u8 { u8::MAX }
}

When I turn the impl into a macro, why do I need to surround the type itself with angle brackets, as in this?

macro_rules! impl_boundable {
    ($a:ty) => {
        impl Boundable<$a> for $a {
            fn max_value() -> $a { <$a>::MAX }
        }
    };
}

impl_boundable!(i8);

In particular, <$a>::MAX. Without it, the compiler gives me error missing angle brackets in associated item path. It puzzles me why the macro code needs to be different from the non-macro code.

playground

1 Answers

The syntax is _path_::item, not _type_::item. Valid paths include identifiers and <T> for types T.

In u8::MAX, the u8 is allowed because it is an identifier, not because it is a type. [u8; 1]::item is not allowed.

If your macro takes $a:ident, instead of $a:ty, it will work as is with types which are also identifiers like u8. But, accepting a type $a:ty, the generic way to make a path from a type is with angle brackets <$a>.

It is also an option for your macro to accept a path directly: $a:path. But you are likely to encounter bug #48067: the parser cannot figure out how to compose a path from smaller path segments. There is a workaround for this case in the ticket of use $a as base; base::MAX.

Related