forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of rust-lang#73670 - davidhewitt:format-args-capture, r=…
…varkor Add `format_args_capture` feature This is the initial implementation PR for [RFC 2795](rust-lang/rfcs#2795). Note that, as dicussed in the tracking issue (rust-lang#67984), the feature gate has been called `format_args_capture`. Next up I guess I need to add documentation for this feature. I've not written any docs before for rustc / std so I would appreciate suggestions on where I should add docs.
- Loading branch information
Showing
13 changed files
with
303 additions
and
5 deletions.
There are no files selected for viewing
47 changes: 47 additions & 0 deletions
47
src/doc/unstable-book/src/library-features/format-args-capture.md
This file contains 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,47 @@ | ||
# `format_args_capture` | ||
|
||
The tracking issue for this feature is: [#67984] | ||
|
||
[#67984]: https://github.com/rust-lang/rust/issues/67984 | ||
|
||
------------------------ | ||
|
||
Enables `format_args!` (and macros which use `format_args!` in their implementation, such | ||
as `format!`, `print!` and `panic!`) to capture variables from the surrounding scope. | ||
This avoids the need to pass named parameters when the binding in question | ||
already exists in scope. | ||
|
||
```rust | ||
#![feature(format_args_capture)] | ||
|
||
let (person, species, name) = ("Charlie Brown", "dog", "Snoopy"); | ||
|
||
// captures named argument `person` | ||
print!("Hello {person}"); | ||
|
||
// captures named arguments `species` and `name` | ||
format!("The {species}'s name is {name}."); | ||
``` | ||
|
||
This also works for formatting parameters such as width and precision: | ||
|
||
```rust | ||
#![feature(format_args_capture)] | ||
|
||
let precision = 2; | ||
let s = format!("{:.precision$}", 1.324223); | ||
|
||
assert_eq!(&s, "1.32"); | ||
``` | ||
|
||
A non-exhaustive list of macros which benefit from this functionality include: | ||
- `format!` | ||
- `print!` and `println!` | ||
- `eprint!` and `eprintln!` | ||
- `write!` and `writeln!` | ||
- `panic!` | ||
- `unreachable!` | ||
- `unimplemented!` | ||
- `todo!` | ||
- `assert!` and similar | ||
- macros in many thirdparty crates, such as `log` |
This file contains 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
This file contains 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
This file contains 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
This file contains 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 |
---|---|---|
|
@@ -339,6 +339,7 @@ symbols! { | |
forbid, | ||
format_args, | ||
format_args_nl, | ||
format_args_capture, | ||
from, | ||
From, | ||
from_desugaring, | ||
|
This file contains 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,6 @@ | ||
fn main() { | ||
format!("{foo}"); //~ ERROR: there is no argument named `foo` | ||
|
||
// panic! doesn't hit format_args! unless there are two or more arguments. | ||
panic!("{foo} {bar}", bar=1); //~ ERROR: there is no argument named `foo` | ||
} |
This file contains 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,18 @@ | ||
error: there is no argument named `foo` | ||
--> $DIR/feature-gate-format-args-capture.rs:2:14 | ||
| | ||
LL | format!("{foo}"); | ||
| ^^^^^ | ||
| | ||
= help: if you intended to capture `foo` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes | ||
|
||
error: there is no argument named `foo` | ||
--> $DIR/feature-gate-format-args-capture.rs:5:13 | ||
| | ||
LL | panic!("{foo} {bar}", bar=1); | ||
| ^^^^^ | ||
| | ||
= help: if you intended to capture `foo` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes | ||
|
||
error: aborting due to 2 previous errors | ||
|
This file contains 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,6 @@ | ||
#![feature(format_args_capture)] | ||
|
||
fn main() { | ||
format!(concat!("{foo}")); //~ ERROR: there is no argument named `foo` | ||
format!(concat!("{ba", "r} {}"), 1); //~ ERROR: there is no argument named `bar` | ||
} |
This file contains 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,22 @@ | ||
error: there is no argument named `foo` | ||
--> $DIR/format-args-capture-macro-hygiene.rs:4:13 | ||
| | ||
LL | format!(concat!("{foo}")); | ||
| ^^^^^^^^^^^^^^^^ | ||
| | ||
= note: did you intend to capture a variable `foo` from the surrounding scope? | ||
= note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro | ||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error: there is no argument named `bar` | ||
--> $DIR/format-args-capture-macro-hygiene.rs:5:13 | ||
| | ||
LL | format!(concat!("{ba", "r} {}"), 1); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^ | ||
| | ||
= note: did you intend to capture a variable `bar` from the surrounding scope? | ||
= note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro | ||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error: aborting due to 2 previous errors | ||
|
This file contains 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,22 @@ | ||
#![feature(format_args_capture)] | ||
|
||
fn main() { | ||
format!("{} {foo} {} {bar} {}", 1, 2, 3); | ||
//~^ ERROR: cannot find value `foo` in this scope | ||
//~^^ ERROR: cannot find value `bar` in this scope | ||
|
||
format!("{foo}"); //~ ERROR: cannot find value `foo` in this scope | ||
|
||
format!("{valuea} {valueb}", valuea=5, valuec=7); | ||
//~^ ERROR cannot find value `valueb` in this scope | ||
//~^^ ERROR named argument never used | ||
|
||
format!(r##" | ||
{foo} | ||
"##); | ||
//~^^^^^ ERROR: cannot find value `foo` in this scope | ||
|
||
panic!("{foo} {bar}", bar=1); //~ ERROR: cannot find value `foo` in this scope | ||
} |
52 changes: 52 additions & 0 deletions
52
src/test/ui/fmt/format-args-capture-missing-variables.stderr
This file contains 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,52 @@ | ||
error: named argument never used | ||
--> $DIR/format-args-capture-missing-variables.rs:10:51 | ||
| | ||
LL | format!("{valuea} {valueb}", valuea=5, valuec=7); | ||
| ------------------- ^ named argument never used | ||
| | | ||
| formatting specifier missing | ||
|
||
error[E0425]: cannot find value `foo` in this scope | ||
--> $DIR/format-args-capture-missing-variables.rs:4:13 | ||
| | ||
LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); | ||
| ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | ||
|
||
error[E0425]: cannot find value `bar` in this scope | ||
--> $DIR/format-args-capture-missing-variables.rs:4:13 | ||
| | ||
LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); | ||
| ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | ||
|
||
error[E0425]: cannot find value `foo` in this scope | ||
--> $DIR/format-args-capture-missing-variables.rs:8:13 | ||
| | ||
LL | format!("{foo}"); | ||
| ^^^^^^^ not found in this scope | ||
|
||
error[E0425]: cannot find value `valueb` in this scope | ||
--> $DIR/format-args-capture-missing-variables.rs:10:13 | ||
| | ||
LL | format!("{valuea} {valueb}", valuea=5, valuec=7); | ||
| ^^^^^^^^^^^^^^^^^^^ not found in this scope | ||
|
||
error[E0425]: cannot find value `foo` in this scope | ||
--> $DIR/format-args-capture-missing-variables.rs:14:13 | ||
| | ||
LL | format!(r##" | ||
| _____________^ | ||
LL | | | ||
LL | | {foo} | ||
LL | | | ||
LL | | "##); | ||
| |_______^ not found in this scope | ||
|
||
error[E0425]: cannot find value `foo` in this scope | ||
--> $DIR/format-args-capture-missing-variables.rs:21:12 | ||
| | ||
LL | panic!("{foo} {bar}", bar=1); | ||
| ^^^^^^^^^^^^^ not found in this scope | ||
|
||
error: aborting due to 7 previous errors | ||
|
||
For more information about this error, try `rustc --explain E0425`. |
This file contains 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,62 @@ | ||
// run-pass | ||
#![feature(format_args_capture)] | ||
|
||
fn main() { | ||
named_argument_takes_precedence_to_captured(); | ||
panic_with_single_argument_does_not_get_formatted(); | ||
panic_with_multiple_arguments_is_formatted(); | ||
formatting_parameters_can_be_captured(); | ||
} | ||
|
||
fn named_argument_takes_precedence_to_captured() { | ||
let foo = "captured"; | ||
let s = format!("{foo}", foo="named"); | ||
assert_eq!(&s, "named"); | ||
|
||
let s = format!("{foo}-{foo}-{foo}", foo="named"); | ||
assert_eq!(&s, "named-named-named"); | ||
|
||
let s = format!("{}-{bar}-{foo}", "positional", bar="named"); | ||
assert_eq!(&s, "positional-named-captured"); | ||
} | ||
|
||
fn panic_with_single_argument_does_not_get_formatted() { | ||
// panic! with a single argument does not perform string formatting. | ||
// RFC #2795 suggests that this may need to change so that captured arguments are formatted. | ||
// For stability reasons this will need to part of an edition change. | ||
|
||
let msg = std::panic::catch_unwind(|| { | ||
panic!("{foo}"); | ||
}).unwrap_err(); | ||
|
||
assert_eq!(msg.downcast_ref::<&str>(), Some(&"{foo}")) | ||
} | ||
|
||
fn panic_with_multiple_arguments_is_formatted() { | ||
let foo = "captured"; | ||
|
||
let msg = std::panic::catch_unwind(|| { | ||
panic!("{}-{bar}-{foo}", "positional", bar="named"); | ||
}).unwrap_err(); | ||
|
||
assert_eq!(msg.downcast_ref::<String>(), Some(&"positional-named-captured".to_string())) | ||
} | ||
|
||
fn formatting_parameters_can_be_captured() { | ||
let width = 9; | ||
let precision = 3; | ||
|
||
let x = 7.0; | ||
|
||
let s = format!("{x:width$}"); | ||
assert_eq!(&s, " 7"); | ||
|
||
let s = format!("{x:<width$}"); | ||
assert_eq!(&s, "7 "); | ||
|
||
let s = format!("{x:-^width$}"); | ||
assert_eq!(&s, "----7----"); | ||
|
||
let s = format!("{x:-^width$.precision$}"); | ||
assert_eq!(&s, "--7.000--"); | ||
} |
This file contains 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