let_chains: Add support for parsing let expressions.
This commit is contained in:
parent
3fc9642014
commit
dff1e379fc
3 changed files with 21 additions and 52 deletions
|
@ -2215,13 +2215,8 @@ impl<'a> Parser<'a> {
|
||||||
} else {
|
} else {
|
||||||
ex = ExprKind::Yield(None);
|
ex = ExprKind::Yield(None);
|
||||||
}
|
}
|
||||||
} else if self.token.is_keyword(kw::Let) {
|
} else if self.eat_keyword(kw::Let) {
|
||||||
// Catch this syntax error here, instead of in `parse_ident`, so
|
return self.parse_let_expr(attrs);
|
||||||
// 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 is_span_rust_2018 && self.eat_keyword(kw::Await) {
|
} 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)?;
|
let (await_hi, e_kind) = self.parse_await_macro_or_alt(lo, self.prev_span)?;
|
||||||
hi = await_hi;
|
hi = await_hi;
|
||||||
|
@ -2483,15 +2478,13 @@ impl<'a> Parser<'a> {
|
||||||
attrs.extend::<Vec<_>>(expr.attrs.into());
|
attrs.extend::<Vec<_>>(expr.attrs.into());
|
||||||
expr.attrs = attrs;
|
expr.attrs = attrs;
|
||||||
match expr.node {
|
match expr.node {
|
||||||
ExprKind::If(..) | ExprKind::IfLet(..) => {
|
ExprKind::If(..) if !expr.attrs.is_empty() => {
|
||||||
if !expr.attrs.is_empty() {
|
// Just point to the first attribute in there...
|
||||||
// Just point to the first attribute in there...
|
let span = expr.attrs[0].span;
|
||||||
let span = expr.attrs[0].span;
|
|
||||||
|
|
||||||
self.span_err(span,
|
self.span_err(span,
|
||||||
"attributes are not yet allowed on `if` \
|
"attributes are not yet allowed on `if` \
|
||||||
expressions");
|
expressions");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -3163,9 +3156,6 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
/// Parses an `if` or `if let` expression (`if` token already eaten).
|
/// Parses an `if` or `if let` expression (`if` token already eaten).
|
||||||
fn parse_if_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
|
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 lo = self.prev_span;
|
||||||
let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
|
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))
|
Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses an `if let` expression (`if` token already eaten).
|
/// Parses a `let $pats = $expr` pseudo-expression.
|
||||||
fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>)
|
/// The `let` token has already been eaten.
|
||||||
-> PResult<'a, P<Expr>> {
|
fn parse_let_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
|
||||||
let lo = self.prev_span;
|
let lo = self.prev_span;
|
||||||
self.expect_keyword(kw::Let)?;
|
|
||||||
let pats = self.parse_pats()?;
|
let pats = self.parse_pats()?;
|
||||||
self.expect(&token::Eq)?;
|
self.expect(&token::Eq)?;
|
||||||
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
|
|
||||||
let thn = self.parse_block()?;
|
let expr = self.with_res(
|
||||||
let (hi, els) = if self.eat_keyword(kw::Else) {
|
Restrictions::NO_STRUCT_LITERAL,
|
||||||
let expr = self.parse_else_expr()?;
|
|this| this.parse_assoc_expr_with(1 + AssocOp::LAnd.precedence(), None.into())
|
||||||
(expr.span, Some(expr))
|
)?;
|
||||||
} else {
|
Ok(self.mk_expr(lo.to(expr.span), ExprKind::Let(pats, expr), attrs))
|
||||||
(thn.span, None)
|
|
||||||
};
|
|
||||||
Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pats, expr, thn, els), attrs))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses `move |args| expr`.
|
/// Parses `move |args| expr`.
|
||||||
|
@ -3299,9 +3285,6 @@ impl<'a> Parser<'a> {
|
||||||
fn parse_while_expr(&mut self, opt_label: Option<Label>,
|
fn parse_while_expr(&mut self, opt_label: Option<Label>,
|
||||||
span_lo: Span,
|
span_lo: Span,
|
||||||
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
|
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 cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
|
||||||
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
|
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
|
||||||
attrs.extend(iattrs);
|
attrs.extend(iattrs);
|
||||||
|
@ -3309,20 +3292,6 @@ impl<'a> Parser<'a> {
|
||||||
return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs));
|
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
|
// parse `loop {...}`, `loop` token already eaten
|
||||||
fn parse_loop_expr(&mut self, opt_label: Option<Label>,
|
fn parse_loop_expr(&mut self, opt_label: Option<Label>,
|
||||||
span_lo: Span,
|
span_lo: Span,
|
||||||
|
|
|
@ -134,6 +134,7 @@ pub(crate) fn ident_can_begin_expr(name: ast::Name, span: Span, is_raw: bool) ->
|
||||||
kw::Continue,
|
kw::Continue,
|
||||||
kw::False,
|
kw::False,
|
||||||
kw::For,
|
kw::For,
|
||||||
|
kw::Let,
|
||||||
kw::If,
|
kw::If,
|
||||||
kw::Loop,
|
kw::Loop,
|
||||||
kw::Match,
|
kw::Match,
|
||||||
|
|
|
@ -260,6 +260,7 @@ pub enum ExprPrecedence {
|
||||||
|
|
||||||
Box,
|
Box,
|
||||||
AddrOf,
|
AddrOf,
|
||||||
|
Let,
|
||||||
Unary,
|
Unary,
|
||||||
|
|
||||||
Call,
|
Call,
|
||||||
|
@ -277,9 +278,7 @@ pub enum ExprPrecedence {
|
||||||
Path,
|
Path,
|
||||||
Paren,
|
Paren,
|
||||||
If,
|
If,
|
||||||
IfLet,
|
|
||||||
While,
|
While,
|
||||||
WhileLet,
|
|
||||||
ForLoop,
|
ForLoop,
|
||||||
Loop,
|
Loop,
|
||||||
Match,
|
Match,
|
||||||
|
@ -318,6 +317,8 @@ impl ExprPrecedence {
|
||||||
// Unary, prefix
|
// Unary, prefix
|
||||||
ExprPrecedence::Box |
|
ExprPrecedence::Box |
|
||||||
ExprPrecedence::AddrOf |
|
ExprPrecedence::AddrOf |
|
||||||
|
// Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
|
||||||
|
ExprPrecedence::Let |
|
||||||
ExprPrecedence::Unary => PREC_PREFIX,
|
ExprPrecedence::Unary => PREC_PREFIX,
|
||||||
|
|
||||||
// Unary, postfix
|
// Unary, postfix
|
||||||
|
@ -338,9 +339,7 @@ impl ExprPrecedence {
|
||||||
ExprPrecedence::Path |
|
ExprPrecedence::Path |
|
||||||
ExprPrecedence::Paren |
|
ExprPrecedence::Paren |
|
||||||
ExprPrecedence::If |
|
ExprPrecedence::If |
|
||||||
ExprPrecedence::IfLet |
|
|
||||||
ExprPrecedence::While |
|
ExprPrecedence::While |
|
||||||
ExprPrecedence::WhileLet |
|
|
||||||
ExprPrecedence::ForLoop |
|
ExprPrecedence::ForLoop |
|
||||||
ExprPrecedence::Loop |
|
ExprPrecedence::Loop |
|
||||||
ExprPrecedence::Match |
|
ExprPrecedence::Match |
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue