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:
commit
eacbe5437e
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user