Skip to content

Commit 62eee18

Browse files
authored
Merge pull request #20880 from A4-Tacks/conv-tuple-to-named-rest-pat
Fix invalid RestPat for convert_tuple_struct_to_named_struct
2 parents 76ebe7d + ceb6903 commit 62eee18

File tree

1 file changed

+56
-8
lines changed

1 file changed

+56
-8
lines changed

crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,7 @@ fn edit_struct_references(
154154
ast::TupleStructPat(tuple_struct_pat) => {
155155
Some(make.record_pat_with_fields(
156156
tuple_struct_pat.path()?,
157-
ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
158-
|(pat, name)| {
159-
ast::make::record_pat_field(
160-
ast::make::name_ref(&name.to_string()),
161-
pat,
162-
)
163-
},
164-
), None),
157+
generate_record_pat_list(&tuple_struct_pat, names),
165158
).syntax().clone())
166159
},
167160
// for tuple struct creations like Foo(42)
@@ -284,6 +277,24 @@ fn generate_names(fields: impl Iterator<Item = ast::TupleField>) -> Vec<ast::Nam
284277
.collect()
285278
}
286279

280+
fn generate_record_pat_list(
281+
pat: &ast::TupleStructPat,
282+
names: &[ast::Name],
283+
) -> ast::RecordPatFieldList {
284+
let pure_fields = pat.fields().filter(|p| !matches!(p, ast::Pat::RestPat(_)));
285+
let rest_len = names.len().saturating_sub(pure_fields.clone().count());
286+
let rest_pat = pat.fields().find_map(|p| ast::RestPat::cast(p.syntax().clone()));
287+
let rest_idx =
288+
pat.fields().position(|p| ast::RestPat::can_cast(p.syntax().kind())).unwrap_or(names.len());
289+
let before_rest = pat.fields().zip(names).take(rest_idx);
290+
let after_rest = pure_fields.zip(names.iter().skip(rest_len)).skip(rest_idx);
291+
292+
let fields = before_rest
293+
.chain(after_rest)
294+
.map(|(pat, name)| ast::make::record_pat_field(ast::make::name_ref(&name.text()), pat));
295+
ast::make::record_pat_field_list(fields, rest_pat)
296+
}
297+
287298
#[cfg(test)]
288299
mod tests {
289300
use crate::tests::{check_assist, check_assist_not_applicable};
@@ -358,6 +369,43 @@ impl A {
358369
);
359370
}
360371

372+
#[test]
373+
fn convert_struct_and_rest_pat() {
374+
check_assist(
375+
convert_tuple_struct_to_named_struct,
376+
r#"
377+
struct Inner;
378+
struct A$0(Inner);
379+
fn foo(A(..): A) {}
380+
"#,
381+
r#"
382+
struct Inner;
383+
struct A { field1: Inner }
384+
fn foo(A { .. }: A) {}
385+
"#,
386+
);
387+
388+
check_assist(
389+
convert_tuple_struct_to_named_struct,
390+
r#"
391+
struct A;
392+
struct B;
393+
struct C;
394+
struct D;
395+
struct X$0(A, B, C, D);
396+
fn foo(X(a, .., d): X) {}
397+
"#,
398+
r#"
399+
struct A;
400+
struct B;
401+
struct C;
402+
struct D;
403+
struct X { field1: A, field2: B, field3: C, field4: D }
404+
fn foo(X { field1: a, field4: d, .. }: X) {}
405+
"#,
406+
);
407+
}
408+
361409
#[test]
362410
fn convert_simple_struct_cursor_on_struct_keyword() {
363411
check_assist(

0 commit comments

Comments
 (0)