Skip to content

Commit 9df1ed9

Browse files
committed
WIP method suggestion jamboree
1 parent d8d5b61 commit 9df1ed9

File tree

2 files changed

+29
-7
lines changed

2 files changed

+29
-7
lines changed

src/librustc_typeck/check/demand.rs

+27-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use std::ops::Deref;
1112

1213
use check::FnCtxt;
1314
use rustc::infer::InferOk;
@@ -18,7 +19,7 @@ use syntax_pos::{self, Span};
1819
use rustc::hir;
1920
use rustc::hir::print;
2021
use rustc::hir::def::Def;
21-
use rustc::ty::{self, Ty, AssociatedItem};
22+
use rustc::ty::{self, Ty, AssociatedItem, AssociatedItemContainer};
2223
use errors::{DiagnosticBuilder, CodeMapper};
2324

2425
use super::method::probe;
@@ -146,7 +147,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
146147
checked_ty,
147148
ast::DUMMY_NODE_ID);
148149
if suggestions.len() > 0 {
149-
err.help(&format!("here are some functions which \
150+
err.help(&format!("here are some methods which \
150151
might fulfill your needs:\n{}",
151152
self.get_best_match(&suggestions).join("\n")));
152153
}
@@ -165,18 +166,39 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
165166
}
166167

167168
fn display_suggested_methods(&self, methods: &[AssociatedItem]) -> Vec<String> {
169+
let limit = if methods.len() == 4 { 4 } else { 3 }; // never omit just one method
168170
methods.iter()
169-
.take(5)
171+
.take(limit)
170172
.map(|method| self.format_method_suggestion(&*method))
171173
.collect::<Vec<String>>()
172174
}
173175

174176
fn get_best_match(&self, methods: &[AssociatedItem]) -> Vec<String> {
175-
let no_argument_methods: Vec<_> =
177+
let mut no_argument_methods: Vec<_> =
176178
methods.iter()
177179
.filter(|ref x| self.has_no_input_arg(&*x))
178-
.map(|x| x.clone())
180+
.cloned()
179181
.collect();
182+
183+
// We want the list to prioritize methods that are plausibly
184+
// conversions: we do so first by name, and then by whether the method
185+
// comes from a trait (so that methods from actual conversion traits
186+
// like `Into<_>` and `ToString` come before methods that merely have a
187+
// suggestive name)
188+
let conversion_method_name = |n: &str| {
189+
n.starts_with("to_") || n.starts_with("into") ||
190+
n.starts_with("as_") || n.starts_with("borrow")
191+
};
192+
no_argument_methods.sort_by_key(|m| {
193+
let name = m.name.as_str();
194+
let name_fit = if conversion_method_name(name.deref()) { 0 } else { 1 };
195+
let traitness = match m.container {
196+
AssociatedItemContainer::TraitContainer(_) => 0,
197+
AssociatedItemContainer::ImplContainer(_) => 1,
198+
};
199+
(name_fit, traitness, name)
200+
});
201+
180202
if no_argument_methods.len() > 0 {
181203
self.display_suggested_methods(&no_argument_methods)
182204
} else {

src/librustc_typeck/check/method/probe.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
183183
scope_expr_id);
184184
let method_names =
185185
self.probe_op(span, mode, None, Some(return_type), IsSuggestion(true),
186-
self_ty, scope_expr_id, ProbeScope::TraitsInScope,
186+
self_ty, scope_expr_id, ProbeScope::AllTraits,
187187
|probe_cx| Ok(probe_cx.candidate_method_names()))
188188
.unwrap_or(vec![]);
189189
method_names
@@ -192,7 +192,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
192192
self.probe_op(
193193
span, mode, Some(method_name), Some(return_type),
194194
IsSuggestion(true), self_ty, scope_expr_id,
195-
ProbeScope::TraitsInScope, |probe_cx| probe_cx.pick()
195+
ProbeScope::AllTraits, |probe_cx| probe_cx.pick()
196196
).ok().map(|pick| pick.item)
197197
})
198198
.collect()

0 commit comments

Comments
 (0)