-
Notifications
You must be signed in to change notification settings - Fork 72
Make format_args!() its own AST node (ast::ExprKind::FormatArgs) #541
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Labels
major-change
A proposal to make a major change to rustc
major-change-accepted
A major change proposal that was accepted
T-compiler
Add this label so rfcbot knows to poll the compiler team
Comments
This issue is not meant to be used for technical discussion. There is a Zulip stream for that. Use this issue to leave procedural comments, such as volunteering to review, indicating that you second the proposal (or third, etc), or raising a concern that you would like to be addressed. cc @rust-lang/compiler @rust-lang/compiler-contributors |
50 tasks
@rustbot second |
@rustbot label -final-comment-period +major-change-accepted |
bors
added a commit
to rust-lang-ci/rust
that referenced
this issue
Sep 28, 2022
Rewrite and refactor format_args!() builtin macro. This is a near complete rewrite of `compiler/rustc_builtin_macros/src/format.rs`. This gets rid of the massive unmaintanable [`Context` struct](https://github.com/rust-lang/rust/blob/76531befc4b0352247ada67bd225e8cf71ee5686/compiler/rustc_builtin_macros/src/format.rs#L176-L263), and splits the macro expansion into three parts: 1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax, but doesn't parse the template (the literal) itself. 2. Second, `make_format_args` will parse the template, the format options, resolve argument references, produce diagnostics, and turn the whole thing into a `FormatArgs` structure. 3. Finally, `expand_parsed_format_args` will turn that `FormatArgs` structure into the expression that the macro expands to. In other words, the `format_args` builtin macro used to be a hard-to-maintain 'single pass compiler', which I've split into a three phase compiler with a parser/tokenizer (step 1), semantic analysis (step 2), and backend (step 3). (It's compilers all the way down. ^^) This can serve as a great starting point for rust-lang#99012, which will only need to change the implementation of 3, while leaving step 1 and 2 unchanged. It also makes rust-lang/compiler-team#541 easier, which could then upgrade the new `FormatArgs` struct to an `ast` node and remove step 3, moving that step to later in the compilation process. It also fixes a few diagnostics bugs. This also [significantly reduces](https://gist.github.com/m-ou-se/b67b2d54172c4837a5ab1b26fa3e5284) the amount of generated code for cases with arguments in non-default order without formatting options, like `"{1} {0}"` or `"{a} {}"`, etc.
bors
added a commit
to rust-lang-ci/rust
that referenced
this issue
Jan 26, 2023
Move format_args!() into AST (and expand it during AST lowering) Implements rust-lang/compiler-team#541 This moves FormatArgs from rustc_builtin_macros to rustc_ast_lowering. For now, the end result is the same. But this allows for future changes to do smarter things with format_args!(). It also allows Clippy to directly access the ast::FormatArgs, making things a lot easier. This change turns the format args types into lang items. The builtin macro used to refer to them by their path. After this change, the path is no longer relevant, making it easier to make changes in `core`. This updates clippy to use the new language items, but this doesn't yet make clippy use the ast::FormatArgs structure that's now available. That should be done after this is merged.
flip1995
pushed a commit
to flip1995/rust-clippy
that referenced
this issue
Jan 27, 2023
Move format_args!() into AST (and expand it during AST lowering) Implements rust-lang/compiler-team#541 This moves FormatArgs from rustc_builtin_macros to rustc_ast_lowering. For now, the end result is the same. But this allows for future changes to do smarter things with format_args!(). It also allows Clippy to directly access the ast::FormatArgs, making things a lot easier. This change turns the format args types into lang items. The builtin macro used to refer to them by their path. After this change, the path is no longer relevant, making it easier to make changes in `core`. This updates clippy to use the new language items, but this doesn't yet make clippy use the ast::FormatArgs structure that's now available. That should be done after this is merged.
bors
added a commit
to rust-lang/miri
that referenced
this issue
Jan 31, 2023
Move format_args!() into AST (and expand it during AST lowering) Implements rust-lang/compiler-team#541 This moves FormatArgs from rustc_builtin_macros to rustc_ast_lowering. For now, the end result is the same. But this allows for future changes to do smarter things with format_args!(). It also allows Clippy to directly access the ast::FormatArgs, making things a lot easier. This change turns the format args types into lang items. The builtin macro used to refer to them by their path. After this change, the path is no longer relevant, making it easier to make changes in `core`. This updates clippy to use the new language items, but this doesn't yet make clippy use the ast::FormatArgs structure that's now available. That should be done after this is merged.
thomcc
pushed a commit
to tcdi/postgrestd
that referenced
this issue
May 31, 2023
Move format_args!() into AST (and expand it during AST lowering) Implements rust-lang/compiler-team#541 This moves FormatArgs from rustc_builtin_macros to rustc_ast_lowering. For now, the end result is the same. But this allows for future changes to do smarter things with format_args!(). It also allows Clippy to directly access the ast::FormatArgs, making things a lot easier. This change turns the format args types into lang items. The builtin macro used to refer to them by their path. After this change, the path is no longer relevant, making it easier to make changes in `core`. This updates clippy to use the new language items, but this doesn't yet make clippy use the ast::FormatArgs structure that's now available. That should be done after this is merged.
calebcartwright
pushed a commit
to calebcartwright/rustfmt
that referenced
this issue
Jun 20, 2023
Move format_args!() into AST (and expand it during AST lowering) Implements rust-lang/compiler-team#541 This moves FormatArgs from rustc_builtin_macros to rustc_ast_lowering. For now, the end result is the same. But this allows for future changes to do smarter things with format_args!(). It also allows Clippy to directly access the ast::FormatArgs, making things a lot easier. This change turns the format args types into lang items. The builtin macro used to refer to them by their path. After this change, the path is no longer relevant, making it easier to make changes in `core`. This updates clippy to use the new language items, but this doesn't yet make clippy use the ast::FormatArgs structure that's now available. That should be done after this is merged.
RalfJung
pushed a commit
to RalfJung/rust-analyzer
that referenced
this issue
Apr 20, 2024
Rewrite and refactor format_args!() builtin macro. This is a near complete rewrite of `compiler/rustc_builtin_macros/src/format.rs`. This gets rid of the massive unmaintanable [`Context` struct](https://github.com/rust-lang/rust/blob/76531befc4b0352247ada67bd225e8cf71ee5686/compiler/rustc_builtin_macros/src/format.rs#L176-L263), and splits the macro expansion into three parts: 1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax, but doesn't parse the template (the literal) itself. 2. Second, `make_format_args` will parse the template, the format options, resolve argument references, produce diagnostics, and turn the whole thing into a `FormatArgs` structure. 3. Finally, `expand_parsed_format_args` will turn that `FormatArgs` structure into the expression that the macro expands to. In other words, the `format_args` builtin macro used to be a hard-to-maintain 'single pass compiler', which I've split into a three phase compiler with a parser/tokenizer (step 1), semantic analysis (step 2), and backend (step 3). (It's compilers all the way down. ^^) This can serve as a great starting point for rust-lang/rust#99012, which will only need to change the implementation of 3, while leaving step 1 and 2 unchanged. It also makes rust-lang/compiler-team#541 easier, which could then upgrade the new `FormatArgs` struct to an `ast` node and remove step 3, moving that step to later in the compilation process. It also fixes a few diagnostics bugs. This also [significantly reduces](https://gist.github.com/m-ou-se/b67b2d54172c4837a5ab1b26fa3e5284) the amount of generated code for cases with arguments in non-default order without formatting options, like `"{1} {0}"` or `"{a} {}"`, etc.
RalfJung
pushed a commit
to RalfJung/rust-analyzer
that referenced
this issue
Apr 27, 2024
Rewrite and refactor format_args!() builtin macro. This is a near complete rewrite of `compiler/rustc_builtin_macros/src/format.rs`. This gets rid of the massive unmaintanable [`Context` struct](https://github.com/rust-lang/rust/blob/76531befc4b0352247ada67bd225e8cf71ee5686/compiler/rustc_builtin_macros/src/format.rs#L176-L263), and splits the macro expansion into three parts: 1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax, but doesn't parse the template (the literal) itself. 2. Second, `make_format_args` will parse the template, the format options, resolve argument references, produce diagnostics, and turn the whole thing into a `FormatArgs` structure. 3. Finally, `expand_parsed_format_args` will turn that `FormatArgs` structure into the expression that the macro expands to. In other words, the `format_args` builtin macro used to be a hard-to-maintain 'single pass compiler', which I've split into a three phase compiler with a parser/tokenizer (step 1), semantic analysis (step 2), and backend (step 3). (It's compilers all the way down. ^^) This can serve as a great starting point for rust-lang/rust#99012, which will only need to change the implementation of 3, while leaving step 1 and 2 unchanged. It also makes rust-lang/compiler-team#541 easier, which could then upgrade the new `FormatArgs` struct to an `ast` node and remove step 3, moving that step to later in the compilation process. It also fixes a few diagnostics bugs. This also [significantly reduces](https://gist.github.com/m-ou-se/b67b2d54172c4837a5ab1b26fa3e5284) the amount of generated code for cases with arguments in non-default order without formatting options, like `"{1} {0}"` or `"{a} {}"`, etc.
# for free
to join this conversation on GitHub.
Already have an account?
# to comment
Labels
major-change
A proposal to make a major change to rustc
major-change-accepted
A major change proposal that was accepted
T-compiler
Add this label so rfcbot knows to poll the compiler team
Proposal
I originally wrote about this idea here: rust-lang/rust#78356 (comment)
Today,
format_args!()
expands to a (often rather big) call expression offmt::Arguments::new…(…)
. Instead, I think it'd be better if it expanded to its own special AST node (e.g.ast::ExprKind::FormatArgs
), which is only lowered to the actualfmt::Argument::new
call in a later stage when the types and values of the arguments can be inspected (hir? mir?).This means it'll be much easier to implement optimizations like the ones I described in rust-lang/rust#78356: Flattening and simplifying
format_args!()
. Not only to make things likeformat_args!("a {}", "b")
compile down to the same code asformat_args!("a b")
(which const evaluation might also be able to achieve at some point), but also to makeformat_args!("a {} {}", "b", x)
compile down to the same asformat_args!("a b {}", x)
, and also to flatten nested format_args. For example, instead of needingformat_args_nl!(…)
, aformat_args!("{}\n", format_args!(…))
could result in the exact same code.These optimization possibilities remove the need for some bad use cases of concat!() we currently see in the ecosystem. A crate might have a
log!()
macro that expands to something likewrite!(log, concat!("info: ", first_arg, "\n"), other_args…)
, which has the unfortunate consequence thatlog!(1)
works, sinceconcat
converts that1
to"1"
implicitly. It also breaks implicit capturing likelog!("hello {name}")
. The "proper" solution is to instead expand towrite!(log, "info: {}\n", format_args!(all_args…))
, which, today, is far less efficient. (Which is the reason we haveformat_args_nl!()
today forprintln
.)Separately from the optimization possibilities, having an intermediate representation of a parsed
format_args!()
invocation (with all the numeric and named and implicitly captured placeholders 'resolved', after any lints/errors/etc.), makes it much easier to try out differentfmt::Arguments
implementations. Today, changing the structure/implementation offmt::Arguments
is quite a big task, since it requires changing large parts of the format_args builtin macro. This makes experimenting with new, more efficient, implementations harder than necessary, which is a bit of a blocker for rust-lang/rust#99012.In addition, it'd also make diagnostics/lints around formatting much easier, since a
format_args!()
invocation can be recognized as a single node, without having to pattern-match on the exact expansion of that macro. For example, check out Clippy's current code for recognizing format_args!(): https://github.com/rust-lang/rust-clippy/blob/97a0cf2de2367187c1f9eb9d9f6d333cb8bc8b8f/clippy_utils/src/macros.rs#L353-L552. Changing the implementation offmt::Arguments
also involves updating that part of Clippy at the same time, which adds even more resistance to any work on rust-lang/rust#99012.And as a bonus,
-Zunpretty=expanded
would be a lot less noisy if every println/format/format_args call didn't result in a huge unreadable expansion. Theast::ExprKind::FormatArgs
node would simply be displayed asformat_args!(…)
.cc @eddyb @oli-obk, I think I discussed this idea with both of you some time last year.
Mentors or Reviewers
If you have a reviewer or mentor in mind for this work, mention then
here. You can put your own name here if you are planning to mentor the
work.
Process
The main points of the Major Change Process are as follows:
@rustbot second
.-C flag
, then full team check-off is required.@rfcbot fcp merge
on either the MCP or the PR.You can read more about Major Change Proposals on forge.
Comments
This issue is not meant to be used for technical discussion. There is a Zulip stream for that. Use this issue to leave procedural comments, such as volunteering to review, indicating that you second the proposal (or third, etc), or raising a concern that you would like to be addressed.
The text was updated successfully, but these errors were encountered: