about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCorey Farwell <coreyf@rwell.org>2017-04-21 23:29:13 -0400
committerGitHub <noreply@github.com>2017-04-21 23:29:13 -0400
commit5da19f2b69694312ec8733fcdb145923391a5af7 (patch)
treea57e3349ee577aa3cc0aaa2554019583bde65dab
parent1785bca5137fad1f26e4d3c347cbb68408a28fa9 (diff)
parent7ce1eb77c77ce0a56efc7d11ac8003e6a95208d0 (diff)
downloadrust-5da19f2b69694312ec8733fcdb145923391a5af7.tar.gz
rust-5da19f2b69694312ec8733fcdb145923391a5af7.zip
Rollup merge of #37658 - GuillaumeGomez:ref_suggestion, r=nikomatsakis,eddyb
Ref suggestion
-rw-r--r--src/librustc_typeck/check/coercion.rs11
-rw-r--r--src/librustc_typeck/check/demand.rs89
-rw-r--r--src/test/compile-fail/coercion-slice.rs1
-rw-r--r--src/test/compile-fail/cross-borrow-trait.rs2
-rw-r--r--src/test/compile-fail/issue-11374.rs2
-rw-r--r--src/test/compile-fail/issue-13058.rs1
-rw-r--r--src/test/ui/span/coerce-suggestions.rs1
-rw-r--r--src/test/ui/span/coerce-suggestions.stderr14
8 files changed, 94 insertions, 27 deletions
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index c6a1f6cfc0d..d21b5f739bd 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -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").
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index e922c7447ff..4cc3f2dacdf 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -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,
+        }
+    }
 }
diff --git a/src/test/compile-fail/coercion-slice.rs b/src/test/compile-fail/coercion-slice.rs
index 6b468ff9662..7c5a4e0c3c6 100644
--- a/src/test/compile-fail/coercion-slice.rs
+++ b/src/test/compile-fail/coercion-slice.rs
@@ -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
 }
diff --git a/src/test/compile-fail/cross-borrow-trait.rs b/src/test/compile-fail/cross-borrow-trait.rs
index e5afccb9cf3..847a82c0826 100644
--- a/src/test/compile-fail/cross-borrow-trait.rs
+++ b/src/test/compile-fail/cross-borrow-trait.rs
@@ -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>`
 }
diff --git a/src/test/compile-fail/issue-11374.rs b/src/test/compile-fail/issue-11374.rs
index f78786a2889..1e444a6bebf 100644
--- a/src/test/compile-fail/issue-11374.rs
+++ b/src/test/compile-fail/issue-11374.rs
@@ -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
 }
diff --git a/src/test/compile-fail/issue-13058.rs b/src/test/compile-fail/issue-13058.rs
index 408c6d411de..ed163444149 100644
--- a/src/test/compile-fail/issue-13058.rs
+++ b/src/test/compile-fail/issue-13058.rs
@@ -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)`
 }
diff --git a/src/test/ui/span/coerce-suggestions.rs b/src/test/ui/span/coerce-suggestions.rs
index 3177e858ff4..bc3122bf71c 100644
--- a/src/test/ui/span/coerce-suggestions.rs
+++ b/src/test/ui/span/coerce-suggestions.rs
@@ -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
diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr
index 6a70b8ff851..220b2f471da 100644
--- a/src/test/ui/span/coerce-suggestions.stderr
+++ b/src/test/ui/span/coerce-suggestions.stderr
@@ -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 `_`