From f50b201c865c5883f254c46c162ffffe3b2171da Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 27 Oct 2024 05:08:49 +0200 Subject: [PATCH] Put leading `|` in patterns under `OrPat` Previously it was one level above, and that caused problems with macros that expand to it, because macros expect to get only one top-level node. --- .../crates/hir-def/src/body/lower.rs | 4 +++ .../src/handlers/unmerge_match_arm.rs | 3 ++ .../crates/parser/src/grammar/patterns.rs | 13 ++++---- .../crates/parser/src/tests/top_entries.rs | 32 +++++++++++++++++++ .../test_data/parser/inline/ok/match_arm.rast | 15 +++++---- .../test_data/parser/inline/ok/slice_pat.rast | 11 ++++--- .../test_data/parser/inline/ok/tuple_pat.rast | 15 +++++---- .../parser/inline/ok/tuple_pat_fields.rast | 11 ++++--- .../rust-analyzer/crates/syntax/rust.ungram | 2 +- .../crates/syntax/src/ast/generated/nodes.rs | 2 ++ .../crates/syntax/src/ast/node_ext.rs | 10 ++++++ 11 files changed, 87 insertions(+), 31 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index b87e94f9c51..6117664c64c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -1598,6 +1598,10 @@ fn collect_pat(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatI for (id, _) in current_is_used.into_iter() { binding_list.check_is_used(self, id); } + if let &[pat] = &*pats { + // Leading pipe without real OR pattern. Leaving an one-item OR pattern may confuse later stages. + return pat; + } Pat::Or(pats.into()) } ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat(), binding_list), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs index db789cfa334..648bf358b4b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs @@ -34,6 +34,9 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let pipe_token = ctx.find_token_syntax_at_offset(T![|])?; let or_pat = ast::OrPat::cast(pipe_token.parent()?)?.clone_for_update(); + if or_pat.leading_pipe().is_some_and(|it| it == pipe_token) { + return None; + } let match_arm = ast::MatchArm::cast(or_pat.syntax().parent()?)?; let match_arm_body = match_arm.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 3db1a10ca5c..ed01fca2acd 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs @@ -21,7 +21,8 @@ expressions::LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[T![-], T![const]])); pub(crate) fn pattern(p: &mut Parser<'_>) { - pattern_r(p, PAT_RECOVERY_SET); + let m = p.start(); + pattern_r(p, m, false, PAT_RECOVERY_SET); } /// Parses a pattern list separated by pipes `|`. @@ -36,8 +37,9 @@ 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) { - p.eat(T![|]); - pattern_r(p, recovery_set); + let m = p.start(); + let has_leading_pipe = p.eat(T![|]); + pattern_r(p, m, has_leading_pipe, recovery_set); } // test or_pattern @@ -51,11 +53,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<'_>, recovery_set: TokenSet) { - let m = p.start(); +fn pattern_r(p: &mut Parser<'_>, m: Marker, has_leading_pipe: bool, recovery_set: TokenSet) { pattern_single_r(p, recovery_set); - if !p.at(T![|]) { + if !p.at(T![|]) && !has_leading_pipe { m.abandon(p); return; } diff --git a/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs b/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs index c56bf0b6448..7076e03ba4b 100644 --- a/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs +++ b/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs @@ -195,6 +195,38 @@ fn macro_pattern() { error 0: expected pattern "#]], ); + + check( + TopEntryPoint::Pattern, + "| 42 | 43", + expect![[r#" + OR_PAT + PIPE "|" + WHITESPACE " " + LITERAL_PAT + LITERAL + INT_NUMBER "42" + WHITESPACE " " + PIPE "|" + WHITESPACE " " + LITERAL_PAT + LITERAL + INT_NUMBER "43" + "#]], + ); + + check( + TopEntryPoint::Pattern, + "| 42", + expect![[r#" + OR_PAT + PIPE "|" + WHITESPACE " " + LITERAL_PAT + LITERAL + INT_NUMBER "42" + "#]], + ); } #[test] diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast index 8189cf0a8e5..92210281629 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast @@ -102,9 +102,9 @@ SOURCE_FILE COMMA "," WHITESPACE "\n " MATCH_ARM - PIPE "|" - WHITESPACE " " OR_PAT + PIPE "|" + WHITESPACE " " IDENT_PAT NAME IDENT "X" @@ -132,11 +132,12 @@ SOURCE_FILE COMMA "," WHITESPACE "\n " MATCH_ARM - PIPE "|" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "X" + OR_PAT + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "X" WHITESPACE " " FAT_ARROW "=>" WHITESPACE " " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast index dff72ba886f..06c30bba59f 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast @@ -43,11 +43,12 @@ SOURCE_FILE WHITESPACE " " SLICE_PAT L_BRACK "[" - PIPE "|" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "a" + OR_PAT + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "a" COMMA "," WHITESPACE " " REST_PAT diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast index 1a01e0f6938..c7cd11f774b 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast @@ -91,9 +91,9 @@ SOURCE_FILE WHITESPACE " " TUPLE_PAT L_PAREN "(" - PIPE "|" - WHITESPACE " " OR_PAT + PIPE "|" + WHITESPACE " " IDENT_PAT NAME IDENT "a" @@ -105,11 +105,12 @@ SOURCE_FILE IDENT "a" COMMA "," WHITESPACE " " - PIPE "|" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "b" + OR_PAT + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "b" R_PAREN ")" WHITESPACE " " EQ "=" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast index 55baf2fdcb4..96353f46976 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast @@ -110,11 +110,12 @@ SOURCE_FILE NAME_REF IDENT "S" L_PAREN "(" - PIPE "|" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "a" + OR_PAT + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "a" R_PAREN ")" WHITESPACE " " EQ "=" diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 3609da0bb26..02c59646a99 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -736,7 +736,7 @@ PathPat = Path OrPat = - (Pat ('|' Pat)* '|'?) + '|'? (Pat ('|' Pat)*) BoxPat = 'box' Pat diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index b9eb1abb112..23d2b355a94 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -1283,6 +1283,8 @@ pub struct OrPat { impl OrPat { #[inline] pub fn pats(&self) -> AstChildren { support::children(&self.syntax) } + #[inline] + pub fn pipe_token(&self) -> Option { support::token(&self.syntax, T![|]) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs index 11f5e662e3d..6ec73e76f78 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs @@ -1140,3 +1140,13 @@ fn from(node: ast::AssocItem) -> Self { Self::new(node) } } + +impl ast::OrPat { + pub fn leading_pipe(&self) -> Option { + self.syntax + .children_with_tokens() + .find(|it| !it.kind().is_trivia()) + .and_then(NodeOrToken::into_token) + .filter(|it| it.kind() == T![|]) + } +}