replace_if_let_with_match: don't assume sad pattern

This commit is contained in:
Dániel Buga 2021-01-22 23:29:51 +01:00
parent f301da3c3d
commit 24f0cd8293
2 changed files with 103 additions and 2 deletions

View file

@ -5,7 +5,7 @@ use syntax::{
ast::{
self,
edit::{AstNodeEdit, IndentLevel},
make,
make, Pat,
},
AstNode,
};
@ -66,7 +66,13 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext)
.sema
.type_of_pat(&pat)
.and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty))
.map(|it| it.sad_pattern())
.map(|it| {
if does_pat_match_variant(&pat, &it.sad_pattern()) {
it.happy_pattern()
} else {
it.sad_pattern()
}
})
.unwrap_or_else(|| make::wildcard_pat().into());
let else_expr = unwrap_trivial_block(else_block);
make::match_arm(vec![pattern], else_expr)
@ -81,6 +87,26 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext)
)
}
fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool {
let first_node_text = |pat: &Pat| pat.syntax().first_child().map(|node| node.text());
let pat_head = match pat {
Pat::IdentPat(bind_pat) => {
if let Some(p) = bind_pat.pat() {
first_node_text(&p)
} else {
return pat.syntax().text() == var.syntax().text();
}
}
pat => first_node_text(pat),
};
let var_head = first_node_text(var);
println!("{:?} {:?}", pat_head, var_head);
pat_head == var_head
}
// Assist: replace_match_with_if_let
//
// Replaces a binary `match` with a wildcard pattern and no guards with an `if let` expression.
@ -278,6 +304,36 @@ fn foo(x: Option<i32>) {
);
}
#[test]
fn special_case_inverted_option() {
check_assist(
replace_if_let_with_match,
r#"
enum Option<T> { Some(T), None }
use Option::*;
fn foo(x: Option<i32>) {
$0if let None = x {
println!("none")
} else {
println!("some")
}
}
"#,
r#"
enum Option<T> { Some(T), None }
use Option::*;
fn foo(x: Option<i32>) {
match x {
None => println!("none"),
Some(_) => println!("some"),
}
}
"#,
);
}
#[test]
fn special_case_result() {
check_assist(
@ -308,6 +364,36 @@ fn foo(x: Result<i32, ()>) {
);
}
#[test]
fn special_case_inverted_result() {
check_assist(
replace_if_let_with_match,
r#"
enum Result<T, E> { Ok(T), Err(E) }
use Result::*;
fn foo(x: Result<i32, ()>) {
$0if let Err(x) = x {
println!("{}", x)
} else {
println!("ok")
}
}
"#,
r#"
enum Result<T, E> { Ok(T), Err(E) }
use Result::*;
fn foo(x: Result<i32, ()>) {
match x {
Err(x) => println!("{}", x),
Ok(_) => println!("ok"),
}
}
"#,
);
}
#[test]
fn nested_indent() {
check_assist(

View file

@ -49,6 +49,21 @@ impl TryEnum {
}
}
pub fn happy_pattern(self) -> ast::Pat {
match self {
TryEnum::Result => make::tuple_struct_pat(
make::path_unqualified(make::path_segment(make::name_ref("Ok"))),
iter::once(make::wildcard_pat().into()),
)
.into(),
TryEnum::Option => make::tuple_struct_pat(
make::path_unqualified(make::path_segment(make::name_ref("Some"))),
iter::once(make::wildcard_pat().into()),
)
.into(),
}
}
fn type_name(self) -> &'static str {
match self {
TryEnum::Result => "Result",