mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Auto merge of #38099 - GuillaumeGomez:cast_suggestions, r=nikomatsakis
Cast suggestions r? @nikomatsakis
This commit is contained in:
commit
439c3128d7
@ -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,
|
||||
|
@ -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>,
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
@ -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>
|
||||
{
|
||||
|
@ -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
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>),
|
||||
@ -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,
|
||||
@ -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);
|
||||
@ -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);
|
||||
|
@ -16,12 +16,12 @@ 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};
|
||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||
use rustc::util::nodemap::FxHashSet;
|
||||
use rustc::infer::{self, InferOk};
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
use rustc::hir;
|
||||
@ -32,11 +32,24 @@ use std::rc::Rc;
|
||||
use self::CandidateKind::*;
|
||||
pub use self::PickKind::*;
|
||||
|
||||
pub enum LookingFor<'tcx> {
|
||||
/// looking for methods with the given name; this is the normal case
|
||||
MethodName(ast::Name),
|
||||
|
||||
/// looking for methods that return a given type; this is used to
|
||||
/// assemble suggestions
|
||||
ReturnType(Ty<'tcx>),
|
||||
}
|
||||
|
||||
/// Boolean flag used to indicate if this search is for a suggestion
|
||||
/// or not. If true, we can allow ambiguity and so forth.
|
||||
pub struct IsSuggestion(pub bool);
|
||||
|
||||
struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
|
||||
span: Span,
|
||||
mode: Mode,
|
||||
item_name: ast::Name,
|
||||
looking_for: LookingFor<'tcx>,
|
||||
steps: Rc<Vec<CandidateStep<'tcx>>>,
|
||||
opt_simplified_steps: Option<Vec<ty::fast_reject::SimplifiedType>>,
|
||||
inherent_candidates: Vec<Candidate<'tcx>>,
|
||||
@ -144,18 +157,72 @@ pub enum Mode {
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn probe_method(&self,
|
||||
span: Span,
|
||||
mode: Mode,
|
||||
item_name: ast::Name,
|
||||
self_ty: Ty<'tcx>,
|
||||
scope_expr_id: ast::NodeId)
|
||||
-> PickResult<'tcx> {
|
||||
/// This is used to offer suggestions to users. It returns methods
|
||||
/// that could have been called which have the desired return
|
||||
/// type. Some effort is made to rule out methods that, if called,
|
||||
/// would result in an error (basically, the same criteria we
|
||||
/// would use to decide if a method is a plausible fit for
|
||||
/// ambiguity purposes).
|
||||
pub fn probe_for_return_type(&self,
|
||||
span: Span,
|
||||
mode: Mode,
|
||||
return_type: Ty<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
scope_expr_id: ast::NodeId)
|
||||
-> Vec<ty::AssociatedItem> {
|
||||
debug!("probe(self_ty={:?}, return_type={}, scope_expr_id={})",
|
||||
self_ty,
|
||||
return_type,
|
||||
scope_expr_id);
|
||||
let method_names =
|
||||
self.probe_op(span, mode, LookingFor::ReturnType(return_type), IsSuggestion(true),
|
||||
self_ty, scope_expr_id,
|
||||
|probe_cx| Ok(probe_cx.candidate_method_names()))
|
||||
.unwrap_or(vec![]);
|
||||
method_names
|
||||
.iter()
|
||||
.flat_map(|&method_name| {
|
||||
match self.probe_for_name(span, mode, method_name, IsSuggestion(true), self_ty,
|
||||
scope_expr_id) {
|
||||
Ok(pick) => Some(pick.item),
|
||||
Err(_) => None,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn probe_for_name(&self,
|
||||
span: Span,
|
||||
mode: Mode,
|
||||
item_name: ast::Name,
|
||||
is_suggestion: IsSuggestion,
|
||||
self_ty: Ty<'tcx>,
|
||||
scope_expr_id: ast::NodeId)
|
||||
-> PickResult<'tcx> {
|
||||
debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})",
|
||||
self_ty,
|
||||
item_name,
|
||||
scope_expr_id);
|
||||
self.probe_op(span,
|
||||
mode,
|
||||
LookingFor::MethodName(item_name),
|
||||
is_suggestion,
|
||||
self_ty,
|
||||
scope_expr_id,
|
||||
|probe_cx| probe_cx.pick())
|
||||
}
|
||||
|
||||
fn probe_op<OP,R>(&'a self,
|
||||
span: Span,
|
||||
mode: Mode,
|
||||
looking_for: LookingFor<'tcx>,
|
||||
is_suggestion: IsSuggestion,
|
||||
self_ty: Ty<'tcx>,
|
||||
scope_expr_id: ast::NodeId,
|
||||
op: OP)
|
||||
-> Result<R, MethodError<'tcx>>
|
||||
where OP: FnOnce(ProbeContext<'a, 'gcx, 'tcx>) -> Result<R, MethodError<'tcx>>
|
||||
{
|
||||
// FIXME(#18741) -- right now, creating the steps involves evaluating the
|
||||
// `*` operator, which registers obligations that then escape into
|
||||
// the global fulfillment context and thus has global
|
||||
@ -164,7 +231,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// think cause spurious errors. Really though this part should
|
||||
// take place in the `self.probe` below.
|
||||
let steps = if mode == Mode::MethodCall {
|
||||
match self.create_steps(span, self_ty) {
|
||||
match self.create_steps(span, self_ty, is_suggestion) {
|
||||
Some(steps) => steps,
|
||||
None => {
|
||||
return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(),
|
||||
@ -207,14 +274,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// that we create during the probe process are removed later
|
||||
self.probe(|_| {
|
||||
let mut probe_cx =
|
||||
ProbeContext::new(self, span, mode, item_name, steps, opt_simplified_steps);
|
||||
ProbeContext::new(self, span, mode, looking_for,
|
||||
steps, opt_simplified_steps);
|
||||
probe_cx.assemble_inherent_candidates();
|
||||
probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?;
|
||||
probe_cx.pick()
|
||||
op(probe_cx)
|
||||
})
|
||||
}
|
||||
|
||||
fn create_steps(&self, span: Span, self_ty: Ty<'tcx>) -> Option<Vec<CandidateStep<'tcx>>> {
|
||||
fn create_steps(&self,
|
||||
span: Span,
|
||||
self_ty: Ty<'tcx>,
|
||||
is_suggestion: IsSuggestion)
|
||||
-> Option<Vec<CandidateStep<'tcx>>> {
|
||||
// FIXME: we don't need to create the entire steps in one pass
|
||||
|
||||
let mut autoderef = self.autoderef(span, self_ty);
|
||||
@ -228,8 +300,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let final_ty = autoderef.unambiguous_final_ty();
|
||||
let final_ty = autoderef.maybe_ambiguous_final_ty();
|
||||
match final_ty.sty {
|
||||
ty::TyInfer(ty::TyVar(_)) => {
|
||||
// Ended in an inference variable. If we are doing
|
||||
// a real method lookup, this is a hard error (it's an
|
||||
// ambiguity and we can't make progress).
|
||||
if !is_suggestion.0 {
|
||||
let t = self.structurally_resolved_type(span, final_ty);
|
||||
assert_eq!(t, self.tcx.types.err);
|
||||
return None
|
||||
} else {
|
||||
// If we're just looking for suggestions,
|
||||
// though, ambiguity is no big thing, we can
|
||||
// just ignore it.
|
||||
}
|
||||
}
|
||||
ty::TyArray(elem_ty, _) => {
|
||||
let dereferences = steps.len() - 1;
|
||||
|
||||
@ -253,7 +339,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
|
||||
span: Span,
|
||||
mode: Mode,
|
||||
item_name: ast::Name,
|
||||
looking_for: LookingFor<'tcx>,
|
||||
steps: Vec<CandidateStep<'tcx>>,
|
||||
opt_simplified_steps: Option<Vec<ty::fast_reject::SimplifiedType>>)
|
||||
-> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
@ -261,7 +347,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
fcx: fcx,
|
||||
span: span,
|
||||
mode: mode,
|
||||
item_name: item_name,
|
||||
looking_for: looking_for,
|
||||
inherent_candidates: Vec::new(),
|
||||
extension_candidates: Vec::new(),
|
||||
impl_dups: FxHashSet(),
|
||||
@ -410,44 +496,40 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
debug!("assemble_inherent_impl_probe {:?}", impl_def_id);
|
||||
|
||||
let item = match self.associated_item(impl_def_id) {
|
||||
Some(m) => m,
|
||||
None => {
|
||||
return;
|
||||
} // No method with correct name on this impl
|
||||
};
|
||||
for item in self.impl_or_trait_item(impl_def_id) {
|
||||
if !self.has_applicable_self(&item) {
|
||||
// No receiver declared. Not a candidate.
|
||||
self.record_static_candidate(ImplSource(impl_def_id));
|
||||
continue
|
||||
}
|
||||
|
||||
if !self.has_applicable_self(&item) {
|
||||
// No receiver declared. Not a candidate.
|
||||
return self.record_static_candidate(ImplSource(impl_def_id));
|
||||
if !item.vis.is_accessible_from(self.body_id, &self.tcx.map) {
|
||||
self.private_candidate = Some(item.def());
|
||||
continue
|
||||
}
|
||||
|
||||
let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
|
||||
let impl_ty = impl_ty.subst(self.tcx, impl_substs);
|
||||
|
||||
// Determine the receiver type that the method itself expects.
|
||||
let xform_self_ty = self.xform_self_ty(&item, impl_ty, impl_substs);
|
||||
|
||||
// We can't use normalize_associated_types_in as it will pollute the
|
||||
// fcx's fulfillment context after this probe is over.
|
||||
let cause = traits::ObligationCause::misc(self.span, self.body_id);
|
||||
let mut selcx = &mut traits::SelectionContext::new(self.fcx);
|
||||
let traits::Normalized { value: xform_self_ty, obligations } =
|
||||
traits::normalize(selcx, cause, &xform_self_ty);
|
||||
debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
|
||||
xform_self_ty);
|
||||
|
||||
self.inherent_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
item: item,
|
||||
kind: InherentImplCandidate(impl_substs, obligations),
|
||||
import_id: self.import_id,
|
||||
});
|
||||
}
|
||||
|
||||
if !item.vis.is_accessible_from(self.body_id, &self.tcx.map) {
|
||||
self.private_candidate = Some(item.def());
|
||||
return;
|
||||
}
|
||||
|
||||
let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
|
||||
let impl_ty = impl_ty.subst(self.tcx, impl_substs);
|
||||
|
||||
// Determine the receiver type that the method itself expects.
|
||||
let xform_self_ty = self.xform_self_ty(&item, impl_ty, impl_substs);
|
||||
|
||||
// We can't use normalize_associated_types_in as it will pollute the
|
||||
// fcx's fulfillment context after this probe is over.
|
||||
let cause = traits::ObligationCause::misc(self.span, self.body_id);
|
||||
let mut selcx = &mut traits::SelectionContext::new(self.fcx);
|
||||
let traits::Normalized { value: xform_self_ty, obligations } =
|
||||
traits::normalize(selcx, cause, &xform_self_ty);
|
||||
debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
|
||||
xform_self_ty);
|
||||
|
||||
self.inherent_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
item: item,
|
||||
kind: InherentImplCandidate(impl_substs, obligations),
|
||||
import_id: self.import_id,
|
||||
});
|
||||
}
|
||||
|
||||
fn assemble_inherent_candidates_from_object(&mut self,
|
||||
@ -540,17 +622,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
let tcx = self.tcx;
|
||||
for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
|
||||
let item = match self.associated_item(bound_trait_ref.def_id()) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
continue;
|
||||
for item in self.impl_or_trait_item(bound_trait_ref.def_id()) {
|
||||
if !self.has_applicable_self(&item) {
|
||||
self.record_static_candidate(TraitSource(bound_trait_ref.def_id()));
|
||||
} else {
|
||||
mk_cand(self, bound_trait_ref, item);
|
||||
}
|
||||
};
|
||||
|
||||
if !self.has_applicable_self(&item) {
|
||||
self.record_static_candidate(TraitSource(bound_trait_ref.def_id()));
|
||||
} else {
|
||||
mk_cand(self, bound_trait_ref, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -584,37 +661,46 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn matches_return_type(&self, method: &ty::AssociatedItem,
|
||||
expected: ty::Ty<'tcx>) -> bool {
|
||||
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 = 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()
|
||||
})
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_extension_candidates_for_trait(&mut self,
|
||||
trait_def_id: DefId)
|
||||
-> Result<(), MethodError<'tcx>> {
|
||||
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})",
|
||||
trait_def_id);
|
||||
|
||||
// Check whether `trait_def_id` defines a method with suitable name:
|
||||
let maybe_item = self.tcx.associated_items(trait_def_id)
|
||||
.find(|item| item.name == self.item_name);
|
||||
let item = match maybe_item {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
return Ok(());
|
||||
for item in self.impl_or_trait_item(trait_def_id) {
|
||||
// Check whether `trait_def_id` defines a method with suitable name:
|
||||
if !self.has_applicable_self(&item) {
|
||||
debug!("method has inapplicable self");
|
||||
self.record_static_candidate(TraitSource(trait_def_id));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Check whether `trait_def_id` defines a method with suitable name:
|
||||
if !self.has_applicable_self(&item) {
|
||||
debug!("method has inapplicable self");
|
||||
self.record_static_candidate(TraitSource(trait_def_id));
|
||||
return Ok(());
|
||||
self.assemble_extension_candidates_for_trait_impls(trait_def_id, item.clone());
|
||||
|
||||
self.assemble_closure_candidates(trait_def_id, item.clone())?;
|
||||
|
||||
self.assemble_projection_candidates(trait_def_id, item.clone());
|
||||
|
||||
self.assemble_where_clause_candidates(trait_def_id, item.clone());
|
||||
}
|
||||
|
||||
self.assemble_extension_candidates_for_trait_impls(trait_def_id, item.clone());
|
||||
|
||||
self.assemble_closure_candidates(trait_def_id, item.clone())?;
|
||||
|
||||
self.assemble_projection_candidates(trait_def_id, item.clone());
|
||||
|
||||
self.assemble_where_clause_candidates(trait_def_id, item.clone());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -833,10 +919,30 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn candidate_method_names(&self) -> Vec<ast::Name> {
|
||||
let mut set = FxHashSet();
|
||||
let mut names: Vec<_> =
|
||||
self.inherent_candidates
|
||||
.iter()
|
||||
.chain(&self.extension_candidates)
|
||||
.map(|candidate| candidate.item.name)
|
||||
.filter(|&name| set.insert(name))
|
||||
.collect();
|
||||
|
||||
// sort them by the name so we have a stable result
|
||||
names.sort_by_key(|n| n.as_str());
|
||||
names
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// THE ACTUAL SEARCH
|
||||
|
||||
fn pick(mut self) -> PickResult<'tcx> {
|
||||
assert!(match self.looking_for {
|
||||
LookingFor::MethodName(_) => true,
|
||||
LookingFor::ReturnType(_) => false,
|
||||
});
|
||||
|
||||
if let Some(r) = self.pick_core() {
|
||||
return r;
|
||||
}
|
||||
@ -855,6 +961,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
let out_of_scope_traits = match self.pick_core() {
|
||||
Some(Ok(p)) => vec![p.item.container.id()],
|
||||
//Some(Ok(p)) => p.iter().map(|p| p.item.container().id()).collect(),
|
||||
Some(Err(MethodError::Ambiguity(v))) => {
|
||||
v.into_iter()
|
||||
.map(|source| {
|
||||
@ -1257,10 +1364,20 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
self.tcx.erase_late_bound_regions(value)
|
||||
}
|
||||
|
||||
/// 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)
|
||||
/// Find the method with the appropriate name (or return type, as the case may be).
|
||||
fn impl_or_trait_item(&self, def_id: DefId) -> Vec<ty::AssociatedItem> {
|
||||
match self.looking_for {
|
||||
LookingFor::MethodName(name) => {
|
||||
self.fcx.associated_item(def_id, name).map_or(Vec::new(), |x| vec![x])
|
||||
}
|
||||
LookingFor::ReturnType(return_ty) => {
|
||||
self.tcx
|
||||
.associated_items(def_id)
|
||||
.map(|did| self.tcx.associated_item(did.def_id))
|
||||
.filter(|m| self.matches_return_type(m, return_ty))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2986,7 +2986,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
self.report_mismatched_types(&cause, expected_ty, found_ty, e);
|
||||
self.report_mismatched_types(&cause, expected_ty, found_ty, e).emit();
|
||||
self.tcx.types.err
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3880,7 +3880,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
match result {
|
||||
Ok(ty) => unified = ty,
|
||||
Err(e) => {
|
||||
self.report_mismatched_types(&cause, unified, e_ty, e);
|
||||
self.report_mismatched_types(&cause, unified, e_ty, e).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -356,7 +356,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
infcx.report_mismatched_types(&cause,
|
||||
mk_ptr(mt_b.ty),
|
||||
target,
|
||||
ty::error::TypeError::Mutability);
|
||||
ty::error::TypeError::Mutability).emit();
|
||||
}
|
||||
(mt_a.ty, mt_b.ty, unsize_trait, None)
|
||||
};
|
||||
|
@ -185,7 +185,7 @@ fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
true
|
||||
}
|
||||
Err(err) => {
|
||||
infcx.report_mismatched_types(cause, expected, actual, err);
|
||||
infcx.report_mismatched_types(cause, expected, actual, err).emit();
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -304,6 +304,7 @@ declare_features! (
|
||||
// Allows using `Self` and associated types in struct expressions and patterns.
|
||||
(active, more_struct_aliases, "1.14.0", Some(37544)),
|
||||
|
||||
|
||||
// Allows #[link(..., cfg(..))]
|
||||
(active, link_cfg, "1.14.0", Some(37406)),
|
||||
|
||||
@ -314,6 +315,9 @@ declare_features! (
|
||||
|
||||
// Allows #[target_feature(...)]
|
||||
(active, target_feature, "1.15.0", None),
|
||||
|
||||
// Allow safe suggestions for potential type conversions.
|
||||
(active, safe_suggestion, "1.0.0", Some(37384)),
|
||||
);
|
||||
|
||||
declare_features! (
|
||||
|
47
src/test/ui/span/coerce-suggestions.rs
Normal file
47
src/test/ui/span/coerce-suggestions.rs
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(box_syntax)]
|
||||
|
||||
fn test(_x: &mut String) {}
|
||||
fn test2(_x: &mut i32) {}
|
||||
|
||||
fn main() {
|
||||
let x: usize = String::new();
|
||||
//~^ ERROR E0308
|
||||
//~| NOTE expected usize, found struct `std::string::String`
|
||||
//~| NOTE expected type `usize`
|
||||
//~| NOTE found type `std::string::String`
|
||||
//~| HELP here are some functions which might fulfill your needs:
|
||||
let x: &str = String::new();
|
||||
//~^ ERROR E0308
|
||||
//~| NOTE expected &str, found struct `std::string::String`
|
||||
//~| NOTE expected type `&str`
|
||||
//~| NOTE found type `std::string::String`
|
||||
//~| HELP try with `&String::new()`
|
||||
let y = String::new();
|
||||
test(&y);
|
||||
//~^ ERROR E0308
|
||||
//~| NOTE types differ in mutability
|
||||
//~| NOTE expected type `&mut std::string::String`
|
||||
//~| NOTE found type `&std::string::String`
|
||||
//~| HELP try with `&mut y`
|
||||
test2(&y);
|
||||
//~^ ERROR E0308
|
||||
//~| NOTE types differ in mutability
|
||||
//~| NOTE expected type `&mut i32`
|
||||
//~| NOTE found type `&std::string::String`
|
||||
let f;
|
||||
f = box f;
|
||||
//~^ ERROR E0308
|
||||
//~| NOTE cyclic type of infinite size
|
||||
//~| NOTE expected type `_`
|
||||
//~| NOTE found type `Box<_>`
|
||||
}
|
55
src/test/ui/span/coerce-suggestions.stderr
Normal file
55
src/test/ui/span/coerce-suggestions.stderr
Normal file
@ -0,0 +1,55 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-suggestions.rs:17:20
|
||||
|
|
||||
17 | let x: usize = String::new();
|
||||
| ^^^^^^^^^^^^^ expected usize, found struct `std::string::String`
|
||||
|
|
||||
= note: expected type `usize`
|
||||
= note: found type `std::string::String`
|
||||
= help: here are some functions which might fulfill your needs:
|
||||
- .capacity()
|
||||
- .len()
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-suggestions.rs:23:19
|
||||
|
|
||||
23 | let x: &str = String::new();
|
||||
| ^^^^^^^^^^^^^ expected &str, found struct `std::string::String`
|
||||
|
|
||||
= note: expected type `&str`
|
||||
= note: found type `std::string::String`
|
||||
= help: here are some functions which might fulfill your needs:
|
||||
- .as_str()
|
||||
- .trim()
|
||||
- .trim_left()
|
||||
- .trim_right()
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-suggestions.rs:30:10
|
||||
|
|
||||
30 | test(&y);
|
||||
| ^^ types differ in mutability
|
||||
|
|
||||
= note: expected type `&mut std::string::String`
|
||||
= note: found type `&std::string::String`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-suggestions.rs:36:11
|
||||
|
|
||||
36 | test2(&y);
|
||||
| ^^ types differ in mutability
|
||||
|
|
||||
= note: expected type `&mut i32`
|
||||
= note: found type `&std::string::String`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-suggestions.rs:42:9
|
||||
|
|
||||
42 | f = box f;
|
||||
| ^^^^^ cyclic type of infinite size
|
||||
|
|
||||
= note: expected type `_`
|
||||
= note: found type `Box<_>`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user