|
8 | 8 | // option. This file may not be copied, modified, or distributed
|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
| 11 | +use std::iter; |
11 | 12 |
|
12 | 13 | use check::FnCtxt;
|
13 | 14 | use rustc::infer::InferOk;
|
@@ -137,49 +138,45 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
137 | 138 | if let Some((msg, suggestion)) = self.check_ref(expr, checked_ty, expected) {
|
138 | 139 | err.span_suggestion(expr.span, msg, suggestion);
|
139 | 140 | } else {
|
140 |
| - let mode = probe::Mode::MethodCall; |
141 |
| - let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP, |
142 |
| - mode, |
143 |
| - expected, |
144 |
| - checked_ty, |
145 |
| - ast::DUMMY_NODE_ID); |
146 |
| - if suggestions.len() > 0 { |
147 |
| - err.help(&format!("here are some functions which \ |
148 |
| - might fulfill your needs:\n{}", |
149 |
| - self.get_best_match(&suggestions).join("\n"))); |
| 141 | + let methods = self.get_conversion_methods(expected, checked_ty); |
| 142 | + if let Ok(expr_text) = self.tcx.sess.codemap().span_to_snippet(expr.span) { |
| 143 | + let suggestions = iter::repeat(expr_text).zip(methods.iter()) |
| 144 | + .map(|(receiver, method)| format!("{}.{}()", receiver, method.name)) |
| 145 | + .collect::<Vec<_>>(); |
| 146 | + if !suggestions.is_empty() { |
| 147 | + err.span_suggestions(expr.span, |
| 148 | + "try using a conversion method", |
| 149 | + suggestions); |
| 150 | + } |
150 | 151 | }
|
151 | 152 | }
|
152 | 153 | (expected, Some(err))
|
153 | 154 | }
|
154 | 155 |
|
155 |
| - fn format_method_suggestion(&self, method: &AssociatedItem) -> String { |
156 |
| - format!("- .{}({})", |
157 |
| - method.name, |
158 |
| - if self.has_no_input_arg(method) { |
159 |
| - "" |
160 |
| - } else { |
161 |
| - "..." |
162 |
| - }) |
163 |
| - } |
164 |
| - |
165 |
| - fn display_suggested_methods(&self, methods: &[AssociatedItem]) -> Vec<String> { |
166 |
| - methods.iter() |
167 |
| - .take(5) |
168 |
| - .map(|method| self.format_method_suggestion(&*method)) |
169 |
| - .collect::<Vec<String>>() |
170 |
| - } |
| 156 | + fn get_conversion_methods(&self, expected: Ty<'tcx>, checked_ty: Ty<'tcx>) |
| 157 | + -> Vec<AssociatedItem> { |
| 158 | + let mut methods = self.probe_for_return_type(syntax_pos::DUMMY_SP, |
| 159 | + probe::Mode::MethodCall, |
| 160 | + expected, |
| 161 | + checked_ty, |
| 162 | + ast::DUMMY_NODE_ID); |
| 163 | + methods.retain(|m| { |
| 164 | + self.has_no_input_arg(m) && |
| 165 | + self.tcx.get_attrs(m.def_id).iter() |
| 166 | + // This special internal attribute is used to whitelist |
| 167 | + // "identity-like" conversion methods to be suggested here. |
| 168 | + // |
| 169 | + // FIXME (#46459 and #46460): ideally |
| 170 | + // `std::convert::Into::into` and `std::borrow:ToOwned` would |
| 171 | + // also be `#[rustc_conversion_suggestion]`, if not for |
| 172 | + // method-probing false-positives and -negatives (respectively). |
| 173 | + // |
| 174 | + // FIXME? Other potential candidate methods: `as_ref` and |
| 175 | + // `as_mut`? |
| 176 | + .find(|a| a.check_name("rustc_conversion_suggestion")).is_some() |
| 177 | + }); |
171 | 178 |
|
172 |
| - fn get_best_match(&self, methods: &[AssociatedItem]) -> Vec<String> { |
173 |
| - let no_argument_methods: Vec<_> = |
174 |
| - methods.iter() |
175 |
| - .filter(|ref x| self.has_no_input_arg(&*x)) |
176 |
| - .map(|x| x.clone()) |
177 |
| - .collect(); |
178 |
| - if no_argument_methods.len() > 0 { |
179 |
| - self.display_suggested_methods(&no_argument_methods) |
180 |
| - } else { |
181 |
| - self.display_suggested_methods(&methods) |
182 |
| - } |
| 179 | + methods |
183 | 180 | }
|
184 | 181 |
|
185 | 182 | // This function checks if the method isn't static and takes other arguments than `self`.
|
|
0 commit comments