diff options
-rw-r--r-- | crates/assists/src/handlers/replace_if_let_with_match.rs | 90 | ||||
-rw-r--r-- | crates/ide_db/src/ty_filter.rs | 15 |
2 files changed, 103 insertions, 2 deletions
diff --git a/crates/assists/src/handlers/replace_if_let_with_match.rs b/crates/assists/src/handlers/replace_if_let_with_match.rs index aee3397ab..abebd4b6a 100644 --- a/crates/assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/assists/src/handlers/replace_if_let_with_match.rs | |||
@@ -5,7 +5,7 @@ use syntax::{ | |||
5 | ast::{ | 5 | ast::{ |
6 | self, | 6 | self, |
7 | edit::{AstNodeEdit, IndentLevel}, | 7 | edit::{AstNodeEdit, IndentLevel}, |
8 | make, | 8 | make, Pat, |
9 | }, | 9 | }, |
10 | AstNode, | 10 | AstNode, |
11 | }; | 11 | }; |
@@ -66,7 +66,13 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
66 | .sema | 66 | .sema |
67 | .type_of_pat(&pat) | 67 | .type_of_pat(&pat) |
68 | .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty)) | 68 | .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty)) |
69 | .map(|it| it.sad_pattern()) | 69 | .map(|it| { |
70 | if does_pat_match_variant(&pat, &it.sad_pattern()) { | ||
71 | it.happy_pattern() | ||
72 | } else { | ||
73 | it.sad_pattern() | ||
74 | } | ||
75 | }) | ||
70 | .unwrap_or_else(|| make::wildcard_pat().into()); | 76 | .unwrap_or_else(|| make::wildcard_pat().into()); |
71 | let else_expr = unwrap_trivial_block(else_block); | 77 | let else_expr = unwrap_trivial_block(else_block); |
72 | make::match_arm(vec![pattern], else_expr) | 78 | make::match_arm(vec![pattern], else_expr) |
@@ -81,6 +87,26 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
81 | ) | 87 | ) |
82 | } | 88 | } |
83 | 89 | ||
90 | fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool { | ||
91 | let first_node_text = |pat: &Pat| pat.syntax().first_child().map(|node| node.text()); | ||
92 | |||
93 | let pat_head = match pat { | ||
94 | Pat::IdentPat(bind_pat) => { | ||
95 | if let Some(p) = bind_pat.pat() { | ||
96 | first_node_text(&p) | ||
97 | } else { | ||
98 | return pat.syntax().text() == var.syntax().text(); | ||
99 | } | ||
100 | } | ||
101 | pat => first_node_text(pat), | ||
102 | }; | ||
103 | |||
104 | let var_head = first_node_text(var); | ||
105 | println!("{:?} {:?}", pat_head, var_head); | ||
106 | |||
107 | pat_head == var_head | ||
108 | } | ||
109 | |||
84 | // Assist: replace_match_with_if_let | 110 | // Assist: replace_match_with_if_let |
85 | // | 111 | // |
86 | // Replaces a binary `match` with a wildcard pattern and no guards with an `if let` expression. | 112 | // Replaces a binary `match` with a wildcard pattern and no guards with an `if let` expression. |
@@ -279,6 +305,36 @@ fn foo(x: Option<i32>) { | |||
279 | } | 305 | } |
280 | 306 | ||
281 | #[test] | 307 | #[test] |
308 | fn special_case_inverted_option() { | ||
309 | check_assist( | ||
310 | replace_if_let_with_match, | ||
311 | r#" | ||
312 | enum Option<T> { Some(T), None } | ||
313 | use Option::*; | ||
314 | |||
315 | fn foo(x: Option<i32>) { | ||
316 | $0if let None = x { | ||
317 | println!("none") | ||
318 | } else { | ||
319 | println!("some") | ||
320 | } | ||
321 | } | ||
322 | "#, | ||
323 | r#" | ||
324 | enum Option<T> { Some(T), None } | ||
325 | use Option::*; | ||
326 | |||
327 | fn foo(x: Option<i32>) { | ||
328 | match x { | ||
329 | None => println!("none"), | ||
330 | Some(_) => println!("some"), | ||
331 | } | ||
332 | } | ||
333 | "#, | ||
334 | ); | ||
335 | } | ||
336 | |||
337 | #[test] | ||
282 | fn special_case_result() { | 338 | fn special_case_result() { |
283 | check_assist( | 339 | check_assist( |
284 | replace_if_let_with_match, | 340 | replace_if_let_with_match, |
@@ -309,6 +365,36 @@ fn foo(x: Result<i32, ()>) { | |||
309 | } | 365 | } |
310 | 366 | ||
311 | #[test] | 367 | #[test] |
368 | fn special_case_inverted_result() { | ||
369 | check_assist( | ||
370 | replace_if_let_with_match, | ||
371 | r#" | ||
372 | enum Result<T, E> { Ok(T), Err(E) } | ||
373 | use Result::*; | ||
374 | |||
375 | fn foo(x: Result<i32, ()>) { | ||
376 | $0if let Err(x) = x { | ||
377 | println!("{}", x) | ||
378 | } else { | ||
379 | println!("ok") | ||
380 | } | ||
381 | } | ||
382 | "#, | ||
383 | r#" | ||
384 | enum Result<T, E> { Ok(T), Err(E) } | ||
385 | use Result::*; | ||
386 | |||
387 | fn foo(x: Result<i32, ()>) { | ||
388 | match x { | ||
389 | Err(x) => println!("{}", x), | ||
390 | Ok(_) => println!("ok"), | ||
391 | } | ||
392 | } | ||
393 | "#, | ||
394 | ); | ||
395 | } | ||
396 | |||
397 | #[test] | ||
312 | fn nested_indent() { | 398 | fn nested_indent() { |
313 | check_assist( | 399 | check_assist( |
314 | replace_if_let_with_match, | 400 | replace_if_let_with_match, |
diff --git a/crates/ide_db/src/ty_filter.rs b/crates/ide_db/src/ty_filter.rs index 63a945282..f8406851b 100644 --- a/crates/ide_db/src/ty_filter.rs +++ b/crates/ide_db/src/ty_filter.rs | |||
@@ -49,6 +49,21 @@ impl TryEnum { | |||
49 | } | 49 | } |
50 | } | 50 | } |
51 | 51 | ||
52 | pub fn happy_pattern(self) -> ast::Pat { | ||
53 | match self { | ||
54 | TryEnum::Result => make::tuple_struct_pat( | ||
55 | make::path_unqualified(make::path_segment(make::name_ref("Ok"))), | ||
56 | iter::once(make::wildcard_pat().into()), | ||
57 | ) | ||
58 | .into(), | ||
59 | TryEnum::Option => make::tuple_struct_pat( | ||
60 | make::path_unqualified(make::path_segment(make::name_ref("Some"))), | ||
61 | iter::once(make::wildcard_pat().into()), | ||
62 | ) | ||
63 | .into(), | ||
64 | } | ||
65 | } | ||
66 | |||
52 | fn type_name(self) -> &'static str { | 67 | fn type_name(self) -> &'static str { |
53 | match self { | 68 | match self { |
54 | TryEnum::Result => "Result", | 69 | TryEnum::Result => "Result", |