mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 22:13:39 +00:00
34df29620a
fix: rewrite code_action `generate_delegate_trait` I've made substantial enhancements to the "generate delegate trait" code action in rust-analyzer. Here's a summary of the changes: #### Resolved the "Can’t find CONST_ARG@158..159 in AstIdMap" error Fix #15804, fix #15968, fix #15108 The issue stemmed from an incorrect application of PathTransform in the original code. Previously, a new 'impl' was generated first and then transformed, causing PathTransform to fail in locating the correct AST node, resulting in an error. I rectified this by performing the transformation before generating the new 'impl' (using make::impl_trait), ensuring a step-by-step transformation of associated items. #### Rectified generation of `Self` type `generate_delegate_trait` is unable to properly handle trait with `Self` type. Let's take the following code as an example: ```rust trait Trait { fn f() -> Self; } struct B {} impl Trait for B { fn f() -> B { B{} } } struct S { b: B, } ``` Here, if we implement `Trait` for `S`, the type of `f` should be `() -> Self`, i.e. `() -> S`. However we cannot automatically generate a function that constructs `S`. To ensure that the code action doesn't generate delegate traits for traits with Self types, I add a function named `has_self_type` to handle it. #### Extended support for generics in structs and fields within this code action The former version of `generate_delegate_trait` cannot handle structs with generics properly. Here's an example: ```rust struct B<T> { a: T } trait Trait<T> { fn f(a: T); } impl<T1, T2> Trait<T1> for B<T2> { fn f(a: T1) -> T2 { self.a } } struct A {} struct S { b$0 : B<A>, } ``` The former version will generates improper code: ```rust impl<T1, T2> Trait<T1, T2> for S { fn f(&self, a: T1) -> T1 { <B as Trait<T1, T2>>::f( &self.b , a) } } ``` The rewritten version can handle generics properly: ```rust impl<T1> Trait<T1> for S { fn f(&self, a: T1) -> T1 { <B<A> as Trait<T1>>::f(&self.b, a) } } ``` See more examples in added unit tests. I enabled support for generic structs in `generate_delegate_trait` through the following steps (using the code example provided): 1. Initially, to prevent conflicts between the generic parameters in struct `S` and the ones in the impl of `B`, I renamed the generic parameters of `S`. 2. Then, since `B`'s parameters are instantiated within `S`, the original generic parameters of `B` needed removal within `S` (to avoid errors from redundant parameters). An important consideration here arises when Trait and B share parameters in `B`'s impl. In such cases, these shared generic parameters cannot be removed. 3. Next, I addressed the matching of types between `B`'s type in `S` and its type in the impl. Given that some generic parameters in the impl are instantiated in `B`, I replaced these parameters with their instantiated results using PathTransform. For instance, in the example provided, matching `B<A>` and `B<T2>`, where `T2` is instantiated as `A`, I replaced all occurrences of `T2` in the impl with `A` (i.e. apply the instantiated generic arguments to the params). 4. Finally, I performed transformations on each assoc item (also to prevent the initial issue) and handled redundant where clauses. For a more detailed explanation, please refer to the code and comments. I welcome suggestions and any further questions! |
||
---|---|---|
.. | ||
src | ||
Cargo.toml |