@@ -50,6 +50,15 @@ use rustc_hir::intravisit::Visitor;
5050use std:: cmp:: { self , Ordering } ;
5151use std:: iter;
5252
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+
5362impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
5463 fn is_fn_ty ( & self , ty : Ty < ' tcx > , span : Span ) -> bool {
5564 let tcx = self . tcx ;
@@ -115,7 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
115124 item_name : Ident ,
116125 source : SelfSource < ' tcx > ,
117126 error : MethodError < ' tcx > ,
118- args : Option < ( & ' tcx hir :: Expr < ' tcx > , & ' tcx [ hir :: Expr < ' tcx > ] ) > ,
127+ args : Option < MethodCallComponents < ' tcx > > ,
119128 expected : Expectation < ' tcx > ,
120129 trait_missing_method : bool ,
121130 ) -> Option < DiagnosticBuilder < ' _ , ErrorGuaranteed > > {
@@ -257,18 +266,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
257266 fn suggest_missing_writer (
258267 & self ,
259268 rcvr_ty : Ty < ' tcx > ,
260- args : ( & ' tcx hir :: Expr < ' tcx > , & ' tcx [ hir :: Expr < ' tcx > ] ) ,
269+ args : MethodCallComponents < ' tcx > ,
261270 ) -> DiagnosticBuilder < ' _ , ErrorGuaranteed > {
262271 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+ ) ;
265279 err. span_note (
266- args. 0 . span ,
280+ args. receiver . span ,
267281 "must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method" ,
268282 ) ;
269- if let ExprKind :: Lit ( _) = args. 0 . kind {
283+ if let ExprKind :: Lit ( _) = args. receiver . kind {
270284 err. span_help (
271- args. 0 . span . shrink_to_lo ( ) ,
285+ args. receiver . span . shrink_to_lo ( ) ,
272286 "a writer is needed before this format string" ,
273287 ) ;
274288 } ;
@@ -282,7 +296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
282296 rcvr_ty : Ty < ' tcx > ,
283297 item_name : Ident ,
284298 source : SelfSource < ' tcx > ,
285- args : Option < ( & ' tcx hir :: Expr < ' tcx > , & ' tcx [ hir :: Expr < ' tcx > ] ) > ,
299+ args : Option < MethodCallComponents < ' tcx > > ,
286300 sugg_span : Span ,
287301 no_match_data : & mut NoMatchData < ' tcx > ,
288302 expected : Expectation < ' tcx > ,
@@ -953,6 +967,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
953967
954968 unsatisfied_bounds = true ;
955969 }
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+ }
9561003 }
9571004
9581005 let label_span_not_found = |err : & mut Diagnostic | {
@@ -1111,7 +1158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11111158 span,
11121159 rcvr_ty,
11131160 item_name,
1114- args. map ( |( _ , args) | args. len ( ) + 1 ) ,
1161+ args. map ( |MethodCallComponents { args, .. } | args. len ( ) + 1 ) ,
11151162 source,
11161163 no_match_data. out_of_scope_traits . clone ( ) ,
11171164 & unsatisfied_predicates,
@@ -1192,7 +1239,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11921239 & self ,
11931240 rcvr_ty : Ty < ' tcx > ,
11941241 item_name : Ident ,
1195- args : Option < ( & ' tcx hir :: Expr < ' tcx > , & ' tcx [ hir :: Expr < ' tcx > ] ) > ,
1242+ args : Option < MethodCallComponents < ' tcx > > ,
11961243 span : Span ,
11971244 err : & mut Diagnostic ,
11981245 sources : & mut Vec < CandidateSource > ,
@@ -1343,7 +1390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13431390 rcvr_ty : Ty < ' tcx > ,
13441391 source : SelfSource < ' tcx > ,
13451392 item_name : Ident ,
1346- args : Option < ( & hir :: Expr < ' tcx > , & [ hir :: Expr < ' tcx > ] ) > ,
1393+ args : Option < MethodCallComponents < ' tcx > > ,
13471394 sugg_span : Span ,
13481395 ) {
13491396 let mut has_unsuggestable_args = false ;
@@ -1415,7 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14151462 None
14161463 } ;
14171464 let mut applicability = Applicability :: MachineApplicable ;
1418- let args = if let Some ( ( receiver, args) ) = args {
1465+ let args = if let Some ( MethodCallComponents { receiver, args, .. } ) = args {
14191466 // The first arg is the same kind as the receiver
14201467 let explicit_args = if first_arg. is_some ( ) {
14211468 std:: iter:: once ( receiver) . chain ( args. iter ( ) ) . collect :: < Vec < _ > > ( )
@@ -2995,7 +3042,7 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
29953042
29963043fn print_disambiguation_help < ' tcx > (
29973044 item_name : Ident ,
2998- args : Option < ( & ' tcx hir :: Expr < ' tcx > , & ' tcx [ hir :: Expr < ' tcx > ] ) > ,
3045+ args : Option < MethodCallComponents < ' tcx > > ,
29993046 err : & mut Diagnostic ,
30003047 trait_name : String ,
30013048 rcvr_ty : Ty < ' _ > ,
@@ -3007,7 +3054,11 @@ fn print_disambiguation_help<'tcx>(
30073054 fn_has_self_parameter : bool ,
30083055) {
30093056 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+ {
30113062 let args = format ! (
30123063 "({}{})" ,
30133064 rcvr_ty. ref_mutability( ) . map_or( "" , |mutbl| mutbl. ref_prefix_str( ) ) ,
0 commit comments