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