2 use ide_db::RootDatabase;
3 use syntax::ast::{edit::AstNodeEdit, AstNode, HasName, LetStmt, Name, Pat};
6 use crate::{AssistContext, AssistId, AssistKind, Assists};
8 /// Gets a list of binders in a pattern, and whether they are mut.
10 acc: &mut Vec<(Name, bool)>,
12 sem: &Semantics<'_, RootDatabase>,
17 let ident = p.name()?;
18 let ismut = p.ref_token().is_none() && p.mut_token().is_some();
19 // check for const reference
20 if sem.resolve_bind_pat_to_const(p).is_none() {
21 acc.push((ident, ismut));
23 if let Some(inner) = p.pat() {
24 binders_in_pat(acc, &inner, sem)?;
28 BoxPat(p) => p.pat().and_then(|p| binders_in_pat(acc, &p, sem)),
29 RestPat(_) | LiteralPat(_) | PathPat(_) | WildcardPat(_) | ConstBlockPat(_) => Some(()),
32 binders_in_pat(acc, &p, sem)?;
36 ParenPat(p) => p.pat().and_then(|p| binders_in_pat(acc, &p, sem)),
38 if let Some(st) = p.start() {
39 binders_in_pat(acc, &st, sem)?
41 if let Some(ed) = p.end() {
42 binders_in_pat(acc, &ed, sem)?
47 for f in p.record_pat_field_list()?.fields() {
49 binders_in_pat(acc, &pat, sem)?;
53 RefPat(p) => p.pat().and_then(|p| binders_in_pat(acc, &p, sem)),
56 binders_in_pat(acc, &p, sem)?;
62 binders_in_pat(acc, &p, sem)?;
66 TupleStructPat(p) => {
68 binders_in_pat(acc, &p, sem)?;
72 // don't support macro pat yet
77 fn binders_to_str(binders: &[(Name, bool)], addmut: bool) -> String {
83 format!("mut {}", ident)
91 if binders.is_empty() {
93 } else if binders.len() == 1 {
100 // Assist: convert_let_else_to_match
102 // Converts let-else statement to let statement and match expression.
106 // let Ok(mut x) = f() else$0 { return };
112 // let mut x = match f() {
118 pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
119 // should focus on else token to trigger
120 let else_token = ctx.find_token_syntax_at_offset(T![else])?;
121 let let_stmt = LetStmt::cast(else_token.parent()?.parent()?)?;
122 let let_else_block = let_stmt.let_else()?.block_expr()?;
123 let let_init = let_stmt.initializer()?;
124 if let_stmt.ty().is_some() {
125 // don't support let with type annotation
128 let pat = let_stmt.pat()?;
129 let mut binders = Vec::new();
130 binders_in_pat(&mut binders, &pat, &ctx.sema)?;
132 let target = let_stmt.syntax().text_range();
134 AssistId("convert_let_else_to_match", AssistKind::RefactorRewrite),
135 "Convert let-else to let and match",
138 let indent_level = let_stmt.indent_level().0 as usize;
139 let indent = " ".repeat(indent_level);
140 let indent1 = " ".repeat(indent_level + 1);
142 let binders_str = binders_to_str(&binders, false);
143 let binders_str_mut = binders_to_str(&binders, true);
145 let init_expr = let_init.syntax().text();
146 let mut pat_no_mut = pat.syntax().text().to_string();
147 // remove the mut from the pattern
148 for (b, ismut) in binders.iter() {
150 pat_no_mut = pat_no_mut.replace(&format!("mut {b}"), &b.to_string());
154 let only_expr = let_else_block.statements().next().is_none();
155 let branch2 = match &let_else_block.tail_expr() {
156 Some(tail) if only_expr => format!("{},", tail.syntax().text()),
157 _ => let_else_block.syntax().text().to_string(),
159 let replace = if binders.is_empty() {
161 "match {init_expr} {{
162 {indent1}{pat_no_mut} => {binders_str}
163 {indent1}_ => {branch2}
168 "let {binders_str_mut} = match {init_expr} {{
169 {indent1}{pat_no_mut} => {binders_str},
170 {indent1}_ => {branch2}
174 edit.replace(target, replace);
183 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
186 fn convert_let_else_to_match_no_type_let() {
187 check_assist_not_applicable(
188 convert_let_else_to_match,
191 let 1: u32 = v.iter().sum() else$0 { return };
197 fn convert_let_else_to_match_on_else() {
198 check_assist_not_applicable(
199 convert_let_else_to_match,
202 let Ok(x) = f() else {$0 return };
209 fn convert_let_else_to_match_no_macropat() {
210 check_assist_not_applicable(
211 convert_let_else_to_match,
214 let m!() = g() else$0 { return };
221 fn convert_let_else_to_match_target() {
223 convert_let_else_to_match,
226 let Ok(x) = f() else$0 { continue };
228 "let Ok(x) = f() else { continue };",
233 fn convert_let_else_to_match_basic() {
235 convert_let_else_to_match,
238 let Ok(x) = f() else$0 { continue };
251 fn convert_let_else_to_match_const_ref() {
253 convert_let_else_to_match,
261 let None = f() el$0se { continue };
279 fn convert_let_else_to_match_const_ref_const() {
281 convert_let_else_to_match,
283 const NEG1: i32 = -1;
285 let NEG1 = f() el$0se { continue };
288 const NEG1: i32 = -1;
299 fn convert_let_else_to_match_mut() {
301 convert_let_else_to_match,
304 let Ok(mut x) = f() el$0se { continue };
308 let mut x = match f() {
317 fn convert_let_else_to_match_multi_binders() {
319 convert_let_else_to_match,
322 let ControlFlow::Break((x, "tag", y, ..)) = f() else$0 { g(); return };
326 let (x, y) = match f() {
327 ControlFlow::Break((x, "tag", y, ..)) => (x, y),
335 fn convert_let_else_to_match_slice() {
337 convert_let_else_to_match,
340 let [one, 1001, other] = f() else$0 { break };
344 let (one, other) = match f() {
345 [one, 1001, other] => (one, other),
353 fn convert_let_else_to_match_struct() {
355 convert_let_else_to_match,
358 let [Struct { inner: Some(it) }, 1001, other] = f() else$0 { break };
362 let (it, other) = match f() {
363 [Struct { inner: Some(it) }, 1001, other] => (it, other),
371 fn convert_let_else_to_match_struct_ident_pat() {
373 convert_let_else_to_match,
376 let [Struct { inner }, 1001, other] = f() else$0 { break };
380 let (inner, other) = match f() {
381 [Struct { inner }, 1001, other] => (inner, other),
389 fn convert_let_else_to_match_no_binder() {
391 convert_let_else_to_match,
394 let (8 | 9) = f() else$0 { panic!() };
407 fn convert_let_else_to_match_range() {
409 convert_let_else_to_match,
412 let 1.. = f() e$0lse { return };
425 fn convert_let_else_to_match_refpat() {
427 convert_let_else_to_match,
430 let Ok(&mut x) = f(&mut 0) else$0 { return };
434 let x = match f(&mut 0) {
443 fn convert_let_else_to_match_refmut() {
445 convert_let_else_to_match,
448 let Ok(ref mut x) = f() else$0 { return };
461 fn convert_let_else_to_match_atpat() {
463 convert_let_else_to_match,
466 let out @ Ok(ins) = f() else$0 { return };
470 let (out, ins) = match f() {
471 out @ Ok(ins) => (out, ins),
479 fn convert_let_else_to_match_complex_init() {
481 convert_let_else_to_match,
484 let v = vec![1, 2, 3];
485 let &[mut x, y, ..] = &v.iter().collect::<Vec<_>>()[..] else$0 { return };
489 let v = vec![1, 2, 3];
490 let (mut x, y) = match &v.iter().collect::<Vec<_>>()[..] {
491 &[x, y, ..] => (x, y),