Rollup merge of #150897 - Unique-Usman:ua/debug, r=estebank
rustc_parse_format: improve diagnostics for unsupported debug = syntax
Detect Python-style f-string debug syntax in format strings and emit a
clear diagnostic explaining that it is not supported in Rust. When the
intended operation can be inferred, suggest the corresponding Rust
alternative (e.g. `dbg!` for `{x=}`).
This commit is contained in:
commit
af70d82355
8 changed files with 97 additions and 2 deletions
|
|
@ -678,6 +678,18 @@ pub(crate) enum InvalidFormatStringSuggestion {
|
|||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[suggestion(
|
||||
"use rust debug printing macro",
|
||||
code = "{replacement}",
|
||||
style = "verbose",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
UseRustDebugPrintingMacro {
|
||||
#[primary_span]
|
||||
macro_span: Span,
|
||||
replacement: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@ fn make_format_args(
|
|||
ecx: &mut ExtCtxt<'_>,
|
||||
input: MacroInput,
|
||||
append_newline: bool,
|
||||
macro_span: Span,
|
||||
) -> ExpandResult<Result<FormatArgs, ErrorGuaranteed>, ()> {
|
||||
let msg = "format argument must be a string literal";
|
||||
let unexpanded_fmt_span = input.fmtstr.span;
|
||||
|
|
@ -333,6 +334,23 @@ fn make_format_args(
|
|||
let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
|
||||
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::AddMissingColon { span });
|
||||
}
|
||||
parse::Suggestion::UseRustDebugPrintingMacro => {
|
||||
// This targets `println!("{=}", x);` and `println!("{0=}", x);`
|
||||
if let [arg] = args.all_args() {
|
||||
let expr_span = arg.expr.span;
|
||||
if let Ok(expr_snippet) = ecx.source_map().span_to_snippet(expr_span) {
|
||||
let replacement = format!("{}!({})", "dbg", expr_snippet);
|
||||
|
||||
let call_span = macro_span.source_callsite();
|
||||
e.sugg_ = Some(
|
||||
errors::InvalidFormatStringSuggestion::UseRustDebugPrintingMacro {
|
||||
macro_span: call_span,
|
||||
replacement,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let guar = ecx.dcx().emit_err(e);
|
||||
return ExpandResult::Ready(Err(guar));
|
||||
|
|
@ -1048,7 +1066,7 @@ fn expand_format_args_impl<'cx>(
|
|||
sp = ecx.with_def_site_ctxt(sp);
|
||||
ExpandResult::Ready(match parse_args(ecx, sp, tts) {
|
||||
Ok(input) => {
|
||||
let ExpandResult::Ready(mac) = make_format_args(ecx, input, nl) else {
|
||||
let ExpandResult::Ready(mac) = make_format_args(ecx, input, nl, sp) else {
|
||||
return ExpandResult::Retry(());
|
||||
};
|
||||
match mac {
|
||||
|
|
|
|||
|
|
@ -187,6 +187,9 @@ pub enum Suggestion {
|
|||
/// Add missing colon:
|
||||
/// `format!("{foo?}")` -> `format!("{foo:?}")`
|
||||
AddMissingColon(Range<usize>),
|
||||
/// Use Rust format string:
|
||||
/// `format!("{x=}")` -> `dbg!(x)`
|
||||
UseRustDebugPrintingMacro,
|
||||
}
|
||||
|
||||
/// The parser structure for interpreting the input format string. This is
|
||||
|
|
@ -462,6 +465,7 @@ impl<'input> Parser<'input> {
|
|||
('?', _) => self.suggest_format_debug(),
|
||||
('<' | '^' | '>', _) => self.suggest_format_align(c),
|
||||
(',', _) => self.suggest_unsupported_python_numeric_grouping(),
|
||||
('=', '}') => self.suggest_rust_debug_printing_macro(),
|
||||
_ => self.suggest_positional_arg_instead_of_captured_arg(arg),
|
||||
}
|
||||
}
|
||||
|
|
@ -871,6 +875,27 @@ impl<'input> Parser<'input> {
|
|||
}
|
||||
}
|
||||
|
||||
fn suggest_rust_debug_printing_macro(&mut self) {
|
||||
if let Some((range, _)) = self.consume_pos('=') {
|
||||
self.errors.insert(
|
||||
0,
|
||||
ParseError {
|
||||
description:
|
||||
"python's f-string debug `=` is not supported in rust, use `dbg(x)` instead"
|
||||
.to_owned(),
|
||||
note: Some(format!("to print `{{`, you can escape it using `{{{{`",)),
|
||||
label: "expected `}`".to_owned(),
|
||||
span: range,
|
||||
secondary_label: self
|
||||
.last_open_brace
|
||||
.clone()
|
||||
.map(|sp| ("because of this opening brace".to_owned(), sp)),
|
||||
suggestion: Suggestion::UseRustDebugPrintingMacro,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_format_align(&mut self, alignment: char) {
|
||||
if let Some((range, _)) = self.consume_pos(alignment) {
|
||||
self.errors.insert(
|
||||
|
|
|
|||
|
|
@ -88,4 +88,7 @@ raw { \n
|
|||
//~^ ERROR invalid format string: expected `}`, found `?`
|
||||
println!("{x,}, world!",);
|
||||
//~^ ERROR invalid format string: python's numeric grouping `,` is not supported in rust format strings
|
||||
|
||||
println!("{x=}");
|
||||
//~^ ERROR invalid format string: python's f-string debug `=` is not supported in rust, use `dbg(x)` instead
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,5 +198,15 @@ LL | println!("{x,}, world!",);
|
|||
|
|
||||
= note: to print `{`, you can escape it using `{{`
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
error: invalid format string: python's f-string debug `=` is not supported in rust, use `dbg(x)` instead
|
||||
--> $DIR/format-string-error-2.rs:92:17
|
||||
|
|
||||
LL | println!("{x=}");
|
||||
| - ^ expected `}` in format string
|
||||
| |
|
||||
| because of this opening brace
|
||||
|
|
||||
= note: to print `{`, you can escape it using `{{`
|
||||
|
||||
error: aborting due to 21 previous errors
|
||||
|
||||
|
|
|
|||
5
tests/ui/fmt/format-string-error-3.fixed
Normal file
5
tests/ui/fmt/format-string-error-3.fixed
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
//@ run-rustfix
|
||||
fn main() {
|
||||
let x = 32;
|
||||
dbg!(x); //~ ERROR invalid format string: python's f-string debug
|
||||
}
|
||||
5
tests/ui/fmt/format-string-error-3.rs
Normal file
5
tests/ui/fmt/format-string-error-3.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
//@ run-rustfix
|
||||
fn main() {
|
||||
let x = 32;
|
||||
println!("{=}", x); //~ ERROR invalid format string: python's f-string debug
|
||||
}
|
||||
17
tests/ui/fmt/format-string-error-3.stderr
Normal file
17
tests/ui/fmt/format-string-error-3.stderr
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
error: invalid format string: python's f-string debug `=` is not supported in rust, use `dbg(x)` instead
|
||||
--> $DIR/format-string-error-3.rs:4:16
|
||||
|
|
||||
LL | println!("{=}", x);
|
||||
| -^ expected `}` in format string
|
||||
| |
|
||||
| because of this opening brace
|
||||
|
|
||||
= note: to print `{`, you can escape it using `{{`
|
||||
help: use rust debug printing macro
|
||||
|
|
||||
LL - println!("{=}", x);
|
||||
LL + dbg!(x);
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue