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