Add suggestion for & coercions
This commit is contained in:
parent
968ae7babe
commit
d360091e79
@ -11,8 +11,9 @@
|
||||
|
||||
use check::FnCtxt;
|
||||
use rustc::ty::Ty;
|
||||
use rustc::infer::{InferOk};
|
||||
use rustc::infer::{InferOk, TypeOrigin};
|
||||
use rustc::traits::ObligationCause;
|
||||
use rustc::ty;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax_pos::{self, Span};
|
||||
@ -80,12 +81,18 @@ pub fn demand_coerce(&self,
|
||||
if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
|
||||
let cause = self.misc(expr.span);
|
||||
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
|
||||
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 suggestions = if let Some(suggestions) = self.check_ref(expr,
|
||||
checked_ty,
|
||||
expected) {
|
||||
suggestions
|
||||
} else {
|
||||
let mode = probe::Mode::MethodCall;
|
||||
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 \
|
||||
@ -140,4 +147,60 @@ fn has_no_input_arg(&self, method: &AssociatedItem) -> bool {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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(_, _), &ty::TyRef(_, _)) => 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user