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.
This commit is contained in:
Matthias Krüger 2022-08-20 07:09:01 +02:00 committed by GitHub
commit eacbe5437e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 19 deletions

View File

@ -32,3 +32,12 @@ parser_incorrect_use_of_await =
parser_in_in_typo = parser_in_in_typo =
expected iterable, found keyword `in` expected iterable, found keyword `in`
.suggestion = remove the duplicated `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

View File

@ -334,6 +334,35 @@ struct InInTypo {
sugg_span: Span, 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 // SnapshotParser is used to create a snapshot of the parser
// without causing duplicate errors being emitted when the `Parser` // without causing duplicate errors being emitted when the `Parser`
// is dropped. // is dropped.

View File

@ -1,5 +1,7 @@
use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN; 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::expr::LhsExpr;
use super::pat::RecoverComma; use super::pat::RecoverComma;
use super::path::PathStyle; use super::path::PathStyle;
@ -58,28 +60,22 @@ pub(crate) fn parse_stmt_without_recovery(
if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) { if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) {
self.bump(); self.bump();
let mut_let_span = lo.to(self.token.span); let mut_let_span = lo.to(self.token.span);
self.struct_span_err(mut_let_span, "invalid variable declaration") self.sess.emit_err(InvalidVariableDeclaration {
.span_suggestion( span: mut_let_span,
mut_let_span, sub: InvalidVariableDeclarationSub::SwitchMutLetOrder(mut_let_span),
"switch the order of `mut` and `let`", });
"let mut",
Applicability::MaybeIncorrect,
)
.emit();
} }
Ok(Some(if self.token.is_keyword(kw::Let) { Ok(Some(if self.token.is_keyword(kw::Let) {
self.parse_local_mk(lo, attrs, capture_semi, force_collect)? self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
} else if self.is_kw_followed_by_ident(kw::Mut) { } 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) { } else if self.is_kw_followed_by_ident(kw::Auto) {
self.bump(); // `auto` self.bump(); // `auto`
let msg = "write `let` instead of `auto` to introduce a new variable"; self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotAuto)?
self.recover_stmt_local(lo, attrs, msg, "let")?
} else if self.is_kw_followed_by_ident(sym::var) { } else if self.is_kw_followed_by_ident(sym::var) {
self.bump(); // `var` self.bump(); // `var`
let msg = "write `let` instead of `var` to introduce a new variable"; self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotVar)?
self.recover_stmt_local(lo, attrs, msg, "let")?
} else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() { } 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, // 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 // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
@ -217,13 +213,10 @@ fn recover_stmt_local(
&mut self, &mut self,
lo: Span, lo: Span,
attrs: AttrWrapper, attrs: AttrWrapper,
msg: &str, subdiagnostic: fn(Span) -> InvalidVariableDeclarationSub,
sugg: &str,
) -> PResult<'a, Stmt> { ) -> PResult<'a, Stmt> {
let stmt = self.recover_local_after_let(lo, attrs)?; let stmt = self.recover_local_after_let(lo, attrs)?;
self.struct_span_err(lo, "invalid variable declaration") self.sess.emit_err(InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) });
.span_suggestion(lo, msg, sugg, Applicability::MachineApplicable)
.emit();
Ok(stmt) Ok(stmt)
} }