ra_ap_ide_assists/handlers/
replace_if_let_with_match.rs

1use std::iter::successors;
2
3use either::Either;
4use ide_db::{
5    RootDatabase,
6    defs::NameClass,
7    syntax_helpers::node_ext::{is_pattern_cond, single_let},
8    ty_filter::TryEnum,
9};
10use syntax::{
11    AstNode, Edition, T, TextRange,
12    ast::{self, HasName, edit::IndentLevel, edit_in_place::Indent, syntax_factory::SyntaxFactory},
13};
14
15use crate::{
16    AssistContext, AssistId, Assists,
17    utils::{does_pat_match_variant, does_pat_variant_nested_or_literal, unwrap_trivial_block},
18};
19
20// Assist: replace_if_let_with_match
21//
22// Replaces a `if let` expression with a `match` expression.
23//
24// ```
25// enum Action { Move { distance: u32 }, Stop }
26//
27// fn handle(action: Action) {
28//     $0if let Action::Move { distance } = action {
29//         foo(distance)
30//     } else {
31//         bar()
32//     }
33// }
34// ```
35// ->
36// ```
37// enum Action { Move { distance: u32 }, Stop }
38//
39// fn handle(action: Action) {
40//     match action {
41//         Action::Move { distance } => foo(distance),
42//         _ => bar(),
43//     }
44// }
45// ```
46pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
47    let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
48    let available_range = TextRange::new(
49        if_expr.syntax().text_range().start(),
50        if_expr.then_branch()?.syntax().text_range().start(),
51    );
52    let cursor_in_range = available_range.contains_range(ctx.selection_trimmed());
53    if !cursor_in_range {
54        return None;
55    }
56    let mut else_block = None;
57    let if_exprs = successors(Some(if_expr.clone()), |expr| match expr.else_branch()? {
58        ast::ElseBranch::IfExpr(expr) => Some(expr),
59        ast::ElseBranch::Block(block) => {
60            else_block = Some(block);
61            None
62        }
63    });
64    let scrutinee_to_be_expr = if_expr.condition()?;
65    let scrutinee_to_be_expr = match single_let(scrutinee_to_be_expr.clone()) {
66        Some(cond) => cond.expr()?,
67        None => scrutinee_to_be_expr,
68    };
69
70    let mut pat_seen = false;
71    let mut cond_bodies = Vec::new();
72    for if_expr in if_exprs {
73        let cond = if_expr.condition()?;
74        let cond = match single_let(cond.clone()) {
75            Some(let_) => {
76                let pat = let_.pat()?;
77                let expr = let_.expr()?;
78                // FIXME: If one `let` is wrapped in parentheses and the second is not,
79                // we'll exit here.
80                if scrutinee_to_be_expr.syntax().text() != expr.syntax().text() {
81                    // Only if all condition expressions are equal we can merge them into a match
82                    return None;
83                }
84                pat_seen = true;
85                Either::Left(pat)
86            }
87            // Multiple `let`, unsupported.
88            None if is_pattern_cond(cond.clone()) => return None,
89            None => Either::Right(cond),
90        };
91        let body = if_expr.then_branch()?;
92        cond_bodies.push((cond, body));
93    }
94
95    if !pat_seen && cond_bodies.len() != 1 {
96        // Don't offer turning an if (chain) without patterns into a match,
97        // unless its a simple `if cond { .. } (else { .. })`
98        return None;
99    }
100
101    let let_ = if pat_seen { " let" } else { "" };
102
103    acc.add(
104        AssistId::refactor_rewrite("replace_if_let_with_match"),
105        format!("Replace if{let_} with match"),
106        available_range,
107        move |builder| {
108            let make = SyntaxFactory::with_mappings();
109            let match_expr = {
110                let else_arm = make_else_arm(ctx, &make, else_block, &cond_bodies);
111                let make_match_arm = |(pat, body): (_, ast::BlockExpr)| {
112                    let body = make.block_expr(body.statements(), body.tail_expr());
113                    body.indent(IndentLevel::from(1));
114                    let body = unwrap_trivial_block(body);
115                    match pat {
116                        Either::Left(pat) => make.match_arm(pat, None, body),
117                        Either::Right(_) if !pat_seen => {
118                            make.match_arm(make.literal_pat("true").into(), None, body)
119                        }
120                        Either::Right(expr) => make.match_arm(
121                            make.wildcard_pat().into(),
122                            Some(make.match_guard(expr)),
123                            body,
124                        ),
125                    }
126                };
127                let arms = cond_bodies.into_iter().map(make_match_arm).chain([else_arm]);
128                let match_expr = make.expr_match(scrutinee_to_be_expr, make.match_arm_list(arms));
129                match_expr.indent(IndentLevel::from_node(if_expr.syntax()));
130                match_expr.into()
131            };
132
133            let has_preceding_if_expr =
134                if_expr.syntax().parent().is_some_and(|it| ast::IfExpr::can_cast(it.kind()));
135            let expr = if has_preceding_if_expr {
136                // make sure we replace the `else if let ...` with a block so we don't end up with `else expr`
137                make.block_expr([], Some(match_expr)).into()
138            } else {
139                match_expr
140            };
141
142            let mut editor = builder.make_editor(if_expr.syntax());
143            editor.replace(if_expr.syntax(), expr.syntax());
144            editor.add_mappings(make.finish_with_mappings());
145            builder.add_file_edits(ctx.vfs_file_id(), editor);
146        },
147    )
148}
149
150fn make_else_arm(
151    ctx: &AssistContext<'_>,
152    make: &SyntaxFactory,
153    else_block: Option<ast::BlockExpr>,
154    conditionals: &[(Either<ast::Pat, ast::Expr>, ast::BlockExpr)],
155) -> ast::MatchArm {
156    let (pattern, expr) = if let Some(else_block) = else_block {
157        let pattern = match conditionals {
158            [(Either::Right(_), _)] => make.literal_pat("false").into(),
159            [(Either::Left(pat), _)] => match ctx
160                .sema
161                .type_of_pat(pat)
162                .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.adjusted()))
163            {
164                Some(it) => {
165                    if does_pat_match_variant(pat, &it.sad_pattern()) {
166                        it.happy_pattern_wildcard()
167                    } else if does_pat_variant_nested_or_literal(ctx, pat) {
168                        make.wildcard_pat().into()
169                    } else {
170                        it.sad_pattern()
171                    }
172                }
173                None => make.wildcard_pat().into(),
174            },
175            _ => make.wildcard_pat().into(),
176        };
177        (pattern, unwrap_trivial_block(else_block))
178    } else {
179        let pattern = match conditionals {
180            [(Either::Right(_), _)] => make.literal_pat("false").into(),
181            _ => make.wildcard_pat().into(),
182        };
183        (pattern, make.expr_unit())
184    };
185    make.match_arm(pattern, None, expr)
186}
187
188// Assist: replace_match_with_if_let
189//
190// Replaces a binary `match` with a wildcard pattern with an `if let` expression.
191//
192// ```
193// enum Action { Move { distance: u32 }, Stop }
194//
195// fn handle(action: Action) {
196//     $0match action {
197//         Action::Move { distance } => foo(distance),
198//         _ => bar(),
199//     }
200// }
201// ```
202// ->
203// ```
204// enum Action { Move { distance: u32 }, Stop }
205//
206// fn handle(action: Action) {
207//     if let Action::Move { distance } = action {
208//         foo(distance)
209//     } else {
210//         bar()
211//     }
212// }
213// ```
214pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
215    let match_expr: ast::MatchExpr = ctx.find_node_at_offset()?;
216    let match_arm_list = match_expr.match_arm_list()?;
217    let available_range = TextRange::new(
218        match_expr.syntax().text_range().start(),
219        match_arm_list.syntax().text_range().start(),
220    );
221    let cursor_in_range = available_range.contains_range(ctx.selection_trimmed());
222    if !cursor_in_range {
223        return None;
224    }
225
226    let mut arms = match_arm_list.arms();
227    let (first_arm, second_arm) = (arms.next()?, arms.next()?);
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 {
232        return None;
233    }
234
235    let (if_let_pat, guard, then_expr, else_expr) = pick_pattern_and_expr_order(
236        &ctx.sema,
237        first_arm.pat()?,
238        second_arm.pat()?,
239        first_arm.expr()?,
240        second_arm.expr()?,
241        first_arm.guard(),
242        second_arm.guard(),
243    )?;
244    let scrutinee = match_expr.expr()?;
245    let guard = guard.and_then(|it| it.condition());
246
247    let let_ = match &if_let_pat {
248        ast::Pat::LiteralPat(p)
249            if p.literal()
250                .map(|it| it.token().kind())
251                .is_some_and(|it| it == T![true] || it == T![false]) =>
252        {
253            ""
254        }
255        _ => " let",
256    };
257    acc.add(
258        AssistId::refactor_rewrite("replace_match_with_if_let"),
259        format!("Replace match with if{let_}"),
260        match_expr.syntax().text_range(),
261        move |builder| {
262            let make = SyntaxFactory::with_mappings();
263            let make_block_expr = |expr: ast::Expr| {
264                // Blocks with modifiers (unsafe, async, etc.) are parsed as BlockExpr, but are
265                // formatted without enclosing braces. If we encounter such block exprs,
266                // wrap them in another BlockExpr.
267                match expr {
268                    ast::Expr::BlockExpr(block) if block.modifier().is_none() => block,
269                    expr => make.block_expr([], Some(expr)),
270                }
271            };
272
273            let condition = match if_let_pat {
274                ast::Pat::LiteralPat(p)
275                    if p.literal().is_some_and(|it| it.token().kind() == T![true]) =>
276                {
277                    scrutinee
278                }
279                ast::Pat::LiteralPat(p)
280                    if p.literal().is_some_and(|it| it.token().kind() == T![false]) =>
281                {
282                    make.expr_prefix(T![!], scrutinee).into()
283                }
284                _ => make.expr_let(if_let_pat, scrutinee).into(),
285            };
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            };
291            let then_expr = then_expr.clone_for_update();
292            then_expr.reindent_to(IndentLevel::single());
293            let then_block = make_block_expr(then_expr);
294            let else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) };
295            let if_let_expr = make.expr_if(
296                condition,
297                then_block,
298                else_expr.map(make_block_expr).map(ast::ElseBranch::Block),
299            );
300            if_let_expr.indent(IndentLevel::from_node(match_expr.syntax()));
301
302            let mut editor = builder.make_editor(match_expr.syntax());
303            editor.replace(match_expr.syntax(), if_let_expr.syntax());
304            editor.add_mappings(make.finish_with_mappings());
305            builder.add_file_edits(ctx.vfs_file_id(), editor);
306        },
307    )
308}
309
310/// Pick the pattern for the if let condition and return the expressions for the `then` body and `else` body in that order.
311fn pick_pattern_and_expr_order(
312    sema: &hir::Semantics<'_, RootDatabase>,
313    pat: ast::Pat,
314    pat2: ast::Pat,
315    expr: ast::Expr,
316    expr2: 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    }
323    let res = match (pat, pat2) {
324        (ast::Pat::WildcardPat(_), _) => return None,
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),
328        (pat, pat2) => match (binds_name(sema, &pat), binds_name(sema, &pat2)) {
329            (true, true) => return None,
330            (true, false) => (pat, guard, expr, expr2),
331            (false, true) => {
332                // This pattern triggers an invalid transformation.
333                // See issues #11373, #19443
334                if let ast::Pat::IdentPat(_) = pat2 {
335                    return None;
336                }
337                (pat2, guard2, expr2, expr)
338            }
339            _ if is_sad_pat(sema, &pat) => (pat2, guard2, expr2, expr),
340            (false, false) => (pat, guard, expr, expr2),
341        },
342    };
343    Some(res)
344}
345
346fn is_empty_expr(expr: &ast::Expr) -> bool {
347    match expr {
348        ast::Expr::BlockExpr(expr) => match expr.stmt_list() {
349            Some(it) => it.statements().next().is_none() && it.tail_expr().is_none(),
350            None => true,
351        },
352        ast::Expr::TupleExpr(expr) => expr.fields().next().is_none(),
353        _ => false,
354    }
355}
356
357fn binds_name(sema: &hir::Semantics<'_, RootDatabase>, pat: &ast::Pat) -> bool {
358    let binds_name_v = |pat| binds_name(sema, &pat);
359    match pat {
360        ast::Pat::IdentPat(pat) => !matches!(
361            pat.name().and_then(|name| NameClass::classify(sema, &name)),
362            Some(NameClass::ConstReference(_))
363        ),
364        ast::Pat::MacroPat(_) => true,
365        ast::Pat::OrPat(pat) => pat.pats().any(binds_name_v),
366        ast::Pat::SlicePat(pat) => pat.pats().any(binds_name_v),
367        ast::Pat::TuplePat(it) => it.fields().any(binds_name_v),
368        ast::Pat::TupleStructPat(it) => it.fields().any(binds_name_v),
369        ast::Pat::RecordPat(it) => it
370            .record_pat_field_list()
371            .is_some_and(|rpfl| rpfl.fields().flat_map(|rpf| rpf.pat()).any(binds_name_v)),
372        ast::Pat::RefPat(pat) => pat.pat().is_some_and(binds_name_v),
373        ast::Pat::BoxPat(pat) => pat.pat().is_some_and(binds_name_v),
374        ast::Pat::ParenPat(pat) => pat.pat().is_some_and(binds_name_v),
375        _ => false,
376    }
377}
378
379fn is_sad_pat(sema: &hir::Semantics<'_, RootDatabase>, pat: &ast::Pat) -> bool {
380    sema.type_of_pat(pat)
381        .and_then(|ty| TryEnum::from_ty(sema, &ty.adjusted()))
382        .is_some_and(|it| does_pat_match_variant(pat, &it.sad_pattern()))
383}
384
385#[cfg(test)]
386mod tests {
387    use super::*;
388
389    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
390
391    #[test]
392    fn test_if_let_with_match_inapplicable_for_simple_ifs() {
393        check_assist_not_applicable(
394            replace_if_let_with_match,
395            r#"
396fn main() {
397    if $0true {} else if false {} else {}
398}
399"#,
400        )
401    }
402
403    #[test]
404    fn test_if_with_match_no_else() {
405        check_assist(
406            replace_if_let_with_match,
407            r#"
408pub fn foo(foo: bool) {
409    if foo$0 {
410        self.foo();
411    }
412}
413"#,
414            r#"
415pub fn foo(foo: bool) {
416    match foo {
417        true => {
418            self.foo();
419        }
420        false => (),
421    }
422}
423"#,
424        )
425    }
426
427    #[test]
428    fn test_if_with_match_with_else() {
429        check_assist(
430            replace_if_let_with_match,
431            r#"
432pub fn foo(foo: bool) {
433    if foo$0 {
434        self.foo();
435    } else {
436        self.bar();
437    }
438}
439"#,
440            r#"
441pub fn foo(foo: bool) {
442    match foo {
443        true => {
444            self.foo();
445        }
446        false => {
447            self.bar();
448        }
449    }
450}
451"#,
452        )
453    }
454
455    #[test]
456    fn test_if_let_with_match_no_else() {
457        check_assist(
458            replace_if_let_with_match,
459            r#"
460impl VariantData {
461    pub fn foo(&self) {
462        if $0let VariantData::Struct(..) = *self {
463            self.foo();
464        }
465    }
466}
467"#,
468            r#"
469impl VariantData {
470    pub fn foo(&self) {
471        match *self {
472            VariantData::Struct(..) => {
473                self.foo();
474            }
475            _ => (),
476        }
477    }
478}
479"#,
480        )
481    }
482
483    #[test]
484    fn test_if_let_with_match_available_range_left() {
485        check_assist_not_applicable(
486            replace_if_let_with_match,
487            r#"
488impl VariantData {
489    pub fn foo(&self) {
490        $0 if let VariantData::Struct(..) = *self {
491            self.foo();
492        }
493    }
494}
495"#,
496        )
497    }
498
499    #[test]
500    fn test_if_let_with_match_available_range_right() {
501        check_assist_not_applicable(
502            replace_if_let_with_match,
503            r#"
504impl VariantData {
505    pub fn foo(&self) {
506        if let VariantData::Struct(..) = *self {$0
507            self.foo();
508        }
509    }
510}
511"#,
512        )
513    }
514
515    #[test]
516    fn test_if_let_with_match_let_chain() {
517        check_assist_not_applicable(
518            replace_if_let_with_match,
519            r#"
520fn main() {
521    if $0let true = true && let Some(1) = None {}
522}
523"#,
524        )
525    }
526
527    #[test]
528    fn test_if_let_with_match_basic() {
529        check_assist(
530            replace_if_let_with_match,
531            r#"
532impl VariantData {
533    pub fn is_struct(&self) -> bool {
534        if $0let VariantData::Struct(..) = *self {
535            true
536        } else if let VariantData::Tuple(..) = *self {
537            false
538        } else if cond() {
539            true
540        } else {
541            bar(
542                123
543            )
544        }
545    }
546}
547"#,
548            r#"
549impl VariantData {
550    pub fn is_struct(&self) -> bool {
551        match *self {
552            VariantData::Struct(..) => true,
553            VariantData::Tuple(..) => false,
554            _ if cond() => true,
555            _ => {
556                    bar(
557                        123
558                    )
559                }
560        }
561    }
562}
563"#,
564        )
565    }
566
567    #[test]
568    fn test_if_let_with_match_on_tail_if_let() {
569        check_assist(
570            replace_if_let_with_match,
571            r#"
572impl VariantData {
573    pub fn is_struct(&self) -> bool {
574        if let VariantData::Struct(..) = *self {
575            true
576        } else if let$0 VariantData::Tuple(..) = *self {
577            false
578        } else {
579            false
580        }
581    }
582}
583"#,
584            r#"
585impl VariantData {
586    pub fn is_struct(&self) -> bool {
587        if let VariantData::Struct(..) = *self {
588            true
589        } else {
590    match *self {
591            VariantData::Tuple(..) => false,
592            _ => false,
593        }
594}
595    }
596}
597"#,
598        )
599    }
600
601    #[test]
602    fn special_case_option() {
603        check_assist(
604            replace_if_let_with_match,
605            r#"
606//- minicore: option
607fn foo(x: Option<i32>) {
608    $0if let Some(x) = x {
609        println!("{}", x)
610    } else {
611        println!("none")
612    }
613}
614"#,
615            r#"
616fn foo(x: Option<i32>) {
617    match x {
618        Some(x) => println!("{}", x),
619        None => println!("none"),
620    }
621}
622"#,
623        );
624    }
625
626    #[test]
627    fn special_case_inverted_option() {
628        check_assist(
629            replace_if_let_with_match,
630            r#"
631//- minicore: option
632fn foo(x: Option<i32>) {
633    $0if let None = x {
634        println!("none")
635    } else {
636        println!("some")
637    }
638}
639"#,
640            r#"
641fn foo(x: Option<i32>) {
642    match x {
643        None => println!("none"),
644        Some(_) => println!("some"),
645    }
646}
647"#,
648        );
649    }
650
651    #[test]
652    fn special_case_result() {
653        check_assist(
654            replace_if_let_with_match,
655            r#"
656//- minicore: result
657fn foo(x: Result<i32, ()>) {
658    $0if let Ok(x) = x {
659        println!("{}", x)
660    } else {
661        println!("none")
662    }
663}
664"#,
665            r#"
666fn foo(x: Result<i32, ()>) {
667    match x {
668        Ok(x) => println!("{}", x),
669        Err(_) => println!("none"),
670    }
671}
672"#,
673        );
674    }
675
676    #[test]
677    fn special_case_inverted_result() {
678        check_assist(
679            replace_if_let_with_match,
680            r#"
681//- minicore: result
682fn foo(x: Result<i32, ()>) {
683    $0if let Err(x) = x {
684        println!("{}", x)
685    } else {
686        println!("ok")
687    }
688}
689"#,
690            r#"
691fn foo(x: Result<i32, ()>) {
692    match x {
693        Err(x) => println!("{}", x),
694        Ok(_) => println!("ok"),
695    }
696}
697"#,
698        );
699    }
700
701    #[test]
702    fn nested_indent() {
703        check_assist(
704            replace_if_let_with_match,
705            r#"
706fn main() {
707    if true {
708        $0if let Ok(rel_path) = path.strip_prefix(root_path) {
709            let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
710            Some((*id, rel_path))
711        } else {
712            None
713        }
714    }
715}
716"#,
717            r#"
718fn main() {
719    if true {
720        match path.strip_prefix(root_path) {
721            Ok(rel_path) => {
722                let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
723                Some((*id, rel_path))
724            }
725            _ => None,
726        }
727    }
728}
729"#,
730        )
731    }
732
733    #[test]
734    fn test_if_let_with_match_nested_tuple_struct() {
735        check_assist(
736            replace_if_let_with_match,
737            r#"
738//- minicore: result, option
739fn foo(x: Result<i32, ()>) {
740    let bar: Result<_, ()> = Ok(Some(1));
741    $0if let Ok(Some(_)) = bar {
742        ()
743    } else {
744        ()
745    }
746}
747"#,
748            r#"
749fn foo(x: Result<i32, ()>) {
750    let bar: Result<_, ()> = Ok(Some(1));
751    match bar {
752        Ok(Some(_)) => (),
753        _ => (),
754    }
755}
756"#,
757        );
758
759        check_assist(
760            replace_if_let_with_match,
761            r#"
762//- minicore: result
763struct MyStruct(i32, i32);
764fn foo(x: Result<MyStruct, ()>) {
765    let bar: Result<MyStruct, ()> = Ok(MyStruct(1, 2));
766    $0if let Ok(MyStruct(a, b)) = bar {
767        ()
768    } else {
769        ()
770    }
771}
772"#,
773            r#"
774struct MyStruct(i32, i32);
775fn foo(x: Result<MyStruct, ()>) {
776    let bar: Result<MyStruct, ()> = Ok(MyStruct(1, 2));
777    match bar {
778        Ok(MyStruct(a, b)) => (),
779        Err(_) => (),
780    }
781}
782"#,
783        );
784    }
785
786    #[test]
787    fn test_if_let_with_match_nested_slice() {
788        check_assist(
789            replace_if_let_with_match,
790            r#"
791//- minicore: result
792fn foo(x: Result<&[i32], ()>) {
793    let foo: Result<&[_], ()> = Ok(&[0, 1, 2]);
794    $0if let Ok([]) = foo {
795        ()
796    } else {
797        ()
798    }
799}
800        "#,
801            r#"
802fn foo(x: Result<&[i32], ()>) {
803    let foo: Result<&[_], ()> = Ok(&[0, 1, 2]);
804    match foo {
805        Ok([]) => (),
806        _ => (),
807    }
808}
809        "#,
810        );
811
812        check_assist(
813            replace_if_let_with_match,
814            r#"
815//- minicore: result
816fn foo(x: Result<[&'static str; 2], ()>) {
817    let foobar: Result<_, ()> = Ok(["foo", "bar"]);
818    $0if let Ok([_, "bar"]) = foobar {
819        ()
820    } else {
821        ()
822    }
823}
824"#,
825            r#"
826fn foo(x: Result<[&'static str; 2], ()>) {
827    let foobar: Result<_, ()> = Ok(["foo", "bar"]);
828    match foobar {
829        Ok([_, "bar"]) => (),
830        _ => (),
831    }
832}
833"#,
834        );
835
836        check_assist(
837            replace_if_let_with_match,
838            r#"
839//- minicore: result
840fn foo(x: Result<[&'static str; 2], ()>) {
841    let foobar: Result<_, ()> = Ok(["foo", "bar"]);
842    $0if let Ok([..]) = foobar {
843        ()
844    } else {
845        ()
846    }
847}
848"#,
849            r#"
850fn foo(x: Result<[&'static str; 2], ()>) {
851    let foobar: Result<_, ()> = Ok(["foo", "bar"]);
852    match foobar {
853        Ok([..]) => (),
854        Err(_) => (),
855    }
856}
857"#,
858        );
859
860        check_assist(
861            replace_if_let_with_match,
862            r#"
863//- minicore: result
864fn foo(x: Result<&[&'static str], ()>) {
865    let foobar: Result<&[&'static str], ()> = Ok(&["foo", "bar"]);
866    $0if let Ok([a, ..]) = foobar {
867        ()
868    } else {
869        ()
870    }
871}
872"#,
873            r#"
874fn foo(x: Result<&[&'static str], ()>) {
875    let foobar: Result<&[&'static str], ()> = Ok(&["foo", "bar"]);
876    match foobar {
877        Ok([a, ..]) => (),
878        _ => (),
879    }
880}
881"#,
882        );
883
884        check_assist(
885            replace_if_let_with_match,
886            r#"
887//- minicore: result
888fn foo(x: Result<&[&'static str], ()>) {
889    let foobar: Result<&[&'static str], ()> = Ok(&["foo", "bar"]);
890    $0if let Ok([a, .., b, c]) = foobar {
891        ()
892    } else {
893        ()
894    }
895}
896"#,
897            r#"
898fn foo(x: Result<&[&'static str], ()>) {
899    let foobar: Result<&[&'static str], ()> = Ok(&["foo", "bar"]);
900    match foobar {
901        Ok([a, .., b, c]) => (),
902        _ => (),
903    }
904}
905"#,
906        );
907
908        check_assist(
909            replace_if_let_with_match,
910            r#"
911//- minicore: result
912fn foo(x: Result<Option<[&'static str; 2]>, ()>) {
913    let foobar: Result<_, ()> = Ok(Some(["foo", "bar"]));
914    $0if let Ok(Some([_, "bar"])) = foobar {
915        ()
916    } else {
917        ()
918    }
919}
920"#,
921            r#"
922fn foo(x: Result<Option<[&'static str; 2]>, ()>) {
923    let foobar: Result<_, ()> = Ok(Some(["foo", "bar"]));
924    match foobar {
925        Ok(Some([_, "bar"])) => (),
926        _ => (),
927    }
928}
929"#,
930        );
931    }
932
933    #[test]
934    fn test_if_let_with_match_nested_literal() {
935        check_assist(
936            replace_if_let_with_match,
937            r#"
938//- minicore: result
939fn foo(x: Result<&'static str, ()>) {
940    let bar: Result<&_, ()> = Ok("bar");
941    $0if let Ok("foo") = bar {
942        ()
943    } else {
944        ()
945    }
946}
947"#,
948            r#"
949fn foo(x: Result<&'static str, ()>) {
950    let bar: Result<&_, ()> = Ok("bar");
951    match bar {
952        Ok("foo") => (),
953        _ => (),
954    }
955}
956"#,
957        );
958    }
959
960    #[test]
961    fn test_if_let_with_match_nested_tuple() {
962        check_assist(
963            replace_if_let_with_match,
964            r#"
965//- minicore: result
966fn foo(x: Result<(i32, i32, i32), ()>) {
967    let bar: Result<(i32, i32, i32), ()> = Ok((1, 2, 3));
968    $0if let Ok((1, second, third)) = bar {
969        ()
970    } else {
971        ()
972    }
973}
974"#,
975            r#"
976fn foo(x: Result<(i32, i32, i32), ()>) {
977    let bar: Result<(i32, i32, i32), ()> = Ok((1, 2, 3));
978    match bar {
979        Ok((1, second, third)) => (),
980        _ => (),
981    }
982}
983"#,
984        );
985
986        check_assist(
987            replace_if_let_with_match,
988            r#"
989//- minicore: result
990fn foo(x: Result<(i32, i32, i32), ()>) {
991    let bar: Result<(i32, i32, i32), ()> = Ok((1, 2, 3));
992    $0if let Ok((first, second, third)) = bar {
993        ()
994    } else {
995        ()
996    }
997}
998"#,
999            r#"
1000fn foo(x: Result<(i32, i32, i32), ()>) {
1001    let bar: Result<(i32, i32, i32), ()> = Ok((1, 2, 3));
1002    match bar {
1003        Ok((first, second, third)) => (),
1004        Err(_) => (),
1005    }
1006}
1007"#,
1008        );
1009    }
1010
1011    #[test]
1012    fn test_if_let_with_match_nested_or() {
1013        check_assist(
1014            replace_if_let_with_match,
1015            r#"
1016//- minicore: result
1017fn foo(x: Result<i32, ()>) {
1018    let bar: Result<i32, ()> = Ok(1);
1019    $0if let Ok(1 | 2) = bar {
1020        ()
1021    } else {
1022        ()
1023    }
1024}
1025"#,
1026            r#"
1027fn foo(x: Result<i32, ()>) {
1028    let bar: Result<i32, ()> = Ok(1);
1029    match bar {
1030        Ok(1 | 2) => (),
1031        _ => (),
1032    }
1033}
1034"#,
1035        );
1036
1037        check_assist(
1038            replace_if_let_with_match,
1039            r#"
1040//- minicore: result
1041fn foo(x: Result<(i32, i32), ()>) {
1042    let bar: Result<(i32, i32), ()> = Ok((1, 2));
1043    $0if let Ok((b, a) | (a, b)) = bar {
1044        ()
1045    } else {
1046        ()
1047    }
1048}
1049"#,
1050            r#"
1051fn foo(x: Result<(i32, i32), ()>) {
1052    let bar: Result<(i32, i32), ()> = Ok((1, 2));
1053    match bar {
1054        Ok((b, a) | (a, b)) => (),
1055        Err(_) => (),
1056    }
1057}
1058"#,
1059        );
1060
1061        check_assist(
1062            replace_if_let_with_match,
1063            r#"
1064//- minicore: result
1065fn foo(x: Result<(i32, i32), ()>) {
1066    let bar: Result<(i32, i32), ()> = Ok((1, 2));
1067    $0if let Ok((1, a) | (a, 2)) = bar {
1068        ()
1069    } else {
1070        ()
1071    }
1072}
1073"#,
1074            r#"
1075fn foo(x: Result<(i32, i32), ()>) {
1076    let bar: Result<(i32, i32), ()> = Ok((1, 2));
1077    match bar {
1078        Ok((1, a) | (a, 2)) => (),
1079        _ => (),
1080    }
1081}
1082"#,
1083        );
1084    }
1085
1086    #[test]
1087    fn test_if_let_with_match_nested_range() {
1088        check_assist(
1089            replace_if_let_with_match,
1090            r#"
1091//- minicore: result
1092fn foo(x: Result<i32, ()>) {
1093    let bar: Result<i32, ()> = Ok(1);
1094    $0if let Ok(1..2) = bar {
1095        ()
1096    } else {
1097        ()
1098    }
1099}
1100"#,
1101            r#"
1102fn foo(x: Result<i32, ()>) {
1103    let bar: Result<i32, ()> = Ok(1);
1104    match bar {
1105        Ok(1..2) => (),
1106        _ => (),
1107    }
1108}
1109"#,
1110        );
1111    }
1112
1113    #[test]
1114    fn test_if_let_with_match_nested_paren() {
1115        check_assist(
1116            replace_if_let_with_match,
1117            r#"
1118//- minicore: result
1119fn foo(x: Result<(i32, i32), ()>) {
1120    let bar: Result<(i32, i32), ()> = Ok((1, 1));
1121    $0if let Ok(((1, 2))) = bar {
1122        ()
1123    } else {
1124        ()
1125    }
1126}
1127"#,
1128            r#"
1129fn foo(x: Result<(i32, i32), ()>) {
1130    let bar: Result<(i32, i32), ()> = Ok((1, 1));
1131    match bar {
1132        Ok(((1, 2))) => (),
1133        _ => (),
1134    }
1135}
1136"#,
1137        );
1138
1139        check_assist(
1140            replace_if_let_with_match,
1141            r#"
1142//- minicore: result
1143fn foo(x: Result<(i32, i32), ()>) {
1144    let bar: Result<(i32, i32), ()> = Ok((1, 1));
1145    $0if let Ok(((a, b))) = bar {
1146        ()
1147    } else {
1148        ()
1149    }
1150}
1151"#,
1152            r#"
1153fn foo(x: Result<(i32, i32), ()>) {
1154    let bar: Result<(i32, i32), ()> = Ok((1, 1));
1155    match bar {
1156        Ok(((a, b))) => (),
1157        Err(_) => (),
1158    }
1159}
1160"#,
1161        );
1162    }
1163
1164    #[test]
1165    fn test_if_let_with_match_nested_macro() {
1166        check_assist(
1167            replace_if_let_with_match,
1168            r#"
1169//- minicore: result
1170fn foo(x: Result<i32, ()>) {
1171    macro_rules! is_42 {
1172        () => {
1173            42
1174        };
1175    }
1176
1177    let bar: Result<i32, ()> = Ok(1);
1178    $0if let Ok(is_42!()) = bar {
1179        ()
1180    } else {
1181        ()
1182    }
1183}
1184"#,
1185            r#"
1186fn foo(x: Result<i32, ()>) {
1187    macro_rules! is_42 {
1188        () => {
1189            42
1190        };
1191    }
1192
1193    let bar: Result<i32, ()> = Ok(1);
1194    match bar {
1195        Ok(is_42!()) => (),
1196        _ => (),
1197    }
1198}
1199"#,
1200        );
1201    }
1202
1203    #[test]
1204    fn test_if_let_with_match_nested_path() {
1205        check_assist(
1206            replace_if_let_with_match,
1207            r#"
1208//- minicore: result
1209enum MyEnum {
1210    Foo,
1211    Bar,
1212}
1213
1214fn foo(x: Result<MyEnum, ()>) {
1215    let bar: Result<MyEnum, ()> = Ok(MyEnum::Foo);
1216    $0if let Ok(MyEnum::Foo) = bar {
1217        ()
1218    } else {
1219        ()
1220    }
1221}
1222"#,
1223            r#"
1224enum MyEnum {
1225    Foo,
1226    Bar,
1227}
1228
1229fn foo(x: Result<MyEnum, ()>) {
1230    let bar: Result<MyEnum, ()> = Ok(MyEnum::Foo);
1231    match bar {
1232        Ok(MyEnum::Foo) => (),
1233        _ => (),
1234    }
1235}
1236"#,
1237        );
1238    }
1239
1240    #[test]
1241    fn test_if_let_with_match_nested_record() {
1242        check_assist(
1243            replace_if_let_with_match,
1244            r#"
1245//- minicore: result
1246struct MyStruct {
1247    foo: i32,
1248    bar: i32,
1249}
1250
1251fn foo(x: Result<MyStruct, ()>) {
1252    let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
1253    $0if let Ok(MyStruct { foo, bar }) = bar {
1254        ()
1255    } else {
1256        ()
1257    }
1258}
1259"#,
1260            r#"
1261struct MyStruct {
1262    foo: i32,
1263    bar: i32,
1264}
1265
1266fn foo(x: Result<MyStruct, ()>) {
1267    let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
1268    match bar {
1269        Ok(MyStruct { foo, bar }) => (),
1270        Err(_) => (),
1271    }
1272}
1273"#,
1274        );
1275
1276        check_assist(
1277            replace_if_let_with_match,
1278            r#"
1279//- minicore: result
1280struct MyStruct {
1281    foo: i32,
1282    bar: i32,
1283}
1284
1285fn foo(x: Result<MyStruct, ()>) {
1286    let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
1287    $0if let Ok(MyStruct { foo, bar: 12 }) = bar {
1288        ()
1289    } else {
1290        ()
1291    }
1292}
1293"#,
1294            r#"
1295struct MyStruct {
1296    foo: i32,
1297    bar: i32,
1298}
1299
1300fn foo(x: Result<MyStruct, ()>) {
1301    let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
1302    match bar {
1303        Ok(MyStruct { foo, bar: 12 }) => (),
1304        _ => (),
1305    }
1306}
1307"#,
1308        );
1309
1310        check_assist(
1311            replace_if_let_with_match,
1312            r#"
1313//- minicore: result
1314struct MyStruct {
1315    foo: i32,
1316    bar: i32,
1317}
1318
1319fn foo(x: Result<MyStruct, ()>) {
1320    let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
1321    $0if let Ok(MyStruct { foo, .. }) = bar {
1322        ()
1323    } else {
1324        ()
1325    }
1326}
1327"#,
1328            r#"
1329struct MyStruct {
1330    foo: i32,
1331    bar: i32,
1332}
1333
1334fn foo(x: Result<MyStruct, ()>) {
1335    let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
1336    match bar {
1337        Ok(MyStruct { foo, .. }) => (),
1338        Err(_) => (),
1339    }
1340}
1341"#,
1342        );
1343
1344        check_assist(
1345            replace_if_let_with_match,
1346            r#"
1347//- minicore: result
1348enum MyEnum {
1349    Foo(i32, i32),
1350    Bar { a: i32, b: i32 },
1351}
1352
1353fn foo(x: Result<MyEnum, ()>) {
1354    let bar: Result<MyEnum, ()> = Ok(MyEnum::Foo(1, 2));
1355    $0if let Ok(MyEnum::Bar { a, b }) = bar {
1356        ()
1357    } else {
1358        ()
1359    }
1360}
1361"#,
1362            r#"
1363enum MyEnum {
1364    Foo(i32, i32),
1365    Bar { a: i32, b: i32 },
1366}
1367
1368fn foo(x: Result<MyEnum, ()>) {
1369    let bar: Result<MyEnum, ()> = Ok(MyEnum::Foo(1, 2));
1370    match bar {
1371        Ok(MyEnum::Bar { a, b }) => (),
1372        _ => (),
1373    }
1374}
1375"#,
1376        );
1377    }
1378
1379    #[test]
1380    fn test_if_let_with_match_nested_ident() {
1381        check_assist(
1382            replace_if_let_with_match,
1383            r#"
1384//- minicore: result
1385fn foo(x: Result<i32, ()>) {
1386    let bar: Result<i32, ()> = Ok(1);
1387    $0if let Ok(a @ 1..2) = bar {
1388        ()
1389    } else {
1390        ()
1391    }
1392}
1393"#,
1394            r#"
1395fn foo(x: Result<i32, ()>) {
1396    let bar: Result<i32, ()> = Ok(1);
1397    match bar {
1398        Ok(a @ 1..2) => (),
1399        _ => (),
1400    }
1401}
1402"#,
1403        );
1404
1405        check_assist(
1406            replace_if_let_with_match,
1407            r#"
1408//- minicore: result
1409fn foo(x: Result<i32, ()>) {
1410    let bar: Result<i32, ()> = Ok(1);
1411    $0if let Ok(a) = bar {
1412        ()
1413    } else {
1414        ()
1415    }
1416}
1417"#,
1418            r#"
1419fn foo(x: Result<i32, ()>) {
1420    let bar: Result<i32, ()> = Ok(1);
1421    match bar {
1422        Ok(a) => (),
1423        Err(_) => (),
1424    }
1425}
1426"#,
1427        );
1428
1429        check_assist(
1430            replace_if_let_with_match,
1431            r#"
1432//- minicore: result
1433fn foo(x: Result<i32, ()>) {
1434    let bar: Result<i32, ()> = Ok(1);
1435    $0if let Ok(a @ b @ c @ d) = bar {
1436        ()
1437    } else {
1438        ()
1439    }
1440}
1441"#,
1442            r#"
1443fn foo(x: Result<i32, ()>) {
1444    let bar: Result<i32, ()> = Ok(1);
1445    match bar {
1446        Ok(a @ b @ c @ d) => (),
1447        Err(_) => (),
1448    }
1449}
1450"#,
1451        );
1452    }
1453
1454    #[test]
1455    fn test_replace_match_with_if_let_unwraps_simple_expressions() {
1456        check_assist(
1457            replace_match_with_if_let,
1458            r#"
1459impl VariantData {
1460    pub fn is_struct(&self) -> bool {
1461        $0match *self {
1462            VariantData::Struct(..) => true,
1463            _ => false,
1464        }
1465    }
1466}           "#,
1467            r#"
1468impl VariantData {
1469    pub fn is_struct(&self) -> bool {
1470        if let VariantData::Struct(..) = *self {
1471            true
1472        } else {
1473            false
1474        }
1475    }
1476}           "#,
1477        )
1478    }
1479
1480    #[test]
1481    fn test_replace_match_with_if_let_doesnt_unwrap_multiline_expressions() {
1482        check_assist(
1483            replace_match_with_if_let,
1484            r#"
1485fn foo() {
1486    $0match a {
1487        VariantData::Struct(..) => {
1488            bar(
1489                123
1490            )
1491        }
1492        _ => false,
1493    }
1494}           "#,
1495            r#"
1496fn foo() {
1497    if let VariantData::Struct(..) = a {
1498        bar(
1499            123
1500        )
1501    } else {
1502        false
1503    }
1504}           "#,
1505        )
1506    }
1507
1508    #[test]
1509    fn replace_match_with_if_let_target() {
1510        check_assist_target(
1511            replace_match_with_if_let,
1512            r#"
1513impl VariantData {
1514    pub fn is_struct(&self) -> bool {
1515        $0match *self {
1516            VariantData::Struct(..) => true,
1517            _ => false,
1518        }
1519    }
1520}           "#,
1521            r#"match *self {
1522            VariantData::Struct(..) => true,
1523            _ => false,
1524        }"#,
1525        );
1526    }
1527
1528    #[test]
1529    fn special_case_option_match_to_if_let() {
1530        check_assist(
1531            replace_match_with_if_let,
1532            r#"
1533//- minicore: option
1534fn foo(x: Option<i32>) {
1535    $0match x {
1536        Some(x) => println!("{}", x),
1537        None => println!("none"),
1538    }
1539}
1540"#,
1541            r#"
1542fn foo(x: Option<i32>) {
1543    if let Some(x) = x {
1544        println!("{}", x)
1545    } else {
1546        println!("none")
1547    }
1548}
1549"#,
1550        );
1551    }
1552
1553    #[test]
1554    fn special_case_result_match_to_if_let() {
1555        check_assist(
1556            replace_match_with_if_let,
1557            r#"
1558//- minicore: result
1559fn foo(x: Result<i32, ()>) {
1560    $0match x {
1561        Ok(x) => println!("{}", x),
1562        Err(_) => println!("none"),
1563    }
1564}
1565"#,
1566            r#"
1567fn foo(x: Result<i32, ()>) {
1568    if let Ok(x) = x {
1569        println!("{}", x)
1570    } else {
1571        println!("none")
1572    }
1573}
1574"#,
1575        );
1576    }
1577
1578    #[test]
1579    fn nested_indent_match_to_if_let() {
1580        check_assist(
1581            replace_match_with_if_let,
1582            r#"
1583fn main() {
1584    if true {
1585        $0match path.strip_prefix(root_path) {
1586            Ok(rel_path) => {
1587                let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
1588                Some((*id, rel_path))
1589            }
1590            _ => None,
1591        }
1592    }
1593}
1594"#,
1595            r#"
1596fn main() {
1597    if true {
1598        if let Ok(rel_path) = path.strip_prefix(root_path) {
1599            let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
1600            Some((*id, rel_path))
1601        } else {
1602            None
1603        }
1604    }
1605}
1606"#,
1607        )
1608    }
1609
1610    #[test]
1611    fn replace_match_with_if_let_empty_wildcard_expr() {
1612        check_assist(
1613            replace_match_with_if_let,
1614            r#"
1615fn main() {
1616    $0match path.strip_prefix(root_path) {
1617        Ok(rel_path) => println!("{}", rel_path),
1618        _ => (),
1619    }
1620}
1621"#,
1622            r#"
1623fn main() {
1624    if let Ok(rel_path) = path.strip_prefix(root_path) {
1625        println!("{}", rel_path)
1626    }
1627}
1628"#,
1629        )
1630    }
1631
1632    #[test]
1633    fn replace_match_with_if_let_number_body() {
1634        check_assist(
1635            replace_match_with_if_let,
1636            r#"
1637fn main() {
1638    $0match Ok(()) {
1639        Ok(()) => {},
1640        Err(_) => 0,
1641    }
1642}
1643"#,
1644            r#"
1645fn main() {
1646    if let Err(_) = Ok(()) {
1647        0
1648    }
1649}
1650"#,
1651        )
1652    }
1653
1654    #[test]
1655    fn replace_match_with_if_let_exhaustive() {
1656        check_assist(
1657            replace_match_with_if_let,
1658            r#"
1659fn print_source(def_source: ModuleSource) {
1660    match def_so$0urce {
1661        ModuleSource::SourceFile(..) => { println!("source file"); }
1662        ModuleSource::Module(..) => { println!("module"); }
1663    }
1664}
1665"#,
1666            r#"
1667fn print_source(def_source: ModuleSource) {
1668    if let ModuleSource::SourceFile(..) = def_source { println!("source file"); } else { println!("module"); }
1669}
1670"#,
1671        )
1672    }
1673
1674    #[test]
1675    fn replace_match_with_if_let_prefer_name_bind() {
1676        check_assist(
1677            replace_match_with_if_let,
1678            r#"
1679fn foo() {
1680    match $0Foo(0) {
1681        Foo(_) => (),
1682        Bar(bar) => println!("bar {}", bar),
1683    }
1684}
1685"#,
1686            r#"
1687fn foo() {
1688    if let Bar(bar) = Foo(0) {
1689        println!("bar {}", bar)
1690    }
1691}
1692"#,
1693        );
1694        check_assist(
1695            replace_match_with_if_let,
1696            r#"
1697fn foo() {
1698    match $0Foo(0) {
1699        Bar(bar) => println!("bar {}", bar),
1700        Foo(_) => (),
1701    }
1702}
1703"#,
1704            r#"
1705fn foo() {
1706    if let Bar(bar) = Foo(0) {
1707        println!("bar {}", bar)
1708    }
1709}
1710"#,
1711        );
1712    }
1713
1714    #[test]
1715    fn replace_match_with_if_let_prefer_nonempty_body() {
1716        check_assist(
1717            replace_match_with_if_let,
1718            r#"
1719fn foo() {
1720    match $0Ok(0) {
1721        Ok(value) => {},
1722        Err(err) => eprintln!("{}", err),
1723    }
1724}
1725"#,
1726            r#"
1727fn foo() {
1728    if let Err(err) = Ok(0) {
1729        eprintln!("{}", err)
1730    }
1731}
1732"#,
1733        );
1734        check_assist(
1735            replace_match_with_if_let,
1736            r#"
1737fn foo() {
1738    match $0Ok(0) {
1739        Err(err) => eprintln!("{}", err),
1740        Ok(value) => {},
1741    }
1742}
1743"#,
1744            r#"
1745fn foo() {
1746    if let Err(err) = Ok(0) {
1747        eprintln!("{}", err)
1748    }
1749}
1750"#,
1751        );
1752    }
1753
1754    #[test]
1755    fn replace_match_with_if_let_rejects_double_name_bindings() {
1756        check_assist_not_applicable(
1757            replace_match_with_if_let,
1758            r#"
1759fn foo() {
1760    match $0Foo(0) {
1761        Foo(foo) => println!("bar {}", foo),
1762        Bar(bar) => println!("bar {}", bar),
1763    }
1764}
1765"#,
1766        );
1767    }
1768
1769    #[test]
1770    fn test_replace_match_with_if_let_keeps_unsafe_block() {
1771        check_assist(
1772            replace_match_with_if_let,
1773            r#"
1774impl VariantData {
1775    pub fn is_struct(&self) -> bool {
1776        $0match *self {
1777            VariantData::Struct(..) => true,
1778            _ => unsafe { unreachable_unchecked() },
1779        }
1780    }
1781}           "#,
1782            r#"
1783impl VariantData {
1784    pub fn is_struct(&self) -> bool {
1785        if let VariantData::Struct(..) = *self {
1786            true
1787        } else {
1788            unsafe { unreachable_unchecked() }
1789        }
1790    }
1791}           "#,
1792        )
1793    }
1794
1795    #[test]
1796    fn test_replace_match_with_if_let_forces_else() {
1797        check_assist(
1798            replace_match_with_if_let,
1799            r#"
1800fn main() {
1801    match$0 0 {
1802        0 => (),
1803        _ => code(),
1804    }
1805}
1806"#,
1807            r#"
1808fn main() {
1809    if let 0 = 0 {
1810        ()
1811    } else {
1812        code()
1813    }
1814}
1815"#,
1816        )
1817    }
1818
1819    #[test]
1820    fn test_replace_match_with_if_bool() {
1821        check_assist(
1822            replace_match_with_if_let,
1823            r#"
1824fn main() {
1825    match$0 b {
1826        true => (),
1827        _ => code(),
1828    }
1829}
1830"#,
1831            r#"
1832fn main() {
1833    if b {
1834        ()
1835    } else {
1836        code()
1837    }
1838}
1839"#,
1840        );
1841        check_assist(
1842            replace_match_with_if_let,
1843            r#"
1844fn main() {
1845    match$0 b {
1846        false => code(),
1847        true => (),
1848    }
1849}
1850"#,
1851            r#"
1852fn main() {
1853    if !b {
1854        code()
1855    }
1856}
1857"#,
1858        );
1859        check_assist(
1860            replace_match_with_if_let,
1861            r#"
1862fn main() {
1863    match$0 b {
1864        false => (),
1865        true => code(),
1866    }
1867}
1868"#,
1869            r#"
1870fn main() {
1871    if b {
1872        code()
1873    }
1874}
1875"#,
1876        )
1877    }
1878
1879    #[test]
1880    fn test_replace_match_with_if_let_chain() {
1881        check_assist(
1882            replace_match_with_if_let,
1883            r#"
1884fn main() {
1885    match$0 Some(0) {
1886        Some(n) if n % 2 == 0 && n != 6 => (),
1887        _ => code(),
1888    }
1889}
1890"#,
1891            r#"
1892fn main() {
1893    if let Some(n) = Some(0) && n % 2 == 0 && n != 6 {
1894        ()
1895    } else {
1896        code()
1897    }
1898}
1899"#,
1900        )
1901    }
1902
1903    #[test]
1904    fn test_replace_match_with_if_let_not_applicable_pat2_is_ident_pat() {
1905        check_assist_not_applicable(
1906            replace_match_with_if_let,
1907            r"
1908fn test(a: i32) {
1909    match$0 a {
1910        1 => code(),
1911        other => code(other),
1912    }
1913}
1914",
1915        )
1916    }
1917}