From 4a938b5b3c475a5a12fa582eca2dd91d76cb0d3e Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Wed, 10 Apr 2019 10:35:48 -0700 Subject: Special error when using catch after try --- src/libsyntax/parse/parser.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5b430d13516..98bad0a80aa 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3618,7 +3618,13 @@ impl<'a> Parser<'a> { { let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - Ok(self.mk_expr(span_lo.to(body.span), ExprKind::TryBlock(body), attrs)) + if self.eat_keyword(keywords::Catch) { + let mut error = self.struct_span_err(self.prev_span, "`try {} catch` is not a valid syntax"); + error.help("try using `match` on the result of the `try` block instead"); + Err(error) + } else { + Ok(self.mk_expr(span_lo.to(body.span), ExprKind::TryBlock(body), attrs)) + } } // `match` token already eaten -- cgit 1.4.1-3-g733a5 From de02dd96fd955212d4555b2861f25a71c34db6b7 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Wed, 10 Apr 2019 10:41:47 -0700 Subject: Adhere to tidy script --- src/libsyntax/parse/parser.rs | 3 ++- src/test/ui/try-block/try-block-catch.rs | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 98bad0a80aa..4d2a9f2c13c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3619,7 +3619,8 @@ impl<'a> Parser<'a> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); if self.eat_keyword(keywords::Catch) { - let mut error = self.struct_span_err(self.prev_span, "`try {} catch` is not a valid syntax"); + let mut error = self.struct_span_err(self.prev_span, + "`try {} catch` is not a valid syntax"); error.help("try using `match` on the result of the `try` block instead"); Err(error) } else { diff --git a/src/test/ui/try-block/try-block-catch.rs b/src/test/ui/try-block/try-block-catch.rs index 8f3d6d87258..d3a74c21422 100644 --- a/src/test/ui/try-block/try-block-catch.rs +++ b/src/test/ui/try-block/try-block-catch.rs @@ -3,7 +3,7 @@ #![feature(try_blocks)] fn main() { - let res: Option = try { - true - } catch { }; //~ ERROR `try {} catch` is not a valid syntax + let res: Option = try { + true + } catch { }; //~ ERROR `try {} catch` is not a valid syntax } -- cgit 1.4.1-3-g733a5 From ac037c1359afa273bd5573b5be1b21d074c22219 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Wed, 10 Apr 2019 18:07:52 -0700 Subject: 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 `()` ``` --- src/libsyntax/parse/parser.rs | 27 ++++++++++++++++++ src/test/ui/parser/recover-missing-semi.rs | 13 +++++++++ src/test/ui/parser/recover-missing-semi.stderr | 39 ++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 src/test/ui/parser/recover-missing-semi.rs create mode 100644 src/test/ui/parser/recover-missing-semi.stderr (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 37360a56395..d2875a5f275 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -796,6 +796,10 @@ impl<'a> Parser<'a> { .chain(inedible.iter().map(|x| TokenType::Token(x.clone()))) .chain(self.expected_tokens.iter().cloned()) .collect::>(); + 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 @@ impl<'a> Parser<'a> { 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 @@ impl<'a> Parser<'a> { 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 index 00000000000..1893dc716be --- /dev/null +++ b/src/test/ui/parser/recover-missing-semi.rs @@ -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 index 00000000000..25ce408d8b2 --- /dev/null +++ b/src/test/ui/parser/recover-missing-semi.stderr @@ -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`. -- cgit 1.4.1-3-g733a5 From 1156ce6f54dde7555bb00828ba4ec6c2a170fc83 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Wed, 10 Apr 2019 19:22:43 -0700 Subject: Feedback --- src/libsyntax/parse/parser.rs | 3 ++- src/test/ui/try-block/try-block-catch.rs | 2 +- src/test/ui/try-block/try-block-catch.stderr | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4d2a9f2c13c..d95a5843eb5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3620,8 +3620,9 @@ impl<'a> Parser<'a> { attrs.extend(iattrs); if self.eat_keyword(keywords::Catch) { let mut error = self.struct_span_err(self.prev_span, - "`try {} catch` is not a valid syntax"); + "keyword `catch` cannot follow a `try` block"); error.help("try using `match` on the result of the `try` block instead"); + error.emit(); Err(error) } else { Ok(self.mk_expr(span_lo.to(body.span), ExprKind::TryBlock(body), attrs)) diff --git a/src/test/ui/try-block/try-block-catch.rs b/src/test/ui/try-block/try-block-catch.rs index a7dc41fc423..d165015611d 100644 --- a/src/test/ui/try-block/try-block-catch.rs +++ b/src/test/ui/try-block/try-block-catch.rs @@ -6,5 +6,5 @@ fn main() { let res: Option = try { true } catch { }; - //~^ ERROR `try {} catch` is not a valid syntax + //~^ ERROR keyword `catch` cannot follow a `try` block } diff --git a/src/test/ui/try-block/try-block-catch.stderr b/src/test/ui/try-block/try-block-catch.stderr index b54cc3ccbbb..39cf943f4d8 100644 --- a/src/test/ui/try-block/try-block-catch.stderr +++ b/src/test/ui/try-block/try-block-catch.stderr @@ -1,4 +1,4 @@ -error: `try {} catch` is not a valid syntax +error: keyword `catch` cannot follow a `try` block --> $DIR/try-block-catch.rs:8:7 | LL | } catch { }; -- cgit 1.4.1-3-g733a5 From 9b6b3d618c16976a273cfd4f95408eef37e6c82e Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Thu, 11 Apr 2019 14:24:31 -0700 Subject: review comments --- src/libsyntax/parse/parser.rs | 31 +++++++++++++------------- src/test/ui/parser/recover-missing-semi.stderr | 4 ++-- 2 files changed, 17 insertions(+), 18 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d2875a5f275..7992867692e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -796,10 +796,6 @@ impl<'a> Parser<'a> { .chain(inedible.iter().map(|x| TokenType::Token(x.clone()))) .chain(self.expected_tokens.iter().cloned()) .collect::>(); - 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[..]); @@ -839,17 +835,6 @@ impl<'a> Parser<'a> { 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 @@ -866,6 +851,20 @@ impl<'a> Parser<'a> { } } + let is_semi_suggestable = expected.iter().any(|t| match t { + TokenType::Token(token::Semi) => true, // we expect a `;` here + _ => false, + }) && ( // a `;` would be expected before the current keyword + 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 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 => { @@ -873,7 +872,7 @@ impl<'a> Parser<'a> { // High likelihood that it is only a missing `;`. err.span_suggestion_short( label_sp, - "missing semicolon here", + "a semicolon may be missing here", ";".to_string(), Applicability::MaybeIncorrect, ); diff --git a/src/test/ui/parser/recover-missing-semi.stderr b/src/test/ui/parser/recover-missing-semi.stderr index 25ce408d8b2..99339e4dd50 100644 --- a/src/test/ui/parser/recover-missing-semi.stderr +++ b/src/test/ui/parser/recover-missing-semi.stderr @@ -2,7 +2,7 @@ error: expected one of `.`, `;`, `?`, or an operator, found `let` --> $DIR/recover-missing-semi.rs:4:5 | LL | let _: usize = () - | - help: missing semicolon here + | - help: a semicolon may be missing here LL | LL | let _ = 3; | ^^^ @@ -11,7 +11,7 @@ error: expected one of `.`, `;`, `?`, or an operator, found `return` --> $DIR/recover-missing-semi.rs:11:5 | LL | let _: usize = () - | - help: missing semicolon here + | - help: a semicolon may be missing here LL | LL | return 3; | ^^^^^^ -- cgit 1.4.1-3-g733a5