@@ -398,122 +398,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
398398 custom_span_label = true ;
399399 }
400400 if static_candidates. len ( ) == 1 {
401- let mut has_unsuggestable_args = false ;
402- let ty_str = if let Some ( CandidateSource :: Impl ( impl_did) ) =
403- static_candidates. get ( 0 )
404- {
405- // When the "method" is resolved through dereferencing, we really want the
406- // original type that has the associated function for accurate suggestions.
407- // (#61411)
408- let ty = tcx. at ( span) . type_of ( * impl_did) ;
409- match ( & ty. peel_refs ( ) . kind ( ) , & rcvr_ty. peel_refs ( ) . kind ( ) ) {
410- ( ty:: Adt ( def, _) , ty:: Adt ( def_actual, substs) ) if def == def_actual => {
411- // If there are any inferred arguments, (`{integer}`), we should replace
412- // them with underscores to allow the compiler to infer them
413- let infer_substs: Vec < GenericArg < ' _ > > = substs
414- . into_iter ( )
415- . map ( |arg| {
416- if !arg. is_suggestable ( tcx, true ) {
417- has_unsuggestable_args = true ;
418- match arg. unpack ( ) {
419- GenericArgKind :: Lifetime ( _) => self
420- . next_region_var ( RegionVariableOrigin :: MiscVariable (
421- rustc_span:: DUMMY_SP ,
422- ) )
423- . into ( ) ,
424- GenericArgKind :: Type ( _) => self
425- . next_ty_var ( TypeVariableOrigin {
426- span : rustc_span:: DUMMY_SP ,
427- kind : TypeVariableOriginKind :: MiscVariable ,
428- } )
429- . into ( ) ,
430- GenericArgKind :: Const ( arg) => self
431- . next_const_var (
432- arg. ty ( ) ,
433- ConstVariableOrigin {
434- span : rustc_span:: DUMMY_SP ,
435- kind : ConstVariableOriginKind :: MiscVariable ,
436- } ,
437- )
438- . into ( ) ,
439- }
440- } else {
441- arg
442- }
443- } )
444- . collect :: < Vec < _ > > ( ) ;
445-
446- tcx. value_path_str_with_substs (
447- def_actual. did ( ) ,
448- tcx. intern_substs ( & infer_substs) ,
449- )
450- }
451- _ => self . ty_to_value_string ( ty. peel_refs ( ) ) ,
452- }
453- } else {
454- self . ty_to_value_string ( rcvr_ty. peel_refs ( ) )
455- } ;
456- if let SelfSource :: MethodCall ( _) = source {
457- let first_arg = if let Some ( CandidateSource :: Impl ( impl_did) ) = static_candidates. get ( 0 ) &&
458- let Some ( assoc) = self . associated_value ( * impl_did, item_name) {
459- let sig = self . tcx . fn_sig ( assoc. def_id ) ;
460- if let Some ( first) = sig. inputs ( ) . skip_binder ( ) . get ( 0 ) {
461- if first. peel_refs ( ) == rcvr_ty. peel_refs ( ) {
462- None
463- } else {
464- Some ( if first. is_region_ptr ( ) {
465- if first. is_mutable_ptr ( ) { "&mut " } else { "&" }
466- } else {
467- ""
468- } )
469- }
470- } else {
471- None
472- }
473- } else {
474- None
475- } ;
476- let mut applicability = Applicability :: MachineApplicable ;
477- let args = if let Some ( ( receiver, args) ) = args {
478- // The first arg is the same kind as the receiver
479- let explicit_args = if first_arg. is_some ( ) {
480- std:: iter:: once ( receiver) . chain ( args. iter ( ) ) . collect :: < Vec < _ > > ( )
481- } else {
482- // There is no `Self` kind to infer the arguments from
483- if has_unsuggestable_args {
484- applicability = Applicability :: HasPlaceholders ;
485- }
486- args. iter ( ) . collect ( )
487- } ;
488- format ! (
489- "({}{})" ,
490- first_arg. unwrap_or( "" ) ,
491- explicit_args
492- . iter( )
493- . map( |arg| tcx
494- . sess
495- . source_map( )
496- . span_to_snippet( arg. span)
497- . unwrap_or_else( |_| {
498- applicability = Applicability :: HasPlaceholders ;
499- "_" . to_owned( )
500- } ) )
501- . collect:: <Vec <_>>( )
502- . join( ", " ) ,
503- )
504- } else {
505- applicability = Applicability :: HasPlaceholders ;
506- "(...)" . to_owned ( )
507- } ;
508- err. span_suggestion (
509- sugg_span,
510- "use associated function syntax instead" ,
511- format ! ( "{}::{}{}" , ty_str, item_name, args) ,
512- applicability,
513- ) ;
514- } else {
515- err. help ( & format ! ( "try with `{}::{}`" , ty_str, item_name, ) ) ;
516- }
401+ self . suggest_associated_call_syntax (
402+ & mut err,
403+ & static_candidates,
404+ rcvr_ty,
405+ source,
406+ item_name,
407+ args,
408+ sugg_span,
409+ ) ;
517410
518411 report_candidates ( span, & mut err, & mut static_candidates, sugg_span) ;
519412 } else if static_candidates. len ( ) > 1 {
@@ -1180,6 +1073,137 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11801073 None
11811074 }
11821075
1076+ /// Suggest calling `Ty::method` if `.method()` isn't found because the method
1077+ /// doesn't take a `self` receiver.
1078+ fn suggest_associated_call_syntax (
1079+ & self ,
1080+ err : & mut Diagnostic ,
1081+ static_candidates : & Vec < CandidateSource > ,
1082+ rcvr_ty : Ty < ' tcx > ,
1083+ source : SelfSource < ' tcx > ,
1084+ item_name : Ident ,
1085+ args : Option < ( & hir:: Expr < ' tcx > , & [ hir:: Expr < ' tcx > ] ) > ,
1086+ sugg_span : Span ,
1087+ ) {
1088+ let mut has_unsuggestable_args = false ;
1089+ let ty_str = if let Some ( CandidateSource :: Impl ( impl_did) ) = static_candidates. get ( 0 ) {
1090+ // When the "method" is resolved through dereferencing, we really want the
1091+ // original type that has the associated function for accurate suggestions.
1092+ // (#61411)
1093+ let ty = self . tcx . type_of ( * impl_did) ;
1094+ match ( & ty. peel_refs ( ) . kind ( ) , & rcvr_ty. peel_refs ( ) . kind ( ) ) {
1095+ ( ty:: Adt ( def, _) , ty:: Adt ( def_actual, substs) ) if def == def_actual => {
1096+ // If there are any inferred arguments, (`{integer}`), we should replace
1097+ // them with underscores to allow the compiler to infer them
1098+ let infer_substs: Vec < GenericArg < ' _ > > = substs
1099+ . into_iter ( )
1100+ . map ( |arg| {
1101+ if !arg. is_suggestable ( self . tcx , true ) {
1102+ has_unsuggestable_args = true ;
1103+ match arg. unpack ( ) {
1104+ GenericArgKind :: Lifetime ( _) => self
1105+ . next_region_var ( RegionVariableOrigin :: MiscVariable (
1106+ rustc_span:: DUMMY_SP ,
1107+ ) )
1108+ . into ( ) ,
1109+ GenericArgKind :: Type ( _) => self
1110+ . next_ty_var ( TypeVariableOrigin {
1111+ span : rustc_span:: DUMMY_SP ,
1112+ kind : TypeVariableOriginKind :: MiscVariable ,
1113+ } )
1114+ . into ( ) ,
1115+ GenericArgKind :: Const ( arg) => self
1116+ . next_const_var (
1117+ arg. ty ( ) ,
1118+ ConstVariableOrigin {
1119+ span : rustc_span:: DUMMY_SP ,
1120+ kind : ConstVariableOriginKind :: MiscVariable ,
1121+ } ,
1122+ )
1123+ . into ( ) ,
1124+ }
1125+ } else {
1126+ arg
1127+ }
1128+ } )
1129+ . collect :: < Vec < _ > > ( ) ;
1130+
1131+ self . tcx . value_path_str_with_substs (
1132+ def_actual. did ( ) ,
1133+ self . tcx . intern_substs ( & infer_substs) ,
1134+ )
1135+ }
1136+ _ => self . ty_to_value_string ( ty. peel_refs ( ) ) ,
1137+ }
1138+ } else {
1139+ self . ty_to_value_string ( rcvr_ty. peel_refs ( ) )
1140+ } ;
1141+ if let SelfSource :: MethodCall ( _) = source {
1142+ let first_arg = if let Some ( CandidateSource :: Impl ( impl_did) ) = static_candidates. get ( 0 )
1143+ && let Some ( assoc) = self . associated_value ( * impl_did, item_name)
1144+ && assoc. kind == ty:: AssocKind :: Fn
1145+ {
1146+ let sig = self . tcx . fn_sig ( assoc. def_id ) ;
1147+ if let Some ( first) = sig. inputs ( ) . skip_binder ( ) . get ( 0 ) {
1148+ if first. peel_refs ( ) == rcvr_ty. peel_refs ( ) {
1149+ None
1150+ } else {
1151+ Some ( if first. is_region_ptr ( ) {
1152+ if first. is_mutable_ptr ( ) { "&mut " } else { "&" }
1153+ } else {
1154+ ""
1155+ } )
1156+ }
1157+ } else {
1158+ None
1159+ }
1160+ } else {
1161+ None
1162+ } ;
1163+ let mut applicability = Applicability :: MachineApplicable ;
1164+ let args = if let Some ( ( receiver, args) ) = args {
1165+ // The first arg is the same kind as the receiver
1166+ let explicit_args = if first_arg. is_some ( ) {
1167+ std:: iter:: once ( receiver) . chain ( args. iter ( ) ) . collect :: < Vec < _ > > ( )
1168+ } else {
1169+ // There is no `Self` kind to infer the arguments from
1170+ if has_unsuggestable_args {
1171+ applicability = Applicability :: HasPlaceholders ;
1172+ }
1173+ args. iter ( ) . collect ( )
1174+ } ;
1175+ format ! (
1176+ "({}{})" ,
1177+ first_arg. unwrap_or( "" ) ,
1178+ explicit_args
1179+ . iter( )
1180+ . map( |arg| self
1181+ . tcx
1182+ . sess
1183+ . source_map( )
1184+ . span_to_snippet( arg. span)
1185+ . unwrap_or_else( |_| {
1186+ applicability = Applicability :: HasPlaceholders ;
1187+ "_" . to_owned( )
1188+ } ) )
1189+ . collect:: <Vec <_>>( )
1190+ . join( ", " ) ,
1191+ )
1192+ } else {
1193+ applicability = Applicability :: HasPlaceholders ;
1194+ "(...)" . to_owned ( )
1195+ } ;
1196+ err. span_suggestion (
1197+ sugg_span,
1198+ "use associated function syntax instead" ,
1199+ format ! ( "{}::{}{}" , ty_str, item_name, args) ,
1200+ applicability,
1201+ ) ;
1202+ } else {
1203+ err. help ( & format ! ( "try with `{}::{}`" , ty_str, item_name, ) ) ;
1204+ }
1205+ }
1206+
11831207 /// Suggest calling a field with a type that implements the `Fn*` traits instead of a method with
11841208 /// the same name as the field i.e. `(a.my_fn_ptr)(10)` instead of `a.my_fn_ptr(10)`.
11851209 fn suggest_calling_field_as_fn (
0 commit comments