8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
+ use std:: ops:: Deref ;
11
12
12
13
use check:: FnCtxt ;
13
14
use rustc:: infer:: InferOk ;
@@ -18,7 +19,7 @@ use syntax_pos::{self, Span};
18
19
use rustc:: hir;
19
20
use rustc:: hir:: print;
20
21
use rustc:: hir:: def:: Def ;
21
- use rustc:: ty:: { self , Ty , AssociatedItem } ;
22
+ use rustc:: ty:: { self , Ty , AssociatedItem , AssociatedItemContainer } ;
22
23
use errors:: { DiagnosticBuilder , CodeMapper } ;
23
24
24
25
use super :: method:: probe;
@@ -139,49 +140,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
139
140
expected) {
140
141
err. help ( & suggestion) ;
141
142
} else {
142
- let mode = probe:: Mode :: MethodCall ;
143
- let suggestions = self . probe_for_return_type ( syntax_pos:: DUMMY_SP ,
144
- mode,
145
- expected,
146
- checked_ty,
147
- ast:: DUMMY_NODE_ID ) ;
148
- if suggestions. len ( ) > 0 {
149
- err. help ( & format ! ( "here are some functions which \
150
- might fulfill your needs:\n {}",
151
- self . get_best_match( & suggestions) . join( "\n " ) ) ) ;
152
- }
143
+ let suggestions = self . get_conversion_suggestions ( expected, checked_ty) ;
144
+ err. span_suggestions ( expr. span . next_point ( ) ,
145
+ "try using a conversion method" ,
146
+ suggestions) ;
153
147
}
154
148
( expected, Some ( err) )
155
149
}
156
150
157
- fn format_method_suggestion ( & self , method : & AssociatedItem ) -> String {
158
- format ! ( "- .{}({})" ,
159
- method. name,
160
- if self . has_no_input_arg( method) {
161
- ""
162
- } else {
163
- "..."
164
- } )
165
- }
151
+ fn get_conversion_suggestions ( & self , expected : Ty < ' tcx > , checked_ty : Ty < ' tcx > ) -> Vec < String > {
152
+ let mut methods = self . probe_for_return_type ( syntax_pos:: DUMMY_SP ,
153
+ probe:: Mode :: MethodCall ,
154
+ expected,
155
+ checked_ty,
156
+ ast:: DUMMY_NODE_ID ) ;
166
157
167
- fn display_suggested_methods ( & self , methods : & [ AssociatedItem ] ) -> Vec < String > {
168
- methods. iter ( )
169
- . take ( 5 )
170
- . map ( |method| self . format_method_suggestion ( & * method) )
171
- . collect :: < Vec < String > > ( )
172
- }
158
+ // We want methods with no arguments that are plausibly conversions:
159
+ // though a whitelist of trait DefIDs might be a better way of doing
160
+ // this (FIXME!), we presently resort to the expediency of detecting
161
+ // conversions by both name, and whether the method comes from a trait
162
+ // (thereby picking methods from traits like `Into<_>` and `ToString`,
163
+ // rather than inherent methods that merely have a suggestive name)
164
+ let conversion_method_name = |n : & str | {
165
+ n. starts_with ( "to_" ) || n. starts_with ( "into" ) ||
166
+ n. starts_with ( "as_" ) || n. starts_with ( "borrow" )
167
+ } ;
168
+ methods. retain ( |m| {
169
+ if !self . has_no_input_arg ( m) {
170
+ return false ;
171
+ }
172
+ if let AssociatedItemContainer :: TraitContainer ( _def_id) = m. container {
173
+ let name = m. name . as_str ( ) ;
174
+ conversion_method_name ( name. deref ( ) )
175
+ } else {
176
+ false
177
+ }
178
+ } ) ;
173
179
174
- fn get_best_match ( & self , methods : & [ AssociatedItem ] ) -> Vec < String > {
175
- let no_argument_methods: Vec < _ > =
176
- methods. iter ( )
177
- . filter ( |ref x| self . has_no_input_arg ( & * x) )
178
- . map ( |x| x. clone ( ) )
179
- . collect ( ) ;
180
- if no_argument_methods. len ( ) > 0 {
181
- self . display_suggested_methods ( & no_argument_methods)
182
- } else {
183
- self . display_suggested_methods ( & methods)
184
- }
180
+ methods. into_iter ( ) . map ( |m| format ! ( ".{}()" , m. name) ) . collect ( )
185
181
}
186
182
187
183
// This function checks if the method isn't static and takes other arguments than `self`.
0 commit comments