diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 8cdfbf5f55ca0..6cc7818d712f6 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 34dd213e2b390..bc3013b78b38c 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 236f742db3f71..a9347926bda0a 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 0000000000000..c4fc01469bf65 --- /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 0000000000000..b7497be6ceb36 --- /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` + --> $DIR/match-ergonomics.rs:8:9 + | +LL | [&v] => {}, + | ^^^^ pattern cannot match with input type `std::vec::Vec` + +error[E0529]: expected an array or slice, found `std::vec::Vec` + --> $DIR/match-ergonomics.rs:20:9 + | +LL | [v] => {}, + | ^^^ pattern cannot match with input type `std::vec::Vec` + +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`.