Skip to content

Commit ac037c1

Browse files
committed
Recover from missing semicolon based on the found token
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 `()` ```
1 parent 96d700f commit ac037c1

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

src/libsyntax/parse/parser.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,10 @@ impl<'a> Parser<'a> {
796796
.chain(inedible.iter().map(|x| TokenType::Token(x.clone())))
797797
.chain(self.expected_tokens.iter().cloned())
798798
.collect::<Vec<_>>();
799+
let expects_semi = expected.iter().any(|t| match t {
800+
TokenType::Token(token::Semi) => true,
801+
_ => false,
802+
});
799803
expected.sort_by_cached_key(|x| x.to_string());
800804
expected.dedup();
801805
let expect = tokens_to_string(&expected[..]);
@@ -835,6 +839,17 @@ impl<'a> Parser<'a> {
835839
Applicability::MaybeIncorrect,
836840
);
837841
}
842+
let is_semi_suggestable = expects_semi && (
843+
self.token.is_keyword(keywords::Break) ||
844+
self.token.is_keyword(keywords::Continue) ||
845+
self.token.is_keyword(keywords::For) ||
846+
self.token.is_keyword(keywords::If) ||
847+
self.token.is_keyword(keywords::Let) ||
848+
self.token.is_keyword(keywords::Loop) ||
849+
self.token.is_keyword(keywords::Match) ||
850+
self.token.is_keyword(keywords::Return) ||
851+
self.token.is_keyword(keywords::While)
852+
);
838853
let sp = if self.token == token::Token::Eof {
839854
// This is EOF, don't want to point at the following char, but rather the last token
840855
self.prev_span
@@ -853,6 +868,18 @@ impl<'a> Parser<'a> {
853868

854869
let cm = self.sess.source_map();
855870
match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) {
871+
(Ok(ref a), Ok(ref b)) if a.line != b.line && is_semi_suggestable => {
872+
// The spans are in different lines, expected `;` and found `let` or `return`.
873+
// High likelihood that it is only a missing `;`.
874+
err.span_suggestion_short(
875+
label_sp,
876+
"missing semicolon here",
877+
";".to_string(),
878+
Applicability::MaybeIncorrect,
879+
);
880+
err.emit();
881+
return Ok(true);
882+
}
856883
(Ok(ref a), Ok(ref b)) if a.line == b.line => {
857884
// When the spans are in the same line, it means that the only content between
858885
// them is whitespace, point at the found token in that case:
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
fn main() {
2+
let _: usize = ()
3+
//~^ ERROR mismatched types
4+
let _ = 3;
5+
//~^ ERROR expected one of
6+
}
7+
8+
fn foo() -> usize {
9+
let _: usize = ()
10+
//~^ ERROR mismatched types
11+
return 3;
12+
//~^ ERROR expected one of
13+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
error: expected one of `.`, `;`, `?`, or an operator, found `let`
2+
--> $DIR/recover-missing-semi.rs:4:5
3+
|
4+
LL | let _: usize = ()
5+
| - help: missing semicolon here
6+
LL |
7+
LL | let _ = 3;
8+
| ^^^
9+
10+
error: expected one of `.`, `;`, `?`, or an operator, found `return`
11+
--> $DIR/recover-missing-semi.rs:11:5
12+
|
13+
LL | let _: usize = ()
14+
| - help: missing semicolon here
15+
LL |
16+
LL | return 3;
17+
| ^^^^^^
18+
19+
error[E0308]: mismatched types
20+
--> $DIR/recover-missing-semi.rs:2:20
21+
|
22+
LL | let _: usize = ()
23+
| ^^ expected usize, found ()
24+
|
25+
= note: expected type `usize`
26+
found type `()`
27+
28+
error[E0308]: mismatched types
29+
--> $DIR/recover-missing-semi.rs:9:20
30+
|
31+
LL | let _: usize = ()
32+
| ^^ expected usize, found ()
33+
|
34+
= note: expected type `usize`
35+
found type `()`
36+
37+
error: aborting due to 4 previous errors
38+
39+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)