about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-05-15 16:03:22 +0200
committerMazdak Farrokhzad <twingoow@gmail.com>2019-06-23 01:29:29 +0200
commitdff1e379fc55429ea9a4794634e02c17cebee603 (patch)
tree4ec38d68cd0186eebcfba9d20144d43e742a0a74 /src/libsyntax
parent3fc964201486f9fdb006bfb7d0caf9b1c3e6cb71 (diff)
downloadrust-dff1e379fc55429ea9a4794634e02c17cebee603.tar.gz
rust-dff1e379fc55429ea9a4794634e02c17cebee603.zip
let_chains: Add support for parsing let expressions.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/parse/parser.rs67
-rw-r--r--src/libsyntax/parse/token.rs1
-rw-r--r--src/libsyntax/util/parser.rs7
3 files changed, 22 insertions, 53 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index fa697e06d26..8cf05059e8a 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2215,13 +2215,8 @@ impl<'a> Parser<'a> {
                     } else {
                         ex = ExprKind::Yield(None);
                     }
-                } else if self.token.is_keyword(kw::Let) {
-                    // Catch this syntax error here, instead of in `parse_ident`, so
-                    // that we can explicitly mention that let is not to be used as an expression
-                    let mut db = self.fatal("expected expression, found statement (`let`)");
-                    db.span_label(self.token.span, "expected expression");
-                    db.note("variable declaration using `let` is a statement");
-                    return Err(db);
+                } else if self.eat_keyword(kw::Let) {
+                    return self.parse_let_expr(attrs);
                 } else if is_span_rust_2018 && self.eat_keyword(kw::Await) {
                     let (await_hi, e_kind) = self.parse_await_macro_or_alt(lo, self.prev_span)?;
                     hi = await_hi;
@@ -2483,15 +2478,13 @@ impl<'a> Parser<'a> {
                 attrs.extend::<Vec<_>>(expr.attrs.into());
                 expr.attrs = attrs;
                 match expr.node {
-                    ExprKind::If(..) | ExprKind::IfLet(..) => {
-                        if !expr.attrs.is_empty() {
-                            // Just point to the first attribute in there...
-                            let span = expr.attrs[0].span;
-
-                            self.span_err(span,
-                                "attributes are not yet allowed on `if` \
-                                expressions");
-                        }
+                    ExprKind::If(..) if !expr.attrs.is_empty() => {
+                        // Just point to the first attribute in there...
+                        let span = expr.attrs[0].span;
+
+                        self.span_err(span,
+                            "attributes are not yet allowed on `if` \
+                            expressions");
                     }
                     _ => {}
                 }
@@ -3163,9 +3156,6 @@ impl<'a> Parser<'a> {
 
     /// Parses an `if` or `if let` expression (`if` token already eaten).
     fn parse_if_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
-        if self.check_keyword(kw::Let) {
-            return self.parse_if_let_expr(attrs);
-        }
         let lo = self.prev_span;
         let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
 
@@ -3197,22 +3187,18 @@ impl<'a> Parser<'a> {
         Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs))
     }
 
-    /// Parses an `if let` expression (`if` token already eaten).
-    fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>)
-                             -> PResult<'a, P<Expr>> {
+    /// Parses a `let $pats = $expr` pseudo-expression.
+    /// The `let` token has already been eaten.
+    fn parse_let_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         let lo = self.prev_span;
-        self.expect_keyword(kw::Let)?;
         let pats = self.parse_pats()?;
         self.expect(&token::Eq)?;
-        let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
-        let thn = self.parse_block()?;
-        let (hi, els) = if self.eat_keyword(kw::Else) {
-            let expr = self.parse_else_expr()?;
-            (expr.span, Some(expr))
-        } else {
-            (thn.span, None)
-        };
-        Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pats, expr, thn, els), attrs))
+
+        let expr = self.with_res(
+            Restrictions::NO_STRUCT_LITERAL,
+            |this| this.parse_assoc_expr_with(1 + AssocOp::LAnd.precedence(), None.into())
+        )?;
+        Ok(self.mk_expr(lo.to(expr.span), ExprKind::Let(pats, expr), attrs))
     }
 
     /// Parses `move |args| expr`.
@@ -3299,9 +3285,6 @@ impl<'a> Parser<'a> {
     fn parse_while_expr(&mut self, opt_label: Option<Label>,
                             span_lo: Span,
                             mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
-        if self.token.is_keyword(kw::Let) {
-            return self.parse_while_let_expr(opt_label, span_lo, attrs);
-        }
         let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
@@ -3309,20 +3292,6 @@ impl<'a> Parser<'a> {
         return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs));
     }
 
-    /// Parses a `while let` expression (`while` token already eaten).
-    fn parse_while_let_expr(&mut self, opt_label: Option<Label>,
-                                span_lo: Span,
-                                mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
-        self.expect_keyword(kw::Let)?;
-        let pats = self.parse_pats()?;
-        self.expect(&token::Eq)?;
-        let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
-        let (iattrs, body) = self.parse_inner_attrs_and_block()?;
-        attrs.extend(iattrs);
-        let span = span_lo.to(body.span);
-        return Ok(self.mk_expr(span, ExprKind::WhileLet(pats, expr, body, opt_label), attrs));
-    }
-
     // parse `loop {...}`, `loop` token already eaten
     fn parse_loop_expr(&mut self, opt_label: Option<Label>,
                            span_lo: Span,
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index cc34883e2e8..98e06ad73c9 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -134,6 +134,7 @@ pub(crate) fn ident_can_begin_expr(name: ast::Name, span: Span, is_raw: bool) ->
         kw::Continue,
         kw::False,
         kw::For,
+        kw::Let,
         kw::If,
         kw::Loop,
         kw::Match,
diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs
index fcecee8c57f..81b5b085937 100644
--- a/src/libsyntax/util/parser.rs
+++ b/src/libsyntax/util/parser.rs
@@ -260,6 +260,7 @@ pub enum ExprPrecedence {
 
     Box,
     AddrOf,
+    Let,
     Unary,
 
     Call,
@@ -277,9 +278,7 @@ pub enum ExprPrecedence {
     Path,
     Paren,
     If,
-    IfLet,
     While,
-    WhileLet,
     ForLoop,
     Loop,
     Match,
@@ -318,6 +317,8 @@ impl ExprPrecedence {
             // Unary, prefix
             ExprPrecedence::Box |
             ExprPrecedence::AddrOf |
+            // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
+            ExprPrecedence::Let |
             ExprPrecedence::Unary => PREC_PREFIX,
 
             // Unary, postfix
@@ -338,9 +339,7 @@ impl ExprPrecedence {
             ExprPrecedence::Path |
             ExprPrecedence::Paren |
             ExprPrecedence::If |
-            ExprPrecedence::IfLet |
             ExprPrecedence::While |
-            ExprPrecedence::WhileLet |
             ExprPrecedence::ForLoop |
             ExprPrecedence::Loop |
             ExprPrecedence::Match |