@@ -15,7 +15,7 @@ use rustc::traits::Obligation;
1515use rustc:: ty:: { self , Ty , TyCtxt , ToPolyTraitRef , ToPredicate , TypeFoldable } ;
1616use rustc:: ty:: print:: with_crate_prefix;
1717use syntax_pos:: { Span , FileName } ;
18- use syntax:: ast;
18+ use syntax:: { ast, source_map } ;
1919use syntax:: util:: lev_distance;
2020
2121use rustc_error_codes:: * ;
@@ -79,37 +79,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7979 return None ;
8080 }
8181
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-
10982 let report_candidates = |
11083 span : Span ,
11184 err : & mut DiagnosticBuilder < ' _ > ,
11285 mut sources : Vec < CandidateSource > ,
86+ sugg_span : Span ,
11387 | {
11488 sources. sort( ) ;
11589 sources. dedup( ) ;
@@ -150,15 +124,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
150124 }
151125 } ;
152126
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 ) )
158134 } 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 )
162140 } ;
163141 if let Some ( note_span) = note_span {
164142 // We have a span pointing to the method. Show note with snippet.
@@ -168,7 +146,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
168146 err. note ( & note_str) ;
169147 }
170148 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+ ) ;
172174 }
173175 }
174176 CandidateSource :: TraitSource ( trait_did) => {
@@ -182,19 +184,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
182184 } ;
183185 let item_span = self . tcx . sess . source_map ( )
184186 . def_span ( self . tcx . def_span ( item. def_id ) ) ;
185- if sources. len ( ) > 1 {
187+ let idx = if sources. len ( ) > 1 {
186188 span_note ! ( err,
187189 item_span,
188190 "candidate #{} is defined in the trait `{}`" ,
189191 idx + 1 ,
190192 self . tcx. def_path_str( trait_did) ) ;
193+ Some ( idx + 1 )
191194 } else {
192195 span_note ! ( err,
193196 item_span,
194197 "the candidate is defined in the trait `{}`" ,
195198 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+ ) ;
198213 }
199214 }
200215 }
@@ -203,6 +218,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
203218 }
204219 } ;
205220
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+
206228 match error {
207229 MethodError :: NoMatch ( NoMatchData {
208230 static_candidates: static_sources,
@@ -495,9 +517,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
495517 ) ) ;
496518 }
497519
498- report_candidates ( span, & mut err, static_sources) ;
520+ report_candidates ( span, & mut err, static_sources, sugg_span ) ;
499521 } else if static_sources. len ( ) > 1 {
500- report_candidates ( span, & mut err, static_sources) ;
522+ report_candidates ( span, & mut err, static_sources, sugg_span ) ;
501523 }
502524
503525 if !unsatisfied_predicates. is_empty ( ) {
@@ -584,7 +606,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
584606 "multiple applicable items in scope" ) ;
585607 err. span_label ( span, format ! ( "multiple `{}` found" , item_name) ) ;
586608
587- report_candidates ( span, & mut err, sources) ;
609+ report_candidates ( span, & mut err, sources, sugg_span ) ;
588610 err. emit ( ) ;
589611 }
590612
@@ -1123,3 +1145,56 @@ impl hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
11231145 hir:: intravisit:: NestedVisitorMap :: None
11241146 }
11251147}
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