@@ -82,34 +82,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
82
82
let print_disambiguation_help = |
83
83
err : & mut DiagnosticBuilder < ' _ > ,
84
84
trait_name : String ,
85
+ rcvr_ty : Ty < ' _ > ,
86
+ kind : ty:: AssocKind ,
87
+ span : Span ,
88
+ candidate : Option < usize > ,
85
89
| {
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
+ }
93
100
} 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
+ ) ;
107
135
} ;
108
136
109
137
let report_candidates = |
110
138
span : Span ,
111
139
err : & mut DiagnosticBuilder < ' _ > ,
112
140
mut sources : Vec < CandidateSource > ,
141
+ sugg_span : Span ,
113
142
| {
114
143
sources. sort( ) ;
115
144
sources. dedup( ) ;
@@ -150,15 +179,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
150
179
}
151
180
} ;
152
181
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 ) )
158
189
} 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 )
162
195
} ;
163
196
if let Some ( note_span) = note_span {
164
197
// We have a span pointing to the method. Show note with snippet.
@@ -168,7 +201,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
168
201
err. note ( & note_str) ;
169
202
}
170
203
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) ;
172
219
}
173
220
}
174
221
CandidateSource :: TraitSource ( trait_did) => {
@@ -182,19 +229,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
182
229
} ;
183
230
let item_span = self . tcx . sess . source_map ( )
184
231
. def_span ( self . tcx . def_span ( item. def_id ) ) ;
185
- if sources. len ( ) > 1 {
232
+ let idx = if sources. len ( ) > 1 {
186
233
span_note ! ( err,
187
234
item_span,
188
235
"candidate #{} is defined in the trait `{}`" ,
189
236
idx + 1 ,
190
237
self . tcx. def_path_str( trait_did) ) ;
238
+ Some ( idx + 1 )
191
239
} else {
192
240
span_note ! ( err,
193
241
item_span,
194
242
"the candidate is defined in the trait `{}`" ,
195
243
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) ;
198
248
}
199
249
}
200
250
}
@@ -203,6 +253,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
203
253
}
204
254
} ;
205
255
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
+
206
263
match error {
207
264
MethodError :: NoMatch ( NoMatchData {
208
265
static_candidates : static_sources,
@@ -495,9 +552,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
495
552
) ) ;
496
553
}
497
554
498
- report_candidates ( span, & mut err, static_sources) ;
555
+ report_candidates ( span, & mut err, static_sources, sugg_span ) ;
499
556
} else if static_sources. len ( ) > 1 {
500
- report_candidates ( span, & mut err, static_sources) ;
557
+ report_candidates ( span, & mut err, static_sources, sugg_span ) ;
501
558
}
502
559
503
560
if !unsatisfied_predicates. is_empty ( ) {
@@ -584,7 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
584
641
"multiple applicable items in scope" ) ;
585
642
err. span_label ( span, format ! ( "multiple `{}` found" , item_name) ) ;
586
643
587
- report_candidates ( span, & mut err, sources) ;
644
+ report_candidates ( span, & mut err, sources, sugg_span ) ;
588
645
err. emit ( ) ;
589
646
}
590
647
0 commit comments