31
31
//! }
32
32
//! ```
33
33
34
- use hir:: HasAttrs ;
34
+ use hir:: { HasAttrs , Name } ;
35
35
use ide_db:: {
36
36
documentation:: HasDocs , path_transform:: PathTransform ,
37
37
syntax_helpers:: insert_whitespace_into_node, traits:: get_missing_assoc_items, SymbolKind ,
38
38
} ;
39
39
use 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 ,
42
42
} ;
43
43
use text_edit:: TextEdit ;
44
44
@@ -178,12 +178,36 @@ fn add_function_impl(
178
178
func : hir:: Function ,
179
179
impl_def : hir:: Impl ,
180
180
) {
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
+ }
182
193
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
+ } ;
184
208
let label = format_smolstr ! (
185
209
"{}fn {}({})" ,
186
- if is_async { "async " } else { "" } ,
210
+ async_ ,
187
211
fn_name. display( ctx. db, ctx. edition) ,
188
212
if func. assoc_fn_params( ctx. db) . is_empty( ) { "" } else { ".." }
189
213
) ;
@@ -195,22 +219,14 @@ fn add_function_impl(
195
219
} ) ;
196
220
197
221
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 ( ) } ) ;
205
225
206
226
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
+ {
214
230
let function_decl = function_declaration ( & transformed_fn, source. file_id . is_macro ( ) ) ;
215
231
match ctx. config . snippet_cap {
216
232
Some ( cap) => {
@@ -227,6 +243,14 @@ fn add_function_impl(
227
243
}
228
244
}
229
245
246
+ #[ derive( Copy , Clone ) ]
247
+ enum AsyncSugaring {
248
+ Desugar ,
249
+ Resugar ,
250
+ Async ,
251
+ Plain ,
252
+ }
253
+
230
254
/// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc.
231
255
fn get_transformed_assoc_item (
232
256
ctx : & CompletionContext < ' _ > ,
@@ -251,6 +275,82 @@ fn get_transformed_assoc_item(
251
275
Some ( assoc_item)
252
276
}
253
277
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
+
254
354
fn add_type_alias_impl (
255
355
acc : & mut Completions ,
256
356
ctx : & CompletionContext < ' _ > ,
@@ -1401,6 +1501,134 @@ trait Tr {
1401
1501
impl Tr for () {
1402
1502
type Item = $0;
1403
1503
}
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
+ }
1404
1632
"# ,
1405
1633
) ;
1406
1634
}
0 commit comments