Skip to content

Commit

Permalink
Auto merge of #38099 - GuillaumeGomez:cast_suggestions, r=nikomatsakis
Browse files Browse the repository at this point in the history
Cast suggestions

r? @nikomatsakis
  • Loading branch information
bors committed Dec 21, 2016
2 parents 92d4600 + 28e2c6a commit 439c312
Show file tree
Hide file tree
Showing 13 changed files with 401 additions and 100 deletions.
5 changes: 3 additions & 2 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1367,9 +1367,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
cause: &ObligationCause<'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
err: TypeError<'tcx>) {
err: TypeError<'tcx>)
-> DiagnosticBuilder<'tcx> {
let trace = TypeTrace::types(cause, true, expected, actual);
self.report_and_explain_type_error(trace, &err).emit();
self.report_and_explain_type_error(trace, &err)
}

pub fn report_conflicting_default_types(&self,
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ pub struct ProjectionTy<'tcx> {
pub struct BareFnTy<'tcx> {
pub unsafety: hir::Unsafety,
pub abi: abi::Abi,
/// Signature (inputs and output) of this function type.
pub sig: PolyFnSig<'tcx>,
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
} else {
(result_ty, arm_ty)
};
self.report_mismatched_types(&cause, expected, found, e);
self.report_mismatched_types(&cause, expected, found, e).emit();
self.tcx.types.err
}
};
Expand Down
8 changes: 8 additions & 0 deletions src/librustc_typeck/check/autoderef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,18 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
Some(self.fcx.resolve_type_vars_if_possible(&normalized.value))
}

/// Returns the final type, generating an error if it is an
/// unresolved inference variable.
pub fn unambiguous_final_ty(&self) -> Ty<'tcx> {
self.fcx.structurally_resolved_type(self.span, self.cur_ty)
}

/// Returns the final type we ended up with, which may well be an
/// inference variable (we will resolve it first, if possible).
pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> {
self.fcx.resolve_type_vars_if_possible(&self.cur_ty)
}

pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I)
where I: IntoIterator<Item = &'b hir::Expr>
{
Expand Down
71 changes: 67 additions & 4 deletions src/librustc_typeck/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@ use rustc::ty::Ty;
use rustc::infer::{InferOk};
use rustc::traits::ObligationCause;

use syntax_pos::Span;
use syntax::ast;
use syntax_pos::{self, Span};
use rustc::hir;
use rustc::hir::def::Def;
use rustc::ty::{self, AssociatedItem};

use super::method::probe;

impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Requires that the two types unify, and prints an error message if
Expand All @@ -27,7 +32,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.register_predicates(obligations);
},
Err(e) => {
self.report_mismatched_types(&cause, expected, actual, e);
self.report_mismatched_types(&cause, expected, actual, e).emit();
}
}
}
Expand All @@ -46,7 +51,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.register_predicates(obligations);
},
Err(e) => {
self.report_mismatched_types(cause, expected, actual, e);
self.report_mismatched_types(cause, expected, actual, e).emit();
}
}
}
Expand All @@ -57,7 +62,65 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
let cause = self.misc(expr.span);
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
self.report_mismatched_types(&cause, expected, expr_ty, e);
let mode = probe::Mode::MethodCall;
let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
mode,
expected,
checked_ty,
ast::DUMMY_NODE_ID);
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
if suggestions.len() > 0 {
err.help(&format!("here are some functions which \
might fulfill your needs:\n - {}",
self.get_best_match(&suggestions)));
};
err.emit();
}
}

fn format_method_suggestion(&self, method: &AssociatedItem) -> String {
format!(".{}({})",
method.name,
if self.has_no_input_arg(method) {
""
} else {
"..."
})
}

fn display_suggested_methods(&self, methods: &[AssociatedItem]) -> String {
methods.iter()
.take(5)
.map(|method| self.format_method_suggestion(&*method))
.collect::<Vec<String>>()
.join("\n - ")
}

fn get_best_match(&self, methods: &[AssociatedItem]) -> 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)
}
}

// This function checks if the method isn't static and takes other arguments than `self`.
fn has_no_input_arg(&self, method: &AssociatedItem) -> bool {
match method.def() {
Def::Method(def_id) => {
match self.tcx.item_type(def_id).sty {
ty::TypeVariants::TyFnDef(_, _, fty) => {
fty.sig.skip_binder().inputs().len() == 1
}
_ => false,
}
}
_ => false,
}
}
}
13 changes: 9 additions & 4 deletions src/librustc_typeck/check/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ pub use self::CandidateSource::*;
pub use self::suggest::AllTraitsVec;

mod confirm;
mod probe;
pub mod probe;
mod suggest;

use self::probe::IsSuggestion;

pub enum MethodError<'tcx> {
// Did not find an applicable method, but we did find various near-misses that may work.
NoMatch(NoMatchData<'tcx>),
Expand Down Expand Up @@ -91,7 +93,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
allow_private: bool)
-> bool {
let mode = probe::Mode::MethodCall;
match self.probe_method(span, mode, method_name, self_ty, call_expr_id) {
match self.probe_for_name(span, mode, method_name, IsSuggestion(false),
self_ty, call_expr_id) {
Ok(..) => true,
Err(NoMatch(..)) => false,
Err(Ambiguity(..)) => true,
Expand Down Expand Up @@ -130,7 +133,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {

let mode = probe::Mode::MethodCall;
let self_ty = self.resolve_type_vars_if_possible(&self_ty);
let pick = self.probe_method(span, mode, method_name, self_ty, call_expr.id)?;
let pick = self.probe_for_name(span, mode, method_name, IsSuggestion(false),
self_ty, call_expr.id)?;

if let Some(import_id) = pick.import_id {
self.tcx.used_trait_imports.borrow_mut().insert(import_id);
Expand Down Expand Up @@ -328,7 +332,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
expr_id: ast::NodeId)
-> Result<Def, MethodError<'tcx>> {
let mode = probe::Mode::Path;
let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?;
let pick = self.probe_for_name(span, mode, method_name, IsSuggestion(false),
self_ty, expr_id)?;

if let Some(import_id) = pick.import_id {
self.tcx.used_trait_imports.borrow_mut().insert(import_id);
Expand Down
Loading

0 comments on commit 439c312

Please sign in to comment.