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};
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 \
_ => 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,
+ }
+ }
}