Skip to content

Commit 140bb59

Browse files
committed
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 is a part of an effort toward #145718 Signed-off-by: Usman Akinyemi <usmanakinyemi202@gmail.com>
1 parent b0e65da commit 140bb59

6 files changed

Lines changed: 63 additions & 1 deletion

File tree

compiler/rustc_builtin_macros/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,5 @@ builtin_macros_unexpected_lit = expected path to a trait, found literal
316316
.other = for example, write `#[derive(Debug)]` for `Debug`
317317
318318
builtin_macros_unnameable_test_items = cannot test inner items
319+
320+
builtin_macros_use_rust_debug_printing_macro = use rust debug printing macro

compiler/rustc_builtin_macros/src/errors.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,19 @@ pub(crate) enum InvalidFormatStringSuggestion {
652652
#[primary_span]
653653
span: Span,
654654
},
655+
656+
#[multipart_suggestion(
657+
builtin_macros_use_rust_debug_printing_macro,
658+
style = "verbose",
659+
applicability = "machine-applicable"
660+
)]
661+
UseRustDebugPrintingMacro {
662+
#[suggestion_part(code = "dbg!(")]
663+
macro_span: Span,
664+
#[suggestion_part(code = "{{{ident}}}")]
665+
fmt_span: Span,
666+
ident: String,
667+
},
655668
}
656669

657670
#[derive(Diagnostic)]

compiler/rustc_builtin_macros/src/format.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,19 @@ fn make_format_args(
333333
let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
334334
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::AddMissingColon { span });
335335
}
336+
parse::Suggestion::UseRustDebugPrintingMacro(span) => {
337+
let fmt_span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
338+
339+
// Span of `format!` or `println!`
340+
// let ident =
341+
// let macro_span =
342+
343+
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::UseRustDebugPrintingMacro {
344+
macro_span,
345+
fmt_span,
346+
ident,
347+
});
348+
}
336349
}
337350
let guar = ecx.dcx().emit_err(e);
338351
return ExpandResult::Ready(Err(guar));

compiler/rustc_parse_format/src/lib.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ pub enum Suggestion {
187187
/// Add missing colon:
188188
/// `format!("{foo?}")` -> `format!("{foo:?}")`
189189
AddMissingColon(Range<usize>),
190+
/// Use Rust format string:
191+
/// `format!("{x=}")` -> `dbg!("{x}")`
192+
UseRustDebugPrintingMacro(Range<usize>),
190193
}
191194

192195
/// The parser structure for interpreting the input format string. This is
@@ -461,6 +464,7 @@ impl<'input> Parser<'input> {
461464
('?', '}') => self.missing_colon_before_debug_formatter(),
462465
('?', _) => self.suggest_format_debug(),
463466
('<' | '^' | '>', _) => self.suggest_format_align(c),
467+
('=', _) => self.suggest_rust_debug_printing_macro(),
464468
_ => self.suggest_positional_arg_instead_of_captured_arg(arg),
465469
}
466470
}
@@ -870,6 +874,25 @@ impl<'input> Parser<'input> {
870874
}
871875
}
872876

877+
fn suggest_rust_debug_printing_macro(&mut self) {
878+
if let Some((range, _)) = self.consume_pos('=') {
879+
let span = range.clone();
880+
self.errors.insert(
881+
0,
882+
ParseError {
883+
description: "expected `}`, found `=`".to_owned(),
884+
note: Some(format!("to print `{{`, you can escape it using `{{{{`",)),
885+
label:
886+
"python f-string debug `=` is not supported in rust, use `dbg(x)` instead"
887+
.to_owned(),
888+
span: range,
889+
secondary_label: None,
890+
suggestion: Suggestion::UseRustDebugPrintingMacro(span),
891+
},
892+
);
893+
}
894+
}
895+
873896
fn suggest_format_align(&mut self, alignment: char) {
874897
if let Some((range, _)) = self.consume_pos(alignment) {
875898
self.errors.insert(

tests/ui/fmt/format-string-error-2.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,7 @@ raw { \n
8686

8787
println!("{x?}, world!",);
8888
//~^ ERROR invalid format string: expected `}`, found `?`
89+
90+
println!("{x=}, world!",);
91+
//~^ ERROR invalid format string: expected `}`, found `=`
8992
}

tests/ui/fmt/format-string-error-2.stderr

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,5 +188,13 @@ LL | println!("{x?}, world!",);
188188
|
189189
= note: to print `{`, you can escape it using `{{`
190190

191-
error: aborting due to 19 previous errors
191+
error: invalid format string: expected `}`, found `=`
192+
--> $DIR/format-string-error-2.rs:90:17
193+
|
194+
LL | println!("{x=}, world!",);
195+
| ^ python f-string debug `=` is not supported in rust, use `dbg(x)` instead in format string
196+
|
197+
= note: to print `{`, you can escape it using `{{`
198+
199+
error: aborting due to 20 previous errors
192200

0 commit comments

Comments
 (0)