Skip to content

Commit f8d6d6f

Browse files
Merge #3074
3074: Or patterns r=matthewjasper a=matthewjasper Works towards #2458 Co-authored-by: Matthew Jasper <[email protected]>
2 parents 29f5e7e + 49b53cd commit f8d6d6f

File tree

21 files changed

+427
-113
lines changed

21 files changed

+427
-113
lines changed

crates/ra_assists/src/handlers/fill_match_arms.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,10 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> {
7575
}
7676

7777
fn is_trivial(arm: &ast::MatchArm) -> bool {
78-
arm.pats().any(|pat| match pat {
79-
ast::Pat::PlaceholderPat(..) => true,
78+
match arm.pat() {
79+
Some(ast::Pat::PlaceholderPat(..)) => true,
8080
_ => false,
81-
})
81+
}
8282
}
8383

8484
fn resolve_enum_def(

crates/ra_assists/src/handlers/merge_match_arms.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> {
7575
} else {
7676
arms_to_merge
7777
.iter()
78-
.flat_map(ast::MatchArm::pats)
78+
.filter_map(ast::MatchArm::pat)
7979
.map(|x| x.syntax().to_string())
8080
.collect::<Vec<String>>()
8181
.join(" | ")
@@ -96,10 +96,10 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> {
9696
}
9797

9898
fn contains_placeholder(a: &ast::MatchArm) -> bool {
99-
a.pats().any(|x| match x {
100-
ra_syntax::ast::Pat::PlaceholderPat(..) => true,
99+
match a.pat() {
100+
Some(ra_syntax::ast::Pat::PlaceholderPat(..)) => true,
101101
_ => false,
102-
})
102+
}
103103
}
104104

105105
fn next_arm(arm: &ast::MatchArm) -> Option<ast::MatchArm> {

crates/ra_assists/src/handlers/move_guard.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option<Assist> {
9090
// ```
9191
pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> {
9292
let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?;
93-
let last_match_pat = match_arm.pats().last()?;
93+
let match_pat = match_arm.pat()?;
9494

9595
let arm_body = match_arm.expr()?;
9696
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> {
122122
_ => edit.replace(if_expr.syntax().text_range(), then_block.syntax().text()),
123123
}
124124

125-
edit.insert(last_match_pat.syntax().text_range().end(), buf);
126-
edit.set_cursor(last_match_pat.syntax().text_range().end() + TextUnit::from(1));
125+
edit.insert(match_pat.syntax().text_range().end(), buf);
126+
edit.set_cursor(match_pat.syntax().text_range().end() + TextUnit::from(1));
127127
},
128128
)
129129
}

crates/ra_hir_def/src/body/lower.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,9 @@ where
164164
let match_expr = self.collect_expr_opt(condition.expr());
165165
let placeholder_pat = self.missing_pat();
166166
let arms = vec![
167-
MatchArm { pats: vec![pat], expr: then_branch, guard: None },
167+
MatchArm { pat, expr: then_branch, guard: None },
168168
MatchArm {
169-
pats: vec![placeholder_pat],
169+
pat: placeholder_pat,
170170
expr: else_branch.unwrap_or_else(|| self.empty_block()),
171171
guard: None,
172172
},
@@ -203,8 +203,8 @@ where
203203
let placeholder_pat = self.missing_pat();
204204
let break_ = self.alloc_expr_desugared(Expr::Break { expr: None });
205205
let arms = vec![
206-
MatchArm { pats: vec![pat], expr: body, guard: None },
207-
MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None },
206+
MatchArm { pat, expr: body, guard: None },
207+
MatchArm { pat: placeholder_pat, expr: break_, guard: None },
208208
];
209209
let match_expr =
210210
self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
@@ -250,7 +250,7 @@ where
250250
match_arm_list
251251
.arms()
252252
.map(|arm| MatchArm {
253-
pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
253+
pat: self.collect_pat_opt(arm.pat()),
254254
expr: self.collect_expr_opt(arm.expr()),
255255
guard: arm
256256
.guard()
@@ -587,6 +587,11 @@ where
587587
let path = p.path().and_then(|path| self.expander.parse_path(path));
588588
path.map(Pat::Path).unwrap_or(Pat::Missing)
589589
}
590+
ast::Pat::OrPat(p) => {
591+
let pats = p.pats().map(|p| self.collect_pat(p)).collect();
592+
Pat::Or(pats)
593+
}
594+
ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()),
590595
ast::Pat::TuplePat(p) => {
591596
let args = p.args().map(|p| self.collect_pat(p)).collect();
592597
Pat::Tuple(args)

crates/ra_hir_def/src/body/scope.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
158158
compute_expr_scopes(*expr, body, scopes, scope);
159159
for arm in arms {
160160
let scope = scopes.new_scope(scope);
161-
for pat in &arm.pats {
162-
scopes.add_bindings(body, scope, *pat);
163-
}
161+
scopes.add_bindings(body, scope, arm.pat);
164162
scopes.set_scope(arm.expr, scope);
165163
compute_expr_scopes(arm.expr, body, scopes, scope);
166164
}

crates/ra_hir_def/src/expr.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ pub enum Array {
202202

203203
#[derive(Debug, Clone, Eq, PartialEq)]
204204
pub struct MatchArm {
205-
pub pats: Vec<PatId>,
205+
pub pat: PatId,
206206
pub guard: Option<ExprId>,
207207
pub expr: ExprId,
208208
}
@@ -382,6 +382,7 @@ pub enum Pat {
382382
Missing,
383383
Wild,
384384
Tuple(Vec<PatId>),
385+
Or(Vec<PatId>),
385386
Record {
386387
path: Option<Path>,
387388
args: Vec<RecordFieldPat>,
@@ -420,7 +421,7 @@ impl Pat {
420421
Pat::Bind { subpat, .. } => {
421422
subpat.iter().copied().for_each(f);
422423
}
423-
Pat::Tuple(args) | Pat::TupleStruct { args, .. } => {
424+
Pat::Or(args) | Pat::Tuple(args) | Pat::TupleStruct { args, .. } => {
424425
args.iter().copied().for_each(f);
425426
}
426427
Pat::Ref { pat, .. } => f(*pat),

crates/ra_hir_ty/src/infer/expr.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
168168
let mut result_ty = self.table.new_maybe_never_type_var();
169169

170170
for arm in arms {
171-
for &pat in &arm.pats {
172-
let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::default());
173-
}
171+
let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
174172
if let Some(guard_expr) = arm.guard {
175173
self.infer_expr(
176174
guard_expr,

crates/ra_hir_ty/src/infer/pat.rs

+12
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
8282

8383
let is_non_ref_pat = match &body[pat] {
8484
Pat::Tuple(..)
85+
| Pat::Or(..)
8586
| Pat::TupleStruct { .. }
8687
| Pat::Record { .. }
8788
| Pat::Range { .. }
@@ -126,6 +127,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
126127

127128
Ty::apply(TypeCtor::Tuple { cardinality: args.len() as u16 }, Substs(inner_tys))
128129
}
130+
Pat::Or(ref pats) => {
131+
if let Some((first_pat, rest)) = pats.split_first() {
132+
let ty = self.infer_pat(*first_pat, expected, default_bm);
133+
for pat in rest {
134+
self.infer_pat(*pat, expected, default_bm);
135+
}
136+
ty
137+
} else {
138+
Ty::Unknown
139+
}
140+
}
129141
Pat::Ref { pat, mutability } => {
130142
let expectation = match expected.as_reference() {
131143
Some((inner_ty, exp_mut)) => {

crates/ra_ide/src/inlay_hints.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ fn get_inlay_hints(
8080
},
8181
ast::MatchArmList(it) => {
8282
it.arms()
83-
.map(|match_arm| match_arm.pats())
84-
.flatten()
83+
.filter_map(|match_arm| match_arm.pat())
8584
.for_each(|root_pat| get_pat_type_hints(acc, db, &analyzer, root_pat, true, max_inlay_hint_length));
8685
},
8786
ast::CallExpr(it) => {
@@ -202,6 +201,7 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
202201
Some(pat) => pats_to_process.push_back(pat),
203202
_ => leaf_pats.push(maybe_leaf_pat),
204203
},
204+
ast::Pat::OrPat(ref_pat) => pats_to_process.extend(ref_pat.pats()),
205205
ast::Pat::TuplePat(tuple_pat) => pats_to_process.extend(tuple_pat.args()),
206206
ast::Pat::RecordPat(record_pat) => {
207207
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> {
222222
ast::Pat::TupleStructPat(tuple_struct_pat) => {
223223
pats_to_process.extend(tuple_struct_pat.args())
224224
}
225+
ast::Pat::ParenPat(inner_pat) => pats_to_process.extend(inner_pat.pat()),
225226
ast::Pat::RefPat(ref_pat) => pats_to_process.extend(ref_pat.pat()),
226227
_ => (),
227228
}

crates/ra_parser/src/grammar/expressions/atom.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
336336
fn cond(p: &mut Parser) {
337337
let m = p.start();
338338
if p.eat(T![let]) {
339-
patterns::pattern_list(p);
339+
patterns::pattern_top(p);
340340
p.expect(T![=]);
341341
}
342342
expr_no_struct(p);
@@ -430,7 +430,7 @@ fn match_arm(p: &mut Parser) -> BlockLike {
430430
// }
431431
attributes::outer_attributes(p);
432432

433-
patterns::pattern_list_r(p, TokenSet::EMPTY);
433+
patterns::pattern_top_r(p, TokenSet::EMPTY);
434434
if p.at(T![if]) {
435435
match_guard(p);
436436
}

crates/ra_parser/src/grammar/params.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ fn value_parameter(p: &mut Parser, flavor: Flavor) {
116116
// type Qux = fn(baz: Bar::Baz);
117117
Flavor::FnPointer => {
118118
if p.at(IDENT) && p.nth(1) == T![:] && !p.nth_at(1, T![::]) {
119-
patterns::pattern(p);
119+
patterns::pattern_single(p);
120120
types::ascription(p);
121121
} else {
122122
types::type_(p);
@@ -127,7 +127,7 @@ fn value_parameter(p: &mut Parser, flavor: Flavor) {
127127
// let foo = |bar, baz: Baz, qux: Qux::Quux| ();
128128
// }
129129
Flavor::Closure => {
130-
patterns::pattern(p);
130+
patterns::pattern_single(p);
131131
if p.at(T![:]) && !p.at(T![::]) {
132132
types::ascription(p);
133133
}

crates/ra_parser/src/grammar/patterns.rs

+57-10
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,47 @@ pub(crate) fn pattern(p: &mut Parser) {
1111
}
1212

1313
/// Parses a pattern list separated by pipes `|`
14-
pub(super) fn pattern_list(p: &mut Parser) {
15-
pattern_list_r(p, PAT_RECOVERY_SET)
14+
pub(super) fn pattern_top(p: &mut Parser) {
15+
pattern_top_r(p, PAT_RECOVERY_SET)
16+
}
17+
18+
pub(crate) fn pattern_single(p: &mut Parser) {
19+
pattern_single_r(p, PAT_RECOVERY_SET);
1620
}
1721

1822
/// Parses a pattern list separated by pipes `|`
1923
/// using the given `recovery_set`
20-
pub(super) fn pattern_list_r(p: &mut Parser, recovery_set: TokenSet) {
24+
pub(super) fn pattern_top_r(p: &mut Parser, recovery_set: TokenSet) {
2125
p.eat(T![|]);
2226
pattern_r(p, recovery_set);
27+
}
2328

29+
/// Parses a pattern list separated by pipes `|`, with no leading `|`,using the
30+
/// given `recovery_set`
31+
// test or_pattern
32+
// fn main() {
33+
// match () {
34+
// (_ | _) => (),
35+
// &(_ | _) => (),
36+
// (_ | _,) => (),
37+
// [_ | _,] => (),
38+
// }
39+
// }
40+
fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
41+
let m = p.start();
42+
pattern_single_r(p, recovery_set);
43+
44+
if !p.at(T![|]) {
45+
m.abandon(p);
46+
return;
47+
}
2448
while p.eat(T![|]) {
25-
pattern_r(p, recovery_set);
49+
pattern_single_r(p, recovery_set);
2650
}
51+
m.complete(p, OR_PAT);
2752
}
2853

29-
pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
54+
fn pattern_single_r(p: &mut Parser, recovery_set: TokenSet) {
3055
if let Some(lhs) = atom_pat(p, recovery_set) {
3156
// test range_pat
3257
// fn main() {
@@ -258,19 +283,41 @@ fn ref_pat(p: &mut Parser) -> CompletedMarker {
258283
let m = p.start();
259284
p.bump(T![&]);
260285
p.eat(T![mut]);
261-
pattern(p);
286+
pattern_single(p);
262287
m.complete(p, REF_PAT)
263288
}
264289

265290
// test tuple_pat
266291
// fn main() {
267292
// let (a, b, ..) = ();
293+
// let (a,) = ();
294+
// let (..) = ();
295+
// let () = ();
268296
// }
269297
fn tuple_pat(p: &mut Parser) -> CompletedMarker {
270298
assert!(p.at(T!['(']));
271299
let m = p.start();
272-
tuple_pat_fields(p);
273-
m.complete(p, TUPLE_PAT)
300+
p.bump(T!['(']);
301+
let mut has_comma = false;
302+
let mut has_pat = false;
303+
let mut has_rest = false;
304+
while !p.at(EOF) && !p.at(T![')']) {
305+
has_pat = true;
306+
if !p.at_ts(PATTERN_FIRST) {
307+
p.error("expected a pattern");
308+
break;
309+
}
310+
has_rest |= p.at(T![..]);
311+
312+
pattern(p);
313+
if !p.at(T![')']) {
314+
has_comma = true;
315+
p.expect(T![,]);
316+
}
317+
}
318+
p.expect(T![')']);
319+
320+
m.complete(p, if !has_comma && !has_rest && has_pat { PAREN_PAT } else { TUPLE_PAT })
274321
}
275322

276323
// test slice_pat
@@ -315,7 +362,7 @@ fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
315362
p.eat(T![mut]);
316363
name(p);
317364
if with_at && p.eat(T![@]) {
318-
pattern(p);
365+
pattern_single(p);
319366
}
320367
m.complete(p, BIND_PAT)
321368
}
@@ -330,6 +377,6 @@ fn box_pat(p: &mut Parser) -> CompletedMarker {
330377
assert!(p.at(T![box]));
331378
let m = p.start();
332379
p.bump(T![box]);
333-
pattern(p);
380+
pattern_single(p);
334381
m.complete(p, BOX_PAT)
335382
}

crates/ra_parser/src/syntax_kind/generated.rs

+2
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ pub enum SyntaxKind {
151151
FOR_TYPE,
152152
IMPL_TRAIT_TYPE,
153153
DYN_TRAIT_TYPE,
154+
OR_PAT,
155+
PAREN_PAT,
154156
REF_PAT,
155157
BOX_PAT,
156158
BIND_PAT,

0 commit comments

Comments
 (0)