about summary refs log tree commit diff
path: root/src/librustc_parse/parser
diff options
context:
space:
mode:
authormibac138 <5672750+mibac138@users.noreply.github.com>2020-05-07 04:09:57 +0200
committermibac138 <5672750+mibac138@users.noreply.github.com>2020-05-20 20:42:09 +0200
commit48ff12acb184672393692e087927a66ff7907d71 (patch)
tree07069e9606ecc036a80d396dccb4b4e346a4401b /src/librustc_parse/parser
parentd4fe9553f65df51a18999e956fd507e26271e74e (diff)
Expand partial error recovery for `let` with `BinOpEq`
Diffstat (limited to 'src/librustc_parse/parser')
-rw-r--r--src/librustc_parse/parser/stmt.rs40
1 files changed, 30 insertions, 10 deletions
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index 049aa7447f4..aceee814328 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -145,12 +145,12 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_local_mk(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
-        let local = self.parse_local(attrs)?;
+        let local = self.parse_local(lo, attrs)?;
         Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Local(local)))
     }
 
     /// Parses a local variable declaration.
-    fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
+    fn parse_local(&mut self, let_span: Span, attrs: AttrVec) -> PResult<'a, P<Local>> {
         let lo = self.prev_token.span;
         let pat = self.parse_top_pat(GateOr::Yes)?;
 
@@ -174,7 +174,7 @@ impl<'a> Parser<'a> {
         } else {
             (None, None)
         };
-        let init = match (self.parse_initializer(err.is_some()), err) {
+        let init = match (self.parse_initializer(let_span, ty.is_some(), err.is_some()), err) {
             (Ok(init), None) => {
                 // init parsed, ty parsed
                 init
@@ -216,23 +216,43 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses the RHS of a local variable declaration (e.g., '= 14;').
-    fn parse_initializer(&mut self, skip_eq: bool) -> PResult<'a, Option<P<Expr>>> {
+    fn parse_initializer(
+        &mut self,
+        let_span: Span,
+        has_ty: bool,
+        skip_eq: bool,
+    ) -> PResult<'a, Option<P<Expr>>> {
         let parse = if !self.eat(&token::Eq) && !skip_eq {
             // Error recovery for `let x += 1`
             if matches!(self.token.kind, TokenKind::BinOpEq(_)) {
-                struct_span_err!(
+                let mut err = struct_span_err!(
                     self.sess.span_diagnostic,
                     self.token.span,
                     E0067,
                     "can't reassign to a uninitialized variable"
-                )
-                .span_suggestion_short(
+                );
+                err.span_suggestion_short(
                     self.token.span,
                     "replace with `=` to initialize the variable",
                     "=".to_string(),
-                    Applicability::MaybeIncorrect,
-                )
-                .emit();
+                    if has_ty {
+                        // for `let x: i8 += 1` it's highly likely that the `+` is a typo
+                        Applicability::MachineApplicable
+                    } else {
+                        // for `let x += 1` it's a bit less likely that the `+` is a typo
+                        Applicability::MaybeIncorrect
+                    },
+                );
+                // In case of code like `let x += 1` it's possible the user may have meant to write `x += 1`
+                if !has_ty {
+                    err.span_suggestion_short(
+                        let_span,
+                        "remove to reassign to a previously initialized variable",
+                        "".to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                err.emit();
                 self.bump();
                 true
             } else {