Update to last master
This commit is contained in:
parent
3bb3278e53
commit
044b07dd20
3 changed files with 44 additions and 121 deletions
|
|
@ -17,7 +17,8 @@ use rustc::traits::ObligationCause;
|
|||
use syntax::ast;
|
||||
use syntax_pos::{self, Span};
|
||||
use rustc::hir;
|
||||
use rustc::ty::{self, ImplOrTraitItem};
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::ty::{self, AssociatedItem};
|
||||
|
||||
use super::method::probe;
|
||||
|
||||
|
|
@ -31,11 +32,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
self.register_predicates(obligations);
|
||||
},
|
||||
Err(e) => {
|
||||
<<<<<<< HEAD
|
||||
self.report_mismatched_types(&cause, expected, actual, e);
|
||||
=======
|
||||
self.report_mismatched_types(origin, expected, actual, e).emit();
|
||||
>>>>>>> Return DiagnosticBuilder to add help suggestions
|
||||
self.report_mismatched_types(&cause, expected, actual, e).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -59,74 +56,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// This function is used to determine potential "simple" improvements or users' errors and
|
||||
/// provide them useful help. For example:
|
||||
///
|
||||
/// ```
|
||||
/// fn some_fn(s: &str) {}
|
||||
///
|
||||
/// let x = "hey!".to_owned();
|
||||
/// some_fn(x); // error
|
||||
/// ```
|
||||
///
|
||||
/// No need to find every potential function which could make a coercion to transform a
|
||||
/// `String` into a `&str` since a `&` would do the trick!
|
||||
///
|
||||
/// In addition of this check, it also checks between references mutability state. If the
|
||||
/// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
|
||||
/// `&mut`!".
|
||||
fn check_ref(&self,
|
||||
expr: &hir::Expr,
|
||||
checked_ty: Ty<'tcx>,
|
||||
expected: Ty<'tcx>)
|
||||
-> Option<String> {
|
||||
match (&expected.sty, &checked_ty.sty) {
|
||||
(&ty::TyRef(_, expected_mutability),
|
||||
&ty::TyRef(_, checked_mutability)) => {
|
||||
// check if there is a mutability difference
|
||||
if checked_mutability.mutbl == hir::Mutability::MutImmutable &&
|
||||
checked_mutability.mutbl != expected_mutability.mutbl &&
|
||||
self.can_sub_types(&checked_mutability.ty,
|
||||
expected_mutability.ty).is_ok() {
|
||||
if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
|
||||
return Some(format!("try with `&mut {}`", &src.replace("&", "")));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
(&ty::TyRef(_, mutability), _) => {
|
||||
// Check if it can work when put into a ref. For example:
|
||||
//
|
||||
// ```
|
||||
// fn bar(x: &mut i32) {}
|
||||
//
|
||||
// let x = 0u32;
|
||||
// bar(&x); // error, expected &mut
|
||||
// ```
|
||||
let ref_ty = match mutability.mutbl {
|
||||
hir::Mutability::MutMutable => self.tcx.mk_mut_ref(
|
||||
self.tcx.mk_region(ty::ReStatic),
|
||||
checked_ty),
|
||||
hir::Mutability::MutImmutable => self.tcx.mk_imm_ref(
|
||||
self.tcx.mk_region(ty::ReStatic),
|
||||
checked_ty),
|
||||
};
|
||||
if self.try_coerce(expr, ref_ty, expected).is_ok() {
|
||||
if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
|
||||
return Some(format!("try with `{}{}`",
|
||||
match mutability.mutbl {
|
||||
hir::Mutability::MutMutable => "&mut ",
|
||||
hir::Mutability::MutImmutable => "&",
|
||||
},
|
||||
&src));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// Checks that the type of `expr` can be coerced to `expected`.
|
||||
pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) {
|
||||
let expected = self.resolve_type_vars_with_obligations(expected);
|
||||
|
|
@ -134,37 +63,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
let cause = self.misc(expr.span);
|
||||
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
|
||||
let mode = probe::Mode::MethodCall;
|
||||
let suggestions = if let Some(s) = self.check_ref(expr, checked_ty, expected) {
|
||||
Some(s)
|
||||
} else {
|
||||
let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
|
||||
mode,
|
||||
expected,
|
||||
checked_ty,
|
||||
ast::DUMMY_NODE_ID);
|
||||
if suggestions.len() > 0 {
|
||||
Some(format!("here are some functions which \
|
||||
might fulfill your needs:\n - {}",
|
||||
self.get_best_match(&suggestions)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
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)));
|
||||
};
|
||||
let mut err = self.report_mismatched_types(origin, expected, expr_ty, e);
|
||||
if let Some(suggestions) = suggestions {
|
||||
err.help(&suggestions);
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
self.report_mismatched_types(&cause, expected, expr_ty, e);
|
||||
=======
|
||||
err.emit();
|
||||
>>>>>>> Return DiagnosticBuilder to add help suggestions
|
||||
}
|
||||
}
|
||||
|
||||
fn format_method_suggestion(&self, method: &ImplOrTraitItem<'tcx>) -> String {
|
||||
fn format_method_suggestion(&self, method: &AssociatedItem) -> String {
|
||||
format!(".{}({})",
|
||||
method.name(),
|
||||
method.name,
|
||||
if self.has_not_input_arg(method) {
|
||||
""
|
||||
} else {
|
||||
|
|
@ -172,7 +88,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
fn display_suggested_methods(&self, methods: &[ImplOrTraitItem<'tcx>]) -> String {
|
||||
fn display_suggested_methods(&self, methods: &[AssociatedItem]) -> String {
|
||||
methods.iter()
|
||||
.take(5)
|
||||
.map(|method| self.format_method_suggestion(&*method))
|
||||
|
|
@ -180,7 +96,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
.join("\n - ")
|
||||
}
|
||||
|
||||
fn get_best_match(&self, methods: &[ImplOrTraitItem<'tcx>]) -> String {
|
||||
fn get_best_match(&self, methods: &[AssociatedItem]) -> String {
|
||||
let no_argument_methods: Vec<_> =
|
||||
methods.iter()
|
||||
.filter(|ref x| self.has_not_input_arg(&*x))
|
||||
|
|
@ -194,10 +110,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
// This function checks if the method isn't static and takes other arguments than `self`.
|
||||
fn has_not_input_arg(&self, method: &ImplOrTraitItem<'tcx>) -> bool {
|
||||
match *method {
|
||||
ImplOrTraitItem::MethodTraitItem(ref x) => {
|
||||
x.fty.sig.skip_binder().inputs.len() == 1
|
||||
fn has_not_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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ use super::suggest;
|
|||
use check::FnCtxt;
|
||||
use hir::def_id::DefId;
|
||||
use hir::def::Def;
|
||||
use rustc::infer::InferOk;
|
||||
use rustc::ty::subst::{Subst, Substs};
|
||||
use rustc::traits::{self, ObligationCause};
|
||||
use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable};
|
||||
|
|
@ -162,7 +161,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
return_type: Ty<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
scope_expr_id: ast::NodeId)
|
||||
-> Vec<ty::ImplOrTraitItem<'tcx>> {
|
||||
-> Vec<ty::AssociatedItem> {
|
||||
debug!("probe(self_ty={:?}, return_type={}, scope_expr_id={})",
|
||||
self_ty,
|
||||
return_type,
|
||||
|
|
@ -643,13 +642,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn matches_return_type(&self, method: &ty::ImplOrTraitItem<'tcx>,
|
||||
pub fn matches_return_type(&self, method: &ty::AssociatedItem,
|
||||
expected: ty::Ty<'tcx>) -> bool {
|
||||
match *method {
|
||||
ty::ImplOrTraitItem::MethodTraitItem(ref x) => {
|
||||
match method.def() {
|
||||
Def::Method(def_id) => {
|
||||
let fty = self.tcx.item_type(def_id).fn_sig();
|
||||
self.probe(|_| {
|
||||
let substs = self.fresh_substs_for_item(self.span, method.def_id());
|
||||
let output = x.fty.sig.output().subst(self.tcx, substs);
|
||||
let substs = self.fresh_substs_for_item(self.span, method.def_id);
|
||||
let output = fty.output().subst(self.tcx, substs);
|
||||
let (output, _) = self.replace_late_bound_regions_with_fresh_var(
|
||||
self.span, infer::FnCall, &output);
|
||||
self.can_sub_types(output, expected).is_ok()
|
||||
|
|
@ -906,12 +906,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
fn candidate_method_names(&self) -> Vec<ast::Name> {
|
||||
let mut set = FnvHashSet();
|
||||
let mut set = FxHashSet();
|
||||
let mut names: Vec<_> =
|
||||
self.inherent_candidates
|
||||
.iter()
|
||||
.chain(&self.extension_candidates)
|
||||
.map(|candidate| candidate.item.name())
|
||||
.map(|candidate| candidate.item.name)
|
||||
.filter(|&name| set.insert(name))
|
||||
.collect();
|
||||
|
||||
|
|
@ -1353,19 +1353,21 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
|||
/// Find item with name `item_name` defined in impl/trait `def_id`
|
||||
/// and return it, or `None`, if no such item was defined there.
|
||||
fn associated_item(&self, def_id: DefId) -> Option<ty::AssociatedItem> {
|
||||
self.fcx.associated_item(def_id, self.item_name)
|
||||
match self.looking_for {
|
||||
LookingFor::MethodName(item_name) => self.fcx.associated_item(def_id, item_name),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn impl_or_trait_item(&self, def_id: DefId) -> Option<ty::ImplOrTraitItem<'tcx>> {
|
||||
fn impl_or_trait_item(&self, def_id: DefId) -> Option<ty::AssociatedItem> {
|
||||
match self.looking_for {
|
||||
LookingFor::MethodName(name) => {
|
||||
self.fcx.impl_or_trait_item(def_id, name)
|
||||
self.fcx.associated_item(def_id, name)
|
||||
}
|
||||
LookingFor::ReturnType(return_ty) => {
|
||||
self.tcx
|
||||
.impl_or_trait_items(def_id)
|
||||
.iter()
|
||||
.map(|&did| self.tcx.impl_or_trait_item(did))
|
||||
.associated_items(def_id)
|
||||
.map(|did| self.tcx.associated_item(did.def_id))
|
||||
.find(|m| self.matches_return_type(m, return_ty))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3697,7 +3697,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
match result {
|
||||
Ok(ty) => ctxt.unified = ty,
|
||||
Err(err) => {
|
||||
self.report_mismatched_types(&cause, ctxt.unified, e_ty, err);
|
||||
self.report_mismatched_types(&cause, ctxt.unified, e_ty, err).emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue