]> git.lizzy.rs Git - rust.git/commitdiff
recover on 'mut', 'var', 'auto'
authorMazdak Farrokhzad <twingoow@gmail.com>
Tue, 3 Dec 2019 17:08:19 +0000 (18:08 +0100)
committerMazdak Farrokhzad <twingoow@gmail.com>
Fri, 20 Dec 2019 21:53:40 +0000 (22:53 +0100)
src/librustc_parse/parser/stmt.rs
src/libsyntax_pos/symbol.rs
src/test/ui/parser/issue-65257-invalid-var-decl-recovery.rs [new file with mode: 0644]
src/test/ui/parser/issue-65257-invalid-var-decl-recovery.stderr [new file with mode: 0644]

index a080806311613c861bb31c4475c3595013dbf9c8..abee24e2b0929aa7a1d93bab8d3bd5a18490dabd 100644 (file)
@@ -14,7 +14,7 @@
 use syntax::util::classify;
 use syntax::token;
 use syntax_pos::source_map::{respan, Span};
-use syntax_pos::symbol::kw;
+use syntax_pos::symbol::{kw, sym, Symbol};
 
 use std::mem;
 
@@ -39,8 +39,20 @@ fn parse_stmt_without_recovery(
         let lo = self.token.span;
 
         if self.eat_keyword(kw::Let) {
-            let local = self.parse_local(attrs.into())?;
-            return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Local(local))));
+            return self.parse_local_mk(lo, attrs.into()).map(Some)
+        }
+        if self.is_kw_followed_by_ident(kw::Mut) {
+            return self.recover_stmt_local(lo, attrs.into(), "missing `let`", "let mut");
+        }
+        if self.is_kw_followed_by_ident(kw::Auto) {
+            self.bump(); // `auto`
+            let msg = "to introduce a variable, write `let` instead of `auto`";
+            return self.recover_stmt_local(lo, attrs.into(), msg, "let");
+        }
+        if self.is_kw_followed_by_ident(sym::var) {
+            self.bump(); // `var`
+            let msg = "to introduce a variable, write `let` instead of `var`";
+            return self.recover_stmt_local(lo, attrs.into(), msg, "let");
         }
 
         let mac_vis = respan(lo, VisibilityKind::Inherited);
@@ -189,6 +201,30 @@ fn error_outer_attrs(&self, attrs: &[Attribute]) {
         }
     }
 
+    fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool {
+        self.token.is_keyword(kw)
+            && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())
+    }
+
+    fn recover_stmt_local(
+        &mut self,
+        span: Span,
+        attrs: AttrVec,
+        msg: &str,
+        sugg: &str,
+    ) -> PResult<'a, Option<Stmt>> {
+        let stmt = self.parse_local_mk(span, attrs)?;
+        self.struct_span_err(stmt.span, "invalid variable declaration")
+            .span_suggestion_short(span, msg, sugg.to_string(), Applicability::MachineApplicable)
+            .emit();
+        Ok(Some(stmt))
+    }
+
+    fn parse_local_mk(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
+        let local = self.parse_local(attrs.into())?;
+        Ok(self.mk_stmt(lo.to(self.prev_span), StmtKind::Local(local)))
+    }
+
     /// Parses a local variable declaration.
     fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
         let lo = self.prev_span;
index ae34064c9267bd1d073e437040260a8b80f8608f..d3e80fc4fddd6d6505afc24dd3b68508c2299127 100644 (file)
         usize,
         v1,
         val,
+        var,
         vec,
         Vec,
         vis,
diff --git a/src/test/ui/parser/issue-65257-invalid-var-decl-recovery.rs b/src/test/ui/parser/issue-65257-invalid-var-decl-recovery.rs
new file mode 100644 (file)
index 0000000..7efc417
--- /dev/null
@@ -0,0 +1,21 @@
+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;
+
+    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;
+
+    mut n = 0;//~ ERROR invalid variable declaration
+    //~^ HELP missing `let`
+    mut var;//~ ERROR invalid variable declaration
+    //~^ HELP missing `let`
+    var = 0;
+
+    let _recovery_witness: () = 0; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/parser/issue-65257-invalid-var-decl-recovery.stderr b/src/test/ui/parser/issue-65257-invalid-var-decl-recovery.stderr
new file mode 100644 (file)
index 0000000..429c122
--- /dev/null
@@ -0,0 +1,59 @@
+error: invalid variable declaration
+  --> $DIR/issue-65257-invalid-var-decl-recovery.rs:2:5
+   |
+LL |     auto n = 0;
+   |     ----^^^^^^
+   |     |
+   |     help: to introduce a variable, write `let` instead of `auto`
+
+error: invalid variable declaration
+  --> $DIR/issue-65257-invalid-var-decl-recovery.rs:4:5
+   |
+LL |     auto m;
+   |     ----^^
+   |     |
+   |     help: to introduce a variable, write `let` instead of `auto`
+
+error: invalid variable declaration
+  --> $DIR/issue-65257-invalid-var-decl-recovery.rs:8:5
+   |
+LL |     var n = 0;
+   |     ---^^^^^^
+   |     |
+   |     help: to introduce a variable, write `let` instead of `var`
+
+error: invalid variable declaration
+  --> $DIR/issue-65257-invalid-var-decl-recovery.rs:10:5
+   |
+LL |     var m;
+   |     ---^^
+   |     |
+   |     help: to introduce a variable, write `let` instead of `var`
+
+error: invalid variable declaration
+  --> $DIR/issue-65257-invalid-var-decl-recovery.rs:14:5
+   |
+LL |     mut n = 0;
+   |     ---^^^^^^
+   |     |
+   |     help: missing `let`
+
+error: invalid variable declaration
+  --> $DIR/issue-65257-invalid-var-decl-recovery.rs:16:5
+   |
+LL |     mut var;
+   |     ---^^^^
+   |     |
+   |     help: missing `let`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-65257-invalid-var-decl-recovery.rs:20:33
+   |
+LL |     let _recovery_witness: () = 0;
+   |                            --   ^ expected `()`, found integer
+   |                            |
+   |                            expected due to this
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0308`.