@@ -75,14 +75,18 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
75
75
. collect ( ) ;
76
76
77
77
let module = ctx. sema . scope ( expr. syntax ( ) ) ?. module ( ) ;
78
- let ( mut missing_pats, is_non_exhaustive) : (
78
+ let ( mut missing_pats, is_non_exhaustive, has_hidden_variants ) : (
79
79
Peekable < Box < dyn Iterator < Item = ( ast:: Pat , bool ) > > > ,
80
80
bool ,
81
+ bool ,
81
82
) = if let Some ( enum_def) = resolve_enum_def ( & ctx. sema , & expr) {
82
83
let is_non_exhaustive = enum_def. is_non_exhaustive ( ctx. db ( ) , module. krate ( ) ) ;
83
84
84
85
let variants = enum_def. variants ( ctx. db ( ) ) ;
85
86
87
+ let has_hidden_variants =
88
+ variants. iter ( ) . any ( |variant| variant. should_be_hidden ( ctx. db ( ) , module. krate ( ) ) ) ;
89
+
86
90
let missing_pats = variants
87
91
. into_iter ( )
88
92
. filter_map ( |variant| {
@@ -101,7 +105,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
101
105
} else {
102
106
Box :: new ( missing_pats)
103
107
} ;
104
- ( missing_pats. peekable ( ) , is_non_exhaustive)
108
+ ( missing_pats. peekable ( ) , is_non_exhaustive, has_hidden_variants )
105
109
} else if let Some ( enum_defs) = resolve_tuple_of_enum_def ( & ctx. sema , & expr) {
106
110
let is_non_exhaustive =
107
111
enum_defs. iter ( ) . any ( |enum_def| enum_def. is_non_exhaustive ( ctx. db ( ) , module. krate ( ) ) ) ;
@@ -124,6 +128,12 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
124
128
if n_arms > 256 {
125
129
return None ;
126
130
}
131
+
132
+ let has_hidden_variants = variants_of_enums
133
+ . iter ( )
134
+ . flatten ( )
135
+ . any ( |variant| variant. should_be_hidden ( ctx. db ( ) , module. krate ( ) ) ) ;
136
+
127
137
let missing_pats = variants_of_enums
128
138
. into_iter ( )
129
139
. multi_cartesian_product ( )
@@ -139,7 +149,11 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
139
149
( ast:: Pat :: from ( make:: tuple_pat ( patterns) ) , is_hidden)
140
150
} )
141
151
. filter ( |( variant_pat, _) | is_variant_missing ( & top_lvl_pats, variant_pat) ) ;
142
- ( ( Box :: new ( missing_pats) as Box < dyn Iterator < Item = _ > > ) . peekable ( ) , is_non_exhaustive)
152
+ (
153
+ ( Box :: new ( missing_pats) as Box < dyn Iterator < Item = _ > > ) . peekable ( ) ,
154
+ is_non_exhaustive,
155
+ has_hidden_variants,
156
+ )
143
157
} else if let Some ( ( enum_def, len) ) = resolve_array_of_enum_def ( & ctx. sema , & expr) {
144
158
let is_non_exhaustive = enum_def. is_non_exhaustive ( ctx. db ( ) , module. krate ( ) ) ;
145
159
let variants = enum_def. variants ( ctx. db ( ) ) ;
@@ -148,6 +162,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
148
162
return None ;
149
163
}
150
164
165
+ let has_hidden_variants =
166
+ variants. iter ( ) . any ( |variant| variant. should_be_hidden ( ctx. db ( ) , module. krate ( ) ) ) ;
167
+
151
168
let variants_of_enums = vec ! [ variants; len] ;
152
169
153
170
let missing_pats = variants_of_enums
@@ -164,14 +181,20 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
164
181
( ast:: Pat :: from ( make:: slice_pat ( patterns) ) , is_hidden)
165
182
} )
166
183
. filter ( |( variant_pat, _) | is_variant_missing ( & top_lvl_pats, variant_pat) ) ;
167
- ( ( Box :: new ( missing_pats) as Box < dyn Iterator < Item = _ > > ) . peekable ( ) , is_non_exhaustive)
184
+ (
185
+ ( Box :: new ( missing_pats) as Box < dyn Iterator < Item = _ > > ) . peekable ( ) ,
186
+ is_non_exhaustive,
187
+ has_hidden_variants,
188
+ )
168
189
} else {
169
190
return None ;
170
191
} ;
171
192
172
193
let mut needs_catch_all_arm = is_non_exhaustive && !has_catch_all_arm;
173
194
174
- if !needs_catch_all_arm && missing_pats. peek ( ) . is_none ( ) {
195
+ if !needs_catch_all_arm
196
+ && ( ( has_hidden_variants && has_catch_all_arm) || missing_pats. peek ( ) . is_none ( ) )
197
+ {
175
198
return None ;
176
199
}
177
200
@@ -181,11 +204,17 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
181
204
target_range,
182
205
|builder| {
183
206
let new_match_arm_list = match_arm_list. clone_for_update ( ) ;
184
- let missing_arms = missing_pats
185
- . map ( |( pat, hidden) | {
186
- ( make:: match_arm ( iter:: once ( pat) , None , make:: ext:: expr_todo ( ) ) , hidden)
207
+
208
+ // having any hidden variants means that we need a catch-all arm
209
+ needs_catch_all_arm |= has_hidden_variants;
210
+
211
+ let missing_arms = missing_pats. filter_map ( |( pat, hidden) | {
212
+ // filter out hidden patterns because they're handled by the catch-all arm
213
+ ( !hidden) . then ( || {
214
+ make:: match_arm ( iter:: once ( pat) , None , make:: ext:: expr_todo ( ) )
215
+ . clone_for_update ( )
187
216
} )
188
- . map ( | ( it , hidden ) | ( it . clone_for_update ( ) , hidden ) ) ;
217
+ } ) ;
189
218
190
219
let catch_all_arm = new_match_arm_list
191
220
. arms ( )
@@ -204,15 +233,13 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
204
233
cov_mark:: hit!( add_missing_match_arms_empty_expr) ;
205
234
}
206
235
}
236
+
207
237
let mut first_new_arm = None ;
208
- for ( arm, hidden) in missing_arms {
209
- if hidden {
210
- needs_catch_all_arm = !has_catch_all_arm;
211
- } else {
212
- first_new_arm. get_or_insert_with ( || arm. clone ( ) ) ;
213
- new_match_arm_list. add_arm ( arm) ;
214
- }
238
+ for arm in missing_arms {
239
+ first_new_arm. get_or_insert_with ( || arm. clone ( ) ) ;
240
+ new_match_arm_list. add_arm ( arm) ;
215
241
}
242
+
216
243
if needs_catch_all_arm && !has_catch_all_arm {
217
244
cov_mark:: hit!( added_wildcard_pattern) ;
218
245
let arm = make:: match_arm (
@@ -1621,10 +1648,9 @@ pub enum E { #[doc(hidden)] A, }
1621
1648
) ;
1622
1649
}
1623
1650
1624
- // FIXME: I don't think the assist should be applicable in this case
1625
1651
#[ test]
1626
1652
fn does_not_fill_wildcard_with_wildcard ( ) {
1627
- check_assist (
1653
+ check_assist_not_applicable (
1628
1654
add_missing_match_arms,
1629
1655
r#"
1630
1656
//- /main.rs crate:main deps:e
@@ -1635,13 +1661,6 @@ fn foo(t: ::e::E) {
1635
1661
}
1636
1662
//- /e.rs crate:e
1637
1663
pub enum E { #[doc(hidden)] A, }
1638
- "# ,
1639
- r#"
1640
- fn foo(t: ::e::E) {
1641
- match t {
1642
- _ => todo!(),
1643
- }
1644
- }
1645
1664
"# ,
1646
1665
) ;
1647
1666
}
@@ -1777,7 +1796,7 @@ fn foo(t: ::e::E, b: bool) {
1777
1796
1778
1797
#[ test]
1779
1798
fn does_not_fill_wildcard_with_partial_wildcard_and_wildcard ( ) {
1780
- check_assist (
1799
+ check_assist_not_applicable (
1781
1800
add_missing_match_arms,
1782
1801
r#"
1783
1802
//- /main.rs crate:main deps:e
@@ -1789,14 +1808,6 @@ fn foo(t: ::e::E, b: bool) {
1789
1808
}
1790
1809
//- /e.rs crate:e
1791
1810
pub enum E { #[doc(hidden)] A, }"# ,
1792
- r#"
1793
- fn foo(t: ::e::E, b: bool) {
1794
- match t {
1795
- _ if b => todo!(),
1796
- _ => todo!(),
1797
- }
1798
- }
1799
- "# ,
1800
1811
) ;
1801
1812
}
1802
1813
0 commit comments