@@ -408,6 +408,86 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
408408 err. downgrade_to_delayed_bug ( ) ;
409409 }
410410
411+ if let ( ty:: Adt ( adt_def, _) , SelfSource :: QPath ( _) ) = ( rcvr_ty. kind ( ) , source) {
412+ // Look at all the associated functions without receivers in the type's inherent impls
413+ // to look for builders that return `Self`, `Option<Self>` or `Result<Self, _>`.
414+ let mut items = self
415+ . tcx
416+ . inherent_impls ( adt_def. did ( ) )
417+ . iter ( )
418+ . flat_map ( |i| self . tcx . associated_items ( i) . in_definition_order ( ) )
419+ . filter ( |item| {
420+ // Only assoc fn with no receivers.
421+ matches ! ( item. kind, ty:: AssocKind :: Fn ) && !item. fn_has_self_parameter
422+ } )
423+ . filter_map ( |item| {
424+ // Only assoc fns that return `Self`, `Option<Self>` or `Result<Self, _>`.
425+ let ret_ty = self . tcx . fn_sig ( item. def_id ) . skip_binder ( ) . output ( ) ;
426+ let ret_ty = self . tcx . erase_late_bound_regions ( ret_ty) ;
427+ let ty:: Adt ( def, args) = ret_ty. kind ( ) else {
428+ return None ;
429+ } ;
430+ // Check for `-> Self`
431+ if self . can_eq ( self . param_env , ret_ty, rcvr_ty) {
432+ return Some ( ( item. def_id , ret_ty) ) ;
433+ }
434+ // Check for `-> Option<Self>` or `-> Result<Self, _>`
435+ if ![
436+ self . tcx . lang_items ( ) . option_type ( ) ,
437+ self . tcx . get_diagnostic_item ( sym:: Result ) ,
438+ ]
439+ . contains ( & Some ( def. did ( ) ) )
440+ {
441+ return None ;
442+ }
443+ let arg = args. get ( 0 ) ?. expect_ty ( ) ;
444+ if self . can_eq ( self . param_env , rcvr_ty, arg) {
445+ Some ( ( item. def_id , ret_ty) )
446+ } else {
447+ None
448+ }
449+ } )
450+ . collect :: < Vec < _ > > ( ) ;
451+ let post = if items. len ( ) > 5 {
452+ let items_len = items. len ( ) ;
453+ items. truncate ( 4 ) ;
454+ format ! ( "\n and {} others" , items_len - 4 )
455+ } else {
456+ String :: new ( )
457+ } ;
458+ match & items[ ..] {
459+ [ ] => { }
460+ [ ( def_id, ret_ty) ] => {
461+ err. span_note (
462+ self . tcx . def_span ( def_id) ,
463+ format ! (
464+ "if you're trying to build a new `{rcvr_ty}`, consider using `{}` \
465+ which returns `{ret_ty}`",
466+ self . tcx. def_path_str( def_id) ,
467+ ) ,
468+ ) ;
469+ }
470+ _ => {
471+ let span: MultiSpan = items
472+ . iter ( )
473+ . map ( |( def_id, _) | self . tcx . def_span ( def_id) )
474+ . collect :: < Vec < Span > > ( )
475+ . into ( ) ;
476+ err. span_note (
477+ span,
478+ format ! (
479+ "if you're trying to build a new `{rcvr_ty}` consider using one of the \
480+ following associated functions:\n {}{post}",
481+ items
482+ . iter( )
483+ . map( |( def_id, _ret_ty) | self . tcx. def_path_str( def_id) )
484+ . collect:: <Vec <String >>( )
485+ . join( "\n " )
486+ ) ,
487+ ) ;
488+ }
489+ }
490+ } ;
411491 if tcx. ty_is_opaque_future ( rcvr_ty) && item_name. name == sym:: poll {
412492 err. help ( format ! (
413493 "method `poll` found on `Pin<&mut {ty_str}>`, \
0 commit comments