@@ -15,7 +15,7 @@ use rustc::traits::Obligation;
15
15
use rustc:: ty:: { self , Ty , TyCtxt , ToPolyTraitRef , ToPredicate , TypeFoldable } ;
16
16
use rustc:: ty:: print:: with_crate_prefix;
17
17
use syntax_pos:: { Span , FileName } ;
18
- use syntax:: ast;
18
+ use syntax:: { ast, source_map } ;
19
19
use syntax:: util:: lev_distance;
20
20
21
21
use rustc_error_codes:: * ;
@@ -79,37 +79,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
79
79
return None ;
80
80
}
81
81
82
- let print_disambiguation_help = |
83
- err : & mut DiagnosticBuilder < ' _ > ,
84
- trait_name : String ,
85
- | {
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 "
93
- } 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
- ) ) ;
107
- } ;
108
-
109
82
let report_candidates = |
110
83
span : Span ,
111
84
err : & mut DiagnosticBuilder < ' _ > ,
112
85
mut sources : Vec < CandidateSource > ,
86
+ sugg_span : Span ,
113
87
| {
114
88
sources. sort( ) ;
115
89
sources. dedup( ) ;
@@ -150,15 +124,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
150
124
}
151
125
} ;
152
126
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)
127
+ let ( note_str, idx) = if sources. len ( ) > 1 {
128
+ ( format ! (
129
+ "candidate #{} is defined in an impl{} for the type `{}`" ,
130
+ idx + 1 ,
131
+ insertion,
132
+ impl_ty,
133
+ ) , Some ( idx + 1 ) )
158
134
} else {
159
- format ! ( "the candidate is defined in an impl{} for the type `{}`" ,
160
- insertion,
161
- impl_ty)
135
+ ( format ! (
136
+ "the candidate is defined in an impl{} for the type `{}`" ,
137
+ insertion,
138
+ impl_ty,
139
+ ) , None )
162
140
} ;
163
141
if let Some ( note_span) = note_span {
164
142
// We have a span pointing to the method. Show note with snippet.
@@ -168,7 +146,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
168
146
err. note ( & note_str) ;
169
147
}
170
148
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 ) ) ;
149
+ let path = self . tcx . def_path_str ( trait_ref. def_id ) ;
150
+
151
+ let ty = match item. kind {
152
+ ty:: AssocKind :: Const |
153
+ ty:: AssocKind :: Type |
154
+ ty:: AssocKind :: OpaqueTy => rcvr_ty,
155
+ ty:: AssocKind :: Method => self . tcx . fn_sig ( item. def_id )
156
+ . inputs ( )
157
+ . skip_binder ( )
158
+ . get ( 0 )
159
+ . filter ( |ty| ty. is_region_ptr ( ) && !rcvr_ty. is_region_ptr ( ) )
160
+ . map ( |ty| * ty)
161
+ . unwrap_or ( rcvr_ty) ,
162
+ } ;
163
+ print_disambiguation_help (
164
+ item_name,
165
+ args,
166
+ err,
167
+ path,
168
+ ty,
169
+ item. kind ,
170
+ sugg_span,
171
+ idx,
172
+ self . tcx . sess . source_map ( ) ,
173
+ ) ;
172
174
}
173
175
}
174
176
CandidateSource :: TraitSource ( trait_did) => {
@@ -182,19 +184,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
182
184
} ;
183
185
let item_span = self . tcx . sess . source_map ( )
184
186
. def_span ( self . tcx . def_span ( item. def_id ) ) ;
185
- if sources. len ( ) > 1 {
187
+ let idx = if sources. len ( ) > 1 {
186
188
span_note ! ( err,
187
189
item_span,
188
190
"candidate #{} is defined in the trait `{}`" ,
189
191
idx + 1 ,
190
192
self . tcx. def_path_str( trait_did) ) ;
193
+ Some ( idx + 1 )
191
194
} else {
192
195
span_note ! ( err,
193
196
item_span,
194
197
"the candidate is defined in the trait `{}`" ,
195
198
self . tcx. def_path_str( trait_did) ) ;
196
- }
197
- print_disambiguation_help ( err, self . tcx . def_path_str ( trait_did) ) ;
199
+ None
200
+ } ;
201
+ let path = self . tcx . def_path_str ( trait_did) ;
202
+ print_disambiguation_help (
203
+ item_name,
204
+ args,
205
+ err,
206
+ path,
207
+ rcvr_ty,
208
+ item. kind ,
209
+ sugg_span,
210
+ idx,
211
+ self . tcx . sess . source_map ( ) ,
212
+ ) ;
198
213
}
199
214
}
200
215
}
@@ -203,6 +218,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
203
218
}
204
219
} ;
205
220
221
+ let sugg_span = if let SelfSource :: MethodCall ( expr) = source {
222
+ // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
223
+ self . tcx . hir ( ) . expect_expr ( self . tcx . hir ( ) . get_parent_node ( expr. hir_id ) ) . span
224
+ } else {
225
+ span
226
+ } ;
227
+
206
228
match error {
207
229
MethodError :: NoMatch ( NoMatchData {
208
230
static_candidates: static_sources,
@@ -495,9 +517,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
495
517
) ) ;
496
518
}
497
519
498
- report_candidates ( span, & mut err, static_sources) ;
520
+ report_candidates ( span, & mut err, static_sources, sugg_span ) ;
499
521
} else if static_sources. len ( ) > 1 {
500
- report_candidates ( span, & mut err, static_sources) ;
522
+ report_candidates ( span, & mut err, static_sources, sugg_span ) ;
501
523
}
502
524
503
525
if !unsatisfied_predicates. is_empty ( ) {
@@ -584,7 +606,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
584
606
"multiple applicable items in scope" ) ;
585
607
err. span_label ( span, format ! ( "multiple `{}` found" , item_name) ) ;
586
608
587
- report_candidates ( span, & mut err, sources) ;
609
+ report_candidates ( span, & mut err, sources, sugg_span ) ;
588
610
err. emit ( ) ;
589
611
}
590
612
@@ -1123,3 +1145,56 @@ impl hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1123
1145
hir:: intravisit:: NestedVisitorMap :: None
1124
1146
}
1125
1147
}
1148
+
1149
+ fn print_disambiguation_help (
1150
+ item_name : ast:: Ident ,
1151
+ args : Option < & ' tcx [ hir:: Expr ] > ,
1152
+ err : & mut DiagnosticBuilder < ' _ > ,
1153
+ trait_name : String ,
1154
+ rcvr_ty : Ty < ' _ > ,
1155
+ kind : ty:: AssocKind ,
1156
+ span : Span ,
1157
+ candidate : Option < usize > ,
1158
+ source_map : & source_map:: SourceMap ,
1159
+ ) {
1160
+ let mut applicability = Applicability :: MachineApplicable ;
1161
+ let sugg_args = if let ( ty:: AssocKind :: Method , Some ( args) ) = ( kind, args) {
1162
+ format ! (
1163
+ "({}{})" ,
1164
+ if rcvr_ty. is_region_ptr( ) {
1165
+ if rcvr_ty. is_mutable_ptr( ) {
1166
+ "&mut "
1167
+ } else {
1168
+ "&"
1169
+ }
1170
+ } else {
1171
+ ""
1172
+ } ,
1173
+ args. iter( )
1174
+ . map( |arg| source_map. span_to_snippet( arg. span)
1175
+ . unwrap_or_else( |_| {
1176
+ applicability = Applicability :: HasPlaceholders ;
1177
+ "_" . to_owned( )
1178
+ } ) )
1179
+ . collect:: <Vec <_>>( )
1180
+ . join( ", " ) ,
1181
+ )
1182
+ } else {
1183
+ String :: new ( )
1184
+ } ;
1185
+ let sugg = format ! ( "{}::{}{}" , trait_name, item_name, sugg_args) ;
1186
+ err. span_suggestion (
1187
+ span,
1188
+ & format ! (
1189
+ "disambiguate the {} for {}" ,
1190
+ kind. suggestion_descr( ) ,
1191
+ if let Some ( candidate) = candidate {
1192
+ format!( "candidate #{}" , candidate)
1193
+ } else {
1194
+ "the candidate" . to_string( )
1195
+ } ,
1196
+ ) ,
1197
+ sugg,
1198
+ applicability,
1199
+ ) ;
1200
+ }
0 commit comments