@@ -409,6 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
409409 err. downgrade_to_delayed_bug ( ) ;
410410 }
411411
412+ self . find_builder_fn ( & mut err, rcvr_ty, source) ;
412413 if tcx. ty_is_opaque_future ( rcvr_ty) && item_name. name == sym:: poll {
413414 err. help ( format ! (
414415 "method `poll` found on `Pin<&mut {ty_str}>`, \
@@ -1407,6 +1408,93 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14071408 }
14081409 }
14091410
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+
14101498 /// Suggest calling `Ty::method` if `.method()` isn't found because the method
14111499 /// doesn't take a `self` receiver.
14121500 fn suggest_associated_call_syntax (
0 commit comments