]> git.lizzy.rs Git - rust.git/commitdiff
Recover from missing semicolon based on the found token
authorEsteban Küber <esteban@kuber.com.ar>
Thu, 11 Apr 2019 01:07:52 +0000 (18:07 -0700)
committerEsteban Küber <esteban@kuber.com.ar>
Thu, 11 Apr 2019 01:07:52 +0000 (18:07 -0700)
When encountering one of a few keywords when a semicolon was
expected, suggest the semicolon and recover:

```
error: expected one of `.`, `;`, `?`, or an operator, found `let`
  --> $DIR/recover-missing-semi.rs:4:5
   |
LL |     let _: usize = ()
   |                      - help: missing semicolon here
LL |
LL |     let _ = 3;
   |     ^^^

error[E0308]: mismatched types
  --> $DIR/recover-missing-semi.rs:2:20
   |
LL |     let _: usize = ()
   |                    ^^ expected usize, found ()
   |
   = note: expected type `usize`
              found type `()`
```

src/libsyntax/parse/parser.rs
src/test/ui/parser/recover-missing-semi.rs [new file with mode: 0644]
src/test/ui/parser/recover-missing-semi.stderr [new file with mode: 0644]

index 37360a563950b89fbf33f9a1fc6ce55e15d40662..d2875a5f27551e35ebbf18b849de09e9c3e0dda9 100644 (file)
@@ -796,6 +796,10 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
                 .chain(inedible.iter().map(|x| TokenType::Token(x.clone())))
                 .chain(self.expected_tokens.iter().cloned())
                 .collect::<Vec<_>>();
+            let expects_semi = expected.iter().any(|t| match t {
+                TokenType::Token(token::Semi) => true,
+                _ => false,
+            });
             expected.sort_by_cached_key(|x| x.to_string());
             expected.dedup();
             let expect = tokens_to_string(&expected[..]);
@@ -835,6 +839,17 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
                     Applicability::MaybeIncorrect,
                 );
             }
+            let is_semi_suggestable = expects_semi && (
+                self.token.is_keyword(keywords::Break) ||
+                self.token.is_keyword(keywords::Continue) ||
+                self.token.is_keyword(keywords::For) ||
+                self.token.is_keyword(keywords::If) ||
+                self.token.is_keyword(keywords::Let) ||
+                self.token.is_keyword(keywords::Loop) ||
+                self.token.is_keyword(keywords::Match) ||
+                self.token.is_keyword(keywords::Return) ||
+                self.token.is_keyword(keywords::While)
+            );
             let sp = if self.token == token::Token::Eof {
                 // This is EOF, don't want to point at the following char, but rather the last token
                 self.prev_span
@@ -853,6 +868,18 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
 
             let cm = self.sess.source_map();
             match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) {
+                (Ok(ref a), Ok(ref b)) if a.line != b.line && is_semi_suggestable => {
+                    // The spans are in different lines, expected `;` and found `let` or `return`.
+                    // High likelihood that it is only a missing `;`.
+                    err.span_suggestion_short(
+                        label_sp,
+                        "missing semicolon here",
+                        ";".to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                    err.emit();
+                    return Ok(true);
+                }
                 (Ok(ref a), Ok(ref b)) if a.line == b.line => {
                     // When the spans are in the same line, it means that the only content between
                     // them is whitespace, point at the found token in that case:
diff --git a/src/test/ui/parser/recover-missing-semi.rs b/src/test/ui/parser/recover-missing-semi.rs
new file mode 100644 (file)
index 0000000..1893dc7
--- /dev/null
@@ -0,0 +1,13 @@
+fn main() {
+    let _: usize = ()
+    //~^ ERROR mismatched types
+    let _ = 3;
+    //~^ ERROR expected one of
+}
+
+fn foo() -> usize {
+    let _: usize = ()
+    //~^ ERROR mismatched types
+    return 3;
+    //~^ ERROR expected one of
+}
diff --git a/src/test/ui/parser/recover-missing-semi.stderr b/src/test/ui/parser/recover-missing-semi.stderr
new file mode 100644 (file)
index 0000000..25ce408
--- /dev/null
@@ -0,0 +1,39 @@
+error: expected one of `.`, `;`, `?`, or an operator, found `let`
+  --> $DIR/recover-missing-semi.rs:4:5
+   |
+LL |     let _: usize = ()
+   |                      - help: missing semicolon here
+LL |
+LL |     let _ = 3;
+   |     ^^^
+
+error: expected one of `.`, `;`, `?`, or an operator, found `return`
+  --> $DIR/recover-missing-semi.rs:11:5
+   |
+LL |     let _: usize = ()
+   |                      - help: missing semicolon here
+LL |
+LL |     return 3;
+   |     ^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/recover-missing-semi.rs:2:20
+   |
+LL |     let _: usize = ()
+   |                    ^^ expected usize, found ()
+   |
+   = note: expected type `usize`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/recover-missing-semi.rs:9:20
+   |
+LL |     let _: usize = ()
+   |                    ^^ expected usize, found ()
+   |
+   = note: expected type `usize`
+              found type `()`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.