more specifically: you can’t infer anything after an !, so it’s an “stopper” as far as the expression is concerned. whereas macros are “starters”.
we’d even be able to have foo!.bar macro syntax and not conflict with Magic!
(ofc, the compiler’s pattern matching doesn’t necessarily match our expectations of patterns… just because it can’t be ambiguous, doesn’t mean it can’t look ambiguous. but generally speaking you can tell foo!; and foo!(); etc apart - these aren’t visually ambiguous.)
basically, currently rust has “starters” and “middlers” (if I’m not missing anything). for starters:
ident, macro!(invokation), (tuple), [array]
for middlers:
[index], (call), .field_or_method, etc
(note that () and [] show up on both starters and middlers!)
and “stoppers” generally can’t be followed by either starters or middlers (except ; but that one is very special, so I don’t consider it a stopper.), whereas macro invokation requires a specific kind of middler (specifically, one of (), [] or {}) to validate.
(this is extremely difficult to explain in plain english and I’ve gone through like 5 or so iterations of this “starters middlers and enders” idea… then again, I don’t exactly write compilers/parsers for a living…)