@@ -13,6 +13,7 @@ use rustc_hir::{ExprKind, Node, QPath};
1313use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
1414use rustc_middle:: ty:: fast_reject:: simplify_type;
1515use rustc_middle:: ty:: print:: with_crate_prefix;
16+ use rustc_middle:: ty:: subst:: GenericArgKind ;
1617use rustc_middle:: ty:: {
1718 self , ToPolyTraitRef , ToPredicate , Ty , TyCtxt , TypeFoldable , WithConstness ,
1819} ;
@@ -383,6 +384,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
383384 return None ;
384385 } else {
385386 span = item_name. span ;
387+
388+ // issue #81576, elision of generic argument when no methode can be found in any implementation
389+ let mut ty_str_reported = ty_str. clone ( ) ;
390+ if let ty:: Adt ( _, ref generics) = actual. kind ( ) {
391+ if generics. len ( ) > 0 {
392+ let candidate_numbers: usize = self
393+ . autoderef ( span, actual)
394+ . map ( |( ty, _) | {
395+ if let ty:: Adt ( ref adt_deref, _) = ty. kind ( ) {
396+ self . tcx
397+ . inherent_impls ( adt_deref. did )
398+ . iter ( )
399+ . filter_map ( |def_id| {
400+ self . associated_item (
401+ * def_id,
402+ item_name,
403+ Namespace :: ValueNS ,
404+ )
405+ } )
406+ . count ( )
407+ } else {
408+ 0
409+ }
410+ } )
411+ . sum ( ) ;
412+ if candidate_numbers == 0 && unsatisfied_predicates. is_empty ( ) {
413+ if let Some ( ( path_string, _) ) = ty_str. split_once ( '<' ) {
414+ ty_str_reported = format ! ( "{}<" , path_string) ;
415+ for ( index, arg) in generics. iter ( ) . enumerate ( ) {
416+ let arg_replace = match arg. unpack ( ) {
417+ GenericArgKind :: Lifetime ( _) => "'_" ,
418+ GenericArgKind :: Type ( _)
419+ | GenericArgKind :: Const ( _) => "_" ,
420+ } ;
421+ ty_str_reported =
422+ format ! ( "{}{}" , ty_str_reported, arg_replace) ;
423+ if index < generics. len ( ) - 1 {
424+ ty_str_reported = format ! ( "{}, " , ty_str_reported) ;
425+ }
426+ }
427+ ty_str_reported = format ! ( "{}>" , ty_str_reported) ;
428+ }
429+ }
430+ }
431+ }
432+
386433 let mut err = struct_span_err ! (
387434 tcx. sess,
388435 span,
@@ -391,7 +438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
391438 item_kind,
392439 item_name,
393440 actual. prefix_string( self . tcx) ,
394- ty_str ,
441+ ty_str_reported ,
395442 ) ;
396443 if let Mode :: MethodCall = mode {
397444 if let SelfSource :: MethodCall ( call) = source {
@@ -449,6 +496,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
449496 let mut label_span_not_found = || {
450497 if unsatisfied_predicates. is_empty ( ) {
451498 err. span_label ( span, format ! ( "{item_kind} not found in `{ty_str}`" ) ) ;
499+ if let ty:: Adt ( ref adt, _) = rcvr_ty. kind ( ) {
500+ let mut inherent_impls_candidate = self
501+ . tcx
502+ . inherent_impls ( adt. did )
503+ . iter ( )
504+ . copied ( )
505+ . filter ( |def_id| {
506+ if let Some ( assoc) =
507+ self . associated_item ( * def_id, item_name, Namespace :: ValueNS )
508+ {
509+ // Check for both mode is the same so we avoid suggesting
510+ // incorect associated item.
511+ match ( mode, assoc. fn_has_self_parameter ) {
512+ ( Mode :: MethodCall , true ) => {
513+ if let SelfSource :: MethodCall ( _) = source {
514+ // We check that the suggest type is actually
515+ // different from the received one
516+ // So we avoid suggestion method with Box<Self>
517+ // for instance
518+ self . tcx . at ( span) . type_of ( * def_id) != actual
519+ && self . tcx . at ( span) . type_of ( * def_id)
520+ != rcvr_ty
521+ } else {
522+ false
523+ }
524+ }
525+ ( Mode :: Path , false ) => true ,
526+ _ => false ,
527+ }
528+ } else {
529+ false
530+ }
531+ } )
532+ . collect :: < Vec < _ > > ( ) ;
533+ if inherent_impls_candidate. len ( ) > 0 {
534+ inherent_impls_candidate. sort ( ) ;
535+ inherent_impls_candidate. dedup ( ) ;
536+ // number of type to shows at most.
537+ const LIMIT : usize = 3 ;
538+ let mut note = format ! ( "The {item_kind} was found for" ) ;
539+ if inherent_impls_candidate. len ( ) > 1 {
540+ for impl_item in inherent_impls_candidate. iter ( ) . take ( LIMIT - 2 )
541+ {
542+ let impl_ty = self . tcx . at ( span) . type_of ( * impl_item) ;
543+ note = format ! ( "{} {}," , note, impl_ty) ;
544+ }
545+ let impl_ty = self . tcx . at ( span) . type_of (
546+ inherent_impls_candidate
547+ [ inherent_impls_candidate. len ( ) - 1 ] ,
548+ ) ;
549+ if inherent_impls_candidate. len ( ) > LIMIT {
550+ note = format ! ( "{} {}," , note, impl_ty) ;
551+ } else {
552+ note = format ! ( "{} {} and" , note, impl_ty) ;
553+ }
554+ }
555+ let impl_ty = self
556+ . tcx
557+ . at ( span)
558+ . type_of ( * inherent_impls_candidate. last ( ) . unwrap ( ) ) ;
559+ note = format ! ( "{} {}" , note, impl_ty) ;
560+ if inherent_impls_candidate. len ( ) > LIMIT {
561+ note = format ! (
562+ "{} and {} more" ,
563+ note,
564+ inherent_impls_candidate. len( ) - LIMIT
565+ ) ;
566+ }
567+ err. note ( & format ! ( "{}." , note) ) ;
568+ }
569+ }
452570 } else {
453571 err. span_label ( span, format ! ( "{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds" ) ) ;
454572 }
0 commit comments