-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature: Add destructure_struct_binding
#16638
Conversation
e556829
to
059b35f
Compare
fn is_auto_ref(ctx: &AssistContext<'_>, call_expr: &MethodCallExpr) -> bool { | ||
fn impl_(ctx: &AssistContext<'_>, call_expr: &MethodCallExpr) -> Option<bool> { | ||
let rec = call_expr.receiver()?; | ||
let rec_ty = ctx.sema.type_of_expr(&rec)?.original(); | ||
// input must be actual value | ||
if rec_ty.is_reference() { | ||
return Some(false); | ||
} | ||
|
||
// doesn't resolve trait impl | ||
let f = ctx.sema.resolve_method_call(call_expr)?; | ||
let self_param = f.self_param(ctx.db())?; | ||
// self must be ref | ||
match self_param.access(ctx.db()) { | ||
hir::Access::Shared | hir::Access::Exclusive => Some(true), | ||
hir::Access::Owned => Some(false), | ||
} | ||
} | ||
impl_(ctx, call_expr).unwrap_or(false) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to use sema.expr_adjustments(&rec)
and inspect the adjustments for whether an autoref happened or not. That should simplify this I believe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(also just noticed you didn't write that part, but if you want you could look into that nevertheless)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I just moved it for now. I wouldn't mind looking at it in a follow-up PR!
Thanks! |
feature: Add `destructure_struct_binding` Adds an assist for destructuring a struct in a binding (#8673). I saw that #13997 has been abandoned for a while, so I thought I'd give it a go. ## Example ```rust let foo = Foo { bar: 1, baz: 2 }; let bar2 = foo.bar; let baz2 = foo.baz; let foo2 = foo; let fizz = Fizz(1, 2); let buzz = fizz.0; ``` becomes ```rust let Foo { bar, baz } = Foo { bar: 1, baz: 2 }; let bar2 = bar; let baz2 = baz; let foo2 = todo!(); let Fizz(_0, _1) = Fizz(1, 2); let buzz = _0; ``` More examples in the tests. ## What is included? - [x] Destructure record, tuple, and unit struct bindings - [x] Edit field usages - [x] Non-exhaustive structs in foreign crates and private fields get hidden behind `..` - [x] Nested bindings - [x] Carry over `mut` and `ref mut` in nested bindings to fields, i.e. `let Foo { ref mut bar } = ...` becomes `let Foo { bar: Bar { baz: ref mut baz } } = ...` - [x] Attempt to resolve collisions with other names in the scope - [x] If the binding is to a reference, field usages are dereferenced if required - [x] Use shorthand notation if possible ## Known limitations - `let foo = Foo { bar: 1 }; foo;` currently results in `let Foo { bar } = Foo { bar: 1 }; todo!();` instead of reassembling the struct. This requires user intervention. - Unused fields are not currently omitted. I thought that this is more ergonomic, as there already is a quick fix action for adding `: _` to unused field patterns.
💔 Test failed - checks-actions |
Needs a rebase |
059b35f
to
653fc75
Compare
Done, thanks for reviewing! |
Separate into create and apply edit Rename usages Hacky name map Add more tests Handle non-exhaustive Add some more TODOs Private fields Use todo Nesting Improve rest token generation Cleanup Doc -> regular comment Support mut
653fc75
to
dc7b502
Compare
Thanks! |
☀️ Test successful - checks-actions |
fix: Don't destructure struct with no public fields Unfortunately I missed this case in #16638. If a struct only has private members, the assist should not be applicable. Though valid syntax exists (`Foo { .. }`), it isn't particularly useful. Since this case applies to a lot of common types (`Arc`, `Vec`, ...), it probably makes the most sense to hide the action. As a side effect, this also disables the action for unit structs, where it also isn't particularly useful. I'd be open to changing it though if you think it makes more sense to keep it. This also fixes the `make::record_pat_field_list` function to produce valid syntax if the field list is empty, as it is used in other places too. ## Current behaviour ```rust // In crate `other_crate` pub struct Foo { bar: i32 } // In current crate fn do_something(foo: other_crate::Foo) {} // Becomes fn do_something(other_crate::Foo { , .. }: other_crate::Foo) {} ``` ## Fixed behaviour Assist should not be applicable in this case anymore.
Adds an assist for destructuring a struct in a binding (#8673). I saw that #13997 has been abandoned for a while, so I thought I'd give it a go.
Example
becomes
More examples in the tests.
What is included?
..
mut
andref mut
in nested bindings to fields, i.e.let Foo { ref mut bar } = ...
becomeslet Foo { bar: Bar { baz: ref mut baz } } = ...
Known limitations
let foo = Foo { bar: 1 }; foo;
currently results inlet Foo { bar } = Foo { bar: 1 }; todo!();
instead of reassembling the struct. This requires user intervention.: _
to unused field patterns.