Skip to content

Commit eacbe54

Browse files
authored
Rollup merge of #100667 - Xiretza:diag-structs-parser-ivd, r=davidtwco
Migrate "invalid variable declaration" errors to SessionDiagnostic After seeing the great blog post on Inside Rust, I decided to try my hand at this. Just one diagnostic for now to get used to the workflow and to check if this is the way to do it or if there are any problems.
2 parents 61a529d + e8499cf commit eacbe54

File tree

3 files changed

+50
-19
lines changed

3 files changed

+50
-19
lines changed

compiler/rustc_error_messages/locales/en-US/parser.ftl

+9
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,12 @@ parser_incorrect_use_of_await =
3232
parser_in_in_typo =
3333
expected iterable, found keyword `in`
3434
.suggestion = remove the duplicated `in`
35+
36+
parser_invalid_variable_declaration =
37+
invalid variable declaration
38+
39+
parser_switch_mut_let_order =
40+
switch the order of `mut` and `let`
41+
parser_missing_let_before_mut = missing keyword
42+
parser_use_let_not_auto = write `let` instead of `auto` to introduce a new variable
43+
parser_use_let_not_var = write `let` instead of `var` to introduce a new variable

compiler/rustc_parse/src/parser/diagnostics.rs

+29
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,35 @@ struct InInTypo {
334334
sugg_span: Span,
335335
}
336336

337+
#[derive(SessionDiagnostic)]
338+
#[error(parser::invalid_variable_declaration)]
339+
pub struct InvalidVariableDeclaration {
340+
#[primary_span]
341+
pub span: Span,
342+
#[subdiagnostic]
343+
pub sub: InvalidVariableDeclarationSub,
344+
}
345+
346+
#[derive(SessionSubdiagnostic)]
347+
pub enum InvalidVariableDeclarationSub {
348+
#[suggestion(
349+
parser::switch_mut_let_order,
350+
applicability = "maybe-incorrect",
351+
code = "let mut"
352+
)]
353+
SwitchMutLetOrder(#[primary_span] Span),
354+
#[suggestion(
355+
parser::missing_let_before_mut,
356+
applicability = "machine-applicable",
357+
code = "let mut"
358+
)]
359+
MissingLet(#[primary_span] Span),
360+
#[suggestion(parser::use_let_not_auto, applicability = "machine-applicable", code = "let")]
361+
UseLetNotAuto(#[primary_span] Span),
362+
#[suggestion(parser::use_let_not_var, applicability = "machine-applicable", code = "let")]
363+
UseLetNotVar(#[primary_span] Span),
364+
}
365+
337366
// SnapshotParser is used to create a snapshot of the parser
338367
// without causing duplicate errors being emitted when the `Parser`
339368
// is dropped.

compiler/rustc_parse/src/parser/stmt.rs

+12-19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN;
2-
use super::diagnostics::{AttemptLocalParseRecovery, Error};
2+
use super::diagnostics::{
3+
AttemptLocalParseRecovery, Error, InvalidVariableDeclaration, InvalidVariableDeclarationSub,
4+
};
35
use super::expr::LhsExpr;
46
use super::pat::RecoverComma;
57
use super::path::PathStyle;
@@ -58,28 +60,22 @@ impl<'a> Parser<'a> {
5860
if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) {
5961
self.bump();
6062
let mut_let_span = lo.to(self.token.span);
61-
self.struct_span_err(mut_let_span, "invalid variable declaration")
62-
.span_suggestion(
63-
mut_let_span,
64-
"switch the order of `mut` and `let`",
65-
"let mut",
66-
Applicability::MaybeIncorrect,
67-
)
68-
.emit();
63+
self.sess.emit_err(InvalidVariableDeclaration {
64+
span: mut_let_span,
65+
sub: InvalidVariableDeclarationSub::SwitchMutLetOrder(mut_let_span),
66+
});
6967
}
7068

7169
Ok(Some(if self.token.is_keyword(kw::Let) {
7270
self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
7371
} else if self.is_kw_followed_by_ident(kw::Mut) {
74-
self.recover_stmt_local(lo, attrs, "missing keyword", "let mut")?
72+
self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::MissingLet)?
7573
} else if self.is_kw_followed_by_ident(kw::Auto) {
7674
self.bump(); // `auto`
77-
let msg = "write `let` instead of `auto` to introduce a new variable";
78-
self.recover_stmt_local(lo, attrs, msg, "let")?
75+
self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotAuto)?
7976
} else if self.is_kw_followed_by_ident(sym::var) {
8077
self.bump(); // `var`
81-
let msg = "write `let` instead of `var` to introduce a new variable";
82-
self.recover_stmt_local(lo, attrs, msg, "let")?
78+
self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotVar)?
8379
} else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
8480
// We have avoided contextual keywords like `union`, items with `crate` visibility,
8581
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
@@ -217,13 +213,10 @@ impl<'a> Parser<'a> {
217213
&mut self,
218214
lo: Span,
219215
attrs: AttrWrapper,
220-
msg: &str,
221-
sugg: &str,
216+
subdiagnostic: fn(Span) -> InvalidVariableDeclarationSub,
222217
) -> PResult<'a, Stmt> {
223218
let stmt = self.recover_local_after_let(lo, attrs)?;
224-
self.struct_span_err(lo, "invalid variable declaration")
225-
.span_suggestion(lo, msg, sugg, Applicability::MachineApplicable)
226-
.emit();
219+
self.sess.emit_err(InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) });
227220
Ok(stmt)
228221
}
229222

0 commit comments

Comments
 (0)