This commit is contained in:
A4-Tacks 2025-12-21 14:55:12 +01:00 committed by GitHub
commit 64981d059e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,3 +1,6 @@
use std::iter;
use either::Either;
use syntax::{
AstNode, T,
ast::{self, edit::AstNodeEdit},
@ -24,11 +27,16 @@ use crate::{AssistContext, AssistId, Assists};
// ```
pub(crate) fn unwrap_tuple(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
let let_kw = ctx.find_token_syntax_at_offset(T![let])?;
let let_stmt = let_kw.parent().and_then(ast::LetStmt::cast)?;
let indent_level = let_stmt.indent_level().0 as usize;
let pat = let_stmt.pat()?;
let ty = let_stmt.ty();
let init = let_stmt.initializer()?;
let let_stmt = let_kw.parent().and_then(Either::<ast::LetStmt, ast::LetExpr>::cast)?;
let mut indent_level = let_stmt.indent_level();
let pat = either::for_both!(&let_stmt, it => it.pat())?;
let (ty, init, prefix, suffix) = match &let_stmt {
Either::Left(let_stmt) => (let_stmt.ty(), let_stmt.initializer()?, "", ";"),
Either::Right(let_expr) => {
indent_level = indent_level + 1;
(None, let_expr.expr()?, "&& ", "")
}
};
// This only applies for tuple patterns, types, and initializers.
let tuple_pat = match pat {
@ -60,25 +68,19 @@ pub(crate) fn unwrap_tuple(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
"Unwrap tuple",
let_kw.text_range(),
|edit| {
let indents = " ".repeat(indent_level);
let mut decls = String::new();
// If there is an ascribed type, insert that type for each declaration,
// otherwise, omit that type.
if let Some(tys) = tuple_ty {
let mut zipped_decls = String::new();
for (pat, ty, expr) in
itertools::izip!(tuple_pat.fields(), tys.fields(), tuple_init.fields())
{
zipped_decls.push_str(&format!("{indents}let {pat}: {ty} = {expr};\n"))
}
edit.replace(parent.text_range(), zipped_decls.trim());
} else {
let mut zipped_decls = String::new();
for (pat, expr) in itertools::izip!(tuple_pat.fields(), tuple_init.fields()) {
zipped_decls.push_str(&format!("{indents}let {pat} = {expr};\n"));
}
edit.replace(parent.text_range(), zipped_decls.trim());
let tys =
tuple_ty.into_iter().flat_map(|it| it.fields().map(Some)).chain(iter::repeat(None));
for (pat, ty, expr) in itertools::izip!(tuple_pat.fields(), tys, tuple_init.fields()) {
let ty = ty.map_or_else(String::new, |ty| format!(": {ty}"));
decls.push_str(&format!("{prefix}let {pat}{ty} = {expr}{suffix}\n{indent_level}"))
}
let s = decls.trim();
edit.replace(parent.text_range(), s.strip_prefix(prefix).unwrap_or(s));
},
)
}
@ -123,6 +125,28 @@ fn main() {
);
}
#[test]
fn unwrap_tuples_in_let_expr() {
check_assist(
unwrap_tuple,
r#"
fn main() {
if $0let (foo, bar) = ("Foo", "Bar") {
code();
}
}
"#,
r#"
fn main() {
if let foo = "Foo"
&& let bar = "Bar" {
code();
}
}
"#,
);
}
#[test]
fn unwrap_tuple_with_types() {
check_assist(