From 59cdb318740e433f6c459e84c1c79911d9fedd8b Mon Sep 17 00:00:00 2001 From: Wang Ruochen Date: Sat, 30 Apr 2022 20:19:12 -0700 Subject: [PATCH 1/5] Turn let-else statements into let and match --- .../src/handlers/convert_let_else_to_match.rs | 426 ++++++++++++++++++ crates/ide-assists/src/lib.rs | 2 + crates/ide-assists/src/tests/generated.rs | 20 + 3 files changed, 448 insertions(+) create mode 100644 crates/ide-assists/src/handlers/convert_let_else_to_match.rs diff --git a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs new file mode 100644 index 000000000000..bf6b84ca7f3d --- /dev/null +++ b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs @@ -0,0 +1,426 @@ +use syntax::ast::{edit::AstNodeEdit, AstNode, HasName, LetStmt, Pat}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +/// Gets a list of binders in a pattern, and whether they are mut. +fn binders_in_pat(pat: &Pat) -> Option> { + use Pat::*; + match pat { + IdentPat(p) => { + let ident = p.name()?.text().to_string(); + let ismut = p.ref_token().is_none() && p.mut_token().is_some(); + let mut res = vec![(ident, ismut)]; + if let Some(inner) = p.pat() { + res.extend(binders_in_pat(&inner)?); + } + Some(res) + } + BoxPat(p) => p.pat().and_then(|p| binders_in_pat(&p)), + RestPat(_) | LiteralPat(_) | PathPat(_) | WildcardPat(_) | ConstBlockPat(_) => Some(vec![]), + OrPat(p) => { + let mut v = vec![]; + for p in p.pats() { + v.extend(binders_in_pat(&p)?); + } + Some(v) + } + ParenPat(p) => p.pat().and_then(|p| binders_in_pat(&p)), + RangePat(p) => { + let mut start = if let Some(st) = p.start() { binders_in_pat(&st)? } else { vec![] }; + let end = if let Some(st) = p.end() { binders_in_pat(&st)? } else { vec![] }; + start.extend(end); + Some(start) + } + RecordPat(p) => { + let mut v = vec![]; + for f in p.record_pat_field_list()?.fields() { + let pat = f.pat()?; + v.extend(binders_in_pat(&pat)?); + } + Some(v) + } + RefPat(p) => p.pat().and_then(|p| binders_in_pat(&p)), + SlicePat(p) => { + let mut v = vec![]; + for p in p.pats() { + v.extend(binders_in_pat(&p)?); + } + Some(v) + } + TuplePat(p) => { + let mut v = vec![]; + for p in p.fields() { + v.extend(binders_in_pat(&p)?); + } + Some(v) + } + TupleStructPat(p) => { + let mut v = vec![]; + for p in p.fields() { + v.extend(binders_in_pat(&p)?); + } + Some(v) + } + // don't support macro pat yet + MacroPat(_) => None, + } +} + +fn binders_to_str(binders: &[(String, bool)], addmut: bool) -> String { + let vars = binders + .iter() + .map( + |(ident, ismut)| { + if *ismut && addmut { + format!("mut {}", ident) + } else { + ident.to_string() + } + }, + ) + .collect::>() + .join(", "); + if binders.is_empty() { + String::from("{}") + } else if binders.len() == 1 { + vars + } else { + format!("({})", vars) + } +} + +// Assist: convert_let_else_to_match +// +// Converts let-else statement to let statement and match expression. +// +// ``` +// fn main() { +// let Ok(mut x) = f() else {$0 return }; +// } +// ``` +// -> +// ``` +// fn main() { +// let mut x = match f() { +// Ok(x) => x, +// _ => return, +// }; +// } +// ``` +pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { + let let_stmt: LetStmt = ctx.find_node_at_offset()?; + let let_else_block = let_stmt.let_else()?.block_expr()?; + let let_init = let_stmt.initializer()?; + if let_stmt.ty().is_some() { + // don't support let with type annotation + return None; + } + let pat = let_stmt.pat()?; + let binders = binders_in_pat(&pat)?; + + let target = let_stmt.syntax().text_range(); + acc.add( + AssistId("convert_let_else_to_match", AssistKind::RefactorRewrite), + "Convert let-else to let and match", + target, + |edit| { + let indent_level = let_stmt.indent_level().0 as usize; + let indent = " ".repeat(indent_level); + let indent1 = " ".repeat(indent_level + 1); + + let binders_str = binders_to_str(&binders, false); + let binders_str_mut = binders_to_str(&binders, true); + + let init_expr = let_init.syntax().text(); + let mut pat_no_mut = pat.syntax().text().to_string(); + // remove the mut from the pattern + for (b, ismut) in binders.iter() { + if *ismut { + pat_no_mut = pat_no_mut.replace(&format!("mut {b}"), b); + } + } + + let only_expr = let_else_block.statements().next().is_none(); + let branch2 = match &let_else_block.tail_expr() { + Some(tail) if only_expr => format!("{},", tail.syntax().text()), + _ => let_else_block.syntax().text().to_string(), + }; + let replace = if binders.is_empty() { + format!( + "match {init_expr} {{ +{indent1}{pat_no_mut} => {binders_str} +{indent1}_ => {branch2} +{indent}}}" + ) + } else { + format!( + "let {binders_str_mut} = match {init_expr} {{ +{indent1}{pat_no_mut} => {binders_str}, +{indent1}_ => {branch2} +{indent}}};" + ) + }; + edit.replace(target, replace); + }, + ) +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; + + #[test] + fn convert_let_else_to_match_no_type_let() { + check_assist_not_applicable( + convert_let_else_to_match, + r#" +fn main() { + let 1: u32 = v.iter().sum() else {$0 return }; +}"#, + ); + } + + #[test] + fn convert_let_else_to_match_no_macropat() { + check_assist_not_applicable( + convert_let_else_to_match, + r#" +fn main() { + let m!() = g() else {$0 return }; +} + "#, + ); + } + + #[test] + fn convert_let_else_to_match_target() { + check_assist_target( + convert_let_else_to_match, + r" +fn main() { + let Ok(x) = f() else {$0 continue }; +}", + "let Ok(x) = f() else { continue };", + ); + } + + #[test] + fn convert_let_else_to_match_basic() { + check_assist( + convert_let_else_to_match, + r" +fn main() { + let Ok(x) = f() else {$0 continue }; +}", + r" +fn main() { + let x = match f() { + Ok(x) => x, + _ => continue, + }; +}", + ); + } + + #[test] + fn convert_let_else_to_match_mut() { + check_assist( + convert_let_else_to_match, + r" +fn main() { + let Ok(mut x) = f() else {$0 continue }; +}", + r" +fn main() { + let mut x = match f() { + Ok(x) => x, + _ => continue, + }; +}", + ); + } + + #[test] + fn convert_let_else_to_match_multi_binders() { + check_assist( + convert_let_else_to_match, + r#" +fn main() { + let ControlFlow::Break((x, "tag", y, ..)) = f() else {$0 g(); return }; +}"#, + r#" +fn main() { + let (x, y) = match f() { + ControlFlow::Break((x, "tag", y, ..)) => (x, y), + _ => { g(); return } + }; +}"#, + ); + } + + #[test] + fn convert_let_else_to_match_slice() { + check_assist( + convert_let_else_to_match, + r#" +fn main() { + let [one, 1001, other] = f() else {$0 break }; +}"#, + r#" +fn main() { + let (one, other) = match f() { + [one, 1001, other] => (one, other), + _ => break, + }; +}"#, + ); + } + + #[test] + fn convert_let_else_to_match_struct() { + check_assist( + convert_let_else_to_match, + r#" +fn main() { + let [Struct { inner: Some(it) }, 1001, other] = f() else {$0 break }; +}"#, + r#" +fn main() { + let (it, other) = match f() { + [Struct { inner: Some(it) }, 1001, other] => (it, other), + _ => break, + }; +}"#, + ); + } + + #[test] + fn convert_let_else_to_match_struct_ident_pat() { + check_assist( + convert_let_else_to_match, + r#" +fn main() { + let [Struct { inner }, 1001, other] = f() else {$0 break }; +}"#, + r#" +fn main() { + let (inner, other) = match f() { + [Struct { inner }, 1001, other] => (inner, other), + _ => break, + }; +}"#, + ); + } + + #[test] + fn convert_let_else_to_match_no_binder() { + check_assist( + convert_let_else_to_match, + r#" +fn main() { + let (8 | 9) = f() else {$0 panic!() }; +}"#, + r#" +fn main() { + match f() { + (8 | 9) => {} + _ => panic!(), + } +}"#, + ); + } + + #[test] + fn convert_let_else_to_match_range() { + check_assist( + convert_let_else_to_match, + r#" +fn main() { + let 1.. = f() else {$0 return }; +}"#, + r#" +fn main() { + match f() { + 1.. => {} + _ => return, + } +}"#, + ); + } + + #[test] + fn convert_let_else_to_match_refpat() { + check_assist( + convert_let_else_to_match, + r#" +fn main() { + let Ok(&mut x) = f(&mut 0) else {$0 return }; +}"#, + r#" +fn main() { + let x = match f(&mut 0) { + Ok(&mut x) => x, + _ => return, + }; +}"#, + ); + } + + #[test] + fn convert_let_else_to_match_refmut() { + check_assist( + convert_let_else_to_match, + r#" +fn main() { + let Ok(ref mut x) = f() else {$0 return }; +}"#, + r#" +fn main() { + let x = match f() { + Ok(ref mut x) => x, + _ => return, + }; +}"#, + ); + } + + #[test] + fn convert_let_else_to_match_atpat() { + check_assist( + convert_let_else_to_match, + r#" +fn main() { + let out @ Ok(ins) = f() else {$0 return }; +}"#, + r#" +fn main() { + let (out, ins) = match f() { + out @ Ok(ins) => (out, ins), + _ => return, + }; +}"#, + ); + } + + #[test] + fn convert_let_else_to_match_complex_init() { + check_assist( + convert_let_else_to_match, + r#" +fn main() { + let v = vec![1, 2, 3]; + let &[mut x, y, ..] = &v.iter().collect::>()[..]$0 else { return }; +}"#, + r#" +fn main() { + let v = vec![1, 2, 3]; + let (mut x, y) = match &v.iter().collect::>()[..] { + &[x, y, ..] => (x, y), + _ => return, + }; +}"#, + ); + } +} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index ef4aa1c62bdf..4896c327198c 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -116,6 +116,7 @@ mod handlers { mod convert_integer_literal; mod convert_into_to_from; mod convert_iter_for_each_to_for; + mod convert_let_else_to_match; mod convert_tuple_struct_to_named_struct; mod convert_to_guarded_return; mod convert_while_to_loop; @@ -206,6 +207,7 @@ mod handlers { convert_into_to_from::convert_into_to_from, convert_iter_for_each_to_for::convert_iter_for_each_to_for, convert_iter_for_each_to_for::convert_for_loop_with_for_each, + convert_let_else_to_match::convert_let_else_to_match, convert_to_guarded_return::convert_to_guarded_return, convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct, convert_while_to_loop::convert_while_to_loop, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 8a1e95d8947b..577387871a4d 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -364,6 +364,26 @@ fn main() { ) } +#[test] +fn doctest_convert_let_else_to_match() { + check_doc_test( + "convert_let_else_to_match", + r#####" +fn main() { + let Ok(mut x) = f() else {$0 return }; +} +"#####, + r#####" +fn main() { + let mut x = match f() { + Ok(x) => x, + _ => return, + }; +} +"#####, + ) +} + #[test] fn doctest_convert_to_guarded_return() { check_doc_test( From a70beea9e9c0ffd226708abdb6a2860f7a32be19 Mon Sep 17 00:00:00 2001 From: Wang Ruochen Date: Mon, 2 May 2022 14:45:31 -0700 Subject: [PATCH 2/5] Trigger only when cursor is on else --- .../src/handlers/convert_let_else_to_match.rs | 49 ++++++++++++------- crates/ide-assists/src/tests/generated.rs | 2 +- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs index bf6b84ca7f3d..cfd176fcf253 100644 --- a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs +++ b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs @@ -1,4 +1,5 @@ use syntax::ast::{edit::AstNodeEdit, AstNode, HasName, LetStmt, Pat}; +use syntax::T; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -95,7 +96,7 @@ fn binders_to_str(binders: &[(String, bool)], addmut: bool) -> String { // // ``` // fn main() { -// let Ok(mut x) = f() else {$0 return }; +// let Ok(mut x) = f() else$0 { return }; // } // ``` // -> @@ -108,7 +109,9 @@ fn binders_to_str(binders: &[(String, bool)], addmut: bool) -> String { // } // ``` pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { - let let_stmt: LetStmt = ctx.find_node_at_offset()?; + // should focus on else token to trigger + let else_token = ctx.find_token_syntax_at_offset(T![else])?; + let let_stmt = LetStmt::cast(else_token.parent()?.parent()?)?; let let_else_block = let_stmt.let_else()?.block_expr()?; let let_init = let_stmt.initializer()?; if let_stmt.ty().is_some() { @@ -177,18 +180,30 @@ mod tests { convert_let_else_to_match, r#" fn main() { - let 1: u32 = v.iter().sum() else {$0 return }; + let 1: u32 = v.iter().sum() else$0 { return }; }"#, ); } + #[test] + fn convert_let_else_to_match_on_else() { + check_assist_not_applicable( + convert_let_else_to_match, + r#" +fn main() { + let Ok(x) = f() else {$0 return }; +} + "#, + ); + } + #[test] fn convert_let_else_to_match_no_macropat() { check_assist_not_applicable( convert_let_else_to_match, r#" fn main() { - let m!() = g() else {$0 return }; + let m!() = g() else$0 { return }; } "#, ); @@ -200,7 +215,7 @@ fn main() { convert_let_else_to_match, r" fn main() { - let Ok(x) = f() else {$0 continue }; + let Ok(x) = f() else$0 { continue }; }", "let Ok(x) = f() else { continue };", ); @@ -212,7 +227,7 @@ fn main() { convert_let_else_to_match, r" fn main() { - let Ok(x) = f() else {$0 continue }; + let Ok(x) = f() else$0 { continue }; }", r" fn main() { @@ -230,7 +245,7 @@ fn main() { convert_let_else_to_match, r" fn main() { - let Ok(mut x) = f() else {$0 continue }; + let Ok(mut x) = f() el$0se { continue }; }", r" fn main() { @@ -248,7 +263,7 @@ fn main() { convert_let_else_to_match, r#" fn main() { - let ControlFlow::Break((x, "tag", y, ..)) = f() else {$0 g(); return }; + let ControlFlow::Break((x, "tag", y, ..)) = f() else$0 { g(); return }; }"#, r#" fn main() { @@ -266,7 +281,7 @@ fn main() { convert_let_else_to_match, r#" fn main() { - let [one, 1001, other] = f() else {$0 break }; + let [one, 1001, other] = f() else$0 { break }; }"#, r#" fn main() { @@ -284,7 +299,7 @@ fn main() { convert_let_else_to_match, r#" fn main() { - let [Struct { inner: Some(it) }, 1001, other] = f() else {$0 break }; + let [Struct { inner: Some(it) }, 1001, other] = f() else$0 { break }; }"#, r#" fn main() { @@ -302,7 +317,7 @@ fn main() { convert_let_else_to_match, r#" fn main() { - let [Struct { inner }, 1001, other] = f() else {$0 break }; + let [Struct { inner }, 1001, other] = f() else$0 { break }; }"#, r#" fn main() { @@ -320,7 +335,7 @@ fn main() { convert_let_else_to_match, r#" fn main() { - let (8 | 9) = f() else {$0 panic!() }; + let (8 | 9) = f() else$0 { panic!() }; }"#, r#" fn main() { @@ -338,7 +353,7 @@ fn main() { convert_let_else_to_match, r#" fn main() { - let 1.. = f() else {$0 return }; + let 1.. = f() e$0lse { return }; }"#, r#" fn main() { @@ -356,7 +371,7 @@ fn main() { convert_let_else_to_match, r#" fn main() { - let Ok(&mut x) = f(&mut 0) else {$0 return }; + let Ok(&mut x) = f(&mut 0) else$0 { return }; }"#, r#" fn main() { @@ -374,7 +389,7 @@ fn main() { convert_let_else_to_match, r#" fn main() { - let Ok(ref mut x) = f() else {$0 return }; + let Ok(ref mut x) = f() else$0 { return }; }"#, r#" fn main() { @@ -392,7 +407,7 @@ fn main() { convert_let_else_to_match, r#" fn main() { - let out @ Ok(ins) = f() else {$0 return }; + let out @ Ok(ins) = f() else$0 { return }; }"#, r#" fn main() { @@ -411,7 +426,7 @@ fn main() { r#" fn main() { let v = vec![1, 2, 3]; - let &[mut x, y, ..] = &v.iter().collect::>()[..]$0 else { return }; + let &[mut x, y, ..] = &v.iter().collect::>()[..] else$0 { return }; }"#, r#" fn main() { diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 577387871a4d..008dd7eec174 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -370,7 +370,7 @@ fn doctest_convert_let_else_to_match() { "convert_let_else_to_match", r#####" fn main() { - let Ok(mut x) = f() else {$0 return }; + let Ok(mut x) = f() else$0 { return }; } "#####, r#####" From 81d7cbbbe23ae85e9f9003fec65ba1959af16513 Mon Sep 17 00:00:00 2001 From: Wang Ruochen Date: Thu, 5 May 2022 10:14:11 -0700 Subject: [PATCH 3/5] Avoid allocations --- .../src/handlers/convert_let_else_to_match.rs | 69 ++++++++++--------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs index cfd176fcf253..e7560b0c18bf 100644 --- a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs +++ b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs @@ -1,73 +1,77 @@ -use syntax::ast::{edit::AstNodeEdit, AstNode, HasName, LetStmt, Pat}; +use hir::Semantics; +use ide_db::RootDatabase; +use syntax::ast::{edit::AstNodeEdit, AstNode, HasName, LetStmt, Name, Pat}; use syntax::T; use crate::{AssistContext, AssistId, AssistKind, Assists}; /// Gets a list of binders in a pattern, and whether they are mut. -fn binders_in_pat(pat: &Pat) -> Option> { +fn binders_in_pat( + acc: &mut Vec<(Name, bool)>, + pat: &Pat, + sem: &Semantics, +) -> Option<()> { use Pat::*; match pat { IdentPat(p) => { - let ident = p.name()?.text().to_string(); + let ident = p.name()?; let ismut = p.ref_token().is_none() && p.mut_token().is_some(); - let mut res = vec![(ident, ismut)]; + acc.push((ident, ismut)); if let Some(inner) = p.pat() { - res.extend(binders_in_pat(&inner)?); + binders_in_pat(acc, &inner, sem)?; } - Some(res) + Some(()) } - BoxPat(p) => p.pat().and_then(|p| binders_in_pat(&p)), - RestPat(_) | LiteralPat(_) | PathPat(_) | WildcardPat(_) | ConstBlockPat(_) => Some(vec![]), + BoxPat(p) => p.pat().and_then(|p| binders_in_pat(acc, &p, sem)), + RestPat(_) | LiteralPat(_) | PathPat(_) | WildcardPat(_) | ConstBlockPat(_) => Some(()), OrPat(p) => { - let mut v = vec![]; for p in p.pats() { - v.extend(binders_in_pat(&p)?); + binders_in_pat(acc, &p, sem)?; } - Some(v) + Some(()) } - ParenPat(p) => p.pat().and_then(|p| binders_in_pat(&p)), + ParenPat(p) => p.pat().and_then(|p| binders_in_pat(acc, &p, sem)), RangePat(p) => { - let mut start = if let Some(st) = p.start() { binders_in_pat(&st)? } else { vec![] }; - let end = if let Some(st) = p.end() { binders_in_pat(&st)? } else { vec![] }; - start.extend(end); - Some(start) + if let Some(st) = p.start() { + binders_in_pat(acc, &st, sem)? + } + if let Some(ed) = p.end() { + binders_in_pat(acc, &ed, sem)? + } + Some(()) } RecordPat(p) => { - let mut v = vec![]; for f in p.record_pat_field_list()?.fields() { let pat = f.pat()?; - v.extend(binders_in_pat(&pat)?); + binders_in_pat(acc, &pat, sem)?; } - Some(v) + Some(()) } - RefPat(p) => p.pat().and_then(|p| binders_in_pat(&p)), + RefPat(p) => p.pat().and_then(|p| binders_in_pat(acc, &p, sem)), SlicePat(p) => { - let mut v = vec![]; for p in p.pats() { - v.extend(binders_in_pat(&p)?); + binders_in_pat(acc, &p, sem)?; } - Some(v) + Some(()) } TuplePat(p) => { - let mut v = vec![]; for p in p.fields() { - v.extend(binders_in_pat(&p)?); + binders_in_pat(acc, &p, sem)?; } - Some(v) + Some(()) } TupleStructPat(p) => { - let mut v = vec![]; for p in p.fields() { - v.extend(binders_in_pat(&p)?); + binders_in_pat(acc, &p, sem)?; } - Some(v) + Some(()) } // don't support macro pat yet MacroPat(_) => None, } } -fn binders_to_str(binders: &[(String, bool)], addmut: bool) -> String { +fn binders_to_str(binders: &[(Name, bool)], addmut: bool) -> String { let vars = binders .iter() .map( @@ -119,7 +123,8 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext) return None; } let pat = let_stmt.pat()?; - let binders = binders_in_pat(&pat)?; + let mut binders = Vec::new(); + binders_in_pat(&mut binders, &pat, &ctx.sema)?; let target = let_stmt.syntax().text_range(); acc.add( @@ -139,7 +144,7 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext) // remove the mut from the pattern for (b, ismut) in binders.iter() { if *ismut { - pat_no_mut = pat_no_mut.replace(&format!("mut {b}"), b); + pat_no_mut = pat_no_mut.replace(&format!("mut {b}"), &b.to_string()); } } From 8d7a393008b975b43da10633450fc0044c90d895 Mon Sep 17 00:00:00 2001 From: Wang Ruochen Date: Thu, 5 May 2022 10:57:47 -0700 Subject: [PATCH 4/5] Check const reference --- .../src/handlers/convert_let_else_to_match.rs | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs index e7560b0c18bf..5498afddd951 100644 --- a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs +++ b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs @@ -16,7 +16,10 @@ fn binders_in_pat( IdentPat(p) => { let ident = p.name()?; let ismut = p.ref_token().is_none() && p.mut_token().is_some(); - acc.push((ident, ismut)); + // check for const reference + if !(p.is_simple_ident() && sem.resolve_bind_pat_to_const(p).is_some()) { + acc.push((ident, ismut)); + } if let Some(inner) = p.pat() { binders_in_pat(acc, &inner, sem)?; } @@ -244,6 +247,54 @@ fn main() { ); } + #[test] + fn convert_let_else_to_match_const_ref() { + check_assist( + convert_let_else_to_match, + r" +enum Option { + Some(T), + None, +} +use Option::*; +fn main() { + let None = f() el$0se { continue }; +}", + r" +enum Option { + Some(T), + None, +} +use Option::*; +fn main() { + match f() { + None => {} + _ => continue, + } +}", + ); + } + + #[test] + fn convert_let_else_to_match_const_ref_const() { + check_assist( + convert_let_else_to_match, + r" +const NEG1: i32 = -1; +fn main() { + let NEG1 = f() el$0se { continue }; +}", + r" +const NEG1: i32 = -1; +fn main() { + match f() { + NEG1 => {} + _ => continue, + } +}", + ); + } + #[test] fn convert_let_else_to_match_mut() { check_assist( From 4a0821f332a2c2bf05496a20e1a4dc4b3eb863cc Mon Sep 17 00:00:00 2001 From: weirane Date: Wed, 18 May 2022 02:38:50 +0800 Subject: [PATCH 5/5] Simplify const reference check Co-authored-by: Lukas Wirth --- crates/ide-assists/src/handlers/convert_let_else_to_match.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs index 5498afddd951..2363aa7cbd90 100644 --- a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs +++ b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs @@ -17,7 +17,7 @@ fn binders_in_pat( let ident = p.name()?; let ismut = p.ref_token().is_none() && p.mut_token().is_some(); // check for const reference - if !(p.is_simple_ident() && sem.resolve_bind_pat_to_const(p).is_some()) { + if sem.resolve_bind_pat_to_const(p).is_none() { acc.push((ident, ismut)); } if let Some(inner) = p.pat() {