@@ -82,34 +82,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8282 let print_disambiguation_help = |
8383 err : & mut DiagnosticBuilder < ' _ > ,
8484 trait_name : String ,
85+ rcvr_ty : Ty < ' _ > ,
86+ kind : ty:: AssocKind ,
87+ span : Span ,
88+ candidate : Option < usize > ,
8589 | {
86- err. help( & format ! (
87- "to disambiguate the method call, write `{}::{}({}{})` instead" ,
88- trait_name,
89- item_name,
90- if rcvr_ty. is_region_ptr( ) && args. is_some( ) {
91- if rcvr_ty. is_mutable_ptr( ) {
92- "&mut "
90+ let mut applicability = Applicability :: MachineApplicable ;
91+ let sugg_args = if let ty:: AssocKind :: Method = kind {
92+ format!(
93+ "({}{})" ,
94+ if rcvr_ty. is_region_ptr ( ) && args. is_some ( ) {
95+ if rcvr_ty. is_mutable_ptr ( ) {
96+ "&mut "
97+ } else {
98+ "&"
99+ }
93100 } else {
94- "&"
95- }
96- } else {
97- ""
98- } ,
99- args. map( |arg| arg
100- . iter( )
101- . map( |arg| self . tcx. sess. source_map( ) . span_to_snippet( arg. span)
102- . unwrap_or_else( |_| "..." . to_owned( ) ) )
103- . collect:: <Vec <_>>( )
104- . join( ", " )
105- ) . unwrap_or_else( || "..." . to_owned( ) )
106- ) ) ;
101+ ""
102+ } ,
103+ args. map ( |arg| arg
104+ . iter ( )
105+ . map ( |arg| self . tcx . sess . source_map ( ) . span_to_snippet ( arg. span )
106+ . unwrap_or_else ( |_| {
107+ applicability = Applicability :: HasPlaceholders ;
108+ "..." . to_owned ( )
109+ } ) )
110+ . collect :: < Vec < _ > > ( )
111+ . join ( ", " )
112+ ) . unwrap_or_else ( || {
113+ applicability = Applicability :: HasPlaceholders ;
114+ "..." . to_owned ( )
115+ } ) ,
116+ )
117+ } else {
118+ String :: new ( )
119+ } ;
120+ let sugg = format ! ( "{}::{}{}" , trait_name, item_name, sugg_args) ;
121+ err. span_suggestion (
122+ span,
123+ & format ! (
124+ "disambiguate the {} for {}" ,
125+ kind. suggestion_descr( ) ,
126+ if let Some ( candidate) = candidate {
127+ format!( "candidate #{}" , candidate)
128+ } else {
129+ "the candidate" . to_string( )
130+ } ,
131+ ) ,
132+ sugg,
133+ applicability,
134+ ) ;
107135 } ;
108136
109137 let report_candidates = |
110138 span : Span ,
111139 err : & mut DiagnosticBuilder < ' _ > ,
112140 mut sources : Vec < CandidateSource > ,
141+ sugg_span : Span ,
113142 | {
114143 sources. sort( ) ;
115144 sources. dedup( ) ;
@@ -150,15 +179,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
150179 }
151180 } ;
152181
153- let note_str = if sources. len ( ) > 1 {
154- format ! ( "candidate #{} is defined in an impl{} for the type `{}`" ,
155- idx + 1 ,
156- insertion,
157- impl_ty)
182+ let ( note_str, idx) = if sources. len ( ) > 1 {
183+ ( format ! (
184+ "candidate #{} is defined in an impl{} for the type `{}`" ,
185+ idx + 1 ,
186+ insertion,
187+ impl_ty,
188+ ) , Some ( idx + 1 ) )
158189 } else {
159- format ! ( "the candidate is defined in an impl{} for the type `{}`" ,
160- insertion,
161- impl_ty)
190+ ( format ! (
191+ "the candidate is defined in an impl{} for the type `{}`" ,
192+ insertion,
193+ impl_ty,
194+ ) , None )
162195 } ;
163196 if let Some ( note_span) = note_span {
164197 // We have a span pointing to the method. Show note with snippet.
@@ -168,7 +201,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
168201 err. note ( & note_str) ;
169202 }
170203 if let Some ( trait_ref) = self . tcx . impl_trait_ref ( impl_did) {
171- print_disambiguation_help ( err, self . tcx . def_path_str ( trait_ref. def_id ) ) ;
204+ let path = self . tcx . def_path_str ( trait_ref. def_id ) ;
205+
206+ let ty = match item. kind {
207+ ty:: AssocKind :: Const |
208+ ty:: AssocKind :: Type |
209+ ty:: AssocKind :: OpaqueTy => rcvr_ty,
210+ ty:: AssocKind :: Method => self . tcx . fn_sig ( item. def_id )
211+ . inputs ( )
212+ . skip_binder ( )
213+ . get ( 0 )
214+ . filter ( |ty| ty. is_region_ptr ( ) && !rcvr_ty. is_region_ptr ( ) )
215+ . map ( |ty| * ty)
216+ . unwrap_or ( rcvr_ty) ,
217+ } ;
218+ print_disambiguation_help ( err, path, ty, item. kind , sugg_span, idx) ;
172219 }
173220 }
174221 CandidateSource :: TraitSource ( trait_did) => {
@@ -182,19 +229,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
182229 } ;
183230 let item_span = self . tcx . sess . source_map ( )
184231 . def_span ( self . tcx . def_span ( item. def_id ) ) ;
185- if sources. len ( ) > 1 {
232+ let idx = if sources. len ( ) > 1 {
186233 span_note ! ( err,
187234 item_span,
188235 "candidate #{} is defined in the trait `{}`" ,
189236 idx + 1 ,
190237 self . tcx. def_path_str( trait_did) ) ;
238+ Some ( idx + 1 )
191239 } else {
192240 span_note ! ( err,
193241 item_span,
194242 "the candidate is defined in the trait `{}`" ,
195243 self . tcx. def_path_str( trait_did) ) ;
196- }
197- print_disambiguation_help ( err, self . tcx . def_path_str ( trait_did) ) ;
244+ None
245+ } ;
246+ let path = self . tcx . def_path_str ( trait_did) ;
247+ print_disambiguation_help ( err, path, rcvr_ty, item. kind , sugg_span, idx) ;
198248 }
199249 }
200250 }
@@ -203,6 +253,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
203253 }
204254 } ;
205255
256+ let sugg_span = if let SelfSource :: MethodCall ( expr) = source {
257+ // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
258+ self . tcx . hir ( ) . expect_expr ( self . tcx . hir ( ) . get_parent_node ( expr. hir_id ) ) . span
259+ } else {
260+ span
261+ } ;
262+
206263 match error {
207264 MethodError :: NoMatch ( NoMatchData {
208265 static_candidates : static_sources,
@@ -495,9 +552,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
495552 ) ) ;
496553 }
497554
498- report_candidates ( span, & mut err, static_sources) ;
555+ report_candidates ( span, & mut err, static_sources, sugg_span ) ;
499556 } else if static_sources. len ( ) > 1 {
500- report_candidates ( span, & mut err, static_sources) ;
557+ report_candidates ( span, & mut err, static_sources, sugg_span ) ;
501558 }
502559
503560 if !unsatisfied_predicates. is_empty ( ) {
@@ -584,7 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
584641 "multiple applicable items in scope" ) ;
585642 err. span_label ( span, format ! ( "multiple `{}` found" , item_name) ) ;
586643
587- report_candidates ( span, & mut err, sources) ;
644+ report_candidates ( span, & mut err, sources, sugg_span ) ;
588645 err. emit ( ) ;
589646 }
590647
0 commit comments