about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-05-16 13:33:26 -0700
committerEsteban Küber <esteban@kuber.com.ar>2019-05-16 13:58:44 -0700
commitb9d6fe3ae96a7f1f478dc6baf29b8e4cff5ab865 (patch)
treecacec5fe5fed51d05d3829435284069e6299e38e /src/libsyntax
parent0183a575f686003586ca3308db8a55d6224f4789 (diff)
downloadrust-b9d6fe3ae96a7f1f478dc6baf29b8e4cff5ab865.tar.gz
rust-b9d6fe3ae96a7f1f478dc6baf29b8e4cff5ab865.zip
Review comments
- Change wording of suggestion
- Move recovery logic to `diagnostics.rs`
- Reduce ammount of code duplication
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/parse/diagnostics.rs40
-rw-r--r--src/libsyntax/parse/parser.rs124
2 files changed, 68 insertions, 96 deletions
diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs
index 32e1ee94f0d..61453e35095 100644
--- a/src/libsyntax/parse/diagnostics.rs
+++ b/src/libsyntax/parse/diagnostics.rs
@@ -1,5 +1,5 @@
 use crate::ast;
-use crate::ast::{Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
+use crate::ast::{BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
 use crate::parse::parser::PathStyle;
 use crate::parse::token;
 use crate::parse::PResult;
@@ -223,4 +223,42 @@ impl<'a> Parser<'a> {
             false
         }
     }
+
+    /// Consume alternative await syntaxes like `await <expr>`, `await? <expr>`, `await(<expr>)`
+    /// and `await { <expr> }`.
+    crate fn parse_incorrect_await_syntax(
+        &mut self,
+        lo: Span,
+        await_sp: Span,
+    ) -> PResult<'a, (Span, ExprKind)> {
+        let is_question = self.eat(&token::Question); // Handle `await? <expr>`.
+        let expr = if self.token == 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 expression");
+            err
+        })?;
+        let expr_str = self.sess.source_map().span_to_snippet(expr.span)
+            .unwrap_or_else(|_| pprust::expr_to_string(&expr));
+        let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" });
+        let sp = lo.to(expr.span);
+        let app = match expr.node {
+            ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?`
+            _ => Applicability::MachineApplicable,
+        };
+        self.struct_span_err(sp, "incorrect use of `await`")
+            .span_suggestion(sp, "`await` is a postfix operation", suggestion, app)
+            .emit();
+        Ok((sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr)))
+    }
 }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 45081aadfd9..bb0f9fa9502 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2629,10 +2629,9 @@ 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) {
-                    let await_sp = self.prev_span;
-                    let e = self.parse_async_macro_or_stmt(lo, await_sp)?;
-                    hi = e.0;
-                    ex = e.1;
+                    let (await_hi, e_kind) = self.parse_await_macro_or_alt(lo, self.prev_span)?;
+                    hi = await_hi;
+                    ex = e_kind;
                 } else if self.token.is_path_start() {
                     let path = self.parse_path(PathStyle::Expr)?;
 
@@ -2697,97 +2696,29 @@ impl<'a> Parser<'a> {
         self.maybe_recover_from_bad_qpath(expr, true)
     }
 
-    fn parse_async_macro_or_stmt(
+    /// Parse `await!(<expr>)` calls, or alternatively recover from incorrect but reasonable
+    /// alternative syntaxes `await <expr>`, `await? <expr>`, `await(<expr>)` and
+    /// `await { <expr> }`.
+    fn parse_await_macro_or_alt(
         &mut self,
         lo: Span,
         await_sp: Span,
     ) -> PResult<'a, (Span, ExprKind)> {
-        Ok(match self.token {
-            token::Not => {
-                // Handle correct `await!(<expr>)`
-                // 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))?;
-                (expr.span, 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(),
-                );
-                let mut err = self.struct_span_err(
-                    sp,
-                    "incorrect use of `await`",
-                );
-                err.span_suggestion(
-                    sp,
-                    "`await` is not a statement",
-                    format!("{}.await?", expr_str),
-                    Applicability::MachineApplicable,
-                );
-                err.emit();
-                (sp, ExprKind::Try(expr))
-            }
-            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);
-                let mut err = self.struct_span_err(
-                    sp,
-                    "incorrect use of `await`",
-                );
-                err.span_suggestion(
-                    sp,
-                    "`await` is not a statement",
-                    format!("{}.await", expr_str),
-                    Applicability::MachineApplicable,
-                );
-                err.emit();
-                (sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr))
-            }
-        })
+        if self.token == token::Not {
+            // Handle correct `await!(<expr>)`.
+            // 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))?;
+            Ok((expr.span, ExprKind::Await(ast::AwaitOrigin::MacroLike, expr)))
+        } else { // Handle `await <expr>`.
+            self.parse_incorrect_await_syntax(lo, await_sp)
+        }
     }
 
     fn maybe_parse_struct_expr(
@@ -2938,10 +2869,13 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a block or unsafe block.
-    fn parse_block_expr(&mut self, opt_label: Option<Label>,
-                            lo: Span, blk_mode: BlockCheckMode,
-                            outer_attrs: ThinVec<Attribute>)
-                            -> PResult<'a, P<Expr>> {
+    crate fn parse_block_expr(
+        &mut self,
+        opt_label: Option<Label>,
+        lo: Span,
+        blk_mode: BlockCheckMode,
+        outer_attrs: ThinVec<Attribute>,
+    ) -> PResult<'a, P<Expr>> {
         self.expect(&token::OpenDelim(token::Brace))?;
 
         let mut attrs = outer_attrs;