3131//! }
3232//! ```
3333
34- use hir:: HasAttrs ;
34+ use hir:: { HasAttrs , Name } ;
3535use ide_db:: {
3636 documentation:: HasDocs , path_transform:: PathTransform ,
3737 syntax_helpers:: insert_whitespace_into_node, traits:: get_missing_assoc_items, SymbolKind ,
3838} ;
3939use syntax:: {
40- ast:: { self , edit_in_place:: AttrsOwnerEdit , HasTypeBounds } ,
41- format_smolstr, AstNode , SmolStr , SyntaxElement , SyntaxKind , TextRange , ToSmolStr , T ,
40+ ast:: { self , edit_in_place:: AttrsOwnerEdit , make , HasGenericArgs , HasTypeBounds } ,
41+ format_smolstr, ted , AstNode , SmolStr , SyntaxElement , SyntaxKind , TextRange , ToSmolStr , T ,
4242} ;
4343use text_edit:: TextEdit ;
4444
@@ -178,12 +178,36 @@ fn add_function_impl(
178178 func : hir:: Function ,
179179 impl_def : hir:: Impl ,
180180) {
181- let fn_name = func. name ( ctx. db ) ;
181+ let fn_name = & func. name ( ctx. db ) ;
182+ let sugar: & [ _ ] = if func. is_async ( ctx. db ) {
183+ & [ AsyncSugaring :: Async , AsyncSugaring :: Desugar ]
184+ } else if func. returns_impl_future ( ctx. db ) {
185+ & [ AsyncSugaring :: Plain , AsyncSugaring :: Resugar ]
186+ } else {
187+ & [ AsyncSugaring :: Plain ]
188+ } ;
189+ for & sugaring in sugar {
190+ add_function_impl_ ( acc, ctx, replacement_range, func, impl_def, fn_name, sugaring) ;
191+ }
192+ }
182193
183- let is_async = func. is_async ( ctx. db ) ;
194+ fn add_function_impl_ (
195+ acc : & mut Completions ,
196+ ctx : & CompletionContext < ' _ > ,
197+ replacement_range : TextRange ,
198+ func : hir:: Function ,
199+ impl_def : hir:: Impl ,
200+ fn_name : & Name ,
201+ async_sugaring : AsyncSugaring ,
202+ ) {
203+ let async_ = if let AsyncSugaring :: Async | AsyncSugaring :: Resugar = async_sugaring {
204+ "async "
205+ } else {
206+ ""
207+ } ;
184208 let label = format_smolstr ! (
185209 "{}fn {}({})" ,
186- if is_async { "async " } else { "" } ,
210+ async_ ,
187211 fn_name. display( ctx. db, ctx. edition) ,
188212 if func. assoc_fn_params( ctx. db) . is_empty( ) { "" } else { ".." }
189213 ) ;
@@ -195,22 +219,14 @@ fn add_function_impl(
195219 } ) ;
196220
197221 let mut item = CompletionItem :: new ( completion_kind, replacement_range, label, ctx. edition ) ;
198- item. lookup_by ( format ! (
199- "{}fn {}" ,
200- if is_async { "async " } else { "" } ,
201- fn_name. display( ctx. db, ctx. edition)
202- ) )
203- . set_documentation ( func. docs ( ctx. db ) )
204- . set_relevance ( CompletionRelevance { is_item_from_trait : true , ..Default :: default ( ) } ) ;
222+ item. lookup_by ( format ! ( "{}fn {}" , async_, fn_name. display( ctx. db, ctx. edition) ) )
223+ . set_documentation ( func. docs ( ctx. db ) )
224+ . set_relevance ( CompletionRelevance { is_item_from_trait : true , ..Default :: default ( ) } ) ;
205225
206226 if let Some ( source) = ctx. sema . source ( func) {
207- let assoc_item = ast:: AssocItem :: Fn ( source. value ) ;
208- if let Some ( transformed_item) = get_transformed_assoc_item ( ctx, assoc_item, impl_def) {
209- let transformed_fn = match transformed_item {
210- ast:: AssocItem :: Fn ( func) => func,
211- _ => unreachable ! ( ) ,
212- } ;
213-
227+ if let Some ( transformed_fn) =
228+ get_transformed_fn ( ctx, source. value , impl_def, async_sugaring)
229+ {
214230 let function_decl = function_declaration ( & transformed_fn, source. file_id . is_macro ( ) ) ;
215231 match ctx. config . snippet_cap {
216232 Some ( cap) => {
@@ -227,6 +243,14 @@ fn add_function_impl(
227243 }
228244}
229245
246+ #[ derive( Copy , Clone ) ]
247+ enum AsyncSugaring {
248+ Desugar ,
249+ Resugar ,
250+ Async ,
251+ Plain ,
252+ }
253+
230254/// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc.
231255fn get_transformed_assoc_item (
232256 ctx : & CompletionContext < ' _ > ,
@@ -251,6 +275,82 @@ fn get_transformed_assoc_item(
251275 Some ( assoc_item)
252276}
253277
278+ /// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc.
279+ fn get_transformed_fn (
280+ ctx : & CompletionContext < ' _ > ,
281+ fn_ : ast:: Fn ,
282+ impl_def : hir:: Impl ,
283+ async_ : AsyncSugaring ,
284+ ) -> Option < ast:: Fn > {
285+ let trait_ = impl_def. trait_ ( ctx. db ) ?;
286+ let source_scope = & ctx. sema . scope ( fn_. syntax ( ) ) ?;
287+ let target_scope = & ctx. sema . scope ( ctx. sema . source ( impl_def) ?. syntax ( ) . value ) ?;
288+ let transform = PathTransform :: trait_impl (
289+ target_scope,
290+ source_scope,
291+ trait_,
292+ ctx. sema . source ( impl_def) ?. value ,
293+ ) ;
294+
295+ let fn_ = fn_. clone_for_update ( ) ;
296+ // FIXME: Paths in nested macros are not handled well. See
297+ // `macro_generated_assoc_item2` test.
298+ transform. apply ( fn_. syntax ( ) ) ;
299+ fn_. remove_attrs_and_docs ( ) ;
300+ match async_ {
301+ AsyncSugaring :: Desugar => {
302+ match fn_. ret_type ( ) {
303+ Some ( ret_ty) => {
304+ let ty = ret_ty. ty ( ) ?;
305+ ted:: replace (
306+ ty. syntax ( ) ,
307+ make:: ty ( & format ! ( "impl Future<Output = {ty}>" ) )
308+ . syntax ( )
309+ . clone_for_update ( ) ,
310+ ) ;
311+ }
312+ None => ted:: append_child (
313+ fn_. param_list ( ) ?. syntax ( ) ,
314+ make:: ret_type ( make:: ty ( "impl Future<Output = ()>" ) )
315+ . syntax ( )
316+ . clone_for_update ( ) ,
317+ ) ,
318+ }
319+ fn_. async_token ( ) . unwrap ( ) . detach ( ) ;
320+ }
321+ AsyncSugaring :: Resugar => {
322+ let ty = fn_. ret_type ( ) ?. ty ( ) ?;
323+ match & ty {
324+ // best effort guessing here
325+ ast:: Type :: ImplTraitType ( t) => {
326+ let output = t. type_bound_list ( ) ?. bounds ( ) . find_map ( |b| match b. ty ( ) ? {
327+ ast:: Type :: PathType ( p) => {
328+ let p = p. path ( ) ?. segment ( ) ?;
329+ if p. name_ref ( ) ?. text ( ) != "Future" {
330+ return None ;
331+ }
332+ match p. generic_arg_list ( ) ?. generic_args ( ) . next ( ) ? {
333+ ast:: GenericArg :: AssocTypeArg ( a)
334+ if a. name_ref ( ) ?. text ( ) == "Output" =>
335+ {
336+ a. ty ( )
337+ }
338+ _ => None ,
339+ }
340+ }
341+ _ => None ,
342+ } ) ?;
343+ ted:: replace ( ty. syntax ( ) , output. syntax ( ) ) ;
344+ }
345+ _ => ( ) ,
346+ }
347+ ted:: prepend_child ( fn_. syntax ( ) , make:: token ( T ! [ async ] ) ) ;
348+ }
349+ AsyncSugaring :: Async | AsyncSugaring :: Plain => ( ) ,
350+ }
351+ Some ( fn_)
352+ }
353+
254354fn add_type_alias_impl (
255355 acc : & mut Completions ,
256356 ctx : & CompletionContext < ' _ > ,
@@ -1401,6 +1501,134 @@ trait Tr {
14011501impl Tr for () {
14021502 type Item = $0;
14031503}
1504+ "# ,
1505+ ) ;
1506+ }
1507+
1508+ #[ test]
1509+ fn impl_fut ( ) {
1510+ check_edit (
1511+ "fn foo" ,
1512+ r#"
1513+ //- minicore: future, send, sized
1514+ use core::future::Future;
1515+
1516+ trait DesugaredAsyncTrait {
1517+ fn foo(&self) -> impl Future<Output = usize> + Send;
1518+ }
1519+
1520+ impl DesugaredAsyncTrait for () {
1521+ $0
1522+ }
1523+ "# ,
1524+ r#"
1525+ use core::future::Future;
1526+
1527+ trait DesugaredAsyncTrait {
1528+ fn foo(&self) -> impl Future<Output = usize> + Send;
1529+ }
1530+
1531+ impl DesugaredAsyncTrait for () {
1532+ fn foo(&self) -> impl Future<Output = usize> + Send {
1533+ $0
1534+ }
1535+ }
1536+ "# ,
1537+ ) ;
1538+ }
1539+
1540+ #[ test]
1541+ fn impl_fut_resugared ( ) {
1542+ check_edit (
1543+ "async fn foo" ,
1544+ r#"
1545+ //- minicore: future, send, sized
1546+ use core::future::Future;
1547+
1548+ trait DesugaredAsyncTrait {
1549+ fn foo(&self) -> impl Future<Output = usize> + Send;
1550+ }
1551+
1552+ impl DesugaredAsyncTrait for () {
1553+ $0
1554+ }
1555+ "# ,
1556+ r#"
1557+ use core::future::Future;
1558+
1559+ trait DesugaredAsyncTrait {
1560+ fn foo(&self) -> impl Future<Output = usize> + Send;
1561+ }
1562+
1563+ impl DesugaredAsyncTrait for () {
1564+ async fn foo(&self) -> usize {
1565+ $0
1566+ }
1567+ }
1568+ "# ,
1569+ ) ;
1570+ }
1571+
1572+ #[ test]
1573+ fn async_desugared ( ) {
1574+ check_edit (
1575+ "fn foo" ,
1576+ r#"
1577+ //- minicore: future, send, sized
1578+ use core::future::Future;
1579+
1580+ trait DesugaredAsyncTrait {
1581+ async fn foo(&self) -> usize;
1582+ }
1583+
1584+ impl DesugaredAsyncTrait for () {
1585+ $0
1586+ }
1587+ "# ,
1588+ r#"
1589+ use core::future::Future;
1590+
1591+ trait DesugaredAsyncTrait {
1592+ async fn foo(&self) -> usize;
1593+ }
1594+
1595+ impl DesugaredAsyncTrait for () {
1596+ fn foo(&self) -> impl Future<Output = usize> {
1597+ $0
1598+ }
1599+ }
1600+ "# ,
1601+ ) ;
1602+ }
1603+
1604+ #[ test]
1605+ fn async_ ( ) {
1606+ check_edit (
1607+ "async fn foo" ,
1608+ r#"
1609+ //- minicore: future, send, sized
1610+ use core::future::Future;
1611+
1612+ trait DesugaredAsyncTrait {
1613+ async fn foo(&self) -> usize;
1614+ }
1615+
1616+ impl DesugaredAsyncTrait for () {
1617+ $0
1618+ }
1619+ "# ,
1620+ r#"
1621+ use core::future::Future;
1622+
1623+ trait DesugaredAsyncTrait {
1624+ async fn foo(&self) -> usize;
1625+ }
1626+
1627+ impl DesugaredAsyncTrait for () {
1628+ async fn foo(&self) -> usize {
1629+ $0
1630+ }
1631+ }
14041632"# ,
14051633 ) ;
14061634 }
0 commit comments