about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs13
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs32
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast15
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast11
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast15
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast11
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs10
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 @@ impl ExprCollector<'_> {
                 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 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 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 @@ 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<'_>) {
-    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<Pat> { support::children(&self.syntax) }
+    #[inline]
+    pub fn pipe_token(&self) -> Option<SyntaxToken> { 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 @@ impl From<ast::AssocItem> for ast::AnyHasAttrs {
         Self::new(node)
     }
 }
+
+impl ast::OrPat {
+    pub fn leading_pipe(&self) -> Option<SyntaxToken> {
+        self.syntax
+            .children_with_tokens()
+            .find(|it| !it.kind().is_trivia())
+            .and_then(NodeOrToken::into_token)
+            .filter(|it| it.kind() == T![|])
+    }
+}