mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 05:15:04 +00:00
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:
parent
d6ed146a1c
commit
de8633f15f
7 changed files with 99 additions and 67 deletions
|
@ -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![/=]),
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue