Skip to content

Commit cfb0295

Browse files
committed
let_chains: Add support for parsing let expressions.
1 parent e9a6e5a commit cfb0295

File tree

3 files changed

+22
-53
lines changed

3 files changed

+22
-53
lines changed

src/libsyntax/parse/parser.rs

Lines changed: 18 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2621,13 +2621,8 @@ impl<'a> Parser<'a> {
26212621
} else {
26222622
ex = ExprKind::Yield(None);
26232623
}
2624-
} else if self.token.is_keyword(keywords::Let) {
2625-
// Catch this syntax error here, instead of in `parse_ident`, so
2626-
// that we can explicitly mention that let is not to be used as an expression
2627-
let mut db = self.fatal("expected expression, found statement (`let`)");
2628-
db.span_label(self.span, "expected expression");
2629-
db.note("variable declaration using `let` is a statement");
2630-
return Err(db);
2624+
} else if self.eat_keyword(keywords::Let) {
2625+
return self.parse_let_expr(attrs);
26312626
} else if self.span.rust_2018() && self.eat_keyword(keywords::Await) {
26322627
// FIXME: remove this branch when `await!` is no longer supported
26332628
// https://github.com/rust-lang/rust/issues/60610
@@ -2886,15 +2881,13 @@ impl<'a> Parser<'a> {
28862881
attrs.extend::<Vec<_>>(expr.attrs.into());
28872882
expr.attrs = attrs;
28882883
match expr.node {
2889-
ExprKind::If(..) | ExprKind::IfLet(..) => {
2890-
if !expr.attrs.is_empty() {
2891-
// Just point to the first attribute in there...
2892-
let span = expr.attrs[0].span;
2893-
2894-
self.span_err(span,
2895-
"attributes are not yet allowed on `if` \
2896-
expressions");
2897-
}
2884+
ExprKind::If(..) if !expr.attrs.is_empty() => {
2885+
// Just point to the first attribute in there...
2886+
let span = expr.attrs[0].span;
2887+
2888+
self.span_err(span,
2889+
"attributes are not yet allowed on `if` \
2890+
expressions");
28982891
}
28992892
_ => {}
29002893
}
@@ -3778,9 +3771,6 @@ impl<'a> Parser<'a> {
37783771

37793772
/// Parses an `if` or `if let` expression (`if` token already eaten).
37803773
fn parse_if_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
3781-
if self.check_keyword(keywords::Let) {
3782-
return self.parse_if_let_expr(attrs);
3783-
}
37843774
let lo = self.prev_span;
37853775
let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
37863776

@@ -3812,22 +3802,18 @@ impl<'a> Parser<'a> {
38123802
Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs))
38133803
}
38143804

3815-
/// Parses an `if let` expression (`if` token already eaten).
3816-
fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>)
3817-
-> PResult<'a, P<Expr>> {
3805+
/// Parses a `let $pats = $expr` pseudo-expression.
3806+
/// The `let` token has already been eaten.
3807+
fn parse_let_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
38183808
let lo = self.prev_span;
3819-
self.expect_keyword(keywords::Let)?;
38203809
let pats = self.parse_pats()?;
38213810
self.expect(&token::Eq)?;
3822-
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
3823-
let thn = self.parse_block()?;
3824-
let (hi, els) = if self.eat_keyword(keywords::Else) {
3825-
let expr = self.parse_else_expr()?;
3826-
(expr.span, Some(expr))
3827-
} else {
3828-
(thn.span, None)
3829-
};
3830-
Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pats, expr, thn, els), attrs))
3811+
3812+
let expr = self.with_res(
3813+
Restrictions::NO_STRUCT_LITERAL,
3814+
|this| this.parse_assoc_expr_with(1 + AssocOp::LAnd.precedence(), None.into())
3815+
)?;
3816+
Ok(self.mk_expr(lo.to(expr.span), ExprKind::Let(pats, expr), attrs))
38313817
}
38323818

38333819
/// Parses `move |args| expr`.
@@ -3930,30 +3916,13 @@ impl<'a> Parser<'a> {
39303916
fn parse_while_expr(&mut self, opt_label: Option<Label>,
39313917
span_lo: Span,
39323918
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
3933-
if self.token.is_keyword(keywords::Let) {
3934-
return self.parse_while_let_expr(opt_label, span_lo, attrs);
3935-
}
39363919
let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
39373920
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
39383921
attrs.extend(iattrs);
39393922
let span = span_lo.to(body.span);
39403923
return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs));
39413924
}
39423925

3943-
/// Parses a `while let` expression (`while` token already eaten).
3944-
fn parse_while_let_expr(&mut self, opt_label: Option<Label>,
3945-
span_lo: Span,
3946-
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
3947-
self.expect_keyword(keywords::Let)?;
3948-
let pats = self.parse_pats()?;
3949-
self.expect(&token::Eq)?;
3950-
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
3951-
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
3952-
attrs.extend(iattrs);
3953-
let span = span_lo.to(body.span);
3954-
return Ok(self.mk_expr(span, ExprKind::WhileLet(pats, expr, body, opt_label), attrs));
3955-
}
3956-
39573926
// parse `loop {...}`, `loop` token already eaten
39583927
fn parse_loop_expr(&mut self, opt_label: Option<Label>,
39593928
span_lo: Span,

src/libsyntax/parse/token.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ pub(crate) fn ident_can_begin_expr(ident: ast::Ident, is_raw: bool) -> bool {
122122
keywords::Continue.name(),
123123
keywords::False.name(),
124124
keywords::For.name(),
125+
keywords::Let.name(),
125126
keywords::If.name(),
126127
keywords::Loop.name(),
127128
keywords::Match.name(),

src/libsyntax/util/parser.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ pub enum ExprPrecedence {
265265

266266
Box,
267267
AddrOf,
268+
Let,
268269
Unary,
269270

270271
Call,
@@ -282,9 +283,7 @@ pub enum ExprPrecedence {
282283
Path,
283284
Paren,
284285
If,
285-
IfLet,
286286
While,
287-
WhileLet,
288287
ForLoop,
289288
Loop,
290289
Match,
@@ -324,6 +323,8 @@ impl ExprPrecedence {
324323
// Unary, prefix
325324
ExprPrecedence::Box |
326325
ExprPrecedence::AddrOf |
326+
// Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
327+
ExprPrecedence::Let |
327328
ExprPrecedence::Unary => PREC_PREFIX,
328329

329330
// Unary, postfix
@@ -344,9 +345,7 @@ impl ExprPrecedence {
344345
ExprPrecedence::Path |
345346
ExprPrecedence::Paren |
346347
ExprPrecedence::If |
347-
ExprPrecedence::IfLet |
348348
ExprPrecedence::While |
349-
ExprPrecedence::WhileLet |
350349
ExprPrecedence::ForLoop |
351350
ExprPrecedence::Loop |
352351
ExprPrecedence::Match |

0 commit comments

Comments
 (0)