11//! FIXME: write short doc here
22
3- use std:: { collections :: LinkedList , iter} ;
3+ use std:: iter;
44
55use hir:: { Adt , HasSource , Semantics } ;
66use ra_ide_db:: RootDatabase ;
77
88use 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
167100fn 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) ]
195128mod 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