From a2fc4ac43d404eb107554d8c87614abfa65fb145 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 14 Oct 2024 19:31:44 -0700 Subject: [PATCH 01/29] Macro fragment fields --- text/0000-macro-fragment-fields.md | 168 +++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 text/0000-macro-fragment-fields.md diff --git a/text/0000-macro-fragment-fields.md b/text/0000-macro-fragment-fields.md new file mode 100644 index 00000000000..f9a4191e346 --- /dev/null +++ b/text/0000-macro-fragment-fields.md @@ -0,0 +1,168 @@ +- Feature Name: `macro_fragment_fields` +- Start Date: 2024-10-14 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + +# Summary +[summary]: #summary + +Add a syntax and mechanism for macros to access "fields" of high-level fragment +specifiers that they've matched, to let macros use the Rust parser for +robustness and future compatibility, while still extracting pieces of the +matched syntax. + +# Motivation +[motivation]: #motivation + +The macros-by-example system is powerful, but sometimes difficult to work with. +In particular, parsing complex parts of Rust syntax often requires carefully +recreating large chunks of the Rust grammar, in order to parse out the desired +pieces. Missing or incorrectly handling any portion of the syntax can result in +not accepting the same syntax Rust does; this includes future extensions to +Rust syntax that the macro was not yet aware of. Higher-level fragment +specifiers are more robust for these cases, but don't allow extracting +individual pieces of the matched syntax. + +This RFC introduces a mechanism to use high-level fragment specifiers while +still extracting individual pieces of the matched syntax. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +When writing macros by example, and using certain high-level fragment +specifiers, you can use the syntax `${matched_name.field_name}` to extract +specific "fields" of the matched syntax. This allows you to use the Rust parser +for those high-level fragments, rather than having to recreate parts of the +Rust grammar in order to extract the specific pieces you want. Fields evaluate +to pieces of Rust syntax, suitable for substitution into the program or passing +to other macros for further processing. + +For example, the fragment `:adt` parses any abstract data type supported by +Rust: struct, union, or enum. Given a match `$t:adt`, you can obtain the name +of the matched type with `${t.name}`: + +```rust +macro_rules! get_name { + ($t:adt) => { println!("{}", stringify!(${t.name})); } +} + +fn main() { + let n1 = get_name!(struct S { field: u32 }); + let n2 = get_name!(enum E { V1, V2 = 42, V3(u8) }); + let n3 = get_name!(union U { u: u32, f: f32 }); + println!("{n3}{n1}{n2}"); // prints "USE" +} +``` + +An attempt to access a field that doesn't exist will produce a compilation +error on the macro definition, whether or not the specific macro rule gets +invoked. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +Fragment fields may be used in a macro transcriber anywhere the corresponding +fragment name could be used. They must follow the same rules for repetition +handling as the corresponding fragment (e.g. being used at the same level/kind +of repetition). + +This RFC introduces the following new fragment specifiers, with specified fields: + +- `:fn`: A function item. + - `name`: The name of the function, as an `ident`. + - `params`: The parameters of the function, not including the surrounding + parentheses. May be empty if the function has no parameters. + - `return_type`: The return type of the function, as a `ty`. Will be `()` if + the function has no explicitly specified return type. + - `body`: The body of the function, as a block (including the + surrounding braces). + - `vis`: The visibility of the function, as a `vis` (may be empty). +- `:adt`: An ADT (struct, union, or enum). + - `name`: The name of the ADT, as an `ident`. + +The tokens within fields have the spans of the corresponding tokens from the +source. If a token has no corresponding source (e.g. the `()` in `return_type` +for a `fn` with no explicitly specified return type) it will have the span of +the entire fragment the field came from. + +Mentioning a field of a fragment counts as a use of the fragment, for the +purposes of ensuring every fragment gets used at least once at the appropriate +level of repetition. + +This extends the grammar of macro metavariable expressions to allow using a dot +and identifier to access a field. + +# Drawbacks +[drawbacks]: #drawbacks + +This adds complexity to the macro system, in order to simplify macros in the +ecosystem. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +Rather than using field syntax, we could use function-like syntax in the style +of RFC 3086's macro metavariable expressions. However, field syntax seems like +a more natural fit for this concept. + +# Prior art +[prior-art]: #prior-art + +RFC 3086, for macro metavariable expressions, introduced a similar mechanism to +add helpers for macros to more easily process the contents of fragments. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +Is the handling of synthesized tokens reasonable? Should we choose the span +differently? + +# Future possibilities +[future-possibilities]: #future-possibilities + +This RFC proposes a few obvious useful fields, both for their own sake and to +serve as examples of the concept. There are many more fields we may want to +introduce in the future. This RFC intentionally proposes only a few fields, to +allow evaluating the RFC on the basis of the concept and proposed syntax rather +than every individual field proposal. If any individual proposed field proves +controversial or requires more extensive design, it should be removed and +deferred to a future RFC, rather than complicating this RFC with that more +extensive design. + +Some examples of *possible* fields, to be evaluated in the future: +- For `fn`, a field for the ABI. This could be a synthesized `"Rust"` for + functions without a specified ABI. +- For `adt` and `fn`, fields for the generics and bounds. We may want to + provide them exactly as specified, or we may want to combine the bounds from + both generics and where clauses. (This would work well together with a macro + metavariable expression to generate the appropriate `where` bounds for a + `derive`.) + +Some examples of additional fragment specifiers, to be evaluated in the future: +- `param` for a single function parameter. +- `field` for a single field of a `struct`, `union`, or struct-style enum + variant. +- `variant` for a single variant of an `enum` +- `doc` for a doc comment, with `head` and `body` fields (handled the same way + rustdoc does). + +Some of these have tensions between providing convenient fields and handling +variations of these fragments that can't provide those fields. We could handle +this via separate fragment specifiers for different variations, or by some +mechanism for conditionally handling fields that may not exist. The former +would be less robust against future variations, while the latter would be more +complex. + +If, in the future, we introduce fields whose values have fragment types that +themselves have fields, we should support nested field syntax. + +We may want to provide a macro metavariable function to extract syntax that has +specific attributes (e.g. derive helper attributes) attached to it. For +instance, a derive macro applied to a struct may want to get the fields that +have a specific helper attribute attached. + +If, in the future, we have a robust mechanism for compilation-time execution of +Rust or some subset of Rust, without requiring separately compiled proc macro +crates, we may want to use and extend that mechanism in preference to any +further complexity in the `macro_rules` system. However, such a mechanism seems +likely to be far in the future. From 1edb079507eaff3177217e09894897ee1fb77ee7 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 21 Oct 2024 14:26:16 +0800 Subject: [PATCH 02/29] RFC 3714 --- ...0-macro-fragment-fields.md => 3714-macro-fragment-fields.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename text/{0000-macro-fragment-fields.md => 3714-macro-fragment-fields.md} (98%) diff --git a/text/0000-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md similarity index 98% rename from text/0000-macro-fragment-fields.md rename to text/3714-macro-fragment-fields.md index f9a4191e346..0e476e9b9b9 100644 --- a/text/0000-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -1,6 +1,6 @@ - Feature Name: `macro_fragment_fields` - Start Date: 2024-10-14 -- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- RFC PR: [rust-lang/rfcs#3714](https://github.com/rust-lang/rfcs/pull/3714) - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) # Summary From 7fc82cd546e9b1737e52caf75a5e38fc70b9c3bf Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 21 Oct 2024 23:31:06 +0800 Subject: [PATCH 03/29] Improve spans for fields without corresponding tokens --- text/3714-macro-fragment-fields.md | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 0e476e9b9b9..2539ad42b83 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -72,8 +72,9 @@ This RFC introduces the following new fragment specifiers, with specified fields - `name`: The name of the function, as an `ident`. - `params`: The parameters of the function, not including the surrounding parentheses. May be empty if the function has no parameters. - - `return_type`: The return type of the function, as a `ty`. Will be `()` if - the function has no explicitly specified return type. + - `return_type`: The return type of the function, as a `ty`. If the function + has no explicitly specified return type, this will be `()`, with a span of + the closing parenthesis for the function arguments. - `body`: The body of the function, as a block (including the surrounding braces). - `vis`: The visibility of the function, as a `vis` (may be empty). @@ -82,8 +83,8 @@ This RFC introduces the following new fragment specifiers, with specified fields The tokens within fields have the spans of the corresponding tokens from the source. If a token has no corresponding source (e.g. the `()` in `return_type` -for a `fn` with no explicitly specified return type) it will have the span of -the entire fragment the field came from. +for a `fn` with no explicitly specified return type), the field definition +defines an appropriate span. Mentioning a field of a fragment counts as a use of the fragment, for the purposes of ensuring every fragment gets used at least once at the appropriate @@ -111,12 +112,6 @@ a more natural fit for this concept. RFC 3086, for macro metavariable expressions, introduced a similar mechanism to add helpers for macros to more easily process the contents of fragments. -# Unresolved questions -[unresolved-questions]: #unresolved-questions - -Is the handling of synthesized tokens reasonable? Should we choose the span -differently? - # Future possibilities [future-possibilities]: #future-possibilities From bbb2dd0dd729661e804971df4230ab28f9f787c8 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 22 Oct 2024 18:58:44 +0800 Subject: [PATCH 04/29] Rephrase some future work --- text/3714-macro-fragment-fields.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 2539ad42b83..6282207e25c 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -133,7 +133,8 @@ Some examples of *possible* fields, to be evaluated in the future: metavariable expression to generate the appropriate `where` bounds for a `derive`.) -Some examples of additional fragment specifiers, to be evaluated in the future: +Some examples of *possible* additional fragment specifiers, to be evaluated in +the future: - `param` for a single function parameter. - `field` for a single field of a `struct`, `union`, or struct-style enum variant. From 195f8a953327c0d03c4bcd895a9d123d24e6977e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 22 Oct 2024 05:05:25 -0700 Subject: [PATCH 05/29] Rephrase explanation of using fragment fields --- text/3714-macro-fragment-fields.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 6282207e25c..234e73902ea 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -86,9 +86,9 @@ source. If a token has no corresponding source (e.g. the `()` in `return_type` for a `fn` with no explicitly specified return type), the field definition defines an appropriate span. -Mentioning a field of a fragment counts as a use of the fragment, for the -purposes of ensuring every fragment gets used at least once at the appropriate -level of repetition. +Using a field of a fragment counts as a use of the fragment, for the purposes +of ensuring every fragment gets used at least once at the appropriate level of +repetition. This extends the grammar of macro metavariable expressions to allow using a dot and identifier to access a field. From 5d002f41bd26e388d2d94de1b2b357dba841cca4 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 22 Oct 2024 05:05:39 -0700 Subject: [PATCH 06/29] Define `param` using repetition, to allow users more flexibility without parsing --- text/3714-macro-fragment-fields.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 234e73902ea..8c3e3ce98b6 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -62,16 +62,21 @@ invoked. [reference-level-explanation]: #reference-level-explanation Fragment fields may be used in a macro transcriber anywhere the corresponding -fragment name could be used. They must follow the same rules for repetition -handling as the corresponding fragment (e.g. being used at the same level/kind -of repetition). +fragment name could be used. + +Fragment fields typically follow the same rules for repetition handling as the +corresponding fragment (e.g. being used at the same level/kind of repetition). +However, fragment fields that contain multiple items require one additional +level of repetition; see the `param` field of `:fn`, below. This RFC introduces the following new fragment specifiers, with specified fields: - `:fn`: A function item. - `name`: The name of the function, as an `ident`. - - `params`: The parameters of the function, not including the surrounding - parentheses. May be empty if the function has no parameters. + - `param`: The parameters of the function, presented as though captured by a + level of `*` repetition. For instance, you can write `$(${f.param}),*` to + get a comma-separated list of parameters, or `$(other_macro!(${f.param}))*` + to pass each parameter to another macro. - `return_type`: The return type of the function, as a `ty`. If the function has no explicitly specified return type, this will be `()`, with a span of the closing parenthesis for the function arguments. From 3e149490b27dd4c8be9de71d5c155066ac901de5 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 22 Oct 2024 05:10:38 -0700 Subject: [PATCH 07/29] Clarify that `:fn` is a definition, including a body --- text/3714-macro-fragment-fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 8c3e3ce98b6..32452e99ebc 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -71,7 +71,7 @@ level of repetition; see the `param` field of `:fn`, below. This RFC introduces the following new fragment specifiers, with specified fields: -- `:fn`: A function item. +- `:fn`: A function definition (including body). - `name`: The name of the function, as an `ident`. - `param`: The parameters of the function, presented as though captured by a level of `*` repetition. For instance, you can write `$(${f.param}),*` to From b032d5e36bc101016c6862534ed92f15e5c48220 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 22 Oct 2024 05:13:07 -0700 Subject: [PATCH 08/29] Future work: function declarations --- text/3714-macro-fragment-fields.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 32452e99ebc..28f530d187a 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -144,6 +144,8 @@ the future: - `field` for a single field of a `struct`, `union`, or struct-style enum variant. - `variant` for a single variant of an `enum` +- `fndecl` for a function declaration (rather than a definition), such as in a + trait or an extern block. - `doc` for a doc comment, with `head` and `body` fields (handled the same way rustdoc does). From df73c4530385567024cc61f3cae97f3d89ef8cb8 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 22 Oct 2024 05:35:04 -0700 Subject: [PATCH 09/29] Add more future possibilities --- text/3714-macro-fragment-fields.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 28f530d187a..ff1cd525fcc 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -137,6 +137,11 @@ Some examples of *possible* fields, to be evaluated in the future: both generics and where clauses. (This would work well together with a macro metavariable expression to generate the appropriate `where` bounds for a `derive`.) +- For `adt`, `fn`, and various others, a field for the doc comment, if any. +- For `block`, a field for the statements in the block. +- For `path`, a field for the segments in the path, and a field for the leading + `::` if any. +- For `lifetime`, a field for the lifetime identifier, without the `'`. Some examples of *possible* additional fragment specifiers, to be evaluated in the future: @@ -146,6 +151,12 @@ the future: - `variant` for a single variant of an `enum` - `fndecl` for a function declaration (rather than a definition), such as in a trait or an extern block. +- `trait` for a trait definition, with fields for functions and associated + types. +- `binop` for a binary operator expression, with fields for the operator and + the two operands. +- `match` for a match expression, with fields for the scrutinee and the arms. +- `match_arm` for one arm of a match, with fields for the pattern and the body. - `doc` for a doc comment, with `head` and `body` fields (handled the same way rustdoc does). From d6a5314e621524d550f6b6819fe536e6dacdfb5d Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 24 Oct 2024 14:57:53 -0700 Subject: [PATCH 10/29] Fix example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: René Kijewski --- text/3714-macro-fragment-fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index ff1cd525fcc..0bbf79d42c1 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -43,7 +43,7 @@ of the matched type with `${t.name}`: ```rust macro_rules! get_name { - ($t:adt) => { println!("{}", stringify!(${t.name})); } + ($t:adt) => { stringify!(${t.name}) } } fn main() { From d0ba412c7c4c0d39464ab5a887066d8d80b6bd1a Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 24 Oct 2024 14:59:39 -0700 Subject: [PATCH 11/29] Future possibilities: function qualifiers like `const` and `async` --- text/3714-macro-fragment-fields.md | 1 + 1 file changed, 1 insertion(+) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 0bbf79d42c1..cb8de38e34f 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -132,6 +132,7 @@ extensive design. Some examples of *possible* fields, to be evaluated in the future: - For `fn`, a field for the ABI. This could be a synthesized `"Rust"` for functions without a specified ABI. +- For `fn`, a field for qualifiers such as `const` and `async`. - For `adt` and `fn`, fields for the generics and bounds. We may want to provide them exactly as specified, or we may want to combine the bounds from both generics and where clauses. (This would work well together with a macro From 271c9c483a486dc7ee1a123852490f79d2990cdb Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 24 Oct 2024 15:00:41 -0700 Subject: [PATCH 12/29] Hedge a future possibility further --- text/3714-macro-fragment-fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index cb8de38e34f..d70800c81f1 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -132,7 +132,7 @@ extensive design. Some examples of *possible* fields, to be evaluated in the future: - For `fn`, a field for the ABI. This could be a synthesized `"Rust"` for functions without a specified ABI. -- For `fn`, a field for qualifiers such as `const` and `async`. +- For `fn`, one or more fields for qualifiers such as `const` and `async`. - For `adt` and `fn`, fields for the generics and bounds. We may want to provide them exactly as specified, or we may want to combine the bounds from both generics and where clauses. (This would work well together with a macro From 62bf518ab15c5f9ebacc12132803279a615f0035 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 24 Oct 2024 15:07:41 -0700 Subject: [PATCH 13/29] Expand on possible future handling of `param` --- text/3714-macro-fragment-fields.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index d70800c81f1..f6c68404579 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -146,7 +146,9 @@ Some examples of *possible* fields, to be evaluated in the future: Some examples of *possible* additional fragment specifiers, to be evaluated in the future: -- `param` for a single function parameter. +- `param` for a single function parameter, with fields for the pattern and the + type. (This would also need to handle cases like `...` in variadic functions, + and cases like `self`, perhaps by acting as if it was `self: Self`.) - `field` for a single field of a `struct`, `union`, or struct-style enum variant. - `variant` for a single variant of an `enum` From aacf8bab360a6eef2233b1038238966151490fbf Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 24 Oct 2024 15:09:31 -0700 Subject: [PATCH 14/29] Note that adding new fields to an existing matcher is forward-compatible --- text/3714-macro-fragment-fields.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index f6c68404579..94e56406650 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -98,6 +98,9 @@ repetition. This extends the grammar of macro metavariable expressions to allow using a dot and identifier to access a field. +Note that future versions of Rust can add new fields to an existing matcher; +doing so is a compatible change. + # Drawbacks [drawbacks]: #drawbacks From 2da993796064b06f455fccd592e7d709e79f9fa2 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 24 Oct 2024 15:11:25 -0700 Subject: [PATCH 15/29] Add `vis` for `:adt` --- text/3714-macro-fragment-fields.md | 1 + 1 file changed, 1 insertion(+) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 94e56406650..6adf1768df3 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -85,6 +85,7 @@ This RFC introduces the following new fragment specifiers, with specified fields - `vis`: The visibility of the function, as a `vis` (may be empty). - `:adt`: An ADT (struct, union, or enum). - `name`: The name of the ADT, as an `ident`. + - `vis`: The visibility of the ADT, as a `vis` (may be empty). The tokens within fields have the spans of the corresponding tokens from the source. If a token has no corresponding source (e.g. the `()` in `return_type` From 69a2c9af064afad6d5ed902741b2f500b0760843 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 24 Oct 2024 15:20:54 -0700 Subject: [PATCH 16/29] Discuss synthesis of tokens for fields --- text/3714-macro-fragment-fields.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 6adf1768df3..11b83bf9b1e 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -115,6 +115,12 @@ Rather than using field syntax, we could use function-like syntax in the style of RFC 3086's macro metavariable expressions. However, field syntax seems like a more natural fit for this concept. +Rather than synthesizing tokens for cases like `return_type`, we could make a +rule that we *never* provide tokens that aren't in the original source. +However, this would substantially limit usability of these fields in some +cases, and make macros harder to write. This RFC proposes, in general, that we +can synthesize tokens if necessary to provide useful values for fields. + # Prior art [prior-art]: #prior-art From 37893b4b87b3266fb7adbb4ab6b7a51c437299a1 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 24 Oct 2024 15:39:20 -0700 Subject: [PATCH 17/29] Future possibilities: add speculations about conditionally available fields --- text/3714-macro-fragment-fields.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 11b83bf9b1e..7d4cbfd0c34 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -180,6 +180,17 @@ mechanism for conditionally handling fields that may not exist. The former would be less robust against future variations, while the latter would be more complex. +We could handle conditionally available fields by presenting them as though +they have a repetition of `?`, which would allow expansions within `$(...)?`; +that would support simple conditional cases without much complexity. + +We could handle some other types of conditions by presenting "boolean"-like +fields as fields that expand to no tokens but do so under a repetition of `?`, +to allow writing conditionals like `$(${x.field} ...)?`. This would fit such +conditionals within existing macro concepts, but it may suffer from an unwanted +overabundance of cleverness, and may not be as easy to read as a dedicated +conditional construct. + If, in the future, we introduce fields whose values have fragment types that themselves have fields, we should support nested field syntax. From 39f750c21f5e47f5e5e8b70ec1206b56a272c557 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 12 Nov 2024 09:24:17 -0800 Subject: [PATCH 18/29] More speculative future possibilities --- text/3714-macro-fragment-fields.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 7d4cbfd0c34..4fd6ad68740 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -199,6 +199,13 @@ specific attributes (e.g. derive helper attributes) attached to it. For instance, a derive macro applied to a struct may want to get the fields that have a specific helper attribute attached. +We could have macro metavariable expressions that return structures values with +fields. + +We could allow macros to define new macro metavariable functions that can +return structured values. (This has high potential for complexity and would +need to be handled with care.) + If, in the future, we have a robust mechanism for compilation-time execution of Rust or some subset of Rust, without requiring separately compiled proc macro crates, we may want to use and extend that mechanism in preference to any From 2c885c148d8a756cb043c21a1fedc2d1efa86786 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 12 Nov 2024 10:05:28 -0800 Subject: [PATCH 19/29] Link RFC Co-authored-by: Vincenzo Palazzo --- text/3714-macro-fragment-fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 4fd6ad68740..bb4a10874c5 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -124,7 +124,7 @@ can synthesize tokens if necessary to provide useful values for fields. # Prior art [prior-art]: #prior-art -RFC 3086, for macro metavariable expressions, introduced a similar mechanism to +[RFC 3086](https://rust-lang.github.io/rfcs/3086-macro-metavar-expr.html), for macro metavariable expressions, introduced a similar mechanism to add helpers for macros to more easily process the contents of fragments. # Future possibilities From 39808970eb3d6e5b9103966eff539a4b992de39b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 12 Nov 2024 10:05:45 -0800 Subject: [PATCH 20/29] Word-wrap after merging suggestion --- text/3714-macro-fragment-fields.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index bb4a10874c5..07e6bb96387 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -124,8 +124,9 @@ can synthesize tokens if necessary to provide useful values for fields. # Prior art [prior-art]: #prior-art -[RFC 3086](https://rust-lang.github.io/rfcs/3086-macro-metavar-expr.html), for macro metavariable expressions, introduced a similar mechanism to -add helpers for macros to more easily process the contents of fragments. +[RFC 3086](https://rust-lang.github.io/rfcs/3086-macro-metavar-expr.html), for +macro metavariable expressions, introduced a similar mechanism to add helpers +for macros to more easily process the contents of fragments. # Future possibilities [future-possibilities]: #future-possibilities From 935694c06f82743e5262a3176a0a4022f9e60740 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 12 Nov 2024 10:06:25 -0800 Subject: [PATCH 21/29] Link RFC in more places --- text/3714-macro-fragment-fields.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 07e6bb96387..bf392a96a98 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -112,8 +112,9 @@ ecosystem. [rationale-and-alternatives]: #rationale-and-alternatives Rather than using field syntax, we could use function-like syntax in the style -of RFC 3086's macro metavariable expressions. However, field syntax seems like -a more natural fit for this concept. +of [RFC 3086](https://rust-lang.github.io/rfcs/3086-macro-metavar-expr.html) +macro metavariable expressions. However, field syntax seems like a more natural +fit for this concept. Rather than synthesizing tokens for cases like `return_type`, we could make a rule that we *never* provide tokens that aren't in the original source. From cb7570aed9f0dd4d749d11dbc4758dac61d29ef2 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 20 Nov 2024 04:05:16 -0800 Subject: [PATCH 22/29] Fix typo --- text/3714-macro-fragment-fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index bf392a96a98..3ac68c7ee39 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -201,7 +201,7 @@ specific attributes (e.g. derive helper attributes) attached to it. For instance, a derive macro applied to a struct may want to get the fields that have a specific helper attribute attached. -We could have macro metavariable expressions that return structures values with +We could have macro metavariable expressions that return structured values with fields. We could allow macros to define new macro metavariable functions that can From 185b8416e7251f222dc4e8b74e3fdef2df14e5a8 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 20 Nov 2024 04:47:25 -0800 Subject: [PATCH 23/29] More future possibilities --- text/3714-macro-fragment-fields.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 3ac68c7ee39..24d36107a04 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -196,6 +196,11 @@ conditional construct. If, in the future, we introduce fields whose values have fragment types that themselves have fields, we should support nested field syntax. +We should establish and document a pattern for how to start out by parsing +`$t:adt`, get `${t.name}`, and then handle the case where `$t` is a `struct` vs +the case where `$t` is an `enum`. This would benefit from having better +conditional syntax. + We may want to provide a macro metavariable function to extract syntax that has specific attributes (e.g. derive helper attributes) attached to it. For instance, a derive macro applied to a struct may want to get the fields that From 225773b71c0d62d596173d4ce6f4393240305372 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 20 Nov 2024 10:25:18 -0800 Subject: [PATCH 24/29] Add unresolved question about `return_type` --- text/3714-macro-fragment-fields.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 24d36107a04..9ad601d80d2 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -129,6 +129,16 @@ can synthesize tokens if necessary to provide useful values for fields. macro metavariable expressions, introduced a similar mechanism to add helpers for macros to more easily process the contents of fragments. +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +Should we synthesize an `()` for `return_type`, or should we treat it as an +optional field? + +We could also provide both (e.g. `.return_type` and `.opt_return_type`), or +provide a subfield of `.return_type` that contains only the type as written and +not any synthesized `()`. + # Future possibilities [future-possibilities]: #future-possibilities From 0ea7ea964dd8cc53b4847ac2cd520195bb29bbd9 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 20 Nov 2024 10:36:47 -0800 Subject: [PATCH 25/29] Future possibility: handle structs and tuples uniformly This gives an example of needing to synthesize tokens. --- text/3714-macro-fragment-fields.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 9ad601d80d2..d7550fbe83f 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -211,6 +211,12 @@ We should establish and document a pattern for how to start out by parsing the case where `$t` is an `enum`. This would benefit from having better conditional syntax. +We may want to have a fragment specifier or fields that allow treating a struct +or an enum variant uniformly, not caring whether it is tuple-style or +struct-style. This is another case study in needing synthesized tokens, since +we could present a tuple struct as though it were a struct with fields named +`0`, `1`, etc. + We may want to provide a macro metavariable function to extract syntax that has specific attributes (e.g. derive helper attributes) attached to it. For instance, a derive macro applied to a struct may want to get the fields that From 10413079cedbc0ccf0b1446f4f762bb07ce0489d Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 2 Dec 2024 13:14:51 -0800 Subject: [PATCH 26/29] Add unresolved question about process and delegation --- text/3714-macro-fragment-fields.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index d7550fbe83f..96e71ce4475 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -139,6 +139,10 @@ We could also provide both (e.g. `.return_type` and `.opt_return_type`), or provide a subfield of `.return_type` that contains only the type as written and not any synthesized `()`. +Should we develop a lighter-weight process for approving further macro +fragments or fragment fields? Should we delegate it to another team, such as +wg-macros? + # Future possibilities [future-possibilities]: #future-possibilities From bf3dca0b89a755e483e82c1a8fc17f7abf07ffad Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 2 Dec 2024 13:15:50 -0800 Subject: [PATCH 27/29] Wording tweak --- text/3714-macro-fragment-fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 96e71ce4475..eb9b1384835 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -139,7 +139,7 @@ We could also provide both (e.g. `.return_type` and `.opt_return_type`), or provide a subfield of `.return_type` that contains only the type as written and not any synthesized `()`. -Should we develop a lighter-weight process for approving further macro +Should we develop a lighter-weight process/policy for approving further macro fragments or fragment fields? Should we delegate it to another team, such as wg-macros? From a2f14aba20ccdf6e9aab4bfbac345dc93898aafb Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 2 Dec 2024 13:26:02 -0800 Subject: [PATCH 28/29] Add backquotes to clarify the type of `body` --- text/3714-macro-fragment-fields.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index eb9b1384835..209e1dacfc1 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -80,8 +80,8 @@ This RFC introduces the following new fragment specifiers, with specified fields - `return_type`: The return type of the function, as a `ty`. If the function has no explicitly specified return type, this will be `()`, with a span of the closing parenthesis for the function arguments. - - `body`: The body of the function, as a block (including the - surrounding braces). + - `body`: The body of the function, as a `block` (including the surrounding + braces). - `vis`: The visibility of the function, as a `vis` (may be empty). - `:adt`: An ADT (struct, union, or enum). - `name`: The name of the ADT, as an `ident`. From 2afc67e80571aa52de3a1ac4b1121c51e204d36b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 3 Feb 2025 21:51:58 +0100 Subject: [PATCH 29/29] Add null alternative --- text/3714-macro-fragment-fields.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/text/3714-macro-fragment-fields.md b/text/3714-macro-fragment-fields.md index 209e1dacfc1..fcfcd3dd1bc 100644 --- a/text/3714-macro-fragment-fields.md +++ b/text/3714-macro-fragment-fields.md @@ -111,6 +111,13 @@ ecosystem. # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives +We could do nothing, and leave parsing to third-party crates in the ecosystem. +This entails inherently less efficient re-parsing, requires duplicating a Rust +AST/grammar into one or more third-party crates (and keeping it up to date), +pushes people towards proc macros, increases the supply chains of many crates, +and requires macros to update (or update their dependencies) when Rust adds new +syntax. + Rather than using field syntax, we could use function-like syntax in the style of [RFC 3086](https://rust-lang.github.io/rfcs/3086-macro-metavar-expr.html) macro metavariable expressions. However, field syntax seems like a more natural