@@ -8,7 +8,7 @@ use ide_db::{
88 ty_filter:: TryEnum ,
99} ;
1010use syntax:: {
11- AstNode , T , TextRange ,
11+ AstNode , Edition , T , TextRange ,
1212 ast:: { self , HasName , edit:: IndentLevel , edit_in_place:: Indent , syntax_factory:: SyntaxFactory } ,
1313} ;
1414
@@ -187,7 +187,7 @@ fn make_else_arm(
187187
188188// Assist: replace_match_with_if_let
189189//
190- // Replaces a binary `match` with a wildcard pattern and no guards with an `if let` expression.
190+ // Replaces a binary `match` with a wildcard pattern with an `if let` expression.
191191//
192192// ```
193193// enum Action { Move { distance: u32 }, Stop }
@@ -225,18 +225,24 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
225225
226226 let mut arms = match_arm_list. arms ( ) ;
227227 let ( first_arm, second_arm) = ( arms. next ( ) ?, arms. next ( ) ?) ;
228- if arms. next ( ) . is_some ( ) || first_arm. guard ( ) . is_some ( ) || second_arm. guard ( ) . is_some ( ) {
228+ if arms. next ( ) . is_some ( ) || second_arm. guard ( ) . is_some ( ) {
229+ return None ;
230+ }
231+ if first_arm. guard ( ) . is_some ( ) && ctx. edition ( ) < Edition :: Edition2024 {
229232 return None ;
230233 }
231234
232- let ( if_let_pat, then_expr, else_expr) = pick_pattern_and_expr_order (
235+ let ( if_let_pat, guard , then_expr, else_expr) = pick_pattern_and_expr_order (
233236 & ctx. sema ,
234237 first_arm. pat ( ) ?,
235238 second_arm. pat ( ) ?,
236239 first_arm. expr ( ) ?,
237240 second_arm. expr ( ) ?,
241+ first_arm. guard ( ) ,
242+ second_arm. guard ( ) ,
238243 ) ?;
239244 let scrutinee = match_expr. expr ( ) ?;
245+ let guard = guard. and_then ( |it| it. condition ( ) ) ;
240246
241247 let let_ = match & if_let_pat {
242248 ast:: Pat :: LiteralPat ( p)
@@ -277,6 +283,11 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
277283 }
278284 _ => make. expr_let ( if_let_pat, scrutinee) . into ( ) ,
279285 } ;
286+ let condition = if let Some ( guard) = guard {
287+ make. expr_bin ( condition, ast:: BinaryOp :: LogicOp ( ast:: LogicOp :: And ) , guard) . into ( )
288+ } else {
289+ condition
290+ } ;
280291 let then_expr = then_expr. clone_for_update ( ) ;
281292 then_expr. reindent_to ( IndentLevel :: single ( ) ) ;
282293 let then_block = make_block_expr ( then_expr) ;
@@ -303,18 +314,23 @@ fn pick_pattern_and_expr_order(
303314 pat2 : ast:: Pat ,
304315 expr : ast:: Expr ,
305316 expr2 : ast:: Expr ,
306- ) -> Option < ( ast:: Pat , ast:: Expr , ast:: Expr ) > {
317+ guard : Option < ast:: MatchGuard > ,
318+ guard2 : Option < ast:: MatchGuard > ,
319+ ) -> Option < ( ast:: Pat , Option < ast:: MatchGuard > , ast:: Expr , ast:: Expr ) > {
320+ if guard. is_some ( ) && guard2. is_some ( ) {
321+ return None ;
322+ }
307323 let res = match ( pat, pat2) {
308324 ( ast:: Pat :: WildcardPat ( _) , _) => return None ,
309- ( pat, ast:: Pat :: WildcardPat ( _) ) => ( pat, expr, expr2) ,
310- ( pat, _) if is_empty_expr ( & expr2) => ( pat, expr, expr2) ,
311- ( _, pat) if is_empty_expr ( & expr) => ( pat, expr2, expr) ,
325+ ( pat, ast:: Pat :: WildcardPat ( _) ) => ( pat, guard , expr, expr2) ,
326+ ( pat, _) if is_empty_expr ( & expr2) => ( pat, guard , expr, expr2) ,
327+ ( _, pat) if is_empty_expr ( & expr) => ( pat, guard , expr2, expr) ,
312328 ( pat, pat2) => match ( binds_name ( sema, & pat) , binds_name ( sema, & pat2) ) {
313329 ( true , true ) => return None ,
314- ( true , false ) => ( pat, expr, expr2) ,
315- ( false , true ) => ( pat2, expr2, expr) ,
316- _ if is_sad_pat ( sema, & pat) => ( pat2, expr2, expr) ,
317- ( false , false ) => ( pat, expr, expr2) ,
330+ ( true , false ) => ( pat, guard , expr, expr2) ,
331+ ( false , true ) => ( pat2, guard2 , expr2, expr) ,
332+ _ if is_sad_pat ( sema, & pat) => ( pat2, guard2 , expr2, expr) ,
333+ ( false , false ) => ( pat, guard , expr, expr2) ,
318334 } ,
319335 } ;
320336 Some ( res)
@@ -1849,6 +1865,30 @@ fn main() {
18491865 code()
18501866 }
18511867}
1868+ "# ,
1869+ )
1870+ }
1871+
1872+ #[ test]
1873+ fn test_replace_match_with_if_let_chain ( ) {
1874+ check_assist (
1875+ replace_match_with_if_let,
1876+ r#"
1877+ fn main() {
1878+ match$0 Some(0) {
1879+ Some(n) if n % 2 == 0 && n != 6 => (),
1880+ _ => code(),
1881+ }
1882+ }
1883+ "# ,
1884+ r#"
1885+ fn main() {
1886+ if let Some(n) = Some(0) && n % 2 == 0 && n != 6 {
1887+ ()
1888+ } else {
1889+ code()
1890+ }
1891+ }
18521892"# ,
18531893 )
18541894 }
0 commit comments