-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Declarative macro_rules!
derive macros
#3698
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
joshtriplett
wants to merge
40
commits into
rust-lang:master
Choose a base branch
from
joshtriplett:declarative-derive-macros
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+303
−0
Open
Changes from all commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
a3cd084
Declarative `macro_rules!` derive macros
joshtriplett 567411b
Give a more realistic example
joshtriplett f3f5de9
Add alternative about allowing direct invocation
joshtriplett 65b1053
Mention `$crate`
joshtriplett 923325f
Caching
joshtriplett ba77548
Clarify text about helper attributes
joshtriplett 8881b68
Future possibilities: Better error reporting
joshtriplett f195edf
Mention automatically_derived
joshtriplett c4b185b
Future possibilities: Error recovery
joshtriplett 7bcdf3b
Add drawbacks section mentioning impact on crate maintainers
joshtriplett 7e1d517
Expand future work
joshtriplett bf67d21
Future work: Namespacing helper attributes
joshtriplett 32d91b6
Future work: helpers for `where` bounds
joshtriplett 9faa8f4
Add unresolved question about avoid cascading errors due to missing i…
joshtriplett 5ee8fe0
Add unresolved question to make sure we don't have awful error messages
joshtriplett 8352b1c
Future work: helpers for higher-level concepts like struct fields
joshtriplett f797596
Add further steps about averting pressure on crate maintainers
joshtriplett 3526d7f
Copy a drawback to the unresolved questions section
joshtriplett ba7effc
Fix typo
joshtriplett d4702b8
Future work: unsafe derives
joshtriplett aaf9860
Future possibilities: parameters
joshtriplett c6a2d35
Example
joshtriplett a71fbf7
Elaborate on an alternative
joshtriplett cf8e13e
Add more future possibilities
joshtriplett d50dbff
Further discussion on future possibility of derives with parameters
joshtriplett c323473
Discuss syntax alternative: `derive(...)` rules, like RFC 3697's `att…
joshtriplett e088d55
Unresolved question: helper attribute namespacing and hygiene
joshtriplett 319ca10
Elaborate a future work item
joshtriplett 5be851f
Future possibilities: const Trait and similar
joshtriplett 07f297d
Updates from design meeting
joshtriplett 0bb3ea4
Future work: talk about namespaced, hygienic helper attributes
joshtriplett d38892f
Future work: suggest a possible naming lint
joshtriplett cae86ff
Add unsafe derive rules and corresponding syntax
joshtriplett 98aca06
Add reference-level explanation with grammar additions
joshtriplett d448d19
Remove future possibility of unsafe, now that it's in the RFC
joshtriplett 504fa8c
Update to use only `derive(unsafe(DangerousDeriveMacro))` to match RF…
joshtriplett 27215e7
Update prior art section
joshtriplett ded1ced
Expand the motivation section
joshtriplett 1a2c1a3
Move mention of `derive_alias` to future work
joshtriplett 6f674fa
Add additional motivation
joshtriplett File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,303 @@ | ||||||||||||||||||||||||||||||
- Feature Name: `declarative_derive_macros` | ||||||||||||||||||||||||||||||
- Start Date: 2024-09-20 | ||||||||||||||||||||||||||||||
- RFC PR: [rust-lang/rfcs#3698](https://github.com/rust-lang/rfcs/pull/3698) | ||||||||||||||||||||||||||||||
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# Summary | ||||||||||||||||||||||||||||||
[summary]: #summary | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Support implementing `derive(Trait)` via a `macro_rules!` macro. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# Motivation | ||||||||||||||||||||||||||||||
[motivation]: #motivation | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Many crates support deriving their traits with `derive(Trait)`. Today, this | ||||||||||||||||||||||||||||||
requires defining proc macros, in a separate crate, typically with several | ||||||||||||||||||||||||||||||
additional dependencies adding substantial compilation time, and typically | ||||||||||||||||||||||||||||||
guarded by a feature that users need to remember to enable. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
However, many common cases of derives don't require any more power than an | ||||||||||||||||||||||||||||||
ordinary `macro_rules!` macro. Supporting these common cases would allow many | ||||||||||||||||||||||||||||||
crates to avoid defining proc macros, reduce dependencies and compilation time, | ||||||||||||||||||||||||||||||
and provide these macros unconditionally without requiring the user to enable a | ||||||||||||||||||||||||||||||
feature. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
The [`macro_rules_attribute`](https://crates.io/crates/macro_rules_attribute) | ||||||||||||||||||||||||||||||
crate defines proc macros that allow invoking declarative macros as derives, | ||||||||||||||||||||||||||||||
demonstrating a demand for this. This feature would allow defining such derives | ||||||||||||||||||||||||||||||
without requiring proc macros at all, and would support the same invocation | ||||||||||||||||||||||||||||||
syntax as a proc macro. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
The derive feature of the crate has [various uses in the | ||||||||||||||||||||||||||||||
ecosystem](https://github.com/search?q=macro_rules_attribute%3A%3Aderive&type=code). | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
`derive` macros have a standard syntax that Rust users have come to expect for | ||||||||||||||||||||||||||||||
defining traits; this motivates providing users a way to invoke that mechanism | ||||||||||||||||||||||||||||||
for declarative macros. An attribute or a `macro_name!` invocation could serve | ||||||||||||||||||||||||||||||
the same purpose, but that would be less evocative than `derive(Trait)` for | ||||||||||||||||||||||||||||||
the purposes of making the purpose of the macro clear, and would additionally | ||||||||||||||||||||||||||||||
give the macro more power to rewrite the underlying definition. Derive macros | ||||||||||||||||||||||||||||||
simplify tools like rust-analyzer, which can know that a derive macro will | ||||||||||||||||||||||||||||||
never change the underlying item definition. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# Guide-level explanation | ||||||||||||||||||||||||||||||
[guide-level-explanation]: #guide-level-explanation | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
You can define a macro to implement `derive(MyTrait)` by defining a | ||||||||||||||||||||||||||||||
`macro_rules!` macro with one or more `derive()` rules. Such a macro can create | ||||||||||||||||||||||||||||||
new items based on a struct, enum, or union. Note that the macro can only | ||||||||||||||||||||||||||||||
append new items; it cannot modify the item it was applied to. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
For example: | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
```rust | ||||||||||||||||||||||||||||||
trait Answer { fn answer(&self) -> u32; } | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
macro_rules! Answer { | ||||||||||||||||||||||||||||||
// Simplified for this example | ||||||||||||||||||||||||||||||
derive() (struct $n:ident $_:tt) => { | ||||||||||||||||||||||||||||||
impl Answer for $n { | ||||||||||||||||||||||||||||||
fn answer(&self) -> u32 { 42 } | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#[derive(Answer)] | ||||||||||||||||||||||||||||||
struct Struct; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
fn main() { | ||||||||||||||||||||||||||||||
let s = Struct; | ||||||||||||||||||||||||||||||
assert_eq!(42, s.answer()); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
Comment on lines
+65
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: There seems to be a missed opportunity to have
Suggested change
|
||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Derive macros defined using `macro_rules!` follow the same scoping rules as | ||||||||||||||||||||||||||||||
any other macro, and may be invoked by any path that resolves to them. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
A derive macro may share the same path as a trait of the same name. For | ||||||||||||||||||||||||||||||
instance, the name `mycrate::MyTrait` can refer to both the `MyTrait` trait and | ||||||||||||||||||||||||||||||
the macro for `derive(MyTrait)`. This is consistent with existing derive | ||||||||||||||||||||||||||||||
macros. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
If a derive macro emits a trait impl for the type, it may want to add the | ||||||||||||||||||||||||||||||
[`#[automatically_derived]`](https://doc.rust-lang.org/reference/attributes/derive.html#the-automatically_derived-attribute) | ||||||||||||||||||||||||||||||
attribute, for the benefit of diagnostics. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
If a derive macro mistakenly emits the token stream it was applied to | ||||||||||||||||||||||||||||||
(resulting in a duplicate item definition), the error the compiler emits for | ||||||||||||||||||||||||||||||
the duplicate item should hint to the user that the macro was defined | ||||||||||||||||||||||||||||||
incorrectly, and remind the user that derive macros only append new items. | ||||||||||||||||||||||||||||||
joshtriplett marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
A `derive()` rule can be marked as `unsafe`: | ||||||||||||||||||||||||||||||
`unsafe derive() (...) => { ... }`. | ||||||||||||||||||||||||||||||
Invoking such a derive using a rule marked as `unsafe` | ||||||||||||||||||||||||||||||
requires `unsafe` derive syntax: | ||||||||||||||||||||||||||||||
`#[derive(unsafe(DangerousDeriveMacro))]` | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Invoking an unsafe derive rule without the unsafe derive syntax will produce a | ||||||||||||||||||||||||||||||
compiler error. Using the unsafe derive syntax without an unsafe derive will | ||||||||||||||||||||||||||||||
trigger an "unused unsafe" lint. (RFC 3715 defines the equivalent mechanism for | ||||||||||||||||||||||||||||||
proc macro derives.) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# Reference-level explanation | ||||||||||||||||||||||||||||||
[reference-level-explanation]: #reference-level-explanation | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
The grammar for macros is extended as follows: | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
> _MacroRule_ :\ | ||||||||||||||||||||||||||||||
> ( `unsafe`<sup>?</sup> `derive` `(` `)` )<sup>?</sup> _MacroMatcher_ `=>` _MacroTranscriber_ | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
The _MacroMatcher_ matches the entire construct the attribute was | ||||||||||||||||||||||||||||||
applied to, receiving precisely what a proc-macro-based attribute | ||||||||||||||||||||||||||||||
would in the same place. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
(The empty parentheses after `derive` reserve future syntax space | ||||||||||||||||||||||||||||||
for derives accepting arguments, at which time they'll be replaced | ||||||||||||||||||||||||||||||
by a second _MacroMatcher_ that matches the arguments.) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
A derive invocation that uses an `unsafe derive` rule will produce | ||||||||||||||||||||||||||||||
an error if invoked without using the `unsafe` derive syntax. A | ||||||||||||||||||||||||||||||
derive invocation that uses an `derive` rule (without `unsafe`) | ||||||||||||||||||||||||||||||
will trigger the "unused unsafe" lint if invoked using the `unsafe` | ||||||||||||||||||||||||||||||
derive syntax. A single derive macro may have both `derive` and | ||||||||||||||||||||||||||||||
`unsafe derive` rules, such as if only some invocations are unsafe. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
This grammar addition is backwards compatible: previously, a _MacroRule_ could | ||||||||||||||||||||||||||||||
only start with `(`, `[`, or `{`, so the parser can easily distinguish rules | ||||||||||||||||||||||||||||||
that start with `derive` or `unsafe`. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Adding `derive` rules to an existing macro is a semver-compatible change, | ||||||||||||||||||||||||||||||
though in practice, it will likely be uncommon. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
If a user invokes a macro as a derive and that macro does not have any `derive` | ||||||||||||||||||||||||||||||
rules, the compiler should give a clear error stating that the macro is not | ||||||||||||||||||||||||||||||
usable as a derive because it does not have any `derive` rules. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# Drawbacks | ||||||||||||||||||||||||||||||
[drawbacks]: #drawbacks | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
This feature will not be sufficient for *all* uses of proc macros in the | ||||||||||||||||||||||||||||||
ecosystem, and its existence may create social pressure for crate maintainers | ||||||||||||||||||||||||||||||
to switch even if the result is harder to maintain. We can and should attempt | ||||||||||||||||||||||||||||||
to avert and such pressure, such as by providing a post with guidance that | ||||||||||||||||||||||||||||||
crate maintainers can link to when responding to such requests. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Before stabilizing this feature, we should receive feedback from crate | ||||||||||||||||||||||||||||||
maintainers, and potentially make further improvements to `macro_rules` to make | ||||||||||||||||||||||||||||||
it easier to use for their use cases. This feature will provide motivation to | ||||||||||||||||||||||||||||||
evaluate many new use cases that previously weren't written using | ||||||||||||||||||||||||||||||
`macro_rules`, and we should consider quality-of-life improvements to better | ||||||||||||||||||||||||||||||
support those use cases. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# Rationale and alternatives | ||||||||||||||||||||||||||||||
joshtriplett marked this conversation as resolved.
Show resolved
Hide resolved
joshtriplett marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
[rationale-and-alternatives]: #rationale-and-alternatives | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Adding this feature will allow many crates in the ecosystem to drop their proc | ||||||||||||||||||||||||||||||
macro crates and corresponding dependencies, and decrease their build times. | ||||||||||||||||||||||||||||||
joshtriplett marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
This will also give derive macros access to the `$crate` mechanism to refer to | ||||||||||||||||||||||||||||||
the defining crate, which is simpler than mechanisms currently used in proc | ||||||||||||||||||||||||||||||
macros to achieve the same goal. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Macros defined this way can more easily support caching, as they cannot depend | ||||||||||||||||||||||||||||||
on arbitrary unspecified inputs. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Crates could instead define `macro_rules!` macros and encourage users to invoke | ||||||||||||||||||||||||||||||
them using existing syntax like `macroname! { ... }`, rather than using | ||||||||||||||||||||||||||||||
derives. This would provide the same functionality, but would not support the | ||||||||||||||||||||||||||||||
same syntax people are accustomed to, and could not maintain semver | ||||||||||||||||||||||||||||||
compatibility with an existing proc-macro-based derive. In addition, this would | ||||||||||||||||||||||||||||||
not preserve the property derive macros normally have that they cannot change | ||||||||||||||||||||||||||||||
the item they are applied to. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
A mechanism to define attribute macros would let people write attributes like | ||||||||||||||||||||||||||||||
`#[derive_mytrait]`, but that would not provide compatibility with existing | ||||||||||||||||||||||||||||||
derive syntax. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
We could allow `macro_rules!` derive macros to emit a replacement token stream. | ||||||||||||||||||||||||||||||
That would be inconsistent with the restriction preventing proc macros from | ||||||||||||||||||||||||||||||
doing the same, but it would give macros more capabilities, and simplify some | ||||||||||||||||||||||||||||||
use cases. Notably, that would make it easy for derive macros to re-emit a | ||||||||||||||||||||||||||||||
structure with another `derive` attached to it. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
We could allow directly invoking a `macro_rules!` derive macro as a | ||||||||||||||||||||||||||||||
function-like macro. This has the potential for confusion, given the | ||||||||||||||||||||||||||||||
append-only nature of derive macros versus the behavior of normal function-like | ||||||||||||||||||||||||||||||
macros. It might potentially be useful for code reuse, however. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
## Syntax alternatives | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Rather than using `derive()` rules, we could have `macro_rules!` macros use a | ||||||||||||||||||||||||||||||
`#[macro_derive]` attribute, similar to the `#[proc_macro_derive]` attribute | ||||||||||||||||||||||||||||||
used for proc macros. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
However, this would be inconsistent with `attr()` rules as defined in RFC 3697. | ||||||||||||||||||||||||||||||
This would also make it harder to add parameterized derives in the future (e.g. | ||||||||||||||||||||||||||||||
`derive(MyTrait(params))`). | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# Prior art | ||||||||||||||||||||||||||||||
[prior-art]: #prior-art | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
We have had proc-macro-based derive macros for a long time, and the ecosystem | ||||||||||||||||||||||||||||||
makes extensive use of them. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
The [`macro_rules_attribute`](https://crates.io/crates/macro_rules_attribute) | ||||||||||||||||||||||||||||||
crate defines proc macros that allow invoking declarative macros as derives, | ||||||||||||||||||||||||||||||
demonstrating a demand for this. This feature would allow defining such derives | ||||||||||||||||||||||||||||||
without requiring proc macros at all, and would support the same invocation | ||||||||||||||||||||||||||||||
syntax as a proc macro. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
The derive feature of the crate has [various uses in the | ||||||||||||||||||||||||||||||
ecosystem](https://github.com/search?q=macro_rules_attribute%3A%3Aderive&type=code). | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# Unresolved questions | ||||||||||||||||||||||||||||||
[unresolved-questions]: #unresolved-questions | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Before stabilizing this feature, we should ensure there's a mechanism macros | ||||||||||||||||||||||||||||||
can use to ensure that an error when producing an impl does not result in a | ||||||||||||||||||||||||||||||
cascade of additional errors caused by a missing impl. This may take the form | ||||||||||||||||||||||||||||||
of a fallback impl, for instance. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Before stabilizing this feature, we should make sure it doesn't produce wildly | ||||||||||||||||||||||||||||||
worse error messages in common cases. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Before stabilizing this feature, we should receive feedback from crate | ||||||||||||||||||||||||||||||
maintainers, and potentially make further improvements to `macro_rules` to make | ||||||||||||||||||||||||||||||
it easier to use for their use cases. This feature will provide motivation to | ||||||||||||||||||||||||||||||
evaluate many new use cases that previously weren't written using | ||||||||||||||||||||||||||||||
`macro_rules`, and we should consider quality-of-life improvements to better | ||||||||||||||||||||||||||||||
support those use cases. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Before stabilizing this feature, we should have clear public guidance | ||||||||||||||||||||||||||||||
recommending against pressuring crate maintainers to adopt this feature | ||||||||||||||||||||||||||||||
rapidly, and encourage crate maintainers to link to that guidance if such | ||||||||||||||||||||||||||||||
requests arise. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# Future possibilities | ||||||||||||||||||||||||||||||
[future-possibilities]: #future-possibilities | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
We should provide a way for derive macros to invoke other derive macros. The | ||||||||||||||||||||||||||||||
`macro_rules_attribute` crate includes a `derive_alias` mechanism, which we | ||||||||||||||||||||||||||||||
could trivially implement given a means of invoking another derive macro. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
We should provide a means to perform a `derive` on a struct without being | ||||||||||||||||||||||||||||||
directly attached to that struct. (This would also potentially require | ||||||||||||||||||||||||||||||
something like a compile-time reflection mechanism.) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
We could support passing parameters to derive macros (e.g. | ||||||||||||||||||||||||||||||
`#[derive(Trait(params), OtherTrait(other, params))]`). This may benefit from | ||||||||||||||||||||||||||||||
having `derive(...)` rules inside the `macro_rules!` macro declaration, similar | ||||||||||||||||||||||||||||||
to the `attr(...)` rules proposed in RFC 3697. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
In the future, if we support something like `const Trait` or similar trait | ||||||||||||||||||||||||||||||
modifiers, we'll want to support `derive(const Trait)`, and define how a | ||||||||||||||||||||||||||||||
`macro_rules!` derive handles that. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
We should provide a way for `macro_rules!` macros to provide better error | ||||||||||||||||||||||||||||||
reporting, with spans, rather than just pointing to the macro. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
We may want to support error recovery, so that a derive can produce an error | ||||||||||||||||||||||||||||||
but still provide enough for the remainder of the compilation to proceed far | ||||||||||||||||||||||||||||||
enough to usefully report further errors. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
As people test this feature and run into limitations of `macro_rules!` parsing, | ||||||||||||||||||||||||||||||
we should consider additional features to make this easier to use for various | ||||||||||||||||||||||||||||||
use cases. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
We could provide a macro matcher to match an entire struct field, along with | ||||||||||||||||||||||||||||||
syntax (based on macro metavariable expressions) to extract the field name or | ||||||||||||||||||||||||||||||
type (e.g. `${f.name}`). This would simplify many common cases by leveraging | ||||||||||||||||||||||||||||||
the compiler's own parser. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
We could do the same for various other high-level constructs. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
We may want to provide simple helpers for generating/propagating `where` | ||||||||||||||||||||||||||||||
bounds, which would otherwise be complex to do in a `macro_rules!` macro. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
We may want to add a lint for macro names, encouraging macros with derive rules | ||||||||||||||||||||||||||||||
to use `CamelCase` names, and encouraging macros without derive rules to use | ||||||||||||||||||||||||||||||
`snake_case` names. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
## Helper attribute namespacing and hygiene | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
We should provide a way for derive macros to define helper attributes ([inert | ||||||||||||||||||||||||||||||
attributes](https://doc.rust-lang.org/reference/attributes.html#active-and-inert-attributes) | ||||||||||||||||||||||||||||||
that exist for the derive macro to parse and act upon). Such attributes are | ||||||||||||||||||||||||||||||
supported by proc macro derives; however, such attributes have no namespacing, | ||||||||||||||||||||||||||||||
and thus currently represent compatibility hazards because they can conflict. | ||||||||||||||||||||||||||||||
We should provide a namespaced, hygienic mechanism for defining and using | ||||||||||||||||||||||||||||||
helper attributes. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
For instance, could we have `pub macro_helper_attr! skip` in the standard | ||||||||||||||||||||||||||||||
library, namespaced under `core::derives` or similar? Could we let macros parse | ||||||||||||||||||||||||||||||
that in a way that matches it in a namespaced fashion, so that: | ||||||||||||||||||||||||||||||
- If you write `#[core::derives::skip]`, the macro matches it | ||||||||||||||||||||||||||||||
- If you `use core::derives::skip;` and `write #[skip]`, the macro matches it | ||||||||||||||||||||||||||||||
- If you `use elsewhere::skip` (or no import at all) and write `#[skip]`, the | ||||||||||||||||||||||||||||||
macro *doesn't* match it. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
We already have *some* interaction between macros and name resolution, in order | ||||||||||||||||||||||||||||||
to have namespaced `macro_rules!` macros. Would something like this be feasible? | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
(We would still need to specify the exact mechanism by which macros match these | ||||||||||||||||||||||||||||||
helper attributes.) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.