From c29aadd9cf85d43249748228e858ae75d8edb768 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Sat, 10 Jul 2021 19:54:48 +0200 Subject: [PATCH] Provide a suggestion when trying to destructure a `Vec` as a slice --- compiler/rustc_typeck/src/check/pat.rs | 18 ++++++++++-- .../ui/suggestions/match-ergonomics.stderr | 4 +++ src/test/ui/suggestions/pattern-slice-vec.rs | 20 +++++++++++++ .../ui/suggestions/pattern-slice-vec.stderr | 28 +++++++++++++++++++ 4 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/suggestions/pattern-slice-vec.rs create mode 100644 src/test/ui/suggestions/pattern-slice-vec.stderr diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 981a040e660..db77d155a2b 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -16,6 +16,7 @@ use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Ident; use rustc_span::{BytePos, DUMMY_SP}; +use rustc_trait_selection::autoderef::Autoderef; use rustc_trait_selection::traits::{ObligationCause, Pattern}; use ty::VariantDef; @@ -1769,7 +1770,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // The expected type must be an array or slice, but was neither, so error. _ => { if !expected.references_error() { - self.error_expected_array_or_slice(span, expected); + self.error_expected_array_or_slice(span, expected, ti); } let err = self.tcx.ty_error(); (err, Some(err), err) @@ -1882,7 +1883,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .emit(); } - fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>) { + fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>, ti: TopInfo<'tcx>) { let mut err = struct_span_err!( self.tcx.sess, span, @@ -1894,6 +1895,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::Array(..) | ty::Slice(..) = ty.kind() { err.help("the semantics of slice patterns changed recently; see issue #62254"); } + } else if Autoderef::new(&self.infcx, self.param_env, self.body_id, span, expected_ty, span) + .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..))) + { + if let (Some(span), true) = (ti.span, ti.origin_expr) { + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + err.span_suggestion( + span, + "consider slicing here", + format!("{}[..]", snippet), + Applicability::MachineApplicable, + ); + } + } } err.span_label(span, format!("pattern cannot match with input type `{}`", expected_ty)); err.emit(); diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr index ca7562beb1f..4eab2df3080 100644 --- a/src/test/ui/suggestions/match-ergonomics.stderr +++ b/src/test/ui/suggestions/match-ergonomics.stderr @@ -15,12 +15,16 @@ LL | [&v] => {}, error[E0529]: expected an array or slice, found `Vec` --> $DIR/match-ergonomics.rs:8:9 | +LL | match x { + | - help: consider slicing here: `x[..]` LL | [&v] => {}, | ^^^^ pattern cannot match with input type `Vec` error[E0529]: expected an array or slice, found `Vec` --> $DIR/match-ergonomics.rs:20:9 | +LL | match x { + | - help: consider slicing here: `x[..]` LL | [v] => {}, | ^^^ pattern cannot match with input type `Vec` diff --git a/src/test/ui/suggestions/pattern-slice-vec.rs b/src/test/ui/suggestions/pattern-slice-vec.rs new file mode 100644 index 00000000000..1f010ae32a5 --- /dev/null +++ b/src/test/ui/suggestions/pattern-slice-vec.rs @@ -0,0 +1,20 @@ +// Regression test for #87017. + +fn main() { + fn foo() -> Vec { vec![1, 2, 3] } + + if let [_, _, _] = foo() {} + //~^ ERROR: expected an array or slice + //~| HELP: consider slicing here + if let [] = &foo() {} + //~^ ERROR: expected an array or slice + //~| HELP: consider slicing here + + let v = vec![]; + match &v { + //~^ HELP: consider slicing here + [5] => {} + //~^ ERROR: expected an array or slice + _ => {} + } +} diff --git a/src/test/ui/suggestions/pattern-slice-vec.stderr b/src/test/ui/suggestions/pattern-slice-vec.stderr new file mode 100644 index 00000000000..a6337cc66bf --- /dev/null +++ b/src/test/ui/suggestions/pattern-slice-vec.stderr @@ -0,0 +1,28 @@ +error[E0529]: expected an array or slice, found `Vec` + --> $DIR/pattern-slice-vec.rs:6:12 + | +LL | if let [_, _, _] = foo() {} + | ^^^^^^^^^ ----- help: consider slicing here: `foo()[..]` + | | + | pattern cannot match with input type `Vec` + +error[E0529]: expected an array or slice, found `Vec` + --> $DIR/pattern-slice-vec.rs:9:12 + | +LL | if let [] = &foo() {} + | ^^ ------ help: consider slicing here: `&foo()[..]` + | | + | pattern cannot match with input type `Vec` + +error[E0529]: expected an array or slice, found `Vec<_>` + --> $DIR/pattern-slice-vec.rs:16:9 + | +LL | match &v { + | -- help: consider slicing here: `&v[..]` +LL | +LL | [5] => {} + | ^^^ pattern cannot match with input type `Vec<_>` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0529`.