]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_parse/src/parser/expr.rs
Rollup merge of #88729 - estebank:struct-literal-using-parens, r=oli-obk
[rust.git] / compiler / rustc_parse / src / parser / expr.rs
index cfd3fe93d32eb82ab56de32472862f95fc793cfd..737f1d9cbb15e0f55269c63c22b891063764b7d8 100644 (file)
@@ -1,9 +1,12 @@
 use super::pat::{RecoverColon, RecoverComma, PARAM_EXPECTED};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
-use super::{AttrWrapper, BlockMode, ForceCollect, Parser, PathStyle, Restrictions, TokenType};
+use super::{
+    AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, TokenType,
+};
 use super::{SemiColonMode, SeqSep, TokenExpectType, TrailingToken};
 use crate::maybe_recover_from_interpolated_ty_qpath;
 
+use ast::token::DelimToken;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Token, TokenKind};
 use rustc_ast::tokenstream::Spacing;
@@ -91,6 +94,8 @@ impl<'a> Parser<'a> {
     /// Parses an expression.
     #[inline]
     pub fn parse_expr(&mut self) -> PResult<'a, P<Expr>> {
+        self.current_closure.take();
+
         self.parse_expr_res(Restrictions::empty(), None)
     }
 
@@ -516,6 +521,26 @@ macro_rules! make_it {
             token::BinOp(token::And) | token::AndAnd => {
                 make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo))
             }
+            token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
+                let mut err = this.struct_span_err(lo, "leading `+` is not supported");
+                err.span_label(lo, "unexpected `+`");
+
+                // a block on the LHS might have been intended to be an expression instead
+                if let Some(sp) = this.sess.ambiguous_block_expr_parse.borrow().get(&lo) {
+                    this.sess.expr_parentheses_needed(&mut err, *sp);
+                } else {
+                    err.span_suggestion_verbose(
+                        lo,
+                        "try removing the `+`",
+                        "".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+                err.emit();
+
+                this.bump();
+                this.parse_prefix_expr(None)
+            } // `+expr`
             token::Ident(..) if this.token.is_keyword(kw::Box) => {
                 make_it!(this, attrs, |this, _| this.parse_box_expr(lo))
             }
@@ -1786,7 +1811,7 @@ fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let capture_clause = self.parse_capture_clause()?;
         let decl = self.parse_fn_block_decl()?;
         let decl_hi = self.prev_token.span;
-        let body = match decl.output {
+        let mut body = match decl.output {
             FnRetTy::Default(_) => {
                 let restrictions = self.restrictions - Restrictions::STMT_EXPR;
                 self.parse_expr_res(restrictions, None)?
@@ -1803,11 +1828,28 @@ fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
             self.sess.gated_spans.gate(sym::async_closure, span);
         }
 
-        Ok(self.mk_expr(
+        if self.token.kind == TokenKind::Semi && self.token_cursor.frame.delim == DelimToken::Paren
+        {
+            // It is likely that the closure body is a block but where the
+            // braces have been removed. We will recover and eat the next
+            // statements later in the parsing process.
+            body = self.mk_expr_err(body.span);
+        }
+
+        let body_span = body.span;
+
+        let closure = self.mk_expr(
             lo.to(body.span),
             ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)),
             attrs,
-        ))
+        );
+
+        // Disable recovery for closure body
+        let spans =
+            ClosureSpans { whole_closure: closure.span, closing_pipe: decl_hi, body: body_span };
+        self.current_closure = Some(spans);
+
+        Ok(closure)
     }
 
     /// Parses an optional `move` prefix to a closure-like construct.