Skip to content

Commit

Permalink
WIP method suggestion jamboree
Browse files Browse the repository at this point in the history
  • Loading branch information
zackmdavis committed Nov 20, 2017
1 parent d8d5b61 commit 3b1ab62
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 40 deletions.
72 changes: 34 additions & 38 deletions src/librustc_typeck/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::ops::Deref;

use check::FnCtxt;
use rustc::infer::InferOk;
Expand All @@ -18,7 +19,7 @@ use syntax_pos::{self, Span};
use rustc::hir;
use rustc::hir::print;
use rustc::hir::def::Def;
use rustc::ty::{self, Ty, AssociatedItem};
use rustc::ty::{self, Ty, AssociatedItem, AssociatedItemContainer};
use errors::{DiagnosticBuilder, CodeMapper};

use super::method::probe;
Expand Down Expand Up @@ -139,49 +140,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
expected) {
err.help(&suggestion);
} else {
let mode = probe::Mode::MethodCall;
let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
mode,
expected,
checked_ty,
ast::DUMMY_NODE_ID);
if suggestions.len() > 0 {
err.help(&format!("here are some functions which \
might fulfill your needs:\n{}",
self.get_best_match(&suggestions).join("\n")));
}
let suggestions = self.get_conversion_suggestions(expected, checked_ty);
err.span_suggestions(expr.span.next_point(),
"try using a conversion method",
suggestions);
}
(expected, Some(err))
}

fn format_method_suggestion(&self, method: &AssociatedItem) -> String {
format!("- .{}({})",
method.name,
if self.has_no_input_arg(method) {
""
} else {
"..."
})
}
fn get_conversion_suggestions(&self, expected: Ty<'tcx>, checked_ty: Ty<'tcx>) -> Vec<String> {
let mut methods = self.probe_for_return_type(syntax_pos::DUMMY_SP,
probe::Mode::MethodCall,
expected,
checked_ty,
ast::DUMMY_NODE_ID);

fn display_suggested_methods(&self, methods: &[AssociatedItem]) -> Vec<String> {
methods.iter()
.take(5)
.map(|method| self.format_method_suggestion(&*method))
.collect::<Vec<String>>()
}
// We want methods with no arguments that are plausibly conversions:
// though a whitelist of trait DefIDs might be a better way of doing
// this (FIXME!), we presently resort to the expediency of detecting
// conversions by both name, and whether the method comes from a trait
// (thereby picking methods from traits like `Into<_>` and `ToString`,
// rather than inherent methods that merely have a suggestive name)
let conversion_method_name = |n: &str| {
n.starts_with("to_") || n.starts_with("into") ||
n.starts_with("as_") || n.starts_with("borrow")
};
methods.retain(|m| {
if !self.has_no_input_arg(m) {
return false;
}
if let AssociatedItemContainer::TraitContainer(_def_id) = m.container {
let name = m.name.as_str();
conversion_method_name(name.deref())
} else {
false
}
});

fn get_best_match(&self, methods: &[AssociatedItem]) -> Vec<String> {
let no_argument_methods: Vec<_> =
methods.iter()
.filter(|ref x| self.has_no_input_arg(&*x))
.map(|x| x.clone())
.collect();
if no_argument_methods.len() > 0 {
self.display_suggested_methods(&no_argument_methods)
} else {
self.display_suggested_methods(&methods)
}
methods.into_iter().map(|m| format!(".{}()", m.name)).collect()
}

// This function checks if the method isn't static and takes other arguments than `self`.
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_typeck/check/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
scope_expr_id);
let method_names =
self.probe_op(span, mode, None, Some(return_type), IsSuggestion(true),
self_ty, scope_expr_id, ProbeScope::TraitsInScope,
self_ty, scope_expr_id, ProbeScope::AllTraits,
|probe_cx| Ok(probe_cx.candidate_method_names()))
.unwrap_or(vec![]);
method_names
Expand All @@ -192,7 +192,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.probe_op(
span, mode, Some(method_name), Some(return_type),
IsSuggestion(true), self_ty, scope_expr_id,
ProbeScope::TraitsInScope, |probe_cx| probe_cx.pick()
ProbeScope::AllTraits, |probe_cx| probe_cx.pick()
).ok().map(|pick| pick.item)
})
.collect()
Expand Down

0 comments on commit 3b1ab62

Please sign in to comment.