Skip to content

Commit

Permalink
Rollup merge of rust-lang#100667 - Xiretza:diag-structs-parser-ivd, r…
Browse files Browse the repository at this point in the history
…=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.
  • Loading branch information
ChrisDenton authored Aug 20, 2022
2 parents e70de69 + e8499cf commit dedae00
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 19 deletions.
9 changes: 9 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/parser.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,12 @@ parser_incorrect_use_of_await =
parser_in_in_typo =
expected iterable, found keyword `in`
.suggestion = remove the duplicated `in`
parser_invalid_variable_declaration =
invalid variable declaration
parser_switch_mut_let_order =
switch the order of `mut` and `let`
parser_missing_let_before_mut = missing keyword
parser_use_let_not_auto = write `let` instead of `auto` to introduce a new variable
parser_use_let_not_var = write `let` instead of `var` to introduce a new variable
29 changes: 29 additions & 0 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,35 @@ struct InInTypo {
sugg_span: Span,
}

#[derive(SessionDiagnostic)]
#[error(parser::invalid_variable_declaration)]
pub struct InvalidVariableDeclaration {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub sub: InvalidVariableDeclarationSub,
}

#[derive(SessionSubdiagnostic)]
pub enum InvalidVariableDeclarationSub {
#[suggestion(
parser::switch_mut_let_order,
applicability = "maybe-incorrect",
code = "let mut"
)]
SwitchMutLetOrder(#[primary_span] Span),
#[suggestion(
parser::missing_let_before_mut,
applicability = "machine-applicable",
code = "let mut"
)]
MissingLet(#[primary_span] Span),
#[suggestion(parser::use_let_not_auto, applicability = "machine-applicable", code = "let")]
UseLetNotAuto(#[primary_span] Span),
#[suggestion(parser::use_let_not_var, applicability = "machine-applicable", code = "let")]
UseLetNotVar(#[primary_span] Span),
}

// SnapshotParser is used to create a snapshot of the parser
// without causing duplicate errors being emitted when the `Parser`
// is dropped.
Expand Down
31 changes: 12 additions & 19 deletions compiler/rustc_parse/src/parser/stmt.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN;
use super::diagnostics::{AttemptLocalParseRecovery, Error};
use super::diagnostics::{
AttemptLocalParseRecovery, Error, InvalidVariableDeclaration, InvalidVariableDeclarationSub,
};
use super::expr::LhsExpr;
use super::pat::RecoverComma;
use super::path::PathStyle;
Expand Down Expand Up @@ -58,28 +60,22 @@ impl<'a> Parser<'a> {
if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) {
self.bump();
let mut_let_span = lo.to(self.token.span);
self.struct_span_err(mut_let_span, "invalid variable declaration")
.span_suggestion(
mut_let_span,
"switch the order of `mut` and `let`",
"let mut",
Applicability::MaybeIncorrect,
)
.emit();
self.sess.emit_err(InvalidVariableDeclaration {
span: mut_let_span,
sub: InvalidVariableDeclarationSub::SwitchMutLetOrder(mut_let_span),
});
}

Ok(Some(if self.token.is_keyword(kw::Let) {
self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
} else if self.is_kw_followed_by_ident(kw::Mut) {
self.recover_stmt_local(lo, attrs, "missing keyword", "let mut")?
self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::MissingLet)?
} else if self.is_kw_followed_by_ident(kw::Auto) {
self.bump(); // `auto`
let msg = "write `let` instead of `auto` to introduce a new variable";
self.recover_stmt_local(lo, attrs, msg, "let")?
self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotAuto)?
} else if self.is_kw_followed_by_ident(sym::var) {
self.bump(); // `var`
let msg = "write `let` instead of `var` to introduce a new variable";
self.recover_stmt_local(lo, attrs, msg, "let")?
self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotVar)?
} else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
// We have avoided contextual keywords like `union`, items with `crate` visibility,
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
Expand Down Expand Up @@ -217,13 +213,10 @@ impl<'a> Parser<'a> {
&mut self,
lo: Span,
attrs: AttrWrapper,
msg: &str,
sugg: &str,
subdiagnostic: fn(Span) -> InvalidVariableDeclarationSub,
) -> PResult<'a, Stmt> {
let stmt = self.recover_local_after_let(lo, attrs)?;
self.struct_span_err(lo, "invalid variable declaration")
.span_suggestion(lo, msg, sugg, Applicability::MachineApplicable)
.emit();
self.sess.emit_err(InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) });
Ok(stmt)
}

Expand Down

0 comments on commit dedae00

Please sign in to comment.