9

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

puritii
  • 1,069
  • 1
  • 7
  • 18
  • I'm guessing its a guard for reference types or other ambiguities, since `<&T>::func()` and `&T::func()` are different things. – kmdreko Feb 20 '21 at 00:01
  • Hmm, I don't think so -- it's matched as `ty`, not `expr`, so even if it were `&T` it couldn't be reparsed as a (partial) expression. – trent Feb 20 '21 at 00:14

1 Answers1

15

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.

Jeff Garrett
  • 5,863
  • 1
  • 13
  • 12
  • Makes sense. I wonder if the special case allowing `u8` to be used as a path is documented anywhere? I tested with `$a:path` but while the macro compiled, I wasn't able to pass bare `u8` to it, so it must be contextual somehow. – trent Feb 20 '21 at 11:03
  • I bet you're encountering 48067. I'll edit. – Jeff Garrett Feb 20 '21 at 17:51
  • Yeah, that must be it. I learned two things today. – trent Feb 20 '21 at 18:03
  • Me too. I didn't find directly relevant documentation, but the issues did help ( https://github.com/rust-lang/rust/issues/52307 and issues/PRs linked from there) – Jeff Garrett Feb 20 '21 at 18:13