Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/parser/src/grammar/expressions.rs')
-rw-r--r--crates/parser/src/grammar/expressions.rs92
1 files changed, 51 insertions, 41 deletions
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs
index 2b4151e3b7..76d26c1ecd 100644
--- a/crates/parser/src/grammar/expressions.rs
+++ b/crates/parser/src/grammar/expressions.rs
@@ -77,38 +77,38 @@ pub(super) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) {
return;
}
- if let Some((cm, blocklike)) = expr_stmt(p, Some(m)) {
- if !(p.at(T!['}']) || (semicolon != Semicolon::Required && p.at(EOF))) {
- // test no_semi_after_block
- // fn foo() {
- // if true {}
- // loop {}
- // match () {}
- // while true {}
- // for _ in () {}
- // {}
- // {}
- // macro_rules! test {
- // () => {}
- // }
- // test!{}
- // }
- let m = cm.precede(p);
- match semicolon {
- Semicolon::Required => {
- if blocklike.is_block() {
- p.eat(T![;]);
- } else {
- p.expect(T![;]);
- }
- }
- Semicolon::Optional => {
+ if let Some((cm, blocklike)) = expr_stmt(p, Some(m))
+ && !(p.at(T!['}']) || (semicolon != Semicolon::Required && p.at(EOF)))
+ {
+ // test no_semi_after_block
+ // fn foo() {
+ // if true {}
+ // loop {}
+ // match () {}
+ // while true {}
+ // for _ in () {}
+ // {}
+ // {}
+ // macro_rules! test {
+ // () => {}
+ // }
+ // test!{}
+ // }
+ let m = cm.precede(p);
+ match semicolon {
+ Semicolon::Required => {
+ if blocklike.is_block() {
p.eat(T![;]);
+ } else {
+ p.expect(T![;]);
}
- Semicolon::Forbidden => (),
}
- m.complete(p, EXPR_STMT);
+ Semicolon::Optional => {
+ p.eat(T![;]);
+ }
+ Semicolon::Forbidden => (),
}
+ m.complete(p, EXPR_STMT);
}
}
@@ -134,14 +134,11 @@ pub(super) fn let_stmt(p: &mut Parser<'_>, with_semi: Semicolon) {
if p.at(T![else]) {
// test_err let_else_right_curly_brace
// fn func() { let Some(_) = {Some(1)} else { panic!("h") };}
- if let Some(expr) = expr_after_eq {
- if let Some(token) = expr.last_token(p) {
- if token == T!['}'] {
- p.error(
- "right curly brace `}` before `else` in a `let...else` statement not allowed"
- )
- }
- }
+ if let Some(expr) = expr_after_eq
+ && let Some(token) = expr.last_token(p)
+ && token == T!['}']
+ {
+ p.error("right curly brace `}` before `else` in a `let...else` statement not allowed")
}
// test let_else
@@ -433,6 +430,11 @@ fn postfix_expr(
// }
T!['('] if allow_calls => call_expr(p, lhs),
T!['['] if allow_calls => index_expr(p, lhs),
+ // test_err postfix_dot_expr_ambiguity
+ // fn foo() {
+ // x.
+ // ()
+ // }
T![.] => match postfix_dot_expr::<false>(p, lhs) {
Ok(it) => it,
Err(it) => {
@@ -461,6 +463,7 @@ fn postfix_dot_expr<const FLOAT_RECOVERY: bool>(
if PATH_NAME_REF_KINDS.contains(p.nth(nth1))
&& (p.nth(nth2) == T!['('] || p.nth_at(nth2, T![::]))
+ || p.nth(nth1) == T!['(']
{
return Ok(method_call_expr::<FLOAT_RECOVERY>(p, lhs));
}
@@ -529,19 +532,26 @@ fn method_call_expr<const FLOAT_RECOVERY: bool>(
lhs: CompletedMarker,
) -> CompletedMarker {
if FLOAT_RECOVERY {
- assert!(p.at_ts(PATH_NAME_REF_KINDS) && (p.nth(1) == T!['('] || p.nth_at(1, T![::])));
+ assert!(
+ p.at_ts(PATH_NAME_REF_KINDS) && (p.nth(1) == T!['('] || p.nth_at(1, T![::]))
+ || p.current() == T!['(']
+ );
} else {
+ assert!(p.at(T![.]));
assert!(
- p.at(T![.])
- && PATH_NAME_REF_KINDS.contains(p.nth(1))
- && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))
+ PATH_NAME_REF_KINDS.contains(p.nth(1)) && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))
+ || p.nth(1) == T!['(']
);
}
let m = lhs.precede(p);
if !FLOAT_RECOVERY {
p.bump(T![.]);
}
- name_ref_mod_path(p);
+ if p.at_ts(PATH_NAME_REF_KINDS) {
+ name_ref_mod_path(p);
+ } else {
+ p.error("expected method name, field name or number");
+ }
generic_args::opt_generic_arg_list_expr(p);
if p.at(T!['(']) {
arg_list(p);