about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-05-15 19:47:18 -0700
committerEsteban Küber <esteban@kuber.com.ar>2019-05-16 13:56:44 -0700
commitd763faf92198e3f0c851388c71d2bb8a2f04afd9 (patch)
tree2613a847c021be3e35e5c78480b24be0249ff770 /src/libsyntax/parse
parent1962adea6ad9b992516ae56ad7f8c5bc33b951cb (diff)
downloadrust-d763faf92198e3f0c851388c71d2bb8a2f04afd9.tar.gz
rust-d763faf92198e3f0c851388c71d2bb8a2f04afd9.zip
Parse alternative incorrect uses of await and recover
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/parser.rs113
1 files changed, 105 insertions, 8 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 99e8db9d8e6..55e13ef00dc 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2629,14 +2629,94 @@ impl<'a> Parser<'a> {
                     db.note("variable declaration using `let` is a statement");
                     return Err(db);
                 } else if self.span.rust_2018() && self.eat_keyword(keywords::Await) {
-                    // FIXME: remove this branch when `await!` is no longer supported
-                    // https://github.com/rust-lang/rust/issues/60610
-                    self.expect(&token::Not)?;
-                    self.expect(&token::OpenDelim(token::Paren))?;
-                    let expr = self.parse_expr()?;
-                    self.expect(&token::CloseDelim(token::Paren))?;
-                    hi = self.prev_span;
-                    ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr);
+                    let await_sp = self.prev_span;
+                    match self.token {
+                        token::Not => {
+                            // FIXME: make this an error when `await!` is no longer supported
+                            // https://github.com/rust-lang/rust/issues/60610
+                            self.expect(&token::Not)?;
+                            self.expect(&token::OpenDelim(token::Paren))?;
+                            let expr = self.parse_expr().map_err(|mut err| {
+                                err.span_label(
+                                    await_sp,
+                                    "while parsing this await macro call",
+                                );
+                                err
+                            })?;
+                            self.expect(&token::CloseDelim(token::Paren))?;
+                            ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr);
+                        }
+                        token::Question => {
+                            // Handle `await? <expr>`
+                            self.bump(); // `?`
+                            let expr = self.parse_expr().map_err(|mut err| {
+                                err.span_label(
+                                    await_sp,
+                                    "while parsing this incorrect await statement",
+                                );
+                                err
+                            })?;
+                            let sp = lo.to(expr.span);
+                            let expr_str = self.sess.source_map().span_to_snippet(expr.span)
+                                .unwrap_or_else(|_| pprust::expr_to_string(&expr));
+                            let expr = self.mk_expr(
+                                sp,
+                                ExprKind::Await(ast::AwaitOrigin::FieldLike, expr),
+                                ThinVec::new(),
+                            );
+                            hi = sp;
+                            ex = ExprKind::Try(expr);
+                            let mut err = self.struct_span_err(
+                                await_sp,
+                                "incorrect use of `await`",
+                            );
+                            err.span_suggestion(
+                                sp,
+                                "`await` is not a statement",
+                                format!("{}.await?", expr_str),
+                                Applicability::MachineApplicable,
+                            );
+                            err.emit();
+                        }
+                        ref t => {
+                            // Handle `await <expr>`
+                            let expr = if t == &token::OpenDelim(token::Brace) {
+                                // Handle `await { <expr> }`
+                                // this needs to be handled separatedly from the next arm to avoid
+                                // interpreting `await { <expr> }?` as `<expr>?.await`
+                                self.parse_block_expr(
+                                    None,
+                                    self.span,
+                                    BlockCheckMode::Default,
+                                    ThinVec::new(),
+                                )
+                            } else {
+                                self.parse_expr()
+                            }.map_err(|mut err| {
+                                err.span_label(
+                                    await_sp,
+                                    "while parsing this incorrect await statement",
+                                );
+                                err
+                            })?;
+                            let expr_str = self.sess.source_map().span_to_snippet(expr.span)
+                                .unwrap_or_else(|_| pprust::expr_to_string(&expr));
+                            let sp = lo.to(expr.span);
+                            hi = sp;
+                            ex = ExprKind::Await(ast::AwaitOrigin::FieldLike, expr);
+                            let mut err = self.struct_span_err(
+                                await_sp,
+                                "incorrect use of `await`",
+                            );
+                            err.span_suggestion(
+                                sp,
+                                "`await` is not a statement",
+                                format!("{}.await", expr_str),
+                                Applicability::MachineApplicable,
+                            );
+                            err.emit();
+                        }
+                    }
                 } else if self.token.is_path_start() {
                     let path = self.parse_path(PathStyle::Expr)?;
 
@@ -2913,6 +2993,23 @@ impl<'a> Parser<'a> {
                 ExprKind::Await(ast::AwaitOrigin::FieldLike, self_arg),
                 ThinVec::new(),
             );
+            if self.token == token::OpenDelim(token::Paren) &&
+                self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren))
+            {
+                // future.await()
+                let lo = self.span;
+                self.bump(); // (
+                let sp = lo.to(self.span);
+                self.bump(); // )
+                let mut err = self.struct_span_err(span, "incorrect use of `await`");
+                err.span_suggestion(
+                    sp,
+                    "`await` is not a method call, remove the parentheses",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                );
+                err.emit()
+            }
             return Ok(await_expr);
         }
         let segment = self.parse_path_segment(PathStyle::Expr)?;