about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-02-10 20:14:08 +0000
committerGitHub <noreply@github.com>2020-02-10 20:14:08 +0000
commitf8d6d6f23bfb15021be91031ba983da19f0d3ada (patch)
tree9c6ab9425ba72c440b2a475d92ed984ccf1aebcc
parent29f5e7eebf606c1929d5a77ad66624cd4f3fcf49 (diff)
parent49b53cd7a0861cdba65643e3da441eefbe18d6e6 (diff)
downloadrust-f8d6d6f23bfb15021be91031ba983da19f0d3ada.tar.gz
rust-f8d6d6f23bfb15021be91031ba983da19f0d3ada.zip
Merge #3074
3074: Or patterns r=matthewjasper a=matthewjasper

Works towards #2458

Co-authored-by: Matthew Jasper <mjjasper1@gmail.com>
-rw-r--r--crates/ra_assists/src/handlers/fill_match_arms.rs6
-rw-r--r--crates/ra_assists/src/handlers/merge_match_arms.rs8
-rw-r--r--crates/ra_assists/src/handlers/move_guard.rs6
-rw-r--r--crates/ra_hir_def/src/body/lower.rs15
-rw-r--r--crates/ra_hir_def/src/body/scope.rs4
-rw-r--r--crates/ra_hir_def/src/expr.rs5
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs4
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs12
-rw-r--r--crates/ra_ide/src/inlay_hints.rs5
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs4
-rw-r--r--crates/ra_parser/src/grammar/params.rs4
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs67
-rw-r--r--crates/ra_parser/src/syntax_kind/generated.rs2
-rw-r--r--crates/ra_syntax/src/ast/generated.rs81
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0030_cond.txt86
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt38
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.rs3
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.txt62
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.rs8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.txt112
-rw-r--r--xtask/src/ast_src.rs8
21 files changed, 427 insertions, 113 deletions
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs
index 0908fc2469f..ae2437ed32f 100644
--- a/crates/ra_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ra_assists/src/handlers/fill_match_arms.rs
@@ -75,10 +75,10 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> {
 }
 
 fn is_trivial(arm: &ast::MatchArm) -> bool {
-    arm.pats().any(|pat| match pat {
-        ast::Pat::PlaceholderPat(..) => true,
+    match arm.pat() {
+        Some(ast::Pat::PlaceholderPat(..)) => true,
         _ => false,
-    })
+    }
 }
 
 fn resolve_enum_def(
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs
index 670614dd83d..b2a194cb5f2 100644
--- a/crates/ra_assists/src/handlers/merge_match_arms.rs
+++ b/crates/ra_assists/src/handlers/merge_match_arms.rs
@@ -75,7 +75,7 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> {
         } else {
             arms_to_merge
                 .iter()
-                .flat_map(ast::MatchArm::pats)
+                .filter_map(ast::MatchArm::pat)
                 .map(|x| x.syntax().to_string())
                 .collect::<Vec<String>>()
                 .join(" | ")
@@ -96,10 +96,10 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> {
 }
 
 fn contains_placeholder(a: &ast::MatchArm) -> bool {
-    a.pats().any(|x| match x {
-        ra_syntax::ast::Pat::PlaceholderPat(..) => true,
+    match a.pat() {
+        Some(ra_syntax::ast::Pat::PlaceholderPat(..)) => true,
         _ => false,
-    })
+    }
 }
 
 fn next_arm(arm: &ast::MatchArm) -> Option<ast::MatchArm> {
diff --git a/crates/ra_assists/src/handlers/move_guard.rs b/crates/ra_assists/src/handlers/move_guard.rs
index 2b91ce7c4dc..a61a2ba3e12 100644
--- a/crates/ra_assists/src/handlers/move_guard.rs
+++ b/crates/ra_assists/src/handlers/move_guard.rs
@@ -90,7 +90,7 @@ pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option<Assist> {
 // ```
 pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> {
     let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?;
-    let last_match_pat = match_arm.pats().last()?;
+    let match_pat = match_arm.pat()?;
 
     let arm_body = match_arm.expr()?;
     let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone())?;
@@ -122,8 +122,8 @@ pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> {
                 _ => edit.replace(if_expr.syntax().text_range(), then_block.syntax().text()),
             }
 
-            edit.insert(last_match_pat.syntax().text_range().end(), buf);
-            edit.set_cursor(last_match_pat.syntax().text_range().end() + TextUnit::from(1));
+            edit.insert(match_pat.syntax().text_range().end(), buf);
+            edit.set_cursor(match_pat.syntax().text_range().end() + TextUnit::from(1));
         },
     )
 }
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index e656f9a41bc..fe0973fc764 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -164,9 +164,9 @@ where
                             let match_expr = self.collect_expr_opt(condition.expr());
                             let placeholder_pat = self.missing_pat();
                             let arms = vec![
-                                MatchArm { pats: vec![pat], expr: then_branch, guard: None },
+                                MatchArm { pat, expr: then_branch, guard: None },
                                 MatchArm {
-                                    pats: vec![placeholder_pat],
+                                    pat: placeholder_pat,
                                     expr: else_branch.unwrap_or_else(|| self.empty_block()),
                                     guard: None,
                                 },
@@ -203,8 +203,8 @@ where
                             let placeholder_pat = self.missing_pat();
                             let break_ = self.alloc_expr_desugared(Expr::Break { expr: None });
                             let arms = vec![
-                                MatchArm { pats: vec![pat], expr: body, guard: None },
-                                MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None },
+                                MatchArm { pat, expr: body, guard: None },
+                                MatchArm { pat: placeholder_pat, expr: break_, guard: None },
                             ];
                             let match_expr =
                                 self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
@@ -250,7 +250,7 @@ where
                     match_arm_list
                         .arms()
                         .map(|arm| MatchArm {
-                            pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
+                            pat: self.collect_pat_opt(arm.pat()),
                             expr: self.collect_expr_opt(arm.expr()),
                             guard: arm
                                 .guard()
@@ -587,6 +587,11 @@ where
                 let path = p.path().and_then(|path| self.expander.parse_path(path));
                 path.map(Pat::Path).unwrap_or(Pat::Missing)
             }
+            ast::Pat::OrPat(p) => {
+                let pats = p.pats().map(|p| self.collect_pat(p)).collect();
+                Pat::Or(pats)
+            }
+            ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()),
             ast::Pat::TuplePat(p) => {
                 let args = p.args().map(|p| self.collect_pat(p)).collect();
                 Pat::Tuple(args)
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
index 5d027994508..a58a7b21f92 100644
--- a/crates/ra_hir_def/src/body/scope.rs
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -158,9 +158,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
             compute_expr_scopes(*expr, body, scopes, scope);
             for arm in arms {
                 let scope = scopes.new_scope(scope);
-                for pat in &arm.pats {
-                    scopes.add_bindings(body, scope, *pat);
-                }
+                scopes.add_bindings(body, scope, arm.pat);
                 scopes.set_scope(arm.expr, scope);
                 compute_expr_scopes(arm.expr, body, scopes, scope);
             }
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs
index a75ef9970d8..5a84e08eded 100644
--- a/crates/ra_hir_def/src/expr.rs
+++ b/crates/ra_hir_def/src/expr.rs
@@ -202,7 +202,7 @@ pub enum Array {
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct MatchArm {
-    pub pats: Vec<PatId>,
+    pub pat: PatId,
     pub guard: Option<ExprId>,
     pub expr: ExprId,
 }
@@ -382,6 +382,7 @@ pub enum Pat {
     Missing,
     Wild,
     Tuple(Vec<PatId>),
+    Or(Vec<PatId>),
     Record {
         path: Option<Path>,
         args: Vec<RecordFieldPat>,
@@ -420,7 +421,7 @@ impl Pat {
             Pat::Bind { subpat, .. } => {
                 subpat.iter().copied().for_each(f);
             }
-            Pat::Tuple(args) | Pat::TupleStruct { args, .. } => {
+            Pat::Or(args) | Pat::Tuple(args) | Pat::TupleStruct { args, .. } => {
                 args.iter().copied().for_each(f);
             }
             Pat::Ref { pat, .. } => f(*pat),
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 3c9c02d03ed..186857b8b21 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -168,9 +168,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
                 let mut result_ty = self.table.new_maybe_never_type_var();
 
                 for arm in arms {
-                    for &pat in &arm.pats {
-                        let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::default());
-                    }
+                    let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
                     if let Some(guard_expr) = arm.guard {
                         self.infer_expr(
                             guard_expr,
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index e7283f24cd3..a5dfdf6c4be 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -82,6 +82,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
 
         let is_non_ref_pat = match &body[pat] {
             Pat::Tuple(..)
+            | Pat::Or(..)
             | Pat::TupleStruct { .. }
             | Pat::Record { .. }
             | Pat::Range { .. }
@@ -126,6 +127,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
 
                 Ty::apply(TypeCtor::Tuple { cardinality: args.len() as u16 }, Substs(inner_tys))
             }
+            Pat::Or(ref pats) => {
+                if let Some((first_pat, rest)) = pats.split_first() {
+                    let ty = self.infer_pat(*first_pat, expected, default_bm);
+                    for pat in rest {
+                        self.infer_pat(*pat, expected, default_bm);
+                    }
+                    ty
+                } else {
+                    Ty::Unknown
+                }
+            }
             Pat::Ref { pat, mutability } => {
                 let expectation = match expected.as_reference() {
                     Some((inner_ty, exp_mut)) => {
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 6b0d3d996fa..2ae97e65f50 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -80,8 +80,7 @@ fn get_inlay_hints(
             },
             ast::MatchArmList(it) => {
                 it.arms()
-                    .map(|match_arm| match_arm.pats())
-                    .flatten()
+                    .filter_map(|match_arm| match_arm.pat())
                     .for_each(|root_pat| get_pat_type_hints(acc, db, &analyzer, root_pat, true, max_inlay_hint_length));
             },
             ast::CallExpr(it) => {
@@ -202,6 +201,7 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
                 Some(pat) => pats_to_process.push_back(pat),
                 _ => leaf_pats.push(maybe_leaf_pat),
             },
+            ast::Pat::OrPat(ref_pat) => pats_to_process.extend(ref_pat.pats()),
             ast::Pat::TuplePat(tuple_pat) => pats_to_process.extend(tuple_pat.args()),
             ast::Pat::RecordPat(record_pat) => {
                 if let Some(pat_list) = record_pat.record_field_pat_list() {
@@ -222,6 +222,7 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
             ast::Pat::TupleStructPat(tuple_struct_pat) => {
                 pats_to_process.extend(tuple_struct_pat.args())
             }
+            ast::Pat::ParenPat(inner_pat) => pats_to_process.extend(inner_pat.pat()),
             ast::Pat::RefPat(ref_pat) => pats_to_process.extend(ref_pat.pat()),
             _ => (),
         }
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index f154077a86c..b72d2e9e648 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -336,7 +336,7 @@ fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
 fn cond(p: &mut Parser) {
     let m = p.start();
     if p.eat(T![let]) {
-        patterns::pattern_list(p);
+        patterns::pattern_top(p);
         p.expect(T![=]);
     }
     expr_no_struct(p);
@@ -430,7 +430,7 @@ fn match_arm(p: &mut Parser) -> BlockLike {
     // }
     attributes::outer_attributes(p);
 
-    patterns::pattern_list_r(p, TokenSet::EMPTY);
+    patterns::pattern_top_r(p, TokenSet::EMPTY);
     if p.at(T![if]) {
         match_guard(p);
     }
diff --git a/crates/ra_parser/src/grammar/params.rs b/crates/ra_parser/src/grammar/params.rs
index 94edc7f35da..ed4f93347a2 100644
--- a/crates/ra_parser/src/grammar/params.rs
+++ b/crates/ra_parser/src/grammar/params.rs
@@ -116,7 +116,7 @@ fn value_parameter(p: &mut Parser, flavor: Flavor) {
         // type Qux = fn(baz: Bar::Baz);
         Flavor::FnPointer => {
             if p.at(IDENT) && p.nth(1) == T![:] && !p.nth_at(1, T![::]) {
-                patterns::pattern(p);
+                patterns::pattern_single(p);
                 types::ascription(p);
             } else {
                 types::type_(p);
@@ -127,7 +127,7 @@ fn value_parameter(p: &mut Parser, flavor: Flavor) {
         //    let foo = |bar, baz: Baz, qux: Qux::Quux| ();
         // }
         Flavor::Closure => {
-            patterns::pattern(p);
+            patterns::pattern_single(p);
             if p.at(T![:]) && !p.at(T![::]) {
                 types::ascription(p);
             }
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs
index 422a4e3dc17..3afbaa82b84 100644
--- a/crates/ra_parser/src/grammar/patterns.rs
+++ b/crates/ra_parser/src/grammar/patterns.rs
@@ -11,22 +11,47 @@ pub(crate) fn pattern(p: &mut Parser) {
 }
 
 /// Parses a pattern list separated by pipes `|`
-pub(super) fn pattern_list(p: &mut Parser) {
-    pattern_list_r(p, PAT_RECOVERY_SET)
+pub(super) fn pattern_top(p: &mut Parser) {
+    pattern_top_r(p, PAT_RECOVERY_SET)
+}
+
+pub(crate) fn pattern_single(p: &mut Parser) {
+    pattern_single_r(p, PAT_RECOVERY_SET);
 }
 
 /// Parses a pattern list separated by pipes `|`
 /// using the given `recovery_set`
-pub(super) fn pattern_list_r(p: &mut Parser, recovery_set: TokenSet) {
+pub(super) fn pattern_top_r(p: &mut Parser, recovery_set: TokenSet) {
     p.eat(T![|]);
     pattern_r(p, recovery_set);
+}
 
+/// Parses a pattern list separated by pipes `|`, with no leading `|`,using the
+/// given `recovery_set`
+// test or_pattern
+// fn main() {
+//     match () {
+//         (_ | _) => (),
+//         &(_ | _) => (),
+//         (_ | _,) => (),
+//         [_ | _,] => (),
+//     }
+// }
+fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
+    let m = p.start();
+    pattern_single_r(p, recovery_set);
+
+    if !p.at(T![|]) {
+        m.abandon(p);
+        return;
+    }
     while p.eat(T![|]) {
-        pattern_r(p, recovery_set);
+        pattern_single_r(p, recovery_set);
     }
+    m.complete(p, OR_PAT);
 }
 
-pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
+fn pattern_single_r(p: &mut Parser, recovery_set: TokenSet) {
     if let Some(lhs) = atom_pat(p, recovery_set) {
         // test range_pat
         // fn main() {
@@ -258,19 +283,41 @@ fn ref_pat(p: &mut Parser) -> CompletedMarker {
     let m = p.start();
     p.bump(T![&]);
     p.eat(T![mut]);
-    pattern(p);
+    pattern_single(p);
     m.complete(p, REF_PAT)
 }
 
 // test tuple_pat
 // fn main() {
 //     let (a, b, ..) = ();
+//     let (a,) = ();
+//     let (..) = ();
+//     let () = ();
 // }
 fn tuple_pat(p: &mut Parser) -> CompletedMarker {
     assert!(p.at(T!['(']));
     let m = p.start();
-    tuple_pat_fields(p);
-    m.complete(p, TUPLE_PAT)
+    p.bump(T!['(']);
+    let mut has_comma = false;
+    let mut has_pat = false;
+    let mut has_rest = false;
+    while !p.at(EOF) && !p.at(T![')']) {
+        has_pat = true;
+        if !p.at_ts(PATTERN_FIRST) {
+            p.error("expected a pattern");
+            break;
+        }
+        has_rest |= p.at(T![..]);
+
+        pattern(p);
+        if !p.at(T![')']) {
+            has_comma = true;
+            p.expect(T![,]);
+        }
+    }
+    p.expect(T![')']);
+
+    m.complete(p, if !has_comma && !has_rest && has_pat { PAREN_PAT } else { TUPLE_PAT })
 }
 
 // test slice_pat
@@ -315,7 +362,7 @@ fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
     p.eat(T![mut]);
     name(p);
     if with_at && p.eat(T![@]) {
-        pattern(p);
+        pattern_single(p);
     }
     m.complete(p, BIND_PAT)
 }
@@ -330,6 +377,6 @@ fn box_pat(p: &mut Parser) -> CompletedMarker {
     assert!(p.at(T![box]));
     let m = p.start();
     p.bump(T![box]);
-    pattern(p);
+    pattern_single(p);
     m.complete(p, BOX_PAT)
 }
diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs
index e27b27ffabc..1068da0a063 100644
--- a/crates/ra_parser/src/syntax_kind/generated.rs
+++ b/crates/ra_parser/src/syntax_kind/generated.rs
@@ -151,6 +151,8 @@ pub enum SyntaxKind {
     FOR_TYPE,
     IMPL_TRAIT_TYPE,
     DYN_TRAIT_TYPE,
+    OR_PAT,
+    PAREN_PAT,
     REF_PAT,
     BOX_PAT,
     BIND_PAT,
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 435135f92d5..8d640642d27 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -1759,8 +1759,8 @@ impl AstNode for MatchArm {
 }
 impl ast::AttrsOwner for MatchArm {}
 impl MatchArm {
-    pub fn pats(&self) -> AstChildren<Pat> {
-        AstChildren::new(&self.syntax)
+    pub fn pat(&self) -> Option<Pat> {
+        AstChildren::new(&self.syntax).next()
     }
     pub fn guard(&self) -> Option<MatchGuard> {
         AstChildren::new(&self.syntax).next()
@@ -1887,6 +1887,60 @@ impl RecordField {
     }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct OrPat {
+    pub(crate) syntax: SyntaxNode,
+}
+impl AstNode for OrPat {
+    fn can_cast(kind: SyntaxKind) -> bool {
+        match kind {
+            OR_PAT => true,
+            _ => false,
+        }
+    }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode {
+        &self.syntax
+    }
+}
+impl OrPat {
+    pub fn pats(&self) -> AstChildren<Pat> {
+        AstChildren::new(&self.syntax)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ParenPat {
+    pub(crate) syntax: SyntaxNode,
+}
+impl AstNode for ParenPat {
+    fn can_cast(kind: SyntaxKind) -> bool {
+        match kind {
+            PAREN_PAT => true,
+            _ => false,
+        }
+    }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode {
+        &self.syntax
+    }
+}
+impl ParenPat {
+    pub fn pat(&self) -> Option<Pat> {
+        AstChildren::new(&self.syntax).next()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct RefPat {
     pub(crate) syntax: SyntaxNode,
 }
@@ -3900,6 +3954,8 @@ impl AstNode for Expr {
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Pat {
+    OrPat(OrPat),
+    ParenPat(ParenPat),
     RefPat(RefPat),
     BoxPat(BoxPat),
     BindPat(BindPat),
@@ -3913,6 +3969,16 @@ pub enum Pat {
     RangePat(RangePat),
     LiteralPat(LiteralPat),
 }
+impl From<OrPat> for Pat {
+    fn from(node: OrPat) -> Pat {
+        Pat::OrPat(node)
+    }
+}
+impl From<ParenPat> for Pat {
+    fn from(node: ParenPat) -> Pat {
+        Pat::ParenPat(node)
+    }
+}
 impl From<RefPat> for Pat {
     fn from(node: RefPat) -> Pat {
         Pat::RefPat(node)
@@ -3976,15 +4042,16 @@ impl From<LiteralPat> for Pat {
 impl AstNode for Pat {
     fn can_cast(kind: SyntaxKind) -> bool {
         match kind {
-            REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | DOT_DOT_PAT | PATH_PAT
-            | RECORD_PAT | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT | LITERAL_PAT => {
-                true
-            }
+            OR_PAT | PAREN_PAT | REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | DOT_DOT_PAT
+            | PATH_PAT | RECORD_PAT | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT
+            | LITERAL_PAT => true,
             _ => false,
         }
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
+            OR_PAT => Pat::OrPat(OrPat { syntax }),
+            PAREN_PAT => Pat::ParenPat(ParenPat { syntax }),
             REF_PAT => Pat::RefPat(RefPat { syntax }),
             BOX_PAT => Pat::BoxPat(BoxPat { syntax }),
             BIND_PAT => Pat::BindPat(BindPat { syntax }),
@@ -4003,6 +4070,8 @@ impl AstNode for Pat {
     }
     fn syntax(&self) -> &SyntaxNode {
         match self {
+            Pat::OrPat(it) => &it.syntax,
+            Pat::ParenPat(it) => &it.syntax,
             Pat::RefPat(it) => &it.syntax,
             Pat::BoxPat(it) => &it.syntax,
             Pat::BindPat(it) => &it.syntax,
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0030_cond.txt b/crates/ra_syntax/test_data/parser/inline/ok/0030_cond.txt
index 4028ca24377..6fd49c7bc62 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0030_cond.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0030_cond.txt
@@ -63,27 +63,28 @@ SOURCE_FILE@[0; 197)
             CONDITION@[56; 84)
               LET_KW@[56; 59) "let"
               WHITESPACE@[59; 60) " "
-              TUPLE_STRUCT_PAT@[60; 67)
-                PATH@[60; 64)
-                  PATH_SEGMENT@[60; 64)
-                    NAME_REF@[60; 64)
-                      IDENT@[60; 64) "Some"
-                L_PAREN@[64; 65) "("
-                PLACEHOLDER_PAT@[65; 66)
-                  UNDERSCORE@[65; 66) "_"
-                R_PAREN@[66; 67) ")"
-              WHITESPACE@[67; 68) " "
-              PIPE@[68; 69) "|"
-              WHITESPACE@[69; 70) " "
-              TUPLE_STRUCT_PAT@[70; 77)
-                PATH@[70; 74)
-                  PATH_SEGMENT@[70; 74)
-                    NAME_REF@[70; 74)
-                      IDENT@[70; 74) "Some"
-                L_PAREN@[74; 75) "("
-                PLACEHOLDER_PAT@[75; 76)
-                  UNDERSCORE@[75; 76) "_"
-                R_PAREN@[76; 77) ")"
+              OR_PAT@[60; 77)
+                TUPLE_STRUCT_PAT@[60; 67)
+                  PATH@[60; 64)
+                    PATH_SEGMENT@[60; 64)
+                      NAME_REF@[60; 64)
+                        IDENT@[60; 64) "Some"
+                  L_PAREN@[64; 65) "("
+                  PLACEHOLDER_PAT@[65; 66)
+                    UNDERSCORE@[65; 66) "_"
+                  R_PAREN@[66; 67) ")"
+                WHITESPACE@[67; 68) " "
+                PIPE@[68; 69) "|"
+                WHITESPACE@[69; 70) " "
+                TUPLE_STRUCT_PAT@[70; 77)
+                  PATH@[70; 74)
+                    PATH_SEGMENT@[70; 74)
+                      NAME_REF@[70; 74)
+                        IDENT@[70; 74) "Some"
+                  L_PAREN@[74; 75) "("
+                  PLACEHOLDER_PAT@[75; 76)
+                    UNDERSCORE@[75; 76) "_"
+                  R_PAREN@[76; 77) ")"
               WHITESPACE@[77; 78) " "
               EQ@[78; 79) "="
               WHITESPACE@[79; 80) " "
@@ -137,27 +138,28 @@ SOURCE_FILE@[0; 197)
             CONDITION@[129; 157)
               LET_KW@[129; 132) "let"
               WHITESPACE@[132; 133) " "
-              TUPLE_STRUCT_PAT@[133; 140)
-                PATH@[133; 137)
-                  PATH_SEGMENT@[133; 137)
-                    NAME_REF@[133; 137)
-                      IDENT@[133; 137) "Some"
-                L_PAREN@[137; 138) "("
-                PLACEHOLDER_PAT@[138; 139)
-                  UNDERSCORE@[138; 139) "_"
-                R_PAREN@[139; 140) ")"
-              WHITESPACE@[140; 141) " "
-              PIPE@[141; 142) "|"
-              WHITESPACE@[142; 143) " "
-              TUPLE_STRUCT_PAT@[143; 150)
-                PATH@[143; 147)
-                  PATH_SEGMENT@[143; 147)
-                    NAME_REF@[143; 147)
-                      IDENT@[143; 147) "Some"
-                L_PAREN@[147; 148) "("
-                PLACEHOLDER_PAT@[148; 149)
-                  UNDERSCORE@[148; 149) "_"
-                R_PAREN@[149; 150) ")"
+              OR_PAT@[133; 150)
+                TUPLE_STRUCT_PAT@[133; 140)
+                  PATH@[133; 137)
+                    PATH_SEGMENT@[133; 137)
+                      NAME_REF@[133; 137)
+                        IDENT@[133; 137) "Some"
+                  L_PAREN@[137; 138) "("
+                  PLACEHOLDER_PAT@[138; 139)
+                    UNDERSCORE@[138; 139) "_"
+                  R_PAREN@[139; 140) ")"
+                WHITESPACE@[140; 141) " "
+                PIPE@[141; 142) "|"
+                WHITESPACE@[142; 143) " "
+                TUPLE_STRUCT_PAT@[143; 150)
+                  PATH@[143; 147)
+                    PATH_SEGMENT@[143; 147)
+                      NAME_REF@[143; 147)
+                        IDENT@[143; 147) "Some"
+                  L_PAREN@[147; 148) "("
+                  PLACEHOLDER_PAT@[148; 149)
+                    UNDERSCORE@[148; 149) "_"
+                  R_PAREN@[149; 150) ")"
               WHITESPACE@[150; 151) " "
               EQ@[151; 152) "="
               WHITESPACE@[152; 153) " "
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt b/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt
index 87272917b19..2f07af4e197 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt
@@ -74,15 +74,16 @@ SOURCE_FILE@[0; 167)
               COMMA@[83; 84) ","
               WHITESPACE@[84; 93) "\n        "
               MATCH_ARM@[93; 109)
-                BIND_PAT@[93; 94)
-                  NAME@[93; 94)
-                    IDENT@[93; 94) "X"
-                WHITESPACE@[94; 95) " "
-                PIPE@[95; 96) "|"
-                WHITESPACE@[96; 97) " "
-                BIND_PAT@[97; 98)
-                  NAME@[97; 98)
-                    IDENT@[97; 98) "Y"
+                OR_PAT@[93; 98)
+                  BIND_PAT@[93; 94)
+                    NAME@[93; 94)
+                      IDENT@[93; 94) "X"
+                  WHITESPACE@[94; 95) " "
+                  PIPE@[95; 96) "|"
+                  WHITESPACE@[96; 97) " "
+                  BIND_PAT@[97; 98)
+                    NAME@[97; 98)
+                      IDENT@[97; 98) "Y"
                 WHITESPACE@[98; 99) " "
                 MATCH_GUARD@[99; 103)
                   IF_KW@[99; 101) "if"
@@ -103,15 +104,16 @@ SOURCE_FILE@[0; 167)
               MATCH_ARM@[119; 137)
                 PIPE@[119; 120) "|"
                 WHITESPACE@[120; 121) " "
-                BIND_PAT@[121; 122)
-                  NAME@[121; 122)
-                    IDENT@[121; 122) "X"
-                WHITESPACE@[122; 123) " "
-                PIPE@[123; 124) "|"
-                WHITESPACE@[124; 125) " "
-                BIND_PAT@[125; 126)
-                  NAME@[125; 126)
-                    IDENT@[125; 126) "Y"
+                OR_PAT@[121; 126)
+                  BIND_PAT@[121; 122)
+                    NAME@[121; 122)
+                      IDENT@[121; 122) "X"
+                  WHITESPACE@[122; 123) " "
+                  PIPE@[123; 124) "|"
+                  WHITESPACE@[124; 125) " "
+                  BIND_PAT@[125; 126)
+                    NAME@[125; 126)
+                      IDENT@[125; 126) "Y"
                 WHITESPACE@[126; 127) " "
                 MATCH_GUARD@[127; 131)
                   IF_KW@[127; 129) "if"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.rs b/crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.rs
index f785acd36d9..ba719879d4c 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.rs
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.rs
@@ -1,3 +1,6 @@
 fn main() {
     let (a, b, ..) = ();
+    let (a,) = ();
+    let (..) = ();
+    let () = ();
 }
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.txt b/crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.txt
index 674dec4937e..4680c267e7e 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.txt
@@ -1,5 +1,5 @@
-SOURCE_FILE@[0; 39)
-  FN_DEF@[0; 38)
+SOURCE_FILE@[0; 94)
+  FN_DEF@[0; 93)
     FN_KW@[0; 2) "fn"
     WHITESPACE@[2; 3) " "
     NAME@[3; 7)
@@ -8,8 +8,8 @@ SOURCE_FILE@[0; 39)
       L_PAREN@[7; 8) "("
       R_PAREN@[8; 9) ")"
     WHITESPACE@[9; 10) " "
-    BLOCK_EXPR@[10; 38)
-      BLOCK@[10; 38)
+    BLOCK_EXPR@[10; 93)
+      BLOCK@[10; 93)
         L_CURLY@[10; 11) "{"
         WHITESPACE@[11; 16) "\n    "
         LET_STMT@[16; 36)
@@ -37,6 +37,54 @@ SOURCE_FILE@[0; 39)
             L_PAREN@[33; 34) "("
             R_PAREN@[34; 35) ")"
           SEMI@[35; 36) ";"
-        WHITESPACE@[36; 37) "\n"
-        R_CURLY@[37; 38) "}"
-  WHITESPACE@[38; 39) "\n"
+        WHITESPACE@[36; 41) "\n    "
+        LET_STMT@[41; 55)
+          LET_KW@[41; 44) "let"
+          WHITESPACE@[44; 45) " "
+          TUPLE_PAT@[45; 49)
+            L_PAREN@[45; 46) "("
+            BIND_PAT@[46; 47)
+              NAME@[46; 47)
+                IDENT@[46; 47) "a"
+            COMMA@[47; 48) ","
+            R_PAREN@[48; 49) ")"
+          WHITESPACE@[49; 50) " "
+          EQ@[50; 51) "="
+          WHITESPACE@[51; 52) " "
+          TUPLE_EXPR@[52; 54)
+            L_PAREN@[52; 53) "("
+            R_PAREN@[53; 54) ")"
+          SEMI@[54; 55) ";"
+        WHITESPACE@[55; 60) "\n    "
+        LET_STMT@[60; 74)
+          LET_KW@[60; 63) "let"
+          WHITESPACE@[63; 64) " "
+          TUPLE_PAT@[64; 68)
+            L_PAREN@[64; 65) "("
+            DOT_DOT_PAT@[65; 67)
+              DOTDOT@[65; 67) ".."
+            R_PAREN@[67; 68) ")"
+          WHITESPACE@[68; 69) " "
+          EQ@[69; 70) "="
+          WHITESPACE@[70; 71) " "
+          TUPLE_EXPR@[71; 73)
+            L_PAREN@[71; 72) "("
+            R_PAREN@[72; 73) ")"
+          SEMI@[73; 74) ";"
+        WHITESPACE@[74; 79) "\n    "
+        LET_STMT@[79; 91)
+          LET_KW@[79; 82) "let"
+          WHITESPACE@[82; 83) " "
+          TUPLE_PAT@[83; 85)
+            L_PAREN@[83; 84) "("
+            R_PAREN@[84; 85) ")"
+          WHITESPACE@[85; 86) " "
+          EQ@[86; 87) "="
+          WHITESPACE@[87; 88) " "
+          TUPLE_EXPR@[88; 90)
+            L_PAREN@[88; 89) "("
+            R_PAREN@[89; 90) ")"
+          SEMI@[90; 91) ";"
+        WHITESPACE@[91; 92) "\n"
+        R_CURLY@[92; 93) "}"
+  WHITESPACE@[93; 94) "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.rs b/crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.rs
new file mode 100644
index 00000000000..a2631660550
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.rs
@@ -0,0 +1,8 @@
+fn main() {
+    match () {
+        (_ | _) => (),
+        &(_ | _) => (),
+        (_ | _,) => (),
+        [_ | _,] => (),
+    }
+}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.txt b/crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.txt
new file mode 100644
index 00000000000..3a196d3c030
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.txt
@@ -0,0 +1,112 @@
+SOURCE_FILE@[0; 130)
+  FN_DEF@[0; 129)
+    FN_KW@[0; 2) "fn"
+    WHITESPACE@[2; 3) " "
+    NAME@[3; 7)
+      IDENT@[3; 7) "main"
+    PARAM_LIST@[7; 9)
+      L_PAREN@[7; 8) "("
+      R_PAREN@[8; 9) ")"
+    WHITESPACE@[9; 10) " "
+    BLOCK_EXPR@[10; 129)
+      BLOCK@[10; 129)
+        L_CURLY@[10; 11) "{"
+        WHITESPACE@[11; 16) "\n    "
+        MATCH_EXPR@[16; 127)
+          MATCH_KW@[16; 21) "match"
+          WHITESPACE@[21; 22) " "
+          TUPLE_EXPR@[22; 24)
+            L_PAREN@[22; 23) "("
+            R_PAREN@[23; 24) ")"
+          WHITESPACE@[24; 25) " "
+          MATCH_ARM_LIST@[25; 127)
+            L_CURLY@[25; 26) "{"
+            WHITESPACE@[26; 35) "\n        "
+            MATCH_ARM@[35; 48)
+              PAREN_PAT@[35; 42)
+                L_PAREN@[35; 36) "("
+                OR_PAT@[36; 41)
+                  PLACEHOLDER_PAT@[36; 37)
+                    UNDERSCORE@[36; 37) "_"
+                  WHITESPACE@[37; 38) " "
+                  PIPE@[38; 39) "|"
+                  WHITESPACE@[39; 40) " "
+                  PLACEHOLDER_PAT@[40; 41)
+                    UNDERSCORE@[40; 41) "_"
+                R_PAREN@[41; 42) ")"
+              WHITESPACE@[42; 43) " "
+              FAT_ARROW@[43; 45) "=>"
+              WHITESPACE@[45; 46) " "
+              TUPLE_EXPR@[46; 48)
+                L_PAREN@[46; 47) "("
+                R_PAREN@[47; 48) ")"
+            COMMA@[48; 49) ","
+            WHITESPACE@[49; 58) "\n        "
+            MATCH_ARM@[58; 72)
+              REF_PAT@[58; 66)
+                AMP@[58; 59) "&"
+                PAREN_PAT@[59; 66)
+                  L_PAREN@[59; 60) "("
+                  OR_PAT@[60; 65)
+                    PLACEHOLDER_PAT@[60; 61)
+                      UNDERSCORE@[60; 61) "_"
+                    WHITESPACE@[61; 62) " "
+                    PIPE@[62; 63) "|"
+                    WHITESPACE@[63; 64) " "
+                    PLACEHOLDER_PAT@[64; 65)
+                      UNDERSCORE@[64; 65) "_"
+                  R_PAREN@[65; 66) ")"
+              WHITESPACE@[66; 67) " "
+              FAT_ARROW@[67; 69) "=>"
+              WHITESPACE@[69; 70) " "
+              TUPLE_EXPR@[70; 72)
+                L_PAREN@[70; 71) "("
+                R_PAREN@[71; 72) ")"
+            COMMA@[72; 73) ","
+            WHITESPACE@[73; 82) "\n        "
+            MATCH_ARM@[82; 96)
+              TUPLE_PAT@[82; 90)
+                L_PAREN@[82; 83) "("
+                OR_PAT@[83; 88)
+                  PLACEHOLDER_PAT@[83; 84)
+                    UNDERSCORE@[83; 84) "_"
+                  WHITESPACE@[84; 85) " "
+                  PIPE@[85; 86) "|"
+                  WHITESPACE@[86; 87) " "
+                  PLACEHOLDER_PAT@[87; 88)
+                    UNDERSCORE@[87; 88) "_"
+                COMMA@[88; 89) ","
+                R_PAREN@[89; 90) ")"
+              WHITESPACE@[90; 91) " "
+              FAT_ARROW@[91; 93) "=>"
+              WHITESPACE@[93; 94) " "
+              TUPLE_EXPR@[94; 96)
+                L_PAREN@[94; 95) "("
+                R_PAREN@[95; 96) ")"
+            COMMA@[96; 97) ","
+            WHITESPACE@[97; 106) "\n        "
+            MATCH_ARM@[106; 120)
+              SLICE_PAT@[106; 114)
+                L_BRACK@[106; 107) "["
+                OR_PAT@[107; 112)
+                  PLACEHOLDER_PAT@[107; 108)
+                    UNDERSCORE@[107; 108) "_"
+                  WHITESPACE@[108; 109) " "
+                  PIPE@[109; 110) "|"
+                  WHITESPACE@[110; 111) " "
+                  PLACEHOLDER_PAT@[111; 112)
+                    UNDERSCORE@[111; 112) "_"
+                COMMA@[112; 113) ","
+                R_BRACK@[113; 114) "]"
+              WHITESPACE@[114; 115) " "
+              FAT_ARROW@[115; 117) "=>"
+              WHITESPACE@[117; 118) " "
+              TUPLE_EXPR@[118; 120)
+                L_PAREN@[118; 119) "("
+                R_PAREN@[119; 120) ")"
+            COMMA@[120; 121) ","
+            WHITESPACE@[121; 126) "\n    "
+            R_CURLY@[126; 127) "}"
+        WHITESPACE@[127; 128) "\n"
+        R_CURLY@[128; 129) "}"
+  WHITESPACE@[129; 130) "\n"
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index 67d1f41bca2..3f530e4899c 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -120,6 +120,8 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
         "FOR_TYPE",
         "IMPL_TRAIT_TYPE",
         "DYN_TRAIT_TYPE",
+        "OR_PAT",
+        "PAREN_PAT",
         "REF_PAT",
         "BOX_PAT",
         "BIND_PAT",
@@ -412,7 +414,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
         struct MatchExpr { Expr, MatchArmList }
         struct MatchArmList: AttrsOwner { arms: [MatchArm] }
         struct MatchArm: AttrsOwner {
-            pats: [Pat],
+            pat: Pat,
             guard: MatchGuard,
             Expr,
          }
@@ -425,6 +427,8 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
          }
         struct RecordField { NameRef, Expr }
 
+        struct OrPat { pats: [Pat] }
+        struct ParenPat { Pat }
         struct RefPat { Pat }
         struct BoxPat { Pat }
         struct BindPat: NameOwner { Pat }
@@ -601,6 +605,8 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
         }
 
         enum Pat {
+            OrPat,
+            ParenPat,
             RefPat,
             BoxPat,
             BindPat,