Fix invalid RestPat for convert_tuple_struct_to_named_struct
```rust
struct X$0(i8, i16, i32, i64);
fn foo(X(a, .., d): X) {}
```
**Before this PR**:
```rust
struct X { field1: i8, field2: i16, field3: i32, field4: i64 }
fn foo(X { field1: a, field2: .., field3: d }: X) {}
```
**After this PR**:
```rust
struct X { field1: i8, field2: i16, field3: i32, field4: i64 }
fn foo(X { field1: a, field4: d, .. }: X) {}
```
diff --git a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
index 3d78895..61d8449 100644
--- a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
+++ b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
@@ -154,14 +154,7 @@
ast::TupleStructPat(tuple_struct_pat) => {
Some(make.record_pat_with_fields(
tuple_struct_pat.path()?,
- ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
- |(pat, name)| {
- ast::make::record_pat_field(
- ast::make::name_ref(&name.to_string()),
- pat,
- )
- },
- ), None),
+ generate_record_pat_list(&tuple_struct_pat, names),
).syntax().clone())
},
// for tuple struct creations like Foo(42)
@@ -284,6 +277,24 @@
.collect()
}
+fn generate_record_pat_list(
+ pat: &ast::TupleStructPat,
+ names: &[ast::Name],
+) -> ast::RecordPatFieldList {
+ let pure_fields = pat.fields().filter(|p| !matches!(p, ast::Pat::RestPat(_)));
+ let rest_len = names.len().saturating_sub(pure_fields.clone().count());
+ let rest_pat = pat.fields().find_map(|p| ast::RestPat::cast(p.syntax().clone()));
+ let rest_idx =
+ pat.fields().position(|p| ast::RestPat::can_cast(p.syntax().kind())).unwrap_or(names.len());
+ let before_rest = pat.fields().zip(names).take(rest_idx);
+ let after_rest = pure_fields.zip(names.iter().skip(rest_len)).skip(rest_idx);
+
+ let fields = before_rest
+ .chain(after_rest)
+ .map(|(pat, name)| ast::make::record_pat_field(ast::make::name_ref(&name.text()), pat));
+ ast::make::record_pat_field_list(fields, rest_pat)
+}
+
#[cfg(test)]
mod tests {
use crate::tests::{check_assist, check_assist_not_applicable};
@@ -359,6 +370,43 @@
}
#[test]
+ fn convert_struct_and_rest_pat() {
+ check_assist(
+ convert_tuple_struct_to_named_struct,
+ r#"
+struct Inner;
+struct A$0(Inner);
+fn foo(A(..): A) {}
+"#,
+ r#"
+struct Inner;
+struct A { field1: Inner }
+fn foo(A { .. }: A) {}
+"#,
+ );
+
+ check_assist(
+ convert_tuple_struct_to_named_struct,
+ r#"
+struct A;
+struct B;
+struct C;
+struct D;
+struct X$0(A, B, C, D);
+fn foo(X(a, .., d): X) {}
+"#,
+ r#"
+struct A;
+struct B;
+struct C;
+struct D;
+struct X { field1: A, field2: B, field3: C, field4: D }
+fn foo(X { field1: a, field4: d, .. }: X) {}
+"#,
+ );
+ }
+
+ #[test]
fn convert_simple_struct_cursor_on_struct_keyword() {
check_assist(
convert_tuple_struct_to_named_struct,