@@ -398,122 +398,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
398
398
custom_span_label = true ;
399
399
}
400
400
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
+ ) ;
517
410
518
411
report_candidates ( span, & mut err, & mut static_candidates, sugg_span) ;
519
412
} else if static_candidates. len ( ) > 1 {
@@ -1180,6 +1073,137 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1180
1073
None
1181
1074
}
1182
1075
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
+
1183
1207
/// Suggest calling a field with a type that implements the `Fn*` traits instead of a method with
1184
1208
/// the same name as the field i.e. `(a.my_fn_ptr)(10)` instead of `a.my_fn_ptr(10)`.
1185
1209
fn suggest_calling_field_as_fn (
0 commit comments