@@ -409,6 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
409
409
err. downgrade_to_delayed_bug ( ) ;
410
410
}
411
411
412
+ self . find_builder_fn ( & mut err, rcvr_ty, source) ;
412
413
if tcx. ty_is_opaque_future ( rcvr_ty) && item_name. name == sym:: poll {
413
414
err. help ( format ! (
414
415
"method `poll` found on `Pin<&mut {ty_str}>`, \
@@ -1407,6 +1408,93 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1407
1408
}
1408
1409
}
1409
1410
1411
+ /// Look at all the associated functions without receivers in the type's inherent impls
1412
+ /// to look for builders that return `Self`, `Option<Self>` or `Result<Self, _>`.
1413
+ fn find_builder_fn ( & self , err : & mut Diagnostic , rcvr_ty : Ty < ' tcx > , source : SelfSource < ' tcx > ) {
1414
+ let ty:: Adt ( adt_def, _) = rcvr_ty. kind ( ) else {
1415
+ return ;
1416
+ } ;
1417
+ let SelfSource :: QPath ( ty) = source else {
1418
+ return ;
1419
+ } ;
1420
+ let hir = self . tcx . hir ( ) ;
1421
+ if let Some ( Node :: Pat ( _) ) = hir. find ( hir. parent_id ( ty. hir_id ) ) {
1422
+ // Do not suggest a fn call when a pattern is expected.
1423
+ return ;
1424
+ }
1425
+ let mut items = self
1426
+ . tcx
1427
+ . inherent_impls ( adt_def. did ( ) )
1428
+ . iter ( )
1429
+ . flat_map ( |i| self . tcx . associated_items ( i) . in_definition_order ( ) )
1430
+ // Only assoc fn with no receivers.
1431
+ . filter ( |item| matches ! ( item. kind, ty:: AssocKind :: Fn ) && !item. fn_has_self_parameter )
1432
+ . filter_map ( |item| {
1433
+ // Only assoc fns that return `Self`, `Option<Self>` or `Result<Self, _>`.
1434
+ let ret_ty = self . tcx . fn_sig ( item. def_id ) . skip_binder ( ) . output ( ) ;
1435
+ let ret_ty = self . tcx . erase_late_bound_regions ( ret_ty) ;
1436
+ let ty:: Adt ( def, args) = ret_ty. kind ( ) else {
1437
+ return None ;
1438
+ } ;
1439
+ // Check for `-> Self`
1440
+ if self . can_eq ( self . param_env , ret_ty, rcvr_ty) {
1441
+ return Some ( ( item. def_id , ret_ty) ) ;
1442
+ }
1443
+ // Check for `-> Option<Self>` or `-> Result<Self, _>`
1444
+ if ![ self . tcx . lang_items ( ) . option_type ( ) , self . tcx . get_diagnostic_item ( sym:: Result ) ]
1445
+ . contains ( & Some ( def. did ( ) ) )
1446
+ {
1447
+ return None ;
1448
+ }
1449
+ let arg = args. get ( 0 ) ?. expect_ty ( ) ;
1450
+ if self . can_eq ( self . param_env , rcvr_ty, arg) {
1451
+ Some ( ( item. def_id , ret_ty) )
1452
+ } else {
1453
+ None
1454
+ }
1455
+ } )
1456
+ . collect :: < Vec < _ > > ( ) ;
1457
+ let post = if items. len ( ) > 5 {
1458
+ let items_len = items. len ( ) ;
1459
+ items. truncate ( 4 ) ;
1460
+ format ! ( "\n and {} others" , items_len - 4 )
1461
+ } else {
1462
+ String :: new ( )
1463
+ } ;
1464
+ match & items[ ..] {
1465
+ [ ] => { }
1466
+ [ ( def_id, ret_ty) ] => {
1467
+ err. span_note (
1468
+ self . tcx . def_span ( def_id) ,
1469
+ format ! (
1470
+ "if you're trying to build a new `{rcvr_ty}`, consider using `{}` which \
1471
+ returns `{ret_ty}`",
1472
+ self . tcx. def_path_str( def_id) ,
1473
+ ) ,
1474
+ ) ;
1475
+ }
1476
+ _ => {
1477
+ let span: MultiSpan = items
1478
+ . iter ( )
1479
+ . map ( |( def_id, _) | self . tcx . def_span ( def_id) )
1480
+ . collect :: < Vec < Span > > ( )
1481
+ . into ( ) ;
1482
+ err. span_note (
1483
+ span,
1484
+ format ! (
1485
+ "if you're trying to build a new `{rcvr_ty}` consider using one of the \
1486
+ following associated functions:\n {}{post}",
1487
+ items
1488
+ . iter( )
1489
+ . map( |( def_id, _ret_ty) | self . tcx. def_path_str( def_id) )
1490
+ . collect:: <Vec <String >>( )
1491
+ . join( "\n " )
1492
+ ) ,
1493
+ ) ;
1494
+ }
1495
+ }
1496
+ }
1497
+
1410
1498
/// Suggest calling `Ty::method` if `.method()` isn't found because the method
1411
1499
/// doesn't take a `self` receiver.
1412
1500
fn suggest_associated_call_syntax (
0 commit comments