Auto merge of #38099 - GuillaumeGomez:cast_suggestions, r=nikomatsakis

Cast suggestions

r? @nikomatsakis
This commit is contained in:
bors 2016-12-21 07:28:16 +00:00
commit 439c3128d7
13 changed files with 404 additions and 103 deletions

View File

@ -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,

View File

@ -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>,
}

View File

@ -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
}
};

View File

@ -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>
{

View File

@ -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,
}
}
}

View File

@ -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);

View File

@ -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()
}
}
}
}

View File

@ -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();
}
}
}

View File

@ -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)
};

View File

@ -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
}
}

View File

@ -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! (

View 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<_>`
}

View 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