about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/check/_match.rs57
-rw-r--r--src/test/ui/destructure-trait-ref.stderr12
-rw-r--r--src/test/ui/mismatched_types/issue-38371.stderr6
-rw-r--r--src/test/ui/suggestions/match-ergonomics.rs41
-rw-r--r--src/test/ui/suggestions/match-ergonomics.stderr52
5 files changed, 151 insertions, 17 deletions
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 8cdfbf5f55c..6cc7818d712 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -1,8 +1,8 @@
 use crate::check::{FnCtxt, Expectation, Diverges, Needs};
 use crate::check::coercion::CoerceMany;
 use crate::util::nodemap::FxHashMap;
-use errors::Applicability;
-use rustc::hir::{self, PatKind};
+use errors::{Applicability, DiagnosticBuilder};
+use rustc::hir::{self, PatKind, Pat};
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 use rustc::infer;
@@ -377,15 +377,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             // Look for a case like `fn foo(&foo: u32)` and suggest
                             // `fn foo(foo: &u32)`
                             if let Some(mut err) = err {
-                                if let PatKind::Binding(..) = inner.node {
-                                    if let Ok(snippet) = tcx.sess.source_map()
-                                                                    .span_to_snippet(pat.span)
-                                    {
-                                        err.help(&format!("did you mean `{}: &{}`?",
-                                                            &snippet[1..],
-                                                            expected));
-                                    }
-                                }
+                                self.borrow_pat_suggestion(&mut err, &pat, &inner, &expected);
                                 err.emit();
                             }
                             (rptr_ty, inner_ty)
@@ -517,6 +509,49 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // subtyping.
     }
 
+    fn borrow_pat_suggestion(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        pat: &Pat,
+        inner: &Pat,
+        expected: Ty<'tcx>,
+    ) {
+        let tcx = self.tcx;
+        if let PatKind::Binding(..) = inner.node {
+            let parent_id = tcx.hir().get_parent_node_by_hir_id(pat.hir_id);
+            let parent = tcx.hir().get_by_hir_id(parent_id);
+            debug!("inner {:?} pat {:?} parent {:?}", inner, pat, parent);
+            match parent {
+                hir::Node::Item(hir::Item { node: hir::ItemKind::Fn(..), .. }) |
+                hir::Node::ForeignItem(hir::ForeignItem {
+                    node: hir::ForeignItemKind::Fn(..), ..
+                }) |
+                hir::Node::TraitItem(hir::TraitItem { node: hir::TraitItemKind::Method(..), .. }) |
+                hir::Node::ImplItem(hir::ImplItem { node: hir::ImplItemKind::Method(..), .. }) => {
+                    // this pat is likely an argument
+                    if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) {
+                        // FIXME: turn into structured suggestion, will need a span that also
+                        // includes the the arg's type.
+                        err.help(&format!("did you mean `{}: &{}`?", snippet, expected));
+                    }
+                }
+                hir::Node::Expr(hir::Expr { node: hir::ExprKind::Match(..), .. }) |
+                hir::Node::Pat(_) => {
+                    // rely on match ergonomics or it might be nested `&&pat`
+                    if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) {
+                        err.span_suggestion(
+                            pat.span,
+                            "you can probably remove the explicit borrow",
+                            snippet,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+                _ => {} // don't provide suggestions in other cases #55175
+            }
+        }
+    }
+
     pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool {
         if let PatKind::Binding(..) = inner.node {
             if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) {
diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr
index 34dd213e2b3..bc3013b78b3 100644
--- a/src/test/ui/destructure-trait-ref.stderr
+++ b/src/test/ui/destructure-trait-ref.stderr
@@ -20,21 +20,25 @@ error[E0308]: mismatched types
   --> $DIR/destructure-trait-ref.rs:31:10
    |
 LL |     let &&x = &1isize as &T;
-   |          ^^ expected trait T, found reference
+   |          ^^
+   |          |
+   |          expected trait T, found reference
+   |          help: you can probably remove the explicit borrow: `x`
    |
    = note: expected type `dyn T`
               found type `&_`
-   = help: did you mean `x: &dyn T`?
 
 error[E0308]: mismatched types
   --> $DIR/destructure-trait-ref.rs:36:11
    |
 LL |     let &&&x = &(&1isize as &T);
-   |           ^^ expected trait T, found reference
+   |           ^^
+   |           |
+   |           expected trait T, found reference
+   |           help: you can probably remove the explicit borrow: `x`
    |
    = note: expected type `dyn T`
               found type `&_`
-   = help: did you mean `x: &dyn T`?
 
 error[E0308]: mismatched types
   --> $DIR/destructure-trait-ref.rs:41:13
diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr
index 236f742db3f..a9347926bda 100644
--- a/src/test/ui/mismatched_types/issue-38371.stderr
+++ b/src/test/ui/mismatched_types/issue-38371.stderr
@@ -12,11 +12,13 @@ error[E0308]: mismatched types
   --> $DIR/issue-38371.rs:18:9
    |
 LL | fn agh(&&bar: &u32) {
-   |         ^^^^ expected u32, found reference
+   |         ^^^^
+   |         |
+   |         expected u32, found reference
+   |         help: you can probably remove the explicit borrow: `bar`
    |
    = note: expected type `u32`
               found type `&_`
-   = help: did you mean `bar: &u32`?
 
 error[E0308]: mismatched types
   --> $DIR/issue-38371.rs:21:8
diff --git a/src/test/ui/suggestions/match-ergonomics.rs b/src/test/ui/suggestions/match-ergonomics.rs
new file mode 100644
index 00000000000..c4fc01469bf
--- /dev/null
+++ b/src/test/ui/suggestions/match-ergonomics.rs
@@ -0,0 +1,41 @@
+fn main() {
+    let x = vec![1i32];
+    match &x[..] {
+        [&v] => {}, //~ ERROR mismatched types
+        _ => {},
+    }
+    match x {
+        [&v] => {}, //~ ERROR expected an array or slice
+        _ => {},
+    }
+    match &x[..] {
+        [v] => {},
+        _ => {},
+    }
+    match &x[..] {
+        &[v] => {},
+        _ => {},
+    }
+    match x {
+        [v] => {}, //~ ERROR expected an array or slice
+        _ => {},
+    }
+    let y = 1i32;
+    match &y {
+        &v => {},
+        _ => {},
+    }
+    match y {
+        &v => {}, //~ ERROR mismatched types
+        _ => {},
+    }
+    match &y {
+        v => {},
+        _ => {},
+    }
+    match y {
+        v => {},
+        _ => {},
+    }
+    if let [&v] = &x[..] {} //~ ERROR mismatched types
+}
diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr
new file mode 100644
index 00000000000..b7497be6ceb
--- /dev/null
+++ b/src/test/ui/suggestions/match-ergonomics.stderr
@@ -0,0 +1,52 @@
+error[E0308]: mismatched types
+  --> $DIR/match-ergonomics.rs:4:10
+   |
+LL |         [&v] => {},
+   |          ^^
+   |          |
+   |          expected i32, found reference
+   |          help: you can probably remove the explicit borrow: `v`
+   |
+   = note: expected type `i32`
+              found type `&_`
+
+error[E0529]: expected an array or slice, found `std::vec::Vec<i32>`
+  --> $DIR/match-ergonomics.rs:8:9
+   |
+LL |         [&v] => {},
+   |         ^^^^ pattern cannot match with input type `std::vec::Vec<i32>`
+
+error[E0529]: expected an array or slice, found `std::vec::Vec<i32>`
+  --> $DIR/match-ergonomics.rs:20:9
+   |
+LL |         [v] => {},
+   |         ^^^ pattern cannot match with input type `std::vec::Vec<i32>`
+
+error[E0308]: mismatched types
+  --> $DIR/match-ergonomics.rs:29:9
+   |
+LL |         &v => {},
+   |         ^^
+   |         |
+   |         expected i32, found reference
+   |         help: you can probably remove the explicit borrow: `v`
+   |
+   = note: expected type `i32`
+              found type `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/match-ergonomics.rs:40:13
+   |
+LL |     if let [&v] = &x[..] {}
+   |             ^^
+   |             |
+   |             expected i32, found reference
+   |             help: you can probably remove the explicit borrow: `v`
+   |
+   = note: expected type `i32`
+              found type `&_`
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0308, E0529.
+For more information about an error, try `rustc --explain E0308`.