Uh oh!
There was an error while loading. Please reload this page.
resolve: Introduce two sub-namespaces in macro namespace - #54069
Conversation
rust-highfive
commented
Sep 8, 2018
(rust_highfive has picked a reviewer for you, use r? to override) |
petrochenkov
commented
Sep 8, 2018
r? @alexcrichton |
Some alternatives:
|
eddyb
commented
Sep 8, 2018
Is this because derives are typically |
Centril
commented
Sep 8, 2018
So, 2 questions:
I would expect that to be the reason. |
Most likely.
Yes, that's orthogonal and still worth doing because other issues (#53481) arise due to derive helper attributes being very low-priority right now, but this PR fixes #53583 as well, just in another way.
In this code the macro call looks unambiguously "bang" syntactically, and the choice of namespace during resolution is driven by syntax, so this case shouldn't cause any problems. my_attr!{fn f(){}}In theory, such call could can pass the input tokens to the attribute macro in the same way as |
petrochenkov
commented
Sep 8, 2018
cc @dtolnay |
Centril
commented
Sep 8, 2018
I agree.
So I thought about this a bit and came up with the following example of where it would be useful: The proptest crate currently has a proptest!{
#[test]fn my_sorting_algo_works(xs:Vec<u8>){
...
}}Currently, this is just a #[proptest]fnmy_sorting_algo_works(xs:Vec<u8>){
...}However, the I suppose that you could do this by putting the attribute on a module (particularly if it has no name, e.g. |
petrochenkov
commented
Sep 9, 2018
bors
commented
Sep 9, 2018
☔ The latest upstream changes (presumably #53778) made this pull request unmergeable. Please resolve the merge conflicts. |
alexcrichton
commented
Sep 10, 2018
This seems like a solid solution to me and a solid implementation, would someone from @rust-lang/lang like to fcp to merge? |
aturon
commented
Sep 10, 2018
@rfcbot poll lang Please review this PR for merging prior to cutting beta |
Team member @aturon has asked teams: T-lang, for consensus on:
|
nikomatsakis
commented
Sep 10, 2018
On the topic of using In particular, I imagine that -- had decorators existed -- this is how |
nrc
commented
Sep 10, 2018
cc @djrenren - does this seem fine for CTFs? |
djrenren
commented
Sep 10, 2018
This looks great! The single macro namespace has been confusing and getting this landed with the stabilization of procmacro attributes seems like the right choice. |
Centril
commented
Sep 10, 2018
Probably yes; proptest!{
#![proptest_config(ProptestConfig{
fork:true,
timeout:1000,
.. ProptestConfig::default()})]fn first_test(n:u64){ ... }fn second_test(n:u64){ ... }}This reuses the same configuration for both tests; if you instead put With constCONFIG = ProptestConfig{ fork:true,timeout:1000, ..ProptestConfig::default()};#[proptest(CONFIG)]mod tests {// Ideally we would be able to remove `tests` from here and just write `mod { .. }` instead.fnfirst_test(n:u64){ ...}fnsecond_test(n:u64){ ...}}which seems just as, if not more ergonomic. All in all; I think this alternative is good enough to give up the ability to use |
petrochenkov
commented
Sep 10, 2018
I've updated #53913 with a mini-version of this PR that affects only the built-in attribute check and nothing else, so it is now unblocked. |
Centril
commented
Sep 10, 2018
@petrochenkov it is a known issue, but file this at https://github.com/anp/rfcbot-rs please. :) |
cramertj
commented
Sep 10, 2018
I've checked my box above, but with the reservation that we need to remember to re-resolve this discussion when it comes time to stabilize |
petrochenkov
commented
Sep 10, 2018
I think this door is still open. #[this_is_attr]macro mmm(){ ... }#[mmm]// OKstructS; |
cramertj
commented
Sep 10, 2018
@petrochenkov The question, I suppose, is whether you'd ever want a macro that worked in both positions. |
petrochenkov
commented
Sep 10, 2018
@cramertj |
petrochenkov
commented
Sep 11, 2018
Wait, actually no. #[this_is_both_bang_and_attr]macro mac(){ ... }#[mac]// OKstructS;mac!();// OKIn fact proc macro stubs behave exactly like this right now, because I was lazy and didn't refactor |
joshtriplett
commented
Sep 11, 2018
I'm a little concerned about doing this halfway, such that shadowing gets ignored but you can't actually have different macros of both types with the same name in the same module. Or have I misunderstood? |
petrochenkov
commented
Sep 11, 2018
Yes, that's correct.
I'd say it's half-bad vs bad in this case, since the primary motivation is compatibility and there's not much need in two new separate namespaces in isolation. |
joshtriplett
commented
Sep 13, 2018
As long as functional proc macros ( (Checked my box.) |
nikomatsakis
commented
Sep 13, 2018
Discussed briefly in the @rust-lang/lang meeting: General consensus was that we ought to split the namespace for "attribute macros" (aka decorators) like However, if this is forwards compatible with that universe -- and we believe it is -- then we should land this now and we can revisit the rest of it later. |
petrochenkov
commented
Sep 14, 2018
@nikomatsakis@Centril |
aturon
commented
Sep 14, 2018
@petrochenkov Yep! @bors r+ |
bors
commented
Sep 14, 2018
📌 Commit beb3b5d has been approved by |
bors
commented
Sep 14, 2018
resolve: Introduce two sub-namespaces in macro namespace
Two sub-namespaces are introduced in the macro namespace - one for bang macros and one for attribute-like macros (attributes, derives).
"Sub-namespace" means this is not a newly introduced full namespace, the single macro namespace is still in place.
I.e. you still can't define/import two macros with the same name in a single module, `use` imports still import only one name in macro namespace (from any sub-namespace) and not possibly two.
However, when we are searching for a name used in a `!` macro call context (`my_macro!()`) we skip attribute names in scope, and when we are searching for a name used in attribute context (`#[my_macro]`/`#[derive(my_macro)]`) we are skipping bang macro names in scope.
In other words, bang macros cannot shadow attribute macros and vice versa.
For a non-macro analogy, we could e.g. skip non-traits when searching for `MyTrait` in `impl MyTrait for Type { ... }`.
However we do not do it in non-macro namespaces because we don't have practical issues with e.g. non-traits shadowing traits with the same name, but with macros we do, especially after macro modularization.
For `#[test]` and `#[bench]` we have a hack in the compiler right now preventing their shadowing by `macro_rules! test` and similar things. This hack was introduced after making `#[test]`/`#[bench]` built-in macros instead of built-in attributes (#53410), something that needed to be done from the start since they are "active" attributes transforming their inputs.
Now they are passed through normal name resolution and can be shadowed, but that's a breaking change, so we have a special hack basically applying this PR for `#[test]` and `#[bench]` only.
Soon all potentially built-in attributes will be passed through normal name resolution (#53913) and that uncovers even more cases where the strict "macro namespace is a single namespace" rule needs to be broken.
For example, with strict rules, built-in macro `cfg!(...)` would shadow built-in attribute `#[cfg]` (they are different things), standard library macro `thread_local!(...)` would shadow built-in attribute `#[thread_local]` - both of these cases are covered by special hacks in #53913 as well.
Crater run uncovered more cases of attributes being shadowed by user-defined macros (`warn`, `doc`, `main`, even `deprecated`), we cannot add exceptions in the compiler for all of them.
Regressions with user-defined attributes like #53583 and #53898 also appeared after enabling macro modularization.
People are also usually confused (#53205 (comment), #53583 (comment)) when they see conflicts between attributes and non-attribute macros for the first time.
So my proposed solution is to solve this issue by introducing two sub-namespaces and thus skipping resolutions of the wrong kind and preventing more error-causing cases of shadowing.
Fixes#53583bors
commented
Sep 15, 2018
☀️ Test successful - status-appveyor, status-travis |
Two sub-namespaces are introduced in the macro namespace - one for bang macros and one for attribute-like macros (attributes, derives).
"Sub-namespace" means this is not a newly introduced full namespace, the single macro namespace is still in place.
I.e. you still can't define/import two macros with the same name in a single module,
useimports still import only one name in macro namespace (from any sub-namespace) and not possibly two.However, when we are searching for a name used in a
!macro call context (my_macro!()) we skip attribute names in scope, and when we are searching for a name used in attribute context (#[my_macro]/#[derive(my_macro)]) we are skipping bang macro names in scope.In other words, bang macros cannot shadow attribute macros and vice versa.
For a non-macro analogy, we could e.g. skip non-traits when searching for
MyTraitinimpl MyTrait for Type { ... }.However we do not do it in non-macro namespaces because we don't have practical issues with e.g. non-traits shadowing traits with the same name, but with macros we do, especially after macro modularization.
For
#[test]and#[bench]we have a hack in the compiler right now preventing their shadowing bymacro_rules! testand similar things. This hack was introduced after making#[test]/#[bench]built-in macros instead of built-in attributes (#53410), something that needed to be done from the start since they are "active" attributes transforming their inputs.Now they are passed through normal name resolution and can be shadowed, but that's a breaking change, so we have a special hack basically applying this PR for
#[test]and#[bench]only.Soon all potentially built-in attributes will be passed through normal name resolution (#53913) and that uncovers even more cases where the strict "macro namespace is a single namespace" rule needs to be broken.
For example, with strict rules, built-in macro
cfg!(...)would shadow built-in attribute#[cfg](they are different things), standard library macrothread_local!(...)would shadow built-in attribute#[thread_local]- both of these cases are covered by special hacks in #53913 as well.Crater run uncovered more cases of attributes being shadowed by user-defined macros (
warn,doc,main, evendeprecated), we cannot add exceptions in the compiler for all of them.Regressions with user-defined attributes like #53583 and #53898 also appeared after enabling macro modularization.
People are also usually confused (#53205 (comment), #53583 (comment)) when they see conflicts between attributes and non-attribute macros for the first time.
So my proposed solution is to solve this issue by introducing two sub-namespaces and thus skipping resolutions of the wrong kind and preventing more error-causing cases of shadowing.
Fixes#53583