feat(ide-completion): extra sugar auto-completion `async fn ...` in `impl trait` for `async fn in trait` that's defined in desugar form
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 96a6e6f..74ec522 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2207,6 +2207,53 @@
         db.function_data(self.id).is_async()
     }
 
+    /// Whether this function is a `fn` that returns `impl Future`.
+    pub fn is_desugar_async(self, db: &dyn HirDatabase) -> bool {
+        if self.is_async(db) || self.is_const(db) {
+            return false;
+        }
+
+        let Some(impl_traits) = self.ret_type(db).as_impl_traits(db) else { return false };
+
+        let Some(future_trait_id) =
+            db.lang_item(self.ty(db).env.krate, LangItem::Future).and_then(|t| t.as_trait())
+        else {
+            return false;
+        };
+
+        let Some(size_trait_id) =
+            db.lang_item(self.ty(db).env.krate, LangItem::Sized).and_then(|t| t.as_trait())
+        else {
+            return false;
+        };
+
+        let Some(sync_trait_id) =
+            db.lang_item(self.ty(db).env.krate, LangItem::Sync).and_then(|t| t.as_trait())
+        else {
+            return false;
+        };
+
+        // TODO: There's no `LangItem::Send`. How do we get the id of `Send` trait?
+        // let Some(send_trait_id) = db.lang_item(self.ty(db).env.krate, LangItem::Send).and_then(|t| t.as_trait()) else {
+        //     eprint!("no future_trait_id\n");
+        //     return false
+        // };
+
+        let allowed_to_leaked_types = vec![size_trait_id, sync_trait_id];
+
+        let mut has_impl_future = false;
+        let mut has_types_not_allow_to_leaked = false;
+        for impl_trait in impl_traits {
+            if impl_trait.id == future_trait_id {
+                has_impl_future = true;
+            } else if !allowed_to_leaked_types.contains(&impl_trait.id) {
+                has_types_not_allow_to_leaked = true;
+            }
+        }
+
+        has_impl_future && !has_types_not_allow_to_leaked
+    }
+
     /// Does this function have `#[test]` attribute?
     pub fn is_test(self, db: &dyn HirDatabase) -> bool {
         db.function_data(self.id).attrs.is_test()
diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs
index fc6e1eb..7887a87 100644
--- a/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -210,7 +210,7 @@
                 ast::AssocItem::Fn(func) => func,
                 _ => unreachable!(),
             };
-
+            // TODO: need `function_decl` that unwraps future in the return type
             let function_decl = function_declaration(&transformed_fn, source.file_id.is_macro());
             match ctx.config.snippet_cap {
                 Some(cap) => {
@@ -225,6 +225,42 @@
             item.add_to(acc, ctx.db);
         }
     }
+
+    eprint!("is_desugar_async: {}", func.is_desugar_async(ctx.db));
+    if func.is_desugar_async(ctx.db) {
+        let label = format_smolstr!(
+            "async fn {}({})",
+            fn_name.display(ctx.db),
+            if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." }
+        );
+        let mut item = CompletionItem::new(completion_kind, replacement_range, label);
+        item.lookup_by(format!("async fn {}", fn_name.display(ctx.db)))
+            .set_documentation(func.docs(ctx.db))
+            .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() });
+        if let Some(source) = ctx.sema.source(func) {
+            let assoc_item = ast::AssocItem::Fn(source.value);
+            if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
+                let transformed_fn = match transformed_item {
+                    ast::AssocItem::Fn(func) => func,
+                    _ => unreachable!(),
+                };
+
+                let function_decl =
+                    function_declaration(&transformed_fn, source.file_id.is_macro());
+                match ctx.config.snippet_cap {
+                    Some(cap) => {
+                        let snippet = format!("{function_decl} {{\n    $0\n}}");
+                        item.snippet_edit(cap, TextEdit::replace(replacement_range, snippet));
+                    }
+                    None => {
+                        let header = format!("{function_decl} {{");
+                        item.text_edit(TextEdit::replace(replacement_range, header));
+                    }
+                };
+                item.add_to(acc, ctx.db);
+            }
+        }
+    }
 }
 
 /// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc.