Skip to content

Commit b5ba9c3

Browse files
committed
Address nits and suggestions.
Simplify the logic a lot by removing the check for a placeholder pat. This means the auto-fill no longer returns a compile-able value.
1 parent 5f8f8a3 commit b5ba9c3

File tree

1 file changed

+32
-140
lines changed

1 file changed

+32
-140
lines changed

crates/ra_assists/src/handlers/fill_match_arms.rs

Lines changed: 32 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
//! FIXME: write short doc here
22
3-
use std::{collections::LinkedList, iter};
3+
use std::iter;
44

55
use hir::{Adt, HasSource, Semantics};
66
use ra_ide_db::RootDatabase;
77

88
use crate::{Assist, AssistCtx, AssistId};
9-
use ra_syntax::{
10-
ast::{self, edit::IndentLevel, make, AstNode, NameOwner},
11-
SyntaxKind, SyntaxNode,
12-
};
9+
use ra_syntax::ast::{self, edit::IndentLevel, make, AstNode, NameOwner};
1310

14-
use ast::{MatchArm, MatchGuard, Pat};
11+
use ast::{MatchArm, Pat};
1512

1613
// Assist: fill_match_arms
1714
//
@@ -57,48 +54,20 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> {
5754
}
5855
}
5956

60-
let mut has_partial_match = false;
6157
let db = ctx.db;
6258
let missing_arms: Vec<MatchArm> = variants
6359
.into_iter()
6460
.filter_map(|variant| build_pat(db, module, variant))
65-
.filter(|variant_pat| {
66-
!arms.iter().filter_map(|arm| arm.pat().map(|_| arm)).any(|arm| {
67-
let pat = arm.pat().unwrap();
68-
69-
// Special casee OrPat as separate top-level pats
70-
let pats: Vec<Pat> = match Pat::from(pat.clone()) {
71-
Pat::OrPat(pats) => pats.pats().collect::<Vec<_>>(),
72-
_ => vec![pat],
73-
};
74-
75-
pats.iter().any(|pat| {
76-
match does_arm_pat_match_variant(pat, arm.guard(), variant_pat) {
77-
ArmMatch::Yes => true,
78-
ArmMatch::No => false,
79-
ArmMatch::Partial => {
80-
has_partial_match = true;
81-
true
82-
}
83-
}
84-
})
85-
})
86-
})
61+
.filter(|variant_pat| is_variant_missing(&mut arms, variant_pat))
8762
.map(|pat| make::match_arm(iter::once(pat), make::expr_unit()))
8863
.collect();
8964

90-
if missing_arms.is_empty() && !has_partial_match {
65+
if missing_arms.is_empty() {
9166
return None;
9267
}
9368

9469
ctx.add_assist(AssistId("fill_match_arms"), "Fill match arms", |edit| {
9570
arms.extend(missing_arms);
96-
if has_partial_match {
97-
arms.push(make::match_arm(
98-
iter::once(make::placeholder_pat().into()),
99-
make::expr_unit(),
100-
));
101-
}
10271

10372
let indent_level = IndentLevel::from_node(match_arm_list.syntax());
10473
let new_arm_list = indent_level.increase_indent(make::match_arm_list(arms));
@@ -109,59 +78,23 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> {
10978
})
11079
}
11180

112-
enum ArmMatch {
113-
Yes,
114-
No,
115-
Partial,
116-
}
117-
118-
fn does_arm_pat_match_variant(arm: &Pat, arm_guard: Option<MatchGuard>, var: &Pat) -> ArmMatch {
119-
let arm = flatten_pats(arm.clone());
120-
let var = flatten_pats(var.clone());
121-
let mut arm = arm.iter();
122-
let mut var = var.iter();
123-
124-
// If the first part of the Pat don't match, there's no match
125-
match (arm.next(), var.next()) {
126-
(Some(arm), Some(var)) if arm.text() == var.text() => {}
127-
_ => return ArmMatch::No,
128-
}
129-
130-
// If we have a guard we automatically know we have a partial match
131-
if arm_guard.is_some() {
132-
return ArmMatch::Partial;
133-
}
81+
fn is_variant_missing(existing_arms: &mut Vec<MatchArm>, var: &Pat) -> bool {
82+
existing_arms.iter().filter_map(|arm| arm.pat()).all(|pat| {
83+
// Special casee OrPat as separate top-level pats
84+
let top_level_pats: Vec<Pat> = match pat {
85+
Pat::OrPat(pats) => pats.pats().collect::<Vec<_>>(),
86+
_ => vec![pat],
87+
};
13488

135-
if arm.clone().count() != var.clone().count() {
136-
return ArmMatch::Partial;
137-
}
138-
139-
let direct_match = arm.zip(var).all(|(arm, var)| {
140-
if arm.text() == var.text() {
141-
return true;
142-
}
143-
match (arm.kind(), var.kind()) {
144-
(SyntaxKind::PLACEHOLDER_PAT, SyntaxKind::PLACEHOLDER_PAT) => true,
145-
(SyntaxKind::DOT_DOT_PAT, SyntaxKind::PLACEHOLDER_PAT) => true,
146-
(SyntaxKind::BIND_PAT, SyntaxKind::PLACEHOLDER_PAT) => true,
147-
_ => false,
148-
}
149-
});
150-
151-
match direct_match {
152-
true => ArmMatch::Yes,
153-
false => ArmMatch::Partial,
154-
}
89+
!top_level_pats.iter().any(|pat| does_pat_match_variant(pat, var))
90+
})
15591
}
15692

157-
fn flatten_pats(pat: Pat) -> Vec<SyntaxNode> {
158-
let mut pats: LinkedList<SyntaxNode> = pat.syntax().children().collect();
159-
let mut out: Vec<SyntaxNode> = vec![];
160-
while let Some(p) = pats.pop_front() {
161-
pats.extend(p.children());
162-
out.push(p);
163-
}
164-
out
93+
fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool {
94+
let pat_head = pat.syntax().first_child().map(|node| node.text());
95+
let var_head = var.syntax().first_child().map(|node| node.text());
96+
97+
pat_head == var_head
16598
}
16699

167100
fn resolve_enum_def(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<hir::Enum> {
@@ -193,66 +126,59 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> O
193126

194127
#[cfg(test)]
195128
mod tests {
196-
use crate::helpers::{check_assist, check_assist_target};
129+
use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target};
197130

198131
use super::fill_match_arms;
199132

200133
#[test]
201-
fn partial_fill_multi() {
202-
check_assist(
134+
fn all_match_arms_provided() {
135+
check_assist_not_applicable(
203136
fill_match_arms,
204137
r#"
205138
enum A {
206139
As,
207-
Bs(i32, Option<i32>)
140+
Bs{x:i32, y:Option<i32>},
141+
Cs(i32, Option<i32>),
208142
}
209143
fn main() {
210144
match A::As<|> {
211-
A::Bs(_, Some(_)) => (),
212-
}
213-
}
214-
"#,
215-
r#"
216-
enum A {
217-
As,
218-
Bs(i32, Option<i32>)
219-
}
220-
fn main() {
221-
match <|>A::As {
222-
A::Bs(_, Some(_)) => (),
223-
A::As => (),
224-
_ => (),
145+
A::As,
146+
A::Bs{x,y:Some(_)} => (),
147+
A::Cs(_, Some(_)) => (),
225148
}
226149
}
227150
"#,
228151
);
229152
}
230153

231154
#[test]
232-
fn partial_fill_record() {
155+
fn partial_fill_record_tuple() {
233156
check_assist(
234157
fill_match_arms,
235158
r#"
236159
enum A {
237160
As,
238161
Bs{x:i32, y:Option<i32>},
162+
Cs(i32, Option<i32>),
239163
}
240164
fn main() {
241165
match A::As<|> {
242166
A::Bs{x,y:Some(_)} => (),
167+
A::Cs(_, Some(_)) => (),
243168
}
244169
}
245170
"#,
246171
r#"
247172
enum A {
248173
As,
249174
Bs{x:i32, y:Option<i32>},
175+
Cs(i32, Option<i32>),
250176
}
251177
fn main() {
252178
match <|>A::As {
253179
A::Bs{x,y:Some(_)} => (),
180+
A::Cs(_, Some(_)) => (),
254181
A::As => (),
255-
_ => (),
256182
}
257183
}
258184
"#,
@@ -291,39 +217,6 @@ mod tests {
291217
);
292218
}
293219

294-
#[test]
295-
fn partial_fill_or_pat2() {
296-
check_assist(
297-
fill_match_arms,
298-
r#"
299-
enum A {
300-
As,
301-
Bs,
302-
Cs(Option<i32>),
303-
}
304-
fn main() {
305-
match A::As<|> {
306-
A::Cs(Some(_)) | A::Bs => (),
307-
}
308-
}
309-
"#,
310-
r#"
311-
enum A {
312-
As,
313-
Bs,
314-
Cs(Option<i32>),
315-
}
316-
fn main() {
317-
match <|>A::As {
318-
A::Cs(Some(_)) | A::Bs => (),
319-
A::As => (),
320-
_ => (),
321-
}
322-
}
323-
"#,
324-
);
325-
}
326-
327220
#[test]
328221
fn partial_fill() {
329222
check_assist(
@@ -367,7 +260,6 @@ mod tests {
367260
A::Es(B::Xs) => (),
368261
A::As => (),
369262
A::Cs => (),
370-
_ => (),
371263
}
372264
}
373265
"#,

0 commit comments

Comments
 (0)