Rollup merge of #37658 - GuillaumeGomez:ref_suggestion, r=nikomatsakis,eddyb
Ref suggestion
This commit is contained in:
commit
5da19f2b69
@ -78,6 +78,7 @@ use errors::DiagnosticBuilder;
|
||||
use syntax::abi;
|
||||
use syntax::feature_gate;
|
||||
use syntax::ptr::P;
|
||||
use syntax_pos;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::ops::Deref;
|
||||
@ -722,6 +723,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
Ok(target)
|
||||
}
|
||||
|
||||
/// Same as `try_coerce()`, but without side-effects.
|
||||
pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
|
||||
let source = self.resolve_type_vars_with_obligations(expr_ty);
|
||||
debug!("coercion::can({:?} -> {:?})", source, target);
|
||||
|
||||
let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable);
|
||||
let coerce = Coerce::new(self, cause);
|
||||
self.probe(|_| coerce.coerce::<hir::Expr>(&[], source, target)).is_ok()
|
||||
}
|
||||
|
||||
/// Given some expressions, their known unified type and another expression,
|
||||
/// tries to unify the types, potentially inserting coercions on any of the
|
||||
/// provided expressions and returns their LUB (aka "common supertype").
|
||||
|
@ -10,15 +10,14 @@
|
||||
|
||||
|
||||
use check::FnCtxt;
|
||||
use rustc::ty::Ty;
|
||||
use rustc::infer::{InferOk};
|
||||
use rustc::infer::InferOk;
|
||||
use rustc::traits::ObligationCause;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax_pos::{self, Span};
|
||||
use rustc::hir;
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::ty::{self, AssociatedItem};
|
||||
use rustc::ty::{self, Ty, AssociatedItem};
|
||||
use errors::DiagnosticBuilder;
|
||||
|
||||
use super::method::probe;
|
||||
@ -80,18 +79,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
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 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).join("\n")));
|
||||
};
|
||||
if let Some(suggestion) = self.check_ref(expr,
|
||||
checked_ty,
|
||||
expected) {
|
||||
err.help(&suggestion);
|
||||
} else {
|
||||
let mode = probe::Mode::MethodCall;
|
||||
let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
|
||||
mode,
|
||||
expected,
|
||||
checked_ty,
|
||||
ast::DUMMY_NODE_ID);
|
||||
if suggestions.len() > 0 {
|
||||
err.help(&format!("here are some functions which \
|
||||
might fulfill your needs:\n{}",
|
||||
self.get_best_match(&suggestions).join("\n")));
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
@ -140,4 +145,60 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
_ => 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.can_coerce(ref_ty, expected) {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,5 @@ fn main() {
|
||||
let _: &[i32] = [0];
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected type `&[i32]`
|
||||
//~| found type `[{integer}; 1]`
|
||||
//~| expected &[i32], found array of 1 elements
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ impl Trait for Foo {}
|
||||
|
||||
pub fn main() {
|
||||
let x: Box<Trait> = Box::new(Foo);
|
||||
let _y: &Trait = x; //~ ERROR mismatched types
|
||||
let _y: &Trait = x; //~ ERROR E0308
|
||||
//~| expected type `&Trait`
|
||||
//~| found type `std::boxed::Box<Trait>`
|
||||
}
|
||||
|
@ -33,5 +33,5 @@ pub fn for_stdin<'a>() -> Container<'a> {
|
||||
fn main() {
|
||||
let mut c = for_stdin();
|
||||
let mut v = Vec::new();
|
||||
c.read_to(v); //~ ERROR mismatched types
|
||||
c.read_to(v); //~ ERROR E0308
|
||||
}
|
||||
|
@ -35,4 +35,5 @@ fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &T) -> bool
|
||||
fn main() {
|
||||
check((3, 5));
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP try with `&(3, 5)`
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ fn main() {
|
||||
//~| 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
|
||||
|
@ -18,11 +18,7 @@ error[E0308]: mismatched types
|
||||
|
|
||||
= note: expected type `&str`
|
||||
found type `std::string::String`
|
||||
= help: here are some functions which might fulfill your needs:
|
||||
- .as_str()
|
||||
- .trim()
|
||||
- .trim_left()
|
||||
- .trim_right()
|
||||
= help: try with `&String::new()`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-suggestions.rs:30:10
|
||||
@ -34,18 +30,18 @@ error[E0308]: mismatched types
|
||||
found type `&std::string::String`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-suggestions.rs:36:11
|
||||
--> $DIR/coerce-suggestions.rs:35:11
|
||||
|
|
||||
36 | test2(&y);
|
||||
35 | test2(&y);
|
||||
| ^^ types differ in mutability
|
||||
|
|
||||
= note: expected type `&mut i32`
|
||||
found type `&std::string::String`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-suggestions.rs:42:9
|
||||
--> $DIR/coerce-suggestions.rs:41:9
|
||||
|
|
||||
42 | f = box f;
|
||||
41 | f = box f;
|
||||
| ^^^^^ cyclic type of infinite size
|
||||
|
|
||||
= note: expected type `_`
|
||||
|
Loading…
Reference in New Issue
Block a user