From f0bf75d647ea18ac6a24e03a999019755edd1b17 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 31 Oct 2024 15:32:37 +0200 Subject: [PATCH] Parse patterns with leading pipe properly in all places --- .../crates/parser/src/grammar.rs | 4 +- .../parser/src/grammar/expressions/atom.rs | 2 +- .../crates/parser/src/grammar/patterns.rs | 24 ++++----- .../parser/test_data/generated/runner.rs | 4 ++ .../ok/record_field_pat_leading_or.rast | 54 +++++++++++++++++++ .../inline/ok/record_field_pat_leading_or.rs | 1 + 6 files changed, 73 insertions(+), 16 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_pat_leading_or.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_pat_leading_or.rs diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs index a5c031ad609..a50a2182a7b 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs @@ -67,7 +67,7 @@ pub(crate) fn pat(p: &mut Parser<'_>) { } pub(crate) fn pat_top(p: &mut Parser<'_>) { - patterns::pattern_top(p); + patterns::pattern(p); } pub(crate) fn ty(p: &mut Parser<'_>) { @@ -117,7 +117,7 @@ pub(crate) fn macro_items(p: &mut Parser<'_>) { pub(crate) fn pattern(p: &mut Parser<'_>) { let m = p.start(); - patterns::pattern_top(p); + patterns::pattern(p); if p.at(EOF) { m.abandon(p); return; diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs index 2333e6c862b..97e0392ce15 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs @@ -660,7 +660,7 @@ fn for_expr(p: &mut Parser<'_>, m: Option) -> CompletedMarker { fn let_expr(p: &mut Parser<'_>) -> CompletedMarker { let m = p.start(); p.bump(T![let]); - patterns::pattern_top(p); + patterns::pattern(p); p.expect(T![=]); expr_let(p); m.complete(p, LET_EXPR) diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs index ed01fca2acd..460051a0f4a 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs @@ -20,14 +20,9 @@ const RANGE_PAT_END_FIRST: TokenSet = expressions::LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[T![-], T![const]])); -pub(crate) fn pattern(p: &mut Parser<'_>) { - let m = p.start(); - pattern_r(p, m, false, PAT_RECOVERY_SET); -} - /// Parses a pattern list separated by pipes `|`. -pub(super) fn pattern_top(p: &mut Parser<'_>) { - pattern_top_r(p, PAT_RECOVERY_SET); +pub(crate) fn pattern(p: &mut Parser<'_>) { + pattern_r(p, PAT_RECOVERY_SET); } pub(crate) fn pattern_single(p: &mut Parser<'_>) { @@ -37,9 +32,7 @@ pub(crate) fn pattern_single(p: &mut Parser<'_>) { /// Parses a pattern list separated by pipes `|` /// using the given `recovery_set`. pub(super) fn pattern_top_r(p: &mut Parser<'_>, recovery_set: TokenSet) { - let m = p.start(); - let has_leading_pipe = p.eat(T![|]); - pattern_r(p, m, has_leading_pipe, recovery_set); + pattern_r(p, recovery_set); } // test or_pattern @@ -53,7 +46,10 @@ pub(super) fn pattern_top_r(p: &mut Parser<'_>, recovery_set: TokenSet) { // } /// Parses a pattern list separated by pipes `|`, with no leading `|`,using the /// given `recovery_set`. -fn pattern_r(p: &mut Parser<'_>, m: Marker, has_leading_pipe: bool, recovery_set: TokenSet) { +fn pattern_r(p: &mut Parser<'_>, recovery_set: TokenSet) { + let m = p.start(); + let has_leading_pipe = p.eat(T![|]); + pattern_single_r(p, recovery_set); if !p.at(T![|]) && !has_leading_pipe { @@ -319,6 +315,8 @@ fn record_pat_field(p: &mut Parser<'_>) { IDENT | INT_NUMBER if p.nth(1) == T![:] => { name_ref_or_index(p); p.bump(T![:]); + // test record_field_pat_leading_or + // fn foo() { let R { a: | 1 | 2 } = 0; } pattern(p); } // test_err record_pat_field_eq_recovery @@ -438,7 +436,7 @@ fn tuple_pat(p: &mut Parser<'_>) -> CompletedMarker { } has_rest |= p.at(T![..]); - pattern_top(p); + pattern(p); if !p.at(T![')']) { has_comma = true; p.expect(T![,]); @@ -465,7 +463,7 @@ fn slice_pat(p: &mut Parser<'_>) -> CompletedMarker { fn pat_list(p: &mut Parser<'_>, ket: SyntaxKind) { while !p.at(EOF) && !p.at(ket) { - pattern_top(p); + pattern(p); if !p.eat(T![,]) { if p.at_ts(PAT_TOP_FIRST) { p.error(format!("expected {:?}, got {:?}", T![,], p.current())); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index 5b41dd07adc..62b381b6688 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -493,6 +493,10 @@ fn record_field_list() { run_and_expect_no_errors("test_data/parser/inline/ok/record_field_list.rs"); } #[test] + fn record_field_pat_leading_or() { + run_and_expect_no_errors("test_data/parser/inline/ok/record_field_pat_leading_or.rs"); + } + #[test] fn record_lit() { run_and_expect_no_errors("test_data/parser/inline/ok/record_lit.rs"); } #[test] fn record_literal_field_with_attr() { diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_pat_leading_or.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_pat_leading_or.rast new file mode 100644 index 00000000000..4ef6c1c45f5 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_pat_leading_or.rast @@ -0,0 +1,54 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "foo" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE " " + LET_STMT + LET_KW "let" + WHITESPACE " " + RECORD_PAT + PATH + PATH_SEGMENT + NAME_REF + IDENT "R" + WHITESPACE " " + RECORD_PAT_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_PAT_FIELD + NAME_REF + IDENT "a" + COLON ":" + WHITESPACE " " + OR_PAT + PIPE "|" + WHITESPACE " " + LITERAL_PAT + LITERAL + INT_NUMBER "1" + WHITESPACE " " + PIPE "|" + WHITESPACE " " + LITERAL_PAT + LITERAL + INT_NUMBER "2" + WHITESPACE " " + R_CURLY "}" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "0" + SEMICOLON ";" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_pat_leading_or.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_pat_leading_or.rs new file mode 100644 index 00000000000..a5e7510c140 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_pat_leading_or.rs @@ -0,0 +1 @@ +fn foo() { let R { a: | 1 | 2 } = 0; }