Parse let expressions in order to support let chains

We still need to reject freestanding `let` expressions: see https://github.com/rust-analyzer/rust-analyzer/issues/11320#issuecomment-1018212465.
This commit is contained in:
Chayim Refael Friedman 2022-01-23 04:21:09 +02:00
parent d6ed146a1c
commit de8633f15f
7 changed files with 99 additions and 67 deletions

View file

@ -29,6 +29,15 @@ fn expr_no_struct(p: &mut Parser) {
expr_bp(p, None, r, 1);
}
/// Parses the expression in `let pattern = expression`.
/// It needs to be parsed with lower precedence than `&&`, so that
/// `if let true = true && false` is parsed as `if (let true = true) && (true)`
/// and not `if let true = (true && true)`.
fn expr_let(p: &mut Parser) {
let r = Restrictions { forbid_structs: true, prefer_stmt: false };
expr_bp(p, None, r, 5);
}
pub(super) fn stmt(p: &mut Parser, semicolon: Semicolon) {
if p.eat(T![;]) {
return;
@ -185,6 +194,7 @@ fn current_op(p: &Parser) -> (u8, SyntaxKind) {
T![%] if p.at(T![%=]) => (1, T![%=]),
T![%] => (11, T![%]),
T![&] if p.at(T![&=]) => (1, T![&=]),
// If you update this, remember to update `expr_let()` too.
T![&] if p.at(T![&&]) => (4, T![&&]),
T![&] => (8, T![&]),
T![/] if p.at(T![/=]) => (1, T![/=]),

View file

@ -79,6 +79,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
closure_expr(p)
}
T![if] => if_expr(p),
T![let] => let_expr(p),
T![loop] => loop_expr(p, None),
T![box] => box_expr(p, None),
@ -286,7 +287,7 @@ fn if_expr(p: &mut Parser) -> CompletedMarker {
assert!(p.at(T![if]));
let m = p.start();
p.bump(T![if]);
condition(p);
expr_no_struct(p);
block_expr(p);
if p.at(T![else]) {
p.bump(T![else]);
@ -335,7 +336,7 @@ fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
assert!(p.at(T![while]));
let m = m.unwrap_or_else(|| p.start());
p.bump(T![while]);
condition(p);
expr_no_struct(p);
block_expr(p);
m.complete(p, WHILE_EXPR)
}
@ -355,22 +356,18 @@ fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
m.complete(p, FOR_EXPR)
}
// test cond
// fn foo() { if let Some(_) = None {} }
// fn bar() {
// if let Some(_) | Some(_) = None {}
// if let | Some(_) = None {}
// while let Some(_) | Some(_) = None {}
// while let | Some(_) = None {}
// test let_expr
// fn foo() {
// if let Some(_) = None && true {}
// while 1 == 5 && (let None = None) {}
// }
fn condition(p: &mut Parser) {
fn let_expr(p: &mut Parser) -> CompletedMarker {
let m = p.start();
if p.eat(T![let]) {
patterns::pattern_top(p);
p.expect(T![=]);
}
expr_no_struct(p);
m.complete(p, CONDITION);
p.bump(T![let]);
patterns::pattern_top(p);
p.expect(T![=]);
expr_let(p);
m.complete(p, LET_EXPR)
}
// test match_expr
@ -482,10 +479,6 @@ fn match_guard(p: &mut Parser) -> CompletedMarker {
assert!(p.at(T![if]));
let m = p.start();
p.bump(T![if]);
if p.eat(T![let]) {
patterns::pattern_top(p);
p.expect(T![=]);
}
expr(p);
m.complete(p, MATCH_GUARD)
}