type T
and macro T
coexisting is quite common as well. The most common case is that #[derive(T)]
uses T
from the macro namespace. Perhaps you're willing to replace "cannot construct trait T
with an object literal" errors with "no macro T
in scope," but this is a downside.
Also, while the most common, it's not the only case where macro and type name deliberately collide. When writing a macro which expands to a type name, it's typical to case the macro name as a type. All notable cases I can think of off the top of my head don't actually use the same name (e.g. tstr has TS!
/TStr
, frunk has Coprod!
/Coproduct
), but I know I've seen it done.
Then there's the human ambiguity to consider. It doesn't matter all that much whether the compiler can figure out how to parse a code snippet — code is structured first for the human. When I see nonkeyword { … }
today, I know that this is a struct literal for a type nonkeyword
. If it could be a macro, I have to determine where the name nonkeyword
comes from (which could even be hidden by a use crate::glob::*
import) to determine if this is a struct literal or a macro with potentially arbitrary semantics.
Rust has a very hardline stance forbidding breaking changes in all but exceptional cases. Removing !
from arbitrary macro calls doesn't get anywhere close. The better option is to provide less powerful options that don't need the !
warning of arbitrary syntax, but it's quite contentious where exactly the line for requiring !
should be drawn. (I've argued the line should be based on control flow, but the permissive type inference proposed there is enough for several people to say it should require the !
and all the other permissions that come with it.)