use hir::TypeInfo;
-use std::{iter::successors, collections::HashMap};
+use std::{collections::HashMap, iter::successors};
use syntax::{
algo::neighbor,
- ast::{self, AstNode, Pat, MatchArm, HasName},
+ ast::{self, AstNode, HasName},
Direction,
};
return false;
}
- println!("Checking types");
- return are_same_types(¤t_arm_types, arm, ctx);
+ are_same_types(¤t_arm_types, arm, ctx)
}
_ => false,
})
)
}
-fn contains_placeholder(a: &MatchArm) -> bool {
+fn contains_placeholder(a: &ast::MatchArm) -> bool {
matches!(a.pat(), Some(ast::Pat::WildcardPat(..)))
}
ctx: &AssistContext,
) -> bool {
let arm_types = get_arm_types(&ctx, &arm);
- for other_arm_type_entry in arm_types {
- let current_arm_type = current_arm_types.get_key_value(&other_arm_type_entry.0);
- if current_arm_type.is_none() {
- println!("No corresponding type found for {:?}", {other_arm_type_entry});
- return false;
- }
-
- let unwrapped_current_arm_type = current_arm_type.unwrap().1;
-
- if let (Some(other_arm_type), Some(current_arm_type)) = (other_arm_type_entry.1, unwrapped_current_arm_type) {
- if other_arm_type.original != current_arm_type.original {
- println!("Type {:?} is different from {:?}", &other_arm_type.original, ¤t_arm_type.original);
- return false;
+ for (other_arm_type_name, other_arm_type) in arm_types {
+ match (current_arm_types.get(&other_arm_type_name), other_arm_type) {
+ (Some(Some(current_arm_type)), Some(other_arm_type))
+ if other_arm_type.original == current_arm_type.original =>
+ {
+ ()
}
+ _ => return false,
}
}
- return true;
+ true
}
-fn get_arm_types(context: &AssistContext, arm: &MatchArm) -> HashMap<String, Option<TypeInfo>> {
+fn get_arm_types(
+ context: &AssistContext,
+ arm: &ast::MatchArm,
+) -> HashMap<String, Option<TypeInfo>> {
let mut mapping: HashMap<String, Option<TypeInfo>> = HashMap::new();
-
- fn recurse(pat: &Option<Pat>, map: &mut HashMap<String, Option<TypeInfo>>, ctx: &AssistContext) {
+
+ fn recurse(
+ map: &mut HashMap<String, Option<TypeInfo>>,
+ ctx: &AssistContext,
+ pat: &Option<ast::Pat>,
+ ) {
if let Some(local_pat) = pat {
- println!("{:?}", pat);
match pat {
Some(ast::Pat::TupleStructPat(tuple)) => {
for field in tuple.fields() {
- recurse(&Some(field), map, ctx);
+ recurse(map, ctx, &Some(field));
}
- },
+ }
+ Some(ast::Pat::TuplePat(tuple)) => {
+ for field in tuple.fields() {
+ recurse(map, ctx, &Some(field));
+ }
+ }
Some(ast::Pat::RecordPat(record)) => {
if let Some(field_list) = record.record_pat_field_list() {
for field in field_list.fields() {
- recurse(&field.pat(), map, ctx);
+ recurse(map, ctx, &field.pat());
}
}
- },
+ }
+ Some(ast::Pat::ParenPat(parentheses)) => {
+ recurse(map, ctx, &parentheses.pat());
+ }
+ Some(ast::Pat::SlicePat(slice)) => {
+ for slice_pat in slice.pats() {
+ recurse(map, ctx, &Some(slice_pat));
+ }
+ }
Some(ast::Pat::IdentPat(ident_pat)) => {
if let Some(name) = ident_pat.name() {
- println!("Found name: {:?}", name.text().to_string());
let pat_type = ctx.sema.type_of_pat(local_pat);
map.insert(name.text().to_string(), pat_type);
}
- },
+ }
_ => (),
}
}
}
- recurse(&arm.pat(), &mut mapping, &context);
- return mapping;
+ recurse(&mut mapping, &context, &arm.pat());
+ mapping
}
#[cfg(test)]
fn merge_match_arms_different_type() {
check_assist_not_applicable(
merge_match_arms,
- r#"//- minicore: result
+ r#"
+//- minicore: result
fn func() {
match Result::<f64, f32>::Ok(0f64) {
Ok(x) => $0x.classify(),
fn merge_match_arms_different_type_multiple_fields() {
check_assist_not_applicable(
merge_match_arms,
- r#"//- minicore: result
+ r#"
+//- minicore: result
fn func() {
match Result::<(f64, f64), (f32, f32)>::Ok((0f64, 0f64)) {
Ok(x) => $0x.1.classify(),
fn merge_match_arms_same_type_multiple_fields() {
check_assist(
merge_match_arms,
- r#"//- minicore: result
+ r#"
+//- minicore: result
fn func() {
match Result::<(f64, f64), (f64, f64)>::Ok((0f64, 0f64)) {
Ok(x) => $0x.1.classify(),
fn merge_match_arms_same_type_different_number_of_fields() {
check_assist_not_applicable(
merge_match_arms,
- r#"//- minicore: result
+ r#"
+//- minicore: result
fn func() {
match Result::<(f64, f64, f64), (f64, f64)>::Ok((0f64, 0f64, 0f64)) {
Ok(x) => $0x.1.classify(),
MyEnum::Move { x, y } | MyEnum::Crawl { x, y } => "",
};
}
- "#,
+ "#,
)
}
MyEnum::Crawl { a, b } => "",
};
}
- "#
+ "#,
)
}
};
}
"#,
- r#"
+ r#"
enum Color {
Rgb(i32, i32, i32),
Hsv(i32, i32, i32),
MyEnum::Move { x, .. } | MyEnum::Crawl { x, .. } => "",
};
}
- "#,
+ "#,
)
}
_ => "other"
};
}
- "#,
+ "#,
+ )
+ }
+
+ #[test]
+ fn merge_match_arms_tuple() {
+ check_assist_not_applicable(
+ merge_match_arms,
+ r#"
+fn func() {
+ match (0, "boo") {
+ (x, y) => $0"",
+ (y, x) => "",
+ };
+}
+ "#,
+ )
+ }
+
+ #[test]
+ fn merge_match_arms_parentheses() {
+ check_assist_not_applicable(
+ merge_match_arms,
+ r#"
+fn func(x: i32) {
+ let variable = 2;
+ match x {
+ 1 => $0"",
+ ((((variable)))) => "",
+ _ => "other"
+ };
+}
+ "#,
+ )
+ }
+
+ #[test]
+ fn merge_match_arms_refpat() {
+ check_assist_not_applicable(
+ merge_match_arms,
+ r#"
+fn func() {
+ let name = Some(String::from(""));
+ let n = String::from("");
+ match name {
+ Some(ref n) => $0"",
+ Some(n) => "",
+ _ => "other",
+ };
+}
+ "#,
+ )
+ }
+
+ #[test]
+ fn merge_match_arms_slice() {
+ check_assist_not_applicable(
+ merge_match_arms,
+ r#"
+fn func(binary: &[u8]) {
+ let space = b' ';
+ match binary {
+ [0x7f, b'E', b'L', b'F', ..] => $0"",
+ [space] => "",
+ _ => "other",
+ };
+}
+ "#,
+ )
+ }
+
+ #[test]
+ fn merge_match_arms_slice_identical() {
+ check_assist(
+ merge_match_arms,
+ r#"
+fn func(binary: &[u8]) {
+ let space = b' ';
+ match binary {
+ [space, 5u8] => $0"",
+ [space] => "",
+ _ => "other",
+ };
+}
+ "#,
+ r#"
+fn func(binary: &[u8]) {
+ let space = b' ';
+ match binary {
+ [space, 5u8] | [space] => "",
+ _ => "other",
+ };
+}
+ "#,
)
}
}