about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/check/demand.rs33
-rw-r--r--src/test/ui/deref-suggestion.rs34
-rw-r--r--src/test/ui/deref-suggestion.stderr59
3 files changed, 126 insertions, 0 deletions
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 65900dc3f36..7110a1ba81d 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -261,6 +261,39 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
                 None
             }
+            (_, &ty::TyRef(_, checked)) => {
+                // We have `&T`, check if what was expected was `T`. If so,
+                // we may want to suggest adding a `*`, or removing
+                // a `&`.
+                //
+                // (But, also check check the `expn_info()` to see if this is
+                // a macro; if so, it's hard to extract the text and make a good
+                // suggestion, so don't bother.)
+                if self.infcx.can_sub(self.param_env, checked.ty, &expected).is_ok() &&
+                   expr.span.ctxt().outer().expn_info().is_none() {
+                    match expr.node {
+                        // Maybe remove `&`?
+                        hir::ExprAddrOf(_, ref expr) => {
+                            if let Ok(code) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
+                                return Some(format!("try with `{}`", code));
+                            }
+                        }
+
+                        // Maybe add `*`? Only if `T: Copy`.
+                        _ => {
+                            if !self.infcx.type_moves_by_default(self.param_env,
+                                                                checked.ty,
+                                                                expr.span) {
+                                let sp = self.sess().codemap().call_span_if_macro(expr.span);
+                                if let Ok(code) = self.tcx.sess.codemap().span_to_snippet(sp) {
+                                    return Some(format!("try with `*{}`", code));
+                                }
+                            }
+                        },
+                    }
+                }
+                None
+            }
             _ => None,
         }
     }
diff --git a/src/test/ui/deref-suggestion.rs b/src/test/ui/deref-suggestion.rs
new file mode 100644
index 00000000000..16d8226bfec
--- /dev/null
+++ b/src/test/ui/deref-suggestion.rs
@@ -0,0 +1,34 @@
+// Copyright 2017 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.
+
+macro_rules! borrow {
+    ($x:expr) => { &$x }
+}
+
+fn foo(_: String) {}
+
+fn foo2(s: &String) {
+    foo(s);
+}
+
+fn foo3(_: u32) {}
+fn foo4(u: &u32) {
+    foo3(u);
+}
+
+fn main() {
+    let s = String::new();
+    let r_s = &s;
+    foo2(r_s);
+    foo(&"aaa".to_owned());
+    foo(&mut "aaa".to_owned());
+    foo3(borrow!(0));
+    foo4(&0);
+}
diff --git a/src/test/ui/deref-suggestion.stderr b/src/test/ui/deref-suggestion.stderr
new file mode 100644
index 00000000000..5ad9c19fa8c
--- /dev/null
+++ b/src/test/ui/deref-suggestion.stderr
@@ -0,0 +1,59 @@
+error[E0308]: mismatched types
+  --> $DIR/deref-suggestion.rs:18:9
+   |
+18 |     foo(s);
+   |         ^ expected struct `std::string::String`, found reference
+   |
+   = note: expected type `std::string::String`
+              found type `&std::string::String`
+   = help: here are some functions which might fulfill your needs:
+           - .escape_debug()
+           - .escape_default()
+           - .escape_unicode()
+           - .to_lowercase()
+           - .to_uppercase()
+
+error[E0308]: mismatched types
+  --> $DIR/deref-suggestion.rs:23:10
+   |
+23 |     foo3(u);
+   |          ^ expected u32, found &u32
+   |
+   = note: expected type `u32`
+              found type `&u32`
+   = help: try with `*u`
+
+error[E0308]: mismatched types
+  --> $DIR/deref-suggestion.rs:30:9
+   |
+30 |     foo(&"aaa".to_owned());
+   |         ^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found reference
+   |
+   = note: expected type `std::string::String`
+              found type `&std::string::String`
+   = help: try with `"aaa".to_owned()`
+
+error[E0308]: mismatched types
+  --> $DIR/deref-suggestion.rs:31:9
+   |
+31 |     foo(&mut "aaa".to_owned());
+   |         ^^^^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found mutable reference
+   |
+   = note: expected type `std::string::String`
+              found type `&mut std::string::String`
+   = help: try with `"aaa".to_owned()`
+
+error[E0308]: mismatched types
+  --> $DIR/deref-suggestion.rs:12:20
+   |
+12 |     ($x:expr) => { &$x }
+   |                    ^^^ expected u32, found &{integer}
+...
+32 |     foo3(borrow!(0));
+   |          ---------- in this macro invocation
+   |
+   = note: expected type `u32`
+              found type `&{integer}`
+
+error: aborting due to 5 previous errors
+