From 59aa791fe6cd5bc24411f09283ad9af2ddad80f3 Mon Sep 17 00:00:00 2001
From: roife <roifewu@gmail.com>
Date: Wed, 13 Dec 2023 11:22:42 +0800
Subject: [PATCH] fix: rewrite code_action `generate_delegate_trait`

---
 crates/hir/src/semantics.rs                   |  12 +-
 .../src/handlers/generate_delegate_trait.rs   | 953 +++++++++++++++---
 crates/ide-assists/src/tests/generated.rs     |   2 +-
 crates/ide-assists/src/utils/suggest_name.rs  |  26 +
 crates/ide-db/src/path_transform.rs           |  28 +
 crates/syntax/src/ast/edit_in_place.rs        |  46 +-
 crates/syntax/src/ast/make.rs                 |  64 +-
 crates/syntax/src/ast/node_ext.rs             |  10 +
 8 files changed, 983 insertions(+), 158 deletions(-)

diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 92fa76c96fb..31c957175f5 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -40,8 +40,8 @@ use crate::{
     source_analyzer::{resolve_hir_path, SourceAnalyzer},
     Access, Adjust, Adjustment, AutoBorrow, BindingMode, BuiltinAttr, Callable, ConstParam, Crate,
     DeriveHelper, Field, Function, HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local,
-    Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, ToolModule, Trait, Type,
-    TypeAlias, TypeParam, VariantDef,
+    Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, Struct, ToolModule, Trait,
+    Type, TypeAlias, TypeParam, VariantDef,
 };
 
 pub enum DescendPreference {
@@ -229,6 +229,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
     pub fn to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
         self.imp.to_module_def(file)
     }
+
+    pub fn to_struct_def(&self, s: &ast::Struct) -> Option<Struct> {
+        self.imp.to_def(s).map(Struct::from)
+    }
+
+    pub fn to_impl_def(&self, i: &ast::Impl) -> Option<Impl> {
+        self.imp.to_def(i).map(Impl::from)
+    }
 }
 
 impl<'db> SemanticsImpl<'db> {
diff --git a/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index f4fa6a74c6b..0728c587ee0 100644
--- a/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -2,22 +2,25 @@ use std::ops::Not;
 
 use crate::{
     assist_context::{AssistContext, Assists},
-    utils::convert_param_list_to_arg_list,
+    utils::{convert_param_list_to_arg_list, suggest_name},
 };
 use either::Either;
 use hir::{db::HirDatabase, HasVisibility};
 use ide_db::{
     assists::{AssistId, GroupLabel},
     path_transform::PathTransform,
+    FxHashMap, FxHashSet,
 };
+use itertools::Itertools;
 use syntax::{
     ast::{
         self,
         edit::{self, AstNodeEdit},
-        make, AssocItem, HasGenericParams, HasName, HasVisibility as astHasVisibility, Path,
+        make, AssocItem, GenericArgList, GenericParamList, HasGenericParams, HasName,
+        HasTypeBounds, HasVisibility as astHasVisibility, Path,
     },
     ted::{self, Position},
-    AstNode, NodeOrToken, SyntaxKind,
+    AstNode, NodeOrToken, SmolStr, SyntaxKind,
 };
 
 // Assist: generate_delegate_trait
@@ -77,7 +80,7 @@ use syntax::{
 //     }
 //
 //     fn method_(&mut self) -> bool {
-//         <A as SomeTrait>::method_( &mut self.a )
+//         <A as SomeTrait>::method_(&mut self.a)
 //     }
 // }
 // ```
@@ -98,6 +101,7 @@ pub(crate) fn generate_delegate_trait(acc: &mut Assists, ctx: &AssistContext<'_>
 }
 
 /// A utility object that represents a struct's field.
+#[derive(Debug)]
 struct Field {
     name: String,
     ty: ast::Type,
@@ -111,44 +115,33 @@ impl Field {
         f: Either<ast::RecordField, (ast::TupleField, ast::TupleFieldList)>,
     ) -> Option<Field> {
         let db = ctx.sema.db;
-        let name: String;
-        let range: syntax::TextRange;
-        let ty: ast::Type;
 
         let module = ctx.sema.to_module_def(ctx.file_id())?;
 
-        match f {
+        let (name, range, ty) = match f {
             Either::Left(f) => {
-                name = f.name()?.to_string();
-                ty = f.ty()?;
-                range = f.syntax().text_range();
+                let name = f.name()?.to_string();
+                (name, f.syntax().text_range(), f.ty()?)
             }
             Either::Right((f, l)) => {
-                name = l.fields().position(|it| it == f)?.to_string();
-                ty = f.ty()?;
-                range = f.syntax().text_range();
+                let name = l.fields().position(|it| it == f)?.to_string();
+                (name, f.syntax().text_range(), f.ty()?)
             }
         };
 
         let hir_ty = ctx.sema.resolve_type(&ty)?;
         let type_impls = hir::Impl::all_for_type(db, hir_ty.clone());
         let mut impls = Vec::with_capacity(type_impls.len());
-        let type_param = hir_ty.as_type_param(db);
 
-        if let Some(tp) = type_param {
+        if let Some(tp) = hir_ty.as_type_param(db) {
             for tb in tp.trait_bounds(db) {
-                impls.push(Delegee::Bound(BoundCase(tb)));
+                impls.push(Delegee::Bound(tb));
             }
         };
 
         for imp in type_impls {
-            match imp.trait_(db) {
-                Some(tr) => {
-                    if tr.is_visible_from(db, module) {
-                        impls.push(Delegee::Impls(ImplCase(tr, imp)))
-                    }
-                }
-                None => (),
+            if let Some(tr) = imp.trait_(db).filter(|tr| tr.is_visible_from(db, module)) {
+                impls.push(Delegee::Impls(tr, imp))
             }
         }
 
@@ -161,19 +154,17 @@ impl Field {
 /// actually implements the trait and the second way is when the field
 /// has a bound type parameter. We handle these cases in different ways
 /// hence the enum.
+#[derive(Debug)]
 enum Delegee {
-    Bound(BoundCase),
-    Impls(ImplCase),
+    Bound(hir::Trait),
+    Impls(hir::Trait, hir::Impl),
 }
 
-struct BoundCase(hir::Trait);
-struct ImplCase(hir::Trait, hir::Impl);
-
 impl Delegee {
     fn signature(&self, db: &dyn HirDatabase) -> String {
         let mut s = String::new();
 
-        let (Delegee::Bound(BoundCase(it)) | Delegee::Impls(ImplCase(it, _))) = self;
+        let (Delegee::Bound(it) | Delegee::Impls(it, _)) = self;
 
         for m in it.module(db).path_to_root(db).iter().rev() {
             if let Some(name) = m.name(db) {
@@ -200,25 +191,33 @@ impl Struct {
 
     pub(crate) fn delegate(&self, field: Field, acc: &mut Assists, ctx: &AssistContext<'_>) {
         let db = ctx.db();
+
         for delegee in &field.impls {
+            let trait_ = match delegee {
+                Delegee::Bound(b) => b,
+                Delegee::Impls(i, _) => i,
+            };
+
+            // Skip trait that has `Self` type, which cannot be delegated
+            //
+            // See [`test_self_ty`]
+            if has_self_type(*trait_, ctx).is_some() {
+                continue;
+            }
+
             // FIXME :  We can omit already implemented impl_traits
             // But we don't know what the &[hir::Type] argument should look like.
-
-            // let trait_ = match delegee {
-            //     Delegee::Bound(b) => b.0,
-            //     Delegee::Impls(i) => i.1,
-            // };
-
             // if self.hir_ty.impls_trait(db, trait_, &[]) {
             //     continue;
             // }
             let signature = delegee.signature(db);
+
             let Some(delegate) = generate_impl(ctx, self, &field.ty, &field.name, delegee) else {
                 continue;
             };
 
             acc.add_group(
-                &GroupLabel("Delegate trait impl for field...".to_owned()),
+                &GroupLabel(format!("Generate delegate impls for field `{}`", field.name)),
                 AssistId("generate_delegate_trait", ide_db::assists::AssistKind::Generate),
                 format!("Generate delegate impl `{}` for `{}`", signature, field.name),
                 field.range,
@@ -241,46 +240,40 @@ fn generate_impl(
     delegee: &Delegee,
 ) -> Option<ast::Impl> {
     let delegate: ast::Impl;
-    let source: ast::Impl;
-    let genpar: Option<ast::GenericParamList>;
     let db = ctx.db();
-    let base_path = make::path_from_text(&field_ty.to_string().as_str());
-    let s_path = make::ext::ident_path(&strukt.name.to_string());
+    let ast_strukt = &strukt.strukt;
+    let strukt_ty = make::ty_path(make::ext::ident_path(&strukt.name.to_string()));
 
     match delegee {
         Delegee::Bound(delegee) => {
-            let in_file = ctx.sema.source(delegee.0.to_owned())?;
-            let source: ast::Trait = in_file.value;
+            let bound_def = ctx.sema.source(delegee.to_owned())?.value;
+            let bound_params = bound_def.generic_param_list();
+            let strukt_params = ast_strukt.generic_param_list();
 
             delegate = make::impl_trait(
-                delegee.0.is_unsafe(db),
-                None,
-                None,
-                strukt.strukt.generic_param_list(),
-                None,
-                delegee.0.is_auto(db),
-                make::ty(&delegee.0.name(db).to_smol_str()),
-                make::ty_path(s_path),
-                source.where_clause(),
-                strukt.strukt.where_clause(),
+                delegee.is_unsafe(db),
+                bound_params.clone(),
+                bound_params.map(|params| params.to_generic_args()),
+                strukt_params.clone(),
+                strukt_params.map(|params| params.to_generic_args()),
+                delegee.is_auto(db),
+                make::ty(&delegee.name(db).to_smol_str()),
+                strukt_ty,
+                bound_def.where_clause(),
+                ast_strukt.where_clause(),
                 None,
             )
             .clone_for_update();
 
-            genpar = source.generic_param_list();
-            let delegate_assoc_items = delegate.get_or_create_assoc_item_list();
-            let gen_args: String =
-                genpar.map_or_else(String::new, |params| params.to_generic_args().to_string());
-
             // Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths
             let qualified_path_type = make::path_from_text(&format!(
-                "<{} as {}{}>",
-                base_path.to_string(),
-                delegee.0.name(db).to_smol_str(),
-                gen_args.to_string()
+                "<{} as {}>",
+                field_ty.to_string(),
+                delegate.trait_()?.to_string()
             ));
 
-            match source.assoc_item_list() {
+            let delegate_assoc_items = delegate.get_or_create_assoc_item_list();
+            match bound_def.assoc_item_list() {
                 Some(ai) => {
                     ai.assoc_items()
                         .filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
@@ -295,66 +288,394 @@ fn generate_impl(
                 None => {}
             };
 
-            let target = ctx.sema.scope(strukt.strukt.syntax())?;
-            let source = ctx.sema.scope(source.syntax())?;
-
-            let transform =
-                PathTransform::trait_impl(&target, &source, delegee.0, delegate.clone());
+            let target_scope = ctx.sema.scope(strukt.strukt.syntax())?;
+            let source_scope = ctx.sema.scope(bound_def.syntax())?;
+            let transform = PathTransform::generic_transformation(&target_scope, &source_scope);
             transform.apply(&delegate.syntax());
         }
-        Delegee::Impls(delegee) => {
-            let in_file = ctx.sema.source(delegee.1.to_owned())?;
-            source = in_file.value;
+        Delegee::Impls(trait_, old_impl) => {
+            let old_impl = ctx.sema.source(old_impl.to_owned())?.value;
+
+            // `old_trait_args` contains names of generic args for trait in `old_impl`
+            let old_trait_args = old_impl
+                .trait_()?
+                .generic_arg_list()
+                .map(|l| l.generic_args().map(|arg| arg.to_string()))
+                .map_or_else(|| FxHashSet::default(), |it| it.collect());
+
+            let old_impl_params = old_impl.generic_param_list();
+
+            // Resolve conflicts with generic parameters in strukt.
+            // These generics parameters will also be used in `field_ty` and `where_clauses`,
+            // so we should substitude arguments in them as well.
+            let (renamed_strukt_params, field_ty, ty_where_clause) = if let Some(strukt_params) =
+                resolve_conflicts_for_strukt(ast_strukt, old_impl_params.as_ref())
+            {
+                let strukt_args = strukt_params.to_generic_args();
+                let field_ty =
+                    subst_name_in_strukt(ctx, ast_strukt, field_ty, strukt_args.clone())?;
+                let wc = ast_strukt
+                    .where_clause()
+                    .and_then(|wc| Some(subst_name_in_strukt(ctx, ast_strukt, &wc, strukt_args)?));
+                (Some(strukt_params), field_ty, wc)
+            } else {
+                (None, field_ty.clone_for_update(), None)
+            };
+
+            // Some generics used in `field_ty` may be instantiated, so they are no longer
+            // `generics`. We should remove them from generics params, and use the rest params.
+            let trait_gen_params =
+                remove_instantiated_params(&old_impl.self_ty()?, old_impl_params, &old_trait_args);
+
+            // Generate generic args that applied to current impl, this step will also remove unused params
+            let args_for_impl =
+                get_args_for_impl(&old_impl, &field_ty, &trait_gen_params, &old_trait_args);
+
+            let mut trait_gen_args = old_impl.trait_()?.generic_arg_list();
+            if let Some(arg_list) = &mut trait_gen_args {
+                *arg_list = arg_list.clone_for_update();
+                transform_impl(ctx, ast_strukt, &old_impl, &args_for_impl, &arg_list.syntax())?;
+            }
+
+            let mut type_gen_args =
+                renamed_strukt_params.clone().map(|params| params.to_generic_args());
+            if let Some(type_args) = &mut type_gen_args {
+                *type_args = type_args.clone_for_update();
+                transform_impl(ctx, ast_strukt, &old_impl, &args_for_impl, &type_args.syntax())?;
+            }
+
+            let path_type = make::ty(&trait_.name(db).to_smol_str()).clone_for_update();
+            transform_impl(ctx, ast_strukt, &old_impl, &args_for_impl, &path_type.syntax())?;
+
             delegate = make::impl_trait(
-                delegee.0.is_unsafe(db),
-                source.generic_param_list(),
-                None,
-                None,
-                None,
-                delegee.0.is_auto(db),
-                make::ty(&delegee.0.name(db).to_smol_str()),
-                make::ty_path(s_path),
-                source.where_clause(),
-                strukt.strukt.where_clause(),
+                trait_.is_unsafe(db),
+                trait_gen_params,
+                trait_gen_args,
+                renamed_strukt_params,
+                type_gen_args,
+                trait_.is_auto(db),
+                path_type,
+                strukt_ty,
+                old_impl.where_clause().map(|wc| wc.clone_for_update()),
+                ty_where_clause,
                 None,
             )
             .clone_for_update();
-            genpar = source.generic_param_list();
-            let delegate_assoc_items = delegate.get_or_create_assoc_item_list();
-            let gen_args: String =
-                genpar.map_or_else(String::new, |params| params.to_generic_args().to_string());
 
             // Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths
             let qualified_path_type = make::path_from_text(&format!(
-                "<{} as {}{}>",
-                base_path.to_string().as_str(),
-                delegee.0.name(db).to_smol_str(),
-                gen_args.to_string().as_str()
+                "<{} as {}>",
+                field_ty.to_string(),
+                delegate.trait_()?.to_string()
             ));
 
-            source
+            let delegate_assoc_items = delegate.get_or_create_assoc_item_list();
+            for item in old_impl
                 .get_or_create_assoc_item_list()
                 .assoc_items()
                 .filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
-                .for_each(|item| {
-                    let assoc = process_assoc_item(item, qualified_path_type.clone(), &field_name);
-                    if let Some(assoc) = assoc {
-                        delegate_assoc_items.add_item(assoc);
-                    }
-                });
+            {
+                let assoc = process_assoc_item(
+                    transform_assoc_item(ctx, ast_strukt, &old_impl, &args_for_impl, item)?,
+                    qualified_path_type.clone(),
+                    &field_name,
+                )?;
 
-            let target = ctx.sema.scope(strukt.strukt.syntax())?;
-            let source = ctx.sema.scope(source.syntax())?;
+                delegate_assoc_items.add_item(assoc);
+            }
 
-            let transform =
-                PathTransform::trait_impl(&target, &source, delegee.0, delegate.clone());
-            transform.apply(&delegate.syntax());
+            // Remove unused where clauses
+            if let Some(wc) = delegate.where_clause() {
+                remove_useless_where_clauses(&delegate, wc)?;
+            }
         }
     }
 
     Some(delegate)
 }
 
+fn transform_assoc_item(
+    ctx: &AssistContext<'_>,
+    strukt: &ast::Struct,
+    old_impl: &ast::Impl,
+    args: &Option<GenericArgList>,
+    item: AssocItem,
+) -> Option<AssocItem> {
+    let source_scope = ctx.sema.scope(&item.syntax()).unwrap();
+    let target_scope = ctx.sema.scope(&strukt.syntax())?;
+    let hir_old_impl = ctx.sema.to_impl_def(old_impl)?;
+    let item = item.clone_for_update();
+    let transform = args.as_ref().map_or_else(
+        || PathTransform::generic_transformation(&target_scope, &source_scope),
+        |args| {
+            PathTransform::impl_transformation(
+                &target_scope,
+                &source_scope,
+                hir_old_impl,
+                args.clone(),
+            )
+        },
+    );
+    transform.apply(&item.syntax());
+    Some(item)
+}
+
+fn transform_impl(
+    ctx: &AssistContext<'_>,
+    strukt: &ast::Struct,
+    old_impl: &ast::Impl,
+    args: &Option<GenericArgList>,
+    syntax: &syntax::SyntaxNode,
+) -> Option<()> {
+    let source_scope = ctx.sema.scope(&old_impl.self_ty()?.syntax())?;
+    let target_scope = ctx.sema.scope(&strukt.syntax())?;
+    let hir_old_impl = ctx.sema.to_impl_def(old_impl)?;
+
+    let transform = args.as_ref().map_or_else(
+        || PathTransform::generic_transformation(&target_scope, &source_scope),
+        |args| {
+            PathTransform::impl_transformation(
+                &target_scope,
+                &source_scope,
+                hir_old_impl,
+                args.clone(),
+            )
+        },
+    );
+
+    transform.apply(&syntax);
+    Some(())
+}
+
+fn remove_instantiated_params(
+    self_ty: &ast::Type,
+    old_impl_params: Option<GenericParamList>,
+    old_trait_args: &FxHashSet<String>,
+) -> Option<GenericParamList> {
+    match self_ty {
+        ast::Type::PathType(path_type) => {
+            old_impl_params.and_then(|gpl| {
+                // Remove generic parameters in field_ty (which is instantiated).
+                let new_gpl = gpl.clone_for_update();
+
+                path_type
+                    .path()?
+                    .segments()
+                    .filter_map(|seg| seg.generic_arg_list())
+                    .flat_map(|it| it.generic_args())
+                    // However, if the param is also used in the trait arguments, it shouldn't be removed.
+                    .filter(|arg| !old_trait_args.contains(&arg.to_string()))
+                    .for_each(|arg| {
+                        new_gpl.remove_generic_arg(&arg);
+                    });
+                (new_gpl.generic_params().count() > 0).then_some(new_gpl)
+            })
+        }
+        _ => old_impl_params,
+    }
+}
+
+fn remove_useless_where_clauses(delegate: &ast::Impl, wc: ast::WhereClause) -> Option<()> {
+    let trait_args =
+        delegate.trait_()?.generic_arg_list().map(|trait_args| trait_args.generic_args());
+    let strukt_args =
+        delegate.self_ty()?.generic_arg_list().map(|strukt_args| strukt_args.generic_args());
+    let used_generic_names = match (trait_args, strukt_args) {
+        (None, None) => None,
+        (None, Some(y)) => Some(y.map(|arg| arg.to_string()).collect::<FxHashSet<_>>()),
+        (Some(x), None) => Some(x.map(|arg| arg.to_string()).collect::<FxHashSet<_>>()),
+        (Some(x), Some(y)) => Some(x.chain(y).map(|arg| arg.to_string()).collect::<FxHashSet<_>>()),
+    };
+
+    // Keep clauses that have generic clauses after substitution, and remove the rest
+    if let Some(used_generic_names) = used_generic_names {
+        wc.predicates()
+            .filter(|pred| {
+                pred.syntax()
+                    .descendants_with_tokens()
+                    .filter_map(|e| e.into_token())
+                    .find(|e| {
+                        e.kind() == SyntaxKind::IDENT && used_generic_names.contains(&e.to_string())
+                    })
+                    .is_none()
+            })
+            .for_each(|pred| {
+                wc.remove_predicate(pred);
+            });
+    } else {
+        wc.predicates().for_each(|pred| wc.remove_predicate(pred));
+    }
+
+    if wc.predicates().count() == 0 {
+        // Remove useless whitespaces
+        wc.syntax()
+            .siblings_with_tokens(syntax::Direction::Prev)
+            .skip(1)
+            .take_while(|node_or_tok| node_or_tok.kind() == SyntaxKind::WHITESPACE)
+            .for_each(|ws| ted::remove(ws));
+        wc.syntax()
+            .siblings_with_tokens(syntax::Direction::Next)
+            .skip(1)
+            .take_while(|node_or_tok| node_or_tok.kind() == SyntaxKind::WHITESPACE)
+            .for_each(|ws| ted::remove(ws));
+        ted::insert(
+            ted::Position::after(wc.syntax()),
+            NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)),
+        );
+        // Remove where clause
+        ted::remove(wc.syntax());
+    }
+
+    Some(())
+}
+
+fn get_args_for_impl(
+    old_impl: &ast::Impl,
+    field_ty: &ast::Type,
+    trait_params: &Option<GenericParamList>,
+    old_trait_args: &FxHashSet<String>,
+) -> Option<ast::GenericArgList> {
+    // Generate generic args that should be apply to current impl
+    //
+    // For exmaple, if we have `impl<A, B, C> Trait for B<A>`, and `b: B<T>` in `S<T>`,
+    // then the generic `A` should be renamed to `T`. While the last two generic args
+    // doesn't change, it renames <B, C>. So we apply `<T, B C>` as generic arguments
+    // to impl.
+    let old_impl_params = old_impl.generic_param_list();
+    let self_ty = old_impl.self_ty();
+
+    if let (Some(old_impl_gpl), Some(self_ty)) = (old_impl_params, self_ty) {
+        // Make pair of the arguments of `field_ty` and `old_strukt_args` to
+        // get the list for substitution
+        let mut arg_substs = FxHashMap::default();
+
+        match field_ty {
+            field_ty @ ast::Type::PathType(_) => {
+                let field_args = field_ty.generic_arg_list();
+                if let (Some(field_args), Some(old_impl_args)) =
+                    (field_args, self_ty.generic_arg_list())
+                {
+                    field_args.generic_args().zip(old_impl_args.generic_args()).for_each(
+                        |(field_arg, impl_arg)| {
+                            arg_substs.entry(impl_arg.to_string()).or_insert(field_arg);
+                        },
+                    )
+                }
+            }
+            _ => {}
+        }
+
+        let args = old_impl_gpl
+            .to_generic_args()
+            .generic_args()
+            .map(|old_arg| {
+                arg_substs.get(&old_arg.to_string()).map_or_else(
+                    || old_arg.clone(),
+                    |replace_with| {
+                        // The old_arg will be replaced, so it becomes redundant
+                        let old_arg_name = old_arg.to_string();
+                        if old_trait_args.contains(&old_arg_name) {
+                            // However, we should check type bounds and where clauses on old_arg,
+                            // if it has type bound, we should keep the type bound.
+                            // match trait_params.and_then(|params| params.remove_generic_arg(&old_arg)) {
+                            //     Some(ast::GenericParam::TypeParam(ty)) => {
+                            //         ty.type_bound_list().and_then(|bounds| )
+                            //     }
+                            //     _ => {}
+                            // }
+                            if let Some(params) = trait_params {
+                                params.remove_generic_arg(&old_arg);
+                            }
+                        }
+                        replace_with.clone()
+                    },
+                )
+            })
+            .collect_vec();
+        args.is_empty().not().then(|| make::generic_arg_list(args.into_iter()))
+    } else {
+        None
+    }
+}
+
+fn subst_name_in_strukt<N>(
+    ctx: &AssistContext<'_>,
+    strukt: &ast::Struct,
+    item: &N,
+    args: GenericArgList,
+) -> Option<N>
+where
+    N: ast::AstNode,
+{
+    let hir_strukt = ctx.sema.to_struct_def(strukt)?;
+    let hir_adt = hir::Adt::from(hir_strukt);
+
+    let item = item.clone_for_update();
+    let item_scope = ctx.sema.scope(item.syntax())?;
+    let transform = PathTransform::adt_transformation(&item_scope, &item_scope, hir_adt, args);
+    transform.apply(&item.syntax());
+    Some(item)
+}
+
+fn has_self_type(trait_: hir::Trait, ctx: &AssistContext<'_>) -> Option<()> {
+    let trait_source = ctx.sema.source(trait_)?.value;
+    trait_source
+        .syntax()
+        .descendants_with_tokens()
+        .filter_map(|e| e.into_token())
+        .find(|e| e.kind() == SyntaxKind::SELF_TYPE_KW)
+        .map(|_| ())
+}
+
+fn resolve_conflicts_for_strukt(
+    strukt: &ast::Struct,
+    old_impl_params: Option<&ast::GenericParamList>,
+) -> Option<ast::GenericParamList> {
+    match (strukt.generic_param_list(), old_impl_params) {
+        (Some(old_strukt_params), Some(old_impl_params)) => {
+            let params = make::generic_param_list(std::iter::empty()).clone_for_update();
+
+            for old_strukt_param in old_strukt_params.generic_params() {
+                // Get old name from `strukt``
+                let mut name = SmolStr::from(match &old_strukt_param {
+                    ast::GenericParam::ConstParam(c) => c.name()?.to_string(),
+                    ast::GenericParam::LifetimeParam(l) => {
+                        l.lifetime()?.lifetime_ident_token()?.to_string()
+                    }
+                    ast::GenericParam::TypeParam(t) => t.name()?.to_string(),
+                });
+
+                // The new name cannot be conflicted with generics in trait, and the renamed names.
+                name = suggest_name::for_unique_generic_name(&name, old_impl_params);
+                name = suggest_name::for_unique_generic_name(&name, &params);
+                match old_strukt_param {
+                    ast::GenericParam::ConstParam(c) => {
+                        if let Some(const_ty) = c.ty() {
+                            let const_param = make::const_param(make::name(&name), const_ty);
+                            params.add_generic_param(ast::GenericParam::ConstParam(
+                                const_param.clone_for_update(),
+                            ));
+                        }
+                    }
+                    p @ ast::GenericParam::LifetimeParam(_) => {
+                        params.add_generic_param(p.clone_for_update());
+                    }
+                    ast::GenericParam::TypeParam(t) => {
+                        let type_bounds = t.type_bound_list();
+                        let type_param = make::type_param(make::name(&name), type_bounds);
+                        params.add_generic_param(ast::GenericParam::TypeParam(
+                            type_param.clone_for_update(),
+                        ));
+                    }
+                }
+            }
+            Some(params)
+        }
+        (Some(old_strukt_gpl), None) => Some(old_strukt_gpl),
+        _ => None,
+    }
+}
+
 fn process_assoc_item(
     item: syntax::ast::AssocItem,
     qual_path_ty: ast::Path,
@@ -381,10 +702,14 @@ fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option
     // <Base as Trait<GenArgs>>::ConstName;
     // FIXME : We can't rely on `make::path_qualified` for now but it would be nice to replace the following with it.
     // make::path_qualified(qual_path_ty, path_expr_segment.as_single_segment().unwrap());
-    let qualpath = qualpath(qual_path_ty, path_expr_segment);
-    let inner =
-        make::item_const(item.visibility(), item.name()?, item.ty()?, make::expr_path(qualpath))
-            .clone_for_update();
+    let qualified_path = qualified_path(qual_path_ty, path_expr_segment);
+    let inner = make::item_const(
+        item.visibility(),
+        item.name()?,
+        item.ty()?,
+        make::expr_path(qualified_path),
+    )
+    .clone_for_update();
 
     Some(AssocItem::Const(inner))
 }
@@ -395,7 +720,7 @@ fn func_assoc_item(
     base_name: &str,
 ) -> Option<AssocItem> {
     let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str());
-    let qualpath = qualpath(qual_path_ty, path_expr_segment);
+    let qualified_path = qualified_path(qual_path_ty, path_expr_segment);
 
     let call = match item.param_list() {
         // Methods and funcs should be handled separately.
@@ -413,31 +738,33 @@ fn func_assoc_item(
 
                 let param_count = l.params().count();
                 let args = convert_param_list_to_arg_list(l).clone_for_update();
-
+                let pos_after_l_paren = Position::after(args.l_paren_token()?);
                 if param_count > 0 {
                     // Add SelfParam and a TOKEN::COMMA
-                    ted::insert_all(
-                        Position::after(args.l_paren_token()?),
+                    ted::insert_all_raw(
+                        pos_after_l_paren,
                         vec![
                             NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()),
-                            NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)),
                             NodeOrToken::Token(make::token(SyntaxKind::COMMA)),
+                            NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)),
                         ],
                     );
                 } else {
                     // Add SelfParam only
-                    ted::insert(
-                        Position::after(args.l_paren_token()?),
+                    ted::insert_raw(
+                        pos_after_l_paren,
                         NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()),
                     );
                 }
 
-                make::expr_call(make::expr_path(qualpath), args)
+                make::expr_call(make::expr_path(qualified_path), args)
+            }
+            None => {
+                make::expr_call(make::expr_path(qualified_path), convert_param_list_to_arg_list(l))
             }
-            None => make::expr_call(make::expr_path(qualpath), convert_param_list_to_arg_list(l)),
         },
         None => make::expr_call(
-            make::expr_path(qualpath),
+            make::expr_path(qualified_path),
             convert_param_list_to_arg_list(make::param_list(None, Vec::new())),
         ),
     }
@@ -463,8 +790,8 @@ fn func_assoc_item(
 
 fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> Option<AssocItem> {
     let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str());
-    let qualpath = qualpath(qual_path_ty, path_expr_segment);
-    let ty = make::ty_path(qualpath);
+    let qualified_path = qualified_path(qual_path_ty, path_expr_segment);
+    let ty = make::ty_path(qualified_path);
     let ident = item.name()?.to_string();
 
     let alias = make::ty_alias(
@@ -479,7 +806,7 @@ fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> Option<Ass
     Some(AssocItem::TypeAlias(alias))
 }
 
-fn qualpath(qual_path_ty: ast::Path, path_expr_seg: ast::Path) -> ast::Path {
+fn qualified_path(qual_path_ty: ast::Path, path_expr_seg: ast::Path) -> ast::Path {
     make::path_from_text(&format!("{}::{}", qual_path_ty.to_string(), path_expr_seg.to_string()))
 }
 
@@ -510,6 +837,29 @@ impl Trait for Base {}
         );
     }
 
+    #[test]
+    fn test_self_ty() {
+        // trait whith `Self` type cannot be delegated
+        //
+        // See the function `fn f() -> Self`.
+        // It should be `fn f() -> Base` in `Base`, and `fn f() -> S` in `S`
+        check_assist_not_applicable(
+            generate_delegate_trait,
+            r#"
+struct Base(());
+struct S(B$0ase);
+trait Trait {
+    fn f() -> Self;
+}
+impl Trait for Base {
+    fn f() -> Base {
+        Base(())
+    }
+}
+"#,
+        );
+    }
+
     #[test]
     fn test_struct_struct_basic() {
         check_assist(
@@ -628,7 +978,7 @@ unsafe impl Trait for S {
     }
 
     unsafe fn a_method(&self) {
-        <Base as Trait>::a_method( &self.base )
+        <Base as Trait>::a_method(&self.base)
     }
 }
 
@@ -672,6 +1022,235 @@ where
         );
     }
 
+    #[test]
+    fn test_fields_with_generics() {
+        check_assist(
+            generate_delegate_trait,
+            r#"
+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>,
+}"#,
+            r#"
+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 : B<A>,
+}
+
+impl<T1> Trait<T1> for S {
+    fn f(a: T1) -> A {
+        <B<A> as Trait<T1>>::f(a)
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn test_generics_with_conflict_names() {
+        check_assist(
+            generate_delegate_trait,
+            r#"
+struct B<T> {
+    a: T
+}
+
+trait Trait<T> {
+    fn f(&self, a: T) -> T;
+}
+
+impl<T, T0> Trait<T> for B<T0> {
+    fn f(&self, a: T) -> T { a }
+}
+
+struct S<T> {
+    b : $0B<T>,
+}"#,
+            r#"
+struct B<T> {
+    a: T
+}
+
+trait Trait<T> {
+    fn f(&self, a: T) -> T;
+}
+
+impl<T, T0> Trait<T> for B<T0> {
+    fn f(&self, a: T) -> T { a }
+}
+
+struct S<T> {
+    b : B<T>,
+}
+
+impl<T, T1> Trait<T> for S<T1> {
+    fn f(&self, a: T) -> T {
+        <B<T1> as Trait<T>>::f(&self.b, a)
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn test_lifetime_with_conflict_names() {
+        check_assist(
+            generate_delegate_trait,
+            r#"
+struct B<'a, T> {
+    a: &'a T
+}
+
+trait Trait<T> {
+    fn f(&self, a: T) -> T;
+}
+
+impl<'a, T, T0> Trait<T> for B<'a, T0> {
+    fn f(&self, a: T) -> T { a }
+}
+
+struct S<'a, T> {
+    b : $0B<'a, T>,
+}"#,
+            r#"
+struct B<'a, T> {
+    a: &'a T
+}
+
+trait Trait<T> {
+    fn f(&self, a: T) -> T;
+}
+
+impl<'a, T, T0> Trait<T> for B<'a, T0> {
+    fn f(&self, a: T) -> T { a }
+}
+
+struct S<'a, T> {
+    b : B<'a, T>,
+}
+
+impl<'a, T, T1> Trait<T> for S<'a, T1> {
+    fn f(&self, a: T) -> T {
+        <B<'a, T1> as Trait<T>>::f(&self.b, a)
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn test_multiple_generics() {
+        check_assist(
+            generate_delegate_trait,
+            r#"
+struct B<T1, T2> {
+    a: T1,
+    b: T2
+}
+
+trait Trait<T> {
+    fn f(&self, a: T) -> T;
+}
+
+impl<T, T0> Trait<T> for B<T, T0> {
+    fn f(&self, a: T) -> T { a }
+}
+
+struct S<T> {
+    b :$0 B<i32, T>,
+}"#,
+            r#"
+struct B<T1, T2> {
+    a: T1,
+    b: T2
+}
+
+trait Trait<T> {
+    fn f(&self, a: T) -> T;
+}
+
+impl<T, T0> Trait<T> for B<T, T0> {
+    fn f(&self, a: T) -> T { a }
+}
+
+struct S<T> {
+    b : B<i32, T>,
+}
+
+impl<T1> Trait<i32> for S<T1> {
+    fn f(&self, a: i32) -> i32 {
+        <B<i32, T1> as Trait<i32>>::f(&self.b, a)
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn test_generics_multiplex() {
+        check_assist(
+            generate_delegate_trait,
+            r#"
+struct B<T> {
+    a: T
+}
+
+trait Trait<T> {
+    fn f(&self, a: T) -> T;
+}
+
+impl<T> Trait<T> for B<T> {
+    fn f(&self, a: T) -> T { a }
+}
+
+struct S<T> {
+    b : $0B<T>,
+}"#,
+            r#"
+struct B<T> {
+    a: T
+}
+
+trait Trait<T> {
+    fn f(&self, a: T) -> T;
+}
+
+impl<T> Trait<T> for B<T> {
+    fn f(&self, a: T) -> T { a }
+}
+
+struct S<T> {
+    b : B<T>,
+}
+
+impl<T0> Trait<T0> for S<T0> {
+    fn f(&self, a: T0) -> T0 {
+        <B<T0> as Trait<T0>>::f(&self.b, a)
+    }
+}"#,
+        );
+    }
+
     #[test]
     fn test_complex_without_where() {
         check_assist(
@@ -719,7 +1298,7 @@ impl<'a, T, const C: usize> Trait<'a, T, C> for S {
     }
 
     fn assoc_method(&self, p: ()) {
-        <Base as Trait<'a, T, C>>::assoc_method( &self.field , p)
+        <Base as Trait<'a, T, C>>::assoc_method(&self.field, p)
     }
 }
 
@@ -789,7 +1368,7 @@ where
     }
 
     fn assoc_method(&self, p: ()) {
-        <Base as Trait<'b, C, D>>::assoc_method( &self.field , p)
+        <Base as Trait<'b, C, D>>::assoc_method(&self.field, p)
     }
 }
 
@@ -875,7 +1454,7 @@ where
     }
 
     fn assoc_method(&self, p: ()) {
-        <Base as Trait<'b, A, B>>::assoc_method( &self.field , p)
+        <Base as Trait<'b, A, B>>::assoc_method(&self.field, p)
     }
 }
 
@@ -923,6 +1502,132 @@ where
         );
     }
 
+    #[test]
+    fn test_type_bound_with_generics_1() {
+        check_assist(
+            generate_delegate_trait,
+            r#"
+trait AnotherTrait {}
+struct B<T, T1>
+where
+    T1: AnotherTrait
+{
+    a: T,
+    b: T1
+}
+
+trait Trait<T> {
+    fn f(&self, a: T) -> T;
+}
+
+impl<T, T0, T1: AnotherTrait> Trait<T> for B<T0, T1> {
+    fn f(&self, a: T) -> T { a }
+}
+
+struct S<T, T1>
+where
+    T1: AnotherTrait
+{
+    b : $0B<T, T1>,
+}"#,
+            r#"
+trait AnotherTrait {}
+struct B<T, T1>
+where
+    T1: AnotherTrait
+{
+    a: T,
+    b: T1
+}
+
+trait Trait<T> {
+    fn f(&self, a: T) -> T;
+}
+
+impl<T, T0, T1: AnotherTrait> Trait<T> for B<T0, T1> {
+    fn f(&self, a: T) -> T { a }
+}
+
+struct S<T, T1>
+where
+    T1: AnotherTrait
+{
+    b : B<T, T1>,
+}
+
+impl<T, T2, T10> Trait<T> for S<T2, T10>
+where
+    T10: AnotherTrait
+{
+    fn f(&self, a: T) -> T {
+        <B<T2, T10> as Trait<T>>::f(&self.b, a)
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn test_type_bound_with_generics_2() {
+        check_assist(
+            generate_delegate_trait,
+            r#"
+trait AnotherTrait {}
+struct B<T1>
+where
+    T1: AnotherTrait
+{
+    b: T1
+}
+
+trait Trait<T1> {
+    fn f(&self, a: T1) -> T1;
+}
+
+impl<T, T1: AnotherTrait> Trait<T> for B<T1> {
+    fn f(&self, a: T) -> T { a }
+}
+
+struct S<T>
+where
+    T: AnotherTrait
+{
+    b : $0B<T>,
+}"#,
+            r#"
+trait AnotherTrait {}
+struct B<T1>
+where
+    T1: AnotherTrait
+{
+    b: T1
+}
+
+trait Trait<T1> {
+    fn f(&self, a: T1) -> T1;
+}
+
+impl<T, T1: AnotherTrait> Trait<T> for B<T1> {
+    fn f(&self, a: T) -> T { a }
+}
+
+struct S<T>
+where
+    T: AnotherTrait
+{
+    b : B<T>,
+}
+
+impl<T, T0> Trait<T> for S<T0>
+where
+    T0: AnotherTrait
+{
+    fn f(&self, a: T) -> T {
+        <B<T0> as Trait<T>>::f(&self.b, a)
+    }
+}"#,
+        );
+    }
+
     #[test]
     fn test_docstring_example() {
         check_assist(
@@ -975,7 +1680,7 @@ impl SomeTrait for B {
     }
 
     fn method_(&mut self) -> bool {
-        <A as SomeTrait>::method_( &mut self.a )
+        <A as SomeTrait>::method_(&mut self.a)
     }
 }
 "#,
@@ -1043,7 +1748,7 @@ impl some_module::SomeTrait for B {
     }
 
     fn method_(&mut self) -> bool {
-        <some_module::A as some_module::SomeTrait>::method_( &mut self.a )
+        <some_module::A as some_module::SomeTrait>::method_(&mut self.a)
     }
 }"#,
         )
diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index da5822bba9c..0c2331796f9 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -1153,7 +1153,7 @@ impl SomeTrait for B {
     }
 
     fn method_(&mut self) -> bool {
-        <A as SomeTrait>::method_( &mut self.a )
+        <A as SomeTrait>::method_(&mut self.a)
     }
 }
 "#####,
diff --git a/crates/ide-assists/src/utils/suggest_name.rs b/crates/ide-assists/src/utils/suggest_name.rs
index 16704d598ef..caf12008871 100644
--- a/crates/ide-assists/src/utils/suggest_name.rs
+++ b/crates/ide-assists/src/utils/suggest_name.rs
@@ -58,6 +58,32 @@ const USELESS_METHODS: &[&str] = &[
     "into_future",
 ];
 
+pub(crate) fn for_unique_generic_name(
+    name: &str,
+    existing_params: &ast::GenericParamList,
+) -> SmolStr {
+    let param_names = existing_params
+        .generic_params()
+        .map(|param| match param {
+            ast::GenericParam::TypeParam(t) => t.name().unwrap().to_string(),
+            p => p.to_string(),
+        })
+        .collect_vec();
+    let mut name = name.to_string();
+    let base_len = name.len();
+    // 4*len bytes for base, and 2 bytes for 2 digits
+    name.reserve(4 * base_len + 2);
+
+    let mut count = 0;
+    while param_names.contains(&name) {
+        name.truncate(base_len);
+        name.push_str(&count.to_string());
+        count += 1;
+    }
+
+    name.into()
+}
+
 pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr {
     let c = ty
         .type_bound_list()
diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs
index fb4c0c12691..8c1a6e6e40b 100644
--- a/crates/ide-db/src/path_transform.rs
+++ b/crates/ide-db/src/path_transform.rs
@@ -82,6 +82,34 @@ impl<'a> PathTransform<'a> {
         }
     }
 
+    pub fn impl_transformation(
+        target_scope: &'a SemanticsScope<'a>,
+        source_scope: &'a SemanticsScope<'a>,
+        impl_: hir::Impl,
+        generic_arg_list: ast::GenericArgList,
+    ) -> PathTransform<'a> {
+        PathTransform {
+            source_scope,
+            target_scope,
+            generic_def: Some(impl_.into()),
+            substs: get_type_args_from_arg_list(generic_arg_list).unwrap_or_default(),
+        }
+    }
+
+    pub fn adt_transformation(
+        target_scope: &'a SemanticsScope<'a>,
+        source_scope: &'a SemanticsScope<'a>,
+        adt: hir::Adt,
+        generic_arg_list: ast::GenericArgList,
+    ) -> PathTransform<'a> {
+        PathTransform {
+            source_scope,
+            target_scope,
+            generic_def: Some(adt.into()),
+            substs: get_type_args_from_arg_list(generic_arg_list).unwrap_or_default(),
+        }
+    }
+
     pub fn generic_transformation(
         target_scope: &'a SemanticsScope<'a>,
         source_scope: &'a SemanticsScope<'a>,
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index 37d8212042d..fd8c0d2bf71 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -13,7 +13,7 @@ use crate::{
     SyntaxNode, SyntaxToken,
 };
 
-use super::{HasArgList, HasName};
+use super::{GenericParam, HasArgList, HasName};
 
 pub trait GenericParamsOwnerEdit: ast::HasGenericParams {
     fn get_or_create_generic_param_list(&self) -> ast::GenericParamList;
@@ -272,6 +272,36 @@ impl ast::GenericParamList {
         }
     }
 
+    /// Find the params corresponded to generic arg
+    pub fn find_generic_arg(&self, generic_arg: &ast::GenericArg) -> Option<GenericParam> {
+        self.generic_params().find_map(move |param| match (&param, &generic_arg) {
+            (ast::GenericParam::LifetimeParam(a), ast::GenericArg::LifetimeArg(b)) => {
+                (a.lifetime()?.lifetime_ident_token()?.text()
+                    == b.lifetime()?.lifetime_ident_token()?.text())
+                .then_some(param)
+            }
+            (ast::GenericParam::TypeParam(a), ast::GenericArg::TypeArg(b)) => {
+                debug_assert_eq!(b.syntax().first_token(), b.syntax().last_token());
+                (a.name()?.text() == b.syntax().first_token()?.text()).then_some(param)
+            }
+            (ast::GenericParam::ConstParam(a), ast::GenericArg::TypeArg(b)) => {
+                debug_assert_eq!(b.syntax().first_token(), b.syntax().last_token());
+                (a.name()?.text() == b.syntax().first_token()?.text()).then_some(param)
+            }
+            _ => None,
+        })
+    }
+
+    /// Removes the corresponding generic arg
+    pub fn remove_generic_arg(&self, generic_arg: &ast::GenericArg) -> Option<GenericParam> {
+        let param_to_remove = self.find_generic_arg(generic_arg);
+
+        if let Some(param) = &param_to_remove {
+            self.remove_generic_param(param.clone());
+        }
+        param_to_remove
+    }
+
     /// Constructs a matching [`ast::GenericArgList`]
     pub fn to_generic_args(&self) -> ast::GenericArgList {
         let args = self.generic_params().filter_map(|param| match param {
@@ -300,6 +330,20 @@ impl ast::WhereClause {
         }
         ted::append_child(self.syntax(), predicate.syntax());
     }
+
+    pub fn remove_predicate(&self, predicate: ast::WherePred) {
+        if let Some(previous) = predicate.syntax().prev_sibling() {
+            if let Some(next_token) = previous.next_sibling_or_token() {
+                ted::remove_all(next_token..=predicate.syntax().clone().into());
+            }
+        } else if let Some(next) = predicate.syntax().next_sibling() {
+            if let Some(next_token) = next.prev_sibling_or_token() {
+                ted::remove_all(predicate.syntax().clone().into()..=next_token);
+            }
+        } else {
+            ted::remove(predicate.syntax());
+        }
+    }
 }
 
 impl ast::TypeParam {
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index ad63cc55862..2abbfc81f67 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -207,10 +207,28 @@ fn merge_gen_params(
         (None, Some(bs)) => Some(bs),
         (Some(ps), None) => Some(ps),
         (Some(ps), Some(bs)) => {
-            for b in bs.generic_params() {
-                ps.add_generic_param(b);
-            }
-            Some(ps)
+            // make sure lifetime is placed before other generic params
+            let generic_params = ps.generic_params().merge_by(bs.generic_params(), |_, b| {
+                !matches!(b, ast::GenericParam::LifetimeParam(_))
+            });
+            Some(generic_param_list(generic_params))
+        }
+    }
+}
+
+fn merge_where_clause(
+    ps: Option<ast::WhereClause>,
+    bs: Option<ast::WhereClause>,
+) -> Option<ast::WhereClause> {
+    match (ps, bs) {
+        (None, None) => None,
+        (None, Some(bs)) => Some(bs),
+        (Some(ps), None) => Some(ps),
+        (Some(ps), Some(bs)) => {
+            let preds = where_clause(std::iter::empty()).clone_for_update();
+            ps.predicates().for_each(|p| preds.add_predicate(p));
+            bs.predicates().for_each(|p| preds.add_predicate(p));
+            Some(preds)
         }
     }
 }
@@ -251,9 +269,9 @@ pub fn impl_(
 pub fn impl_trait(
     is_unsafe: bool,
     trait_gen_params: Option<ast::GenericParamList>,
-    trait_gen_args: Option<ast::GenericParamList>,
+    trait_gen_args: Option<ast::GenericArgList>,
     type_gen_params: Option<ast::GenericParamList>,
-    type_gen_args: Option<ast::GenericParamList>,
+    type_gen_args: Option<ast::GenericArgList>,
     is_negative: bool,
     path_type: ast::Type,
     ty: ast::Type,
@@ -262,15 +280,9 @@ pub fn impl_trait(
     body: Option<Vec<either::Either<ast::Attr, ast::AssocItem>>>,
 ) -> ast::Impl {
     let is_unsafe = if is_unsafe { "unsafe " } else { "" };
-    let ty_gen_args = match merge_gen_params(type_gen_params.clone(), type_gen_args) {
-        Some(pars) => pars.to_generic_args().to_string(),
-        None => String::new(),
-    };
 
-    let tr_gen_args = match merge_gen_params(trait_gen_params.clone(), trait_gen_args) {
-        Some(pars) => pars.to_generic_args().to_string(),
-        None => String::new(),
-    };
+    let trait_gen_args = trait_gen_args.map(|args| args.to_string()).unwrap_or_default();
+    let type_gen_args = type_gen_args.map(|args| args.to_string()).unwrap_or_default();
 
     let gen_params = match merge_gen_params(trait_gen_params, type_gen_params) {
         Some(pars) => pars.to_string(),
@@ -279,25 +291,15 @@ pub fn impl_trait(
 
     let is_negative = if is_negative { "! " } else { "" };
 
-    let where_clause = match (ty_where_clause, trait_where_clause) {
-        (None, None) => " ".to_string(),
-        (None, Some(tr)) => format!("\n{}\n", tr).to_string(),
-        (Some(ty), None) => format!("\n{}\n", ty).to_string(),
-        (Some(ty), Some(tr)) => {
-            let updated = ty.clone_for_update();
-            tr.predicates().for_each(|p| {
-                ty.add_predicate(p);
-            });
-            format!("\n{}\n", updated).to_string()
-        }
-    };
+    let where_clause = merge_where_clause(ty_where_clause, trait_where_clause)
+        .map_or_else(|| " ".to_string(), |wc| format!("\n{}\n", wc));
 
     let body = match body {
         Some(bd) => bd.iter().map(|elem| elem.to_string()).join(""),
         None => String::new(),
     };
 
-    ast_from_text(&format!("{is_unsafe}impl{gen_params} {is_negative}{path_type}{tr_gen_args} for {ty}{ty_gen_args}{where_clause}{{{}}}" , body))
+    ast_from_text(&format!("{is_unsafe}impl{gen_params} {is_negative}{path_type}{trait_gen_args} for {ty}{type_gen_args}{where_clause}{{{}}}" , body))
 }
 
 pub fn impl_trait_type(bounds: ast::TypeBoundList) -> ast::ImplTraitType {
@@ -922,6 +924,10 @@ pub fn type_param(name: ast::Name, bounds: Option<ast::TypeBoundList>) -> ast::T
     ast_from_text(&format!("fn f<{name}{bounds}>() {{ }}"))
 }
 
+pub fn const_param(name: ast::Name, ty: ast::Type) -> ast::ConstParam {
+    ast_from_text(&format!("fn f<const {name}: {ty}>() {{ }}"))
+}
+
 pub fn lifetime_param(lifetime: ast::Lifetime) -> ast::LifetimeParam {
     ast_from_text(&format!("fn f<{lifetime}>() {{ }}"))
 }
@@ -948,9 +954,7 @@ pub fn turbofish_generic_arg_list(
     ast_from_text(&format!("const S: T::<{args}> = ();"))
 }
 
-pub(crate) fn generic_arg_list(
-    args: impl IntoIterator<Item = ast::GenericArg>,
-) -> ast::GenericArgList {
+pub fn generic_arg_list(args: impl IntoIterator<Item = ast::GenericArg>) -> ast::GenericArgList {
     let args = args.into_iter().join(", ");
     ast_from_text(&format!("const S: T<{args}> = ();"))
 }
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index be5b954ad34..77ac8a3ca0c 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -572,6 +572,16 @@ impl ast::Item {
     }
 }
 
+impl ast::Type {
+    pub fn generic_arg_list(&self) -> Option<ast::GenericArgList> {
+        if let ast::Type::PathType(path_type) = self {
+            path_type.path()?.segment()?.generic_arg_list()
+        } else {
+            None
+        }
+    }
+}
+
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub enum FieldKind {
     Name(ast::NameRef),