1
1
//! FIXME: write short doc here
2
2
3
- use std:: { collections :: LinkedList , iter} ;
3
+ use std:: iter;
4
4
5
5
use hir:: { Adt , HasSource , Semantics } ;
6
6
use ra_ide_db:: RootDatabase ;
7
7
8
8
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 } ;
13
10
14
- use ast:: { MatchArm , MatchGuard , Pat } ;
11
+ use ast:: { MatchArm , Pat } ;
15
12
16
13
// Assist: fill_match_arms
17
14
//
@@ -57,48 +54,20 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> {
57
54
}
58
55
}
59
56
60
- let mut has_partial_match = false ;
61
57
let db = ctx. db ;
62
58
let missing_arms: Vec < MatchArm > = variants
63
59
. into_iter ( )
64
60
. 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) )
87
62
. map ( |pat| make:: match_arm ( iter:: once ( pat) , make:: expr_unit ( ) ) )
88
63
. collect ( ) ;
89
64
90
- if missing_arms. is_empty ( ) && !has_partial_match {
65
+ if missing_arms. is_empty ( ) {
91
66
return None ;
92
67
}
93
68
94
69
ctx. add_assist ( AssistId ( "fill_match_arms" ) , "Fill match arms" , |edit| {
95
70
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
- }
102
71
103
72
let indent_level = IndentLevel :: from_node ( match_arm_list. syntax ( ) ) ;
104
73
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> {
109
78
} )
110
79
}
111
80
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
+ } ;
134
88
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
+ } )
155
91
}
156
92
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
165
98
}
166
99
167
100
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
193
126
194
127
#[ cfg( test) ]
195
128
mod tests {
196
- use crate :: helpers:: { check_assist, check_assist_target} ;
129
+ use crate :: helpers:: { check_assist, check_assist_not_applicable , check_assist_target} ;
197
130
198
131
use super :: fill_match_arms;
199
132
200
133
#[ test]
201
- fn partial_fill_multi ( ) {
202
- check_assist (
134
+ fn all_match_arms_provided ( ) {
135
+ check_assist_not_applicable (
203
136
fill_match_arms,
204
137
r#"
205
138
enum A {
206
139
As,
207
- Bs(i32, Option<i32>)
140
+ Bs{x:i32, y:Option<i32>},
141
+ Cs(i32, Option<i32>),
208
142
}
209
143
fn main() {
210
144
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(_)) => (),
225
148
}
226
149
}
227
150
"# ,
228
151
) ;
229
152
}
230
153
231
154
#[ test]
232
- fn partial_fill_record ( ) {
155
+ fn partial_fill_record_tuple ( ) {
233
156
check_assist (
234
157
fill_match_arms,
235
158
r#"
236
159
enum A {
237
160
As,
238
161
Bs{x:i32, y:Option<i32>},
162
+ Cs(i32, Option<i32>),
239
163
}
240
164
fn main() {
241
165
match A::As<|> {
242
166
A::Bs{x,y:Some(_)} => (),
167
+ A::Cs(_, Some(_)) => (),
243
168
}
244
169
}
245
170
"# ,
246
171
r#"
247
172
enum A {
248
173
As,
249
174
Bs{x:i32, y:Option<i32>},
175
+ Cs(i32, Option<i32>),
250
176
}
251
177
fn main() {
252
178
match <|>A::As {
253
179
A::Bs{x,y:Some(_)} => (),
180
+ A::Cs(_, Some(_)) => (),
254
181
A::As => (),
255
- _ => (),
256
182
}
257
183
}
258
184
"# ,
@@ -291,39 +217,6 @@ mod tests {
291
217
) ;
292
218
}
293
219
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
-
327
220
#[ test]
328
221
fn partial_fill ( ) {
329
222
check_assist (
@@ -367,7 +260,6 @@ mod tests {
367
260
A::Es(B::Xs) => (),
368
261
A::As => (),
369
262
A::Cs => (),
370
- _ => (),
371
263
}
372
264
}
373
265
"# ,
0 commit comments