From e6a6f5237d66f0980688296725a148845e671c68 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Tue, 22 Oct 2019 23:25:41 +0200 Subject: [PATCH 1/2] issues-65257 --- src/libsyntax/parse/parser/stmt.rs | 86 +++++++++++++++++-- src/libsyntax/parse/token.rs | 2 +- src/libsyntax_pos/symbol.rs | 1 + ...sue-65257--auto-instead-of-let-recovery.rs | 9 ++ ...65257--auto-instead-of-let-recovery.stderr | 14 +++ ...ssue-65257--var-instead-of-let-recovery.rs | 9 ++ ...-65257--var-instead-of-let-recovery.stderr | 14 +++ ...issue-65257-mut-instead-of-let-recovery.rs | 9 ++ ...e-65257-mut-instead-of-let-recovery.stderr | 14 +++ 9 files changed, 151 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/parser/issue-65257--auto-instead-of-let-recovery.rs create mode 100644 src/test/ui/parser/issue-65257--auto-instead-of-let-recovery.stderr create mode 100644 src/test/ui/parser/issue-65257--var-instead-of-let-recovery.rs create mode 100644 src/test/ui/parser/issue-65257--var-instead-of-let-recovery.stderr create mode 100644 src/test/ui/parser/issue-65257-mut-instead-of-let-recovery.rs create mode 100644 src/test/ui/parser/issue-65257-mut-instead-of-let-recovery.stderr diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index d54d9c4b8e9fa..dc91dd61093b9 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -10,8 +10,9 @@ use crate::ast::{self, DUMMY_NODE_ID, Stmt, StmtKind, Local, Block, BlockCheckMo use crate::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac, MacDelimiter}; use crate::parse::{classify, DirectoryOwnership}; use crate::parse::token; -use crate::source_map::{respan, Span}; +use crate::source_map::respan; use crate::symbol::{kw, sym}; +use syntax_pos::Span; use std::mem; use errors::Applicability; @@ -41,11 +42,29 @@ impl<'a> Parser<'a> { let lo = self.token.span; Ok(Some(if self.eat_keyword(kw::Let) { - Stmt { - id: DUMMY_NODE_ID, - kind: StmtKind::Local(self.parse_local(attrs.into())?), - span: lo.to(self.prev_span), - } + let local = self.parse_local(attrs.into())?; + self.mk_dummy_stmt(lo.to(self.prev_span), local) + + } else if self.is_ident_mut() { + return self.recover_stmt_local( + lo, + attrs, + "missing `let`", + ); + } else if self.is_var_sym() { + self.bump(); + return self.recover_stmt_local( + lo, + attrs, + "to introduce a variable, write `let` instead of `var`", + ); + } else if self.is_auto_for_let() { + self.bump(); + return self.recover_stmt_local( + lo, + attrs, + "to introduce a variable, write `let` instead of `auto`", + ); } else if let Some(macro_def) = self.eat_macro_def( &attrs, &respan(lo, VisibilityKind::Inherited), @@ -473,4 +492,59 @@ impl<'a> Parser<'a> { "this was erroneously allowed and will become a hard error in a future release" }).emit(); } + + fn recover_stmt_local( + &mut self, + span: Span, + attrs: Vec, + msg: &str, + ) -> PResult<'a, Option> { + let local = self.parse_local(attrs.into())?; + self.struct_span_err(span, "invalid variable declaration") + .span_suggestion_short( + span, + msg, + "let".to_string(), + Applicability::MachineApplicable + ).emit(); + return Ok(Some(self.mk_dummy_stmt(span, local))); + } + + fn mk_dummy_stmt(&mut self, span: Span, kind: P) -> Stmt { + Stmt { + id: DUMMY_NODE_ID, + kind: StmtKind::Local(kind), + span, + } + } + + /// Returns `true` if the next token is Brace + fn is_next_brace(&self) -> bool { self.look_ahead(1, |t| t.eq(&token::OpenDelim(token::Brace))) } + + /// Returns `true` if the token is kw::Mut and next one is an Ident + fn is_ident_mut(&self) -> bool { + self.token.is_keyword(kw::Mut) && + self.look_ahead(1, |t| t.is_ident()) + } + + /// Returns `true` if the token is sym::var. + fn is_var_sym(&self) -> bool { + self.token.is_non_raw_ident_where(|ident| ident.name == sym::var) && + self.is_malformed_declr() + } + + fn has_equals(&self) -> bool { + self.look_ahead(2, |t| t.eq(&token::Eq)) + } + + fn is_auto_for_let(&self) -> bool { + self.token.is_keyword(kw::Auto) && self.is_malformed_declr() + } + + fn is_malformed_declr(&self) -> bool { + (self.has_equals() && !self.is_next_brace()) || + (self.look_ahead(1, |t| t.is_ident()) && + self.look_ahead(2, |t| t.eq(&token::Semi)) + ) + } } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 4a8b25c61079b..c1f0f6f17e38e 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -538,7 +538,7 @@ impl Token { } /// Returns `true` if the token is a non-raw identifier for which `pred` holds. - fn is_non_raw_ident_where(&self, pred: impl FnOnce(ast::Ident) -> bool) -> bool { + pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(ast::Ident) -> bool) -> bool { match self.ident() { Some((id, false)) => pred(id), _ => false, diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index fa9567fb62c0f..59374b1e7a5e2 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -725,6 +725,7 @@ symbols! { usize, v1, val, + var, vec, Vec, vis, diff --git a/src/test/ui/parser/issue-65257--auto-instead-of-let-recovery.rs b/src/test/ui/parser/issue-65257--auto-instead-of-let-recovery.rs new file mode 100644 index 0000000000000..d6f47f1bcd4ba --- /dev/null +++ b/src/test/ui/parser/issue-65257--auto-instead-of-let-recovery.rs @@ -0,0 +1,9 @@ + +#[allow(dead_code)] +fn main() { + auto n = 0;//~ ERROR invalid variable declaration + //~^ HELP to introduce a variable, write `let` instead of `auto` + auto m;//~ ERROR invalid variable declaration + //~^ HELP to introduce a variable, write `let` instead of `auto` + m = 0; +} diff --git a/src/test/ui/parser/issue-65257--auto-instead-of-let-recovery.stderr b/src/test/ui/parser/issue-65257--auto-instead-of-let-recovery.stderr new file mode 100644 index 0000000000000..3bd21f7d101cd --- /dev/null +++ b/src/test/ui/parser/issue-65257--auto-instead-of-let-recovery.stderr @@ -0,0 +1,14 @@ +error: invalid variable declaration + --> $DIR/issue-65257--auto-instead-of-let-recovery.rs:4:5 + | +LL | auto n = 0; + | ^^^^ help: to introduce a variable, write `let` instead of `auto` + +error: invalid variable declaration + --> $DIR/issue-65257--auto-instead-of-let-recovery.rs:6:5 + | +LL | auto m; + | ^^^^ help: to introduce a variable, write `let` instead of `auto` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/issue-65257--var-instead-of-let-recovery.rs b/src/test/ui/parser/issue-65257--var-instead-of-let-recovery.rs new file mode 100644 index 0000000000000..d126799ce1058 --- /dev/null +++ b/src/test/ui/parser/issue-65257--var-instead-of-let-recovery.rs @@ -0,0 +1,9 @@ + +#[allow(dead_code)] +fn main() { + var n = 0;//~ ERROR invalid variable declaration + //~^ HELP to introduce a variable, write `let` instead of `var` + var m;//~ ERROR invalid variable declaration + //~^ HELP to introduce a variable, write `let` instead of `var` + m = 0; +} diff --git a/src/test/ui/parser/issue-65257--var-instead-of-let-recovery.stderr b/src/test/ui/parser/issue-65257--var-instead-of-let-recovery.stderr new file mode 100644 index 0000000000000..e0a6fa6949dc5 --- /dev/null +++ b/src/test/ui/parser/issue-65257--var-instead-of-let-recovery.stderr @@ -0,0 +1,14 @@ +error: invalid variable declaration + --> $DIR/issue-65257--var-instead-of-let-recovery.rs:4:5 + | +LL | var n = 0; + | ^^^ help: to introduce a variable, write `let` instead of `var` + +error: invalid variable declaration + --> $DIR/issue-65257--var-instead-of-let-recovery.rs:6:5 + | +LL | var m; + | ^^^ help: to introduce a variable, write `let` instead of `var` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/issue-65257-mut-instead-of-let-recovery.rs b/src/test/ui/parser/issue-65257-mut-instead-of-let-recovery.rs new file mode 100644 index 0000000000000..73672450dc4ba --- /dev/null +++ b/src/test/ui/parser/issue-65257-mut-instead-of-let-recovery.rs @@ -0,0 +1,9 @@ + +#[allow(dead_code)] +fn main() { + mut n = 0;//~ ERROR invalid variable declaration + //~^ HELP missing `let` + mut var;//~ ERROR invalid variable declaration + //~^ HELP missing `let` + var = 0; +} diff --git a/src/test/ui/parser/issue-65257-mut-instead-of-let-recovery.stderr b/src/test/ui/parser/issue-65257-mut-instead-of-let-recovery.stderr new file mode 100644 index 0000000000000..ad22a5311186f --- /dev/null +++ b/src/test/ui/parser/issue-65257-mut-instead-of-let-recovery.stderr @@ -0,0 +1,14 @@ +error: invalid variable declaration + --> $DIR/issue-65257-mut-instead-of-let-recovery.rs:4:5 + | +LL | mut n = 0; + | ^^^ help: missing `let` + +error: invalid variable declaration + --> $DIR/issue-65257-mut-instead-of-let-recovery.rs:6:5 + | +LL | mut var; + | ^^^ help: missing `let` + +error: aborting due to 2 previous errors + From 56311bf7133e2d3bf945a4a7be65f48f0b74cdb7 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Fri, 25 Oct 2019 16:36:51 +0200 Subject: [PATCH 2/2] tidy --- src/libsyntax/parse/parser/stmt.rs | 4 +++- .../ui/parser/issue-65257--auto-instead-of-let-recovery.rs | 1 - .../ui/parser/issue-65257--var-instead-of-let-recovery.rs | 1 - src/test/ui/parser/issue-65257-mut-instead-of-let-recovery.rs | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index dc91dd61093b9..f309a1308d924 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -519,7 +519,9 @@ impl<'a> Parser<'a> { } /// Returns `true` if the next token is Brace - fn is_next_brace(&self) -> bool { self.look_ahead(1, |t| t.eq(&token::OpenDelim(token::Brace))) } + fn is_next_brace(&self) -> bool { + self.look_ahead(1, |t| t.eq(&token::OpenDelim(token::Brace))) + } /// Returns `true` if the token is kw::Mut and next one is an Ident fn is_ident_mut(&self) -> bool { diff --git a/src/test/ui/parser/issue-65257--auto-instead-of-let-recovery.rs b/src/test/ui/parser/issue-65257--auto-instead-of-let-recovery.rs index d6f47f1bcd4ba..3e58efb0aca2f 100644 --- a/src/test/ui/parser/issue-65257--auto-instead-of-let-recovery.rs +++ b/src/test/ui/parser/issue-65257--auto-instead-of-let-recovery.rs @@ -1,4 +1,3 @@ - #[allow(dead_code)] fn main() { auto n = 0;//~ ERROR invalid variable declaration diff --git a/src/test/ui/parser/issue-65257--var-instead-of-let-recovery.rs b/src/test/ui/parser/issue-65257--var-instead-of-let-recovery.rs index d126799ce1058..8c3cb551bf399 100644 --- a/src/test/ui/parser/issue-65257--var-instead-of-let-recovery.rs +++ b/src/test/ui/parser/issue-65257--var-instead-of-let-recovery.rs @@ -1,4 +1,3 @@ - #[allow(dead_code)] fn main() { var n = 0;//~ ERROR invalid variable declaration diff --git a/src/test/ui/parser/issue-65257-mut-instead-of-let-recovery.rs b/src/test/ui/parser/issue-65257-mut-instead-of-let-recovery.rs index 73672450dc4ba..d2a9f3abc095f 100644 --- a/src/test/ui/parser/issue-65257-mut-instead-of-let-recovery.rs +++ b/src/test/ui/parser/issue-65257-mut-instead-of-let-recovery.rs @@ -1,4 +1,3 @@ - #[allow(dead_code)] fn main() { mut n = 0;//~ ERROR invalid variable declaration