@@ -50,6 +50,15 @@ use rustc_hir::intravisit::Visitor;
50
50
use std:: cmp:: { self , Ordering } ;
51
51
use std:: iter;
52
52
53
+ /// After identifying that `full_expr` is a method call, we use this type to keep the expression's
54
+ /// components readily available to us to point at the right place in diagnostics.
55
+ #[ derive( Debug , Clone , Copy ) ]
56
+ pub struct MethodCallComponents < ' tcx > {
57
+ pub receiver : & ' tcx hir:: Expr < ' tcx > ,
58
+ pub args : & ' tcx [ hir:: Expr < ' tcx > ] ,
59
+ pub full_expr : & ' tcx hir:: Expr < ' tcx > ,
60
+ }
61
+
53
62
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
54
63
fn is_fn_ty ( & self , ty : Ty < ' tcx > , span : Span ) -> bool {
55
64
let tcx = self . tcx ;
@@ -115,7 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
115
124
item_name : Ident ,
116
125
source : SelfSource < ' tcx > ,
117
126
error : MethodError < ' tcx > ,
118
- args : Option < ( & ' tcx hir :: Expr < ' tcx > , & ' tcx [ hir :: Expr < ' tcx > ] ) > ,
127
+ args : Option < MethodCallComponents < ' tcx > > ,
119
128
expected : Expectation < ' tcx > ,
120
129
trait_missing_method : bool ,
121
130
) -> Option < DiagnosticBuilder < ' _ , ErrorGuaranteed > > {
@@ -257,18 +266,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
257
266
fn suggest_missing_writer (
258
267
& self ,
259
268
rcvr_ty : Ty < ' tcx > ,
260
- args : ( & ' tcx hir :: Expr < ' tcx > , & ' tcx [ hir :: Expr < ' tcx > ] ) ,
269
+ args : MethodCallComponents < ' tcx > ,
261
270
) -> DiagnosticBuilder < ' _ , ErrorGuaranteed > {
262
271
let ( ty_str, _ty_file) = self . tcx . short_ty_string ( rcvr_ty) ;
263
- let mut err =
264
- struct_span_err ! ( self . tcx. sess, args. 0 . span, E0599 , "cannot write into `{}`" , ty_str) ;
272
+ let mut err = struct_span_err ! (
273
+ self . tcx. sess,
274
+ args. receiver. span,
275
+ E0599 ,
276
+ "cannot write into `{}`" ,
277
+ ty_str
278
+ ) ;
265
279
err. span_note (
266
- args. 0 . span ,
280
+ args. receiver . span ,
267
281
"must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method" ,
268
282
) ;
269
- if let ExprKind :: Lit ( _) = args. 0 . kind {
283
+ if let ExprKind :: Lit ( _) = args. receiver . kind {
270
284
err. span_help (
271
- args. 0 . span . shrink_to_lo ( ) ,
285
+ args. receiver . span . shrink_to_lo ( ) ,
272
286
"a writer is needed before this format string" ,
273
287
) ;
274
288
} ;
@@ -282,7 +296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
282
296
rcvr_ty : Ty < ' tcx > ,
283
297
item_name : Ident ,
284
298
source : SelfSource < ' tcx > ,
285
- args : Option < ( & ' tcx hir :: Expr < ' tcx > , & ' tcx [ hir :: Expr < ' tcx > ] ) > ,
299
+ args : Option < MethodCallComponents < ' tcx > > ,
286
300
sugg_span : Span ,
287
301
no_match_data : & mut NoMatchData < ' tcx > ,
288
302
expected : Expectation < ' tcx > ,
@@ -953,6 +967,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
953
967
954
968
unsatisfied_bounds = true ;
955
969
}
970
+ } else if let ty:: Adt ( def, targs) = rcvr_ty. kind ( ) && let Some ( args) = args {
971
+ // This is useful for methods on arbitrary self types that might have a simple
972
+ // mutability difference, like calling a method on `Pin<&mut Self>` that is on
973
+ // `Pin<&Self>`.
974
+ if targs. len ( ) == 1 {
975
+ let mut item_segment = hir:: PathSegment :: invalid ( ) ;
976
+ item_segment. ident = item_name;
977
+ for t in [ Ty :: new_mut_ref, Ty :: new_imm_ref, |_, _, t| t] {
978
+ let new_args = tcx. mk_args_from_iter (
979
+ targs
980
+ . iter ( )
981
+ . map ( |arg| match arg. as_type ( ) {
982
+ Some ( ty) => ty:: GenericArg :: from (
983
+ t ( tcx, tcx. lifetimes . re_erased , ty. peel_refs ( ) ) ,
984
+ ) ,
985
+ _ => arg,
986
+ } )
987
+ ) ;
988
+ let rcvr_ty = Ty :: new_adt ( tcx, * def, new_args) ;
989
+ if let Ok ( method) = self . lookup_method_for_diagnostic (
990
+ rcvr_ty,
991
+ & item_segment,
992
+ span,
993
+ args. full_expr ,
994
+ args. receiver ,
995
+ ) {
996
+ err. span_note (
997
+ tcx. def_span ( method. def_id ) ,
998
+ format ! ( "{item_kind} is available for `{rcvr_ty}`" ) ,
999
+ ) ;
1000
+ }
1001
+ }
1002
+ }
956
1003
}
957
1004
958
1005
let label_span_not_found = |err : & mut Diagnostic | {
@@ -1111,7 +1158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1111
1158
span,
1112
1159
rcvr_ty,
1113
1160
item_name,
1114
- args. map ( |( _ , args) | args. len ( ) + 1 ) ,
1161
+ args. map ( |MethodCallComponents { args, .. } | args. len ( ) + 1 ) ,
1115
1162
source,
1116
1163
no_match_data. out_of_scope_traits . clone ( ) ,
1117
1164
& unsatisfied_predicates,
@@ -1192,7 +1239,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1192
1239
& self ,
1193
1240
rcvr_ty : Ty < ' tcx > ,
1194
1241
item_name : Ident ,
1195
- args : Option < ( & ' tcx hir :: Expr < ' tcx > , & ' tcx [ hir :: Expr < ' tcx > ] ) > ,
1242
+ args : Option < MethodCallComponents < ' tcx > > ,
1196
1243
span : Span ,
1197
1244
err : & mut Diagnostic ,
1198
1245
sources : & mut Vec < CandidateSource > ,
@@ -1343,7 +1390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1343
1390
rcvr_ty : Ty < ' tcx > ,
1344
1391
source : SelfSource < ' tcx > ,
1345
1392
item_name : Ident ,
1346
- args : Option < ( & hir :: Expr < ' tcx > , & [ hir :: Expr < ' tcx > ] ) > ,
1393
+ args : Option < MethodCallComponents < ' tcx > > ,
1347
1394
sugg_span : Span ,
1348
1395
) {
1349
1396
let mut has_unsuggestable_args = false ;
@@ -1415,7 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1415
1462
None
1416
1463
} ;
1417
1464
let mut applicability = Applicability :: MachineApplicable ;
1418
- let args = if let Some ( ( receiver, args) ) = args {
1465
+ let args = if let Some ( MethodCallComponents { receiver, args, .. } ) = args {
1419
1466
// The first arg is the same kind as the receiver
1420
1467
let explicit_args = if first_arg. is_some ( ) {
1421
1468
std:: iter:: once ( receiver) . chain ( args. iter ( ) ) . collect :: < Vec < _ > > ( )
@@ -2995,7 +3042,7 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
2995
3042
2996
3043
fn print_disambiguation_help < ' tcx > (
2997
3044
item_name : Ident ,
2998
- args : Option < ( & ' tcx hir :: Expr < ' tcx > , & ' tcx [ hir :: Expr < ' tcx > ] ) > ,
3045
+ args : Option < MethodCallComponents < ' tcx > > ,
2999
3046
err : & mut Diagnostic ,
3000
3047
trait_name : String ,
3001
3048
rcvr_ty : Ty < ' _ > ,
@@ -3007,7 +3054,11 @@ fn print_disambiguation_help<'tcx>(
3007
3054
fn_has_self_parameter : bool ,
3008
3055
) {
3009
3056
let mut applicability = Applicability :: MachineApplicable ;
3010
- let ( span, sugg) = if let ( ty:: AssocKind :: Fn , Some ( ( receiver, args) ) ) = ( kind, args) {
3057
+ let ( span, sugg) = if let (
3058
+ ty:: AssocKind :: Fn ,
3059
+ Some ( MethodCallComponents { receiver, args, .. } ) ,
3060
+ ) = ( kind, args)
3061
+ {
3011
3062
let args = format ! (
3012
3063
"({}{})" ,
3013
3064
rcvr_ty. ref_mutability( ) . map_or( "" , |mutbl| mutbl. ref_prefix_str( ) ) ,
0 commit comments